From 9c66ba8a91ba5e7958ed25296f81e4ab3ae79b93 Mon Sep 17 00:00:00 2001 From: spth Date: Tue, 29 Mar 2022 15:45:56 +0000 Subject: [PATCH] Delete unused files as suggested by Felix Salfelder (felixs). git-svn-id: https://svn.code.sf.net/p/sdcc/code/trunk@13342 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- sdcc/ChangeLog | 5 + sdcc/support/sdbinutils/bfd/aix386-core.c | 269 - sdcc/support/sdbinutils/bfd/aix5ppc-core.c | 357 - sdcc/support/sdbinutils/bfd/aout-adobe.c | 523 - sdcc/support/sdbinutils/bfd/aout-arm.c | 548 - sdcc/support/sdbinutils/bfd/aout-cris.c | 292 - sdcc/support/sdbinutils/bfd/aout-ns32k.c | 364 - sdcc/support/sdbinutils/bfd/aout-sparcle.c | 37 - sdcc/support/sdbinutils/bfd/aout-target.h | 694 - sdcc/support/sdbinutils/bfd/aout-tic30.c | 1123 -- sdcc/support/sdbinutils/bfd/aout0.c | 38 - sdcc/support/sdbinutils/bfd/aout32.c | 24 - sdcc/support/sdbinutils/bfd/aout64.c | 32 - sdcc/support/sdbinutils/bfd/aoutf1.h | 793 - sdcc/support/sdbinutils/bfd/arc-got.h | 528 - sdcc/support/sdbinutils/bfd/arc-plt.h | 196 - sdcc/support/sdbinutils/bfd/archive64.c | 246 - sdcc/support/sdbinutils/bfd/armnetbsd.c | 39 - sdcc/support/sdbinutils/bfd/bfd-in.h | 1051 -- sdcc/support/sdbinutils/bfd/bout.c | 1483 -- sdcc/support/sdbinutils/bfd/cf-i386lynx.c | 34 - sdcc/support/sdbinutils/bfd/cf-sparclynx.c | 29 - sdcc/support/sdbinutils/bfd/cisco-core.c | 418 - sdcc/support/sdbinutils/bfd/coff-alpha.c | 2392 --- sdcc/support/sdbinutils/bfd/coff-apollo.c | 120 - sdcc/support/sdbinutils/bfd/coff-arm.c | 2561 --- sdcc/support/sdbinutils/bfd/coff-aux.c | 145 - sdcc/support/sdbinutils/bfd/coff-go32.c | 45 - sdcc/support/sdbinutils/bfd/coff-h8300.c | 1387 -- sdcc/support/sdbinutils/bfd/coff-h8500.c | 298 - sdcc/support/sdbinutils/bfd/coff-i386.c | 689 - sdcc/support/sdbinutils/bfd/coff-i860.c | 718 - sdcc/support/sdbinutils/bfd/coff-i960.c | 654 - sdcc/support/sdbinutils/bfd/coff-ia64.c | 202 - sdcc/support/sdbinutils/bfd/coff-m68k.c | 548 - sdcc/support/sdbinutils/bfd/coff-m88k.c | 291 - sdcc/support/sdbinutils/bfd/coff-mcore.c | 561 - sdcc/support/sdbinutils/bfd/coff-mips.c | 1502 -- sdcc/support/sdbinutils/bfd/coff-ppc.c | 2596 --- sdcc/support/sdbinutils/bfd/coff-rs6000.c | 4406 ----- sdcc/support/sdbinutils/bfd/coff-sh.c | 3215 ---- sdcc/support/sdbinutils/bfd/coff-sparc.c | 208 - sdcc/support/sdbinutils/bfd/coff-stgo32.c | 424 - sdcc/support/sdbinutils/bfd/coff-svm68k.c | 27 - sdcc/support/sdbinutils/bfd/coff-tic30.c | 222 - sdcc/support/sdbinutils/bfd/coff-tic4x.c | 291 - sdcc/support/sdbinutils/bfd/coff-tic54x.c | 673 - sdcc/support/sdbinutils/bfd/coff-tic80.c | 711 - sdcc/support/sdbinutils/bfd/coff-u68k.c | 36 - sdcc/support/sdbinutils/bfd/coff-w65.c | 375 - sdcc/support/sdbinutils/bfd/coff-we32k.c | 78 - sdcc/support/sdbinutils/bfd/coff-x86_64.c | 811 - sdcc/support/sdbinutils/bfd/coff-z80.c | 283 - sdcc/support/sdbinutils/bfd/coff-z8k.c | 375 - sdcc/support/sdbinutils/bfd/coff64-rs6000.c | 3063 ---- sdcc/support/sdbinutils/bfd/coffgen.c | 3135 ---- sdcc/support/sdbinutils/bfd/cofflink.c | 3154 ---- sdcc/support/sdbinutils/bfd/coffswap.h | 840 - sdcc/support/sdbinutils/bfd/cpu-aarch64.c | 127 - sdcc/support/sdbinutils/bfd/cpu-alpha.c | 53 - sdcc/support/sdbinutils/bfd/cpu-arc.c | 100 - sdcc/support/sdbinutils/bfd/cpu-arm.c | 439 - sdcc/support/sdbinutils/bfd/cpu-avr.c | 163 - sdcc/support/sdbinutils/bfd/cpu-bfin.c | 41 - sdcc/support/sdbinutils/bfd/cpu-cr16.c | 41 - sdcc/support/sdbinutils/bfd/cpu-cr16c.c | 40 - sdcc/support/sdbinutils/bfd/cpu-cris.c | 109 - sdcc/support/sdbinutils/bfd/cpu-crx.c | 41 - sdcc/support/sdbinutils/bfd/cpu-d10v.c | 75 - sdcc/support/sdbinutils/bfd/cpu-d30v.c | 41 - sdcc/support/sdbinutils/bfd/cpu-dlx.c | 41 - sdcc/support/sdbinutils/bfd/cpu-epiphany.c | 58 - sdcc/support/sdbinutils/bfd/cpu-fr30.c | 40 - sdcc/support/sdbinutils/bfd/cpu-frv.c | 65 - sdcc/support/sdbinutils/bfd/cpu-ft32.c | 75 - sdcc/support/sdbinutils/bfd/cpu-h8300.c | 268 - sdcc/support/sdbinutils/bfd/cpu-h8500.c | 59 - sdcc/support/sdbinutils/bfd/cpu-hppa.c | 93 - sdcc/support/sdbinutils/bfd/cpu-i370.c | 77 - sdcc/support/sdbinutils/bfd/cpu-i386.c | 302 - sdcc/support/sdbinutils/bfd/cpu-i860.c | 42 - sdcc/support/sdbinutils/bfd/cpu-i960.c | 172 - sdcc/support/sdbinutils/bfd/cpu-ia64-opc.c | 669 - sdcc/support/sdbinutils/bfd/cpu-ia64.c | 60 - sdcc/support/sdbinutils/bfd/cpu-iamcu.c | 60 - sdcc/support/sdbinutils/bfd/cpu-ip2k.c | 57 - sdcc/support/sdbinutils/bfd/cpu-iq2000.c | 59 - sdcc/support/sdbinutils/bfd/cpu-k1om.c | 60 - sdcc/support/sdbinutils/bfd/cpu-l1om.c | 60 - sdcc/support/sdbinutils/bfd/cpu-lm32.c | 41 - sdcc/support/sdbinutils/bfd/cpu-m10200.c | 40 - sdcc/support/sdbinutils/bfd/cpu-m10300.c | 74 - sdcc/support/sdbinutils/bfd/cpu-m32c.c | 72 - sdcc/support/sdbinutils/bfd/cpu-m32r.c | 39 - sdcc/support/sdbinutils/bfd/cpu-m68hc11.c | 40 - sdcc/support/sdbinutils/bfd/cpu-m68hc12.c | 57 - sdcc/support/sdbinutils/bfd/cpu-m68k.c | 273 - sdcc/support/sdbinutils/bfd/cpu-m88k.c | 41 - sdcc/support/sdbinutils/bfd/cpu-m9s12x.c | 41 - sdcc/support/sdbinutils/bfd/cpu-m9s12xg.c | 41 - sdcc/support/sdbinutils/bfd/cpu-mcore.c | 40 - sdcc/support/sdbinutils/bfd/cpu-mep.c | 30 - sdcc/support/sdbinutils/bfd/cpu-metag.c | 41 - sdcc/support/sdbinutils/bfd/cpu-microblaze.c | 41 - sdcc/support/sdbinutils/bfd/cpu-mips.c | 169 - sdcc/support/sdbinutils/bfd/cpu-mmix.c | 43 - sdcc/support/sdbinutils/bfd/cpu-moxie.c | 41 - sdcc/support/sdbinutils/bfd/cpu-msp430.c | 138 - sdcc/support/sdbinutils/bfd/cpu-mt.c | 75 - sdcc/support/sdbinutils/bfd/cpu-nds32.c | 45 - sdcc/support/sdbinutils/bfd/cpu-nios2.c | 74 - sdcc/support/sdbinutils/bfd/cpu-ns32k.c | 814 - sdcc/support/sdbinutils/bfd/cpu-or1k.c | 59 - sdcc/support/sdbinutils/bfd/cpu-pdp11.c | 41 - sdcc/support/sdbinutils/bfd/cpu-pj.c | 41 - sdcc/support/sdbinutils/bfd/cpu-powerpc.c | 422 - sdcc/support/sdbinutils/bfd/cpu-pru.c | 43 - sdcc/support/sdbinutils/bfd/cpu-riscv.c | 79 - sdcc/support/sdbinutils/bfd/cpu-rl78.c | 40 - sdcc/support/sdbinutils/bfd/cpu-rs6000.c | 113 - sdcc/support/sdbinutils/bfd/cpu-rx.c | 59 - sdcc/support/sdbinutils/bfd/cpu-s390.c | 53 - sdcc/support/sdbinutils/bfd/cpu-score.c | 69 - sdcc/support/sdbinutils/bfd/cpu-sh.c | 498 - sdcc/support/sdbinutils/bfd/cpu-sparc.c | 359 - sdcc/support/sdbinutils/bfd/cpu-spu.c | 55 - sdcc/support/sdbinutils/bfd/cpu-tic30.c | 40 - sdcc/support/sdbinutils/bfd/cpu-tic4x.c | 83 - sdcc/support/sdbinutils/bfd/cpu-tic54x.c | 40 - sdcc/support/sdbinutils/bfd/cpu-tic6x.c | 40 - sdcc/support/sdbinutils/bfd/cpu-tic80.c | 41 - sdcc/support/sdbinutils/bfd/cpu-tilegx.c | 57 - sdcc/support/sdbinutils/bfd/cpu-tilepro.c | 40 - sdcc/support/sdbinutils/bfd/cpu-v850.c | 46 - sdcc/support/sdbinutils/bfd/cpu-v850_rh850.c | 42 - sdcc/support/sdbinutils/bfd/cpu-vax.c | 41 - sdcc/support/sdbinutils/bfd/cpu-visium.c | 41 - sdcc/support/sdbinutils/bfd/cpu-w65.c | 52 - sdcc/support/sdbinutils/bfd/cpu-wasm32.c | 36 - sdcc/support/sdbinutils/bfd/cpu-we32k.c | 41 - sdcc/support/sdbinutils/bfd/cpu-xc16x.c | 76 - sdcc/support/sdbinutils/bfd/cpu-xgate.c | 40 - sdcc/support/sdbinutils/bfd/cpu-xstormy16.c | 40 - sdcc/support/sdbinutils/bfd/cpu-xtensa.c | 40 - sdcc/support/sdbinutils/bfd/cpu-z8k.c | 48 - sdcc/support/sdbinutils/bfd/demo64.c | 30 - sdcc/support/sdbinutils/bfd/dwarf1.c | 583 - sdcc/support/sdbinutils/bfd/dwarf2.c | 5064 ------ sdcc/support/sdbinutils/bfd/ecoff.c | 4476 ----- sdcc/support/sdbinutils/bfd/ecofflink.c | 2477 --- sdcc/support/sdbinutils/bfd/ecoffswap.h | 772 - sdcc/support/sdbinutils/bfd/elf-attrs.c | 734 - sdcc/support/sdbinutils/bfd/elf-eh-frame.c | 2565 --- sdcc/support/sdbinutils/bfd/elf-hppa.h | 1225 -- sdcc/support/sdbinutils/bfd/elf-ifunc.c | 357 - sdcc/support/sdbinutils/bfd/elf-linux-core.h | 234 - sdcc/support/sdbinutils/bfd/elf-m10200.c | 1389 -- sdcc/support/sdbinutils/bfd/elf-m10300.c | 5594 ------ sdcc/support/sdbinutils/bfd/elf-nacl.c | 353 - sdcc/support/sdbinutils/bfd/elf-nacl.h | 23 - sdcc/support/sdbinutils/bfd/elf-properties.c | 510 - sdcc/support/sdbinutils/bfd/elf-s390-common.c | 317 - sdcc/support/sdbinutils/bfd/elf-s390.h | 29 - sdcc/support/sdbinutils/bfd/elf-strtab.c | 446 - sdcc/support/sdbinutils/bfd/elf-vxworks.c | 299 - sdcc/support/sdbinutils/bfd/elf-vxworks.h | 36 - sdcc/support/sdbinutils/bfd/elf32-am33lin.c | 107 - sdcc/support/sdbinutils/bfd/elf32-arc.c | 2962 ---- sdcc/support/sdbinutils/bfd/elf32-arm.c | 19827 --------------------- sdcc/support/sdbinutils/bfd/elf32-avr.c | 4257 ----- sdcc/support/sdbinutils/bfd/elf32-avr.h | 122 - sdcc/support/sdbinutils/bfd/elf32-bfin.c | 5534 ------ sdcc/support/sdbinutils/bfd/elf32-cr16.c | 2940 ---- sdcc/support/sdbinutils/bfd/elf32-cr16c.c | 960 - sdcc/support/sdbinutils/bfd/elf32-cris.c | 4179 ----- sdcc/support/sdbinutils/bfd/elf32-crx.c | 1331 -- sdcc/support/sdbinutils/bfd/elf32-d10v.c | 551 - sdcc/support/sdbinutils/bfd/elf32-d30v.c | 560 - sdcc/support/sdbinutils/bfd/elf32-dlx.c | 581 - sdcc/support/sdbinutils/bfd/elf32-dlx.h | 34 - sdcc/support/sdbinutils/bfd/elf32-epiphany.c | 612 - sdcc/support/sdbinutils/bfd/elf32-fr30.c | 718 - sdcc/support/sdbinutils/bfd/elf32-frv.c | 6878 -------- sdcc/support/sdbinutils/bfd/elf32-ft32.c | 1256 -- sdcc/support/sdbinutils/bfd/elf32-gen.c | 103 - sdcc/support/sdbinutils/bfd/elf32-h8300.c | 1752 -- sdcc/support/sdbinutils/bfd/elf32-hppa.c | 4599 ----- sdcc/support/sdbinutils/bfd/elf32-hppa.h | 88 - sdcc/support/sdbinutils/bfd/elf32-i370.c | 1419 -- sdcc/support/sdbinutils/bfd/elf32-i386.c | 4839 ----- sdcc/support/sdbinutils/bfd/elf32-i860.c | 1265 -- sdcc/support/sdbinutils/bfd/elf32-i960.c | 174 - sdcc/support/sdbinutils/bfd/elf32-ip2k.c | 1523 -- sdcc/support/sdbinutils/bfd/elf32-iq2000.c | 917 - sdcc/support/sdbinutils/bfd/elf32-lm32.c | 2608 --- sdcc/support/sdbinutils/bfd/elf32-m32c.c | 2152 --- sdcc/support/sdbinutils/bfd/elf32-m32r.c | 3910 ----- sdcc/support/sdbinutils/bfd/elf32-m68hc11.c | 1319 -- sdcc/support/sdbinutils/bfd/elf32-m68hc12.c | 669 - sdcc/support/sdbinutils/bfd/elf32-m68hc1x.c | 1479 -- sdcc/support/sdbinutils/bfd/elf32-m68hc1x.h | 193 - sdcc/support/sdbinutils/bfd/elf32-m68k.c | 4657 ----- sdcc/support/sdbinutils/bfd/elf32-m88k.c | 38 - sdcc/support/sdbinutils/bfd/elf32-mcore.c | 673 - sdcc/support/sdbinutils/bfd/elf32-mep.c | 761 - sdcc/support/sdbinutils/bfd/elf32-metag.c | 4163 ----- sdcc/support/sdbinutils/bfd/elf32-metag.h | 38 - sdcc/support/sdbinutils/bfd/elf32-microblaze.c | 3462 ---- sdcc/support/sdbinutils/bfd/elf32-mips.c | 2695 --- sdcc/support/sdbinutils/bfd/elf32-moxie.c | 387 - sdcc/support/sdbinutils/bfd/elf32-msp430.c | 2638 --- sdcc/support/sdbinutils/bfd/elf32-mt.c | 601 - sdcc/support/sdbinutils/bfd/elf32-nds32.c | 15501 ----------------- sdcc/support/sdbinutils/bfd/elf32-nds32.h | 159 - sdcc/support/sdbinutils/bfd/elf32-nios2.c | 6133 ------- sdcc/support/sdbinutils/bfd/elf32-nios2.h | 38 - sdcc/support/sdbinutils/bfd/elf32-or1k.c | 2694 --- sdcc/support/sdbinutils/bfd/elf32-pj.c | 359 - sdcc/support/sdbinutils/bfd/elf32-ppc.c | 10958 ------------ sdcc/support/sdbinutils/bfd/elf32-ppc.h | 71 - sdcc/support/sdbinutils/bfd/elf32-pru.c | 1469 -- sdcc/support/sdbinutils/bfd/elf32-rl78.c | 2596 --- sdcc/support/sdbinutils/bfd/elf32-rx.c | 4039 ----- sdcc/support/sdbinutils/bfd/elf32-rx.h | 21 - sdcc/support/sdbinutils/bfd/elf32-s390.c | 4055 ----- sdcc/support/sdbinutils/bfd/elf32-score.c | 4504 ----- sdcc/support/sdbinutils/bfd/elf32-score.h | 152 - sdcc/support/sdbinutils/bfd/elf32-score7.c | 3875 ----- sdcc/support/sdbinutils/bfd/elf32-sh-relocs.h | 1880 -- sdcc/support/sdbinutils/bfd/elf32-sh-symbian.c | 615 - sdcc/support/sdbinutils/bfd/elf32-sh.c | 7405 -------- sdcc/support/sdbinutils/bfd/elf32-sh64-com.c | 245 - sdcc/support/sdbinutils/bfd/elf32-sh64.c | 813 - sdcc/support/sdbinutils/bfd/elf32-sh64.h | 88 - sdcc/support/sdbinutils/bfd/elf32-sparc.c | 360 - sdcc/support/sdbinutils/bfd/elf32-spu.c | 5512 ------ sdcc/support/sdbinutils/bfd/elf32-spu.h | 125 - sdcc/support/sdbinutils/bfd/elf32-tic6x.c | 4387 ----- sdcc/support/sdbinutils/bfd/elf32-tic6x.h | 42 - sdcc/support/sdbinutils/bfd/elf32-tilegx.c | 134 - sdcc/support/sdbinutils/bfd/elf32-tilegx.h | 38 - sdcc/support/sdbinutils/bfd/elf32-tilepro.c | 3895 ----- sdcc/support/sdbinutils/bfd/elf32-tilepro.h | 38 - sdcc/support/sdbinutils/bfd/elf32-v850.c | 4287 ----- sdcc/support/sdbinutils/bfd/elf32-vax.c | 1947 --- sdcc/support/sdbinutils/bfd/elf32-visium.c | 875 - sdcc/support/sdbinutils/bfd/elf32-wasm32.c | 155 - sdcc/support/sdbinutils/bfd/elf32-xc16x.c | 477 - sdcc/support/sdbinutils/bfd/elf32-xgate.c | 723 - sdcc/support/sdbinutils/bfd/elf32-xgate.h | 142 - sdcc/support/sdbinutils/bfd/elf32-xstormy16.c | 1024 -- sdcc/support/sdbinutils/bfd/elf32-xtensa.c | 11252 ------------ sdcc/support/sdbinutils/bfd/elf32.c | 23 - sdcc/support/sdbinutils/bfd/elf64-alpha.c | 5567 ------ sdcc/support/sdbinutils/bfd/elf64-gen.c | 103 - sdcc/support/sdbinutils/bfd/elf64-hppa.c | 4117 ----- sdcc/support/sdbinutils/bfd/elf64-hppa.h | 51 - sdcc/support/sdbinutils/bfd/elf64-ia64-vms.c | 5621 ------ sdcc/support/sdbinutils/bfd/elf64-mips.c | 4525 ----- sdcc/support/sdbinutils/bfd/elf64-mmix.c | 2925 ---- sdcc/support/sdbinutils/bfd/elf64-ppc.c | 15833 ----------------- sdcc/support/sdbinutils/bfd/elf64-ppc.h | 102 - sdcc/support/sdbinutils/bfd/elf64-s390.c | 3965 ----- sdcc/support/sdbinutils/bfd/elf64-sh64.c | 3977 ----- sdcc/support/sdbinutils/bfd/elf64-sparc.c | 981 -- sdcc/support/sdbinutils/bfd/elf64-tilegx.c | 135 - sdcc/support/sdbinutils/bfd/elf64-tilegx.h | 38 - sdcc/support/sdbinutils/bfd/elf64-x86-64.c | 5421 ------ sdcc/support/sdbinutils/bfd/elf64.c | 23 - sdcc/support/sdbinutils/bfd/elfcore.h | 315 - sdcc/support/sdbinutils/bfd/elflink.c | 14362 --------------- sdcc/support/sdbinutils/bfd/elfn32-mips.c | 3895 ----- sdcc/support/sdbinutils/bfd/elfnn-aarch64.c | 9437 ---------- sdcc/support/sdbinutils/bfd/elfnn-ia64.c | 5123 ------ sdcc/support/sdbinutils/bfd/elfnn-riscv.c | 3547 ---- sdcc/support/sdbinutils/bfd/elfxx-aarch64.c | 662 - sdcc/support/sdbinutils/bfd/elfxx-aarch64.h | 67 - sdcc/support/sdbinutils/bfd/elfxx-ia64.c | 764 - sdcc/support/sdbinutils/bfd/elfxx-ia64.h | 33 - sdcc/support/sdbinutils/bfd/elfxx-mips.c | 16211 ----------------- sdcc/support/sdbinutils/bfd/elfxx-mips.h | 195 - sdcc/support/sdbinutils/bfd/elfxx-riscv.c | 1011 -- sdcc/support/sdbinutils/bfd/elfxx-riscv.h | 33 - sdcc/support/sdbinutils/bfd/elfxx-sparc.c | 5033 ------ sdcc/support/sdbinutils/bfd/elfxx-sparc.h | 146 - sdcc/support/sdbinutils/bfd/elfxx-tilegx.c | 4248 ----- sdcc/support/sdbinutils/bfd/elfxx-tilegx.h | 95 - sdcc/support/sdbinutils/bfd/elfxx-x86.c | 2754 --- sdcc/support/sdbinutils/bfd/elfxx-x86.h | 695 - sdcc/support/sdbinutils/bfd/epoc-pe-arm.c | 38 - sdcc/support/sdbinutils/bfd/epoc-pei-arm.c | 31 - sdcc/support/sdbinutils/bfd/freebsd.h | 106 - sdcc/support/sdbinutils/bfd/gen-aout.c | 120 - sdcc/support/sdbinutils/bfd/go32stub.h | 128 - sdcc/support/sdbinutils/bfd/host-aout.c | 87 - sdcc/support/sdbinutils/bfd/hp300bsd.c | 40 - sdcc/support/sdbinutils/bfd/hp300hpux.c | 855 - sdcc/support/sdbinutils/bfd/hppabsd-core.c | 269 - sdcc/support/sdbinutils/bfd/hpux-core.c | 430 - sdcc/support/sdbinutils/bfd/i386aout.c | 88 - sdcc/support/sdbinutils/bfd/i386bsd.c | 50 - sdcc/support/sdbinutils/bfd/i386dynix.c | 82 - sdcc/support/sdbinutils/bfd/i386freebsd.c | 38 - sdcc/support/sdbinutils/bfd/i386linux.c | 733 - sdcc/support/sdbinutils/bfd/i386lynx.c | 548 - sdcc/support/sdbinutils/bfd/i386mach3.c | 73 - sdcc/support/sdbinutils/bfd/i386msdos.c | 238 - sdcc/support/sdbinutils/bfd/i386netbsd.c | 38 - sdcc/support/sdbinutils/bfd/i386os9k.c | 230 - sdcc/support/sdbinutils/bfd/ieee.c | 3991 ----- sdcc/support/sdbinutils/bfd/irix-core.c | 333 - sdcc/support/sdbinutils/bfd/libbfd-in.h | 862 - sdcc/support/sdbinutils/bfd/libcoff-in.h | 610 - sdcc/support/sdbinutils/bfd/libhppa.h | 594 - sdcc/support/sdbinutils/bfd/libieee.h | 137 - sdcc/support/sdbinutils/bfd/libnlm.h | 222 - sdcc/support/sdbinutils/bfd/liboasys.h | 83 - sdcc/support/sdbinutils/bfd/libpei.h | 371 - sdcc/support/sdbinutils/bfd/libxcoff.h | 260 - sdcc/support/sdbinutils/bfd/lynx-core.c | 226 - sdcc/support/sdbinutils/bfd/m68k4knetbsd.c | 36 - sdcc/support/sdbinutils/bfd/m68klinux.c | 737 - sdcc/support/sdbinutils/bfd/m68knetbsd.c | 38 - sdcc/support/sdbinutils/bfd/m88kmach3.c | 41 - sdcc/support/sdbinutils/bfd/m88kopenbsd.c | 34 - sdcc/support/sdbinutils/bfd/mach-o-aarch64.c | 310 - sdcc/support/sdbinutils/bfd/mach-o-arm.c | 338 - sdcc/support/sdbinutils/bfd/mach-o-i386.c | 416 - sdcc/support/sdbinutils/bfd/mach-o-target.c | 200 - sdcc/support/sdbinutils/bfd/mach-o-x86-64.c | 372 - sdcc/support/sdbinutils/bfd/mach-o.c | 5927 ------- sdcc/support/sdbinutils/bfd/mach-o.h | 768 - sdcc/support/sdbinutils/bfd/mipsbsd.c | 485 - sdcc/support/sdbinutils/bfd/netbsd-core.c | 318 - sdcc/support/sdbinutils/bfd/netbsd.h | 114 - sdcc/support/sdbinutils/bfd/newsos3.c | 43 - sdcc/support/sdbinutils/bfd/nlm-target.h | 265 - sdcc/support/sdbinutils/bfd/nlm.c | 55 - sdcc/support/sdbinutils/bfd/nlm32-alpha.c | 859 - sdcc/support/sdbinutils/bfd/nlm32-i386.c | 429 - sdcc/support/sdbinutils/bfd/nlm32-ppc.c | 986 -- sdcc/support/sdbinutils/bfd/nlm32-sparc.c | 378 - sdcc/support/sdbinutils/bfd/nlm32.c | 22 - sdcc/support/sdbinutils/bfd/nlm64.c | 22 - sdcc/support/sdbinutils/bfd/nlmcode.h | 1982 --- sdcc/support/sdbinutils/bfd/nlmswap.h | 153 - sdcc/support/sdbinutils/bfd/ns32k.h | 30 - sdcc/support/sdbinutils/bfd/ns32knetbsd.c | 53 - sdcc/support/sdbinutils/bfd/oasys.c | 1253 -- sdcc/support/sdbinutils/bfd/osf-core.c | 225 - sdcc/support/sdbinutils/bfd/pc532-mach.c | 108 - sdcc/support/sdbinutils/bfd/pdp11.c | 4543 ----- sdcc/support/sdbinutils/bfd/pe-arm-wince.c | 45 - sdcc/support/sdbinutils/bfd/pe-arm.c | 67 - sdcc/support/sdbinutils/bfd/pe-i386.c | 45 - sdcc/support/sdbinutils/bfd/pe-mcore.c | 41 - sdcc/support/sdbinutils/bfd/pe-mips.c | 924 - sdcc/support/sdbinutils/bfd/pe-ppc.c | 47 - sdcc/support/sdbinutils/bfd/pe-sh.c | 31 - sdcc/support/sdbinutils/bfd/pe-x86_64.c | 120 - sdcc/support/sdbinutils/bfd/peXXigen.c | 4556 ----- sdcc/support/sdbinutils/bfd/pef-traceback.h | 216 - sdcc/support/sdbinutils/bfd/pef.c | 1202 -- sdcc/support/sdbinutils/bfd/pef.h | 187 - sdcc/support/sdbinutils/bfd/pei-arm-wince.c | 31 - sdcc/support/sdbinutils/bfd/pei-arm.c | 55 - sdcc/support/sdbinutils/bfd/pei-i386.c | 45 - sdcc/support/sdbinutils/bfd/pei-ia64.c | 38 - sdcc/support/sdbinutils/bfd/pei-mcore.c | 43 - sdcc/support/sdbinutils/bfd/pei-mips.c | 32 - sdcc/support/sdbinutils/bfd/pei-ppc.c | 50 - sdcc/support/sdbinutils/bfd/pei-sh.c | 35 - sdcc/support/sdbinutils/bfd/pei-x86_64.c | 766 - sdcc/support/sdbinutils/bfd/peicode.h | 1506 -- sdcc/support/sdbinutils/bfd/ppcboot.c | 535 - sdcc/support/sdbinutils/bfd/ptrace-core.c | 217 - sdcc/support/sdbinutils/bfd/reloc16.c | 330 - sdcc/support/sdbinutils/bfd/riscix.c | 652 - sdcc/support/sdbinutils/bfd/rs6000-core.c | 806 - sdcc/support/sdbinutils/bfd/sco5-core.c | 396 - sdcc/support/sdbinutils/bfd/som.c | 6827 -------- sdcc/support/sdbinutils/bfd/som.h | 245 - sdcc/support/sdbinutils/bfd/sparclinux.c | 730 - sdcc/support/sdbinutils/bfd/sparclynx.c | 246 - sdcc/support/sdbinutils/bfd/sparcnetbsd.c | 39 - sdcc/support/sdbinutils/bfd/sunos.c | 2845 --- sdcc/support/sdbinutils/bfd/trad-core.c | 317 - sdcc/support/sdbinutils/bfd/vax1knetbsd.c | 38 - sdcc/support/sdbinutils/bfd/vaxbsd.c | 40 - sdcc/support/sdbinutils/bfd/vaxnetbsd.c | 38 - sdcc/support/sdbinutils/bfd/versados.c | 939 - sdcc/support/sdbinutils/bfd/vms-alpha.c | 9608 ---------- sdcc/support/sdbinutils/bfd/vms-lib.c | 2352 --- sdcc/support/sdbinutils/bfd/vms-misc.c | 672 - sdcc/support/sdbinutils/bfd/vms.h | 142 - sdcc/support/sdbinutils/bfd/wasm-module.c | 839 - sdcc/support/sdbinutils/bfd/wasm-module.h | 52 - sdcc/support/sdbinutils/bfd/xcofflink.c | 6456 ------- sdcc/support/sdbinutils/bfd/xsym.c | 2360 --- sdcc/support/sdbinutils/bfd/xsym.h | 700 - sdcc/support/sdbinutils/bfd/xtensa-isa.c | 1794 -- sdcc/support/sdbinutils/bfd/xtensa-modules.c | 21292 ----------------------- 402 files changed, 5 insertions(+), 515066 deletions(-) delete mode 100644 sdcc/support/sdbinutils/bfd/aix386-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/aix5ppc-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout-adobe.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout-cris.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout-ns32k.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout-sparcle.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout-target.h delete mode 100644 sdcc/support/sdbinutils/bfd/aout-tic30.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout0.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout32.c delete mode 100644 sdcc/support/sdbinutils/bfd/aout64.c delete mode 100644 sdcc/support/sdbinutils/bfd/aoutf1.h delete mode 100644 sdcc/support/sdbinutils/bfd/arc-got.h delete mode 100644 sdcc/support/sdbinutils/bfd/arc-plt.h delete mode 100644 sdcc/support/sdbinutils/bfd/archive64.c delete mode 100644 sdcc/support/sdbinutils/bfd/armnetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/bfd-in.h delete mode 100644 sdcc/support/sdbinutils/bfd/bout.c delete mode 100644 sdcc/support/sdbinutils/bfd/cf-i386lynx.c delete mode 100644 sdcc/support/sdbinutils/bfd/cf-sparclynx.c delete mode 100644 sdcc/support/sdbinutils/bfd/cisco-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-alpha.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-apollo.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-aux.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-go32.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-h8300.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-h8500.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-i860.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-i960.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-ia64.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-m68k.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-m88k.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-mcore.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-ppc.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-rs6000.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-sh.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-sparc.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-stgo32.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-svm68k.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-tic30.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-tic4x.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-tic54x.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-tic80.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-u68k.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-w65.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-we32k.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-x86_64.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-z80.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff-z8k.c delete mode 100644 sdcc/support/sdbinutils/bfd/coff64-rs6000.c delete mode 100644 sdcc/support/sdbinutils/bfd/coffgen.c delete mode 100644 sdcc/support/sdbinutils/bfd/cofflink.c delete mode 100644 sdcc/support/sdbinutils/bfd/coffswap.h delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-aarch64.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-alpha.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-arc.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-avr.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-bfin.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-cr16.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-cr16c.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-cris.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-crx.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-d10v.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-d30v.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-dlx.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-epiphany.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-fr30.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-frv.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-ft32.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-h8300.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-h8500.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-hppa.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-i370.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-i860.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-i960.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-ia64-opc.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-ia64.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-iamcu.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-ip2k.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-iq2000.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-k1om.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-l1om.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-lm32.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m10200.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m10300.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m32c.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m32r.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m68hc11.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m68hc12.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m68k.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m88k.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m9s12x.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-m9s12xg.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-mcore.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-mep.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-metag.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-microblaze.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-mmix.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-moxie.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-msp430.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-mt.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-nds32.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-nios2.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-ns32k.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-or1k.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-pdp11.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-pj.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-powerpc.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-pru.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-riscv.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-rl78.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-rs6000.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-rx.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-s390.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-score.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-sh.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-sparc.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-spu.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tic30.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tic4x.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tic54x.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tic6x.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tic80.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tilegx.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-tilepro.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-v850.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-v850_rh850.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-vax.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-visium.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-w65.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-wasm32.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-we32k.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-xc16x.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-xgate.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-xstormy16.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-xtensa.c delete mode 100644 sdcc/support/sdbinutils/bfd/cpu-z8k.c delete mode 100644 sdcc/support/sdbinutils/bfd/demo64.c delete mode 100644 sdcc/support/sdbinutils/bfd/dwarf1.c delete mode 100644 sdcc/support/sdbinutils/bfd/dwarf2.c delete mode 100644 sdcc/support/sdbinutils/bfd/ecoff.c delete mode 100644 sdcc/support/sdbinutils/bfd/ecofflink.c delete mode 100644 sdcc/support/sdbinutils/bfd/ecoffswap.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf-attrs.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-eh-frame.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-hppa.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf-ifunc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-linux-core.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf-m10200.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-m10300.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-nacl.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-nacl.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf-properties.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-s390-common.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-s390.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf-strtab.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-vxworks.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf-vxworks.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-am33lin.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-arc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-avr.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-avr.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-bfin.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-cr16.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-cr16c.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-cris.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-crx.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-d10v.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-d30v.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-dlx.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-dlx.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-epiphany.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-fr30.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-frv.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-ft32.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-gen.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-h8300.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-hppa.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-hppa.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-i370.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-i860.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-i960.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-ip2k.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-iq2000.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-lm32.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m32c.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m32r.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m68hc11.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m68hc12.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m68hc1x.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m68hc1x.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m68k.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-m88k.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-mcore.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-mep.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-metag.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-metag.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-microblaze.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-moxie.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-msp430.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-mt.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-nds32.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-nds32.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-nios2.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-nios2.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-or1k.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-pj.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-ppc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-ppc.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-pru.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-rl78.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-rx.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-rx.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-s390.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-score.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-score.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-score7.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sh-relocs.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sh-symbian.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sh.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sh64-com.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sh64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sh64.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-sparc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-spu.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-spu.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-tic6x.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-tic6x.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-tilegx.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-tilegx.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-tilepro.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-tilepro.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-v850.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-vax.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-visium.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-wasm32.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-xc16x.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-xgate.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-xgate.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-xstormy16.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32-xtensa.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf32.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-alpha.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-gen.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-hppa.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-hppa.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-ia64-vms.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-mmix.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-ppc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-ppc.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-s390.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-sh64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-sparc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-tilegx.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-tilegx.h delete mode 100644 sdcc/support/sdbinutils/bfd/elf64-x86-64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elf64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfcore.h delete mode 100644 sdcc/support/sdbinutils/bfd/elflink.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfn32-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfnn-aarch64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfnn-ia64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfnn-riscv.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-aarch64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-aarch64.h delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-ia64.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-ia64.h delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-mips.h delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-riscv.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-riscv.h delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-sparc.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-sparc.h delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-tilegx.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-tilegx.h delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-x86.c delete mode 100644 sdcc/support/sdbinutils/bfd/elfxx-x86.h delete mode 100644 sdcc/support/sdbinutils/bfd/epoc-pe-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/epoc-pei-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/freebsd.h delete mode 100644 sdcc/support/sdbinutils/bfd/gen-aout.c delete mode 100644 sdcc/support/sdbinutils/bfd/go32stub.h delete mode 100644 sdcc/support/sdbinutils/bfd/host-aout.c delete mode 100644 sdcc/support/sdbinutils/bfd/hp300bsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/hp300hpux.c delete mode 100644 sdcc/support/sdbinutils/bfd/hppabsd-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/hpux-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386aout.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386bsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386dynix.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386freebsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386linux.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386lynx.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386mach3.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386msdos.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386netbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/i386os9k.c delete mode 100644 sdcc/support/sdbinutils/bfd/ieee.c delete mode 100644 sdcc/support/sdbinutils/bfd/irix-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/libbfd-in.h delete mode 100644 sdcc/support/sdbinutils/bfd/libcoff-in.h delete mode 100644 sdcc/support/sdbinutils/bfd/libhppa.h delete mode 100644 sdcc/support/sdbinutils/bfd/libieee.h delete mode 100644 sdcc/support/sdbinutils/bfd/libnlm.h delete mode 100644 sdcc/support/sdbinutils/bfd/liboasys.h delete mode 100644 sdcc/support/sdbinutils/bfd/libpei.h delete mode 100644 sdcc/support/sdbinutils/bfd/libxcoff.h delete mode 100644 sdcc/support/sdbinutils/bfd/lynx-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/m68k4knetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/m68klinux.c delete mode 100644 sdcc/support/sdbinutils/bfd/m68knetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/m88kmach3.c delete mode 100644 sdcc/support/sdbinutils/bfd/m88kopenbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o-aarch64.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o-target.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o-x86-64.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o.c delete mode 100644 sdcc/support/sdbinutils/bfd/mach-o.h delete mode 100644 sdcc/support/sdbinutils/bfd/mipsbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/netbsd-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/netbsd.h delete mode 100644 sdcc/support/sdbinutils/bfd/newsos3.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm-target.h delete mode 100644 sdcc/support/sdbinutils/bfd/nlm.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm32-alpha.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm32-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm32-ppc.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm32-sparc.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm32.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlm64.c delete mode 100644 sdcc/support/sdbinutils/bfd/nlmcode.h delete mode 100644 sdcc/support/sdbinutils/bfd/nlmswap.h delete mode 100644 sdcc/support/sdbinutils/bfd/ns32k.h delete mode 100644 sdcc/support/sdbinutils/bfd/ns32knetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/oasys.c delete mode 100644 sdcc/support/sdbinutils/bfd/osf-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/pc532-mach.c delete mode 100644 sdcc/support/sdbinutils/bfd/pdp11.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-arm-wince.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-mcore.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-ppc.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-sh.c delete mode 100644 sdcc/support/sdbinutils/bfd/pe-x86_64.c delete mode 100644 sdcc/support/sdbinutils/bfd/peXXigen.c delete mode 100644 sdcc/support/sdbinutils/bfd/pef-traceback.h delete mode 100644 sdcc/support/sdbinutils/bfd/pef.c delete mode 100644 sdcc/support/sdbinutils/bfd/pef.h delete mode 100644 sdcc/support/sdbinutils/bfd/pei-arm-wince.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-arm.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-i386.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-ia64.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-mcore.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-mips.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-ppc.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-sh.c delete mode 100644 sdcc/support/sdbinutils/bfd/pei-x86_64.c delete mode 100644 sdcc/support/sdbinutils/bfd/peicode.h delete mode 100644 sdcc/support/sdbinutils/bfd/ppcboot.c delete mode 100644 sdcc/support/sdbinutils/bfd/ptrace-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/reloc16.c delete mode 100644 sdcc/support/sdbinutils/bfd/riscix.c delete mode 100644 sdcc/support/sdbinutils/bfd/rs6000-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/sco5-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/som.c delete mode 100644 sdcc/support/sdbinutils/bfd/som.h delete mode 100644 sdcc/support/sdbinutils/bfd/sparclinux.c delete mode 100644 sdcc/support/sdbinutils/bfd/sparclynx.c delete mode 100644 sdcc/support/sdbinutils/bfd/sparcnetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/sunos.c delete mode 100644 sdcc/support/sdbinutils/bfd/trad-core.c delete mode 100644 sdcc/support/sdbinutils/bfd/vax1knetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/vaxbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/vaxnetbsd.c delete mode 100644 sdcc/support/sdbinutils/bfd/versados.c delete mode 100644 sdcc/support/sdbinutils/bfd/vms-alpha.c delete mode 100644 sdcc/support/sdbinutils/bfd/vms-lib.c delete mode 100644 sdcc/support/sdbinutils/bfd/vms-misc.c delete mode 100644 sdcc/support/sdbinutils/bfd/vms.h delete mode 100644 sdcc/support/sdbinutils/bfd/wasm-module.c delete mode 100644 sdcc/support/sdbinutils/bfd/wasm-module.h delete mode 100644 sdcc/support/sdbinutils/bfd/xcofflink.c delete mode 100644 sdcc/support/sdbinutils/bfd/xsym.c delete mode 100644 sdcc/support/sdbinutils/bfd/xsym.h delete mode 100644 sdcc/support/sdbinutils/bfd/xtensa-isa.c delete mode 100644 sdcc/support/sdbinutils/bfd/xtensa-modules.c diff --git a/sdcc/ChangeLog b/sdcc/ChangeLog index 4c94f7ff7..042504f7a 100644 --- a/sdcc/ChangeLog +++ b/sdcc/ChangeLog @@ -1,3 +1,8 @@ +2022-03-29 Philipp Klaus Krause + + * support/sdbinutils/bfd/*: + Delete unused files as suggested by Felix Salfelder (felixs). + 2022-03-28 Sebastian 'basxto' Riedel * device/lib/tlcs90/strlen.s: diff --git a/sdcc/support/sdbinutils/bfd/aix386-core.c b/sdcc/support/sdbinutils/bfd/aix386-core.c deleted file mode 100644 index 77d068f12..000000000 --- a/sdcc/support/sdbinutils/bfd/aix386-core.c +++ /dev/null @@ -1,269 +0,0 @@ -/* BFD back-end for AIX on PS/2 core files. - This was based on trad-core.c, which was written by John Gilmore of - Cygnus Support. - Copyright (C) 1988-2018 Free Software Foundation, Inc. - Written by Minh Tran-Le . - Converted to back end form by Ian Lance Taylor . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/i386.h" -#include "coff/internal.h" -#include "libcoff.h" - -#include - -#if defined (_AIX) && defined (_I386) -#define NOCHECKS /* This is for coredump.h. */ -#define _h_USER /* Avoid including user.h from coredump.h. */ -#include -#include -#endif /* _AIX && _I386 */ - -/* Maybe this could work on some other i386 but I have not tried it - * mtranle@paris - Tue Sep 24 12:49:35 1991 - */ - -#ifndef COR_MAGIC -# define COR_MAGIC "core" -#endif - -/* Need this cast because ptr is really void *. */ -#define core_hdr(bfd) \ - (((bfd->tdata.trad_core_data))->hdr) -#define core_section(bfd,n) \ - (((bfd)->tdata.trad_core_data)->sections[n]) -#define core_regsec(bfd) \ - (((bfd)->tdata.trad_core_data)->reg_section) -#define core_reg2sec(bfd) \ - (((bfd)->tdata.trad_core_data)->reg2_section) - -/* These are stored in the bfd's tdata. */ -struct trad_core_struct -{ - struct corehdr *hdr; /* core file header */ - asection *reg_section; - asection *reg2_section; - asection *sections[MAX_CORE_SEGS]; -}; - -static const bfd_target * -aix386_core_file_p (bfd *abfd) -{ - int i, n; - unsigned char longbuf[4]; /* Raw bytes of various header fields */ - bfd_size_type core_size = sizeof (struct corehdr); - bfd_size_type amt; - struct corehdr *core; - struct mergem - { - struct trad_core_struct coredata; - struct corehdr internal_core; - } *mergem; - flagword flags; - - amt = sizeof (longbuf); - if (bfd_bread (longbuf, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return 0; - } - - if (strncmp (longbuf, COR_MAGIC, 4)) - return 0; - - if (bfd_seek (abfd, (file_ptr) 0, 0) != 0) - return 0; - - amt = sizeof (struct mergem); - mergem = (struct mergem *) bfd_zalloc (abfd, amt); - if (mergem == NULL) - return 0; - - core = &mergem->internal_core; - - if ((bfd_bread (core, core_size, abfd)) != core_size) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - loser: - bfd_release (abfd, (char *) mergem); - abfd->tdata.any = NULL; - bfd_section_list_clear (abfd); - return 0; - } - - set_tdata (abfd, &mergem->coredata); - core_hdr (abfd) = core; - - /* Create the sections. */ - flags = SEC_HAS_CONTENTS; - core_regsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg", - flags); - if (core_regsec (abfd) == NULL) - goto loser; - - core_regsec (abfd)->size = sizeof (core->cd_regs); - core_regsec (abfd)->vma = (bfd_vma) -1; - - /* We'll access the regs afresh in the core file, like any section. */ - core_regsec (abfd)->filepos = - (file_ptr) offsetof (struct corehdr, cd_regs[0]); - - flags = SEC_HAS_CONTENTS; - core_reg2sec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg2", - flags); - if (core_reg2sec (abfd) == NULL) - /* bfd_release frees everything allocated after it's arg. */ - goto loser; - - core_reg2sec (abfd)->size = sizeof (core->cd_fpregs); - core_reg2sec (abfd)->vma = (bfd_vma) -1; - core_reg2sec (abfd)->filepos = - (file_ptr) offsetof (struct corehdr, cd_fpregs); - - for (i = 0, n = 0; (i < MAX_CORE_SEGS) && (core->cd_segs[i].cs_type); i++) - { - const char *sname; - flagword flags; - - if (core->cd_segs[i].cs_offset == 0) - continue; - - switch (core->cd_segs[i].cs_type) - { - case COR_TYPE_DATA: - sname = ".data"; - flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; - break; - case COR_TYPE_STACK: - sname = ".stack"; - flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; - break; - case COR_TYPE_LIBDATA: - sname = ".libdata"; - flags = SEC_ALLOC + SEC_HAS_CONTENTS; - break; - case COR_TYPE_WRITE: - sname = ".writeable"; - flags = SEC_ALLOC + SEC_HAS_CONTENTS; - break; - case COR_TYPE_MSC: - sname = ".misc"; - flags = SEC_ALLOC + SEC_HAS_CONTENTS; - break; - default: - sname = ".unknown"; - flags = SEC_ALLOC + SEC_HAS_CONTENTS; - break; - } - core_section (abfd, n) = bfd_make_section_anyway_with_flags (abfd, - sname, - flags); - if (core_section (abfd, n) == NULL) - goto loser; - - core_section (abfd, n)->size = core->cd_segs[i].cs_len; - core_section (abfd, n)->vma = core->cd_segs[i].cs_address; - core_section (abfd, n)->filepos = core->cd_segs[i].cs_offset; - core_section (abfd, n)->alignment_power = 2; - n++; - } - - return abfd->xvec; -} - -static char * -aix386_core_file_failing_command (bfd *abfd) -{ - return core_hdr (abfd)->cd_comm; -} - -static int -aix386_core_file_failing_signal (bfd *abfd) -{ - return core_hdr (abfd)->cd_cursig; -} - -#define aix386_core_file_matches_executable_p generic_core_file_matches_executable_p - -#define aix386_core_file_pid _bfd_nocore_core_file_pid - -/* If somebody calls any byte-swapping routines, shoot them. */ - -static void -swap_abort (void) -{ - /* This way doesn't require any declaration for ANSI to fuck up. */ - abort (); -} - -#define NO_GET ((bfd_vma (*) (const void *)) swap_abort) -#define NO_PUT ((void (*) (bfd_vma, void *)) swap_abort) -#define NO_GETS ((bfd_signed_vma (*) (const void *)) swap_abort) -#define NO_GET64 ((bfd_uint64_t (*) (const void *)) swap_abort) -#define NO_PUT64 ((void (*) (bfd_uint64_t, void *)) swap_abort) -#define NO_GETS64 ((bfd_int64_t (*) (const void *)) swap_abort) - -const bfd_target core_aix386_vec = -{ - "aix386-core", - bfd_target_unknown_flavour, - BFD_ENDIAN_BIG, /* target byte order */ - BFD_ENDIAN_BIG, /* target headers byte order */ - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - 0, /* leading underscore */ - ' ', /* ar_pad_char */ - 16, /* ar_max_namelen */ - 0, /* match priority. */ - NO_GET64, NO_GETS64, NO_PUT64, - NO_GET, NO_GETS, NO_PUT, - NO_GET, NO_GETS, NO_PUT, /* data */ - NO_GET64, NO_GETS64, NO_PUT64, - NO_GET, NO_GETS, NO_PUT, - NO_GET, NO_GETS, NO_PUT, /* hdrs */ - - {_bfd_dummy_target, _bfd_dummy_target, - _bfd_dummy_target, aix386_core_file_p}, - {bfd_false, bfd_false, /* bfd_create_object */ - bfd_false, bfd_false}, - {bfd_false, bfd_false, /* bfd_write_contents */ - bfd_false, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (_bfd_generic), - BFD_JUMP_TABLE_COPY (_bfd_generic), - BFD_JUMP_TABLE_CORE (aix386), - BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), - BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), - BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), - BFD_JUMP_TABLE_WRITE (_bfd_generic), - BFD_JUMP_TABLE_LINK (_bfd_nolink), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - NULL -}; diff --git a/sdcc/support/sdbinutils/bfd/aix5ppc-core.c b/sdcc/support/sdbinutils/bfd/aix5ppc-core.c deleted file mode 100644 index 0922c1842..000000000 --- a/sdcc/support/sdbinutils/bfd/aix5ppc-core.c +++ /dev/null @@ -1,357 +0,0 @@ -/* IBM RS/6000 "XCOFF" back-end for BFD. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - Written by Tom Rix - Contributed by Red Hat Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" - -const bfd_target *xcoff64_core_p (bfd *); -bfd_boolean xcoff64_core_file_matches_executable_p (bfd *, bfd *); -char *xcoff64_core_file_failing_command (bfd *); -int xcoff64_core_file_failing_signal (bfd *); - -#ifdef AIX_5_CORE - -#include "libbfd.h" - -/* Aix 5.1 system include file. */ - -/* Need to define this macro so struct ld_info64 get included. */ -#define __LDINFO_PTRACE64__ -#include -#include - -/* The default architecture and machine for matching core files. */ -#define DEFAULT_ARCHITECTURE bfd_arch_powerpc -#define DEFAULT_MACHINE bfd_mach_ppc_620 - -#define core_hdr(abfd) ((struct core_dumpxx *) abfd->tdata.any) - -#define CHECK_FILE_OFFSET(s, v) \ - ((bfd_signed_vma)(v) < 0 || (bfd_signed_vma)(v) > (bfd_signed_vma)(s).st_size) - -const bfd_target * -xcoff64_core_p (bfd *abfd) -{ - enum bfd_architecture arch; - unsigned long mach; - struct core_dumpxx core, *new_core_hdr; - struct stat statbuf; - asection *sec; - struct __ld_info64 ldinfo; - bfd_vma ld_offset; - bfd_size_type i; - struct vm_infox vminfo; - const bfd_target *return_value = NULL; - flagword flags; - - /* Get the header. */ - if (bfd_seek (abfd, 0, SEEK_SET) != 0) - goto xcoff64_core_p_error; - - if (sizeof (struct core_dumpxx) - != bfd_bread (&core, sizeof (struct core_dumpxx), abfd)) - goto xcoff64_core_p_error; - - if (bfd_stat (abfd, &statbuf) < 0) - goto xcoff64_core_p_error; - - /* Sanity checks - c_flag has CORE_VERSION_1, Aix 4+ - c_entries = 0 for Aix 4.3+ - IS_PROC64 is a macro defined in procinfo.h, test for 64 bit process. - - We will still be confused if a Aix 4.3 64 bit core file is - copied over to a Aix 5 machine. - - Check file header offsets - - See rs6000-core.c for comment on size of core - If there isn't enough of a real core file, bail. */ - - if ((CORE_VERSION_1 != (core.c_flag & CORE_VERSION_1)) - || (0 != core.c_entries) - || (! (IS_PROC64 (&core.c_u.U_proc))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_fdsinfox))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_loader))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_loader + core.c_lsize))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_thr))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_segregion))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_stack))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_stack + core.c_size))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_data))) - || ((CHECK_FILE_OFFSET (statbuf, core.c_data + core.c_datasize))) - || (! (core.c_flag & UBLOCK_VALID)) - || (! (core.c_flag & LE_VALID))) - goto xcoff64_core_p_error; - - /* Check for truncated stack or general truncating. */ - if ((! (core.c_flag & USTACK_VALID)) - || (core.c_flag & CORE_TRUNC)) - { - bfd_set_error (bfd_error_file_truncated); - - return return_value; - } - - new_core_hdr = bfd_zalloc (abfd, sizeof (struct core_dumpxx)); - if (NULL == new_core_hdr) - return return_value; - - memcpy (new_core_hdr, &core, sizeof (struct core_dumpxx)); - /* The core_hdr() macro is no longer used here because it would - expand to code relying on gcc's cast-as-lvalue extension, - which was removed in gcc 4.0. */ - abfd->tdata.any = new_core_hdr; - - /* .stack section. */ - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; - sec = bfd_make_section_anyway_with_flags (abfd, ".stack", flags); - if (NULL == sec) - return return_value; - - sec->size = core.c_size; - sec->vma = core.c_stackorg; - sec->filepos = core.c_stack; - - /* .reg section for all registers. */ - flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY; - sec = bfd_make_section_anyway_with_flags (abfd, ".reg", flags); - if (NULL == sec) - return return_value; - - sec->size = sizeof (struct __context64); - sec->vma = 0; - sec->filepos = 0; - sec->contents = (bfd_byte *)&new_core_hdr->c_flt.r64; - - /* .ldinfo section. - To actually find out how long this section is in this particular - core dump would require going down the whole list of struct - ld_info's. See if we can just fake it. */ - flags = SEC_HAS_CONTENTS; - sec = bfd_make_section_anyway_with_flags (abfd, ".ldinfo", flags); - if (NULL == sec) - return return_value; - - sec->size = core.c_lsize; - sec->vma = 0; - sec->filepos = core.c_loader; - - /* AIX 4 adds data sections from loaded objects to the core file, - which can be found by examining ldinfo, and anonymously mmapped - regions. */ - - /* .data section from executable. */ - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; - sec = bfd_make_section_anyway_with_flags (abfd, ".data", flags); - if (NULL == sec) - return return_value; - - sec->size = core.c_datasize; - sec->vma = core.c_dataorg; - sec->filepos = core.c_data; - - /* .data sections from loaded objects. */ - ld_offset = core.c_loader; - - while (1) - { - if (bfd_seek (abfd, ld_offset, SEEK_SET) != 0) - return return_value; - - if (sizeof (struct __ld_info64) != - bfd_bread (&ldinfo, sizeof (struct __ld_info64), abfd)) - return return_value; - - if (ldinfo.ldinfo_core) - { - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; - sec = bfd_make_section_anyway_with_flags (abfd, ".data", flags); - if (NULL == sec) - return return_value; - - sec->size = ldinfo.ldinfo_datasize; - sec->vma = ldinfo.ldinfo_dataorg; - sec->filepos = ldinfo.ldinfo_core; - } - - if (0 == ldinfo.ldinfo_next) - break; - ld_offset += ldinfo.ldinfo_next; - } - - /* .vmdata sections from anonymously mmapped regions. */ - if (core.c_vmregions) - { - if (bfd_seek (abfd, core.c_vmm, SEEK_SET) != 0) - return return_value; - - for (i = 0; i < core.c_vmregions; i++) - if (sizeof (struct vm_infox) != - bfd_bread (&vminfo, sizeof (struct vm_infox), abfd)) - return return_value; - - if (vminfo.vminfo_offset) - { - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; - sec = bfd_make_section_anyway_with_flags (abfd, ".vmdata", flags); - if (NULL == sec) - return return_value; - - sec->size = vminfo.vminfo_size; - sec->vma = vminfo.vminfo_addr; - sec->filepos = vminfo.vminfo_offset; - } - } - - /* Set the architecture and machine. */ - arch = DEFAULT_ARCHITECTURE; - mach = DEFAULT_MACHINE; - bfd_default_set_arch_mach (abfd, arch, mach); - - return_value = (bfd_target *) abfd->xvec; /* This is garbage for now. */ - - xcoff64_core_p_error: - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - - return return_value; -} - -/* Return `TRUE' if given core is from the given executable. */ - -bfd_boolean -xcoff64_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) -{ - struct core_dumpxx core; - char *path, *s; - size_t alloc; - const char *str1, *str2; - bfd_boolean return_value = FALSE; - - /* Get the header. */ - if (bfd_seek (core_bfd, 0, SEEK_SET) != 0) - return return_value; - - if (sizeof (struct core_dumpxx) != - bfd_bread (&core, sizeof (struct core_dumpxx), core_bfd)) - return return_value; - - if (bfd_seek (core_bfd, core.c_loader, SEEK_SET) != 0) - return return_value; - - alloc = 100; - path = bfd_malloc (alloc); - if (path == NULL) - return return_value; - - s = path; - - while (1) - { - if (bfd_bread (s, 1, core_bfd) != 1) - goto xcoff64_core_file_matches_executable_p_end_1; - - if (*s == '\0') - break; - ++s; - if (s == path + alloc) - { - char *n; - - alloc *= 2; - n = bfd_realloc (path, alloc); - if (n == NULL) - goto xcoff64_core_file_matches_executable_p_end_1; - - s = n + (path - s); - path = n; - } - } - - str1 = strrchr (path, '/'); - str2 = strrchr (exec_bfd->filename, '/'); - - /* Step over character '/'. */ - str1 = str1 != NULL ? str1 + 1 : path; - str2 = str2 != NULL ? str2 + 1 : exec_bfd->filename; - - if (strcmp (str1, str2) == 0) - return_value = TRUE; - - xcoff64_core_file_matches_executable_p_end_1: - free (path); - return return_value; -} - -char * -xcoff64_core_file_failing_command (bfd *abfd) -{ - struct core_dumpxx *c = core_hdr (abfd); - char *return_value = 0; - - if (NULL != c) - return_value = c->c_u.U_proc.pi_comm; - - return return_value; -} - -int -xcoff64_core_file_failing_signal (bfd *abfd) -{ - struct core_dumpxx *c = core_hdr (abfd); - int return_value = 0; - - if (NULL != c) - return_value = c->c_signo; - - return return_value; -} - -#else /* AIX_5_CORE */ - -const bfd_target * -xcoff64_core_p (bfd *abfd ATTRIBUTE_UNUSED) -{ - bfd_set_error (bfd_error_wrong_format); - return 0; -} - -bfd_boolean -xcoff64_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) -{ - return generic_core_file_matches_executable_p (core_bfd, exec_bfd); -} - -char * -xcoff64_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED) -{ - return 0; -} - -int -xcoff64_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED) -{ - return 0; -} - -#endif /* AIX_5_CORE */ diff --git a/sdcc/support/sdbinutils/bfd/aout-adobe.c b/sdcc/support/sdbinutils/bfd/aout-adobe.c deleted file mode 100644 index 4063a8a9c..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-adobe.c +++ /dev/null @@ -1,523 +0,0 @@ -/* BFD back-end for a.out.adobe binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. Based on bout.c. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, 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 "aout/adobe.h" -#include "aout/stab_gnu.h" -#include "libaout.h" /* BFD a.out internal data structures. */ - -/* Forward decl. */ -extern const bfd_target aout_adobe_vec; - -/* Swaps the information in an executable header taken from a raw byte - stream memory image, into the internal exec_header structure. */ - -static void -aout_adobe_swap_exec_header_in (bfd *abfd, - struct external_exec *bytes, - struct internal_exec *execp) -{ - /* Now fill in fields in the execp, from the bytes in the raw data. */ - execp->a_info = H_GET_32 (abfd, bytes->e_info); - execp->a_text = GET_WORD (abfd, bytes->e_text); - execp->a_data = GET_WORD (abfd, bytes->e_data); - execp->a_bss = GET_WORD (abfd, bytes->e_bss); - execp->a_syms = GET_WORD (abfd, bytes->e_syms); - execp->a_entry = GET_WORD (abfd, bytes->e_entry); - execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); - execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); -} - -/* Swaps the information in an internal exec header structure into the - supplied buffer ready for writing to disk. */ - -static void -aout_adobe_swap_exec_header_out (bfd *abfd, - struct internal_exec *execp, - struct external_exec *bytes) -{ - /* Now fill in fields in the raw data, from the fields in the exec - struct. */ - H_PUT_32 (abfd, execp->a_info , bytes->e_info); - PUT_WORD (abfd, execp->a_text , bytes->e_text); - PUT_WORD (abfd, execp->a_data , bytes->e_data); - PUT_WORD (abfd, execp->a_bss , bytes->e_bss); - PUT_WORD (abfd, execp->a_syms , bytes->e_syms); - PUT_WORD (abfd, execp->a_entry , bytes->e_entry); - PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); - PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); -} - -/* Finish up the opening of a b.out file for reading. Fill in all the - fields that are not handled by common code. */ - -static const bfd_target * -aout_adobe_callback (bfd *abfd) -{ - struct internal_exec *execp = exec_hdr (abfd); - asection *sect; - struct external_segdesc ext[1]; - char *section_name; - char try_again[30]; /* Name and number. */ - char *newname; - int trynum; - flagword flags; - - /* Architecture and machine type -- unknown in this format. */ - bfd_set_arch_mach (abfd, bfd_arch_unknown, 0L); - - /* The positions of the string table and symbol table. */ - obj_str_filepos (abfd) = N_STROFF (execp); - obj_sym_filepos (abfd) = N_SYMOFF (execp); - - /* Suck up the section information from the file, one section at a time. */ - for (;;) - { - bfd_size_type amt = sizeof (*ext); - if (bfd_bread ( ext, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - - return NULL; - } - switch (ext->e_type[0]) - { - case N_TEXT: - section_name = ".text"; - flags = SEC_CODE | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS; - break; - - case N_DATA: - section_name = ".data"; - flags = SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS; - break; - - case N_BSS: - section_name = ".bss"; - flags = SEC_DATA | SEC_HAS_CONTENTS; - break; - - case 0: - goto no_more_sections; - - default: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Unknown section type in a.out.adobe file: %x\n"), - abfd, ext->e_type[0]); - goto no_more_sections; - } - - /* First one is called ".text" or whatever; subsequent ones are - ".text1", ".text2", ... */ - bfd_set_error (bfd_error_no_error); - sect = bfd_make_section_with_flags (abfd, section_name, flags); - trynum = 0; - - while (!sect) - { - if (bfd_get_error () != bfd_error_no_error) - /* Some other error -- slide into the sunset. */ - return NULL; - sprintf (try_again, "%s%d", section_name, ++trynum); - sect = bfd_make_section_with_flags (abfd, try_again, flags); - } - - /* Fix the name, if it is a sprintf'd name. */ - if (sect->name == try_again) - { - amt = strlen (sect->name); - newname = bfd_zalloc (abfd, amt); - if (newname == NULL) - return NULL; - strcpy (newname, sect->name); - sect->name = newname; - } - - /* Assumed big-endian. */ - sect->size = ((ext->e_size[0] << 8) - | ext->e_size[1] << 8 - | ext->e_size[2]); - sect->vma = H_GET_32 (abfd, ext->e_virtbase); - sect->filepos = H_GET_32 (abfd, ext->e_filebase); - /* FIXME XXX alignment? */ - - /* Set relocation information for first section of each type. */ - if (trynum == 0) - switch (ext->e_type[0]) - { - case N_TEXT: - sect->rel_filepos = N_TRELOFF (execp); - sect->reloc_count = execp->a_trsize; - break; - - case N_DATA: - sect->rel_filepos = N_DRELOFF (execp); - sect->reloc_count = execp->a_drsize; - break; - - default: - break; - } - } - no_more_sections: - - adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external); - adata (abfd).symbol_entry_size = sizeof (struct external_nlist); - adata (abfd).page_size = 1; /* Not applicable. */ - adata (abfd).segment_size = 1; /* Not applicable. */ - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - - return abfd->xvec; -} - -static const bfd_target * -aout_adobe_object_p (bfd *abfd) -{ - struct internal_exec anexec; - struct external_exec exec_bytes; - char *targ; - bfd_size_type amt = EXEC_BYTES_SIZE; - - if (bfd_bread (& exec_bytes, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - anexec.a_info = H_GET_32 (abfd, exec_bytes.e_info); - - /* Normally we just compare for the magic number. - However, a bunch of Adobe tools aren't fixed up yet; they generate - files using ZMAGIC(!). - If the environment variable GNUTARGET is set to "a.out.adobe", we will - take just about any a.out file as an Adobe a.out file. FIXME! */ - - if (N_BADMAG (&anexec)) - { - targ = getenv ("GNUTARGET"); - if (targ && !strcmp (targ, aout_adobe_vec.name)) - /* Just continue anyway, if specifically set to this format. */ - ; - else - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - } - - aout_adobe_swap_exec_header_in (abfd, &exec_bytes, &anexec); - return aout_32_some_aout_object_p (abfd, &anexec, aout_adobe_callback); -} - -struct bout_data_struct -{ - struct aoutdata a; - struct internal_exec e; -}; - -static bfd_boolean -aout_adobe_mkobject (bfd *abfd) -{ - struct bout_data_struct *rawptr; - bfd_size_type amt = sizeof (struct bout_data_struct); - - rawptr = bfd_zalloc (abfd, amt); - if (rawptr == NULL) - return FALSE; - - abfd->tdata.bout_data = rawptr; - exec_hdr (abfd) = &rawptr->e; - - adata (abfd).reloc_entry_size = sizeof (struct reloc_std_external); - adata (abfd).symbol_entry_size = sizeof (struct external_nlist); - adata (abfd).page_size = 1; /* Not applicable. */ - adata (abfd).segment_size = 1; /* Not applicable. */ - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - - return TRUE; -} - -static void -aout_adobe_write_section (bfd *abfd ATTRIBUTE_UNUSED, - sec_ptr sect ATTRIBUTE_UNUSED) -{ - /* FIXME XXX. */ -} - -static bfd_boolean -aout_adobe_write_object_contents (bfd *abfd) -{ - struct external_exec swapped_hdr; - static struct external_segdesc sentinel[1]; /* Initialized to zero. */ - asection *sect; - bfd_size_type amt; - - exec_hdr (abfd)->a_info = ZMAGIC; - - /* Calculate text size as total of text sections, etc. */ - exec_hdr (abfd)->a_text = 0; - exec_hdr (abfd)->a_data = 0; - exec_hdr (abfd)->a_bss = 0; - exec_hdr (abfd)->a_trsize = 0; - exec_hdr (abfd)->a_drsize = 0; - - for (sect = abfd->sections; sect; sect = sect->next) - { - if (sect->flags & SEC_CODE) - { - exec_hdr (abfd)->a_text += sect->size; - exec_hdr (abfd)->a_trsize += sect->reloc_count * - sizeof (struct reloc_std_external); - } - else if (sect->flags & SEC_DATA) - { - exec_hdr (abfd)->a_data += sect->size; - exec_hdr (abfd)->a_drsize += sect->reloc_count * - sizeof (struct reloc_std_external); - } - else if (sect->flags & SEC_ALLOC && !(sect->flags & SEC_LOAD)) - exec_hdr (abfd)->a_bss += sect->size; - } - - exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd) - * sizeof (struct external_nlist); - exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); - - aout_adobe_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr); - - amt = EXEC_BYTES_SIZE; - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 - || bfd_bwrite (& swapped_hdr, amt, abfd) != amt) - return FALSE; - - /* Now write out the section information. Text first, data next, rest - afterward. */ - for (sect = abfd->sections; sect; sect = sect->next) - if (sect->flags & SEC_CODE) - aout_adobe_write_section (abfd, sect); - - for (sect = abfd->sections; sect; sect = sect->next) - if (sect->flags & SEC_DATA) - aout_adobe_write_section (abfd, sect); - - for (sect = abfd->sections; sect; sect = sect->next) - if (!(sect->flags & (SEC_CODE | SEC_DATA))) - aout_adobe_write_section (abfd, sect); - - /* Write final `sentinel` section header (with type of 0). */ - amt = sizeof (*sentinel); - if (bfd_bwrite (sentinel, amt, abfd) != amt) - return FALSE; - - /* Now write out reloc info, followed by syms and strings. */ - if (bfd_get_symcount (abfd) != 0) - { - if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (exec_hdr (abfd))), SEEK_SET) - != 0) - return FALSE; - - if (! aout_32_write_syms (abfd)) - return FALSE; - - if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (exec_hdr (abfd))), SEEK_SET) - != 0) - return FALSE; - - for (sect = abfd->sections; sect; sect = sect->next) - if (sect->flags & SEC_CODE) - if (!aout_32_squirt_out_relocs (abfd, sect)) - return FALSE; - - if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (exec_hdr (abfd))), SEEK_SET) - != 0) - return FALSE; - - for (sect = abfd->sections; sect; sect = sect->next) - if (sect->flags & SEC_DATA) - if (!aout_32_squirt_out_relocs (abfd, sect)) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -aout_adobe_set_section_contents (bfd *abfd, - asection *section, - const void * location, - file_ptr offset, - bfd_size_type count) -{ - file_ptr section_start; - sec_ptr sect; - - /* Set by bfd.c handler. */ - if (! abfd->output_has_begun) - { - /* Assign file offsets to sections. Text sections are first, and - are contiguous. Then data sections. Everything else at the end. */ - section_start = N_TXTOFF (0); - - for (sect = abfd->sections; sect; sect = sect->next) - { - if (sect->flags & SEC_CODE) - { - sect->filepos = section_start; - /* FIXME: Round to alignment. */ - section_start += sect->size; - } - } - - for (sect = abfd->sections; sect; sect = sect->next) - { - if (sect->flags & SEC_DATA) - { - sect->filepos = section_start; - /* FIXME: Round to alignment. */ - section_start += sect->size; - } - } - - for (sect = abfd->sections; sect; sect = sect->next) - { - if (sect->flags & SEC_HAS_CONTENTS && - !(sect->flags & (SEC_CODE | SEC_DATA))) - { - sect->filepos = section_start; - /* FIXME: Round to alignment. */ - section_start += sect->size; - } - } - } - - /* Regardless, once we know what we're doing, we might as well get - going. */ - if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) - return FALSE; - - if (count == 0) - return TRUE; - - return bfd_bwrite (location, count, abfd) == count; -} - -static bfd_boolean -aout_adobe_set_arch_mach (bfd *abfd, - enum bfd_architecture arch, - unsigned long machine) -{ - if (! bfd_default_set_arch_mach (abfd, arch, machine)) - return FALSE; - - if (arch == bfd_arch_unknown - || arch == bfd_arch_m68k) - return TRUE; - - return FALSE; -} - -static int -aout_adobe_sizeof_headers (bfd *ignore_abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - return sizeof (struct internal_exec); -} - -/* Build the transfer vector for Adobe A.Out files. */ - -#define aout_32_find_line _bfd_nosymbols_find_line -#define aout_32_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string -#define aout_32_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol -#define aout_32_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup -#define aout_32_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup -#define aout_32_close_and_cleanup aout_32_bfd_free_cached_info -#define aout_32_set_arch_mach aout_adobe_set_arch_mach -#define aout_32_set_section_contents aout_adobe_set_section_contents -#define aout_32_sizeof_headers aout_adobe_sizeof_headers -#define aout_32_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents -#define aout_32_get_section_contents_in_window _bfd_generic_get_section_contents_in_window -#define aout_32_bfd_relax_section bfd_generic_relax_section -#define aout_32_bfd_gc_sections bfd_generic_gc_sections -#define aout_32_bfd_lookup_section_flags bfd_generic_lookup_section_flags -#define aout_32_bfd_merge_sections bfd_generic_merge_sections -#define aout_32_bfd_is_group_section bfd_generic_is_group_section -#define aout_32_bfd_discard_group bfd_generic_discard_group -#define aout_32_section_already_linked _bfd_generic_section_already_linked -#define aout_32_bfd_define_common_symbol bfd_generic_define_common_symbol -#define aout_32_bfd_define_start_stop bfd_generic_define_start_stop -#define aout_32_bfd_link_hash_table_create _bfd_generic_link_hash_table_create -#define aout_32_bfd_link_add_symbols _bfd_generic_link_add_symbols -#define aout_32_bfd_link_just_syms _bfd_generic_link_just_syms -#define aout_32_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type -#define aout_32_bfd_final_link _bfd_generic_final_link -#define aout_32_bfd_link_split_section _bfd_generic_link_split_section -#define aout_32_bfd_link_check_relocs _bfd_generic_link_check_relocs -#define aout_32_set_reloc _bfd_generic_set_reloc - -const bfd_target aout_adobe_vec = -{ - "a.out.adobe", /* Name. */ - bfd_target_aout_flavour, - BFD_ENDIAN_BIG, /* Data byte order is unknown (big assumed). */ - BFD_ENDIAN_BIG, /* Header byte order is big. */ - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - /* section flags */ - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_DATA | SEC_RELOC), - '_', /* Symbol leading char. */ - ' ', /* AR_pad_char. */ - 16, /* AR_max_namelen. */ - 0, /* match priority. */ - - 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, aout_adobe_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, aout_adobe_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, aout_adobe_write_object_contents,/* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (aout_32), - BFD_JUMP_TABLE_COPY (_bfd_generic), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), - BFD_JUMP_TABLE_SYMBOLS (aout_32), - BFD_JUMP_TABLE_RELOCS (aout_32), - BFD_JUMP_TABLE_WRITE (aout_32), - BFD_JUMP_TABLE_LINK (aout_32), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - NULL -}; diff --git a/sdcc/support/sdbinutils/bfd/aout-arm.c b/sdcc/support/sdbinutils/bfd/aout-arm.c deleted file mode 100644 index ac05b93d1..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-arm.c +++ /dev/null @@ -1,548 +0,0 @@ -/* BFD back-end for raw ARM a.out binaries. - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" - -/* Avoid multiple definitions from aoutx if supporting standard a.out - as well as our own. */ -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define NAME(x,y) CONCAT3 (aoutarm,_32_,y) - -#define N_TXTADDR(x) \ - ((N_MAGIC (x) == NMAGIC) \ - ? (bfd_vma) 0x8000 \ - : ((N_MAGIC (x) != ZMAGIC) \ - ? (bfd_vma) 0 \ - : ((N_SHARED_LIB (x)) \ - ? ((x)->a_entry & ~(bfd_vma) (TARGET_PAGE_SIZE - 1)) \ - : (bfd_vma) TEXT_START_ADDR))) - -#define TEXT_START_ADDR 0x8000 -#define TARGET_PAGE_SIZE 0x8000 -#define SEGMENT_SIZE TARGET_PAGE_SIZE -#define DEFAULT_ARCH bfd_arch_arm - -#define MY(OP) CONCAT2 (arm_aout_,OP) -#define N_BADMAG(x) ((((x)->a_info & ~007200) != ZMAGIC) && \ - (((x)->a_info & ~006000) != OMAGIC) && \ - ((x)->a_info != NMAGIC)) -#define N_MAGIC(x) ((x)->a_info & ~07200) - -#define MY_bfd_reloc_type_lookup arm_aout_bfd_reloc_type_lookup -#define MY_bfd_reloc_name_lookup arm_aout_bfd_reloc_name_lookup - -#include "libaout.h" -#include "aout/aout64.h" - - -static bfd_reloc_status_type - MY (fix_pcrel_26) (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type - MY (fix_pcrel_26_done) (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -reloc_howto_type MY (howto_table)[] = -{ - /* Type rs size bsz pcrel bitpos ovrf sf name part_inpl - readmask setmask pcdone. */ - HOWTO (0, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "8", TRUE, - 0x000000ff, 0x000000ff, FALSE), - HOWTO (1, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "16", TRUE, - 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (2, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "32", TRUE, - 0xffffffff, 0xffffffff, FALSE), - HOWTO (3, 2, 2, 26, TRUE, 0, complain_overflow_signed, MY (fix_pcrel_26), - "ARM26", TRUE, 0x00ffffff, 0x00ffffff, TRUE), - HOWTO (4, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "DISP8", TRUE, - 0x000000ff, 0x000000ff, TRUE), - HOWTO (5, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "DISP16", TRUE, - 0x0000ffff, 0x0000ffff, TRUE), - HOWTO (6, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "DISP32", TRUE, - 0xffffffff, 0xffffffff, TRUE), - HOWTO (7, 2, 2, 26, FALSE, 0, complain_overflow_signed, - MY (fix_pcrel_26_done), "ARM26D", TRUE, 0x0, 0x0, - FALSE), - EMPTY_HOWTO (-1), - HOWTO (9, 0, -1, 16, FALSE, 0, complain_overflow_bitfield, 0, "NEG16", TRUE, - 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (10, 0, -2, 32, FALSE, 0, complain_overflow_bitfield, 0, "NEG32", TRUE, - 0xffffffff, 0xffffffff, FALSE) -}; - -#define RELOC_ARM_BITS_NEG_BIG ((unsigned int) 0x08) -#define RELOC_ARM_BITS_NEG_LITTLE ((unsigned int) 0x10) - -static reloc_howto_type * -MY (reloc_howto) (bfd *abfd, - struct reloc_std_external *rel, - int *r_index, - int *r_extern, - int *r_pcrel) -{ - unsigned int r_length; - unsigned int r_pcrel_done; - unsigned int r_neg; - int howto_index; - - *r_pcrel = 0; - if (bfd_header_big_endian (abfd)) - { - *r_index = ((rel->r_index[0] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[2]); - *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); - r_pcrel_done = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); - r_neg = (0 != (rel->r_type[0] & RELOC_ARM_BITS_NEG_BIG)); - r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) - >> RELOC_STD_BITS_LENGTH_SH_BIG); - } - else - { - *r_index = ((rel->r_index[2] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[0]); - *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); - r_pcrel_done = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); - r_neg = (0 != (rel->r_type[0] & RELOC_ARM_BITS_NEG_LITTLE)); - r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) - >> RELOC_STD_BITS_LENGTH_SH_LITTLE); - } - howto_index = r_length + 4 * r_pcrel_done + 8 * r_neg; - if (howto_index == 3) - *r_pcrel = 1; - - return MY (howto_table) + howto_index; -} - -#define MY_reloc_howto(BFD, REL, IN, EX, PC) \ - MY (reloc_howto) (BFD, REL, &IN, &EX, &PC) - -static void -MY (put_reloc) (bfd *abfd, - int r_extern, - int r_index, - bfd_vma value, - reloc_howto_type *howto, - struct reloc_std_external *reloc) -{ - unsigned int r_length; - int r_pcrel; - int r_neg; - - PUT_WORD (abfd, value, reloc->r_address); - /* Size as a power of two. */ - r_length = howto->size; - - /* Special case for branch relocations. */ - if (howto->type == 3 || howto->type == 7) - r_length = 3; - - r_pcrel = howto->type & 4; /* PC Relative done? */ - r_neg = howto->type & 8; /* Negative relocation. */ - - if (bfd_header_big_endian (abfd)) - { - reloc->r_index[0] = r_index >> 16; - reloc->r_index[1] = r_index >> 8; - reloc->r_index[2] = r_index; - reloc->r_type[0] = - ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) - | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) - | (r_neg ? RELOC_ARM_BITS_NEG_BIG : 0) - | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); - } - else - { - reloc->r_index[2] = r_index >> 16; - reloc->r_index[1] = r_index >> 8; - reloc->r_index[0] = r_index; - reloc->r_type[0] = - ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) - | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) - | (r_neg ? RELOC_ARM_BITS_NEG_LITTLE : 0) - | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); - } -} - -#define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \ - MY (put_reloc) (BFD, EXT, IDX, VAL, HOWTO, RELOC) - -static void -MY (relocatable_reloc) (reloc_howto_type *howto, - bfd *abfd, - struct reloc_std_external *reloc, - bfd_vma *amount, - bfd_vma r_addr) -{ - if (howto->type == 3) - { - if (reloc->r_type[0] - & (bfd_header_big_endian (abfd) - ? RELOC_STD_BITS_EXTERN_BIG : RELOC_STD_BITS_EXTERN_LITTLE)) - /* The reloc is still external, so don't modify anything. */ - *amount = 0; - else - { - *amount -= r_addr; - /* Change the r_pcrel value -- on the ARM, this bit is set once the - relocation is done. */ - if (bfd_header_big_endian (abfd)) - reloc->r_type[0] |= RELOC_STD_BITS_PCREL_BIG; - else - reloc->r_type[0] |= RELOC_STD_BITS_PCREL_LITTLE; - } - } - else if (howto->type == 7) - *amount = 0; -} - -#define MY_relocatable_reloc(HOW, BFD, REL, AMOUNT, ADDR) \ - MY (relocatable_reloc) (HOW, BFD, REL, &(AMOUNT), ADDR) - -static bfd_reloc_status_type -MY (fix_pcrel_26_done) (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This is dead simple at present. */ - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -MY (fix_pcrel_26) (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - bfd_size_type addr = reloc_entry->address; - bfd_vma target = bfd_get_32 (abfd, (bfd_byte *) data + addr); - bfd_reloc_status_type flag = bfd_reloc_ok; - - /* If this is an undefined symbol, return error. */ - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0) - return output_bfd ? bfd_reloc_ok : bfd_reloc_undefined; - - /* If the sections are different, and we are doing a partial relocation, - just ignore it for now. */ - if (symbol->section->name != input_section->name - && output_bfd != NULL) - return bfd_reloc_ok; - - relocation = (target & 0x00ffffff) << 2; - relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend. */ - relocation += symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - relocation -= input_section->output_section->vma; - relocation -= input_section->output_offset; - relocation -= addr; - if (relocation & 3) - return bfd_reloc_overflow; - - /* Check for overflow. */ - if (relocation & 0x02000000) - { - if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff) - flag = bfd_reloc_overflow; - } - else if (relocation & ~ (bfd_vma) 0x03ffffff) - flag = bfd_reloc_overflow; - - target &= ~ (bfd_vma) 0x00ffffff; - target |= (relocation >> 2) & 0x00ffffff; - bfd_put_32 (abfd, target, (bfd_byte *) data + addr); - - /* Now the ARM magic... Change the reloc type so that it is marked as done. - Strictly this is only necessary if we are doing a partial relocation. */ - reloc_entry->howto = &MY (howto_table)[7]; - - return flag; -} - -static reloc_howto_type * -MY (bfd_reloc_type_lookup) (bfd *abfd, - bfd_reloc_code_real_type code) -{ -#define ASTD(i,j) case i: return & MY (howto_table)[j] - - if (code == BFD_RELOC_CTOR) - switch (bfd_arch_bits_per_address (abfd)) - { - case 32: - code = BFD_RELOC_32; - break; - default: - return NULL; - } - - switch (code) - { - ASTD (BFD_RELOC_16, 1); - ASTD (BFD_RELOC_32, 2); - ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3); - ASTD (BFD_RELOC_8_PCREL, 4); - ASTD (BFD_RELOC_16_PCREL, 5); - ASTD (BFD_RELOC_32_PCREL, 6); - default: - return NULL; - } -} - -static reloc_howto_type * -MY (bfd_reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (MY (howto_table)) / sizeof (MY (howto_table)[0]); - i++) - if (MY (howto_table)[i].name != NULL - && strcasecmp (MY (howto_table)[i].name, r_name) == 0) - return &MY (howto_table)[i]; - - return NULL; -} - -#define MY_swap_std_reloc_in MY (swap_std_reloc_in) -#define MY_swap_std_reloc_out MY (swap_std_reloc_out) -#define MY_get_section_contents _bfd_generic_get_section_contents - -void MY_swap_std_reloc_in (bfd *, struct reloc_std_external *, arelent *, asymbol **, bfd_size_type); -void MY_swap_std_reloc_out (bfd *, arelent *, struct reloc_std_external *); - -#include "aoutx.h" - -void -MY_swap_std_reloc_in (bfd *abfd, - struct reloc_std_external *bytes, - arelent *cache_ptr, - asymbol **symbols, - bfd_size_type symcount ATTRIBUTE_UNUSED) -{ - int r_index; - int r_extern; - int r_pcrel; - struct aoutdata *su = &(abfd->tdata.aout_data->a); - - cache_ptr->address = H_GET_32 (abfd, bytes->r_address); - - cache_ptr->howto = MY_reloc_howto (abfd, bytes, r_index, r_extern, r_pcrel); - - MOVE_ADDRESS (0); -} - -void -MY_swap_std_reloc_out (bfd *abfd, - arelent *g, - struct reloc_std_external *natptr) -{ - int r_index; - asymbol *sym = *(g->sym_ptr_ptr); - int r_extern; - int r_length; - int r_pcrel; - int r_neg = 0; /* Negative relocs use the BASEREL bit. */ - asection *output_section = sym->section->output_section; - - PUT_WORD (abfd, g->address, natptr->r_address); - - r_length = g->howto->size ; /* Size as a power of two. */ - if (r_length < 0) - { - r_length = -r_length; - r_neg = 1; - } - - r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ - - /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the - relocation has been done already (Only for the 26-bit one I think). */ - if (g->howto->type == 3) - { - r_length = 3; - r_pcrel = 0; - } - else if (g->howto->type == 7) - { - r_length = 3; - r_pcrel = 1; - } - - /* Name was clobbered by aout_write_syms to be symbol index. */ - - /* If this relocation is relative to a symbol then set the - r_index to the symbols index, and the r_extern bit. - - Absolute symbols can come in in two ways, either as an offset - from the abs section, or as a symbol which has an abs value. - check for that here. */ - - if (bfd_is_com_section (output_section) - || bfd_is_abs_section (output_section) - || bfd_is_und_section (output_section)) - { - if (bfd_abs_section_ptr->symbol == sym) - { - /* Whoops, looked like an abs symbol, but is really an offset - from the abs section. */ - r_index = 0; - r_extern = 0; - } - else - { - /* Fill in symbol. */ - r_extern = 1; - r_index = (*(g->sym_ptr_ptr))->KEEPIT; - } - } - else - { - /* Just an ordinary section. */ - r_extern = 0; - r_index = output_section->target_index; - } - - /* Now the fun stuff. */ - if (bfd_header_big_endian (abfd)) - { - natptr->r_index[0] = r_index >> 16; - natptr->r_index[1] = r_index >> 8; - natptr->r_index[2] = r_index; - natptr->r_type[0] = - ( (r_extern ? RELOC_STD_BITS_EXTERN_BIG: 0) - | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG: 0) - | (r_neg ? RELOC_ARM_BITS_NEG_BIG: 0) - | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); - } - else - { - natptr->r_index[2] = r_index >> 16; - natptr->r_index[1] = r_index >> 8; - natptr->r_index[0] = r_index; - natptr->r_type[0] = - ( (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE: 0) - | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE: 0) - | (r_neg ? RELOC_ARM_BITS_NEG_LITTLE: 0) - | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); - } -} - -#define MY_BFD_TARGET - -#include "aout-target.h" - -extern const bfd_target arm_aout_be_vec; - -const bfd_target arm_aout_le_vec = -{ - "a.out-arm-little", /* Name. */ - bfd_target_aout_flavour, - BFD_ENDIAN_LITTLE, /* Target byte order (little). */ - BFD_ENDIAN_LITTLE, /* Target headers byte order (little). */ - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - MY_symbol_leading_char, - AR_PAD_CHAR, /* AR_pad_char. */ - 15, /* AR_max_namelen. */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Headers. */ - {_bfd_dummy_target, MY_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, MY_core_file_p}, - {bfd_false, MY_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, MY_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (MY), - BFD_JUMP_TABLE_COPY (MY), - BFD_JUMP_TABLE_CORE (MY), - BFD_JUMP_TABLE_ARCHIVE (MY), - BFD_JUMP_TABLE_SYMBOLS (MY), - BFD_JUMP_TABLE_RELOCS (MY), - BFD_JUMP_TABLE_WRITE (MY), - BFD_JUMP_TABLE_LINK (MY), - BFD_JUMP_TABLE_DYNAMIC (MY), - - & arm_aout_be_vec, - - (void *) MY_backend_data, -}; - -const bfd_target arm_aout_be_vec = -{ - "a.out-arm-big", /* Name. */ - bfd_target_aout_flavour, - BFD_ENDIAN_BIG, /* Target byte order (big). */ - BFD_ENDIAN_BIG, /* Target headers byte order (big). */ - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - MY_symbol_leading_char, - AR_PAD_CHAR, /* AR_pad_char. */ - 15, /* AR_max_namelen. */ - 0, /* match priority. */ - 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, MY_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, MY_core_file_p}, - {bfd_false, MY_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, MY_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (MY), - BFD_JUMP_TABLE_COPY (MY), - BFD_JUMP_TABLE_CORE (MY), - BFD_JUMP_TABLE_ARCHIVE (MY), - BFD_JUMP_TABLE_SYMBOLS (MY), - BFD_JUMP_TABLE_RELOCS (MY), - BFD_JUMP_TABLE_WRITE (MY), - BFD_JUMP_TABLE_LINK (MY), - BFD_JUMP_TABLE_DYNAMIC (MY), - - & arm_aout_le_vec, - - (void *) MY_backend_data, -}; diff --git a/sdcc/support/sdbinutils/bfd/aout-cris.c b/sdcc/support/sdbinutils/bfd/aout-cris.c deleted file mode 100644 index d1a236650..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-cris.c +++ /dev/null @@ -1,292 +0,0 @@ -/* BFD backend for CRIS a.out binaries. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Axis Communications AB. - Written by Hans-Peter Nilsson. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* See info in the file PORTING for documentation of these macros and - functions. Beware; some of the information there is outdated. */ - -#define N_HEADER_IN_TEXT(x) 0 -#define N_TXTOFF(x) 32 -#define ENTRY_CAN_BE_ZERO -#define TEXT_START_ADDR 0 - -/* Without reading symbols to get the text start symbol, there is no way - to know where the text segment starts in an a.out file. Defaulting to - anything as constant as TEXT_START_ADDR is bad. But we can guess from - the entry point, which is usually within the first 64k of the text - segment. We also assume here that the text segment is 64k-aligned. - FIXME: It is also wrong to assume that data and bss follow immediately - after text, but with those, we don't have any choice besides reading - symbol info, and luckily there's no pressing need for correctness for - those vma:s at this time. */ -#define N_TXTADDR(x) ((x)->a_entry & ~(bfd_vma) 0xffff) - -/* If you change this to 4, you can not link to an address N*4+2. */ -#define SEGMENT_SIZE 2 - -/* For some reason, if the a.out file has Z_MAGIC, then - adata(abfd).exec_bytes_size is not used, but rather - adata(abfd).zmagic_disk_block_size, even though the exec_header is - *not* included in the text segment. A simple workaround is to - #define ZMAGIC_DISK_BLOCK_SIZE, which is used if defined; otherwise - TARGET_PAGE_SIZE is used. */ -#define ZMAGIC_DISK_BLOCK_SIZE N_TXTOFF (0) - -/* It seems odd at first to set a page-size this low, but gives greater - freedom in where things can be linked. The drawback is that you have - to set alignment and padding in linker scripts. */ -#define TARGET_PAGE_SIZE SEGMENT_SIZE -#define TARGETNAME "a.out-cris" - -/* The definition here seems not used; just provided as a convention. */ -#define DEFAULT_ARCH bfd_arch_cris - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (cris_aout_,OP) -#define NAME(x, y) CONCAT3 (cris_aout,_32_,y) - -#include "sysdep.h" -#include "bfd.h" - -/* Version 1 of the header. */ -#define MY_exec_hdr_flags 1 - -#define MY_write_object_contents MY (write_object_contents) -static bfd_boolean MY (write_object_contents) (bfd *); - -/* Forward this, so we can use a pointer to it in PARAMS. */ -struct reloc_ext_external; - -#define MY_swap_ext_reloc_out MY (swap_ext_reloc_out) -static void MY (swap_ext_reloc_out) (bfd *, arelent *, struct reloc_ext_external *); - -#define MY_swap_ext_reloc_in MY (swap_ext_reloc_in) -static void MY (swap_ext_reloc_in) (bfd *, struct reloc_ext_external *, - arelent *, asymbol **, bfd_size_type); - -#define MY_set_sizes MY (set_sizes) -static bfd_boolean MY (set_sizes) (bfd *); - -/* To set back reloc_size to ext, we make MY (set_sizes) be called - through this construct. Note that MY_set_arch_mach is only called - through SET_ARCH_MACH. The default bfd_default_set_arch_mach will - not call set_sizes. */ - -#define MY_set_arch_mach NAME (aout, set_arch_mach) -#define SET_ARCH_MACH(BFD, EXECP) \ - MY_set_arch_mach (BFD, DEFAULT_ARCH, N_MACHTYPE (EXECP)) - -/* These macros describe the binary layout of the reloc information we - use in a file. */ -#define RELOC_EXT_BITS_EXTERN_LITTLE 0x80 -#define RELOC_EXT_BITS_TYPE_LITTLE 3 -#define RELOC_EXT_BITS_TYPE_SH_LITTLE 0 - -#ifndef MY_get_section_contents -#define MY_get_section_contents aout_32_get_section_contents -#endif - -#define MACHTYPE_OK(mtype) ((mtype) == M_CRIS) - -/* Include generic functions (some are overridden above). */ -#include "aout32.c" -#include "aout-target.h" - -/* We need our own version to set header flags. */ - -static bfd_boolean -MY (write_object_contents) (bfd *abfd) -{ - struct external_exec exec_bytes; - struct internal_exec *execp = exec_hdr (abfd); - - /* We set the reloc type to RELOC_EXT_SIZE, although setting it at all - seems unnecessary when inspecting as and ld behavior (not an - exhaustive inspection). The default write_object_contents - definition sets RELOC_EXT_SIZE, so we follow suite and set it too. */ - obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; - - /* Setting N_SET_MACHTYPE and using N_SET_FLAGS is not performed by - the default definition. */ - if (bfd_get_arch (abfd) == bfd_arch_cris) - N_SET_MACHTYPE (execp, M_CRIS); - - N_SET_FLAGS (execp, aout_backend_info (abfd)->exec_hdr_flags); - - WRITE_HEADERS (abfd, execp); - - return TRUE; -} - -/* We need our own for these reasons: - - Assert that a normal 8, 16 or 32 reloc is output. - - Fix what seems to be a weak-bug (perhaps there for valid reasons). */ - -static void -MY (swap_ext_reloc_out) (bfd *abfd, - arelent *g, - struct reloc_ext_external *natptr) -{ - int r_index; - int r_extern; - unsigned int r_type; - bfd_vma r_addend; - asymbol *sym = *(g->sym_ptr_ptr); - asection *output_section = sym->section->output_section; - - PUT_WORD (abfd, g->address, natptr->r_address); - - r_type = (unsigned int) g->howto->type; - - r_addend = g->addend; - if ((sym->flags & BSF_SECTION_SYM) != 0) - r_addend += (*(g->sym_ptr_ptr))->section->output_section->vma; - - /* If this relocation is relative to a symbol then set the - r_index to the symbols index, and the r_extern bit. - - Absolute symbols can come in in two ways, either as an offset - from the abs section, or as a symbol which has an abs value. - check for that here. */ - - if (bfd_is_abs_section (bfd_get_section (sym))) - { - r_extern = 0; - r_index = N_ABS; - } - else if ((sym->flags & BSF_SECTION_SYM) == 0) - { - if (bfd_is_und_section (bfd_get_section (sym)) - /* Remember to check for weak symbols; they count as global. */ - || (sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0) - r_extern = 1; - else - r_extern = 0; - r_index = (*(g->sym_ptr_ptr))->KEEPIT; - } - else - { - /* Just an ordinary section. */ - r_extern = 0; - r_index = output_section->target_index; - } - - /* The relocation type is the same as the canonical ones, but only - the first 3 are used: RELOC_8, RELOC_16, RELOC_32. - We may change this later, but assert this for the moment. */ - if (r_type > 2) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Invalid relocation type exported: %d"), - abfd, r_type); - - bfd_set_error (bfd_error_wrong_format); - } - - /* Now the fun stuff. */ - natptr->r_index[2] = r_index >> 16; - natptr->r_index[1] = r_index >> 8; - natptr->r_index[0] = r_index; - natptr->r_type[0] = - (r_extern ? RELOC_EXT_BITS_EXTERN_LITTLE : 0) - | (r_type << RELOC_EXT_BITS_TYPE_SH_LITTLE); - - PUT_WORD (abfd, r_addend, natptr->r_addend); -} - -/* We need our own to assert that a normal 8, 16 or 32 reloc is input. */ - -static void -MY (swap_ext_reloc_in) (bfd *abfd, - struct reloc_ext_external *bytes, - arelent *cache_ptr, - asymbol **symbols, - bfd_size_type symcount) -{ - unsigned int r_index; - int r_extern; - unsigned int r_type; - struct aoutdata *su = &(abfd->tdata.aout_data->a); - - cache_ptr->address = (GET_SWORD (abfd, bytes->r_address)); - - /* Now the fun stuff. */ - r_index = (bytes->r_index[2] << 16) - | (bytes->r_index[1] << 8) - | bytes->r_index[0]; - r_extern = (0 != (bytes->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); - r_type = ((bytes->r_type[0]) >> RELOC_EXT_BITS_TYPE_SH_LITTLE) - & RELOC_EXT_BITS_TYPE_LITTLE; - - if (r_type > 2) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Invalid relocation type imported: %d"), - abfd, r_type); - - bfd_set_error (bfd_error_wrong_format); - } - - cache_ptr->howto = howto_table_ext + r_type; - - if (r_extern && r_index > symcount) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Bad relocation record imported: %d"), abfd, r_index); - - bfd_set_error (bfd_error_wrong_format); - - /* We continue, so we can catch further errors. */ - r_extern = 0; - r_index = N_ABS; - } - - /* Magically uses r_extern, symbols etc. Ugly, but it's what's in the - default. */ - MOVE_ADDRESS (GET_SWORD (abfd, bytes->r_addend)); -} - -/* We use the same as the default, except that we also set - "obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE;", to avoid changing - NAME (aout, set_arch_mach) in aoutx. */ - -static bfd_boolean -MY (set_sizes) (bfd *abfd) -{ - /* Just as the default in aout-target.h (with some #ifdefs folded)... */ - - adata (abfd).page_size = TARGET_PAGE_SIZE; - adata (abfd).segment_size = SEGMENT_SIZE; - adata (abfd).zmagic_disk_block_size = ZMAGIC_DISK_BLOCK_SIZE; - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - - /* ... except for that we have the extended reloc. The alternative - would be to add a check on bfd_arch_cris in NAME (aout, - set_arch_mach) in aoutx.h, but I don't want to do that since - target-specific things should not be added there. */ - - obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; - - return TRUE; -} diff --git a/sdcc/support/sdbinutils/bfd/aout-ns32k.c b/sdcc/support/sdbinutils/bfd/aout-ns32k.c deleted file mode 100644 index f06943941..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-ns32k.c +++ /dev/null @@ -1,364 +0,0 @@ -/* BFD back-end for ns32k a.out-ish binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Contributed by Ian Dall (idall@eleceng.adelaide.edu.au). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "aout/aout64.h" -#include "ns32k.h" - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MYNS(OP) CONCAT2 (ns32k_aout_,OP) - -reloc_howto_type * MYNS (bfd_reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); -reloc_howto_type * MYNS (bfd_reloc_name_lookup) (bfd *, const char *); -bfd_boolean MYNS (write_object_contents) (bfd *); - -/* Avoid multiple definitions from aoutx if supporting - standard a.out format(s) as well as this one. */ -#define NAME(x,y) CONCAT3 (ns32kaout,_32_,y) - -void bfd_ns32k_arch (void); - -#include "libaout.h" - -#define MY(OP) MYNS (OP) - -#define MY_swap_std_reloc_in MY (swap_std_reloc_in) -#define MY_swap_std_reloc_out MY (swap_std_reloc_out) - -/* The ns32k series is ah, unusual, when it comes to relocation. - There are three storage methods for relocatable objects. There - are displacements, immediate operands and ordinary twos complement - data. Of these, only the last fits into the standard relocation - scheme. Immediate operands are stored huffman encoded and - immediate operands are stored big endian (where as the natural byte - order is little endian for this architecture). - - Note that the ns32k displacement storage method is orthogonal to - whether the relocation is pc relative or not. The "displacement" - storage scheme is used for essentially all address constants. The - displacement can be relative to zero (absolute displacement), - relative to the pc (pc relative), the stack pointer, the frame - pointer, the static base register and general purpose register etc. - - For example: - - sym1: .long . # pc relative 2's complement - sym1: .long foo # 2's complement not pc relative - - self: movd @self, r0 # pc relative displacement - movd foo, r0 # non pc relative displacement - - self: movd self, r0 # pc relative immediate - movd foo, r0 # non pc relative immediate - - In addition, for historical reasons the encoding of the relocation types - in the a.out format relocation entries is such that even the relocation - methods which are standard are not encoded the standard way. */ - -reloc_howto_type MY (howto_table)[] = -{ - /* ns32k immediate operands. */ - HOWTO (BFD_RELOC_NS32K_IMM_8, 0, 0, 8, FALSE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_imm, "NS32K_IMM_8", - TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (BFD_RELOC_NS32K_IMM_16, 0, 1, 16, FALSE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_imm, "NS32K_IMM_16", - TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (BFD_RELOC_NS32K_IMM_32, 0, 2, 32, FALSE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_imm, "NS32K_IMM_32", - TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO (BFD_RELOC_NS32K_IMM_8_PCREL, 0, 0, 8, TRUE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_8", - TRUE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (BFD_RELOC_NS32K_IMM_16_PCREL, 0, 1, 16, TRUE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_16", - TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (BFD_RELOC_NS32K_IMM_32_PCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_imm, "PCREL_NS32K_IMM_32", - TRUE, 0xffffffff,0xffffffff, FALSE), - - /* ns32k displacements. */ - HOWTO (BFD_RELOC_NS32K_DISP_8, 0, 0, 7, FALSE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_disp, "NS32K_DISP_8", - TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (BFD_RELOC_NS32K_DISP_16, 0, 1, 14, FALSE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_disp, "NS32K_DISP_16", - TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (BFD_RELOC_NS32K_DISP_32, 0, 2, 30, FALSE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_disp, "NS32K_DISP_32", - TRUE, 0xffffffff, 0xffffffff, FALSE), - HOWTO (BFD_RELOC_NS32K_DISP_8_PCREL, 0, 0, 7, TRUE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_8", - TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (BFD_RELOC_NS32K_DISP_16_PCREL, 0, 1, 14, TRUE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_16", - TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (BFD_RELOC_NS32K_DISP_32_PCREL, 0, 2, 30, TRUE, 0, complain_overflow_signed, - _bfd_ns32k_reloc_disp, "PCREL_NS32K_DISP_32", - TRUE, 0xffffffff,0xffffffff, FALSE), - - /* Normal 2's complement. */ - HOWTO (BFD_RELOC_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,0, - "8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (BFD_RELOC_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield,0, - "16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (BFD_RELOC_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,0, - "32", TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO (BFD_RELOC_8_PCREL, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, - "PCREL_8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (BFD_RELOC_16_PCREL, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, - "PCREL_16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (BFD_RELOC_32_PCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, - "PCREL_32", TRUE, 0xffffffff,0xffffffff, FALSE), -}; - -#define CTOR_TABLE_RELOC_HOWTO(BFD) (MY (howto_table) + 14) - -#define RELOC_STD_BITS_NS32K_TYPE_BIG 0x06 -#define RELOC_STD_BITS_NS32K_TYPE_LITTLE 0x60 -#define RELOC_STD_BITS_NS32K_TYPE_SH_BIG 1 -#define RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE 5 - -static reloc_howto_type * -MY (reloc_howto) (bfd *abfd ATTRIBUTE_UNUSED, - struct reloc_std_external *rel, - int *r_index, - int *r_extern, - int *r_pcrel) -{ - unsigned int r_length; - int r_ns32k_type; - - *r_index = ((rel->r_index[2] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[0] ); - *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); - *r_pcrel = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); - r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) - >> RELOC_STD_BITS_LENGTH_SH_LITTLE); - r_ns32k_type = ((rel->r_type[0] & RELOC_STD_BITS_NS32K_TYPE_LITTLE) - >> RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE); - return (MY (howto_table) + r_length + 3 * (*r_pcrel) + 6 * r_ns32k_type); -} - -#define MY_reloc_howto(BFD, REL, IN, EX, PC) \ - MY (reloc_howto) (BFD, REL, &IN, &EX, &PC) - -static void -MY (put_reloc) (bfd *abfd, - int r_extern, - int r_index, - bfd_vma value, - reloc_howto_type *howto, - struct reloc_std_external *reloc) -{ - unsigned int r_length; - int r_pcrel; - int r_ns32k_type; - - PUT_WORD (abfd, value, reloc->r_address); - r_length = howto->size ; /* Size as a power of two. */ - r_pcrel = (int) howto->pc_relative; /* Relative to PC? */ - r_ns32k_type = (howto - MY (howto_table) )/6; - - reloc->r_index[2] = r_index >> 16; - reloc->r_index[1] = r_index >> 8; - reloc->r_index[0] = r_index; - reloc->r_type[0] = - (r_extern? RELOC_STD_BITS_EXTERN_LITTLE: 0) - | (r_pcrel? RELOC_STD_BITS_PCREL_LITTLE: 0) - | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE) - | (r_ns32k_type << RELOC_STD_BITS_NS32K_TYPE_SH_LITTLE); -} - -#define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \ - MY (put_reloc) (BFD, EXT, IDX, VAL, HOWTO, RELOC) - -#define STAT_FOR_EXEC - -#define MY_final_link_relocate _bfd_ns32k_final_link_relocate -#define MY_relocate_contents _bfd_ns32k_relocate_contents - -static void MY_swap_std_reloc_in (bfd *, struct reloc_std_external *, arelent *, asymbol **, bfd_size_type); -static void MY_swap_std_reloc_out (bfd *, arelent *, struct reloc_std_external *); - -#include "aoutx.h" - -reloc_howto_type * -MY (bfd_reloc_type_lookup) (bfd *abfd, bfd_reloc_code_real_type code) -{ -#define ENTRY(i,j) case i: return &MY (howto_table)[j] - - int ext = obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE; - - BFD_ASSERT (ext == 0); - if (code == BFD_RELOC_CTOR) - switch (bfd_arch_bits_per_address (abfd)) - { - case 32: - code = BFD_RELOC_32; - break; - default: - break; - } - switch (code) - { - ENTRY (BFD_RELOC_NS32K_IMM_8, 0); - ENTRY (BFD_RELOC_NS32K_IMM_16, 1); - ENTRY (BFD_RELOC_NS32K_IMM_32, 2); - ENTRY (BFD_RELOC_NS32K_IMM_8_PCREL, 3); - ENTRY (BFD_RELOC_NS32K_IMM_16_PCREL, 4); - ENTRY (BFD_RELOC_NS32K_IMM_32_PCREL, 5); - ENTRY (BFD_RELOC_NS32K_DISP_8, 6); - ENTRY (BFD_RELOC_NS32K_DISP_16, 7); - ENTRY (BFD_RELOC_NS32K_DISP_32, 8); - ENTRY (BFD_RELOC_NS32K_DISP_8_PCREL, 9); - ENTRY (BFD_RELOC_NS32K_DISP_16_PCREL, 10); - ENTRY (BFD_RELOC_NS32K_DISP_32_PCREL, 11); - ENTRY (BFD_RELOC_8, 12); - ENTRY (BFD_RELOC_16, 13); - ENTRY (BFD_RELOC_32, 14); - ENTRY (BFD_RELOC_8_PCREL, 15); - ENTRY (BFD_RELOC_16_PCREL, 16); - ENTRY (BFD_RELOC_32_PCREL, 17); - default: - return NULL; - } -#undef ENTRY -} - -reloc_howto_type * -MY (bfd_reloc_name_lookup) (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (MY (howto_table)) / sizeof (MY (howto_table)[0]); - i++) - if (MY (howto_table)[i].name != NULL - && strcasecmp (MY (howto_table)[i].name, r_name) == 0) - return &MY (howto_table)[i]; - - return NULL; -} - -static void -MY_swap_std_reloc_in (bfd *abfd, - struct reloc_std_external *bytes, - arelent *cache_ptr, - asymbol **symbols, - bfd_size_type symcount ATTRIBUTE_UNUSED) -{ - int r_index; - int r_extern; - int r_pcrel; - struct aoutdata *su = &(abfd->tdata.aout_data->a); - - cache_ptr->address = H_GET_32 (abfd, bytes->r_address); - - /* Now the fun stuff. */ - cache_ptr->howto = MY_reloc_howto (abfd, bytes, r_index, r_extern, r_pcrel); - - MOVE_ADDRESS (0); -} - -static void -MY_swap_std_reloc_out (bfd *abfd, - arelent *g, - struct reloc_std_external *natptr) -{ - int r_index; - asymbol *sym = *(g->sym_ptr_ptr); - int r_extern; - asection *output_section = sym->section->output_section; - - /* Name was clobbered by aout_write_syms to be symbol index. */ - - /* If this relocation is relative to a symbol then set the - r_index to the symbols index, and the r_extern bit. - - Absolute symbols can come in in two ways, either as an offset - from the abs section, or as a symbol which has an abs value. - Check for that here. */ - if (bfd_is_com_section (output_section) - || bfd_is_abs_section (output_section) - || bfd_is_und_section (output_section)) - { - if (bfd_abs_section_ptr->symbol == sym) - { - /* Whoops, looked like an abs symbol, but is really an offset - from the abs section. */ - r_index = 0; - r_extern = 0; - } - else - { - /* Fill in symbol. */ - r_extern = 1; -#undef KEEPIT -#define KEEPIT udata.i - r_index = (*(g->sym_ptr_ptr))->KEEPIT; -#undef KEEPIT - } - } - else - { - /* Just an ordinary section. */ - r_extern = 0; - r_index = output_section->target_index; - } - - MY_put_reloc (abfd, r_extern, r_index, g->address, g->howto, natptr); -} - -bfd_reloc_status_type -_bfd_ns32k_relocate_contents (reloc_howto_type *howto, - bfd *input_bfd, - bfd_vma relocation, - bfd_byte *location) -{ - int r_ns32k_type = (howto - MY (howto_table)) / 6; - bfd_vma (*get_data) (bfd_byte *, int); - void (*put_data) (bfd_vma, bfd_byte *, int); - - switch (r_ns32k_type) - { - case 0: - get_data = _bfd_ns32k_get_immediate; - put_data = _bfd_ns32k_put_immediate; - break; - case 1: - get_data = _bfd_ns32k_get_displacement; - put_data = _bfd_ns32k_put_displacement; - break; - case 2: - return _bfd_relocate_contents (howto, input_bfd, relocation, - location); - default: - return bfd_reloc_notsupported; - } - return _bfd_do_ns32k_reloc_contents (howto, input_bfd, relocation, - location, get_data, put_data); -} diff --git a/sdcc/support/sdbinutils/bfd/aout-sparcle.c b/sdcc/support/sdbinutils/bfd/aout-sparcle.c deleted file mode 100644 index 2c2ef82e7..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-sparcle.c +++ /dev/null @@ -1,37 +0,0 @@ -/* BFD backend for sparc little-endian aout binaries. - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#define TARGETNAME "a.out-sparc-little" - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (sparc_aout_le_,OP) - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libaout.h" - -#define MACHTYPE_OK(mtype) ((mtype) == M_SPARC || (mtype) == M_SPARCLET) - -/* Include the usual a.out support. */ -#define TARGET_IS_LITTLE_ENDIAN_P -#include "aoutf1.h" diff --git a/sdcc/support/sdbinutils/bfd/aout-target.h b/sdcc/support/sdbinutils/bfd/aout-target.h deleted file mode 100644 index cb14b98da..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-target.h +++ /dev/null @@ -1,694 +0,0 @@ -/* Define a target vector and some small routines for a variant of a.out. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "aout/aout64.h" -#include "aout/stab_gnu.h" -#include "aout/ar.h" -/*#include "libaout.h"*/ - -#ifndef SEGMENT_SIZE -#define SEGMENT_SIZE TARGET_PAGE_SIZE -#endif - -extern reloc_howto_type * NAME (aout, reloc_type_lookup) (bfd *, bfd_reloc_code_real_type); -extern reloc_howto_type * NAME (aout, reloc_name_lookup) (bfd *, const char *); - -/* Set parameters about this a.out file that are machine-dependent. - This routine is called from some_aout_object_p just before it returns. */ -#ifndef MY_callback - -static const bfd_target * -MY (callback) (bfd *abfd) -{ - struct internal_exec *execp = exec_hdr (abfd); - unsigned int arch_align_power; - unsigned long arch_align; - - /* Calculate the file positions of the parts of a newly read aout header. */ - obj_textsec (abfd)->size = N_TXTSIZE (execp); - - /* The virtual memory addresses of the sections. */ - obj_textsec (abfd)->vma = N_TXTADDR (execp); - obj_datasec (abfd)->vma = N_DATADDR (execp); - obj_bsssec (abfd)->vma = N_BSSADDR (execp); - - /* For some targets, if the entry point is not in the same page - as the start of the text, then adjust the VMA so that it is. - FIXME: Do this with a macro like SET_ARCH_MACH instead? */ - if (aout_backend_info (abfd)->entry_is_text_address - && execp->a_entry > obj_textsec (abfd)->vma) - { - bfd_vma adjust; - - adjust = execp->a_entry - obj_textsec (abfd)->vma; - /* Adjust only by whole pages. */ - adjust &= ~(TARGET_PAGE_SIZE - 1); - obj_textsec (abfd)->vma += adjust; - obj_datasec (abfd)->vma += adjust; - obj_bsssec (abfd)->vma += adjust; - } - - /* Set the load addresses to be the same as the virtual addresses. */ - obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; - obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; - obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; - - /* The file offsets of the sections. */ - obj_textsec (abfd)->filepos = N_TXTOFF (execp); - obj_datasec (abfd)->filepos = N_DATOFF (execp); - - /* The file offsets of the relocation info. */ - obj_textsec (abfd)->rel_filepos = N_TRELOFF (execp); - obj_datasec (abfd)->rel_filepos = N_DRELOFF (execp); - - /* The file offsets of the string table and symbol table. */ - obj_sym_filepos (abfd) = N_SYMOFF (execp); - obj_str_filepos (abfd) = N_STROFF (execp); - - /* Determine the architecture and machine type of the object file. */ -#ifdef SET_ARCH_MACH - SET_ARCH_MACH (abfd, execp); -#else - bfd_default_set_arch_mach (abfd, DEFAULT_ARCH, 0); -#endif - - /* The number of relocation records. This must be called after - SET_ARCH_MACH. It assumes that SET_ARCH_MACH will set - obj_reloc_entry_size correctly, if the reloc size is not - RELOC_STD_SIZE. */ - obj_textsec (abfd)->reloc_count = - execp->a_trsize / obj_reloc_entry_size (abfd); - obj_datasec (abfd)->reloc_count = - execp->a_drsize / obj_reloc_entry_size (abfd); - - /* Now that we know the architecture, set the alignments of the - sections. This is normally done by NAME (aout,new_section_hook), - but when the initial sections were created the architecture had - not yet been set. However, for backward compatibility, we don't - set the alignment power any higher than as required by the size - of the section. */ - arch_align_power = bfd_get_arch_info (abfd)->section_align_power; - arch_align = 1 << arch_align_power; - if ((BFD_ALIGN (obj_textsec (abfd)->size, arch_align) - == obj_textsec (abfd)->size) - && (BFD_ALIGN (obj_datasec (abfd)->size, arch_align) - == obj_datasec (abfd)->size) - && (BFD_ALIGN (obj_bsssec (abfd)->size, arch_align) - == obj_bsssec (abfd)->size)) - { - obj_textsec (abfd)->alignment_power = arch_align_power; - obj_datasec (abfd)->alignment_power = arch_align_power; - obj_bsssec (abfd)->alignment_power = arch_align_power; - } - - /* Don't set sizes now -- can't be sure until we know arch & mach. - Sizes get set in set_sizes callback, later. */ - - return abfd->xvec; -} -#endif - -#ifndef MY_object_p -/* Finish up the reading of an a.out file header. */ - -static const bfd_target * -MY (object_p) (bfd *abfd) -{ - struct external_exec exec_bytes; /* Raw exec header from file. */ - struct internal_exec exec; /* Cleaned-up exec header. */ - const bfd_target *target; - bfd_size_type amt = EXEC_BYTES_SIZE; - - if (bfd_bread ((void *) &exec_bytes, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return 0; - } - -#ifdef SWAP_MAGIC - exec.a_info = SWAP_MAGIC (exec_bytes.e_info); -#else - exec.a_info = GET_MAGIC (abfd, exec_bytes.e_info); -#endif - - if (N_BADMAG (&exec)) - return 0; - -#ifdef MACHTYPE_OK - if (!(MACHTYPE_OK (N_MACHTYPE (&exec)))) - return 0; -#endif - - NAME (aout, swap_exec_header_in) (abfd, &exec_bytes, &exec); - -#ifdef SWAP_MAGIC - /* Swap_exec_header_in read in a_info with the wrong byte order. */ - exec.a_info = SWAP_MAGIC (exec_bytes.e_info); -#endif - - target = NAME (aout, some_aout_object_p) (abfd, &exec, MY (callback)); - -#ifdef ENTRY_CAN_BE_ZERO - /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage) - means that it isn't obvious if EXEC_P should be set. - All of the following must be true for an executable: - There must be no relocations, the bfd can be neither an - archive nor an archive element, and the file must be executable. */ - - if (exec.a_trsize + exec.a_drsize == 0 - && bfd_get_format(abfd) == bfd_object && abfd->my_archive == NULL) - { - struct stat buf; -#ifndef S_IXUSR -#define S_IXUSR 0100 /* Execute by owner. */ -#endif - if (stat(abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR)) - abfd->flags |= EXEC_P; - } -#endif /* ENTRY_CAN_BE_ZERO */ - - return target; -} -#define MY_object_p MY (object_p) -#endif - -#ifndef MY_mkobject - -static bfd_boolean -MY (mkobject) (bfd *abfd) -{ - return NAME (aout, mkobject (abfd)); -} - -#define MY_mkobject MY (mkobject) -#endif - -#ifndef MY_bfd_copy_private_section_data - -/* Copy private section data. This actually does nothing with the - sections. It copies the subformat field. We copy it here, because - we need to know whether this is a QMAGIC file before we set the - section contents, and copy_private_bfd_data is not called until - after the section contents have been set. */ - -static bfd_boolean -MY_bfd_copy_private_section_data (bfd *ibfd, - asection *isec ATTRIBUTE_UNUSED, - bfd *obfd, - asection *osec ATTRIBUTE_UNUSED) -{ - if (bfd_get_flavour (ibfd) == bfd_target_aout_flavour - && bfd_get_flavour (obfd) == bfd_target_aout_flavour) - obj_aout_subformat (obfd) = obj_aout_subformat (ibfd); - return TRUE; -} - -#endif - -/* Write an object file. - Section contents have already been written. We write the - file header, symbols, and relocation. */ - -#ifndef MY_write_object_contents - -static bfd_boolean -MY (write_object_contents) (bfd *abfd) -{ - struct external_exec exec_bytes; - struct internal_exec *execp = exec_hdr (abfd); - - obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; - - WRITE_HEADERS (abfd, execp); - - return TRUE; -} -#define MY_write_object_contents MY (write_object_contents) -#endif - -#ifndef MY_set_sizes - -static bfd_boolean -MY (set_sizes) (bfd *abfd) -{ - adata(abfd).page_size = TARGET_PAGE_SIZE; - adata(abfd).segment_size = SEGMENT_SIZE; - -#ifdef ZMAGIC_DISK_BLOCK_SIZE - adata(abfd).zmagic_disk_block_size = ZMAGIC_DISK_BLOCK_SIZE; -#else - adata(abfd).zmagic_disk_block_size = TARGET_PAGE_SIZE; -#endif - - adata(abfd).exec_bytes_size = EXEC_BYTES_SIZE; - return TRUE; -} -#define MY_set_sizes MY (set_sizes) -#endif - -#ifndef MY_exec_hdr_flags -#define MY_exec_hdr_flags 0 -#endif - -#ifndef MY_backend_data - -#ifndef MY_zmagic_contiguous -#define MY_zmagic_contiguous 0 -#endif -#ifndef MY_text_includes_header -#define MY_text_includes_header 0 -#endif -#ifndef MY_entry_is_text_address -#define MY_entry_is_text_address 0 -#endif -#ifndef MY_exec_header_not_counted -#define MY_exec_header_not_counted 0 -#endif -#ifndef MY_add_dynamic_symbols -#define MY_add_dynamic_symbols 0 -#endif -#ifndef MY_add_one_symbol -#define MY_add_one_symbol 0 -#endif -#ifndef MY_link_dynamic_object -#define MY_link_dynamic_object 0 -#endif -#ifndef MY_write_dynamic_symbol -#define MY_write_dynamic_symbol 0 -#endif -#ifndef MY_check_dynamic_reloc -#define MY_check_dynamic_reloc 0 -#endif -#ifndef MY_finish_dynamic_link -#define MY_finish_dynamic_link 0 -#endif - -static const struct aout_backend_data MY (backend_data) = -{ - MY_zmagic_contiguous, - MY_text_includes_header, - MY_entry_is_text_address, - MY_exec_hdr_flags, - 0, /* Text vma? */ - MY_set_sizes, - MY_exec_header_not_counted, - MY_add_dynamic_symbols, - MY_add_one_symbol, - MY_link_dynamic_object, - MY_write_dynamic_symbol, - MY_check_dynamic_reloc, - MY_finish_dynamic_link -}; -#define MY_backend_data &MY (backend_data) -#endif - -#ifndef MY_final_link_callback - -/* Callback for the final_link routine to set the section offsets. */ - -static void -MY_final_link_callback (bfd *abfd, - file_ptr *ptreloff, - file_ptr *pdreloff, - file_ptr *psymoff) -{ - struct internal_exec *execp = exec_hdr (abfd); - - *ptreloff = N_TRELOFF (execp); - *pdreloff = N_DRELOFF (execp); - *psymoff = N_SYMOFF (execp); -} - -#endif - -#ifndef MY_bfd_final_link - -/* Final link routine. We need to use a call back to get the correct - offsets in the output file. */ - -static bfd_boolean -MY_bfd_final_link (bfd *abfd, struct bfd_link_info *info) -{ - return NAME (aout, final_link) (abfd, info, MY_final_link_callback); -} - -#endif - -/* We assume BFD generic archive files. */ -#ifndef MY_openr_next_archived_file -#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file -#endif -#ifndef MY_get_elt_at_index -#define MY_get_elt_at_index _bfd_generic_get_elt_at_index -#endif -#ifndef MY_generic_stat_arch_elt -#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt -#endif -#ifndef MY_slurp_armap -#define MY_slurp_armap bfd_slurp_bsd_armap -#endif -#ifndef MY_slurp_extended_name_table -#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table -#endif -#ifndef MY_construct_extended_name_table -#define MY_construct_extended_name_table \ - _bfd_archive_bsd_construct_extended_name_table -#endif -#ifndef MY_write_armap -#define MY_write_armap _bfd_bsd_write_armap -#endif -#ifndef MY_read_ar_hdr -#define MY_read_ar_hdr _bfd_generic_read_ar_hdr -#endif -#ifndef MY_write_ar_hdr -#define MY_write_ar_hdr _bfd_generic_write_ar_hdr -#endif -#ifndef MY_truncate_arname -#define MY_truncate_arname bfd_bsd_truncate_arname -#endif -#ifndef MY_update_armap_timestamp -#define MY_update_armap_timestamp _bfd_archive_bsd_update_armap_timestamp -#endif - -/* No core file defined here -- configure in trad-core.c separately. */ -#ifndef MY_core_file_failing_command -#define MY_core_file_failing_command _bfd_nocore_core_file_failing_command -#endif -#ifndef MY_core_file_failing_signal -#define MY_core_file_failing_signal _bfd_nocore_core_file_failing_signal -#endif -#ifndef MY_core_file_matches_executable_p -#define MY_core_file_matches_executable_p \ - _bfd_nocore_core_file_matches_executable_p -#endif -#ifndef MY_core_file_pid -#define MY_core_file_pid _bfd_nocore_core_file_pid -#endif -#ifndef MY_core_file_p -#define MY_core_file_p _bfd_dummy_target -#endif - -#ifndef MY_bfd_debug_info_start -#define MY_bfd_debug_info_start bfd_void -#endif -#ifndef MY_bfd_debug_info_end -#define MY_bfd_debug_info_end bfd_void -#endif -#ifndef MY_bfd_debug_info_accumulate -#define MY_bfd_debug_info_accumulate \ - (void (*) (bfd *, struct bfd_section *)) bfd_void -#endif - -#ifndef MY_core_file_failing_command -#define MY_core_file_failing_command NAME (aout, core_file_failing_command) -#endif -#ifndef MY_core_file_failing_signal -#define MY_core_file_failing_signal NAME (aout, core_file_failing_signal) -#endif -#ifndef MY_core_file_matches_executable_p -#define MY_core_file_matches_executable_p NAME (aout, core_file_matches_executable_p) -#endif -#ifndef MY_set_section_contents -#define MY_set_section_contents NAME (aout, set_section_contents) -#endif -#ifndef MY_get_section_contents -#define MY_get_section_contents NAME (aout, get_section_contents) -#endif -#ifndef MY_get_section_contents_in_window -#define MY_get_section_contents_in_window _bfd_generic_get_section_contents_in_window -#endif -#ifndef MY_new_section_hook -#define MY_new_section_hook NAME (aout, new_section_hook) -#endif -#ifndef MY_get_symtab_upper_bound -#define MY_get_symtab_upper_bound NAME (aout, get_symtab_upper_bound) -#endif -#ifndef MY_canonicalize_symtab -#define MY_canonicalize_symtab NAME (aout, canonicalize_symtab) -#endif -#ifndef MY_get_reloc_upper_bound -#define MY_get_reloc_upper_bound NAME (aout,get_reloc_upper_bound) -#endif -#ifndef MY_canonicalize_reloc -#define MY_canonicalize_reloc NAME (aout, canonicalize_reloc) -#endif -#ifndef MY_set_reloc -#define MY_set_reloc _bfd_generic_set_reloc -#endif -#ifndef MY_make_empty_symbol -#define MY_make_empty_symbol NAME (aout, make_empty_symbol) -#endif -#ifndef MY_print_symbol -#define MY_print_symbol NAME (aout, print_symbol) -#endif -#ifndef MY_get_symbol_info -#define MY_get_symbol_info NAME (aout, get_symbol_info) -#endif -#ifndef MY_get_symbol_version_string -#define MY_get_symbol_version_string \ - _bfd_nosymbols_get_symbol_version_string -#endif -#ifndef MY_get_lineno -#define MY_get_lineno NAME (aout, get_lineno) -#endif -#ifndef MY_set_arch_mach -#define MY_set_arch_mach NAME (aout, set_arch_mach) -#endif -#ifndef MY_find_nearest_line -#define MY_find_nearest_line NAME (aout, find_nearest_line) -#endif -#ifndef MY_find_line -#define MY_find_line _bfd_nosymbols_find_line -#endif -#ifndef MY_find_inliner_info -#define MY_find_inliner_info _bfd_nosymbols_find_inliner_info -#endif -#ifndef MY_sizeof_headers -#define MY_sizeof_headers NAME (aout, sizeof_headers) -#endif -#ifndef MY_bfd_get_relocated_section_contents -#define MY_bfd_get_relocated_section_contents \ - bfd_generic_get_relocated_section_contents -#endif -#ifndef MY_bfd_relax_section -#define MY_bfd_relax_section bfd_generic_relax_section -#endif -#ifndef MY_bfd_gc_sections -#define MY_bfd_gc_sections bfd_generic_gc_sections -#endif -#ifndef MY_bfd_lookup_section_flags -#define MY_bfd_lookup_section_flags bfd_generic_lookup_section_flags -#endif -#ifndef MY_bfd_merge_sections -#define MY_bfd_merge_sections bfd_generic_merge_sections -#endif -#ifndef MY_bfd_is_group_section -#define MY_bfd_is_group_section bfd_generic_is_group_section -#endif -#ifndef MY_bfd_discard_group -#define MY_bfd_discard_group bfd_generic_discard_group -#endif -#ifndef MY_section_already_linked -#define MY_section_already_linked \ - _bfd_generic_section_already_linked -#endif -#ifndef MY_bfd_define_common_symbol -#define MY_bfd_define_common_symbol bfd_generic_define_common_symbol -#endif -#ifndef MY_bfd_define_start_stop -#define MY_bfd_define_start_stop bfd_generic_define_start_stop -#endif -#ifndef MY_bfd_reloc_type_lookup -#define MY_bfd_reloc_type_lookup NAME (aout, reloc_type_lookup) -#endif -#ifndef MY_bfd_reloc_name_lookup -#define MY_bfd_reloc_name_lookup NAME (aout, reloc_name_lookup) -#endif -#ifndef MY_bfd_make_debug_symbol -#define MY_bfd_make_debug_symbol 0 -#endif -#ifndef MY_read_minisymbols -#define MY_read_minisymbols NAME (aout, read_minisymbols) -#endif -#ifndef MY_minisymbol_to_symbol -#define MY_minisymbol_to_symbol NAME (aout, minisymbol_to_symbol) -#endif -#ifndef MY_bfd_link_hash_table_create -#define MY_bfd_link_hash_table_create NAME (aout, link_hash_table_create) -#endif -#ifndef MY_bfd_link_add_symbols -#define MY_bfd_link_add_symbols NAME (aout, link_add_symbols) -#endif -#ifndef MY_bfd_link_just_syms -#define MY_bfd_link_just_syms _bfd_generic_link_just_syms -#endif -#ifndef MY_bfd_copy_link_hash_symbol_type -#define MY_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type -#endif -#ifndef MY_bfd_link_split_section -#define MY_bfd_link_split_section _bfd_generic_link_split_section -#endif - -#ifndef MY_bfd_link_check_relocs -#define MY_bfd_link_check_relocs _bfd_generic_link_check_relocs -#endif - -#ifndef MY_bfd_copy_private_bfd_data -#define MY_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data -#endif - -#ifndef MY_bfd_merge_private_bfd_data -#define MY_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data -#endif - -#ifndef MY_bfd_copy_private_symbol_data -#define MY_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data -#endif - -#ifndef MY_bfd_copy_private_header_data -#define MY_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data -#endif - -#ifndef MY_bfd_print_private_bfd_data -#define MY_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data -#endif - -#ifndef MY_bfd_set_private_flags -#define MY_bfd_set_private_flags _bfd_generic_bfd_set_private_flags -#endif - -#ifndef MY_bfd_is_local_label_name -#define MY_bfd_is_local_label_name bfd_generic_is_local_label_name -#endif - -#ifndef MY_bfd_is_target_special_symbol -#define MY_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) -#endif - -#ifndef MY_bfd_free_cached_info -#define MY_bfd_free_cached_info NAME (aout, bfd_free_cached_info) -#endif - -#ifndef MY_close_and_cleanup - -/* Handle closing of a BFD including the resource-releasing parts. */ - -static bfd_boolean -MY_close_and_cleanup (bfd *abfd) -{ - if (!MY_bfd_free_cached_info (abfd)) - return FALSE; - - return _bfd_generic_close_and_cleanup (abfd); -} - -#endif - -#ifndef MY_get_dynamic_symtab_upper_bound -#define MY_get_dynamic_symtab_upper_bound \ - _bfd_nodynamic_get_dynamic_symtab_upper_bound -#endif -#ifndef MY_canonicalize_dynamic_symtab -#define MY_canonicalize_dynamic_symtab \ - _bfd_nodynamic_canonicalize_dynamic_symtab -#endif -#ifndef MY_get_synthetic_symtab -#define MY_get_synthetic_symtab \ - _bfd_nodynamic_get_synthetic_symtab -#endif -#ifndef MY_get_dynamic_reloc_upper_bound -#define MY_get_dynamic_reloc_upper_bound \ - _bfd_nodynamic_get_dynamic_reloc_upper_bound -#endif -#ifndef MY_canonicalize_dynamic_reloc -#define MY_canonicalize_dynamic_reloc \ - _bfd_nodynamic_canonicalize_dynamic_reloc -#endif - -/* Aout symbols normally have leading underscores. */ -#ifndef MY_symbol_leading_char -#define MY_symbol_leading_char '_' -#endif - -/* Aout archives normally use spaces for padding. */ -#ifndef AR_PAD_CHAR -#define AR_PAD_CHAR ' ' -#endif - -#ifndef MY_BFD_TARGET -const bfd_target MY (vec) = -{ - TARGETNAME, /* Name. */ - bfd_target_aout_flavour, -#ifdef TARGET_IS_BIG_ENDIAN_P - BFD_ENDIAN_BIG, /* Target byte order (big). */ - BFD_ENDIAN_BIG, /* Target headers byte order (big). */ -#else - BFD_ENDIAN_LITTLE, /* Target byte order (little). */ - BFD_ENDIAN_LITTLE, /* Target headers byte order (little). */ -#endif - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - MY_symbol_leading_char, - AR_PAD_CHAR, /* AR_pad_char. */ - 15, /* AR_max_namelen. */ - 0, /* match priority. */ -#ifdef TARGET_IS_BIG_ENDIAN_P - 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. */ -#else - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Headers. */ -#endif - {_bfd_dummy_target, MY_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, MY_core_file_p}, - {bfd_false, MY_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, MY_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (MY), - BFD_JUMP_TABLE_COPY (MY), - BFD_JUMP_TABLE_CORE (MY), - BFD_JUMP_TABLE_ARCHIVE (MY), - BFD_JUMP_TABLE_SYMBOLS (MY), - BFD_JUMP_TABLE_RELOCS (MY), - BFD_JUMP_TABLE_WRITE (MY), - BFD_JUMP_TABLE_LINK (MY), - BFD_JUMP_TABLE_DYNAMIC (MY), - - /* Alternative_target. */ - NULL, - - MY_backend_data -}; -#endif /* MY_BFD_TARGET */ diff --git a/sdcc/support/sdbinutils/bfd/aout-tic30.c b/sdcc/support/sdbinutils/bfd/aout-tic30.c deleted file mode 100644 index d8ad415a7..000000000 --- a/sdcc/support/sdbinutils/bfd/aout-tic30.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* BFD back-end for TMS320C30 a.out binaries. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#define TARGET_IS_BIG_ENDIAN_P -#define N_HEADER_IN_TEXT(x) 1 -#define TEXT_START_ADDR 1024 -#define TARGET_PAGE_SIZE 128 -#define SEGMENT_SIZE TARGET_PAGE_SIZE -#define DEFAULT_ARCH bfd_arch_tic30 -#define ARCH_SIZE 32 - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (tic30_aout_,OP) -#define TARGETNAME "a.out-tic30" -#define NAME(x,y) CONCAT3 (tic30_aout,_32_,y) - -#include "sysdep.h" -#include "bfd.h" -#include "libaout.h" -#include "aout/aout64.h" -#include "aout/stab_gnu.h" -#include "aout/ar.h" - -#define MY_reloc_howto(BFD, REL, IN, EX, PC) tic30_aout_reloc_howto (BFD, REL, & IN, & EX, & PC) - -#define MY_final_link_relocate tic30_aout_final_link_relocate -#define MY_object_p tic30_aout_object_p -#define MY_mkobject NAME (aout,mkobject) -#define MY_write_object_contents tic30_aout_write_object_contents -#define MY_set_sizes tic30_aout_set_sizes - -#ifndef MY_exec_hdr_flags -#define MY_exec_hdr_flags 1 -#endif - -#ifndef MY_backend_data - -#ifndef MY_zmagic_contiguous -#define MY_zmagic_contiguous 0 -#endif -#ifndef MY_text_includes_header -#define MY_text_includes_header 0 -#endif -#ifndef MY_entry_is_text_address -#define MY_entry_is_text_address 0 -#endif -#ifndef MY_exec_header_not_counted -#define MY_exec_header_not_counted 1 -#endif -#ifndef MY_add_dynamic_symbols -#define MY_add_dynamic_symbols 0 -#endif -#ifndef MY_add_one_symbol -#define MY_add_one_symbol 0 -#endif -#ifndef MY_link_dynamic_object -#define MY_link_dynamic_object 0 -#endif -#ifndef MY_write_dynamic_symbol -#define MY_write_dynamic_symbol 0 -#endif -#ifndef MY_check_dynamic_reloc -#define MY_check_dynamic_reloc 0 -#endif -#ifndef MY_finish_dynamic_link -#define MY_finish_dynamic_link 0 -#endif - -static bfd_boolean -tic30_aout_set_sizes (bfd *abfd) -{ - adata (abfd).page_size = TARGET_PAGE_SIZE; - -#ifdef SEGMENT_SIZE - adata (abfd).segment_size = SEGMENT_SIZE; -#else - adata (abfd).segment_size = TARGET_PAGE_SIZE; -#endif - -#ifdef ZMAGIC_DISK_BLOCK_SIZE - adata (abfd).zmagic_disk_block_size = ZMAGIC_DISK_BLOCK_SIZE; -#else - adata (abfd).zmagic_disk_block_size = TARGET_PAGE_SIZE; -#endif - - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - - return TRUE; -} - -static const struct aout_backend_data tic30_aout_backend_data = -{ - MY_zmagic_contiguous, - MY_text_includes_header, - MY_entry_is_text_address, - MY_exec_hdr_flags, - 0, /* Text vma? */ - MY_set_sizes, - MY_exec_header_not_counted, - MY_add_dynamic_symbols, - MY_add_one_symbol, - MY_link_dynamic_object, - MY_write_dynamic_symbol, - MY_check_dynamic_reloc, - MY_finish_dynamic_link -}; -#define MY_backend_data &tic30_aout_backend_data -#endif - -static reloc_howto_type * - tic30_aout_reloc_howto (bfd *, struct reloc_std_external *, int *, int *, int *); -static bfd_reloc_status_type - tic30_aout_final_link_relocate - (reloc_howto_type *, bfd *, asection *, bfd_byte *, bfd_vma, bfd_vma, bfd_vma); - -/* FIXME: This is wrong. aoutx.h should really only be included by - aout32.c. */ - -#include "aoutx.h" - -/* This function is used to work out pc-relative offsets for the - TMS320C30. The data already placed by md_pcrel_from within gas is - useless for a relocation, so we just get the offset value and place - a version of this within the object code. - tic30_aout_final_link_relocate will then calculate the required - relocation to add on to the value in the object code. */ - -static bfd_reloc_status_type -tic30_aout_fix_pcrel_16 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation = 1; - bfd_byte offset_data = bfd_get_8 (abfd, (bfd_byte *) data + reloc_entry->address - 1); - - /* The byte before the location of the fix contains bits 23-16 of - the pcrel instruction. Bit 21 is set for a delayed instruction - which requires on offset of 3 instead of 1. */ - if (offset_data & 0x20) - relocation -= 3; - else - relocation -= 1; - bfd_put_16 (abfd, relocation, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -/* This function is used as a callback for 16-bit relocs. This is - required for relocations between segments. A line in aoutx.h - requires that any relocations for the data section should point to - the end of the aligned text section, plus an offset. By default, - this does not happen, therefore this function takes care of - that. */ - -static bfd_reloc_status_type -tic30_aout_fix_16 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - - /* Make sure that the symbol's section is defined. */ - if (bfd_is_und_section (symbol->section) && (symbol->flags & BSF_WEAK) == 0) - return output_bfd ? bfd_reloc_ok : bfd_reloc_undefined; - /* Get the size of the input section and turn it into the TMS320C30 - 32-bit address format. */ - relocation = (symbol->section->vma >> 2); - relocation += bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address); - bfd_put_16 (abfd, relocation, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -/* This function does the same thing as tic30_aout_fix_16 except for 32 - bit relocations. */ - -static bfd_reloc_status_type -tic30_aout_fix_32 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - - /* Make sure that the symbol's section is defined. */ - if (bfd_is_und_section (symbol->section) && (symbol->flags & BSF_WEAK) == 0) - return output_bfd ? bfd_reloc_ok : bfd_reloc_undefined; - /* Get the size of the input section and turn it into the TMS320C30 - 32-bit address format. */ - relocation = (symbol->section->vma >> 2); - relocation += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - bfd_put_32 (abfd, relocation, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -/* This table lists the relocation types for the TMS320C30. There are - only a few relocations required, and all must be divided by 4 (>> - 2) to get the 32-bit addresses in the format the TMS320C30 likes - it. */ -reloc_howto_type tic30_aout_howto_table[] = -{ - EMPTY_HOWTO (-1), - HOWTO (1, 2, 1, 16, FALSE, 0, 0, tic30_aout_fix_16, - "16", FALSE, 0x0000FFFF, 0x0000FFFF, FALSE), - HOWTO (2, 2, 2, 24, FALSE, 0, complain_overflow_bitfield, NULL, - "24", FALSE, 0x00FFFFFF, 0x00FFFFFF, FALSE), - HOWTO (3, 18, 3, 24, FALSE, 0, complain_overflow_bitfield, NULL, - "LDP", FALSE, 0x00FF0000, 0x000000FF, FALSE), - HOWTO (4, 2, 4, 32, FALSE, 0, complain_overflow_bitfield, tic30_aout_fix_32, - "32", FALSE, 0xFFFFFFFF, 0xFFFFFFFF, FALSE), - HOWTO (5, 2, 1, 16, TRUE, 0, complain_overflow_signed, - tic30_aout_fix_pcrel_16, "PCREL", TRUE, 0x0000FFFF, 0x0000FFFF, TRUE), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1) -}; - - -static reloc_howto_type * -tic30_aout_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_8: - case BFD_RELOC_TIC30_LDP: - return &tic30_aout_howto_table[3]; - case BFD_RELOC_16: - return &tic30_aout_howto_table[1]; - case BFD_RELOC_24: - return &tic30_aout_howto_table[2]; - case BFD_RELOC_16_PCREL: - return &tic30_aout_howto_table[5]; - case BFD_RELOC_32: - return &tic30_aout_howto_table[4]; - default: - return NULL; - } -} - -static reloc_howto_type * -tic30_aout_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (tic30_aout_howto_table) - / sizeof (tic30_aout_howto_table[0])); - i++) - if (tic30_aout_howto_table[i].name != NULL - && strcasecmp (tic30_aout_howto_table[i].name, r_name) == 0) - return &tic30_aout_howto_table[i]; - - return NULL; -} - -static reloc_howto_type * -tic30_aout_reloc_howto (bfd *abfd, - struct reloc_std_external *relocs, - int *r_index, - int *r_extern, - int *r_pcrel) -{ - unsigned int r_length; - unsigned int r_pcrel_done; - int howto_index; - - *r_pcrel = 0; - if (bfd_header_big_endian (abfd)) - { - *r_index = ((relocs->r_index[0] << 16) | (relocs->r_index[1] << 8) | relocs->r_index[2]); - *r_extern = (0 != (relocs->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); - r_pcrel_done = (0 != (relocs->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); - r_length = ((relocs->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) >> RELOC_STD_BITS_LENGTH_SH_BIG); - } - else - { - *r_index = ((relocs->r_index[2] << 16) | (relocs->r_index[1] << 8) | relocs->r_index[0]); - *r_extern = (0 != (relocs->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); - r_pcrel_done = (0 != (relocs->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); - r_length = ((relocs->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) >> RELOC_STD_BITS_LENGTH_SH_LITTLE); - } - howto_index = r_length + 4 * r_pcrel_done; - return tic30_aout_howto_table + howto_index; -} - -/* These macros will get 24-bit values from the bfd definition. - Big-endian only. */ -#define bfd_getb_24(BFD,ADDR) \ - (bfd_get_8 (BFD, ADDR ) << 16) | \ - (bfd_get_8 (BFD, ADDR + 1) << 8) | \ - (bfd_get_8 (BFD, ADDR + 2) ) - -#define bfd_putb_24(BFD,DATA,ADDR) \ - bfd_put_8 (BFD, (bfd_byte) ((DATA >> 16) & 0xFF), ADDR ); \ - bfd_put_8 (BFD, (bfd_byte) ((DATA >> 8) & 0xFF), ADDR + 1); \ - bfd_put_8 (BFD, (bfd_byte) ( DATA & 0xFF), ADDR + 2) - -/* Set parameters about this a.out file that are machine-dependent. - This routine is called from some_aout_object_p just before it returns. */ - -static const bfd_target * -tic30_aout_callback (bfd *abfd) -{ - struct internal_exec *execp = exec_hdr (abfd); - unsigned int arch_align_power; - unsigned long arch_align; - - /* Calculate the file positions of the parts of a newly read aout header. */ - obj_textsec (abfd)->size = N_TXTSIZE (execp); - - /* The virtual memory addresses of the sections. */ - obj_textsec (abfd)->vma = N_TXTADDR (execp); - obj_datasec (abfd)->vma = N_DATADDR (execp); - obj_bsssec (abfd)->vma = N_BSSADDR (execp); - - obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; - obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; - obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; - - /* The file offsets of the sections. */ - obj_textsec (abfd)->filepos = N_TXTOFF (execp); - obj_datasec (abfd)->filepos = N_DATOFF (execp); - - /* The file offsets of the relocation info. */ - obj_textsec (abfd)->rel_filepos = N_TRELOFF (execp); - obj_datasec (abfd)->rel_filepos = N_DRELOFF (execp); - - /* The file offsets of the string table and symbol table. */ - obj_sym_filepos (abfd) = N_SYMOFF (execp); - obj_str_filepos (abfd) = N_STROFF (execp); - - /* Determine the architecture and machine type of the object file. */ -#ifdef SET_ARCH_MACH - SET_ARCH_MACH (abfd, execp); -#else - bfd_default_set_arch_mach (abfd, DEFAULT_ARCH, 0L); -#endif - - /* Now that we know the architecture, set the alignments of the - sections. This is normally done by NAME (aout,new_section_hook), - but when the initial sections were created the architecture had - not yet been set. However, for backward compatibility, we don't - set the alignment power any higher than as required by the size - of the section. */ - arch_align_power = bfd_get_arch_info (abfd)->section_align_power; - arch_align = 1 << arch_align_power; - if ((BFD_ALIGN (obj_textsec (abfd)->size, arch_align) - == obj_textsec (abfd)->size) - && (BFD_ALIGN (obj_datasec (abfd)->size, arch_align) - == obj_datasec (abfd)->size) - && (BFD_ALIGN (obj_bsssec (abfd)->size, arch_align) - == obj_bsssec (abfd)->size)) - { - obj_textsec (abfd)->alignment_power = arch_align_power; - obj_datasec (abfd)->alignment_power = arch_align_power; - obj_bsssec (abfd)->alignment_power = arch_align_power; - } - return abfd->xvec; -} - -static bfd_reloc_status_type -tic30_aout_relocate_contents (reloc_howto_type *howto, - bfd *input_bfd, - bfd_vma relocation, - bfd_byte *location) -{ - bfd_vma x; - bfd_boolean overflow; - - if (howto->size < 0) - relocation = -relocation; - - switch (howto->size) - { - default: - case 0: - abort (); - break; - case 1: - x = bfd_get_16 (input_bfd, location); - break; - case 2: - x = bfd_getb_24 (input_bfd, location); - break; - case 3: - x = bfd_get_8 (input_bfd, location); - break; - case 4: - x = bfd_get_32 (input_bfd, location); - break; - } - - overflow = FALSE; - - if (howto->complain_on_overflow != complain_overflow_dont) - { - bfd_vma check; - bfd_signed_vma signed_check; - bfd_vma add; - bfd_signed_vma signed_add; - - if (howto->rightshift == 0) - { - check = relocation; - signed_check = (bfd_signed_vma) relocation; - } - else - { - check = relocation >> howto->rightshift; - if ((bfd_signed_vma) relocation >= 0) - signed_check = check; - else - signed_check = (check | ((bfd_vma) - 1 & ~((bfd_vma) - 1 >> howto->rightshift))); - } - add = x & howto->src_mask; - signed_add = add; - if ((add & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0) - signed_add -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1; - if (howto->bitpos == 0) - { - check += add; - signed_check += signed_add; - } - else - { - check += add >> howto->bitpos; - if (signed_add >= 0) - signed_check += add >> howto->bitpos; - else - signed_check += ((add >> howto->bitpos) | ((bfd_vma) - 1 & ~((bfd_vma) - 1 >> howto->bitpos))); - } - switch (howto->complain_on_overflow) - { - case complain_overflow_signed: - { - bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; - bfd_signed_vma reloc_signed_min = ~reloc_signed_max; - - if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) - overflow = TRUE; - } - break; - case complain_overflow_unsigned: - { - bfd_vma reloc_unsigned_max = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if (check > reloc_unsigned_max) - overflow = TRUE; - } - break; - case complain_overflow_bitfield: - { - bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if ((check & ~reloc_bits) != 0 - && (((bfd_vma) signed_check & ~reloc_bits) - != ((bfd_vma) -1 & ~reloc_bits))) - overflow = TRUE; - } - break; - default: - abort (); - } - } - relocation >>= (bfd_vma) howto->rightshift; - relocation <<= (bfd_vma) howto->bitpos; - x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)); - switch (howto->size) - { - default: - case 0: - abort (); - break; - case 1: - bfd_put_16 (input_bfd, x, location); - break; - case 2: - bfd_putb_24 (input_bfd, x, location); - break; - case 3: - bfd_put_8 (input_bfd, x, location); - break; - case 4: - bfd_put_32 (input_bfd, x, location); - break; - } - return overflow ? bfd_reloc_overflow : bfd_reloc_ok; -} - -static bfd_reloc_status_type -tic30_aout_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; - - if (address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - relocation = value + addend; - if (howto->pc_relative) - { - relocation -= (input_section->output_section->vma + input_section->output_offset); - if (howto->pcrel_offset) - relocation -= address; - } - return tic30_aout_relocate_contents (howto, input_bfd, relocation, - contents + address); -} - -/* Finish up the reading of an a.out file header. */ - -static const bfd_target * -tic30_aout_object_p (bfd *abfd) -{ - struct external_exec exec_bytes; /* Raw exec header from file. */ - struct internal_exec exec; /* Cleaned-up exec header. */ - const bfd_target *target; - bfd_size_type amt = EXEC_BYTES_SIZE; - - if (bfd_bread (& exec_bytes, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return 0; - } - -#ifdef SWAP_MAGIC - exec.a_info = SWAP_MAGIC (exec_bytes.e_info); -#else - exec.a_info = H_GET_32 (abfd, exec_bytes.e_info); -#endif /* SWAP_MAGIC */ - - if (N_BADMAG (&exec)) - return 0; -#ifdef MACHTYPE_OK - if (!(MACHTYPE_OK (N_MACHTYPE (&exec)))) - return 0; -#endif - - NAME (aout, swap_exec_header_in) (abfd, &exec_bytes, &exec); - -#ifdef SWAP_MAGIC - /* Swap_exec_header_in read in a_info with the wrong byte order. */ - exec.a_info = SWAP_MAGIC (exec_bytes.e_info); -#endif - - target = NAME (aout, some_aout_object_p) (abfd, &exec, tic30_aout_callback); - -#ifdef ENTRY_CAN_BE_ZERO - /* The NEWSOS3 entry-point is/was 0, which (amongst other lossage) - means that it isn't obvious if EXEC_P should be set. - All of the following must be true for an executable: - There must be no relocations, the bfd can be neither an - archive nor an archive element, and the file must be executable. */ - - if (exec.a_trsize + exec.a_drsize == 0 - && bfd_get_format (abfd) == bfd_object && abfd->my_archive == NULL) - { - struct stat buf; -#ifndef S_IXUSR -#define S_IXUSR 0100 /* Execute by owner. */ -#endif - if (stat (abfd->filename, &buf) == 0 && (buf.st_mode & S_IXUSR)) - abfd->flags |= EXEC_P; - } -#endif - - return target; -} - -/* Copy private section data. This actually does nothing with the - sections. It copies the subformat field. We copy it here, because - we need to know whether this is a QMAGIC file before we set the - section contents, and copy_private_bfd_data is not called until - after the section contents have been set. */ - -static bfd_boolean -MY_bfd_copy_private_section_data (bfd *ibfd, - asection *isec ATTRIBUTE_UNUSED, - bfd *obfd, - asection *osec ATTRIBUTE_UNUSED) -{ - if (bfd_get_flavour (obfd) == bfd_target_aout_flavour) - obj_aout_subformat (obfd) = obj_aout_subformat (ibfd); - return TRUE; -} - -/* Write an object file. - Section contents have already been written. We write the - file header, symbols, and relocation. */ - -static bfd_boolean -tic30_aout_write_object_contents (bfd *abfd) -{ - struct external_exec exec_bytes; - struct internal_exec *execp = exec_hdr (abfd); - - obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; - - { - if (adata (abfd).magic == undecided_magic) - NAME (aout, adjust_sizes_and_vmas) (abfd); - - 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 (adata (abfd).exec_bytes_size > 0) - { - bfd_size_type amt; - - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) - return FALSE; - amt = adata (abfd).exec_bytes_size; - if (bfd_bwrite (& exec_bytes, amt, abfd) != amt) - return FALSE; - } - - /* Now write out reloc info, followed by syms and strings. */ - if (bfd_get_outsymbols (abfd) != (asymbol **) NULL - && bfd_get_symcount (abfd) != 0) - { - if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (execp)), SEEK_SET) != 0) - return FALSE; - - if (!NAME (aout, write_syms) (abfd)) - return FALSE; - } - - if (bfd_seek (abfd, (file_ptr) (N_TRELOFF (execp)), SEEK_SET) != 0) - return FALSE; - if (!NAME (aout, squirt_out_relocs) (abfd, obj_textsec (abfd))) - return FALSE; - - if (bfd_seek (abfd, (file_ptr) (N_DRELOFF (execp)), SEEK_SET) != 0) - return FALSE; - if (!NAME (aout, squirt_out_relocs) (abfd, obj_datasec (abfd))) - return FALSE; - } - - return TRUE; -} - -#ifndef MY_final_link_callback - -/* Callback for the final_link routine to set the section offsets. */ - -static void -MY_final_link_callback (bfd *abfd, - file_ptr *ptreloff, - file_ptr *pdreloff, - file_ptr *psymoff) -{ - struct internal_exec *execp = exec_hdr (abfd); - - *ptreloff = obj_datasec (abfd)->filepos + execp->a_data; - *pdreloff = *ptreloff + execp->a_trsize; - *psymoff = *pdreloff + execp->a_drsize; -} - -#endif - -#ifndef MY_bfd_final_link - -/* Final link routine. We need to use a call back to get the correct - offsets in the output file. */ - -static bfd_boolean -MY_bfd_final_link (bfd *abfd, struct bfd_link_info *info) -{ - struct internal_exec *execp = exec_hdr (abfd); - file_ptr pos; - bfd_vma vma = 0; - int pad; - - /* Set the executable header size to 0, as we don't want one for an - output. */ - adata (abfd).exec_bytes_size = 0; - pos = adata (abfd).exec_bytes_size; - /* Text. */ - vma = info->create_object_symbols_section->vma; - pos += vma; - obj_textsec (abfd)->filepos = pos; - obj_textsec (abfd)->vma = vma; - obj_textsec (abfd)->user_set_vma = 1; - pos += obj_textsec (abfd)->size; - vma += obj_textsec (abfd)->size; - - /* Data. */ - if (abfd->flags & D_PAGED) - { - if (info->create_object_symbols_section->next->vma > 0) - obj_datasec (abfd)->vma = info->create_object_symbols_section->next->vma; - else - obj_datasec (abfd)->vma = BFD_ALIGN (vma, adata (abfd).segment_size); - } - else - obj_datasec (abfd)->vma = BFD_ALIGN (vma, 4); - - if (obj_datasec (abfd)->vma < vma) - obj_datasec (abfd)->vma = BFD_ALIGN (vma, 4); - - obj_datasec (abfd)->user_set_vma = 1; - vma = obj_datasec (abfd)->vma; - obj_datasec (abfd)->filepos = vma + adata (abfd).exec_bytes_size; - execp->a_text = vma - obj_textsec (abfd)->vma; - obj_textsec (abfd)->size = execp->a_text; - - /* Since BSS follows data immediately, see if it needs alignment. */ - vma += obj_datasec (abfd)->size; - pad = align_power (vma, obj_bsssec (abfd)->alignment_power) - vma; - obj_datasec (abfd)->size += pad; - pos += obj_datasec (abfd)->size; - execp->a_data = obj_datasec (abfd)->size; - - /* BSS. */ - obj_bsssec (abfd)->vma = vma; - obj_bsssec (abfd)->user_set_vma = 1; - - /* We are fully resized, so don't readjust in final_link. */ - adata (abfd).magic = z_magic; - - return NAME (aout, final_link) (abfd, info, MY_final_link_callback); -} - -#endif - -static enum machine_type -tic30_aout_machine_type (enum bfd_architecture arch, - unsigned long machine ATTRIBUTE_UNUSED, - bfd_boolean *unknown) -{ - enum machine_type arch_flags; - - arch_flags = M_UNKNOWN; - *unknown = TRUE; - - switch (arch) - { - case bfd_arch_tic30: - *unknown = FALSE; - break; - default: - arch_flags = M_UNKNOWN; - } - if (arch_flags != M_UNKNOWN) - *unknown = FALSE; - return arch_flags; -} - -static bfd_boolean -tic30_aout_set_arch_mach (bfd *abfd, - enum bfd_architecture arch, - unsigned long machine) -{ - if (!bfd_default_set_arch_mach (abfd, arch, machine)) - return FALSE; - if (arch != bfd_arch_unknown) - { - bfd_boolean unknown; - tic30_aout_machine_type (arch, machine, &unknown); - if (unknown) - return FALSE; - } - obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; - return (*aout_backend_info (abfd)->set_sizes) (abfd); -} - -/* We assume BFD generic archive files. */ -#ifndef MY_openr_next_archived_file -#define MY_openr_next_archived_file bfd_generic_openr_next_archived_file -#endif -#ifndef MY_get_elt_at_index -#define MY_get_elt_at_index _bfd_generic_get_elt_at_index -#endif -#ifndef MY_generic_stat_arch_elt -#define MY_generic_stat_arch_elt bfd_generic_stat_arch_elt -#endif -#ifndef MY_slurp_armap -#define MY_slurp_armap bfd_slurp_bsd_armap -#endif -#ifndef MY_slurp_extended_name_table -#define MY_slurp_extended_name_table _bfd_slurp_extended_name_table -#endif -#ifndef MY_construct_extended_name_table -#define MY_construct_extended_name_table \ - _bfd_archive_bsd_construct_extended_name_table -#endif -#ifndef MY_write_armap -#define MY_write_armap _bfd_bsd_write_armap -#endif -#ifndef MY_read_ar_hdr -#define MY_read_ar_hdr _bfd_generic_read_ar_hdr -#endif -#ifndef MY_write_ar_hdr -#define MY_write_ar_hdr _bfd_generic_write_ar_hdr -#endif -#ifndef MY_truncate_arname -#define MY_truncate_arname bfd_bsd_truncate_arname -#endif -#ifndef MY_update_armap_timestamp -#define MY_update_armap_timestamp _bfd_archive_bsd_update_armap_timestamp -#endif - -/* No core file defined here -- configure in trad-core.c separately. */ -#ifndef MY_core_file_failing_command -#define MY_core_file_failing_command _bfd_nocore_core_file_failing_command -#endif -#ifndef MY_core_file_failing_signal -#define MY_core_file_failing_signal _bfd_nocore_core_file_failing_signal -#endif -#ifndef MY_core_file_matches_executable_p -#define MY_core_file_matches_executable_p \ - _bfd_nocore_core_file_matches_executable_p -#endif -#ifndef MY_core_file_pid -#define MY_core_file_pid _bfd_nocore_core_file_pid -#endif -#ifndef MY_core_file_p -#define MY_core_file_p _bfd_dummy_target -#endif - -#ifndef MY_bfd_debug_info_start -#define MY_bfd_debug_info_start bfd_void -#endif -#ifndef MY_bfd_debug_info_end -#define MY_bfd_debug_info_end bfd_void -#endif -#ifndef MY_bfd_debug_info_accumulate -#define MY_bfd_debug_info_accumulate \ - (void (*) (bfd*, struct bfd_section *)) bfd_void -#endif - -#ifndef MY_core_file_failing_command -#define MY_core_file_failing_command NAME (aout, core_file_failing_command) -#endif -#ifndef MY_core_file_failing_signal -#define MY_core_file_failing_signal NAME (aout, core_file_failing_signal) -#endif -#ifndef MY_core_file_matches_executable_p -#define MY_core_file_matches_executable_p NAME (aout, core_file_matches_executable_p) -#endif -#ifndef MY_set_section_contents -#define MY_set_section_contents NAME (aout, set_section_contents) -#endif -#ifndef MY_get_section_contents -#define MY_get_section_contents aout_32_get_section_contents -#endif -#ifndef MY_get_section_contents_in_window -#define MY_get_section_contents_in_window _bfd_generic_get_section_contents_in_window -#endif -#ifndef MY_new_section_hook -#define MY_new_section_hook NAME (aout, new_section_hook) -#endif -#ifndef MY_get_symtab_upper_bound -#define MY_get_symtab_upper_bound NAME (aout, get_symtab_upper_bound) -#endif -#ifndef MY_canonicalize_symtab -#define MY_canonicalize_symtab NAME (aout, canonicalize_symtab) -#endif -#ifndef MY_get_reloc_upper_bound -#define MY_get_reloc_upper_bound NAME (aout, get_reloc_upper_bound) -#endif -#ifndef MY_canonicalize_reloc -#define MY_canonicalize_reloc NAME (aout, canonicalize_reloc) -#endif -#ifndef MY_set_reloc -#define MY_set_reloc _bfd_generic_set_reloc -#endif -#ifndef MY_make_empty_symbol -#define MY_make_empty_symbol NAME (aout, make_empty_symbol) -#endif -#ifndef MY_print_symbol -#define MY_print_symbol NAME (aout, print_symbol) -#endif -#ifndef MY_get_symbol_info -#define MY_get_symbol_info NAME (aout, get_symbol_info) -#endif -#ifndef MY_get_symbol_version_string -#define MY_get_symbol_version_string \ - _bfd_nosymbols_get_symbol_version_string -#endif -#ifndef MY_get_lineno -#define MY_get_lineno NAME (aout, get_lineno) -#endif -#ifndef MY_set_arch_mach -#define MY_set_arch_mach tic30_aout_set_arch_mach -#endif -#ifndef MY_find_nearest_line -#define MY_find_nearest_line NAME (aout, find_nearest_line) -#endif -#ifndef MY_find_line -#define MY_find_line _bfd_nosymbols_find_line -#endif -#ifndef MY_find_inliner_info -#define MY_find_inliner_info _bfd_nosymbols_find_inliner_info -#endif -#ifndef MY_sizeof_headers -#define MY_sizeof_headers NAME (aout, sizeof_headers) -#endif -#ifndef MY_bfd_get_relocated_section_contents -#define MY_bfd_get_relocated_section_contents \ - bfd_generic_get_relocated_section_contents -#endif -#ifndef MY_bfd_relax_section -#define MY_bfd_relax_section bfd_generic_relax_section -#endif -#ifndef MY_bfd_gc_sections -#define MY_bfd_gc_sections bfd_generic_gc_sections -#endif -#ifndef MY_bfd_lookup_section_flags -#define MY_bfd_lookup_section_flags bfd_generic_lookup_section_flags -#endif -#ifndef MY_bfd_merge_sections -#define MY_bfd_merge_sections bfd_generic_merge_sections -#endif -#ifndef MY_bfd_is_group_section -#define MY_bfd_is_group_section bfd_generic_is_group_section -#endif -#ifndef MY_bfd_discard_group -#define MY_bfd_discard_group bfd_generic_discard_group -#endif -#ifndef MY_section_already_linked -#define MY_section_already_linked \ - _bfd_generic_section_already_linked -#endif -#ifndef MY_bfd_define_common_symbol -#define MY_bfd_define_common_symbol bfd_generic_define_common_symbol -#endif -#ifndef MY_bfd_define_start_stop -#define MY_bfd_define_start_stop bfd_generic_define_start_stop -#endif -#ifndef MY_bfd_reloc_type_lookup -#define MY_bfd_reloc_type_lookup tic30_aout_reloc_type_lookup -#endif -#ifndef MY_bfd_reloc_name_lookup -#define MY_bfd_reloc_name_lookup tic30_aout_reloc_name_lookup -#endif -#ifndef MY_bfd_make_debug_symbol -#define MY_bfd_make_debug_symbol 0 -#endif -#ifndef MY_read_minisymbols -#define MY_read_minisymbols NAME (aout, read_minisymbols) -#endif -#ifndef MY_minisymbol_to_symbol -#define MY_minisymbol_to_symbol NAME (aout, minisymbol_to_symbol) -#endif -#ifndef MY_bfd_link_hash_table_create -#define MY_bfd_link_hash_table_create NAME (aout, link_hash_table_create) -#endif -#ifndef MY_bfd_link_add_symbols -#define MY_bfd_link_add_symbols NAME (aout, link_add_symbols) -#endif -#ifndef MY_bfd_link_just_syms -#define MY_bfd_link_just_syms _bfd_generic_link_just_syms -#endif -#ifndef MY_bfd_copy_link_hash_symbol_type -#define MY_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type -#endif -#ifndef MY_bfd_link_split_section -#define MY_bfd_link_split_section _bfd_generic_link_split_section -#endif - -#ifndef MY_bfd_link_check_relocs -#define MY_bfd_link_check_relocs _bfd_generic_link_check_relocs -#endif - -#ifndef MY_bfd_copy_private_bfd_data -#define MY_bfd_copy_private_bfd_data _bfd_generic_bfd_copy_private_bfd_data -#endif - -#ifndef MY_bfd_merge_private_bfd_data -#define MY_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data -#endif - -#ifndef MY_bfd_copy_private_symbol_data -#define MY_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data -#endif - -#ifndef MY_bfd_copy_private_header_data -#define MY_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data -#endif - -#ifndef MY_bfd_print_private_bfd_data -#define MY_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data -#endif - -#ifndef MY_bfd_set_private_flags -#define MY_bfd_set_private_flags _bfd_generic_bfd_set_private_flags -#endif - -#ifndef MY_bfd_is_local_label_name -#define MY_bfd_is_local_label_name bfd_generic_is_local_label_name -#endif - -#ifndef MY_bfd_is_target_special_symbol -#define MY_bfd_is_target_special_symbol \ - ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) -#endif - -#ifndef MY_bfd_free_cached_info -#define MY_bfd_free_cached_info NAME (aout, bfd_free_cached_info) -#endif - -#ifndef MY_close_and_cleanup -#define MY_close_and_cleanup MY_bfd_free_cached_info -#endif - -#ifndef MY_get_dynamic_symtab_upper_bound -#define MY_get_dynamic_symtab_upper_bound \ - _bfd_nodynamic_get_dynamic_symtab_upper_bound -#endif -#ifndef MY_canonicalize_dynamic_symtab -#define MY_canonicalize_dynamic_symtab \ - _bfd_nodynamic_canonicalize_dynamic_symtab -#endif -#ifndef MY_get_synthetic_symtab -#define MY_get_synthetic_symtab \ - _bfd_nodynamic_get_synthetic_symtab -#endif -#ifndef MY_get_dynamic_reloc_upper_bound -#define MY_get_dynamic_reloc_upper_bound \ - _bfd_nodynamic_get_dynamic_reloc_upper_bound -#endif -#ifndef MY_canonicalize_dynamic_reloc -#define MY_canonicalize_dynamic_reloc \ - _bfd_nodynamic_canonicalize_dynamic_reloc -#endif - -/* Aout symbols normally have leading underscores. */ -#ifndef MY_symbol_leading_char -#define MY_symbol_leading_char '_' -#endif - -/* Aout archives normally use spaces for padding. */ -#ifndef AR_PAD_CHAR -#define AR_PAD_CHAR ' ' -#endif - -#ifndef MY_BFD_TARGET -const bfd_target tic30_aout_vec = -{ - TARGETNAME, /* Name. */ - bfd_target_aout_flavour, - BFD_ENDIAN_BIG, /* Target byte order (big). */ - BFD_ENDIAN_BIG, /* Target headers byte order (big). */ - (HAS_RELOC | /* Object flags. */ - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ - MY_symbol_leading_char, - AR_PAD_CHAR, /* AR_pad_char. */ - 15, /* AR_max_namelen. */ - 0, /* match priority. */ - 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, MY_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, MY_core_file_p}, - {bfd_false, MY_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, MY_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (MY), - BFD_JUMP_TABLE_COPY (MY), - BFD_JUMP_TABLE_CORE (MY), - BFD_JUMP_TABLE_ARCHIVE (MY), - BFD_JUMP_TABLE_SYMBOLS (MY), - BFD_JUMP_TABLE_RELOCS (MY), - BFD_JUMP_TABLE_WRITE (MY), - BFD_JUMP_TABLE_LINK (MY), - BFD_JUMP_TABLE_DYNAMIC (MY), - - NULL, - - MY_backend_data -}; -#endif /* MY_BFD_TARGET */ diff --git a/sdcc/support/sdbinutils/bfd/aout0.c b/sdcc/support/sdbinutils/bfd/aout0.c deleted file mode 100644 index 890dce6de..000000000 --- a/sdcc/support/sdbinutils/bfd/aout0.c +++ /dev/null @@ -1,38 +0,0 @@ -/* BFD backend for SunOS style a.out with flags set to 0 - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGETNAME "a.out-zero-big" - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (aout0_be_,OP) - -#include "sysdep.h" -#include "bfd.h" - -#define MY_exec_hdr_flags 0 - -#define MACHTYPE_OK(mtype) \ - ((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) - -/* Include the usual a.out support. */ -#include "aoutf1.h" diff --git a/sdcc/support/sdbinutils/bfd/aout32.c b/sdcc/support/sdbinutils/bfd/aout32.c deleted file mode 100644 index 6f159e8b4..000000000 --- a/sdcc/support/sdbinutils/bfd/aout32.c +++ /dev/null @@ -1,24 +0,0 @@ -/* BFD back-end for 32-bit a.out files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define ARCH_SIZE 32 - -#include "aoutx.h" diff --git a/sdcc/support/sdbinutils/bfd/aout64.c b/sdcc/support/sdbinutils/bfd/aout64.c deleted file mode 100644 index 936d3b5e1..000000000 --- a/sdcc/support/sdbinutils/bfd/aout64.c +++ /dev/null @@ -1,32 +0,0 @@ -/* BFD back-end for 64-bit a.out files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define ARCH_SIZE 64 - -/* aoutx.h requires definitions for BMAGIC and QMAGIC. */ -#ifndef BMAGIC -#define BMAGIC 0 -#endif -#ifndef QMAGIC -#define QMAGIC 0 -#endif - -#include "aoutx.h" diff --git a/sdcc/support/sdbinutils/bfd/aoutf1.h b/sdcc/support/sdbinutils/bfd/aoutf1.h deleted file mode 100644 index 88ecf1ee1..000000000 --- a/sdcc/support/sdbinutils/bfd/aoutf1.h +++ /dev/null @@ -1,793 +0,0 @@ -/* A.out "format 1" file handling code for BFD. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#include "aout/sun4.h" -#include "libaout.h" /* BFD a.out internal data structures. */ - -#include "aout/aout64.h" -#include "aout/stab_gnu.h" -#include "aout/ar.h" - -/* This is needed to reject a NewsOS file, e.g. in - gdb/testsuite/gdb.t10/crossload.exp. - I needed to add M_UNKNOWN to recognize a 68000 object, so this will - probably no longer reject a NewsOS object. . */ -#ifndef MACHTYPE_OK -#define MACHTYPE_OK(mtype) \ - (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \ - || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \ - && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL)) -#endif - -/* The file @code{aoutf1.h} contains the code for BFD's - a.out back end. Control over the generated back end is given by these - two preprocessor names: - @table @code - @item ARCH_SIZE - This value should be either 32 or 64, depending upon the size of an - int in the target format. It changes the sizes of the structs which - perform the memory/disk mapping of structures. - - The 64 bit backend may only be used if the host compiler supports 64 - ints (eg long long with gcc), by defining the name @code{BFD_HOST_64_BIT} in @code{bfd.h}. - With this name defined, @emph{all} bfd operations are performed with 64bit - arithmetic, not just those to a 64bit target. - - @item TARGETNAME - The name put into the target vector. - @item - @end table. */ - -#if ARCH_SIZE == 64 -#define sunos_set_arch_mach sunos_64_set_arch_mach -#define sunos_write_object_contents aout_64_sunos4_write_object_contents -#else -#define sunos_set_arch_mach sunos_32_set_arch_mach -#define sunos_write_object_contents aout_32_sunos4_write_object_contents -#endif - -/* Merge backend data into the output file. - This is necessary on sparclet-aout where we want the resultant machine - number to be M_SPARCLET if any input file is M_SPARCLET. */ - -#define MY_bfd_merge_private_bfd_data sunos_merge_private_bfd_data - -static bfd_boolean -sunos_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - if (bfd_get_flavour (ibfd) != bfd_target_aout_flavour - || bfd_get_flavour (obfd) != bfd_target_aout_flavour) - return TRUE; - - if (bfd_get_arch (obfd) == bfd_arch_sparc) - { - if (bfd_get_mach (obfd) < bfd_get_mach (ibfd)) - bfd_set_arch_mach (obfd, bfd_arch_sparc, bfd_get_mach (ibfd)); - } - - return TRUE; -} - -/* This is either sunos_32_set_arch_mach or sunos_64_set_arch_mach, - depending upon ARCH_SIZE. */ - -static void -sunos_set_arch_mach (bfd *abfd, enum machine_type machtype) -{ - /* Determine the architecture and machine type of the object file. */ - enum bfd_architecture arch; - unsigned long machine; - - switch (machtype) - { - case M_UNKNOWN: - /* Some Sun3s make magic numbers without cpu types in them, so - we'll default to the 68000. */ - arch = bfd_arch_m68k; - machine = bfd_mach_m68000; - break; - - case M_68010: - case M_HP200: - arch = bfd_arch_m68k; - machine = bfd_mach_m68010; - break; - - case M_68020: - case M_HP300: - arch = bfd_arch_m68k; - machine = bfd_mach_m68020; - break; - - case M_SPARC: - arch = bfd_arch_sparc; - machine = 0; - break; - - case M_SPARCLET: - arch = bfd_arch_sparc; - machine = bfd_mach_sparc_sparclet; - break; - - case M_SPARCLITE_LE: - arch = bfd_arch_sparc; - machine = bfd_mach_sparc_sparclite_le; - break; - - case M_386: - case M_386_DYNIX: - arch = bfd_arch_i386; - machine = 0; - break; - - case M_HPUX: - arch = bfd_arch_m68k; - machine = 0; - break; - - default: - arch = bfd_arch_obscure; - machine = 0; - break; - } - bfd_set_arch_mach (abfd, arch, machine); -} - -#define SET_ARCH_MACH(ABFD, EXECP) \ - NAME(sunos,set_arch_mach) (ABFD, N_MACHTYPE (EXECP)); \ - choose_reloc_size(ABFD); - -/* Determine the size of a relocation entry, based on the architecture. */ - -static void -choose_reloc_size (bfd *abfd) -{ - switch (bfd_get_arch (abfd)) - { - case bfd_arch_sparc: - obj_reloc_entry_size (abfd) = RELOC_EXT_SIZE; - break; - default: - obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; - break; - } -} - -/* Write an object file in SunOS format. Section contents have - already been written. We write the file header, symbols, and - relocation. The real name of this function is either - aout_64_sunos4_write_object_contents or - aout_32_sunos4_write_object_contents, depending upon ARCH_SIZE. */ - -static bfd_boolean -sunos_write_object_contents (bfd *abfd) -{ - struct external_exec exec_bytes; - struct internal_exec *execp = exec_hdr (abfd); - - /* Magic number, maestro, please! */ - switch (bfd_get_arch (abfd)) - { - case bfd_arch_m68k: - switch (bfd_get_mach (abfd)) - { - case bfd_mach_m68000: - N_SET_MACHTYPE (execp, M_UNKNOWN); - break; - case bfd_mach_m68010: - N_SET_MACHTYPE (execp, M_68010); - break; - default: - case bfd_mach_m68020: - N_SET_MACHTYPE (execp, M_68020); - break; - } - break; - case bfd_arch_sparc: - switch (bfd_get_mach (abfd)) - { - case bfd_mach_sparc_sparclet: - N_SET_MACHTYPE (execp, M_SPARCLET); - break; - case bfd_mach_sparc_sparclite_le: - N_SET_MACHTYPE (execp, M_SPARCLITE_LE); - break; - default: - N_SET_MACHTYPE (execp, M_SPARC); - break; - } - break; - case bfd_arch_i386: - N_SET_MACHTYPE (execp, M_386); - break; - default: - N_SET_MACHTYPE (execp, M_UNKNOWN); - } - - choose_reloc_size (abfd); - - N_SET_FLAGS (execp, aout_backend_info (abfd)->exec_hdr_flags); - - N_SET_DYNAMIC (execp, (long)(bfd_get_file_flags (abfd) & DYNAMIC)); - - WRITE_HEADERS (abfd, execp); - - return TRUE; -} - -/* Core files. */ - -#define CORE_MAGIC 0x080456 -#define CORE_NAMELEN 16 - -/* The core structure is taken from the Sun documentation. - Unfortunately, they don't document the FPA structure, or at least I - can't find it easily. Fortunately the core header contains its own - length. So this shouldn't cause problems, except for c_ucode, which - so far we don't use but is easy to find with a little arithmetic. */ - -/* But the reg structure can be gotten from the SPARC processor handbook. - This really should be in a GNU include file though so that gdb can use - the same info. */ -struct regs -{ - int r_psr; - int r_pc; - int r_npc; - int r_y; - int r_g1; - int r_g2; - int r_g3; - int r_g4; - int r_g5; - int r_g6; - int r_g7; - int r_o0; - int r_o1; - int r_o2; - int r_o3; - int r_o4; - int r_o5; - int r_o6; - int r_o7; -}; - -/* Taken from Sun documentation: */ - -/* FIXME: It's worse than we expect. This struct contains TWO substructs - neither of whose size we know, WITH STUFF IN BETWEEN THEM! We can't - even portably access the stuff in between! */ - -struct external_sparc_core -{ - int c_magic; /* Corefile magic number. */ - int c_len; /* Sizeof (struct core). */ -#define SPARC_CORE_LEN 432 - struct regs c_regs; /* General purpose registers -- MACHDEP SIZE. */ - struct external_exec c_aouthdr; /* A.out header. */ - int c_signo; /* Killing signal, if any. */ - int c_tsize; /* Text size (bytes). */ - int c_dsize; /* Data size (bytes). */ - int c_ssize; /* Stack size (bytes). */ - char c_cmdname[CORE_NAMELEN + 1]; /* Command name. */ - double fp_stuff[1]; /* External FPU state (size unknown by us). */ - /* The type "double" is critical here, for alignment. - SunOS declares a struct here, but the struct's - alignment is double since it contains doubles. */ - int c_ucode; /* Exception no. from u_code. */ - /* This member is not accessible by name since - we don't portably know the size of fp_stuff. */ -}; - -/* Core files generated by the BCP (the part of Solaris which allows - it to run SunOS4 a.out files). */ -struct external_solaris_bcp_core -{ - int c_magic; /* Corefile magic number. */ - int c_len; /* Sizeof (struct core). */ -#define SOLARIS_BCP_CORE_LEN 456 - struct regs c_regs; /* General purpose registers -- MACHDEP SIZE. */ - int c_exdata_vp; /* Exdata structure. */ - int c_exdata_tsize; - int c_exdata_dsize; - int c_exdata_bsize; - int c_exdata_lsize; - int c_exdata_nshlibs; - short c_exdata_mach; - short c_exdata_mag; - int c_exdata_toffset; - int c_exdata_doffset; - int c_exdata_loffset; - int c_exdata_txtorg; - int c_exdata_datorg; - int c_exdata_entloc; - int c_signo; /* Killing signal, if any. */ - int c_tsize; /* Text size (bytes). */ - int c_dsize; /* Data size (bytes). */ - int c_ssize; /* Stack size (bytes). */ - char c_cmdname[CORE_NAMELEN + 1]; /* Command name. */ - double fp_stuff[1]; /* External FPU state (size unknown by us). */ - /* The type "double" is critical here, for alignment. - SunOS declares a struct here, but the struct's - alignment is double since it contains doubles. */ - int c_ucode; /* Exception no. from u_code. */ - /* This member is not accessible by name since - we don't portably know the size of fp_stuff. */ -}; - -struct external_sun3_core -{ - int c_magic; /* Corefile magic number. */ - int c_len; /* Sizeof (struct core). */ -#define SUN3_CORE_LEN 826 /* As of SunOS 4.1.1. */ - int c_regs[18]; /* General purpose registers -- MACHDEP SIZE. */ - struct external_exec c_aouthdr; /* A.out header. */ - int c_signo; /* Killing signal, if any. */ - int c_tsize; /* Text size (bytes). */ - int c_dsize; /* Data size (bytes). */ - int c_ssize; /* Stack size (bytes). */ - char c_cmdname[CORE_NAMELEN + 1]; /* Command name. */ - double fp_stuff[1]; /* External FPU state (size unknown by us). */ - /* The type "double" is critical here, for alignment. - SunOS declares a struct here, but the struct's - alignment is double since it contains doubles. */ - int c_ucode; /* Exception no. from u_code. */ - /* This member is not accessible by name since - we don't portably know the size of fp_stuff. */ -}; - -struct internal_sunos_core -{ - int c_magic; /* Corefile magic number. */ - int c_len; /* Sizeof (struct core). */ - long c_regs_pos; /* File offset of General purpose registers. */ - int c_regs_size; /* Size of General purpose registers. */ - struct internal_exec c_aouthdr; /* A.out header. */ - int c_signo; /* Killing signal, if any. */ - int c_tsize; /* Text size (bytes). */ - int c_dsize; /* Data size (bytes). */ - bfd_vma c_data_addr; /* Data start (address). */ - int c_ssize; /* Stack size (bytes). */ - bfd_vma c_stacktop; /* Stack top (address). */ - char c_cmdname[CORE_NAMELEN + 1]; /* Command name. */ - long fp_stuff_pos; /* File offset of external FPU state (regs). */ - int fp_stuff_size; /* Size of it. */ - int c_ucode; /* Exception no. from u_code. */ -}; - -/* Byte-swap in the Sun-3 core structure. */ - -static void -swapcore_sun3 (bfd *abfd, char *ext, struct internal_sunos_core *intcore) -{ - struct external_sun3_core *extcore = (struct external_sun3_core *) ext; - - intcore->c_magic = H_GET_32 (abfd, &extcore->c_magic); - intcore->c_len = H_GET_32 (abfd, &extcore->c_len); - intcore->c_regs_pos = offsetof (struct external_sun3_core, c_regs); - intcore->c_regs_size = sizeof (extcore->c_regs); -#if ARCH_SIZE == 64 - aout_64_swap_exec_header_in -#else - aout_32_swap_exec_header_in -#endif - (abfd, &extcore->c_aouthdr, &intcore->c_aouthdr); - intcore->c_signo = H_GET_32 (abfd, &extcore->c_signo); - intcore->c_tsize = H_GET_32 (abfd, &extcore->c_tsize); - intcore->c_dsize = H_GET_32 (abfd, &extcore->c_dsize); - intcore->c_data_addr = N_DATADDR (&intcore->c_aouthdr); - intcore->c_ssize = H_GET_32 (abfd, &extcore->c_ssize); - memcpy (intcore->c_cmdname, extcore->c_cmdname, sizeof (intcore->c_cmdname)); - intcore->fp_stuff_pos = offsetof (struct external_sun3_core, fp_stuff); - /* FP stuff takes up whole rest of struct, except c_ucode. */ - intcore->fp_stuff_size = intcore->c_len - (sizeof extcore->c_ucode) - - offsetof (struct external_sun3_core, fp_stuff); - /* Ucode is the last thing in the struct -- just before the end. */ - intcore->c_ucode = H_GET_32 (abfd, - (intcore->c_len - - sizeof (extcore->c_ucode) - + (unsigned char *) extcore)); - intcore->c_stacktop = 0x0E000000; /* By experimentation. */ -} - -/* Byte-swap in the Sparc core structure. */ - -static void -swapcore_sparc (bfd *abfd, char *ext, struct internal_sunos_core *intcore) -{ - struct external_sparc_core *extcore = (struct external_sparc_core *) ext; - - intcore->c_magic = H_GET_32 (abfd, &extcore->c_magic); - intcore->c_len = H_GET_32 (abfd, &extcore->c_len); - intcore->c_regs_pos = offsetof (struct external_sparc_core, c_regs); - intcore->c_regs_size = sizeof (extcore->c_regs); -#if ARCH_SIZE == 64 - aout_64_swap_exec_header_in -#else - aout_32_swap_exec_header_in -#endif - (abfd, &extcore->c_aouthdr, &intcore->c_aouthdr); - intcore->c_signo = H_GET_32 (abfd, &extcore->c_signo); - intcore->c_tsize = H_GET_32 (abfd, &extcore->c_tsize); - intcore->c_dsize = H_GET_32 (abfd, &extcore->c_dsize); - intcore->c_data_addr = N_DATADDR (&intcore->c_aouthdr); - intcore->c_ssize = H_GET_32 (abfd, &extcore->c_ssize); - memcpy (intcore->c_cmdname, extcore->c_cmdname, sizeof (intcore->c_cmdname)); - intcore->fp_stuff_pos = offsetof (struct external_sparc_core, fp_stuff); - /* FP stuff takes up whole rest of struct, except c_ucode. */ - intcore->fp_stuff_size = intcore->c_len - (sizeof extcore->c_ucode) - - offsetof (struct external_sparc_core, fp_stuff); - /* Ucode is the last thing in the struct -- just before the end. */ - intcore->c_ucode = H_GET_32 (abfd, - (intcore->c_len - - sizeof (extcore->c_ucode) - + (unsigned char *) extcore)); - - /* Supposedly the user stack grows downward from the bottom of kernel memory. - Presuming that this remains true, this definition will work. */ - /* Now sun has provided us with another challenge. The value is different - for sparc2 and sparc10 (both running SunOS 4.1.3). We pick one or - the other based on the current value of the stack pointer. This - loses (a) if the stack pointer has been clobbered, or (b) if the stack - is larger than 128 megabytes. - - It's times like these you're glad they're switching to ELF. - - Note that using include files or nlist on /vmunix would be wrong, - because we want the value for this core file, no matter what kind of - machine we were compiled on or are running on. */ -#define SPARC_USRSTACK_SPARC2 ((bfd_vma)0xf8000000) -#define SPARC_USRSTACK_SPARC10 ((bfd_vma)0xf0000000) - { - bfd_vma sp = H_GET_32 (abfd, &extcore->c_regs.r_o6); - if (sp < SPARC_USRSTACK_SPARC10) - intcore->c_stacktop = SPARC_USRSTACK_SPARC10; - else - intcore->c_stacktop = SPARC_USRSTACK_SPARC2; - } -} - -/* Byte-swap in the Solaris BCP core structure. */ - -static void -swapcore_solaris_bcp (bfd *abfd, char *ext, struct internal_sunos_core *intcore) -{ - struct external_solaris_bcp_core *extcore = - (struct external_solaris_bcp_core *) ext; - - intcore->c_magic = H_GET_32 (abfd, &extcore->c_magic); - intcore->c_len = H_GET_32 (abfd, &extcore->c_len); - intcore->c_regs_pos = offsetof (struct external_solaris_bcp_core, c_regs); - intcore->c_regs_size = sizeof (extcore->c_regs); - - /* The Solaris BCP exdata structure does not contain an a_syms field, - so we are unable to synthesize an internal exec header. - Luckily we are able to figure out the start address of the data section, - which is the only thing needed from the internal exec header, - from the exdata structure. - - As of Solaris 2.3, BCP core files for statically linked executables - are buggy. The exdata structure is not properly filled in, and - the data section is written from address zero instead of the data - start address. */ - memset ((void *) &intcore->c_aouthdr, 0, sizeof (struct internal_exec)); - intcore->c_data_addr = H_GET_32 (abfd, &extcore->c_exdata_datorg); - intcore->c_signo = H_GET_32 (abfd, &extcore->c_signo); - intcore->c_tsize = H_GET_32 (abfd, &extcore->c_tsize); - intcore->c_dsize = H_GET_32 (abfd, &extcore->c_dsize); - intcore->c_ssize = H_GET_32 (abfd, &extcore->c_ssize); - memcpy (intcore->c_cmdname, extcore->c_cmdname, sizeof (intcore->c_cmdname)); - intcore->fp_stuff_pos = - offsetof (struct external_solaris_bcp_core, fp_stuff); - /* FP stuff takes up whole rest of struct, except c_ucode. */ - intcore->fp_stuff_size = intcore->c_len - (sizeof extcore->c_ucode) - - offsetof (struct external_solaris_bcp_core, fp_stuff); - /* Ucode is the last thing in the struct -- just before the end */ - intcore->c_ucode = H_GET_32 (abfd, - (intcore->c_len - - sizeof (extcore->c_ucode) - + (unsigned char *) extcore)); - - /* Supposedly the user stack grows downward from the bottom of kernel memory. - Presuming that this remains true, this definition will work. */ - /* Now sun has provided us with another challenge. The value is different - for sparc2 and sparc10 (both running SunOS 4.1.3). We pick one or - the other based on the current value of the stack pointer. This - loses (a) if the stack pointer has been clobbered, or (b) if the stack - is larger than 128 megabytes. - - It's times like these you're glad they're switching to ELF. - - Note that using include files or nlist on /vmunix would be wrong, - because we want the value for this core file, no matter what kind of - machine we were compiled on or are running on. */ -#define SPARC_USRSTACK_SPARC2 ((bfd_vma)0xf8000000) -#define SPARC_USRSTACK_SPARC10 ((bfd_vma)0xf0000000) - { - bfd_vma sp = H_GET_32 (abfd, &extcore->c_regs.r_o6); - if (sp < SPARC_USRSTACK_SPARC10) - intcore->c_stacktop = SPARC_USRSTACK_SPARC10; - else - intcore->c_stacktop = SPARC_USRSTACK_SPARC2; - } -} - -/* Need this cast because ptr is really void *. */ -#define core_hdr(bfd) ((bfd)->tdata.sun_core_data) -#define core_datasec(bfd) (core_hdr (bfd)->data_section) -#define core_stacksec(bfd) (core_hdr (bfd)->stack_section) -#define core_regsec(bfd) (core_hdr (bfd)->reg_section) -#define core_reg2sec(bfd) (core_hdr (bfd)->reg2_section) - -/* These are stored in the bfd's tdata. */ -struct sun_core_struct -{ - struct internal_sunos_core *hdr; /* Core file header. */ - asection *data_section; - asection *stack_section; - asection *reg_section; - asection *reg2_section; -}; - -static const bfd_target * -sunos4_core_file_p (bfd *abfd) -{ - unsigned char longbuf[4]; /* Raw bytes of various header fields. */ - bfd_size_type core_size, amt; - unsigned long core_mag; - struct internal_sunos_core *core; - char *extcore; - struct mergem - { - struct sun_core_struct suncoredata; - struct internal_sunos_core internal_sunos_core; - char external_core[1]; - } *mergem; - flagword flags; - - if (bfd_bread ((void *) longbuf, (bfd_size_type) sizeof (longbuf), abfd) - != sizeof (longbuf)) - return NULL; - core_mag = H_GET_32 (abfd, longbuf); - - if (core_mag != CORE_MAGIC) - return NULL; - - /* SunOS core headers can vary in length; second word is size; */ - if (bfd_bread ((void *) longbuf, (bfd_size_type) sizeof (longbuf), abfd) - != sizeof (longbuf)) - return NULL; - core_size = H_GET_32 (abfd, longbuf); - /* Sanity check. */ - if (core_size > 20000) - return NULL; - - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) - return NULL; - - amt = core_size + sizeof (struct mergem); - mergem = bfd_zalloc (abfd, amt); - if (mergem == NULL) - return NULL; - - extcore = mergem->external_core; - - if ((bfd_bread ((void *) extcore, core_size, abfd)) != core_size) - { - loser: - bfd_release (abfd, (char *) mergem); - abfd->tdata.any = NULL; - bfd_section_list_clear (abfd); - return NULL; - } - - /* Validate that it's a core file we know how to handle, due to sun - botching the positioning of registers and other fields in a machine - dependent way. */ - core = &mergem->internal_sunos_core; - switch (core_size) - { - case SPARC_CORE_LEN: - swapcore_sparc (abfd, extcore, core); - break; - case SUN3_CORE_LEN: - swapcore_sun3 (abfd, extcore, core); - break; - case SOLARIS_BCP_CORE_LEN: - swapcore_solaris_bcp (abfd, extcore, core); - break; - default: - bfd_set_error (bfd_error_system_call); /* FIXME. */ - goto loser; - } - - abfd->tdata.sun_core_data = &mergem->suncoredata; - abfd->tdata.sun_core_data->hdr = core; - - /* Create the sections. */ - flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; - core_stacksec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".stack", - flags); - if (core_stacksec (abfd) == NULL) - /* bfd_release frees everything allocated after it's arg. */ - goto loser; - - flags = SEC_ALLOC + SEC_LOAD + SEC_HAS_CONTENTS; - core_datasec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".data", - flags); - if (core_datasec (abfd) == NULL) - goto loser; - - flags = SEC_HAS_CONTENTS; - core_regsec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg", - flags); - if (core_regsec (abfd) == NULL) - goto loser; - - flags = SEC_HAS_CONTENTS; - core_reg2sec (abfd) = bfd_make_section_anyway_with_flags (abfd, ".reg2", - flags); - if (core_reg2sec (abfd) == NULL) - goto loser; - - core_stacksec (abfd)->size = core->c_ssize; - core_datasec (abfd)->size = core->c_dsize; - core_regsec (abfd)->size = core->c_regs_size; - core_reg2sec (abfd)->size = core->fp_stuff_size; - - core_stacksec (abfd)->vma = (core->c_stacktop - core->c_ssize); - core_datasec (abfd)->vma = core->c_data_addr; - core_regsec (abfd)->vma = 0; - core_reg2sec (abfd)->vma = 0; - - core_stacksec (abfd)->filepos = core->c_len + core->c_dsize; - core_datasec (abfd)->filepos = core->c_len; - /* We'll access the regs afresh in the core file, like any section: */ - core_regsec (abfd)->filepos = (file_ptr) core->c_regs_pos; - core_reg2sec (abfd)->filepos = (file_ptr) core->fp_stuff_pos; - - /* Align to word at least. */ - core_stacksec (abfd)->alignment_power = 2; - core_datasec (abfd)->alignment_power = 2; - core_regsec (abfd)->alignment_power = 2; - core_reg2sec (abfd)->alignment_power = 2; - - return abfd->xvec; -} - -static char * -sunos4_core_file_failing_command (bfd *abfd) -{ - return core_hdr (abfd)->hdr->c_cmdname; -} - -static int -sunos4_core_file_failing_signal (bfd *abfd) -{ - return core_hdr (abfd)->hdr->c_signo; -} - -static bfd_boolean -sunos4_core_file_matches_executable_p (bfd *core_bfd, bfd *exec_bfd) -{ - if (core_bfd->xvec != exec_bfd->xvec) - { - bfd_set_error (bfd_error_system_call); - return FALSE; - } - - /* Solaris core files do not include an aouthdr. */ - if ((core_hdr (core_bfd)->hdr)->c_len == SOLARIS_BCP_CORE_LEN) - return TRUE; - - return memcmp ((char *) &((core_hdr (core_bfd)->hdr)->c_aouthdr), - (char *) exec_hdr (exec_bfd), - sizeof (struct internal_exec)) == 0; -} - -#define MY_set_sizes sunos4_set_sizes - -static bfd_boolean -sunos4_set_sizes (bfd *abfd) -{ - switch (bfd_get_arch (abfd)) - { - default: - return FALSE; - case bfd_arch_sparc: - adata (abfd).page_size = 0x2000; - adata (abfd).segment_size = 0x2000; - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - return TRUE; - case bfd_arch_m68k: - adata (abfd).page_size = 0x2000; - adata (abfd).segment_size = 0x20000; - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - return TRUE; - } -} - -/* We default to setting the toolversion field to 1, as is required by - SunOS. */ -#ifndef MY_exec_hdr_flags -#define MY_exec_hdr_flags 1 -#endif - -#ifndef MY_entry_is_text_address -#define MY_entry_is_text_address 0 -#endif -#ifndef MY_add_dynamic_symbols -#define MY_add_dynamic_symbols 0 -#endif -#ifndef MY_add_one_symbol -#define MY_add_one_symbol 0 -#endif -#ifndef MY_link_dynamic_object -#define MY_link_dynamic_object 0 -#endif -#ifndef MY_write_dynamic_symbol -#define MY_write_dynamic_symbol 0 -#endif -#ifndef MY_check_dynamic_reloc -#define MY_check_dynamic_reloc 0 -#endif -#ifndef MY_finish_dynamic_link -#define MY_finish_dynamic_link 0 -#endif - -static const struct aout_backend_data sunos4_aout_backend = -{ - 0, /* Zmagic files are not contiguous. */ - 1, /* Text includes header. */ - MY_entry_is_text_address, - MY_exec_hdr_flags, - 0, /* Default text vma. */ - sunos4_set_sizes, - 0, /* Header is counted in zmagic text. */ - MY_add_dynamic_symbols, - MY_add_one_symbol, - MY_link_dynamic_object, - MY_write_dynamic_symbol, - MY_check_dynamic_reloc, - MY_finish_dynamic_link -}; - -#define MY_core_file_failing_command sunos4_core_file_failing_command -#define MY_core_file_failing_signal sunos4_core_file_failing_signal -#define MY_core_file_matches_executable_p sunos4_core_file_matches_executable_p - -#define MY_bfd_debug_info_start bfd_void -#define MY_bfd_debug_info_end bfd_void -#define MY_bfd_debug_info_accumulate (void (*) (bfd *, struct bfd_section *)) bfd_void -#define MY_core_file_p sunos4_core_file_p -#define MY_write_object_contents NAME(aout, sunos4_write_object_contents) -#define MY_backend_data & sunos4_aout_backend - -#ifndef TARGET_IS_LITTLE_ENDIAN_P -#define TARGET_IS_BIG_ENDIAN_P -#endif - -#include "aout-target.h" diff --git a/sdcc/support/sdbinutils/bfd/arc-got.h b/sdcc/support/sdbinutils/bfd/arc-got.h deleted file mode 100644 index a86061bcb..000000000 --- a/sdcc/support/sdbinutils/bfd/arc-got.h +++ /dev/null @@ -1,528 +0,0 @@ -/* ARC-specific support for 32-bit ELF - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed by Cupertino Miranda (cmiranda@synopsys.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef ARC_GOT_H -#define ARC_GOT_H - -#define TCB_SIZE (8) - -enum tls_type_e -{ - GOT_UNKNOWN = 0, - GOT_NORMAL, - GOT_TLS_GD, - GOT_TLS_IE, - GOT_TLS_LE -}; - -enum tls_got_entries -{ - TLS_GOT_NONE = 0, - TLS_GOT_MOD, - TLS_GOT_OFF, - TLS_GOT_MOD_AND_OFF -}; - -struct got_entry -{ - struct got_entry *next; - enum tls_type_e type; - bfd_vma offset; - bfd_boolean processed; - bfd_boolean created_dyn_relocation; - enum tls_got_entries existing_entries; -}; - -static struct got_entry ** -arc_get_local_got_ents (bfd * abfd) -{ - static struct got_entry **local_got_ents = NULL; - - if (local_got_ents == NULL) - { - size_t size; - Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr); - - size = symtab_hdr->sh_info * sizeof (bfd_vma); - local_got_ents = (struct got_entry **) - bfd_alloc (abfd, sizeof (struct got_entry *) * size); - if (local_got_ents == NULL) - return FALSE; - - memset (local_got_ents, 0, sizeof (struct got_entry *) * size); - elf_local_got_ents (abfd) = local_got_ents; - } - - return local_got_ents; -} - -static struct got_entry * -got_entry_for_type (struct got_entry **list, - enum tls_type_e type) -{ - struct got_entry **p = list; - - while (*p != NULL) - { - if ((*p)->type == type) - return *p; - p = &((*p)->next); - } - return NULL; -} - -static void -new_got_entry_to_list (struct got_entry **list, - enum tls_type_e type, - bfd_vma offset, - enum tls_got_entries existing_entries) -{ - /* Find list end. Avoid having multiple entries of the same - type. */ - struct got_entry **p = list; - struct got_entry *entry; - - while (*p != NULL) - { - if ((*p)->type == type) - return; - p = &((*p)->next); - } - - entry = (struct got_entry *) xmalloc (sizeof (struct got_entry)); - - entry->type = type; - entry->offset = offset; - entry->next = NULL; - entry->processed = FALSE; - entry->created_dyn_relocation = FALSE; - entry->existing_entries = existing_entries; - - ARC_DEBUG ("New GOT got entry added to list: " - "type: %d, offset: %ld, existing_entries: %d\n", - type, (long) offset, existing_entries); - - /* Add the entry to the end of the list. */ - *p = entry; -} - -static enum tls_type_e -tls_type_for_reloc (reloc_howto_type *howto) -{ - enum tls_type_e ret = GOT_UNKNOWN; - - if (is_reloc_for_GOT (howto)) - return GOT_NORMAL; - - switch (howto->type) - { - case R_ARC_TLS_GD_GOT: - ret = GOT_TLS_GD; - break; - case R_ARC_TLS_IE_GOT: - ret = GOT_TLS_IE; - break; - case R_ARC_TLS_LE_32: - ret = GOT_TLS_LE; - break; - default: - ret = GOT_UNKNOWN; - break; - } - - return ret; -}; - -static struct got_entry ** -get_got_entry_list_for_symbol (bfd *abfd, - unsigned long r_symndx, - struct elf_link_hash_entry *h) -{ - if (h != NULL) - { - return &h->got.glist; - } - else - { - struct got_entry **local_got_ents - = arc_get_local_got_ents (abfd); - return &local_got_ents[r_symndx]; - } -} - - -static enum tls_type_e -arc_got_entry_type_for_reloc (reloc_howto_type *howto) -{ - enum tls_type_e type = GOT_UNKNOWN; - - if (is_reloc_for_GOT (howto)) - return GOT_NORMAL; - - if (is_reloc_for_TLS (howto)) - { - switch (howto->type) - { - case R_ARC_TLS_GD_GOT: - type = GOT_TLS_GD; - break; - case R_ARC_TLS_IE_GOT: - type = GOT_TLS_IE; - break; - default: - break; - } - } - return type; -} - -#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \ - htab->s##SECNAME->size; \ - { \ - if (COND_FOR_RELOC) \ - { \ - htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \ - ARC_DEBUG ("arc_info: Added reloc space in " \ - #SECNAME " section at " __FILE__ \ - ":%d for symbol %s\n", \ - __LINE__, name_for_global_symbol (H)); \ - } \ - if (H) \ - if (h->dynindx == -1 && !h->forced_local) \ - if (! bfd_elf_link_record_dynamic_symbol (info, H)) \ - return FALSE; \ - htab->s##SECNAME->size += 4; \ - } \ - -static bfd_boolean -arc_fill_got_info_for_reloc (enum tls_type_e type, - struct got_entry **list, - struct bfd_link_info * info, - struct elf_link_hash_entry *h) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (got_entry_for_type (list, type) != NULL) - return TRUE; - - switch (type) - { - case GOT_NORMAL: - { - bfd_vma offset - = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info) - || h != NULL, h); - new_got_entry_to_list (list, type, offset, TLS_GOT_NONE); - } - break; - - - case GOT_TLS_GD: - { - bfd_vma offset - = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); - bfd_vma ATTRIBUTE_UNUSED notneeded - = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); - new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF); - } - break; - case GOT_TLS_IE: - case GOT_TLS_LE: - { - bfd_vma offset - = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h); - new_got_entry_to_list (list, type, offset, TLS_GOT_OFF); - } - break; - - default: - return FALSE; - break; - } - return TRUE; -} - - -static bfd_vma -relocate_fix_got_relocs_for_got_info (struct got_entry ** list_p, - enum tls_type_e type, - struct bfd_link_info * info, - bfd * output_bfd, - unsigned long r_symndx, - Elf_Internal_Sym * local_syms, - asection ** local_sections, - struct elf_link_hash_entry * h, - struct arc_relocation_data * reloc_data) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - struct got_entry *entry = NULL; - - if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE) - return 0; - - entry = got_entry_for_type (list_p, type); - BFD_ASSERT (entry); - - if (h == NULL - || (! elf_hash_table (info)->dynamic_sections_created - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)))) - { - const char ATTRIBUTE_UNUSED *symbol_name; - static const char local_name[] = "(local)"; - asection *tls_sec = NULL; - bfd_vma sym_value = 0; - - if (h != NULL) - { - // TODO: This should not be here. - reloc_data->sym_value = h->root.u.def.value; - reloc_data->sym_section = h->root.u.def.section; - - sym_value = h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset; - - tls_sec = elf_hash_table (info)->tls_sec; - - symbol_name = h->root.root.string; - } - else - { - Elf_Internal_Sym *sym = local_syms + r_symndx; - asection *sec = local_sections[r_symndx]; - - sym_value = sym->st_value - + sec->output_section->vma - + sec->output_offset; - - tls_sec = elf_hash_table (info)->tls_sec; - - symbol_name = local_name; - } - - - if (entry && !entry->processed) - { - switch (entry->type) - { - case GOT_TLS_GD: - { - BFD_ASSERT (tls_sec && tls_sec->output_section); - bfd_vma sec_vma = tls_sec->output_section->vma; - - bfd_put_32 (output_bfd, - sym_value - sec_vma, - htab->sgot->contents + entry->offset - + (entry->existing_entries == TLS_GOT_MOD_AND_OFF - ? 4 : 0)); - - ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx " - "@ %lx, for symbol %s\n", - (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" : - "GOT_TLS_IE"), - (long) (sym_value - sec_vma), - (long) (htab->sgot->output_section->vma - + htab->sgot->output_offset->vma - + entry->offset - + (entry->existing_entries == TLS_GOT_MOD_AND_OFF - ? 4 : 0)), - symbol_name); - } - break; - - case GOT_TLS_IE: - { - BFD_ASSERT (tls_sec && tls_sec->output_section); - bfd_vma ATTRIBUTE_UNUSED sec_vma - = tls_sec->output_section->vma; - - bfd_put_32 (output_bfd, - sym_value - sec_vma - + (elf_hash_table (info)->dynamic_sections_created ? 0 : TCB_SIZE), - htab->sgot->contents + entry->offset - + (entry->existing_entries == TLS_GOT_MOD_AND_OFF - ? 4 : 0)); - - ARC_DEBUG ("arc_info: FIXED -> %s value = %#lx " - "@ %p, for symbol %s\n", - (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" : - "GOT_TLS_IE"), - (long) (sym_value - sec_vma), - (long) (htab->sgot->output_section->vma - + htab->sgot->output_offset->vma - + entry->offset - + (entry->existing_entries == TLS_GOT_MOD_AND_OFF - ? 4 : 0)), - symbol_name); - } - break; - - case GOT_NORMAL: - { - bfd_vma sec_vma - = reloc_data->sym_section->output_section->vma - + reloc_data->sym_section->output_offset; - - if (h != NULL - && h->root.type == bfd_link_hash_undefweak) - ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED " - "@ %#08lx for sym %s in got offset %#lx " - "(is undefweak)\n", - (long) (htab->sgot->output_section->vma - + htab->sgot->output_offset - + entry->offset), - symbol_name, - (long) entry->offset); - else - { - bfd_put_32 (output_bfd, - reloc_data->sym_value + sec_vma, - htab->sgot->contents + entry->offset); - ARC_DEBUG ("arc_info: PATCHED: %#08lx " - "@ %#08lx for sym %s in got offset %#lx\n", - (long) (reloc_data->sym_value + sec_vma), - (long) (htab->sgot->output_section->vma - + htab->sgot->output_offset + entry->offset), - symbol_name, - (long) entry->offset); - } - } - break; - default: - BFD_ASSERT (0); - break; - } - entry->processed = TRUE; - } - } - - return entry->offset; -} - -static void -create_got_dynrelocs_for_single_entry (struct got_entry *list, - bfd *output_bfd, - struct bfd_link_info * info, - struct elf_link_hash_entry *h) -{ - if (list == NULL) - return; - - bfd_vma got_offset = list->offset; - - if (list->type == GOT_NORMAL - && !list->created_dyn_relocation) - { - if (bfd_link_pic (info) - && h != NULL - && (info->symbolic || h->dynindx == -1) - && h->def_regular) - { - ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0); - } - /* Do not fully understand the side effects of this condition. - The relocation space might still being reserved. Perhaps - I should clear its value. */ - else if (h != NULL && h->dynindx != -1) - { - ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0); - } - list->created_dyn_relocation = TRUE; - } - else if (list->existing_entries != TLS_GOT_NONE - && !list->created_dyn_relocation) - { - /* TODO TLS: This is not called for local symbols. - In order to correctly implement TLS, this should also - be called for all local symbols with tls got entries. - Should be moved to relocate_section in order to make it - work for local symbols. */ - struct elf_link_hash_table *htab = elf_hash_table (info); - enum tls_got_entries e = list->existing_entries; - - BFD_ASSERT (list->type != GOT_TLS_GD - || list->existing_entries == TLS_GOT_MOD_AND_OFF); - - bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx; - - if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD) - { - ADD_RELA (output_bfd, got, got_offset, dynindx, - R_ARC_TLS_DTPMOD, 0); - ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \ -GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = 0x0\n", - list->type, - (long) got_offset, - (long) (htab->sgot->output_section->vma - + htab->sgot->output_offset + got_offset), - (long) dynindx); - } - - if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF) - { - bfd_vma addend = 0; - if (list->type == GOT_TLS_IE) - { - addend = bfd_get_32 (output_bfd, - htab->sgot->contents + got_offset); - } - - ADD_RELA (output_bfd, got, - got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0), - dynindx, - (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF - : R_ARC_TLS_DTPOFF), - addend); - - ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \ -GOT_OFFSET = %#lx, GOT_VMA = %#lx, INDEX = %ld, ADDEND = %#lx\n", - list->type, - (long) got_offset, - (long) (htab->sgot->output_section->vma - + htab->sgot->output_offset + got_offset), - (long) dynindx, (long) addend); - } - list->created_dyn_relocation = TRUE; - } -} - -static void -create_got_dynrelocs_for_got_info (struct got_entry **list_p, - bfd *output_bfd, - struct bfd_link_info * info, - struct elf_link_hash_entry *h) -{ - if (list_p == NULL) - return; - - struct got_entry *list = *list_p; - /* Traverse the list of got entries for this symbol. */ - while (list) - { - create_got_dynrelocs_for_single_entry (list, output_bfd, info, h); - list = list->next; - } -} - -#undef ADD_SYMBOL_REF_SEC_AND_RELOC - -#endif /* ARC_GOT_H */ diff --git a/sdcc/support/sdbinutils/bfd/arc-plt.h b/sdcc/support/sdbinutils/bfd/arc-plt.h deleted file mode 100644 index 2f4ba8604..000000000 --- a/sdcc/support/sdbinutils/bfd/arc-plt.h +++ /dev/null @@ -1,196 +0,0 @@ -/* ARC-specific header file for PLT support. - Copyright (C) 2016-2018 Free Software Foundation, Inc. - Contributed by Cupertino Miranda (cmiranda@synopsys.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef ARC_PLT_H -#define ARC_PLT_H - -#include - -/* Instructions appear in memory as a sequence of half-words (16 bit); - individual half-words are represented on the target in target byte order. - We use 'unsigned short' on the host to represent the PLT templates, - and translate to target byte order as we copy to the target. */ -typedef uint16_t insn_hword; - -enum plt_reloc_symbol -{ - LAST_RELOC = 0, - - SGOT = 1, - - RELATIVE = (1 << 8), - RELATIVE_INSN_32 = (1 << 9), - RELATIVE_INSN_24 = (1 << 10), - - MIDDLE_ENDIAN = (1 << 11) -}; - -#define IS_RELATIVE(S) ((S & (RELATIVE | RELATIVE_INSN_24 | RELATIVE_INSN_32)) != 0) -#define IS_INSN_32(S) ((S & RELATIVE_INSN_32) != 0) -#define IS_INSN_24(S) ((S & RELATIVE_INSN_24) != 0) -#define IS_MIDDLE_ENDIAN(S) ((S & MIDDLE_ENDIAN) != 0) -#define SYM_ONLY(S) (S & 0xFF) - -struct plt_reloc -{ - bfd_vma offset; - bfd_vma size; - bfd_vma mask; - enum plt_reloc_symbol symbol; - bfd_vma addend; -}; - - -#define PLT_TYPE_START(NAME) NAME, -#define PLT_TYPE_END(NAME) -#define PLT_ENTRY(...) -#define PLT_ELEM(...) -#define ENTRY_RELOC(...) -#define ELEM_RELOC(...) - -enum plt_types_enum -{ - PLT_START = -1, -#include "arc-plt.def" - PLT_MAX -}; - -#undef PLT_TYPE_START -#undef PLT_TYPE_END -#undef PLT_ENTRY -#undef PLT_ELEM -#undef ENTRY_RELOC -#undef ELEM_RELOC - -typedef insn_hword insn_hword_array[]; - -struct plt_version_t -{ - const insn_hword_array *entry; - const bfd_vma entry_size; - const insn_hword_array *elem; - const bfd_vma elem_size; - - const struct plt_reloc *entry_relocs; - const struct plt_reloc *elem_relocs; -}; - -#define PLT_TYPE_START(NAME) \ - const insn_hword NAME##_plt_entry[] = { -#define PLT_TYPE_END(NAME) }; -#define PLT_ENTRY(...) __VA_ARGS__, -#define PLT_ELEM(...) -#define ENTRY_RELOC(...) -#define ELEM_RELOC(...) - -#include "arc-plt.def" - -#undef PLT_TYPE_START -#undef PLT_TYPE_END -#undef PLT_ENTRY -#undef PLT_ELEM -#undef ENTRY_RELOC -#undef ELEM_RELOC - -#define PLT_TYPE_START(NAME) \ - const struct plt_reloc NAME##_plt_entry_relocs[] = { -#define PLT_TYPE_END(NAME) \ - {0, 0, 0, LAST_RELOC, 0} \ - }; -#define PLT_ENTRY(...) -#define PLT_ELEM(...) -#define ENTRY_RELOC(...) { __VA_ARGS__ }, -#define ELEM_RELOC(...) - -#include "arc-plt.def" - -#undef PLT_TYPE_START -#undef PLT_TYPE_END -#undef PLT_ENTRY -#undef PLT_ELEM -#undef ENTRY_RELOC -#undef ELEM_RELOC - - -#define PLT_TYPE_START(NAME) \ - const insn_hword NAME##_plt_elem[] = { -#define PLT_TYPE_END(NAME) }; -#define PLT_ENTRY(...) -#define PLT_ELEM(...) __VA_ARGS__, -#define ENTRY_RELOC(...) -#define ELEM_RELOC(...) - -#include "arc-plt.def" - -#undef PLT_TYPE_START -#undef PLT_TYPE_END -#undef PLT_ENTRY -#undef PLT_ELEM -#undef ENTRY_RELOC -#undef ELEM_RELOC - -#define PLT_TYPE_START(NAME) \ - const struct plt_reloc NAME##_plt_elem_relocs[] = { -#define PLT_TYPE_END(NAME) \ - {0, 0, 0, LAST_RELOC, 0} \ - }; -#define PLT_ENTRY(...) -#define PLT_ELEM(...) -#define ENTRY_RELOC(...) -#define ELEM_RELOC(...) { __VA_ARGS__ }, - -#include "arc-plt.def" - -#undef PLT_TYPE_START -#undef PLT_TYPE_END -#undef PLT_ENTRY -#undef PLT_ELEM -#undef ENTRY_RELOC -#undef ELEM_RELOC - - -#define PLT_TYPE_START(NAME) \ - { \ - .entry = &NAME##_plt_entry, \ - .entry_size = sizeof (NAME##_plt_entry), \ - .elem = &NAME##_plt_elem, \ - .elem_size = sizeof (NAME##_plt_elem), \ - .entry_relocs = NAME##_plt_entry_relocs, \ - .elem_relocs = NAME##_plt_elem_relocs -#define PLT_TYPE_END(NAME) }, -#define PLT_ENTRY(...) -#define PLT_ELEM(...) -#define ENTRY_RELOC(...) -#define ELEM_RELOC(...) -struct plt_version_t plt_versions[PLT_MAX] = { - -#include "arc-plt.def" - -}; -#undef PLT_TYPE_START -#undef PLT_TYPE_END -#undef PLT_ENTRY -#undef PLT_ELEM -#undef ENTRY_RELOC -#undef ELEM_RELOC - - -#endif /* ARC_PLT_H */ diff --git a/sdcc/support/sdbinutils/bfd/archive64.c b/sdcc/support/sdbinutils/bfd/archive64.c deleted file mode 100644 index 4cccd5420..000000000 --- a/sdcc/support/sdbinutils/bfd/archive64.c +++ /dev/null @@ -1,246 +0,0 @@ -/* Support for 64-bit archives. - Copyright (C) 1996-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 archives. We use the same format as - the 64-bit (MIPS) ELF archives. */ - -#include "sysdep.h" -#include "bfd.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. */ - -/* Read an Irix 6 armap. */ - -bfd_boolean -_bfd_archive_64_bit_slurp_armap (bfd *abfd) -{ - struct artdata *ardata = bfd_ardata (abfd); - char nextname[17]; - bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize; - struct areltdata *mapdata; - bfd_byte int_buf[8]; - char *stringbase; - char *stringend; - bfd_byte *raw_armap = NULL; - carsym *carsyms; - bfd_size_type amt; - - ardata->symdefs = NULL; - - /* Get the name of the first element. */ - 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 (CONST_STRNEQ (nextname, "/ ")) - return bfd_slurp_armap (abfd); - - if (! CONST_STRNEQ (nextname, "/SYM64/ ")) - { - 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; - free (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; - if (carsym_size < nsymz || ptrsize < nsymz || amt < nsymz) - { - bfd_set_error (bfd_error_malformed_archive); - return FALSE; - } - ardata->symdefs = (struct carsym *) bfd_zalloc (abfd, amt); - if (ardata->symdefs == NULL) - return FALSE; - carsyms = ardata->symdefs; - stringbase = ((char *) ardata->symdefs) + carsym_size; - stringbase[stringsize] = 0; - stringend = stringbase + stringsize; - - raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize); - if (raw_armap == NULL) - 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; - if (stringbase < stringend) - 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_archive_64_bit_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/")); - if (!_bfd_ar_sizepad (hdr.ar_size, sizeof (hdr.ar_size), mapsize)) - return FALSE; - _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. */ - count = 0; - for (current = arch->archive_head; - current != NULL && count < symbol_count; - current = current->archive_next) - { - /* For each symbol which is used defined in this object, write out - the object file's address in the archive. */ - - for (; - count < symbol_count && map[count].u.abfd == current; - count++) - { - bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf); - if (bfd_bwrite (buf, 8, arch) != 8) - return FALSE; - } - - /* Add size of this archive entry */ - archive_member_file_ptr += sizeof (struct ar_hdr); - if (! bfd_is_thin_archive (arch)) - archive_member_file_ptr += arelt_size (current); - /* remember about the even alignment */ - archive_member_file_ptr += archive_member_file_ptr % 2; - } - - /* 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/sdcc/support/sdbinutils/bfd/armnetbsd.c b/sdcc/support/sdbinutils/bfd/armnetbsd.c deleted file mode 100644 index f5560e7ee..000000000 --- a/sdcc/support/sdbinutils/bfd/armnetbsd.c +++ /dev/null @@ -1,39 +0,0 @@ -/* BFD back-end for NetBSD/ARM a.out-ish binaries. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define BYTES_IN_WORD 4 -#undef TARGET_IS_BIG_ENDIAN_P - -#define TARGET_PAGE_SIZE 4096 -#define SEGMENT_SIZE TARGET_PAGE_SIZE - -#define DEFAULT_ARCH bfd_arch_arm -#define DEFAULT_MID M_ARM6_NETBSD -/*#define MACHTYPE_OK(mtype) ((mtype) == M_ARM6_NETBSD)*/ - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (arm_aout_nbsd_, OP) - -/* This needs to start with a.out so GDB knows it is an a.out variant. */ -#define TARGETNAME "a.out-arm-netbsd" - -#include "netbsd.h" diff --git a/sdcc/support/sdbinutils/bfd/bfd-in.h b/sdcc/support/sdbinutils/bfd/bfd-in.h deleted file mode 100644 index 2195ce3db..000000000 --- a/sdcc/support/sdbinutils/bfd/bfd-in.h +++ /dev/null @@ -1,1051 +0,0 @@ -/* Main header file for the bfd library -- portable access to object files. - - Copyright (C) 1990-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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__ - -/* PR 14072: Ensure that config.h is included first. */ -#if !defined PACKAGE && !defined PACKAGE_VERSION -#error config.h must be included before this header -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ansidecl.h" -#include "symcat.h" -#include -#include - -#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 - -/* This is a utility macro to handle the situation where the code - wants to place a constant string into the code, followed by a - comma and then the length of the string. Doing this by hand - is error prone, so using this macro is safer. */ -#define STRING_COMMA_LEN(STR) (STR), (sizeof (STR) - 1) -/* Unfortunately it is not possible to use the STRING_COMMA_LEN macro - to create the arguments to another macro, since the preprocessor - will mis-count the number of arguments to the outer macro (by not - evaluating STRING_COMMA_LEN and so missing the comma). This is a - problem for example when trying to use STRING_COMMA_LEN to build - the arguments to the strncmp() macro. Hence this alternative - definition of strncmp is provided here. - - Note - these macros do NOT work if STR2 is not a constant string. */ -#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0) - /* strcpy() can have a similar problem, but since we know we are - copying a constant string, we can use memcpy which will be faster - since there is no need to check for a NUL byte inside STR. We - can also save time if we do not need to copy the terminating NUL. */ -#define LITMEMCPY(DEST,STR2) memcpy ((DEST), (STR2), sizeof (STR2) - 1) -#define LITSTRCPY(DEST,STR2) memcpy ((DEST), (STR2), sizeof (STR2)) - - -#define BFD_SUPPORTS_PLUGINS @supports_plugins@ - -/* 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_64BIT_LONG_LONG @BFD_HOST_64BIT_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 - -/* Declaring a type wide enough to hold a host long and a host pointer. */ -#define BFD_HOSTPTR_T @BFD_HOSTPTR_T@ -typedef BFD_HOSTPTR_T bfd_hostptr_t; - -/* 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; - -#if BFD_HOST_64BIT_LONG -#define BFD_VMA_FMT "l" -#elif defined (__MSVCRT__) -#define BFD_VMA_FMT "I64" -#else -#define BFD_VMA_FMT "ll" -#endif - -#ifndef fprintf_vma -#define sprintf_vma(s,x) sprintf (s, "%016" BFD_VMA_FMT "x", x) -#define fprintf_vma(f,x) fprintf (f, "%016" BFD_VMA_FMT "x", x) -#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 BFD_VMA_FMT "l" -#define fprintf_vma(s,x) fprintf (s, "%08" BFD_VMA_FMT "x", x) -#define sprintf_vma(s,x) sprintf (s, "%08" BFD_VMA_FMT "x", 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; - -/* 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) \ - (((x)->flags & BSF_SYNTHETIC) != 0 \ - ? bfd_target_unknown_flavour \ - : 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. */ -typedef struct bfd_section *sec_ptr; - -#define align_power(addr, align) \ - (((addr) + ((bfd_vma) 1 << (align)) - 1) & (-((bfd_vma) 1 << (align)))) - -/* 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) - -#define bfd_get_section_name(bfd, ptr) ((void) bfd, (ptr)->name) -#define bfd_get_section_vma(bfd, ptr) ((void) bfd, (ptr)->vma) -#define bfd_get_section_lma(bfd, ptr) ((void) bfd, (ptr)->lma) -#define bfd_get_section_alignment(bfd, ptr) ((void) bfd, \ - (ptr)->alignment_power) -#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) ((void) bfd, (ptr)->flags) -#define bfd_get_section_userdata(bfd, ptr) ((void) bfd, (ptr)->userdata) - -#define bfd_is_com_section(ptr) (((ptr)->flags & SEC_IS_COMMON) != 0) - -#define bfd_get_section_limit_octets(bfd, sec) \ - ((bfd)->direction != write_direction && (sec)->rawsize != 0 \ - ? (sec)->rawsize : (sec)->size) - -/* Find the address one past the end of SEC. */ -#define bfd_get_section_limit(bfd, sec) \ - (bfd_get_section_limit_octets(bfd, sec) / bfd_octets_per_byte (bfd)) - -/* Return TRUE if input section SEC has been discarded. */ -#define discarded_section(sec) \ - (!bfd_is_abs_section (sec) \ - && bfd_is_abs_section ((sec)->output_section) \ - && (sec)->sec_info_type != SEC_INFO_TYPE_MERGE \ - && (sec)->sec_info_type != SEC_INFO_TYPE_JUST_SYMS) - -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; - /* 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; - /* The number of slots in the hash table. */ - unsigned int size; - /* The number of entries in the hash table. */ - unsigned int count; - /* The size of elements. */ - unsigned int entsize; - /* If non-zero, don't grow the hash table. */ - unsigned int frozen:1; -}; - -/* 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); - -/* Insert an entry in a hash table. */ -extern struct bfd_hash_entry *bfd_hash_insert - (struct bfd_hash_table *, const char *, unsigned long); - -/* Rename an entry in a hash table. */ -extern void bfd_hash_rename - (struct bfd_hash_table *, const char *, struct bfd_hash_entry *); - -/* 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 unsigned long bfd_hash_set_default_size (unsigned long); - -/* Types of compressed DWARF debug sections. We currently support - zlib. */ -enum compressed_debug_section_type -{ - COMPRESS_DEBUG_NONE = 0, - COMPRESS_DEBUG = 1 << 0, - COMPRESS_DEBUG_GNU_ZLIB = COMPRESS_DEBUG | 1 << 1, - COMPRESS_DEBUG_GABI_ZLIB = COMPRESS_DEBUG | 1 << 2 -}; - -/* This structure is used to keep track of stabs in sections - information while linking. */ - -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) \ - (_bfd_warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ - bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) -#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ - (_bfd_warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ - bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) -#else -#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ - (_bfd_warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ - bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) -#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ - (_bfd_warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ - bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) -#endif -extern void _bfd_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_has_map(abfd) ((abfd)->has_armap) -#define bfd_is_thin_archive(abfd) ((abfd)->is_thin_archive) - -#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) - -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); - -#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_section_already_linked; -struct bfd_elf_version_tree; -#endif - -extern bfd_boolean bfd_section_already_linked_table_init (void); -extern void bfd_section_already_linked_table_free (void); -extern bfd_boolean _bfd_handle_already_linked - (struct bfd_section *, struct bfd_section_already_linked *, - struct bfd_link_info *); - -/* Externally visible ECOFF routines. */ - -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 -}; - -enum notice_asneeded_action { - notice_as_needed, - notice_not_needed, - notice_needed -}; - -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_stack_segment_size (bfd *, struct bfd_link_info *, - const char *, bfd_vma); -extern bfd_boolean bfd_elf_size_dynamic_sections - (bfd *, const char *, const char *, const char *, const char *, const char *, - const char * const *, struct bfd_link_info *, struct bfd_section **); -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 *, enum dynamic_lib_link_class); -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 int 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 non-zero, SIZE is the known extent of the - object. If not null, *LOADBASEP is filled in with the difference - between the VMAs from which the segments were read, and the VMAs - the file headers (and hence BFD's idea of each section's VMA) put - them at. - - The function TARGET_READ_MEMORY is called to copy LEN bytes from - the remote memory at target address VMA into the local buffer at - MYADDR; it should return zero on success or an `errno' code on - failure. TEMPL must be a BFD for a target with the word size and - byte order found in the remote memory. */ -extern bfd *bfd_elf_bfd_from_remote_memory - (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep, - int (*target_read_memory) (bfd_vma vma, bfd_byte *myaddr, - bfd_size_type len)); - -extern struct bfd_section *_bfd_elf_tls_setup - (bfd *, struct bfd_link_info *); - -extern struct bfd_section * -_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma); - -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 void bfd_elf_m68k_set_target_options (struct bfd_link_info *, int); - -extern bfd_boolean bfd_bfin_elf32_create_embedded_relocs - (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, - char **); - -extern bfd_boolean bfd_cr16_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_split_import_path - (bfd *, const char *, const char **, const char **); -extern bfd_boolean bfd_xcoff_set_archive_import_path - (struct bfd_link_info *, bfd *, const char *); -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, unsigned int, 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_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 VFP11 erratum workaround support. */ -typedef enum -{ - BFD_ARM_VFP11_FIX_DEFAULT, - BFD_ARM_VFP11_FIX_NONE, - BFD_ARM_VFP11_FIX_SCALAR, - BFD_ARM_VFP11_FIX_VECTOR -} bfd_arm_vfp11_fix; - -extern void bfd_elf32_arm_init_maps - (bfd *); - -extern void bfd_elf32_arm_set_vfp11_fix - (bfd *, struct bfd_link_info *); - -extern void bfd_elf32_arm_set_cortex_a8_fix - (bfd *, struct bfd_link_info *); - -extern bfd_boolean bfd_elf32_arm_vfp11_erratum_scan - (bfd *, struct bfd_link_info *); - -extern void bfd_elf32_arm_vfp11_fix_veneer_locations - (bfd *, struct bfd_link_info *); - -/* ARM STM STM32L4XX erratum workaround support. */ -typedef enum -{ - BFD_ARM_STM32L4XX_FIX_NONE, - BFD_ARM_STM32L4XX_FIX_DEFAULT, - BFD_ARM_STM32L4XX_FIX_ALL -} bfd_arm_stm32l4xx_fix; - -extern void bfd_elf32_arm_set_stm32l4xx_fix - (bfd *, struct bfd_link_info *); - -extern bfd_boolean bfd_elf32_arm_stm32l4xx_erratum_scan - (bfd *, struct bfd_link_info *); - -extern void bfd_elf32_arm_stm32l4xx_fix_veneer_locations - (bfd *, struct bfd_link_info *); - -/* 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 *); - -struct elf32_arm_params { - char *thumb_entry_symbol; - int byteswap_code; - int target1_is_rel; - char * target2_type; - int fix_v4bx; - int use_blx; - bfd_arm_vfp11_fix vfp11_denorm_fix; - bfd_arm_stm32l4xx_fix stm32l4xx_fix; - int no_enum_size_warning; - int no_wchar_size_warning; - int pic_veneer; - int fix_cortex_a8; - int fix_arm1176; - int merge_exidx_entries; - int cmse_implib; - bfd *in_implib_bfd; -}; - -void bfd_elf32_arm_set_target_params - (bfd *, struct bfd_link_info *, struct elf32_arm_params *); - -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 *); - -extern void bfd_elf32_arm_keep_private_stub_output_sections - (struct bfd_link_info *); - -/* ELF ARM mapping symbol support. */ -#define BFD_ARM_SPECIAL_SYM_TYPE_MAP (1 << 0) -#define BFD_ARM_SPECIAL_SYM_TYPE_TAG (1 << 1) -#define BFD_ARM_SPECIAL_SYM_TYPE_OTHER (1 << 2) -#define BFD_ARM_SPECIAL_SYM_TYPE_ANY (~0) - -extern bfd_boolean bfd_is_arm_special_symbol_name - (const char *, int); - -extern void bfd_elf32_arm_set_byteswap_code - (struct bfd_link_info *, int); - -extern void bfd_elf32_arm_use_long_plt (void); - -/* ARM Note section processing. */ -extern bfd_boolean bfd_arm_merge_machines - (bfd *, bfd *); - -extern bfd_boolean bfd_arm_update_notes - (bfd *, const char *); - -extern unsigned int bfd_arm_get_mach_from_notes - (bfd *, const char *); - -/* ARM stub generation support. Called from the linker. */ -extern int elf32_arm_setup_section_lists - (bfd *, struct bfd_link_info *); -extern void elf32_arm_next_input_section - (struct bfd_link_info *, struct bfd_section *); -extern bfd_boolean elf32_arm_size_stubs - (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, - struct bfd_section * (*) (const char *, struct bfd_section *, - struct bfd_section *, unsigned int), - void (*) (void)); -extern bfd_boolean elf32_arm_build_stubs - (struct bfd_link_info *); - -/* ARM unwind section editing support. */ -extern bfd_boolean elf32_arm_fix_exidx_coverage -(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean); - -/* C6x unwind section editing support. */ -extern bfd_boolean elf32_tic6x_fix_exidx_coverage -(struct bfd_section **, unsigned int, struct bfd_link_info *, bfd_boolean); - -extern void bfd_elf64_aarch64_init_maps - (bfd *); - -extern void bfd_elf32_aarch64_init_maps - (bfd *); - -extern void bfd_elf64_aarch64_set_options - (bfd *, struct bfd_link_info *, int, int, int, int, int, int); - -extern void bfd_elf32_aarch64_set_options - (bfd *, struct bfd_link_info *, int, int, int, int, int, int); - -/* ELF AArch64 mapping symbol support. */ -#define BFD_AARCH64_SPECIAL_SYM_TYPE_MAP (1 << 0) -#define BFD_AARCH64_SPECIAL_SYM_TYPE_TAG (1 << 1) -#define BFD_AARCH64_SPECIAL_SYM_TYPE_OTHER (1 << 2) -#define BFD_AARCH64_SPECIAL_SYM_TYPE_ANY (~0) -extern bfd_boolean bfd_is_aarch64_special_symbol_name - (const char * name, int type); - -/* AArch64 stub generation support for ELF64. Called from the linker. */ -extern int elf64_aarch64_setup_section_lists - (bfd *, struct bfd_link_info *); -extern void elf64_aarch64_next_input_section - (struct bfd_link_info *, struct bfd_section *); -extern bfd_boolean elf64_aarch64_size_stubs - (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, - struct bfd_section * (*) (const char *, struct bfd_section *), - void (*) (void)); -extern bfd_boolean elf64_aarch64_build_stubs - (struct bfd_link_info *); -/* AArch64 stub generation support for ELF32. Called from the linker. */ -extern int elf32_aarch64_setup_section_lists - (bfd *, struct bfd_link_info *); -extern void elf32_aarch64_next_input_section - (struct bfd_link_info *, struct bfd_section *); -extern bfd_boolean elf32_aarch64_size_stubs - (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, - struct bfd_section * (*) (const char *, struct bfd_section *), - void (*) (void)); -extern bfd_boolean elf32_aarch64_build_stubs - (struct bfd_link_info *); - - -/* TI COFF load page support. */ -extern void bfd_ticoff_set_section_load_page - (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); - -/* V850 Note manipulation routines. */ -extern bfd_boolean v850_elf_create_sections - (struct bfd_link_info *); - -extern bfd_boolean v850_elf_set_note - (bfd *, unsigned int, unsigned int); - -/* MIPS ABI flags data access. For the disassembler. */ -struct elf_internal_abiflags_v0; -extern struct elf_internal_abiflags_v0 *bfd_mips_elf_get_abiflags (bfd *); diff --git a/sdcc/support/sdbinutils/bfd/bout.c b/sdcc/support/sdbinutils/bfd/bout.c deleted file mode 100644 index 1098cf9e4..000000000 --- a/sdcc/support/sdbinutils/bfd/bout.c +++ /dev/null @@ -1,1483 +0,0 @@ -/* BFD back-end for Intel 960 b.out binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "genlink.h" -#include "bout.h" -#include "libiberty.h" - -#include "aout/stab_gnu.h" -#include "libaout.h" /* BFD a.out internal data structures. */ - -#define ABS32CODE 0 -#define ABS32CODE_SHRUNK 1 -#define PCREL24 2 -#define CALLJ 3 -#define ABS32 4 -#define PCREL13 5 -#define ABS32_MAYBE_RELAXABLE 1 -#define ABS32_WAS_RELAXABLE 2 - -#define ALIGNER 10 -#define ALIGNDONE 11 - -static reloc_howto_type howto_reloc_callj = - HOWTO (CALLJ, 0, 2, 24, TRUE, 0, complain_overflow_signed, 0,"callj", TRUE, 0x00ffffff, 0x00ffffff,FALSE); -static reloc_howto_type howto_reloc_abs32 = - HOWTO (ABS32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,0,"abs32", TRUE, 0xffffffff,0xffffffff,FALSE); -static reloc_howto_type howto_reloc_pcrel24 = - HOWTO (PCREL24, 0, 2, 24, TRUE, 0, complain_overflow_signed,0,"pcrel24", TRUE, 0x00ffffff,0x00ffffff,FALSE); -static reloc_howto_type howto_reloc_pcrel13 = - HOWTO (PCREL13, 0, 2, 13, TRUE, 0, complain_overflow_signed,0,"pcrel13", TRUE, 0x00001fff,0x00001fff,FALSE); -static reloc_howto_type howto_reloc_abs32codeshrunk = - HOWTO (ABS32CODE_SHRUNK, 0, 2, 24, TRUE, 0, complain_overflow_signed, 0,"callx->callj", TRUE, 0x00ffffff, 0x00ffffff,FALSE); -static reloc_howto_type howto_reloc_abs32code = - HOWTO (ABS32CODE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,0,"callx", TRUE, 0xffffffff,0xffffffff,FALSE); - -static reloc_howto_type howto_align_table[] = -{ - HOWTO (ALIGNER, 0, 0x1, 0, FALSE, 0, complain_overflow_dont, 0, "align16", FALSE, 0, 0, FALSE), - HOWTO (ALIGNER, 0, 0x3, 0, FALSE, 0, complain_overflow_dont, 0, "align32", FALSE, 0, 0, FALSE), - HOWTO (ALIGNER, 0, 0x7, 0, FALSE, 0, complain_overflow_dont, 0, "align64", FALSE, 0, 0, FALSE), - HOWTO (ALIGNER, 0, 0xf, 0, FALSE, 0, complain_overflow_dont, 0, "align128", FALSE, 0, 0, FALSE), -}; - -static reloc_howto_type howto_done_align_table[] = -{ - HOWTO (ALIGNDONE, 0x1, 0x1, 0, FALSE, 0, complain_overflow_dont, 0, "donealign16", FALSE, 0, 0, FALSE), - HOWTO (ALIGNDONE, 0x3, 0x3, 0, FALSE, 0, complain_overflow_dont, 0, "donealign32", FALSE, 0, 0, FALSE), - HOWTO (ALIGNDONE, 0x7, 0x7, 0, FALSE, 0, complain_overflow_dont, 0, "donealign64", FALSE, 0, 0, FALSE), - HOWTO (ALIGNDONE, 0xf, 0xf, 0, FALSE, 0, complain_overflow_dont, 0, "donealign128", FALSE, 0, 0, FALSE), -}; - -/* Swaps the information in an executable header taken from a raw byte - stream memory image, into the internal exec_header structure. */ - -static void -bout_swap_exec_header_in (bfd *abfd, - struct external_exec *bytes, - struct internal_exec *execp) -{ - /* Now fill in fields in the execp, from the bytes in the raw data. */ - execp->a_info = H_GET_32 (abfd, bytes->e_info); - execp->a_text = GET_WORD (abfd, bytes->e_text); - execp->a_data = GET_WORD (abfd, bytes->e_data); - execp->a_bss = GET_WORD (abfd, bytes->e_bss); - execp->a_syms = GET_WORD (abfd, bytes->e_syms); - execp->a_entry = GET_WORD (abfd, bytes->e_entry); - execp->a_trsize = GET_WORD (abfd, bytes->e_trsize); - execp->a_drsize = GET_WORD (abfd, bytes->e_drsize); - execp->a_tload = GET_WORD (abfd, bytes->e_tload); - execp->a_dload = GET_WORD (abfd, bytes->e_dload); - execp->a_talign = bytes->e_talign[0]; - execp->a_dalign = bytes->e_dalign[0]; - execp->a_balign = bytes->e_balign[0]; - execp->a_relaxable = bytes->e_relaxable[0]; -} - -/* Swaps the information in an internal exec header structure into the - supplied buffer ready for writing to disk. */ - -static void -bout_swap_exec_header_out (bfd *abfd, - struct internal_exec *execp, - struct external_exec *bytes) -{ - /* Now fill in fields in the raw data, from the fields in the exec struct. */ - H_PUT_32 (abfd, execp->a_info , bytes->e_info); - PUT_WORD (abfd, execp->a_text , bytes->e_text); - PUT_WORD (abfd, execp->a_data , bytes->e_data); - PUT_WORD (abfd, execp->a_bss , bytes->e_bss); - PUT_WORD (abfd, execp->a_syms , bytes->e_syms); - PUT_WORD (abfd, execp->a_entry , bytes->e_entry); - PUT_WORD (abfd, execp->a_trsize, bytes->e_trsize); - PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); - PUT_WORD (abfd, execp->a_tload , bytes->e_tload); - PUT_WORD (abfd, execp->a_dload , bytes->e_dload); - bytes->e_talign[0] = execp->a_talign; - bytes->e_dalign[0] = execp->a_dalign; - bytes->e_balign[0] = execp->a_balign; - bytes->e_relaxable[0] = execp->a_relaxable; -} - -/* Finish up the opening of a b.out file for reading. Fill in all the - fields that are not handled by common code. */ - -static const bfd_target * -b_out_callback (bfd *abfd) -{ - struct internal_exec *execp = exec_hdr (abfd); - unsigned long bss_start; - - /* Architecture and machine type. */ - bfd_set_arch_mach (abfd, - bfd_arch_i960, /* B.out only used on i960. */ - bfd_mach_i960_core /* Default. */ - ); - - /* The positions of the string table and symbol table. */ - obj_str_filepos (abfd) = N_STROFF (execp); - obj_sym_filepos (abfd) = N_SYMOFF (execp); - - /* The alignments of the sections. */ - obj_textsec (abfd)->alignment_power = execp->a_talign; - obj_datasec (abfd)->alignment_power = execp->a_dalign; - obj_bsssec (abfd)->alignment_power = execp->a_balign; - - /* The starting addresses of the sections. */ - obj_textsec (abfd)->vma = execp->a_tload; - obj_datasec (abfd)->vma = execp->a_dload; - - obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; - obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; - - /* And reload the sizes, since the aout module zaps them. */ - obj_textsec (abfd)->size = execp->a_text; - - bss_start = execp->a_dload + execp->a_data; /* BSS = end of data section. */ - obj_bsssec (abfd)->vma = align_power (bss_start, execp->a_balign); - - obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; - - /* The file positions of the sections. */ - obj_textsec (abfd)->filepos = N_TXTOFF (execp); - obj_datasec (abfd)->filepos = N_DATOFF (execp); - - /* The file positions of the relocation info. */ - obj_textsec (abfd)->rel_filepos = N_TROFF (execp); - obj_datasec (abfd)->rel_filepos = N_DROFF (execp); - - adata (abfd).page_size = 1; /* Not applicable. */ - adata (abfd).segment_size = 1; /* Not applicable. */ - adata (abfd).exec_bytes_size = EXEC_BYTES_SIZE; - - if (execp->a_relaxable) - abfd->flags |= BFD_IS_RELAXABLE; - return abfd->xvec; -} - -static const bfd_target * -b_out_object_p (bfd *abfd) -{ - struct internal_exec anexec; - struct external_exec exec_bytes; - bfd_size_type amt = EXEC_BYTES_SIZE; - - if (bfd_bread ((void *) &exec_bytes, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return 0; - } - - anexec.a_info = H_GET_32 (abfd, exec_bytes.e_info); - - if (N_BADMAG (&anexec)) - { - bfd_set_error (bfd_error_wrong_format); - return 0; - } - - bout_swap_exec_header_in (abfd, &exec_bytes, &anexec); - return aout_32_some_aout_object_p (abfd, &anexec, b_out_callback); -} - -struct bout_data_struct - { - struct aoutdata a; - struct internal_exec e; - }; - -static bfd_boolean -b_out_mkobject (bfd *abfd) -{ - struct bout_data_struct *rawptr; - bfd_size_type amt = sizeof (struct bout_data_struct); - - rawptr = bfd_zalloc (abfd, amt); - if (rawptr == NULL) - return FALSE; - - abfd->tdata.bout_data = rawptr; - exec_hdr (abfd) = &rawptr->e; - - obj_textsec (abfd) = NULL; - obj_datasec (abfd) = NULL; - obj_bsssec (abfd) = NULL; - - return TRUE; -} - -static int -b_out_symbol_cmp (const void * a_ptr, const void * b_ptr) -{ - struct aout_symbol ** a = (struct aout_symbol **) a_ptr; - struct aout_symbol ** b = (struct aout_symbol **) b_ptr; - asection *sec; - bfd_vma av, bv; - - /* Primary key is address. */ - sec = bfd_get_section (&(*a)->symbol); - av = sec->output_section->vma + sec->output_offset + (*a)->symbol.value; - sec = bfd_get_section (&(*b)->symbol); - bv = sec->output_section->vma + sec->output_offset + (*b)->symbol.value; - - if (av < bv) - return -1; - if (av > bv) - return 1; - - /* Secondary key puts CALLNAME syms last and BALNAME syms first, - so that they have the best chance of being contiguous. */ - if (IS_BALNAME ((*a)->other) || IS_CALLNAME ((*b)->other)) - return -1; - if (IS_CALLNAME ((*a)->other) || IS_BALNAME ((*b)->other)) - return 1; - - return 0; -} - -static bfd_boolean -b_out_squirt_out_relocs (bfd *abfd, asection *section) -{ - arelent **generic; - int r_extern = 0; - int r_idx; - int incode_mask; - int len_1; - unsigned int count = section->reloc_count; - struct relocation_info *native, *natptr; - bfd_size_type natsize; - int extern_mask, pcrel_mask, len_2, callj_mask; - - if (count == 0) - return TRUE; - - generic = section->orelocation; - natsize = (bfd_size_type) count * sizeof (struct relocation_info); - native = bfd_malloc (natsize); - if (!native && natsize != 0) - return FALSE; - - if (bfd_header_big_endian (abfd)) - { - /* Big-endian bit field allocation order. */ - pcrel_mask = 0x80; - extern_mask = 0x10; - len_2 = 0x40; - len_1 = 0x20; - callj_mask = 0x02; - incode_mask = 0x08; - } - else - { - /* Little-endian bit field allocation order. */ - pcrel_mask = 0x01; - extern_mask = 0x08; - len_2 = 0x04; - len_1 = 0x02; - callj_mask = 0x40; - incode_mask = 0x10; - } - - for (natptr = native; count > 0; --count, ++natptr, ++generic) - { - arelent *g = *generic; - unsigned char *raw = (unsigned char *) natptr; - asymbol *sym = *(g->sym_ptr_ptr); - asection *output_section = sym->section->output_section; - - H_PUT_32 (abfd, g->address, raw); - /* Find a type in the output format which matches the input howto - - at the moment we assume input format == output format FIXME!! */ - r_idx = 0; - /* FIXME: Need callj stuff here, and to check the howto entries to - be sure they are real for this architecture. */ - if (g->howto== &howto_reloc_callj) - raw[7] = callj_mask + pcrel_mask + len_2; - else if (g->howto == &howto_reloc_pcrel24) - raw[7] = pcrel_mask + len_2; - else if (g->howto == &howto_reloc_pcrel13) - raw[7] = pcrel_mask + len_1; - else if (g->howto == &howto_reloc_abs32code) - raw[7] = len_2 + incode_mask; - else if (g->howto >= howto_align_table - && g->howto <= (howto_align_table + ARRAY_SIZE (howto_align_table) - 1)) - { - /* symnum == -2; extern_mask not set, pcrel_mask set. */ - r_idx = -2; - r_extern = 0; - raw[7] = (pcrel_mask - | ((g->howto - howto_align_table) << 1)); - } - else - raw[7] = len_2; - - if (r_idx != 0) - /* Already mucked with r_extern, r_idx. */; - else if (bfd_is_com_section (output_section) - || bfd_is_abs_section (output_section) - || bfd_is_und_section (output_section)) - { - if (bfd_abs_section_ptr->symbol == sym) - { - /* Whoops, looked like an abs symbol, but is really an offset - from the abs section. */ - r_idx = 0; - r_extern = 0; - } - else - { - /* Fill in symbol. */ - r_extern = 1; - r_idx = (*g->sym_ptr_ptr)->udata.i; - } - } - else - { - /* Just an ordinary section. */ - r_extern = 0; - r_idx = output_section->target_index; - } - - if (bfd_header_big_endian (abfd)) - { - raw[4] = (unsigned char) (r_idx >> 16); - raw[5] = (unsigned char) (r_idx >> 8); - raw[6] = (unsigned char) (r_idx ); - } - else - { - raw[6] = (unsigned char) (r_idx >> 16); - raw[5] = (unsigned char) (r_idx>> 8); - raw[4] = (unsigned char) (r_idx ); - } - - if (r_extern) - raw[7] |= extern_mask; - } - - if (bfd_bwrite ((void *) native, natsize, abfd) != natsize) - { - free (native); - return FALSE; - } - - free (native); - - return TRUE; -} - -static bfd_boolean -b_out_write_object_contents (bfd *abfd) -{ - struct external_exec swapped_hdr; - bfd_size_type amt; - - if (! aout_32_make_sections (abfd)) - return FALSE; - - exec_hdr (abfd)->a_info = BMAGIC; - - exec_hdr (abfd)->a_text = obj_textsec (abfd)->size; - exec_hdr (abfd)->a_data = obj_datasec (abfd)->size; - exec_hdr (abfd)->a_bss = obj_bsssec (abfd)->size; - exec_hdr (abfd)->a_syms = bfd_get_symcount (abfd) * 12; - exec_hdr (abfd)->a_entry = bfd_get_start_address (abfd); - exec_hdr (abfd)->a_trsize = (obj_textsec (abfd)->reloc_count) * 8; - exec_hdr (abfd)->a_drsize = (obj_datasec (abfd)->reloc_count) * 8; - - exec_hdr (abfd)->a_talign = obj_textsec (abfd)->alignment_power; - exec_hdr (abfd)->a_dalign = obj_datasec (abfd)->alignment_power; - exec_hdr (abfd)->a_balign = obj_bsssec (abfd)->alignment_power; - - exec_hdr (abfd)->a_tload = obj_textsec (abfd)->vma; - exec_hdr (abfd)->a_dload = obj_datasec (abfd)->vma; - - bout_swap_exec_header_out (abfd, exec_hdr (abfd), &swapped_hdr); - - amt = EXEC_BYTES_SIZE; - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 - || bfd_bwrite ((void *) &swapped_hdr, amt, abfd) != amt) - return FALSE; - - /* Now write out reloc info, followed by syms and strings */ - if (bfd_get_symcount (abfd) != 0) - { - /* Make sure {CALL,BAL}NAME symbols remain adjacent on output - by sorting. This is complicated by the fact that stabs are - also ordered. Solve this by shifting all stabs to the end - in order, then sorting the rest. */ - - asymbol **outsyms, **p, **q; - - outsyms = bfd_get_outsymbols (abfd); - p = outsyms + bfd_get_symcount (abfd); - - for (q = p--; p >= outsyms; p--) - { - if ((*p)->flags & BSF_DEBUGGING) - { - asymbol *t = *--q; - *q = *p; - *p = t; - } - } - - if (q > outsyms) - qsort (outsyms, (size_t) (q - outsyms), sizeof (asymbol*), - b_out_symbol_cmp); - - /* Back to your regularly scheduled program. */ - if (bfd_seek (abfd, (file_ptr) (N_SYMOFF (exec_hdr (abfd))), SEEK_SET) - != 0) - return FALSE; - - if (! aout_32_write_syms (abfd)) - return FALSE; - - if (bfd_seek (abfd, (file_ptr) (N_TROFF (exec_hdr (abfd))), SEEK_SET) - != 0) - return FALSE; - - if (!b_out_squirt_out_relocs (abfd, obj_textsec (abfd))) - return FALSE; - if (bfd_seek (abfd, (file_ptr) (N_DROFF (exec_hdr (abfd))), SEEK_SET) - != 0) - return FALSE; - - if (!b_out_squirt_out_relocs (abfd, obj_datasec (abfd))) - return FALSE; - } - return TRUE; -} - -/* Some reloc hackery. */ - -#define CALLS 0x66003800 /* Template for 'calls' instruction */ -#define BAL 0x0b000000 /* Template for 'bal' instruction */ -#define BAL_MASK 0x00ffffff -#define BALX 0x85f00000 /* Template for 'balx' instruction */ -#define BALX_MASK 0x0007ffff -#define CALL 0x09000000 -#define PCREL13_MASK 0x1fff - -#define output_addr(sec) ((sec)->output_offset+(sec)->output_section->vma) - -static bfd_vma -get_value (arelent *reloc, - struct bfd_link_info *link_info, - asection *input_section) -{ - bfd_vma value; - asymbol *symbol = *(reloc->sym_ptr_ptr); - - /* A symbol holds a pointer to a section, and an offset from the - base of the section. To relocate, we find where the section will - live in the output and add that in. */ - if (bfd_is_und_section (symbol->section)) - { - struct bfd_link_hash_entry *h; - - /* The symbol is undefined in this BFD. Look it up in the - global linker hash table. FIXME: This should be changed when - we convert b.out to use a specific final_link function and - change the interface to bfd_relax_section to not require the - generic symbols. */ - h = bfd_wrapped_link_hash_lookup (input_section->owner, link_info, - bfd_asymbol_name (symbol), - FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry *) NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - value = h->u.def.value + output_addr (h->u.def.section); - else if (h != (struct bfd_link_hash_entry *) NULL - && h->type == bfd_link_hash_common) - value = h->u.c.size; - else - { - (*link_info->callbacks->undefined_symbol) - (link_info, bfd_asymbol_name (symbol), - input_section->owner, input_section, reloc->address, TRUE); - value = 0; - } - } - else - value = symbol->value + output_addr (symbol->section); - - /* Add the value contained in the relocation. */ - value += reloc->addend; - - return value; -} - -/* Magic to turn callx into calljx. */ - -static bfd_reloc_status_type -calljx_callback (bfd *abfd, - struct bfd_link_info *link_info, - arelent *reloc_entry, - void * src, - void * dst, - asection *input_section) -{ - int word = bfd_get_32 (abfd, src); - asymbol *symbol_in = *(reloc_entry->sym_ptr_ptr); - aout_symbol_type *symbol = aout_symbol (symbol_in); - bfd_vma value; - - value = get_value (reloc_entry, link_info, input_section); - - if (IS_CALLNAME (symbol->other)) - { - aout_symbol_type *balsym = symbol+1; - int inst = bfd_get_32 (abfd, (bfd_byte *) src-4); - - /* The next symbol should be an N_BALNAME. */ - BFD_ASSERT (IS_BALNAME (balsym->other)); - inst &= BALX_MASK; - inst |= BALX; - bfd_put_32 (abfd, (bfd_vma) inst, (bfd_byte *) dst-4); - symbol = balsym; - value = (symbol->symbol.value - + output_addr (symbol->symbol.section)); - } - - word += value + reloc_entry->addend; - - bfd_put_32 (abfd, (bfd_vma) word, dst); - return bfd_reloc_ok; -} - -/* Magic to turn call into callj. */ - -static bfd_reloc_status_type -callj_callback (bfd *abfd, - struct bfd_link_info *link_info, - arelent *reloc_entry, - void * data, - unsigned int srcidx, - unsigned int dstidx, - asection *input_section, - bfd_boolean shrinking) -{ - int word = bfd_get_32 (abfd, (bfd_byte *) data + srcidx); - asymbol *symbol_in = *(reloc_entry->sym_ptr_ptr); - aout_symbol_type *symbol = aout_symbol (symbol_in); - bfd_vma value; - - value = get_value (reloc_entry, link_info, input_section); - - if (IS_OTHER (symbol->other)) - /* Call to a system procedure - replace code with system - procedure number. */ - word = CALLS | (symbol->other - 1); - - else if (IS_CALLNAME (symbol->other)) - { - aout_symbol_type *balsym = symbol+1; - - /* The next symbol should be an N_BALNAME. */ - BFD_ASSERT (IS_BALNAME (balsym->other)); - - /* We are calling a leaf, so replace the call instruction with a - bal. */ - word = BAL | ((word - + output_addr (balsym->symbol.section) - + balsym->symbol.value + reloc_entry->addend - - dstidx - - output_addr (input_section)) - & BAL_MASK); - } - else if ((symbol->symbol.flags & BSF_SECTION_SYM) != 0) - { - /* A callj against a symbol in the same section is a fully - resolved relative call. We don't need to do anything here. - If the symbol is not in the same section, I'm not sure what - to do; fortunately, this case will probably never arise. */ - BFD_ASSERT (! shrinking); - BFD_ASSERT (symbol->symbol.section == input_section); - } - else - word = CALL | (((word & BAL_MASK) - + value - + reloc_entry->addend - - (shrinking ? dstidx : 0) - - output_addr (input_section)) - & BAL_MASK); - - bfd_put_32 (abfd, (bfd_vma) word, (bfd_byte *) data + dstidx); - return bfd_reloc_ok; -} - -static reloc_howto_type * -b_out_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - default: - return 0; - case BFD_RELOC_I960_CALLJ: - return &howto_reloc_callj; - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - return &howto_reloc_abs32; - case BFD_RELOC_24_PCREL: - return &howto_reloc_pcrel24; - } -} - -static reloc_howto_type * -b_out_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - if (strcasecmp (howto_reloc_callj.name, r_name) == 0) - return &howto_reloc_callj; - if (strcasecmp (howto_reloc_abs32.name, r_name) == 0) - return &howto_reloc_abs32; - if (strcasecmp (howto_reloc_pcrel24.name, r_name) == 0) - return &howto_reloc_pcrel24; - - return NULL; -} - -/* Allocate enough room for all the reloc entries, plus pointers to them all. */ - -static bfd_boolean -b_out_slurp_reloc_table (bfd *abfd, sec_ptr asect, asymbol **symbols) -{ - struct relocation_info *rptr; - unsigned int counter; - arelent *cache_ptr; - int extern_mask, pcrel_mask, callj_mask, length_shift; - int incode_mask; - int size_mask; - bfd_vma prev_addr = 0; - unsigned int count; - bfd_size_type reloc_size, amt; - struct relocation_info *relocs; - arelent *reloc_cache; - - if (asect->relocation) - return TRUE; - - if (!aout_32_slurp_symbol_table (abfd)) - return FALSE; - - if (asect == obj_datasec (abfd)) - reloc_size = exec_hdr (abfd)->a_drsize; - else if (asect == obj_textsec (abfd)) - reloc_size = exec_hdr (abfd)->a_trsize; - else if (asect == obj_bsssec (abfd)) - reloc_size = 0; - else - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - if (bfd_seek (abfd, asect->rel_filepos, SEEK_SET) != 0) - return FALSE; - count = reloc_size / sizeof (struct relocation_info); - - relocs = bfd_malloc (reloc_size); - if (!relocs && reloc_size != 0) - return FALSE; - - amt = ((bfd_size_type) count + 1) * sizeof (arelent); - reloc_cache = bfd_malloc (amt); - if (!reloc_cache) - { - if (relocs != NULL) - free (relocs); - return FALSE; - } - - if (bfd_bread ((void *) relocs, reloc_size, abfd) != reloc_size) - { - free (reloc_cache); - if (relocs != NULL) - free (relocs); - return FALSE; - } - - if (bfd_header_big_endian (abfd)) - { - /* Big-endian bit field allocation order. */ - pcrel_mask = 0x80; - extern_mask = 0x10; - incode_mask = 0x08; - callj_mask = 0x02; - size_mask = 0x20; - length_shift = 5; - } - else - { - /* Little-endian bit field allocation order. */ - pcrel_mask = 0x01; - extern_mask = 0x08; - incode_mask = 0x10; - callj_mask = 0x40; - size_mask = 0x02; - length_shift = 1; - } - - for (rptr = relocs, cache_ptr = reloc_cache, counter = 0; - counter < count; - counter++, rptr++, cache_ptr++) - { - unsigned char *raw = (unsigned char *)rptr; - unsigned int symnum; - - cache_ptr->address = H_GET_32 (abfd, raw + 0); - cache_ptr->howto = 0; - - if (bfd_header_big_endian (abfd)) - symnum = (raw[4] << 16) | (raw[5] << 8) | raw[6]; - else - symnum = (raw[6] << 16) | (raw[5] << 8) | raw[4]; - - if (raw[7] & extern_mask) - { - /* If this is set then the r_index is an index into the symbol table; - if the bit is not set then r_index contains a section map. - We either fill in the sym entry with a pointer to the symbol, - or point to the correct section. */ - cache_ptr->sym_ptr_ptr = symbols + symnum; - cache_ptr->addend = 0; - } - else - { - /* In a.out symbols are relative to the beginning of the - file rather than sections ? - (look in translate_from_native_sym_flags) - The reloc entry addend has added to it the offset into the - file of the data, so subtract the base to make the reloc - section relative. */ - int s; - - /* Sign-extend symnum from 24 bits to whatever host uses. */ - s = symnum; - if (s & (1 << 23)) - s |= (~0U) << 24; - - cache_ptr->sym_ptr_ptr = (asymbol **)NULL; - switch (s) - { - case N_TEXT: - case N_TEXT | N_EXT: - cache_ptr->sym_ptr_ptr = obj_textsec (abfd)->symbol_ptr_ptr; - cache_ptr->addend = - obj_textsec (abfd)->vma; - break; - case N_DATA: - case N_DATA | N_EXT: - cache_ptr->sym_ptr_ptr = obj_datasec (abfd)->symbol_ptr_ptr; - cache_ptr->addend = - obj_datasec (abfd)->vma; - break; - case N_BSS: - case N_BSS | N_EXT: - cache_ptr->sym_ptr_ptr = obj_bsssec (abfd)->symbol_ptr_ptr; - cache_ptr->addend = - obj_bsssec (abfd)->vma; - break; - case N_ABS: - case N_ABS | N_EXT: - cache_ptr->sym_ptr_ptr = obj_bsssec (abfd)->symbol_ptr_ptr; - cache_ptr->addend = 0; - break; - case -2: /* .align */ - if (raw[7] & pcrel_mask) - { - cache_ptr->howto = &howto_align_table[(raw[7] >> length_shift) & 3]; - cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - } - else - { - /* .org? */ - abort (); - } - cache_ptr->addend = 0; - break; - default: - BFD_ASSERT (FALSE); - break; - } - } - - /* The i960 only has a few relocation types: - abs 32-bit and pcrel 24bit. except for callj's! */ - if (cache_ptr->howto != 0) - ; - else if (raw[7] & callj_mask) - { - cache_ptr->howto = &howto_reloc_callj; - } - else if ( raw[7] & pcrel_mask) - { - if (raw[7] & size_mask) - cache_ptr->howto = &howto_reloc_pcrel13; - else - cache_ptr->howto = &howto_reloc_pcrel24; - } - else - { - if (raw[7] & incode_mask) - cache_ptr->howto = &howto_reloc_abs32code; - else - cache_ptr->howto = &howto_reloc_abs32; - } - - if (cache_ptr->address < prev_addr) - { - /* Ouch! this reloc is out of order, insert into the right place. */ - arelent tmp; - arelent *cursor = cache_ptr-1; - bfd_vma stop = cache_ptr->address; - - tmp = *cache_ptr; - while (cursor->address > stop && cursor >= reloc_cache) - { - cursor[1] = cursor[0]; - cursor--; - } - - cursor[1] = tmp; - } - else - prev_addr = cache_ptr->address; - } - - if (relocs != NULL) - free (relocs); - asect->relocation = reloc_cache; - asect->reloc_count = count; - - return TRUE; -} - -/* This is stupid. This function should be a boolean predicate. */ - -static long -b_out_canonicalize_reloc (bfd *abfd, - sec_ptr section, - arelent **relptr, - asymbol **symbols) -{ - arelent *tblptr; - unsigned int count; - - if ((section->flags & SEC_CONSTRUCTOR) != 0) - { - arelent_chain *chain = section->constructor_chain; - - for (count = 0; count < section->reloc_count; count++) - { - *relptr++ = &chain->relent; - chain = chain->next; - } - } - else - { - if (section->relocation == NULL - && ! b_out_slurp_reloc_table (abfd, section, symbols)) - return -1; - - tblptr = section->relocation; - for (count = 0; count++ < section->reloc_count;) - *relptr++ = tblptr++; - } - - *relptr = NULL; - - return section->reloc_count; -} - -static long -b_out_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; - } - - if (asect->flags & SEC_CONSTRUCTOR) - return sizeof (arelent *) * (asect->reloc_count + 1); - - if (asect == obj_datasec (abfd)) - return (sizeof (arelent *) * - ((exec_hdr (abfd)->a_drsize / sizeof (struct relocation_info)) - + 1)); - - if (asect == obj_textsec (abfd)) - return (sizeof (arelent *) * - ((exec_hdr (abfd)->a_trsize / sizeof (struct relocation_info)) - + 1)); - - if (asect == obj_bsssec (abfd)) - return 0; - - bfd_set_error (bfd_error_invalid_operation); - return -1; -} - - -static bfd_boolean -b_out_set_section_contents (bfd *abfd, - asection *section, - const void * location, - file_ptr offset, - bfd_size_type count) -{ - if (! abfd->output_has_begun) - { - /* Set by bfd.c handler. */ - if (! aout_32_make_sections (abfd)) - return FALSE; - - obj_textsec (abfd)->filepos = sizeof (struct external_exec); - obj_datasec (abfd)->filepos = obj_textsec (abfd)->filepos - + obj_textsec (abfd)->size; - } - - /* Regardless, once we know what we're doing, we might as well get going. */ - if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0) - return FALSE; - - if (count == 0) - return TRUE; - - return bfd_bwrite ((void *) location, count, abfd) == count; -} - -static bfd_boolean -b_out_set_arch_mach (bfd *abfd, - enum bfd_architecture arch, - unsigned long machine) -{ - bfd_default_set_arch_mach (abfd, arch, machine); - - if (arch == bfd_arch_unknown) /* Unknown machine arch is OK. */ - return TRUE; - - if (arch == bfd_arch_i960) /* i960 default is OK. */ - switch (machine) - { - case bfd_mach_i960_core: - case bfd_mach_i960_kb_sb: - case bfd_mach_i960_mc: - case bfd_mach_i960_xa: - case bfd_mach_i960_ca: - case bfd_mach_i960_ka_sa: - case bfd_mach_i960_jx: - case bfd_mach_i960_hx: - case 0: - return TRUE; - default: - return FALSE; - } - - return FALSE; -} - -static int -b_out_sizeof_headers (bfd *ignore_abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - return sizeof (struct external_exec); -} - -static void -perform_slip (bfd *abfd, - unsigned int slip, - asection *input_section, - bfd_vma value) -{ - asymbol **s; - - s = _bfd_generic_link_get_symbols (abfd); - BFD_ASSERT (s != (asymbol **) NULL); - - /* Find all symbols past this point, and make them know - what's happened. */ - while (*s) - { - asymbol *p = *s; - - if (p->section == input_section) - { - /* This was pointing into this section, so mangle it. */ - if (p->value > value) - { - p->value -=slip; - - if (p->udata.p != NULL) - { - struct generic_link_hash_entry *h; - - h = (struct generic_link_hash_entry *) p->udata.p; - BFD_ASSERT (h->root.type == bfd_link_hash_defined); - h->root.u.def.value -= slip; - BFD_ASSERT (h->root.u.def.value == p->value); - } - } - } - s++; - } -} - -/* This routine works out if the thing we want to get to can be - reached with a 24bit offset instead of a 32 bit one. - If it can, then it changes the amode. */ - -static int -abs32code (bfd *abfd, - asection *input_section, - arelent *r, - unsigned int shrink, - struct bfd_link_info *link_info) -{ - bfd_vma value = get_value (r, link_info, input_section); - bfd_vma dot = output_addr (input_section) + r->address; - bfd_vma gap; - - /* See if the address we're looking at within 2^23 bytes of where - we are, if so then we can use a small branch rather than the - jump we were going to. */ - gap = value - (dot - shrink); - - if ((long)(-1UL << 23) < (long)gap && (long)gap < 1L << 23) - { - /* Change the reloc type from 32bitcode possible 24, to 24bit - possible 32. */ - r->howto = &howto_reloc_abs32codeshrunk; - /* The place to relc moves back by four bytes. */ - r->address -=4; - - /* This will be four bytes smaller in the long run. */ - shrink += 4 ; - perform_slip (abfd, 4, input_section, r->address-shrink + 4); - } - - return shrink; -} - -static int -aligncode (bfd *abfd, - asection *input_section, - arelent *r, - unsigned int shrink) -{ - bfd_vma dot = output_addr (input_section) + r->address; - bfd_vma old_end; - bfd_vma new_end; - unsigned int shrink_delta; - int size = r->howto->size; - - /* Reduce the size of the alignment so that it's still aligned but - smaller - the current size is already the same size as or bigger - than the alignment required. */ - - /* Calculate the first byte following the padding before we optimize. */ - old_end = ((dot + size ) & ~size) + size+1; - /* Work out where the new end will be - remember that we're smaller - than we used to be. */ - new_end = ((dot - shrink + size) & ~size); - - shrink_delta = (old_end - new_end) - shrink; - - if (shrink_delta) - { - /* Change the reloc so that it knows how far to align to. */ - r->howto = howto_done_align_table + (r->howto - howto_align_table); - - /* Encode the stuff into the addend - for future use we need to - know how big the reloc used to be. */ - r->addend = old_end - dot + r->address; - - /* This will be N bytes smaller in the long run, adjust all the symbols. */ - perform_slip (abfd, shrink_delta, input_section, r->address - shrink); - shrink += shrink_delta; - } - - return shrink; -} - -static bfd_boolean -b_out_bfd_relax_section (bfd *abfd, - asection *i, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - /* Get enough memory to hold the stuff. */ - bfd *input_bfd = i->owner; - asection *input_section = i; - unsigned int shrink = 0 ; - arelent **reloc_vector = NULL; - long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); - - if (bfd_link_relocatable (link_info)) - (*link_info->callbacks->einfo) - (_("%P%F: --relax and -r may not be used together\n")); - - if (reloc_size < 0) - return FALSE; - - /* We only run this relaxation once. It might work to run it - multiple times, but it hasn't been tested. */ - *again = FALSE; - - if (reloc_size) - { - long reloc_count; - - reloc_vector = bfd_malloc ((bfd_size_type) reloc_size); - if (reloc_vector == NULL && reloc_size != 0) - goto error_return; - - /* Get the relocs and think about them. */ - reloc_count = - bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, - _bfd_generic_link_get_symbols (input_bfd)); - if (reloc_count < 0) - goto error_return; - if (reloc_count > 0) - { - arelent **parent; - - for (parent = reloc_vector; *parent; parent++) - { - arelent *r = *parent; - - switch (r->howto->type) - { - case ALIGNER: - /* An alignment reloc. */ - shrink = aligncode (abfd, input_section, r, shrink); - break; - case ABS32CODE: - /* A 32bit reloc in an addressing mode. */ - shrink = abs32code (input_bfd, input_section, r, shrink, - link_info); - break; - case ABS32CODE_SHRUNK: - shrink += 4; - break; - } - } - } - } - input_section->size -= shrink; - - if (reloc_vector != NULL) - free (reloc_vector); - return TRUE; - error_return: - if (reloc_vector != NULL) - free (reloc_vector); - return FALSE; -} - -static bfd_byte * -b_out_bfd_get_relocated_section_contents (bfd *output_bfd, - 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; - - if (reloc_size < 0) - goto error_return; - - /* If producing relocatable output, don't bother to relax. */ - if (relocatable) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, - data, relocatable, - symbols); - - reloc_vector = bfd_malloc ((bfd_size_type) reloc_size); - if (reloc_vector == NULL && reloc_size != 0) - goto error_return; - - /* Read in the section. */ - BFD_ASSERT (bfd_get_section_contents (input_bfd, - input_section, - data, - (bfd_vma) 0, - input_section->size)); - - 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 = reloc_vector; - arelent *reloc ; - unsigned int dst_address = 0; - unsigned int src_address = 0; - unsigned int run; - unsigned int idx; - - /* Find how long a run we can do. */ - while (dst_address < link_order->size) - { - reloc = *parent; - if (reloc) - { - /* Note that the relaxing didn't tie up the addresses in the - relocation, so we use the original address to work out the - run of non-relocated data. */ - BFD_ASSERT (reloc->address >= src_address); - run = reloc->address - src_address; - parent++; - } - else - run = link_order->size - dst_address; - - /* Copy the bytes. */ - for (idx = 0; idx < run; idx++) - data[dst_address++] = data[src_address++]; - - /* Now do the relocation. */ - if (reloc) - { - switch (reloc->howto->type) - { - case ABS32CODE: - calljx_callback (input_bfd, link_info, reloc, - src_address + data, dst_address + data, - input_section); - src_address += 4; - dst_address += 4; - break; - case ABS32: - bfd_put_32 (input_bfd, - (bfd_get_32 (input_bfd, data + src_address) - + get_value (reloc, link_info, input_section)), - data + dst_address); - src_address += 4; - dst_address += 4; - break; - case CALLJ: - callj_callback (input_bfd, link_info, reloc, data, - src_address, dst_address, input_section, - FALSE); - src_address += 4; - dst_address += 4; - break; - case ALIGNDONE: - BFD_ASSERT (reloc->addend >= src_address); - BFD_ASSERT ((bfd_vma) reloc->addend - <= input_section->size); - src_address = reloc->addend; - dst_address = ((dst_address + reloc->howto->size) - & ~reloc->howto->size); - break; - case ABS32CODE_SHRUNK: - /* This used to be a callx, but we've found out that a - callj will reach, so do the right thing. */ - callj_callback (input_bfd, link_info, reloc, data, - src_address + 4, dst_address, input_section, - TRUE); - dst_address += 4; - src_address += 8; - break; - case PCREL24: - { - long int word = bfd_get_32 (input_bfd, - data + src_address); - bfd_vma value; - - value = get_value (reloc, link_info, input_section); - word = ((word & ~BAL_MASK) - | (((word & BAL_MASK) - + value - - output_addr (input_section) - + reloc->addend) - & BAL_MASK)); - - bfd_put_32 (input_bfd, (bfd_vma) word, data + dst_address); - dst_address += 4; - src_address += 4; - - } - break; - case PCREL13: - { - long int word = bfd_get_32 (input_bfd, - data + src_address); - bfd_vma value; - - value = get_value (reloc, link_info, input_section); - word = ((word & ~PCREL13_MASK) - | (((word & PCREL13_MASK) - + value - + reloc->addend - - output_addr (input_section)) - & PCREL13_MASK)); - - bfd_put_32 (input_bfd, (bfd_vma) word, data + dst_address); - dst_address += 4; - src_address += 4; - } - break; - - default: - abort (); - } - } - } - } - if (reloc_vector != NULL) - free (reloc_vector); - return data; - error_return: - if (reloc_vector != NULL) - free (reloc_vector); - return NULL; -} - - -/* Build the transfer vectors for Big and Little-Endian B.OUT files. */ - -#define aout_32_find_line _bfd_nosymbols_find_line -#define aout_32_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string -#define aout_32_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol -#define aout_32_close_and_cleanup aout_32_bfd_free_cached_info -#define b_out_bfd_link_hash_table_create _bfd_generic_link_hash_table_create -#define b_out_bfd_link_add_symbols _bfd_generic_link_add_symbols -#define b_out_bfd_link_just_syms _bfd_generic_link_just_syms -#define b_out_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type -#define b_out_bfd_final_link _bfd_generic_final_link -#define b_out_bfd_link_split_section _bfd_generic_link_split_section -#define b_out_bfd_gc_sections bfd_generic_gc_sections -#define b_out_bfd_lookup_section_flags bfd_generic_lookup_section_flags -#define b_out_bfd_merge_sections bfd_generic_merge_sections -#define b_out_bfd_is_group_section bfd_generic_is_group_section -#define b_out_bfd_discard_group bfd_generic_discard_group -#define b_out_section_already_linked _bfd_generic_section_already_linked -#define b_out_bfd_define_common_symbol bfd_generic_define_common_symbol -#define b_out_bfd_define_start_stop bfd_generic_define_start_stop -#define aout_32_get_section_contents_in_window _bfd_generic_get_section_contents_in_window -#define b_out_bfd_link_check_relocs _bfd_generic_link_check_relocs -#define b_out_set_reloc _bfd_generic_set_reloc - -extern const bfd_target bout_le_vec; - -const bfd_target bout_be_vec = -{ - "b.out.big", /* Name. */ - bfd_target_aout_flavour, - BFD_ENDIAN_LITTLE, /* Data byte order. */ - BFD_ENDIAN_BIG, /* Header byte order. */ - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - '_', /* Symbol leading char. */ - ' ', /* AR_pad_char. */ - 16, /* AR_max_namelen. */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* 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, b_out_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, b_out_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, b_out_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (aout_32), - BFD_JUMP_TABLE_COPY (_bfd_generic), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), - BFD_JUMP_TABLE_SYMBOLS (aout_32), - BFD_JUMP_TABLE_RELOCS (b_out), - BFD_JUMP_TABLE_WRITE (b_out), - BFD_JUMP_TABLE_LINK (b_out), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & bout_le_vec, - - NULL -}; - -const bfd_target bout_le_vec = -{ - "b.out.little", /* Name. */ - bfd_target_aout_flavour, - BFD_ENDIAN_LITTLE, /* Data byte order. */ - BFD_ENDIAN_LITTLE, /* Header byte order. */ - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE ), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - '_', /* Symbol leading char. */ - ' ', /* AR_pad_char. */ - 16, /* AR_max_namelen. */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Headers. */ - - {_bfd_dummy_target, b_out_object_p, /* bfd_check_format. */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, b_out_mkobject, /* bfd_set_format. */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, b_out_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (aout_32), - BFD_JUMP_TABLE_COPY (_bfd_generic), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd), - BFD_JUMP_TABLE_SYMBOLS (aout_32), - BFD_JUMP_TABLE_RELOCS (b_out), - BFD_JUMP_TABLE_WRITE (b_out), - BFD_JUMP_TABLE_LINK (b_out), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & bout_be_vec, - - NULL -}; diff --git a/sdcc/support/sdbinutils/bfd/cf-i386lynx.c b/sdcc/support/sdbinutils/bfd/cf-i386lynx.c deleted file mode 100644 index b7f003b48..000000000 --- a/sdcc/support/sdbinutils/bfd/cf-i386lynx.c +++ /dev/null @@ -1,34 +0,0 @@ -/* BFD back-end for Intel 386 COFF LynxOS files. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" - -#define TARGET_SYM i386_coff_lynx_vec -#define TARGET_NAME "coff-i386-lynx" - -#define LYNXOS - -#define COFF_LONG_FILENAMES - -#define bfd_pe_print_pdata NULL - -#include "coff-i386.c" diff --git a/sdcc/support/sdbinutils/bfd/cf-sparclynx.c b/sdcc/support/sdbinutils/bfd/cf-sparclynx.c deleted file mode 100644 index eda30450a..000000000 --- a/sdcc/support/sdbinutils/bfd/cf-sparclynx.c +++ /dev/null @@ -1,29 +0,0 @@ -/* BFD back-end for Sparc COFF LynxOS files. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGET_SYM sparc_coff_lynx_vec -#define TARGET_NAME "coff-sparc-lynx" - -#define LYNXOS - -#define COFF_LONG_FILENAMES - -#include "coff-sparc.c" diff --git a/sdcc/support/sdbinutils/bfd/cisco-core.c b/sdcc/support/sdbinutils/bfd/cisco-core.c deleted file mode 100644 index e591ef634..000000000 --- a/sdcc/support/sdbinutils/bfd/cisco-core.c +++ /dev/null @@ -1,418 +0,0 @@ -/* BFD back-end for CISCO crash dumps. - Copyright (C) 1994-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -/* core_file_failing_signal returns a host signal (this probably should - be fixed). */ -#include - -/* for MSVC builds */ -#ifndef SIGTRAP -# define SIGTRAP 5 -#endif -#ifndef SIGEMT -# define SIGEMT 6 -#endif -#ifndef SIGBUS -# define SIGBUS 10 -#endif - -int crash_info_locs[] = -{ - 0x0250, /* mips, ppc, x86, i960 */ - 0x0400, /* m68k, mips, x86, i960 */ - 0x0FFC, /* m68k, mips, ppc, x86, i960 */ - 0x3000, /* ppc */ - 0x4FFC, /* m68k */ - -1 -}; - -#define CRASH_MAGIC 0xdead1234 -#define MASK_ADDR(x) ((x) & 0x0fffffff) /* Mask crash info address */ - -typedef enum -{ - CRASH_REASON_NOTCRASHED = 0, - CRASH_REASON_EXCEPTION = 1, - CRASH_REASON_CORRUPT = 2, -} crashreason; - -typedef struct -{ - char magic[4]; /* Magic number */ - char version[4]; /* Version number */ - char reason[4]; /* Crash reason */ - char cpu_vector[4]; /* CPU vector for exceptions */ - char registers[4]; /* Pointer to saved registers */ - char rambase[4]; /* Base of RAM (not in V1 crash info) */ - char textbase[4]; /* Base of .text section (not in V3 crash info) */ - char database[4]; /* Base of .data section (not in V3 crash info) */ - char bssbase[4]; /* Base of .bss section (not in V3 crash info) */ -} crashinfo_external; - -struct cisco_core_struct -{ - int sig; -}; - -#define cisco_core_file_matches_executable_p generic_core_file_matches_executable_p -#define cisco_core_file_pid _bfd_nocore_core_file_pid - -/* Examine the file for a crash info struct at the offset given by - CRASH_INFO_LOC. */ - -static const bfd_target * -cisco_core_file_validate (bfd *abfd, int crash_info_loc) -{ - char buf[4]; - unsigned int crashinfo_offset; - crashinfo_external crashinfo; - bfd_size_type nread; - unsigned int magic; - unsigned int version; - unsigned int rambase; - sec_ptr asect; - struct stat statbuf; - bfd_size_type amt; - flagword flags; - - if (bfd_seek (abfd, (file_ptr) crash_info_loc, SEEK_SET) != 0) - return NULL; - - nread = bfd_bread (buf, (bfd_size_type) 4, abfd); - if (nread != 4) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - crashinfo_offset = MASK_ADDR (bfd_get_32 (abfd, buf)); - - if (bfd_seek (abfd, (file_ptr) crashinfo_offset, SEEK_SET) != 0) - { - /* Most likely we failed because of a bogus (huge) offset */ - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - nread = bfd_bread (&crashinfo, (bfd_size_type) sizeof (crashinfo), abfd); - if (nread != sizeof (crashinfo)) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - if (bfd_stat (abfd, &statbuf) < 0) - { - bfd_set_error (bfd_error_system_call); - return NULL; - } - - magic = bfd_get_32 (abfd, crashinfo.magic); - if (magic != CRASH_MAGIC) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - version = bfd_get_32 (abfd, crashinfo.version); - if (version == 0) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - else if (version == 1) - { - /* V1 core dumps don't specify the dump base, assume 0 */ - rambase = 0; - } - else - { - rambase = bfd_get_32 (abfd, crashinfo.rambase); - } - - /* OK, we believe you. You're a core file. */ - - amt = sizeof (struct cisco_core_struct); - abfd->tdata.cisco_core_data = (struct cisco_core_struct *) bfd_zmalloc (amt); - if (abfd->tdata.cisco_core_data == NULL) - return NULL; - - switch ((crashreason) bfd_get_32 (abfd, crashinfo.reason)) - { - case CRASH_REASON_NOTCRASHED: - /* Crash file probably came from write core. */ - abfd->tdata.cisco_core_data->sig = 0; - break; - case CRASH_REASON_CORRUPT: - /* The crash context area was corrupt -- proceed with caution. - We have no way of passing this information back to the caller. */ - abfd->tdata.cisco_core_data->sig = 0; - break; - case CRASH_REASON_EXCEPTION: - /* Crash occured due to CPU exception. */ - - /* This is 68k-specific; for MIPS we'll need to interpret - cpu_vector differently based on the target configuration - (since CISCO core files don't seem to have the processor - encoded in them). */ - - switch (bfd_get_32 (abfd, crashinfo.cpu_vector)) - { - /* bus error */ - case 2 : abfd->tdata.cisco_core_data->sig = SIGBUS; break; - /* address error */ - case 3 : abfd->tdata.cisco_core_data->sig = SIGBUS; break; - /* illegal instruction */ - case 4 : abfd->tdata.cisco_core_data->sig = SIGILL; break; - /* zero divide */ - case 5 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* chk instruction */ - case 6 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* trapv instruction */ - case 7 : abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* privilege violation */ - case 8 : abfd->tdata.cisco_core_data->sig = SIGSEGV; break; - /* trace trap */ - case 9 : abfd->tdata.cisco_core_data->sig = SIGTRAP; break; - /* line 1010 emulator */ - case 10: abfd->tdata.cisco_core_data->sig = SIGILL; break; - /* line 1111 emulator */ - case 11: abfd->tdata.cisco_core_data->sig = SIGILL; break; - - /* Coprocessor protocol violation. Using a standard MMU or FPU - this cannot be triggered by software. Call it a SIGBUS. */ - case 13: abfd->tdata.cisco_core_data->sig = SIGBUS; break; - - /* interrupt */ - case 31: abfd->tdata.cisco_core_data->sig = SIGINT; break; - /* breakpoint */ - case 33: abfd->tdata.cisco_core_data->sig = SIGTRAP; break; - - /* floating point err */ - case 48: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* floating point err */ - case 49: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* zero divide */ - case 50: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* underflow */ - case 51: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* operand error */ - case 52: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* overflow */ - case 53: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - /* NAN */ - case 54: abfd->tdata.cisco_core_data->sig = SIGFPE; break; - default: -#ifndef SIGEMT -#define SIGEMT SIGTRAP -#endif - /* "software generated"*/ - abfd->tdata.cisco_core_data->sig = SIGEMT; - } - break; - default: - /* Unknown crash reason. */ - abfd->tdata.cisco_core_data->sig = 0; - break; - } - - /* Create a ".data" section that maps the entire file, which is - essentially a dump of the target system's RAM. */ - - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; - asect = bfd_make_section_anyway_with_flags (abfd, ".data", flags); - if (asect == NULL) - goto error_return; - /* The size of memory is the size of the core file itself. */ - asect->size = statbuf.st_size; - asect->vma = rambase; - asect->filepos = 0; - - /* Create a ".crash" section to allow access to the saved - crash information. */ - - flags = SEC_HAS_CONTENTS; - asect = bfd_make_section_anyway_with_flags (abfd, ".crash", flags); - if (asect == NULL) - goto error_return; - asect->vma = 0; - asect->filepos = crashinfo_offset; - asect->size = sizeof (crashinfo); - - /* Create a ".reg" section to allow access to the saved - registers. */ - - asect = bfd_make_section_anyway_with_flags (abfd, ".reg", flags); - if (asect == NULL) - goto error_return; - asect->vma = 0; - asect->filepos = bfd_get_32 (abfd, crashinfo.registers) - rambase; - /* Since we don't know the exact size of the saved register info, - choose a register section size that is either the remaining part - of the file, or 1024, whichever is smaller. */ - nread = statbuf.st_size - asect->filepos; - asect->size = (nread < 1024) ? nread : 1024; - - return abfd->xvec; - - /* Get here if we have already started filling out the BFD - and there is an error of some kind. */ - - error_return: - bfd_release (abfd, abfd->tdata.any); - abfd->tdata.any = NULL; - bfd_section_list_clear (abfd); - return NULL; -} - -static const bfd_target * -cisco_core_file_p (bfd *abfd) -{ - int *crash_info_locp; - const bfd_target *target = NULL; - - for (crash_info_locp = crash_info_locs; - *crash_info_locp != -1 && target == NULL; - crash_info_locp++) - { - target = cisco_core_file_validate (abfd, *crash_info_locp); - } - return (target); -} - -static char * -cisco_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED) -{ - return NULL; -} - -static int -cisco_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED) -{ - return abfd->tdata.cisco_core_data->sig; -} - -extern const bfd_target core_cisco_le_vec; - -const bfd_target core_cisco_be_vec = -{ - "cisco-ios-core-big", - bfd_target_unknown_flavour, - BFD_ENDIAN_BIG, /* target byte order */ - BFD_ENDIAN_BIG, /* target headers byte order */ - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - 0, /* symbol prefix */ - ' ', /* ar_pad_char */ - 16, /* ar_max_namelen */ - 0, /* match priority. */ - 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, /* unknown format */ - _bfd_dummy_target, /* object file */ - _bfd_dummy_target, /* archive */ - cisco_core_file_p /* a core file */ - }, - { /* bfd_set_format */ - bfd_false, bfd_false, - bfd_false, bfd_false - }, - { /* bfd_write_contents */ - bfd_false, bfd_false, - bfd_false, bfd_false - }, - - BFD_JUMP_TABLE_GENERIC (_bfd_generic), - BFD_JUMP_TABLE_COPY (_bfd_generic), - BFD_JUMP_TABLE_CORE (cisco), - BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), - BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), - BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), - BFD_JUMP_TABLE_WRITE (_bfd_generic), - BFD_JUMP_TABLE_LINK (_bfd_nolink), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & core_cisco_le_vec, - - NULL /* backend_data */ -}; - -const bfd_target core_cisco_le_vec = -{ - "cisco-ios-core-little", - bfd_target_unknown_flavour, - BFD_ENDIAN_LITTLE, /* target byte order */ - BFD_ENDIAN_LITTLE, /* target headers byte order */ - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - 0, /* symbol prefix */ - ' ', /* ar_pad_char */ - 16, /* ar_max_namelen */ - 0, /* match_priority */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - { /* bfd_check_format */ - _bfd_dummy_target, /* unknown format */ - _bfd_dummy_target, /* object file */ - _bfd_dummy_target, /* archive */ - cisco_core_file_p /* a core file */ - }, - { /* bfd_set_format */ - bfd_false, bfd_false, - bfd_false, bfd_false - }, - { /* bfd_write_contents */ - bfd_false, bfd_false, - bfd_false, bfd_false - }, - - BFD_JUMP_TABLE_GENERIC (_bfd_generic), - BFD_JUMP_TABLE_COPY (_bfd_generic), - BFD_JUMP_TABLE_CORE (cisco), - BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), - BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), - BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), - BFD_JUMP_TABLE_WRITE (_bfd_generic), - BFD_JUMP_TABLE_LINK (_bfd_nolink), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - &core_cisco_be_vec, - - NULL /* backend_data */ -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-alpha.c b/sdcc/support/sdbinutils/bfd/coff-alpha.c deleted file mode 100644 index fe8669f86..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-alpha.c +++ /dev/null @@ -1,2392 +0,0 @@ -/* BFD back-end for ALPHA Extended-Coff files. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Modified from coff-mips.c by Steve Chamberlain and - Ian Lance Taylor . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "coff/internal.h" -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/ecoff.h" -#include "coff/alpha.h" -#include "aout/ar.h" -#include "libcoff.h" -#include "libecoff.h" - -/* Prototypes for static functions. */ - - - -/* ECOFF has COFF sections, but the debugging information is stored in - a completely different format. ECOFF targets use some of the - swapping routines from coffswap.h, and some of the generic COFF - routines in coffgen.c, but, unlike the real COFF targets, do not - use coffcode.h itself. - - Get the generic COFF swapping routines, except for the reloc, - symbol, and lineno ones. Give them ecoff names. Define some - accessor macros for the large sizes used for Alpha ECOFF. */ - -#define GET_FILEHDR_SYMPTR H_GET_64 -#define PUT_FILEHDR_SYMPTR H_PUT_64 -#define GET_AOUTHDR_TSIZE H_GET_64 -#define PUT_AOUTHDR_TSIZE H_PUT_64 -#define GET_AOUTHDR_DSIZE H_GET_64 -#define PUT_AOUTHDR_DSIZE H_PUT_64 -#define GET_AOUTHDR_BSIZE H_GET_64 -#define PUT_AOUTHDR_BSIZE H_PUT_64 -#define GET_AOUTHDR_ENTRY H_GET_64 -#define PUT_AOUTHDR_ENTRY H_PUT_64 -#define GET_AOUTHDR_TEXT_START H_GET_64 -#define PUT_AOUTHDR_TEXT_START H_PUT_64 -#define GET_AOUTHDR_DATA_START H_GET_64 -#define PUT_AOUTHDR_DATA_START H_PUT_64 -#define GET_SCNHDR_PADDR H_GET_64 -#define PUT_SCNHDR_PADDR H_PUT_64 -#define GET_SCNHDR_VADDR H_GET_64 -#define PUT_SCNHDR_VADDR H_PUT_64 -#define GET_SCNHDR_SIZE H_GET_64 -#define PUT_SCNHDR_SIZE H_PUT_64 -#define GET_SCNHDR_SCNPTR H_GET_64 -#define PUT_SCNHDR_SCNPTR H_PUT_64 -#define GET_SCNHDR_RELPTR H_GET_64 -#define PUT_SCNHDR_RELPTR H_PUT_64 -#define GET_SCNHDR_LNNOPTR H_GET_64 -#define PUT_SCNHDR_LNNOPTR H_PUT_64 - -#define ALPHAECOFF - -#define NO_COFF_RELOCS -#define NO_COFF_SYMBOLS -#define NO_COFF_LINENOS -#define coff_swap_filehdr_in alpha_ecoff_swap_filehdr_in -#define coff_swap_filehdr_out alpha_ecoff_swap_filehdr_out -#define coff_swap_aouthdr_in alpha_ecoff_swap_aouthdr_in -#define coff_swap_aouthdr_out alpha_ecoff_swap_aouthdr_out -#define coff_swap_scnhdr_in alpha_ecoff_swap_scnhdr_in -#define coff_swap_scnhdr_out alpha_ecoff_swap_scnhdr_out -#include "coffswap.h" - -/* Get the ECOFF swapping routines. */ -#define ECOFF_64 -#include "ecoffswap.h" - -/* How to process the various reloc types. */ - -static bfd_reloc_status_type -reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc ATTRIBUTE_UNUSED, - asymbol *sym ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - return bfd_reloc_ok; -} - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -static reloc_howto_type alpha_howto_table[] = -{ - /* Reloc type 0 is ignored by itself. However, it appears after a - GPDISP reloc to identify the location where the low order 16 bits - of the gp register are loaded. */ - HOWTO (ALPHA_R_IGNORE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - reloc_nil, /* special_function */ - "IGNORE", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit reference to a symbol. */ - HOWTO (ALPHA_R_REFLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "REFLONG", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 64 bit reference to a symbol. */ - HOWTO (ALPHA_R_REFQUAD, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "REFQUAD", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit GP relative offset. This is just like REFLONG except - that when the value is used the value of the gp register will be - added in. */ - HOWTO (ALPHA_R_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "GPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used for an instruction that refers to memory off the GP - register. The offset is 16 bits of the 32 bit instruction. This - reloc always seems to be against the .lita section. */ - HOWTO (ALPHA_R_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This reloc only appears immediately following a LITERAL reloc. - It identifies a use of the literal. It seems that the linker can - use this to eliminate a portion of the .lita section. The symbol - index is special: 1 means the literal address is in the base - register of a memory format instruction; 2 means the literal - address is in the byte offset register of a byte-manipulation - instruction; 3 means the literal address is in the target - register of a jsr instruction. This does not actually do any - relocation. */ - HOWTO (ALPHA_R_LITUSE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - reloc_nil, /* special_function */ - "LITUSE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Load the gp register. This is always used for a ldah instruction - which loads the upper 16 bits of the gp register. The next reloc - will be an IGNORE reloc which identifies the location of the lda - instruction which loads the lower 16 bits. The symbol index of - the GPDISP instruction appears to actually be the number of bytes - between the ldah and lda instructions. This gives two different - ways to determine where the lda instruction is; I don't know why - both are used. The value to use for the relocation is the - difference between the GP value and the current location; the - load will always be done against a register holding the current - address. */ - HOWTO (ALPHA_R_GPDISP, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - reloc_nil, /* special_function */ - "GPDISP", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 21 bit branch. The native assembler generates these for - branches within the text segment, and also fills in the PC - relative offset in the instruction. */ - HOWTO (ALPHA_R_BRADDR, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "BRADDR", /* name */ - TRUE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A hint for a jump to a register. */ - HOWTO (ALPHA_R_HINT, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 14, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "HINT", /* name */ - TRUE, /* partial_inplace */ - 0x3fff, /* src_mask */ - 0x3fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative offset. */ - HOWTO (ALPHA_R_SREL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "SREL16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit PC relative offset. */ - HOWTO (ALPHA_R_SREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "SREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 64 bit PC relative offset. */ - HOWTO (ALPHA_R_SREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "SREL64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Push a value on the reloc evaluation stack. */ - HOWTO (ALPHA_R_OP_PUSH, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "OP_PUSH", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Store the value from the stack at the given address. Store it in - a bitfield of size r_size starting at bit position r_offset. */ - HOWTO (ALPHA_R_OP_STORE, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "OP_STORE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Subtract the reloc address from the value on the top of the - relocation stack. */ - HOWTO (ALPHA_R_OP_PSUB, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "OP_PSUB", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Shift the value on the top of the relocation stack right by the - given value. */ - HOWTO (ALPHA_R_OP_PRSHIFT, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "OP_PRSHIFT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Adjust the GP value for a new range in the object file. */ - HOWTO (ALPHA_R_GPVALUE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "GPVALUE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -/* Recognize an Alpha ECOFF file. */ - -static const bfd_target * -alpha_ecoff_object_p (bfd *abfd) -{ - static const bfd_target *ret; - - ret = coff_object_p (abfd); - - if (ret != NULL) - { - asection *sec; - - /* Alpha ECOFF has a .pdata section. The lnnoptr field of the - .pdata section is the number of entries it contains. Each - entry takes up 8 bytes. The number of entries is required - since the section is aligned to a 16 byte boundary. When we - link .pdata sections together, we do not want to include the - alignment bytes. We handle this on input by faking the size - of the .pdata section to remove the unwanted alignment bytes. - On output we will set the lnnoptr field and force the - alignment. */ - sec = bfd_get_section_by_name (abfd, _PDATA); - if (sec != (asection *) NULL) - { - bfd_size_type size; - - size = sec->line_filepos * 8; - BFD_ASSERT (size == sec->size - || size + 8 == sec->size); - if (! bfd_set_section_size (abfd, sec, size)) - return NULL; - } - } - - return ret; -} - -/* See whether the magic number matches. */ - -static bfd_boolean -alpha_ecoff_bad_format_hook (bfd *abfd ATTRIBUTE_UNUSED, - void * filehdr) -{ - struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; - - if (! ALPHA_ECOFF_BADMAG (*internal_f)) - return TRUE; - - if (ALPHA_ECOFF_COMPRESSEDMAG (*internal_f)) - _bfd_error_handler - (_("%B: Cannot handle compressed Alpha binaries.\n" - " Use compiler flags, or objZ, to generate uncompressed binaries."), - abfd); - - return FALSE; -} - -/* This is a hook called by coff_real_object_p to create any backend - specific information. */ - -static void * -alpha_ecoff_mkobject_hook (bfd *abfd, void * filehdr, void * aouthdr) -{ - void * ecoff; - - ecoff = _bfd_ecoff_mkobject_hook (abfd, filehdr, aouthdr); - - if (ecoff != NULL) - { - struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; - - /* Set additional BFD flags according to the object type from the - machine specific file header flags. */ - switch (internal_f->f_flags & F_ALPHA_OBJECT_TYPE_MASK) - { - case F_ALPHA_SHARABLE: - abfd->flags |= DYNAMIC; - break; - case F_ALPHA_CALL_SHARED: - /* Always executable if using shared libraries as the run time - loader might resolve undefined references. */ - abfd->flags |= (DYNAMIC | EXEC_P); - break; - } - } - return ecoff; -} - -/* Reloc handling. */ - -/* Swap a reloc in. */ - -static void -alpha_ecoff_swap_reloc_in (bfd *abfd, - void * ext_ptr, - struct internal_reloc *intern) -{ - const RELOC *ext = (RELOC *) ext_ptr; - - intern->r_vaddr = H_GET_64 (abfd, ext->r_vaddr); - intern->r_symndx = H_GET_32 (abfd, ext->r_symndx); - - BFD_ASSERT (bfd_header_little_endian (abfd)); - - intern->r_type = ((ext->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) - >> RELOC_BITS0_TYPE_SH_LITTLE); - intern->r_extern = (ext->r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; - intern->r_offset = ((ext->r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) - >> RELOC_BITS1_OFFSET_SH_LITTLE); - /* Ignored the reserved bits. */ - intern->r_size = ((ext->r_bits[3] & RELOC_BITS3_SIZE_LITTLE) - >> RELOC_BITS3_SIZE_SH_LITTLE); - - if (intern->r_type == ALPHA_R_LITUSE - || intern->r_type == ALPHA_R_GPDISP) - { - /* Handle the LITUSE and GPDISP relocs specially. Its symndx - value is not actually a symbol index, but is instead a - special code. We put the code in the r_size field, and - clobber the symndx. */ - if (intern->r_size != 0) - abort (); - intern->r_size = intern->r_symndx; - intern->r_symndx = RELOC_SECTION_NONE; - } - else if (intern->r_type == ALPHA_R_IGNORE) - { - /* The IGNORE reloc generally follows a GPDISP reloc, and is - against the .lita section. The section is irrelevant. */ - if (! intern->r_extern && - intern->r_symndx == RELOC_SECTION_ABS) - abort (); - if (! intern->r_extern && intern->r_symndx == RELOC_SECTION_LITA) - intern->r_symndx = RELOC_SECTION_ABS; - } -} - -/* Swap a reloc out. */ - -static void -alpha_ecoff_swap_reloc_out (bfd *abfd, - const struct internal_reloc *intern, - void * dst) -{ - RELOC *ext = (RELOC *) dst; - long symndx; - unsigned char size; - - /* Undo the hackery done in swap_reloc_in. */ - if (intern->r_type == ALPHA_R_LITUSE - || intern->r_type == ALPHA_R_GPDISP) - { - symndx = intern->r_size; - size = 0; - } - else if (intern->r_type == ALPHA_R_IGNORE - && ! intern->r_extern - && intern->r_symndx == RELOC_SECTION_ABS) - { - symndx = RELOC_SECTION_LITA; - size = intern->r_size; - } - else - { - symndx = intern->r_symndx; - size = intern->r_size; - } - - /* XXX FIXME: The maximum symndx value used to be 14 but this - fails with object files produced by DEC's C++ compiler. - Where does the value 14 (or 15) come from anyway ? */ - BFD_ASSERT (intern->r_extern - || (intern->r_symndx >= 0 && intern->r_symndx <= 15)); - - H_PUT_64 (abfd, intern->r_vaddr, ext->r_vaddr); - H_PUT_32 (abfd, symndx, ext->r_symndx); - - BFD_ASSERT (bfd_header_little_endian (abfd)); - - ext->r_bits[0] = ((intern->r_type << RELOC_BITS0_TYPE_SH_LITTLE) - & RELOC_BITS0_TYPE_LITTLE); - ext->r_bits[1] = ((intern->r_extern ? RELOC_BITS1_EXTERN_LITTLE : 0) - | ((intern->r_offset << RELOC_BITS1_OFFSET_SH_LITTLE) - & RELOC_BITS1_OFFSET_LITTLE)); - ext->r_bits[2] = 0; - ext->r_bits[3] = ((size << RELOC_BITS3_SIZE_SH_LITTLE) - & RELOC_BITS3_SIZE_LITTLE); -} - -/* Finish canonicalizing a reloc. Part of this is generic to all - ECOFF targets, and that part is in ecoff.c. The rest is done in - this backend routine. It must fill in the howto field. */ - -static void -alpha_adjust_reloc_in (bfd *abfd, - const struct internal_reloc *intern, - arelent *rptr) -{ - if (intern->r_type > ALPHA_R_GPVALUE) - { - /* xgettext:c-format */ - _bfd_error_handler - (_("%B: unknown/unsupported relocation type %d"), - abfd, intern->r_type); - bfd_set_error (bfd_error_bad_value); - rptr->addend = 0; - rptr->howto = NULL; - return; - } - - switch (intern->r_type) - { - case ALPHA_R_BRADDR: - case ALPHA_R_SREL16: - case ALPHA_R_SREL32: - case ALPHA_R_SREL64: - /* This relocs appear to be fully resolved when they are against - internal symbols. Against external symbols, BRADDR at least - appears to be resolved against the next instruction. */ - if (! intern->r_extern) - rptr->addend = 0; - else - rptr->addend = - (intern->r_vaddr + 4); - break; - - case ALPHA_R_GPREL32: - case ALPHA_R_LITERAL: - /* Copy the gp value for this object file into the addend, to - ensure that we are not confused by the linker. */ - if (! intern->r_extern) - rptr->addend += ecoff_data (abfd)->gp; - break; - - case ALPHA_R_LITUSE: - case ALPHA_R_GPDISP: - /* The LITUSE and GPDISP relocs do not use a symbol, or an - addend, but they do use a special code. Put this code in the - addend field. */ - rptr->addend = intern->r_size; - break; - - case ALPHA_R_OP_STORE: - /* The STORE reloc needs the size and offset fields. We store - them in the addend. */ - BFD_ASSERT (intern->r_offset <= 256); - rptr->addend = (intern->r_offset << 8) + intern->r_size; - break; - - case ALPHA_R_OP_PUSH: - case ALPHA_R_OP_PSUB: - case ALPHA_R_OP_PRSHIFT: - /* The PUSH, PSUB and PRSHIFT relocs do not actually use an - address. I believe that the address supplied is really an - addend. */ - rptr->addend = intern->r_vaddr; - break; - - case ALPHA_R_GPVALUE: - /* Set the addend field to the new GP value. */ - rptr->addend = intern->r_symndx + ecoff_data (abfd)->gp; - break; - - case ALPHA_R_IGNORE: - /* If the type is ALPHA_R_IGNORE, make sure this is a reference - to the absolute section so that the reloc is ignored. For - some reason the address of this reloc type is not adjusted by - the section vma. We record the gp value for this object file - here, for convenience when doing the GPDISP relocation. */ - rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - rptr->address = intern->r_vaddr; - rptr->addend = ecoff_data (abfd)->gp; - break; - - default: - break; - } - - rptr->howto = &alpha_howto_table[intern->r_type]; -} - -/* When writing out a reloc we need to pull some values back out of - the addend field into the reloc. This is roughly the reverse of - alpha_adjust_reloc_in, except that there are several changes we do - not need to undo. */ - -static void -alpha_adjust_reloc_out (bfd *abfd ATTRIBUTE_UNUSED, - const arelent *rel, - struct internal_reloc *intern) -{ - switch (intern->r_type) - { - case ALPHA_R_LITUSE: - case ALPHA_R_GPDISP: - intern->r_size = rel->addend; - break; - - case ALPHA_R_OP_STORE: - intern->r_size = rel->addend & 0xff; - intern->r_offset = (rel->addend >> 8) & 0xff; - break; - - case ALPHA_R_OP_PUSH: - case ALPHA_R_OP_PSUB: - case ALPHA_R_OP_PRSHIFT: - intern->r_vaddr = rel->addend; - break; - - case ALPHA_R_IGNORE: - intern->r_vaddr = rel->address; - break; - - default: - break; - } -} - -/* The size of the stack for the relocation evaluator. */ -#define RELOC_STACKSIZE (10) - -/* Alpha ECOFF relocs have a built in expression evaluator as well as - other interdependencies. Rather than use a bunch of special - functions and global variables, we use a single routine to do all - the relocation for a section. I haven't yet worked out how the - assembler is going to handle this. */ - -static bfd_byte * -alpha_ecoff_get_relocated_section_contents (bfd *abfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - bfd *input_bfd = link_order->u.indirect.section->owner; - asection *input_section = link_order->u.indirect.section; - long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); - arelent **reloc_vector = NULL; - long reloc_count; - bfd *output_bfd = relocatable ? abfd : (bfd *) NULL; - bfd_vma gp; - bfd_size_type sz; - bfd_boolean gp_undefined; - bfd_vma stack[RELOC_STACKSIZE]; - int tos = 0; - - if (reloc_size < 0) - goto error_return; - reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); - if (reloc_vector == NULL && reloc_size != 0) - goto error_return; - - 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) - goto successful_return; - - /* Get the GP value for the output BFD. */ - gp_undefined = FALSE; - gp = _bfd_get_gp_value (abfd); - if (gp == 0) - { - if (relocatable) - { - asection *sec; - bfd_vma lo; - - /* Make up a value. */ - lo = (bfd_vma) -1; - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (sec->vma < lo - && (strcmp (sec->name, ".sbss") == 0 - || strcmp (sec->name, ".sdata") == 0 - || strcmp (sec->name, ".lit4") == 0 - || strcmp (sec->name, ".lit8") == 0 - || strcmp (sec->name, ".lita") == 0)) - lo = sec->vma; - } - gp = lo + 0x8000; - _bfd_set_gp_value (abfd, gp); - } - else - { - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (link_info->hash, "_gp", FALSE, FALSE, - TRUE); - if (h == (struct bfd_link_hash_entry *) NULL - || h->type != bfd_link_hash_defined) - gp_undefined = TRUE; - else - { - gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - _bfd_set_gp_value (abfd, gp); - } - } - } - - for (; *reloc_vector != (arelent *) NULL; reloc_vector++) - { - arelent *rel; - bfd_reloc_status_type r; - char *err; - - rel = *reloc_vector; - r = bfd_reloc_ok; - switch (rel->howto->type) - { - case ALPHA_R_IGNORE: - rel->address += input_section->output_offset; - break; - - case ALPHA_R_REFLONG: - case ALPHA_R_REFQUAD: - case ALPHA_R_BRADDR: - case ALPHA_R_HINT: - case ALPHA_R_SREL16: - case ALPHA_R_SREL32: - case ALPHA_R_SREL64: - if (relocatable - && ((*rel->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0) - { - rel->address += input_section->output_offset; - break; - } - r = bfd_perform_relocation (input_bfd, rel, data, input_section, - output_bfd, &err); - break; - - case ALPHA_R_GPREL32: - /* This relocation is used in a switch table. It is a 32 - bit offset from the current GP value. We must adjust it - by the different between the original GP value and the - current GP value. The original GP value is stored in the - addend. We adjust the addend and let - bfd_perform_relocation finish the job. */ - rel->addend -= gp; - r = bfd_perform_relocation (input_bfd, rel, data, input_section, - output_bfd, &err); - if (r == bfd_reloc_ok && gp_undefined) - { - r = bfd_reloc_dangerous; - err = (char *) _("GP relative relocation used when GP not defined"); - } - break; - - case ALPHA_R_LITERAL: - /* This is a reference to a literal value, generally - (always?) in the .lita section. This is a 16 bit GP - relative relocation. Sometimes the subsequent reloc is a - LITUSE reloc, which indicates how this reloc is used. - This sometimes permits rewriting the two instructions - referred to by the LITERAL and the LITUSE into different - instructions which do not refer to .lita. This can save - a memory reference, and permits removing a value from - .lita thus saving GP relative space. - - We do not these optimizations. To do them we would need - to arrange to link the .lita section first, so that by - the time we got here we would know the final values to - use. This would not be particularly difficult, but it is - not currently implemented. */ - - { - unsigned long insn; - - /* I believe that the LITERAL reloc will only apply to a - ldq or ldl instruction, so check my assumption. */ - insn = bfd_get_32 (input_bfd, data + rel->address); - BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29 - || ((insn >> 26) & 0x3f) == 0x28); - - rel->addend -= gp; - r = bfd_perform_relocation (input_bfd, rel, data, input_section, - output_bfd, &err); - if (r == bfd_reloc_ok && gp_undefined) - { - r = bfd_reloc_dangerous; - err = - (char *) _("GP relative relocation used when GP not defined"); - } - } - break; - - case ALPHA_R_LITUSE: - /* See ALPHA_R_LITERAL above for the uses of this reloc. It - does not cause anything to happen, itself. */ - rel->address += input_section->output_offset; - break; - - case ALPHA_R_GPDISP: - /* This marks the ldah of an ldah/lda pair which loads the - gp register with the difference of the gp value and the - current location. The second of the pair is r_size bytes - ahead; it used to be marked with an ALPHA_R_IGNORE reloc, - but that no longer happens in OSF/1 3.2. */ - { - unsigned long insn1, insn2; - bfd_vma addend; - - /* Get the two instructions. */ - insn1 = bfd_get_32 (input_bfd, data + rel->address); - insn2 = bfd_get_32 (input_bfd, data + rel->address + rel->addend); - - BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ - BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ - - /* Get the existing addend. We must account for the sign - extension done by lda and ldah. */ - addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff); - if (insn1 & 0x8000) - { - addend -= 0x80000000; - addend -= 0x80000000; - } - if (insn2 & 0x8000) - addend -= 0x10000; - - /* The existing addend includes the different between the - gp of the input BFD and the address in the input BFD. - Subtract this out. */ - addend -= (ecoff_data (input_bfd)->gp - - (input_section->vma + rel->address)); - - /* Now add in the final gp value, and subtract out the - final address. */ - addend += (gp - - (input_section->output_section->vma - + input_section->output_offset - + rel->address)); - - /* Change the instructions, accounting for the sign - extension, and write them out. */ - if (addend & 0x8000) - addend += 0x10000; - insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff); - insn2 = (insn2 & 0xffff0000) | (addend & 0xffff); - - bfd_put_32 (input_bfd, (bfd_vma) insn1, data + rel->address); - bfd_put_32 (input_bfd, (bfd_vma) insn2, - data + rel->address + rel->addend); - - rel->address += input_section->output_offset; - } - break; - - case ALPHA_R_OP_PUSH: - /* Push a value on the reloc evaluation stack. */ - { - asymbol *symbol; - bfd_vma relocation; - - if (relocatable) - { - rel->address += input_section->output_offset; - break; - } - - /* Figure out the relocation of this symbol. */ - symbol = *rel->sym_ptr_ptr; - - if (bfd_is_und_section (symbol->section)) - r = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += rel->addend; - - if (tos >= RELOC_STACKSIZE) - abort (); - - stack[tos++] = relocation; - } - break; - - case ALPHA_R_OP_STORE: - /* Store a value from the reloc stack into a bitfield. */ - { - bfd_vma val; - int offset, size; - - if (relocatable) - { - rel->address += input_section->output_offset; - break; - } - - if (tos == 0) - abort (); - - /* The offset and size for this reloc are encoded into the - addend field by alpha_adjust_reloc_in. */ - offset = (rel->addend >> 8) & 0xff; - size = rel->addend & 0xff; - - val = bfd_get_64 (abfd, data + rel->address); - val &=~ (((1 << size) - 1) << offset); - val |= (stack[--tos] & ((1 << size) - 1)) << offset; - bfd_put_64 (abfd, val, data + rel->address); - } - break; - - case ALPHA_R_OP_PSUB: - /* Subtract a value from the top of the stack. */ - { - asymbol *symbol; - bfd_vma relocation; - - if (relocatable) - { - rel->address += input_section->output_offset; - break; - } - - /* Figure out the relocation of this symbol. */ - symbol = *rel->sym_ptr_ptr; - - if (bfd_is_und_section (symbol->section)) - r = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += rel->addend; - - if (tos == 0) - abort (); - - stack[tos - 1] -= relocation; - } - break; - - case ALPHA_R_OP_PRSHIFT: - /* Shift the value on the top of the stack. */ - { - asymbol *symbol; - bfd_vma relocation; - - if (relocatable) - { - rel->address += input_section->output_offset; - break; - } - - /* Figure out the relocation of this symbol. */ - symbol = *rel->sym_ptr_ptr; - - if (bfd_is_und_section (symbol->section)) - r = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += rel->addend; - - if (tos == 0) - abort (); - - stack[tos - 1] >>= relocation; - } - break; - - case ALPHA_R_GPVALUE: - /* I really don't know if this does the right thing. */ - gp = rel->addend; - gp_undefined = FALSE; - break; - - default: - abort (); - } - - if (relocatable) - { - asection *os = input_section->output_section; - - /* A partial link, so keep the relocs. */ - os->orelocation[os->reloc_count] = rel; - os->reloc_count++; - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - case bfd_reloc_undefined: - (*link_info->callbacks->undefined_symbol) - (link_info, bfd_asymbol_name (*rel->sym_ptr_ptr), - input_bfd, input_section, rel->address, TRUE); - break; - case bfd_reloc_dangerous: - (*link_info->callbacks->reloc_dangerous) - (link_info, err, input_bfd, input_section, rel->address); - break; - case bfd_reloc_overflow: - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*rel->sym_ptr_ptr), - rel->howto->name, rel->addend, input_bfd, - input_section, rel->address); - break; - case bfd_reloc_outofrange: - default: - abort (); - break; - } - } - } - - if (tos != 0) - abort (); - - successful_return: - if (reloc_vector != NULL) - free (reloc_vector); - return data; - - error_return: - if (reloc_vector != NULL) - free (reloc_vector); - return NULL; -} - -/* Get the howto structure for a generic reloc type. */ - -static reloc_howto_type * -alpha_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - int alpha_type; - - switch (code) - { - case BFD_RELOC_32: - alpha_type = ALPHA_R_REFLONG; - break; - case BFD_RELOC_64: - case BFD_RELOC_CTOR: - alpha_type = ALPHA_R_REFQUAD; - break; - case BFD_RELOC_GPREL32: - alpha_type = ALPHA_R_GPREL32; - break; - case BFD_RELOC_ALPHA_LITERAL: - alpha_type = ALPHA_R_LITERAL; - break; - case BFD_RELOC_ALPHA_LITUSE: - alpha_type = ALPHA_R_LITUSE; - break; - case BFD_RELOC_ALPHA_GPDISP_HI16: - alpha_type = ALPHA_R_GPDISP; - break; - case BFD_RELOC_ALPHA_GPDISP_LO16: - alpha_type = ALPHA_R_IGNORE; - break; - case BFD_RELOC_23_PCREL_S2: - alpha_type = ALPHA_R_BRADDR; - break; - case BFD_RELOC_ALPHA_HINT: - alpha_type = ALPHA_R_HINT; - break; - case BFD_RELOC_16_PCREL: - alpha_type = ALPHA_R_SREL16; - break; - case BFD_RELOC_32_PCREL: - alpha_type = ALPHA_R_SREL32; - break; - case BFD_RELOC_64_PCREL: - alpha_type = ALPHA_R_SREL64; - break; - default: - return (reloc_howto_type *) NULL; - } - - return &alpha_howto_table[alpha_type]; -} - -static reloc_howto_type * -alpha_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (alpha_howto_table) / sizeof (alpha_howto_table[0]); - i++) - if (alpha_howto_table[i].name != NULL - && strcasecmp (alpha_howto_table[i].name, r_name) == 0) - return &alpha_howto_table[i]; - - return NULL; -} - -/* A helper routine for alpha_relocate_section which converts an - external reloc when generating relocatable output. Returns the - relocation amount. */ - -static bfd_vma -alpha_convert_external_reloc (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - struct external_reloc *ext_rel, - struct ecoff_link_hash_entry *h) -{ - unsigned long r_symndx; - bfd_vma relocation; - - BFD_ASSERT (bfd_link_relocatable (info)); - - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *hsec; - const char *name; - - /* This symbol is defined in the output. Convert the reloc from - being against the symbol to being against the section. */ - - /* Clear the r_extern bit. */ - ext_rel->r_bits[1] &=~ RELOC_BITS1_EXTERN_LITTLE; - - /* Compute a new r_symndx value. */ - hsec = h->root.u.def.section; - name = bfd_get_section_name (output_bfd, hsec->output_section); - - r_symndx = (unsigned long) -1; - switch (name[1]) - { - case 'A': - if (strcmp (name, "*ABS*") == 0) - r_symndx = RELOC_SECTION_ABS; - break; - case 'b': - if (strcmp (name, ".bss") == 0) - r_symndx = RELOC_SECTION_BSS; - break; - case 'd': - if (strcmp (name, ".data") == 0) - r_symndx = RELOC_SECTION_DATA; - break; - case 'f': - if (strcmp (name, ".fini") == 0) - r_symndx = RELOC_SECTION_FINI; - break; - case 'i': - if (strcmp (name, ".init") == 0) - r_symndx = RELOC_SECTION_INIT; - break; - case 'l': - if (strcmp (name, ".lita") == 0) - r_symndx = RELOC_SECTION_LITA; - else if (strcmp (name, ".lit8") == 0) - r_symndx = RELOC_SECTION_LIT8; - else if (strcmp (name, ".lit4") == 0) - r_symndx = RELOC_SECTION_LIT4; - break; - case 'p': - if (strcmp (name, ".pdata") == 0) - r_symndx = RELOC_SECTION_PDATA; - break; - case 'r': - if (strcmp (name, ".rdata") == 0) - r_symndx = RELOC_SECTION_RDATA; - else if (strcmp (name, ".rconst") == 0) - r_symndx = RELOC_SECTION_RCONST; - break; - case 's': - if (strcmp (name, ".sdata") == 0) - r_symndx = RELOC_SECTION_SDATA; - else if (strcmp (name, ".sbss") == 0) - r_symndx = RELOC_SECTION_SBSS; - break; - case 't': - if (strcmp (name, ".text") == 0) - r_symndx = RELOC_SECTION_TEXT; - break; - case 'x': - if (strcmp (name, ".xdata") == 0) - r_symndx = RELOC_SECTION_XDATA; - break; - } - - if (r_symndx == (unsigned long) -1) - abort (); - - /* Add the section VMA and the symbol value. */ - relocation = (h->root.u.def.value - + hsec->output_section->vma - + hsec->output_offset); - } - else - { - /* Change the symndx value to the right one for - the output BFD. */ - r_symndx = h->indx; - if (r_symndx == (unsigned long) -1) - { - /* Caller must give an error. */ - r_symndx = 0; - } - relocation = 0; - } - - /* Write out the new r_symndx value. */ - H_PUT_32 (input_bfd, r_symndx, ext_rel->r_symndx); - - return relocation; -} - -/* Relocate a section while linking an Alpha ECOFF file. This is - quite similar to get_relocated_section_contents. Perhaps they - could be combined somehow. */ - -static bfd_boolean -alpha_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - void * external_relocs) -{ - asection **symndx_to_section, *lita_sec; - struct ecoff_link_hash_entry **sym_hashes; - bfd_vma gp; - bfd_boolean gp_undefined; - bfd_vma stack[RELOC_STACKSIZE]; - int tos = 0; - struct external_reloc *ext_rel; - struct external_reloc *ext_rel_end; - bfd_size_type amt; - - /* We keep a table mapping the symndx found in an internal reloc to - the appropriate section. This is faster than looking up the - section by name each time. */ - symndx_to_section = ecoff_data (input_bfd)->symndx_to_section; - if (symndx_to_section == (asection **) NULL) - { - amt = NUM_RELOC_SECTIONS * sizeof (asection *); - symndx_to_section = (asection **) bfd_alloc (input_bfd, amt); - if (!symndx_to_section) - return FALSE; - - symndx_to_section[RELOC_SECTION_NONE] = NULL; - symndx_to_section[RELOC_SECTION_TEXT] = - bfd_get_section_by_name (input_bfd, ".text"); - symndx_to_section[RELOC_SECTION_RDATA] = - bfd_get_section_by_name (input_bfd, ".rdata"); - symndx_to_section[RELOC_SECTION_DATA] = - bfd_get_section_by_name (input_bfd, ".data"); - symndx_to_section[RELOC_SECTION_SDATA] = - bfd_get_section_by_name (input_bfd, ".sdata"); - symndx_to_section[RELOC_SECTION_SBSS] = - bfd_get_section_by_name (input_bfd, ".sbss"); - symndx_to_section[RELOC_SECTION_BSS] = - bfd_get_section_by_name (input_bfd, ".bss"); - symndx_to_section[RELOC_SECTION_INIT] = - bfd_get_section_by_name (input_bfd, ".init"); - symndx_to_section[RELOC_SECTION_LIT8] = - bfd_get_section_by_name (input_bfd, ".lit8"); - symndx_to_section[RELOC_SECTION_LIT4] = - bfd_get_section_by_name (input_bfd, ".lit4"); - symndx_to_section[RELOC_SECTION_XDATA] = - bfd_get_section_by_name (input_bfd, ".xdata"); - symndx_to_section[RELOC_SECTION_PDATA] = - bfd_get_section_by_name (input_bfd, ".pdata"); - symndx_to_section[RELOC_SECTION_FINI] = - bfd_get_section_by_name (input_bfd, ".fini"); - symndx_to_section[RELOC_SECTION_LITA] = - bfd_get_section_by_name (input_bfd, ".lita"); - symndx_to_section[RELOC_SECTION_ABS] = bfd_abs_section_ptr; - symndx_to_section[RELOC_SECTION_RCONST] = - bfd_get_section_by_name (input_bfd, ".rconst"); - - ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; - } - - sym_hashes = ecoff_data (input_bfd)->sym_hashes; - - /* On the Alpha, the .lita section must be addressable by the global - pointer. To support large programs, we need to allow multiple - global pointers. This works as long as each input .lita section - is <64KB big. This implies that when producing relocatable - output, the .lita section is limited to 64KB. . */ - - lita_sec = symndx_to_section[RELOC_SECTION_LITA]; - gp = _bfd_get_gp_value (output_bfd); - if (! bfd_link_relocatable (info) && lita_sec != NULL) - { - struct ecoff_section_tdata *lita_sec_data; - - /* Make sure we have a section data structure to which we can - hang on to the gp value we pick for the section. */ - lita_sec_data = ecoff_section_data (input_bfd, lita_sec); - if (lita_sec_data == NULL) - { - amt = sizeof (struct ecoff_section_tdata); - lita_sec_data = ((struct ecoff_section_tdata *) - bfd_zalloc (input_bfd, amt)); - lita_sec->used_by_bfd = lita_sec_data; - } - - if (lita_sec_data->gp != 0) - { - /* If we already assigned a gp to this section, we better - stick with that value. */ - gp = lita_sec_data->gp; - } - else - { - bfd_vma lita_vma; - bfd_size_type lita_size; - - lita_vma = lita_sec->output_offset + lita_sec->output_section->vma; - lita_size = lita_sec->size; - - if (gp == 0 - || lita_vma < gp - 0x8000 - || lita_vma + lita_size >= gp + 0x8000) - { - /* Either gp hasn't been set at all or the current gp - cannot address this .lita section. In both cases we - reset the gp to point into the "middle" of the - current input .lita section. */ - if (gp && !ecoff_data (output_bfd)->issued_multiple_gp_warning) - { - (*info->callbacks->warning) (info, - _("using multiple gp values"), - (char *) NULL, output_bfd, - (asection *) NULL, (bfd_vma) 0); - ecoff_data (output_bfd)->issued_multiple_gp_warning = TRUE; - } - if (lita_vma < gp - 0x8000) - gp = lita_vma + lita_size - 0x8000; - else - gp = lita_vma + 0x8000; - - } - - lita_sec_data->gp = gp; - } - - _bfd_set_gp_value (output_bfd, gp); - } - - gp_undefined = (gp == 0); - - BFD_ASSERT (bfd_header_little_endian (output_bfd)); - BFD_ASSERT (bfd_header_little_endian (input_bfd)); - - ext_rel = (struct external_reloc *) external_relocs; - ext_rel_end = ext_rel + input_section->reloc_count; - for (; ext_rel < ext_rel_end; ext_rel++) - { - bfd_vma r_vaddr; - unsigned long r_symndx; - int r_type; - int r_extern; - int r_offset; - int r_size; - bfd_boolean relocatep; - bfd_boolean adjust_addrp; - bfd_boolean gp_usedp; - bfd_vma addend; - - r_vaddr = H_GET_64 (input_bfd, ext_rel->r_vaddr); - r_symndx = H_GET_32 (input_bfd, ext_rel->r_symndx); - - r_type = ((ext_rel->r_bits[0] & RELOC_BITS0_TYPE_LITTLE) - >> RELOC_BITS0_TYPE_SH_LITTLE); - r_extern = (ext_rel->r_bits[1] & RELOC_BITS1_EXTERN_LITTLE) != 0; - r_offset = ((ext_rel->r_bits[1] & RELOC_BITS1_OFFSET_LITTLE) - >> RELOC_BITS1_OFFSET_SH_LITTLE); - /* Ignored the reserved bits. */ - r_size = ((ext_rel->r_bits[3] & RELOC_BITS3_SIZE_LITTLE) - >> RELOC_BITS3_SIZE_SH_LITTLE); - - relocatep = FALSE; - adjust_addrp = TRUE; - gp_usedp = FALSE; - addend = 0; - - switch (r_type) - { - case ALPHA_R_GPRELHIGH: - _bfd_error_handler - (_("%B: unsupported relocation: ALPHA_R_GPRELHIGH"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - continue; - - case ALPHA_R_GPRELLOW: - _bfd_error_handler - (_("%B: unsupported relocation: ALPHA_R_GPRELLOW"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - continue; - - default: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - continue; - - case ALPHA_R_IGNORE: - /* This reloc appears after a GPDISP reloc. On earlier - versions of OSF/1, It marked the position of the second - instruction to be altered by the GPDISP reloc, but it is - not otherwise used for anything. For some reason, the - address of the relocation does not appear to include the - section VMA, unlike the other relocation types. */ - if (bfd_link_relocatable (info)) - H_PUT_64 (input_bfd, input_section->output_offset + r_vaddr, - ext_rel->r_vaddr); - adjust_addrp = FALSE; - break; - - case ALPHA_R_REFLONG: - case ALPHA_R_REFQUAD: - case ALPHA_R_HINT: - relocatep = TRUE; - break; - - case ALPHA_R_BRADDR: - case ALPHA_R_SREL16: - case ALPHA_R_SREL32: - case ALPHA_R_SREL64: - if (r_extern) - addend += - (r_vaddr + 4); - relocatep = TRUE; - break; - - case ALPHA_R_GPREL32: - /* This relocation is used in a switch table. It is a 32 - bit offset from the current GP value. We must adjust it - by the different between the original GP value and the - current GP value. */ - relocatep = TRUE; - addend = ecoff_data (input_bfd)->gp - gp; - gp_usedp = TRUE; - break; - - case ALPHA_R_LITERAL: - /* This is a reference to a literal value, generally - (always?) in the .lita section. This is a 16 bit GP - relative relocation. Sometimes the subsequent reloc is a - LITUSE reloc, which indicates how this reloc is used. - This sometimes permits rewriting the two instructions - referred to by the LITERAL and the LITUSE into different - instructions which do not refer to .lita. This can save - a memory reference, and permits removing a value from - .lita thus saving GP relative space. - - We do not these optimizations. To do them we would need - to arrange to link the .lita section first, so that by - the time we got here we would know the final values to - use. This would not be particularly difficult, but it is - not currently implemented. */ - - /* I believe that the LITERAL reloc will only apply to a ldq - or ldl instruction, so check my assumption. */ - { - unsigned long insn; - - insn = bfd_get_32 (input_bfd, - contents + r_vaddr - input_section->vma); - BFD_ASSERT (((insn >> 26) & 0x3f) == 0x29 - || ((insn >> 26) & 0x3f) == 0x28); - } - - relocatep = TRUE; - addend = ecoff_data (input_bfd)->gp - gp; - gp_usedp = TRUE; - break; - - case ALPHA_R_LITUSE: - /* See ALPHA_R_LITERAL above for the uses of this reloc. It - does not cause anything to happen, itself. */ - break; - - case ALPHA_R_GPDISP: - /* This marks the ldah of an ldah/lda pair which loads the - gp register with the difference of the gp value and the - current location. The second of the pair is r_symndx - bytes ahead. It used to be marked with an ALPHA_R_IGNORE - reloc, but OSF/1 3.2 no longer does that. */ - { - unsigned long insn1, insn2; - - /* Get the two instructions. */ - insn1 = bfd_get_32 (input_bfd, - contents + r_vaddr - input_section->vma); - insn2 = bfd_get_32 (input_bfd, - (contents - + r_vaddr - - input_section->vma - + r_symndx)); - - BFD_ASSERT (((insn1 >> 26) & 0x3f) == 0x09); /* ldah */ - BFD_ASSERT (((insn2 >> 26) & 0x3f) == 0x08); /* lda */ - - /* Get the existing addend. We must account for the sign - extension done by lda and ldah. */ - addend = ((insn1 & 0xffff) << 16) + (insn2 & 0xffff); - if (insn1 & 0x8000) - { - /* This is addend -= 0x100000000 without causing an - integer overflow on a 32 bit host. */ - addend -= 0x80000000; - addend -= 0x80000000; - } - if (insn2 & 0x8000) - addend -= 0x10000; - - /* The existing addend includes the difference between the - gp of the input BFD and the address in the input BFD. - We want to change this to the difference between the - final GP and the final address. */ - addend += (gp - - ecoff_data (input_bfd)->gp - + input_section->vma - - (input_section->output_section->vma - + input_section->output_offset)); - - /* Change the instructions, accounting for the sign - extension, and write them out. */ - if (addend & 0x8000) - addend += 0x10000; - insn1 = (insn1 & 0xffff0000) | ((addend >> 16) & 0xffff); - insn2 = (insn2 & 0xffff0000) | (addend & 0xffff); - - bfd_put_32 (input_bfd, (bfd_vma) insn1, - contents + r_vaddr - input_section->vma); - bfd_put_32 (input_bfd, (bfd_vma) insn2, - contents + r_vaddr - input_section->vma + r_symndx); - - gp_usedp = TRUE; - } - break; - - case ALPHA_R_OP_PUSH: - case ALPHA_R_OP_PSUB: - case ALPHA_R_OP_PRSHIFT: - /* Manipulate values on the reloc evaluation stack. The - r_vaddr field is not an address in input_section, it is - the current value (including any addend) of the object - being used. */ - if (! r_extern) - { - asection *s; - - s = symndx_to_section[r_symndx]; - if (s == (asection *) NULL) - abort (); - addend = s->output_section->vma + s->output_offset - s->vma; - } - else - { - struct ecoff_link_hash_entry *h; - - h = sym_hashes[r_symndx]; - if (h == (struct ecoff_link_hash_entry *) NULL) - abort (); - - if (! bfd_link_relocatable (info)) - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - else - { - /* Note that we pass the address as 0, since we - do not have a meaningful number for the - location within the section that is being - relocated. */ - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, (bfd_vma) 0, TRUE); - addend = 0; - } - } - else - { - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak - && h->indx == -1) - { - /* This symbol is not being written out. Pass - the address as 0, as with undefined_symbol, - above. */ - (*info->callbacks->unattached_reloc) - (info, h->root.root.string, - input_bfd, input_section, (bfd_vma) 0); - } - - addend = alpha_convert_external_reloc (output_bfd, info, - input_bfd, - ext_rel, h); - } - } - - addend += r_vaddr; - - if (bfd_link_relocatable (info)) - { - /* Adjust r_vaddr by the addend. */ - H_PUT_64 (input_bfd, addend, ext_rel->r_vaddr); - } - else - { - switch (r_type) - { - case ALPHA_R_OP_PUSH: - if (tos >= RELOC_STACKSIZE) - abort (); - stack[tos++] = addend; - break; - - case ALPHA_R_OP_PSUB: - if (tos == 0) - abort (); - stack[tos - 1] -= addend; - break; - - case ALPHA_R_OP_PRSHIFT: - if (tos == 0) - abort (); - stack[tos - 1] >>= addend; - break; - } - } - - adjust_addrp = FALSE; - break; - - case ALPHA_R_OP_STORE: - /* Store a value from the reloc stack into a bitfield. If - we are generating relocatable output, all we do is - adjust the address of the reloc. */ - if (! bfd_link_relocatable (info)) - { - bfd_vma mask; - bfd_vma val; - - if (tos == 0) - abort (); - - /* Get the relocation mask. The separate steps and the - casts to bfd_vma are attempts to avoid a bug in the - Alpha OSF 1.3 C compiler. See reloc.c for more - details. */ - mask = 1; - mask <<= (bfd_vma) r_size; - mask -= 1; - - /* FIXME: I don't know what kind of overflow checking, - if any, should be done here. */ - val = bfd_get_64 (input_bfd, - contents + r_vaddr - input_section->vma); - val &=~ mask << (bfd_vma) r_offset; - val |= (stack[--tos] & mask) << (bfd_vma) r_offset; - bfd_put_64 (input_bfd, val, - contents + r_vaddr - input_section->vma); - } - break; - - case ALPHA_R_GPVALUE: - /* I really don't know if this does the right thing. */ - gp = ecoff_data (input_bfd)->gp + r_symndx; - gp_undefined = FALSE; - break; - } - - if (relocatep) - { - reloc_howto_type *howto; - struct ecoff_link_hash_entry *h = NULL; - asection *s = NULL; - bfd_vma relocation; - bfd_reloc_status_type r; - - /* Perform a relocation. */ - - howto = &alpha_howto_table[r_type]; - - if (r_extern) - { - h = sym_hashes[r_symndx]; - /* If h is NULL, that means that there is a reloc - against an external symbol which we thought was just - a debugging symbol. This should not happen. */ - if (h == (struct ecoff_link_hash_entry *) NULL) - abort (); - } - else - { - if (r_symndx >= NUM_RELOC_SECTIONS) - s = NULL; - else - s = symndx_to_section[r_symndx]; - - if (s == (asection *) NULL) - abort (); - } - - if (bfd_link_relocatable (info)) - { - /* We are generating relocatable output, and must - convert the existing reloc. */ - if (r_extern) - { - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak - && h->indx == -1) - { - /* This symbol is not being written out. */ - (*info->callbacks->unattached_reloc) - (info, h->root.root.string, input_bfd, - input_section, r_vaddr - input_section->vma); - } - - relocation = alpha_convert_external_reloc (output_bfd, - info, - input_bfd, - ext_rel, - h); - } - else - { - /* This is a relocation against a section. Adjust - the value by the amount the section moved. */ - relocation = (s->output_section->vma - + s->output_offset - - s->vma); - } - - /* If this is PC relative, the existing object file - appears to already have the reloc worked out. We - must subtract out the old value and add in the new - one. */ - if (howto->pc_relative) - relocation -= (input_section->output_section->vma - + input_section->output_offset - - input_section->vma); - - /* Put in any addend. */ - relocation += addend; - - /* Adjust the contents. */ - r = _bfd_relocate_contents (howto, input_bfd, relocation, - (contents - + r_vaddr - - input_section->vma)); - } - else - { - /* We are producing a final executable. */ - if (r_extern) - { - /* This is a reloc against a symbol. */ - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *hsec; - - hsec = h->root.u.def.section; - relocation = (h->root.u.def.value - + hsec->output_section->vma - + hsec->output_offset); - } - else - { - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - r_vaddr - input_section->vma, TRUE); - relocation = 0; - } - } - else - { - /* This is a reloc against a section. */ - relocation = (s->output_section->vma - + s->output_offset - - s->vma); - - /* Adjust a PC relative relocation by removing the - reference to the original source section. */ - if (howto->pc_relative) - relocation += input_section->vma; - } - - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - r_vaddr - input_section->vma, - relocation, - addend); - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - { - const char *name; - - if (r_extern) - name = sym_hashes[r_symndx]->root.root.string; - else - name = bfd_section_name (input_bfd, - symndx_to_section[r_symndx]); - (*info->callbacks->reloc_overflow) - (info, NULL, name, alpha_howto_table[r_type].name, - (bfd_vma) 0, input_bfd, input_section, - r_vaddr - input_section->vma); - } - break; - } - } - } - - if (bfd_link_relocatable (info) && adjust_addrp) - { - /* Change the address of the relocation. */ - H_PUT_64 (input_bfd, - (input_section->output_section->vma - + input_section->output_offset - - input_section->vma - + r_vaddr), - ext_rel->r_vaddr); - } - - if (gp_usedp && gp_undefined) - { - (*info->callbacks->reloc_dangerous) - (info, _("GP relative relocation used when GP not defined"), - input_bfd, input_section, r_vaddr - input_section->vma); - /* Only give the error once per link. */ - gp = 4; - _bfd_set_gp_value (output_bfd, gp); - gp_undefined = FALSE; - } - } - - if (tos != 0) - abort (); - - return TRUE; -} - -/* Do final adjustments to the filehdr and the aouthdr. This routine - sets the dynamic bits in the file header. */ - -static bfd_boolean -alpha_adjust_headers (bfd *abfd, - struct internal_filehdr *fhdr, - struct internal_aouthdr *ahdr ATTRIBUTE_UNUSED) -{ - if ((abfd->flags & (DYNAMIC | EXEC_P)) == (DYNAMIC | EXEC_P)) - fhdr->f_flags |= F_ALPHA_CALL_SHARED; - else if ((abfd->flags & DYNAMIC) != 0) - fhdr->f_flags |= F_ALPHA_SHARABLE; - return TRUE; -} - -/* Archive handling. In OSF/1 (or Digital Unix) v3.2, Digital - introduced archive packing, in which the elements in an archive are - optionally compressed using a simple dictionary scheme. We know - how to read such archives, but we don't write them. */ - -#define alpha_ecoff_slurp_armap _bfd_ecoff_slurp_armap -#define alpha_ecoff_slurp_extended_name_table \ - _bfd_ecoff_slurp_extended_name_table -#define alpha_ecoff_construct_extended_name_table \ - _bfd_ecoff_construct_extended_name_table -#define alpha_ecoff_truncate_arname _bfd_ecoff_truncate_arname -#define alpha_ecoff_write_armap _bfd_ecoff_write_armap -#define alpha_ecoff_write_ar_hdr _bfd_generic_write_ar_hdr -#define alpha_ecoff_generic_stat_arch_elt _bfd_ecoff_generic_stat_arch_elt -#define alpha_ecoff_update_armap_timestamp _bfd_ecoff_update_armap_timestamp - -/* A compressed file uses this instead of ARFMAG. */ - -#define ARFZMAG "Z\012" - -/* Read an archive header. This is like the standard routine, but it - also accepts ARFZMAG. */ - -static void * -alpha_ecoff_read_ar_hdr (bfd *abfd) -{ - struct areltdata *ret; - struct ar_hdr *h; - - ret = (struct areltdata *) _bfd_generic_read_ar_hdr_mag (abfd, ARFZMAG); - if (ret == NULL) - return NULL; - - h = (struct ar_hdr *) ret->arch_header; - if (strncmp (h->ar_fmag, ARFZMAG, 2) == 0) - { - bfd_byte ab[8]; - - /* This is a compressed file. We must set the size correctly. - The size is the eight bytes after the dummy file header. */ - if (bfd_seek (abfd, (file_ptr) FILHSZ, SEEK_CUR) != 0 - || bfd_bread (ab, (bfd_size_type) 8, abfd) != 8 - || bfd_seek (abfd, (file_ptr) (- (FILHSZ + 8)), SEEK_CUR) != 0) - return NULL; - - ret->parsed_size = H_GET_64 (abfd, ab); - } - - return ret; -} - -/* Get an archive element at a specified file position. This is where - we uncompress the archive element if necessary. */ - -static bfd * -alpha_ecoff_get_elt_at_filepos (bfd *archive, file_ptr filepos) -{ - bfd *nbfd = NULL; - struct areltdata *tdata; - struct ar_hdr *hdr; - bfd_byte ab[8]; - bfd_size_type size; - bfd_byte *buf, *p; - struct bfd_in_memory *bim; - - buf = NULL; - nbfd = _bfd_get_elt_at_filepos (archive, filepos); - if (nbfd == NULL) - goto error_return; - - if ((nbfd->flags & BFD_IN_MEMORY) != 0) - { - /* We have already expanded this BFD. */ - return nbfd; - } - - tdata = (struct areltdata *) nbfd->arelt_data; - hdr = (struct ar_hdr *) tdata->arch_header; - if (strncmp (hdr->ar_fmag, ARFZMAG, 2) != 0) - return nbfd; - - /* We must uncompress this element. We do this by copying it into a - memory buffer, and making bfd_bread and bfd_seek use that buffer. - This can use a lot of memory, but it's simpler than getting a - temporary file, making that work with the file descriptor caching - code, and making sure that it is deleted at all appropriate - times. It can be changed if it ever becomes important. */ - - /* The compressed file starts with a dummy ECOFF file header. */ - if (bfd_seek (nbfd, (file_ptr) FILHSZ, SEEK_SET) != 0) - goto error_return; - - /* The next eight bytes are the real file size. */ - if (bfd_bread (ab, (bfd_size_type) 8, nbfd) != 8) - goto error_return; - size = H_GET_64 (nbfd, ab); - - if (size != 0) - { - bfd_size_type left; - bfd_byte dict[4096]; - unsigned int h; - bfd_byte b; - - buf = (bfd_byte *) bfd_malloc (size); - if (buf == NULL) - goto error_return; - p = buf; - - left = size; - - /* I don't know what the next eight bytes are for. */ - if (bfd_bread (ab, (bfd_size_type) 8, nbfd) != 8) - goto error_return; - - /* This is the uncompression algorithm. It's a simple - dictionary based scheme in which each character is predicted - by a hash of the previous three characters. A control byte - indicates whether the character is predicted or whether it - appears in the input stream; each control byte manages the - next eight bytes in the output stream. */ - memset (dict, 0, sizeof dict); - h = 0; - while (bfd_bread (&b, (bfd_size_type) 1, nbfd) == 1) - { - unsigned int i; - - for (i = 0; i < 8; i++, b >>= 1) - { - bfd_byte n; - - if ((b & 1) == 0) - n = dict[h]; - else - { - if (! bfd_bread (&n, (bfd_size_type) 1, nbfd)) - goto error_return; - dict[h] = n; - } - - *p++ = n; - - --left; - if (left == 0) - break; - - h <<= 4; - h ^= n; - h &= sizeof dict - 1; - } - - if (left == 0) - break; - } - } - - /* Now the uncompressed file contents are in buf. */ - bim = ((struct bfd_in_memory *) - bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory))); - if (bim == NULL) - goto error_return; - bim->size = size; - bim->buffer = buf; - - nbfd->mtime_set = TRUE; - nbfd->mtime = strtol (hdr->ar_date, (char **) NULL, 10); - - nbfd->flags |= BFD_IN_MEMORY; - nbfd->iostream = bim; - nbfd->iovec = &_bfd_memory_iovec; - nbfd->origin = 0; - BFD_ASSERT (! nbfd->cacheable); - - return nbfd; - - error_return: - if (buf != NULL) - free (buf); - if (nbfd != NULL) - bfd_close (nbfd); - return NULL; -} - -/* Open the next archived file. */ - -static bfd * -alpha_ecoff_openr_next_archived_file (bfd *archive, bfd *last_file) -{ - ufile_ptr filestart; - - if (last_file == NULL) - filestart = bfd_ardata (archive)->first_file_filepos; - else - { - struct areltdata *t; - struct ar_hdr *h; - bfd_size_type size; - - /* We can't use arelt_size here, because that uses parsed_size, - which is the uncompressed size. We need the compressed size. */ - t = (struct areltdata *) last_file->arelt_data; - h = (struct ar_hdr *) t->arch_header; - size = strtol (h->ar_size, (char **) NULL, 10); - - /* Pad to an even boundary... - Note that last_file->origin can be odd in the case of - BSD-4.4-style element with a long odd size. */ - filestart = last_file->proxy_origin + size; - filestart += filestart % 2; - if (filestart < last_file->proxy_origin) - { - /* Prevent looping. See PR19256. */ - bfd_set_error (bfd_error_malformed_archive); - return NULL; - } - } - - return alpha_ecoff_get_elt_at_filepos (archive, filestart); -} - -/* Open the archive file given an index into the armap. */ - -static bfd * -alpha_ecoff_get_elt_at_index (bfd *abfd, symindex sym_index) -{ - carsym *entry; - - entry = bfd_ardata (abfd)->symdefs + sym_index; - return alpha_ecoff_get_elt_at_filepos (abfd, entry->file_offset); -} - -/* This is the ECOFF backend structure. The backend field of the - target vector points to this. */ - -static const struct ecoff_backend_data alpha_ecoff_backend_data = -{ - /* COFF backend structure. */ - { - (void (*) (bfd *,void *,int,int,int,int,void *)) bfd_void, /* aux_in */ - (void (*) (bfd *,void *,void *)) bfd_void, /* sym_in */ - (void (*) (bfd *,void *,void *)) bfd_void, /* lineno_in */ - (unsigned (*) (bfd *,void *,int,int,int,int,void *)) bfd_void,/*aux_out*/ - (unsigned (*) (bfd *,void *,void *)) bfd_void, /* sym_out */ - (unsigned (*) (bfd *,void *,void *)) bfd_void, /* lineno_out */ - (unsigned (*) (bfd *,void *,void *)) bfd_void, /* reloc_out */ - alpha_ecoff_swap_filehdr_out, alpha_ecoff_swap_aouthdr_out, - alpha_ecoff_swap_scnhdr_out, - FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE, - ECOFF_NO_LONG_SECTION_NAMES, 4, FALSE, 2, 32768, - alpha_ecoff_swap_filehdr_in, alpha_ecoff_swap_aouthdr_in, - alpha_ecoff_swap_scnhdr_in, NULL, - alpha_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, - alpha_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, - _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL - }, - /* Supported architecture. */ - bfd_arch_alpha, - /* Initial portion of armap string. */ - "________64", - /* The page boundary used to align sections in a demand-paged - executable file. E.g., 0x1000. */ - 0x2000, - /* 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. */ - TRUE, - /* Bitsize of constructor entries. */ - 64, - /* Reloc to use for constructor entries. */ - &alpha_howto_table[ALPHA_R_REFQUAD], - { - /* Symbol table magic number. */ - magicSym2, - /* Alignment of debugging information. E.g., 4. */ - 8, - /* Sizes of external symbolic information. */ - sizeof (struct hdr_ext), - sizeof (struct dnr_ext), - sizeof (struct pdr_ext), - sizeof (struct sym_ext), - sizeof (struct opt_ext), - sizeof (struct fdr_ext), - sizeof (struct rfd_ext), - sizeof (struct ext_ext), - /* Functions to swap in external symbolic data. */ - ecoff_swap_hdr_in, - ecoff_swap_dnr_in, - ecoff_swap_pdr_in, - ecoff_swap_sym_in, - ecoff_swap_opt_in, - ecoff_swap_fdr_in, - ecoff_swap_rfd_in, - ecoff_swap_ext_in, - _bfd_ecoff_swap_tir_in, - _bfd_ecoff_swap_rndx_in, - /* Functions to swap out external symbolic data. */ - ecoff_swap_hdr_out, - ecoff_swap_dnr_out, - ecoff_swap_pdr_out, - ecoff_swap_sym_out, - ecoff_swap_opt_out, - ecoff_swap_fdr_out, - ecoff_swap_rfd_out, - ecoff_swap_ext_out, - _bfd_ecoff_swap_tir_out, - _bfd_ecoff_swap_rndx_out, - /* Function to read in symbolic data. */ - _bfd_ecoff_slurp_symbolic_info - }, - /* External reloc size. */ - RELSZ, - /* Reloc swapping functions. */ - alpha_ecoff_swap_reloc_in, - alpha_ecoff_swap_reloc_out, - /* Backend reloc tweaking. */ - alpha_adjust_reloc_in, - alpha_adjust_reloc_out, - /* Relocate section contents while linking. */ - alpha_relocate_section, - /* Do final adjustments to filehdr and aouthdr. */ - alpha_adjust_headers, - /* Read an element from an archive at a given file position. */ - alpha_ecoff_get_elt_at_filepos -}; - -/* Looking up a reloc type is Alpha specific. */ -#define _bfd_ecoff_bfd_reloc_type_lookup alpha_bfd_reloc_type_lookup -#define _bfd_ecoff_bfd_reloc_name_lookup \ - alpha_bfd_reloc_name_lookup - -/* So is getting relocated section contents. */ -#define _bfd_ecoff_bfd_get_relocated_section_contents \ - alpha_ecoff_get_relocated_section_contents - -/* Handling file windows is generic. */ -#define _bfd_ecoff_get_section_contents_in_window \ - _bfd_generic_get_section_contents_in_window - -/* Input section flag lookup is generic. */ -#define _bfd_ecoff_bfd_lookup_section_flags bfd_generic_lookup_section_flags - -/* Relaxing sections is generic. */ -#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section -#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections -#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections -#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section -#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group -#define _bfd_ecoff_section_already_linked \ - _bfd_coff_section_already_linked -#define _bfd_ecoff_bfd_define_common_symbol bfd_generic_define_common_symbol -#define _bfd_ecoff_bfd_define_start_stop bfd_generic_define_start_stop -#define _bfd_ecoff_bfd_link_check_relocs _bfd_generic_link_check_relocs - -/* Installing internal relocations in a section is also generic. */ -#define _bfd_ecoff_set_reloc _bfd_generic_set_reloc - -const bfd_target alpha_ecoff_le_vec = -{ - "ecoff-littlealpha", /* name */ - bfd_target_ecoff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - 0, /* leading underscore */ - ' ', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, alpha_ecoff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), - BFD_JUMP_TABLE_COPY (_bfd_ecoff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (alpha_ecoff), - BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), - BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), - BFD_JUMP_TABLE_WRITE (_bfd_ecoff), - BFD_JUMP_TABLE_LINK (_bfd_ecoff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - & alpha_ecoff_backend_data -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-apollo.c b/sdcc/support/sdbinutils/bfd/coff-apollo.c deleted file mode 100644 index 36b88b336..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-apollo.c +++ /dev/null @@ -1,120 +0,0 @@ -/* BFD back-end for Apollo 68000 COFF binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - By Troy Rollo (troy@cbme.unsw.edu.au) - Based on m68k standard COFF version Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/apollo.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) - -#ifdef ONLY_DECLARE_RELOCS -extern reloc_howto_type apollocoff_howto_table[]; -#else -reloc_howto_type apollocoff_howto_table[] = - { - HOWTO (R_RELBYTE, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (R_RELWORD, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (R_RELLONG, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "32", TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO (R_PCRBYTE, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "DISP8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (R_PCRWORD, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "DISP16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (R_PCRLONG, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "DISP32", TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO (R_RELLONG_NEG, 0, -2, 32, FALSE, 0, complain_overflow_bitfield, 0, "-32", TRUE, 0xffffffff,0xffffffff, FALSE), - }; -#endif /* not ONLY_DECLARE_RELOCS */ - -#ifndef BADMAG -#define BADMAG(x) M68KBADMAG(x) -#endif -#define APOLLO_M68 1 /* Customize coffcode.h */ - -/* Turn a howto into a reloc number. */ - -extern void apollo_rtype2howto (arelent *, int); -extern int apollo_howto2rtype (reloc_howto_type *); -#ifndef ONLY_DECLARE_RELOCS - -void -apollo_rtype2howto (arelent *internal, int relocentry) -{ - switch (relocentry) - { - case R_RELBYTE: internal->howto = apollocoff_howto_table + 0; break; - case R_RELWORD: internal->howto = apollocoff_howto_table + 1; break; - case R_RELLONG: internal->howto = apollocoff_howto_table + 2; break; - case R_PCRBYTE: internal->howto = apollocoff_howto_table + 3; break; - case R_PCRWORD: internal->howto = apollocoff_howto_table + 4; break; - case R_PCRLONG: internal->howto = apollocoff_howto_table + 5; break; - case R_RELLONG_NEG: internal->howto = apollocoff_howto_table + 6; break; - } -} - -int -apollo_howto2rtype (reloc_howto_type *internal) -{ - if (internal->pc_relative) - { - switch (internal->bitsize) - { - case 32: return R_PCRLONG; - case 16: return R_PCRWORD; - case 8: return R_PCRBYTE; - } - } - else - { - switch (internal->bitsize) - { - case 32: return R_RELLONG; - case 16: return R_RELWORD; - case 8: return R_RELBYTE; - } - } - return R_RELLONG; -} -#endif /* not ONLY_DECLARE_RELOCS */ - -#define RTYPE2HOWTO(internal, relocentry) \ - apollo_rtype2howto (internal, (relocentry)->r_type) - -#define SELECT_RELOC(external, internal) \ - external.r_type = apollo_howto2rtype (internal); - -#define bfd_pe_print_pdata NULL - -#include "coffcode.h" - -#ifndef TARGET_SYM -#define TARGET_SYM m68k_coff_apollo_vec -#endif - -#ifndef TARGET_NAME -#define TARGET_NAME "apollo-m68k" -#endif - -#ifdef NAMES_HAVE_UNDERSCORE -CREATE_BIG_COFF_TARGET_VEC (TARGET_SYM, TARGET_NAME, 0, 0, '_', NULL, COFF_SWAP_TABLE) -#else -CREATE_BIG_COFF_TARGET_VEC (TARGET_SYM, TARGET_NAME, 0, 0, 0, NULL, COFF_SWAP_TABLE) -#endif diff --git a/sdcc/support/sdbinutils/bfd/coff-arm.c b/sdcc/support/sdbinutils/bfd/coff-arm.c deleted file mode 100644 index 4e80a596e..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-arm.c +++ /dev/null @@ -1,2561 +0,0 @@ -/* BFD back-end for ARM COFF files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/arm.h" -#include "coff/internal.h" - -#ifdef COFF_WITH_PE -#include "coff/pe.h" -#endif - -#include "libcoff.h" - -/* Macros for manipulation the bits in the flags field of the coff data - structure. */ -#define APCS_26_FLAG(abfd) \ - (coff_data (abfd)->flags & F_APCS_26) - -#define APCS_FLOAT_FLAG(abfd) \ - (coff_data (abfd)->flags & F_APCS_FLOAT) - -#define PIC_FLAG(abfd) \ - (coff_data (abfd)->flags & F_PIC) - -#define APCS_SET(abfd) \ - (coff_data (abfd)->flags & F_APCS_SET) - -#define SET_APCS_FLAGS(abfd, flgs) \ - do \ - { \ - coff_data (abfd)->flags &= ~(F_APCS_26 | F_APCS_FLOAT | F_PIC); \ - coff_data (abfd)->flags |= (flgs) | F_APCS_SET; \ - } \ - while (0) - -#define INTERWORK_FLAG(abfd) \ - (coff_data (abfd)->flags & F_INTERWORK) - -#define INTERWORK_SET(abfd) \ - (coff_data (abfd)->flags & F_INTERWORK_SET) - -#define SET_INTERWORK_FLAG(abfd, flg) \ - do \ - { \ - coff_data (abfd)->flags &= ~F_INTERWORK; \ - coff_data (abfd)->flags |= (flg) | F_INTERWORK_SET; \ - } \ - while (0) - -#ifndef NUM_ELEM -#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0])) -#endif - -typedef enum {bunknown, b9, b12, b23} thumb_pcrel_branchtype; -/* Some typedefs for holding instructions. */ -typedef unsigned long int insn32; -typedef unsigned short int insn16; - -/* The linker script knows the section names for placement. - The entry_names are used to do simple name mangling on the stubs. - Given a function name, and its type, the stub can be found. The - name can be changed. The only requirement is the %s be present. */ - -#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t" -#define THUMB2ARM_GLUE_ENTRY_NAME "__%s_from_thumb" - -#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7" -#define ARM2THUMB_GLUE_ENTRY_NAME "__%s_from_arm" - -/* Used by the assembler. */ - -static bfd_reloc_status_type -coff_arm_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - symvalue diff; - - if (output_bfd == NULL) - return bfd_reloc_continue; - - diff = reloc_entry->addend; - -#define DOIT(x) \ - x = ((x & ~howto->dst_mask) \ - | (((x & howto->src_mask) + diff) & howto->dst_mask)) - - if (diff != 0) - { - reloc_howto_type *howto = reloc_entry->howto; - unsigned char *addr = (unsigned char *) data + reloc_entry->address; - - if (! bfd_reloc_offset_in_range (howto, abfd, input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - switch (howto->size) - { - case 0: - { - char x = bfd_get_8 (abfd, addr); - DOIT (x); - bfd_put_8 (abfd, x, addr); - } - break; - - case 1: - { - short x = bfd_get_16 (abfd, addr); - DOIT (x); - bfd_put_16 (abfd, (bfd_vma) x, addr); - } - break; - - case 2: - { - long x = bfd_get_32 (abfd, addr); - DOIT (x); - bfd_put_32 (abfd, (bfd_vma) x, addr); - } - break; - - default: - abort (); - } - } - - /* Now let bfd_perform_relocation finish everything up. */ - return bfd_reloc_continue; -} - -/* If USER_LABEL_PREFIX is defined as "_" (see coff_arm_is_local_label_name() - in this file), then TARGET_UNDERSCORE should be defined, otherwise it - should not. */ -#ifndef TARGET_UNDERSCORE -#define TARGET_UNDERSCORE '_' -#endif - -#ifndef PCRELOFFSET -#define PCRELOFFSET TRUE -#endif - -/* These most certainly belong somewhere else. Just had to get rid of - the manifest constants in the code. */ - -#ifdef ARM_WINCE - -#define ARM_26D 0 -#define ARM_32 1 -#define ARM_RVA32 2 -#define ARM_26 3 -#define ARM_THUMB12 4 -#define ARM_SECTION 14 -#define ARM_SECREL 15 - -#else - -#define ARM_8 0 -#define ARM_16 1 -#define ARM_32 2 -#define ARM_26 3 -#define ARM_DISP8 4 -#define ARM_DISP16 5 -#define ARM_DISP32 6 -#define ARM_26D 7 -/* 8 is unused. */ -#define ARM_NEG16 9 -#define ARM_NEG32 10 -#define ARM_RVA32 11 -#define ARM_THUMB9 12 -#define ARM_THUMB12 13 -#define ARM_THUMB23 14 - -#endif - -static bfd_reloc_status_type aoutarm_fix_pcrel_26_done - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type aoutarm_fix_pcrel_26 - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type coff_thumb_pcrel_12 - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -#ifndef ARM_WINCE -static bfd_reloc_status_type coff_thumb_pcrel_9 - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type coff_thumb_pcrel_23 - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -#endif - -static reloc_howto_type aoutarm_std_reloc_howto[] = - { -#ifdef ARM_WINCE - HOWTO (ARM_26D, - 2, - 2, - 24, - TRUE, - 0, - complain_overflow_dont, - aoutarm_fix_pcrel_26_done, - "ARM_26D", - TRUE, /* partial_inplace. */ - 0x00ffffff, - 0x0, - PCRELOFFSET), - HOWTO (ARM_32, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_32", - TRUE, /* partial_inplace. */ - 0xffffffff, - 0xffffffff, - PCRELOFFSET), - HOWTO (ARM_RVA32, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_RVA32", - TRUE, /* partial_inplace. */ - 0xffffffff, - 0xffffffff, - PCRELOFFSET), - HOWTO (ARM_26, - 2, - 2, - 24, - TRUE, - 0, - complain_overflow_signed, - aoutarm_fix_pcrel_26 , - "ARM_26", - FALSE, - 0x00ffffff, - 0x00ffffff, - PCRELOFFSET), - HOWTO (ARM_THUMB12, - 1, - 1, - 11, - TRUE, - 0, - complain_overflow_signed, - coff_thumb_pcrel_12 , - "ARM_THUMB12", - FALSE, - 0x000007ff, - 0x000007ff, - PCRELOFFSET), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - HOWTO (ARM_SECTION, - 0, - 1, - 16, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_SECTION", - TRUE, /* partial_inplace. */ - 0x0000ffff, - 0x0000ffff, - PCRELOFFSET), - HOWTO (ARM_SECREL, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_SECREL", - TRUE, /* partial_inplace. */ - 0xffffffff, - 0xffffffff, - PCRELOFFSET), -#else /* not ARM_WINCE */ - HOWTO (ARM_8, - 0, - 0, - 8, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_8", - TRUE, - 0x000000ff, - 0x000000ff, - PCRELOFFSET), - HOWTO (ARM_16, - 0, - 1, - 16, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_16", - TRUE, - 0x0000ffff, - 0x0000ffff, - PCRELOFFSET), - HOWTO (ARM_32, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_32", - TRUE, - 0xffffffff, - 0xffffffff, - PCRELOFFSET), - HOWTO (ARM_26, - 2, - 2, - 24, - TRUE, - 0, - complain_overflow_signed, - aoutarm_fix_pcrel_26 , - "ARM_26", - FALSE, - 0x00ffffff, - 0x00ffffff, - PCRELOFFSET), - HOWTO (ARM_DISP8, - 0, - 0, - 8, - TRUE, - 0, - complain_overflow_signed, - coff_arm_reloc, - "ARM_DISP8", - TRUE, - 0x000000ff, - 0x000000ff, - TRUE), - HOWTO (ARM_DISP16, - 0, - 1, - 16, - TRUE, - 0, - complain_overflow_signed, - coff_arm_reloc, - "ARM_DISP16", - TRUE, - 0x0000ffff, - 0x0000ffff, - TRUE), - HOWTO (ARM_DISP32, - 0, - 2, - 32, - TRUE, - 0, - complain_overflow_signed, - coff_arm_reloc, - "ARM_DISP32", - TRUE, - 0xffffffff, - 0xffffffff, - TRUE), - HOWTO (ARM_26D, - 2, - 2, - 24, - FALSE, - 0, - complain_overflow_dont, - aoutarm_fix_pcrel_26_done, - "ARM_26D", - TRUE, - 0x00ffffff, - 0x0, - FALSE), - /* 8 is unused */ - EMPTY_HOWTO (-1), - HOWTO (ARM_NEG16, - 0, - -1, - 16, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_NEG16", - TRUE, - 0x0000ffff, - 0x0000ffff, - FALSE), - HOWTO (ARM_NEG32, - 0, - -2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_NEG32", - TRUE, - 0xffffffff, - 0xffffffff, - FALSE), - HOWTO (ARM_RVA32, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - coff_arm_reloc, - "ARM_RVA32", - TRUE, - 0xffffffff, - 0xffffffff, - PCRELOFFSET), - HOWTO (ARM_THUMB9, - 1, - 1, - 8, - TRUE, - 0, - complain_overflow_signed, - coff_thumb_pcrel_9 , - "ARM_THUMB9", - FALSE, - 0x000000ff, - 0x000000ff, - PCRELOFFSET), - HOWTO (ARM_THUMB12, - 1, - 1, - 11, - TRUE, - 0, - complain_overflow_signed, - coff_thumb_pcrel_12 , - "ARM_THUMB12", - FALSE, - 0x000007ff, - 0x000007ff, - PCRELOFFSET), - HOWTO (ARM_THUMB23, - 1, - 2, - 22, - TRUE, - 0, - complain_overflow_signed, - coff_thumb_pcrel_23 , - "ARM_THUMB23", - FALSE, - 0x07ff07ff, - 0x07ff07ff, - PCRELOFFSET) -#endif /* not ARM_WINCE */ - }; - -#define NUM_RELOCS NUM_ELEM (aoutarm_std_reloc_howto) - -#ifdef COFF_WITH_PE -/* Return TRUE if this relocation should - appear in the output .reloc section. */ - -static bfd_boolean -in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, - reloc_howto_type * howto) -{ - return !howto->pc_relative && howto->type != ARM_RVA32; -} -#endif - -#define RTYPE2HOWTO(cache_ptr, dst) \ - (cache_ptr)->howto = \ - (dst)->r_type < NUM_RELOCS \ - ? aoutarm_std_reloc_howto + (dst)->r_type \ - : NULL - -#define coff_rtype_to_howto coff_arm_rtype_to_howto - -static reloc_howto_type * -coff_arm_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - bfd_vma *addendp) -{ - reloc_howto_type * howto; - - if (rel->r_type >= NUM_RELOCS) - return NULL; - - howto = aoutarm_std_reloc_howto + rel->r_type; - - if (rel->r_type == ARM_RVA32) - *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; - -#if defined COFF_WITH_PE && defined ARM_WINCE - if (rel->r_type == ARM_SECREL) - { - bfd_vma osect_vma; - - if (h && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - osect_vma = h->root.u.def.section->output_section->vma; - else - { - int i; - - /* Sigh, the only way to get the section to offset against - is to find it the hard way. */ - - for (sec = abfd->sections, i = 1; i < sym->n_scnum; i++) - sec = sec->next; - - osect_vma = sec->output_section->vma; - } - - *addendp -= osect_vma; - } -#endif - - return howto; -} - -/* Used by the assembler. */ - -static bfd_reloc_status_type -aoutarm_fix_pcrel_26_done (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This is dead simple at present. */ - return bfd_reloc_ok; -} - -/* Used by the assembler. */ - -static bfd_reloc_status_type -aoutarm_fix_pcrel_26 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - bfd_size_type addr = reloc_entry->address; - long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); - bfd_reloc_status_type flag = bfd_reloc_ok; - - /* If this is an undefined symbol, return error. */ - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0) - return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined; - - /* If the sections are different, and we are doing a partial relocation, - just ignore it for now. */ - if (symbol->section->name != input_section->name - && output_bfd != (bfd *)NULL) - return bfd_reloc_continue; - - relocation = (target & 0x00ffffff) << 2; - relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend. */ - relocation += symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - relocation -= input_section->output_section->vma; - relocation -= input_section->output_offset; - relocation -= addr; - - if (relocation & 3) - return bfd_reloc_overflow; - - /* Check for overflow. */ - if (relocation & 0x02000000) - { - if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff) - flag = bfd_reloc_overflow; - } - else if (relocation & ~(bfd_vma) 0x03ffffff) - flag = bfd_reloc_overflow; - - target &= ~0x00ffffff; - target |= (relocation >> 2) & 0x00ffffff; - bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr); - - /* Now the ARM magic... Change the reloc type so that it is marked as done. - Strictly this is only necessary if we are doing a partial relocation. */ - reloc_entry->howto = &aoutarm_std_reloc_howto[ARM_26D]; - - return flag; -} - -static bfd_reloc_status_type -coff_thumb_pcrel_common (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED, - thumb_pcrel_branchtype btype) -{ - bfd_vma relocation = 0; - bfd_size_type addr = reloc_entry->address; - long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); - bfd_reloc_status_type flag = bfd_reloc_ok; - bfd_vma dstmsk; - bfd_vma offmsk; - bfd_vma signbit; - - /* NOTE: This routine is currently used by GAS, but not by the link - phase. */ - switch (btype) - { - case b9: - dstmsk = 0x000000ff; - offmsk = 0x000001fe; - signbit = 0x00000100; - break; - - case b12: - dstmsk = 0x000007ff; - offmsk = 0x00000ffe; - signbit = 0x00000800; - break; - - case b23: - dstmsk = 0x07ff07ff; - offmsk = 0x007fffff; - signbit = 0x00400000; - break; - - default: - abort (); - } - - /* If this is an undefined symbol, return error. */ - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0) - return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined; - - /* If the sections are different, and we are doing a partial relocation, - just ignore it for now. */ - if (symbol->section->name != input_section->name - && output_bfd != (bfd *)NULL) - return bfd_reloc_continue; - - switch (btype) - { - case b9: - case b12: - relocation = ((target & dstmsk) << 1); - break; - - case b23: - if (bfd_big_endian (abfd)) - relocation = ((target & 0x7ff) << 1) | ((target & 0x07ff0000) >> 4); - else - relocation = ((target & 0x7ff) << 12) | ((target & 0x07ff0000) >> 15); - break; - - default: - abort (); - } - - relocation = (relocation ^ signbit) - signbit; /* Sign extend. */ - relocation += symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - relocation -= input_section->output_section->vma; - relocation -= input_section->output_offset; - relocation -= addr; - - if (relocation & 1) - return bfd_reloc_overflow; - - /* Check for overflow. */ - if (relocation & signbit) - { - if ((relocation & ~offmsk) != ~offmsk) - flag = bfd_reloc_overflow; - } - else if (relocation & ~offmsk) - flag = bfd_reloc_overflow; - - target &= ~dstmsk; - switch (btype) - { - case b9: - case b12: - target |= (relocation >> 1); - break; - - case b23: - if (bfd_big_endian (abfd)) - target |= (((relocation & 0xfff) >> 1) - | ((relocation << 4) & 0x07ff0000)); - else - target |= (((relocation & 0xffe) << 15) - | ((relocation >> 12) & 0x7ff)); - break; - - default: - abort (); - } - - bfd_put_32 (abfd, (bfd_vma) target, (bfd_byte *) data + addr); - - /* Now the ARM magic... Change the reloc type so that it is marked as done. - Strictly this is only necessary if we are doing a partial relocation. */ - reloc_entry->howto = & aoutarm_std_reloc_howto [ARM_26D]; - - /* TODO: We should possibly have DONE entries for the THUMB PCREL relocations. */ - return flag; -} - -#ifndef ARM_WINCE -static bfd_reloc_status_type -coff_thumb_pcrel_23 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message, - b23); -} - -static bfd_reloc_status_type -coff_thumb_pcrel_9 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message, - b9); -} -#endif /* not ARM_WINCE */ - -static bfd_reloc_status_type -coff_thumb_pcrel_12 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message, - b12); -} - -static const struct reloc_howto_struct * -coff_arm_reloc_type_lookup (bfd * abfd, bfd_reloc_code_real_type code) -{ -#define ASTD(i,j) case i: return aoutarm_std_reloc_howto + j - - if (code == BFD_RELOC_CTOR) - switch (bfd_arch_bits_per_address (abfd)) - { - case 32: - code = BFD_RELOC_32; - break; - default: - return NULL; - } - - switch (code) - { -#ifdef ARM_WINCE - ASTD (BFD_RELOC_32, ARM_32); - ASTD (BFD_RELOC_RVA, ARM_RVA32); - ASTD (BFD_RELOC_ARM_PCREL_BRANCH, ARM_26); - ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12); - ASTD (BFD_RELOC_32_SECREL, ARM_SECREL); -#else - ASTD (BFD_RELOC_8, ARM_8); - ASTD (BFD_RELOC_16, ARM_16); - ASTD (BFD_RELOC_32, ARM_32); - ASTD (BFD_RELOC_ARM_PCREL_BRANCH, ARM_26); - ASTD (BFD_RELOC_ARM_PCREL_BLX, ARM_26); - ASTD (BFD_RELOC_8_PCREL, ARM_DISP8); - ASTD (BFD_RELOC_16_PCREL, ARM_DISP16); - ASTD (BFD_RELOC_32_PCREL, ARM_DISP32); - ASTD (BFD_RELOC_RVA, ARM_RVA32); - ASTD (BFD_RELOC_THUMB_PCREL_BRANCH9, ARM_THUMB9); - ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12); - ASTD (BFD_RELOC_THUMB_PCREL_BRANCH23, ARM_THUMB23); - ASTD (BFD_RELOC_THUMB_PCREL_BLX, ARM_THUMB23); -#endif - default: return NULL; - } -} - -static reloc_howto_type * -coff_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (aoutarm_std_reloc_howto) - / sizeof (aoutarm_std_reloc_howto[0])); - i++) - if (aoutarm_std_reloc_howto[i].name != NULL - && strcasecmp (aoutarm_std_reloc_howto[i].name, r_name) == 0) - return &aoutarm_std_reloc_howto[i]; - - return NULL; -} - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2 -#define COFF_PAGE_SIZE 0x1000 - -/* Turn a howto into a reloc nunmber. */ -#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } -#define BADMAG(x) ARMBADMAG(x) -#define ARM 1 /* Customize coffcode.h. */ - -#ifndef ARM_WINCE -/* Make sure that the 'r_offset' field is copied properly - so that identical binaries will compare the same. */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#endif - -/* Extend the coff_link_hash_table structure with a few ARM specific fields. - This allows us to store global data here without actually creating any - global variables, which is a no-no in the BFD world. */ -struct coff_arm_link_hash_table - { - /* The original coff_link_hash_table structure. MUST be first field. */ - struct coff_link_hash_table root; - - /* The size in bytes of the section containing the Thumb-to-ARM glue. */ - bfd_size_type thumb_glue_size; - - /* The size in bytes of the section containing the ARM-to-Thumb glue. */ - bfd_size_type arm_glue_size; - - /* An arbitrary input BFD chosen to hold the glue sections. */ - bfd * bfd_of_glue_owner; - - /* Support interworking with old, non-interworking aware ARM code. */ - int support_old_code; -}; - -/* Get the ARM coff linker hash table from a link_info structure. */ -#define coff_arm_hash_table(info) \ - ((struct coff_arm_link_hash_table *) ((info)->hash)) - -/* Create an ARM coff linker hash table. */ - -static struct bfd_link_hash_table * -coff_arm_link_hash_table_create (bfd * abfd) -{ - struct coff_arm_link_hash_table * ret; - bfd_size_type amt = sizeof (struct coff_arm_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_coff_link_hash_table_init (&ret->root, - abfd, - _bfd_coff_link_hash_newfunc, - sizeof (struct coff_link_hash_entry))) - { - free (ret); - return NULL; - } - - return & ret->root.root; -} - -static bfd_boolean -arm_emit_base_file_entry (struct bfd_link_info *info, - bfd *output_bfd, - asection *input_section, - bfd_vma reloc_offset) -{ - bfd_vma addr = (reloc_offset - - input_section->vma - + input_section->output_offset - + input_section->output_section->vma); - - if (coff_data (output_bfd)->pe) - addr -= pe_data (output_bfd)->pe_opthdr.ImageBase; - if (fwrite (&addr, sizeof (addr), 1, (FILE *) info->base_file) == 1) - return TRUE; - - bfd_set_error (bfd_error_system_call); - return FALSE; -} - -#ifndef ARM_WINCE -/* The thumb form of a long branch is a bit finicky, because the offset - encoding is split over two fields, each in it's own instruction. They - can occur in any order. So given a thumb form of long branch, and an - offset, insert the offset into the thumb branch and return finished - instruction. - - It takes two thumb instructions to encode the target address. Each has - 11 bits to invest. The upper 11 bits are stored in one (identified by - H-0.. see below), the lower 11 bits are stored in the other (identified - by H-1). - - Combine together and shifted left by 1 (it's a half word address) and - there you have it. - - Op: 1111 = F, - H-0, upper address-0 = 000 - Op: 1111 = F, - H-1, lower address-0 = 800 - - They can be ordered either way, but the arm tools I've seen always put - the lower one first. It probably doesn't matter. krk@cygnus.com - - XXX: Actually the order does matter. The second instruction (H-1) - moves the computed address into the PC, so it must be the second one - in the sequence. The problem, however is that whilst little endian code - stores the instructions in HI then LOW order, big endian code does the - reverse. nickc@cygnus.com. */ - -#define LOW_HI_ORDER 0xF800F000 -#define HI_LOW_ORDER 0xF000F800 - -static insn32 -insert_thumb_branch (insn32 br_insn, int rel_off) -{ - unsigned int low_bits; - unsigned int high_bits; - - BFD_ASSERT ((rel_off & 1) != 1); - - rel_off >>= 1; /* Half word aligned address. */ - low_bits = rel_off & 0x000007FF; /* The bottom 11 bits. */ - high_bits = (rel_off >> 11) & 0x000007FF; /* The top 11 bits. */ - - if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER) - br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits; - else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER) - br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits; - else - /* FIXME: the BFD library should never abort except for internal errors - - it should return an error status. */ - abort (); /* Error - not a valid branch instruction form. */ - - return br_insn; -} - - -static struct coff_link_hash_entry * -find_thumb_glue (struct bfd_link_info *info, - const char *name, - bfd *input_bfd) -{ - char *tmp_name; - struct coff_link_hash_entry *myh; - bfd_size_type amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1; - - tmp_name = bfd_malloc (amt); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); - - myh = coff_link_hash_lookup - (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL) - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unable to find THUMB glue '%s' for `%s'"), - input_bfd, tmp_name, name); - - free (tmp_name); - - return myh; -} -#endif /* not ARM_WINCE */ - -static struct coff_link_hash_entry * -find_arm_glue (struct bfd_link_info *info, - const char *name, - bfd *input_bfd) -{ - char *tmp_name; - struct coff_link_hash_entry * myh; - bfd_size_type amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1; - - tmp_name = bfd_malloc (amt); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); - - myh = coff_link_hash_lookup - (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL) - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unable to find ARM glue '%s' for `%s'"), - input_bfd, tmp_name, name); - - free (tmp_name); - - return myh; -} - -/* - ARM->Thumb glue: - - .arm - __func_from_arm: - ldr r12, __func_addr - bx r12 - __func_addr: - .word func @ behave as if you saw a ARM_32 reloc -*/ - -#define ARM2THUMB_GLUE_SIZE 12 -static const insn32 a2t1_ldr_insn = 0xe59fc000; -static const insn32 a2t2_bx_r12_insn = 0xe12fff1c; -static const insn32 a2t3_func_addr_insn = 0x00000001; - -/* - Thumb->ARM: Thumb->(non-interworking aware) ARM - - .thumb .thumb - .align 2 .align 2 - __func_from_thumb: __func_from_thumb: - bx pc push {r6, lr} - nop ldr r6, __func_addr - .arm mov lr, pc - __func_change_to_arm: bx r6 - b func .arm - __func_back_to_thumb: - ldmia r13! {r6, lr} - bx lr - __func_addr: - .word func -*/ - -#define THUMB2ARM_GLUE_SIZE (globals->support_old_code ? 20 : 8) -#ifndef ARM_WINCE -static const insn16 t2a1_bx_pc_insn = 0x4778; -static const insn16 t2a2_noop_insn = 0x46c0; -static const insn32 t2a3_b_insn = 0xea000000; - -static const insn16 t2a1_push_insn = 0xb540; -static const insn16 t2a2_ldr_insn = 0x4e03; -static const insn16 t2a3_mov_insn = 0x46fe; -static const insn16 t2a4_bx_insn = 0x4730; -static const insn32 t2a5_pop_insn = 0xe8bd4040; -static const insn32 t2a6_bx_insn = 0xe12fff1e; -#endif - -/* TODO: - We should really create new local (static) symbols in destination - object for each stub we create. We should also create local - (static) symbols within the stubs when switching between ARM and - Thumb code. This will ensure that the debugger and disassembler - can present a better view of stubs. - - We can treat stubs like literal sections, and for the THUMB9 ones - (short addressing range) we should be able to insert the stubs - between sections. i.e. the simplest approach (since relocations - are done on a section basis) is to dump the stubs at the end of - processing a section. That way we can always try and minimise the - offset to and from a stub. However, this does not map well onto - the way that the linker/BFD does its work: mapping all input - sections to output sections via the linker script before doing - all the processing. - - Unfortunately it may be easier to just to disallow short range - Thumb->ARM stubs (i.e. no conditional inter-working branches, - only branch-and-link (BL) calls. This will simplify the processing - since we can then put all of the stubs into their own section. - - TODO: - On a different subject, rather than complaining when a - branch cannot fit in the number of bits available for the - instruction we should generate a trampoline stub (needed to - address the complete 32bit address space). */ - -/* The standard COFF backend linker does not cope with the special - Thumb BRANCH23 relocation. The alternative would be to split the - BRANCH23 into seperate HI23 and LO23 relocations. However, it is a - bit simpler simply providing our own relocation driver. */ - -/* The reloc processing routine for the ARM/Thumb COFF linker. NOTE: - This code is a very slightly modified copy of - _bfd_coff_generic_relocate_section. It would be a much more - maintainable solution to have a MACRO that could be expanded within - _bfd_coff_generic_relocate_section that would only be provided for - ARM/Thumb builds. It is only the code marked THUMBEXTENSION that - is different from the original. */ - -static bfd_boolean -coff_arm_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc * rel; - struct internal_reloc * relend; -#ifndef ARM_WINCE - bfd_vma high_address = bfd_get_section_limit (input_bfd, input_section); -#endif - - rel = relocs; - relend = rel + input_section->reloc_count; - - for (; rel < relend; rel++) - { - int done = 0; - long symndx; - struct coff_link_hash_entry * h; - struct internal_syment * sym; - bfd_vma addend; - bfd_vma val; - reloc_howto_type * howto; - bfd_reloc_status_type rstat; - bfd_vma h_val; - - symndx = rel->r_symndx; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else - { - h = obj_coff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - } - - /* COFF treats common symbols in one of two ways. Either the - size of the symbol is included in the section contents, or it - is not. We assume that the size is not included, and force - the rtype_to_howto function to adjust the addend as needed. */ - - if (sym != NULL && sym->n_scnum != 0) - addend = - sym->n_value; - else - addend = 0; - - howto = coff_rtype_to_howto (input_bfd, input_section, rel, h, - sym, &addend); - if (howto == NULL) - return FALSE; - - /* The relocation_section function will skip pcrel_offset relocs - when doing a relocatable link. However, we want to convert - ARM_26 to ARM_26D relocs if possible. We return a fake howto in - this case without pcrel_offset set, and adjust the addend to - compensate. 'partial_inplace' is also set, since we want 'done' - relocations to be reflected in section's data. */ - if (rel->r_type == ARM_26 - && h != NULL - && bfd_link_relocatable (info) - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && (h->root.u.def.section->output_section - == input_section->output_section)) - { - static reloc_howto_type fake_arm26_reloc = - HOWTO (ARM_26, - 2, - 2, - 24, - TRUE, - 0, - complain_overflow_signed, - aoutarm_fix_pcrel_26 , - "ARM_26", - TRUE, - 0x00ffffff, - 0x00ffffff, - FALSE); - - addend -= rel->r_vaddr - input_section->vma; -#ifdef ARM_WINCE - /* FIXME: I don't know why, but the hack is necessary for correct - generation of bl's instruction offset. */ - addend -= 8; -#endif - howto = & fake_arm26_reloc; - } - -#ifdef ARM_WINCE - /* MS ARM-CE makes the reloc relative to the opcode's pc, not - the next opcode's pc, so is off by one. */ - if (howto->pc_relative && !bfd_link_relocatable (info)) - addend -= 8; -#endif - - /* If we are doing a relocatable link, then we can just ignore - a PC relative reloc that is pcrel_offset. It will already - have the correct value. If this is not a relocatable link, - then we should ignore the symbol value. */ - if (howto->pc_relative && howto->pcrel_offset) - { - if (bfd_link_relocatable (info)) - continue; - /* FIXME - it is not clear which targets need this next test - and which do not. It is known that it is needed for the - VxWorks and EPOC-PE targets, but it is also known that it - was suppressed for other ARM targets. This ought to be - sorted out one day. */ -#ifdef ARM_COFF_BUGFIX - /* We must not ignore the symbol value. If the symbol is - within the same section, the relocation should have already - been fixed, but if it is not, we'll be handed a reloc into - the beginning of the symbol's section, so we must not cancel - out the symbol's value, otherwise we'll be adding it in - twice. */ - if (sym != NULL && sym->n_scnum != 0) - addend += sym->n_value; -#endif - } - - val = 0; - - if (h == NULL) - { - asection *sec; - - if (symndx == -1) - { - sec = bfd_abs_section_ptr; - val = 0; - } - else - { - sec = sections[symndx]; - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value - - sec->vma); - } - } - else - { - /* We don't output the stubs if we are generating a - relocatable output file, since we may as well leave the - stub generation to the final linker pass. If we fail to - verify that the name is defined, we'll try to build stubs - for an undefined name... */ - if (! bfd_link_relocatable (info) - && ( h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - asection * h_sec = h->root.u.def.section; - const char * name = h->root.root.string; - - /* h locates the symbol referenced in the reloc. */ - h_val = (h->root.u.def.value - + h_sec->output_section->vma - + h_sec->output_offset); - - if (howto->type == ARM_26) - { - if ( h->symbol_class == C_THUMBSTATFUNC - || h->symbol_class == C_THUMBEXTFUNC) - { - /* Arm code calling a Thumb function. */ - unsigned long int tmp; - bfd_vma my_offset; - asection * s; - long int ret_offset; - struct coff_link_hash_entry * myh; - struct coff_arm_link_hash_table * globals; - - myh = find_arm_glue (info, name, input_bfd); - if (myh == NULL) - return FALSE; - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - my_offset = myh->root.u.def.value; - - s = bfd_get_section_by_name (globals->bfd_of_glue_owner, - ARM2THUMB_GLUE_SECTION_NAME); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->contents != NULL); - BFD_ASSERT (s->output_section != NULL); - - if ((my_offset & 0x01) == 0x01) - { - if (h_sec->owner != NULL - && INTERWORK_SET (h_sec->owner) - && ! INTERWORK_FLAG (h_sec->owner)) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: arm call to thumb"), - h_sec->owner, name, input_bfd); - - --my_offset; - myh->root.u.def.value = my_offset; - - bfd_put_32 (output_bfd, (bfd_vma) a2t1_ldr_insn, - s->contents + my_offset); - - bfd_put_32 (output_bfd, (bfd_vma) a2t2_bx_r12_insn, - s->contents + my_offset + 4); - - /* It's a thumb address. Add the low order bit. */ - bfd_put_32 (output_bfd, h_val | a2t3_func_addr_insn, - s->contents + my_offset + 8); - - if (info->base_file - && !arm_emit_base_file_entry (info, output_bfd, - s, my_offset + 8)) - return FALSE; - } - - BFD_ASSERT (my_offset <= globals->arm_glue_size); - - tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr - - input_section->vma); - - tmp = tmp & 0xFF000000; - - /* Somehow these are both 4 too far, so subtract 8. */ - ret_offset = - s->output_offset - + my_offset - + s->output_section->vma - - (input_section->output_offset - + input_section->output_section->vma - + rel->r_vaddr) - - 8; - - tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF); - - bfd_put_32 (output_bfd, (bfd_vma) tmp, - contents + rel->r_vaddr - input_section->vma); - done = 1; - } - } - -#ifndef ARM_WINCE - /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12. */ - else if (howto->type == ARM_THUMB23) - { - if ( h->symbol_class == C_EXT - || h->symbol_class == C_STAT - || h->symbol_class == C_LABEL) - { - /* Thumb code calling an ARM function. */ - asection * s = 0; - bfd_vma my_offset; - unsigned long int tmp; - long int ret_offset; - struct coff_link_hash_entry * myh; - struct coff_arm_link_hash_table * globals; - - myh = find_thumb_glue (info, name, input_bfd); - if (myh == NULL) - return FALSE; - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - my_offset = myh->root.u.def.value; - - s = bfd_get_section_by_name (globals->bfd_of_glue_owner, - THUMB2ARM_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->contents != NULL); - BFD_ASSERT (s->output_section != NULL); - - if ((my_offset & 0x01) == 0x01) - { - if (h_sec->owner != NULL - && INTERWORK_SET (h_sec->owner) - && ! INTERWORK_FLAG (h_sec->owner) - && ! globals->support_old_code) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: thumb call to arm\n" - " consider relinking with --support-old-code enabled"), - h_sec->owner, name, input_bfd); - - -- my_offset; - myh->root.u.def.value = my_offset; - - if (globals->support_old_code) - { - bfd_put_16 (output_bfd, (bfd_vma) t2a1_push_insn, - s->contents + my_offset); - - bfd_put_16 (output_bfd, (bfd_vma) t2a2_ldr_insn, - s->contents + my_offset + 2); - - bfd_put_16 (output_bfd, (bfd_vma) t2a3_mov_insn, - s->contents + my_offset + 4); - - bfd_put_16 (output_bfd, (bfd_vma) t2a4_bx_insn, - s->contents + my_offset + 6); - - bfd_put_32 (output_bfd, (bfd_vma) t2a5_pop_insn, - s->contents + my_offset + 8); - - bfd_put_32 (output_bfd, (bfd_vma) t2a6_bx_insn, - s->contents + my_offset + 12); - - /* Store the address of the function in the last word of the stub. */ - bfd_put_32 (output_bfd, h_val, - s->contents + my_offset + 16); - - if (info->base_file - && !arm_emit_base_file_entry (info, - output_bfd, s, - my_offset + 16)) - return FALSE; - } - else - { - bfd_put_16 (output_bfd, (bfd_vma) t2a1_bx_pc_insn, - s->contents + my_offset); - - bfd_put_16 (output_bfd, (bfd_vma) t2a2_noop_insn, - s->contents + my_offset + 2); - - ret_offset = - /* Address of destination of the stub. */ - ((bfd_signed_vma) h_val) - - ((bfd_signed_vma) - /* Offset from the start of the current section to the start of the stubs. */ - (s->output_offset - /* Offset of the start of this stub from the start of the stubs. */ - + my_offset - /* Address of the start of the current section. */ - + s->output_section->vma) - /* The branch instruction is 4 bytes into the stub. */ - + 4 - /* ARM branches work from the pc of the instruction + 8. */ - + 8); - - bfd_put_32 (output_bfd, - (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF), - s->contents + my_offset + 4); - - } - } - - BFD_ASSERT (my_offset <= globals->thumb_glue_size); - - /* Now go back and fix up the original BL insn to point - to here. */ - ret_offset = - s->output_offset - + my_offset - - (input_section->output_offset - + rel->r_vaddr) - -4; - - tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr - - input_section->vma); - - bfd_put_32 (output_bfd, - (bfd_vma) insert_thumb_branch (tmp, - ret_offset), - contents + rel->r_vaddr - input_section->vma); - - done = 1; - } - } -#endif - } - - /* If the relocation type and destination symbol does not - fall into one of the above categories, then we can just - perform a direct link. */ - - if (done) - rstat = bfd_reloc_ok; - else - if ( h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *sec; - - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - - else if (! bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - } - - /* Emit a reloc if the backend thinks it needs it. */ - if (info->base_file - && sym - && pe_data(output_bfd)->in_reloc_p(output_bfd, howto) - && !arm_emit_base_file_entry (info, output_bfd, input_section, - rel->r_vaddr)) - return FALSE; - - if (done) - rstat = bfd_reloc_ok; -#ifndef ARM_WINCE - /* Only perform this fix during the final link, not a relocatable link. */ - else if (! bfd_link_relocatable (info) - && howto->type == ARM_THUMB23) - { - /* This is pretty much a copy of what the default - _bfd_final_link_relocate and _bfd_relocate_contents - routines do to perform a relocation, with special - processing for the split addressing of the Thumb BL - instruction. Again, it would probably be simpler adding a - ThumbBRANCH23 specific macro expansion into the default - code. */ - - bfd_vma address = rel->r_vaddr - input_section->vma; - - if (address > high_address) - rstat = bfd_reloc_outofrange; - else - { - bfd_vma relocation = val + addend; - int size = bfd_get_reloc_size (howto); - bfd_boolean overflow = FALSE; - bfd_byte *location = contents + address; - bfd_vma x = bfd_get_32 (input_bfd, location); - bfd_vma src_mask = 0x007FFFFE; - bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; - bfd_signed_vma reloc_signed_min = ~reloc_signed_max; - bfd_vma check; - bfd_signed_vma signed_check; - bfd_vma add; - bfd_signed_vma signed_add; - - BFD_ASSERT (size == 4); - - /* howto->pc_relative should be TRUE for type 14 BRANCH23. */ - relocation -= (input_section->output_section->vma - + input_section->output_offset); - - /* howto->pcrel_offset should be TRUE for type 14 BRANCH23. */ - relocation -= address; - - /* No need to negate the relocation with BRANCH23. */ - /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23. */ - /* howto->rightshift == 1 */ - - /* Drop unwanted bits from the value we are relocating to. */ - check = relocation >> howto->rightshift; - - /* If this is a signed value, the rightshift just dropped - leading 1 bits (assuming twos complement). */ - if ((bfd_signed_vma) relocation >= 0) - signed_check = check; - else - signed_check = (check - | ((bfd_vma) - 1 - & ~((bfd_vma) - 1 >> howto->rightshift))); - - /* Get the value from the object file. */ - if (bfd_big_endian (input_bfd)) - add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1); - else - add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15)); - - /* Get the value from the object file with an appropriate sign. - The expression involving howto->src_mask isolates the upper - bit of src_mask. If that bit is set in the value we are - adding, it is negative, and we subtract out that number times - two. If src_mask includes the highest possible bit, then we - can not get the upper bit, but that does not matter since - signed_add needs no adjustment to become negative in that - case. */ - signed_add = add; - - if ((add & (((~ src_mask) >> 1) & src_mask)) != 0) - signed_add -= (((~ src_mask) >> 1) & src_mask) << 1; - - /* howto->bitpos == 0 */ - /* Add the value from the object file, shifted so that it is a - straight number. */ - signed_check += signed_add; - relocation += signed_add; - - BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed); - - /* Assumes two's complement. */ - if ( signed_check > reloc_signed_max - || signed_check < reloc_signed_min) - overflow = TRUE; - - /* Put the relocation into the correct bits. - For a BLX instruction, make sure that the relocation is rounded up - to a word boundary. This follows the semantics of the instruction - which specifies that bit 1 of the target address will come from bit - 1 of the base address. */ - if (bfd_big_endian (input_bfd)) - { - if ((x & 0x1800) == 0x0800 && (relocation & 0x02)) - relocation += 2; - relocation = (((relocation & 0xffe) >> 1) | ((relocation << 4) & 0x07ff0000)); - } - else - { - if ((x & 0x18000000) == 0x08000000 && (relocation & 0x02)) - relocation += 2; - relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff)); - } - - /* Add the relocation to the correct bits of X. */ - x = ((x & ~howto->dst_mask) | relocation); - - /* Put the relocated value back in the object file. */ - bfd_put_32 (input_bfd, x, location); - - rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok; - } - } -#endif - else - if (bfd_link_relocatable (info) && ! howto->partial_inplace) - rstat = bfd_reloc_ok; - else - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, - rel->r_vaddr - input_section->vma, - val, addend); - /* Only perform this fix during the final link, not a relocatable link. */ - if (! bfd_link_relocatable (info) - && (rel->r_type == ARM_32 || rel->r_type == ARM_RVA32)) - { - /* Determine if we need to set the bottom bit of a relocated address - because the address is the address of a Thumb code symbol. */ - int patchit = FALSE; - - if (h != NULL - && ( h->symbol_class == C_THUMBSTATFUNC - || h->symbol_class == C_THUMBEXTFUNC)) - { - patchit = TRUE; - } - else if (sym != NULL - && sym->n_scnum > N_UNDEF) - { - /* No hash entry - use the symbol instead. */ - if ( sym->n_sclass == C_THUMBSTATFUNC - || sym->n_sclass == C_THUMBEXTFUNC) - patchit = TRUE; - } - - if (patchit) - { - bfd_byte * location = contents + rel->r_vaddr - input_section->vma; - bfd_vma x = bfd_get_32 (input_bfd, location); - - bfd_put_32 (input_bfd, x | 1, location); - } - } - - switch (rstat) - { - default: - abort (); - case bfd_reloc_ok: - break; - case bfd_reloc_outofrange: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: bad reloc address %#Lx in section `%A'"), - input_bfd, rel->r_vaddr, input_section); - return FALSE; - case bfd_reloc_overflow: - { - const char *name; - char buf[SYMNMLEN + 1]; - - if (symndx == -1) - name = "*ABS*"; - else if (h != NULL) - name = NULL; - else - { - name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); - if (name == NULL) - return FALSE; - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - } - } - - return TRUE; -} - -#ifndef COFF_IMAGE_WITH_PE - -bfd_boolean -bfd_arm_allocate_interworking_sections (struct bfd_link_info * info) -{ - asection * s; - bfd_byte * foo; - struct coff_arm_link_hash_table * globals; - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - - if (globals->arm_glue_size != 0) - { - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_section_by_name - (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - foo = bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size); - - s->size = globals->arm_glue_size; - s->contents = foo; - } - - if (globals->thumb_glue_size != 0) - { - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_section_by_name - (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - foo = bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size); - - s->size = globals->thumb_glue_size; - s->contents = foo; - } - - return TRUE; -} - -static void -record_arm_to_thumb_glue (struct bfd_link_info * info, - struct coff_link_hash_entry * h) -{ - const char * name = h->root.root.string; - register asection * s; - char * tmp_name; - struct coff_link_hash_entry * myh; - struct bfd_link_hash_entry * bh; - struct coff_arm_link_hash_table * globals; - bfd_vma val; - bfd_size_type amt; - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_section_by_name - (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - amt = strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1; - tmp_name = bfd_malloc (amt); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); - - myh = coff_link_hash_lookup - (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); - - if (myh != NULL) - { - free (tmp_name); - /* We've already seen this guy. */ - return; - } - - /* The only trick here is using globals->arm_glue_size as the value. Even - though the section isn't allocated yet, this is where we will be putting - it. */ - bh = NULL; - val = globals->arm_glue_size + 1; - bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, - BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh); - - free (tmp_name); - - globals->arm_glue_size += ARM2THUMB_GLUE_SIZE; - - return; -} - -#ifndef ARM_WINCE -static void -record_thumb_to_arm_glue (struct bfd_link_info * info, - struct coff_link_hash_entry * h) -{ - const char * name = h->root.root.string; - asection * s; - char * tmp_name; - struct coff_link_hash_entry * myh; - struct bfd_link_hash_entry * bh; - struct coff_arm_link_hash_table * globals; - bfd_vma val; - bfd_size_type amt; - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_section_by_name - (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - amt = strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1; - tmp_name = bfd_malloc (amt); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); - - myh = coff_link_hash_lookup - (coff_hash_table (info), tmp_name, FALSE, FALSE, TRUE); - - if (myh != NULL) - { - free (tmp_name); - /* We've already seen this guy. */ - return; - } - - bh = NULL; - val = globals->thumb_glue_size + 1; - bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, - BSF_GLOBAL, s, val, NULL, TRUE, FALSE, &bh); - - /* If we mark it 'thumb', the disassembler will do a better job. */ - myh = (struct coff_link_hash_entry *) bh; - myh->symbol_class = C_THUMBEXTFUNC; - - free (tmp_name); - - /* Allocate another symbol to mark where we switch to arm mode. */ - -#define CHANGE_TO_ARM "__%s_change_to_arm" -#define BACK_FROM_ARM "__%s_back_from_arm" - - amt = strlen (name) + strlen (CHANGE_TO_ARM) + 1; - tmp_name = bfd_malloc (amt); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, globals->support_old_code ? BACK_FROM_ARM : CHANGE_TO_ARM, name); - - bh = NULL; - val = globals->thumb_glue_size + (globals->support_old_code ? 8 : 4); - bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name, - BSF_LOCAL, s, val, NULL, TRUE, FALSE, &bh); - - free (tmp_name); - - globals->thumb_glue_size += THUMB2ARM_GLUE_SIZE; - - return; -} -#endif /* not ARM_WINCE */ - -/* Select a BFD to be used to hold the sections used by the glue code. - This function is called from the linker scripts in ld/emultempl/ - {armcoff/pe}.em */ - -bfd_boolean -bfd_arm_get_bfd_for_interworking (bfd * abfd, - struct bfd_link_info * info) -{ - struct coff_arm_link_hash_table * globals; - flagword flags; - asection * sec; - - /* If we are only performing a partial link do not bother - getting a bfd to hold the glue. */ - if (bfd_link_relocatable (info)) - return TRUE; - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - - if (globals->bfd_of_glue_owner != NULL) - return TRUE; - - sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME); - - if (sec == NULL) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_CODE | SEC_READONLY); - sec = bfd_make_section_with_flags (abfd, ARM2THUMB_GLUE_SECTION_NAME, - flags); - if (sec == NULL - || ! bfd_set_section_alignment (abfd, sec, 2)) - return FALSE; - } - - sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME); - - if (sec == NULL) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_CODE | SEC_READONLY); - sec = bfd_make_section_with_flags (abfd, THUMB2ARM_GLUE_SECTION_NAME, - flags); - - if (sec == NULL - || ! bfd_set_section_alignment (abfd, sec, 2)) - return FALSE; - } - - /* Save the bfd for later use. */ - globals->bfd_of_glue_owner = abfd; - - return TRUE; -} - -bfd_boolean -bfd_arm_process_before_allocation (bfd * abfd, - struct bfd_link_info * info, - int support_old_code) -{ - asection * sec; - struct coff_arm_link_hash_table * globals; - - /* If we are only performing a partial link do not bother - to construct any glue. */ - if (bfd_link_relocatable (info)) - return TRUE; - - /* Here we have a bfd that is to be included on the link. We have a hook - to do reloc rummaging, before section sizes are nailed down. */ - _bfd_coff_get_external_symbols (abfd); - - globals = coff_arm_hash_table (info); - - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - globals->support_old_code = support_old_code; - - /* Rummage around all the relocs and map the glue vectors. */ - sec = abfd->sections; - - if (sec == NULL) - return TRUE; - - for (; sec != NULL; sec = sec->next) - { - struct internal_reloc * i; - struct internal_reloc * rel; - - if (sec->reloc_count == 0) - continue; - - /* Load the relocs. */ - /* FIXME: there may be a storage leak here. */ - i = _bfd_coff_read_internal_relocs (abfd, sec, 1, 0, 0, 0); - - BFD_ASSERT (i != 0); - - for (rel = i; rel < i + sec->reloc_count; ++rel) - { - unsigned short r_type = rel->r_type; - long symndx; - struct coff_link_hash_entry * h; - - symndx = rel->r_symndx; - - /* If the relocation is not against a symbol it cannot concern us. */ - if (symndx == -1) - continue; - - /* If the index is outside of the range of our table, something has gone wrong. */ - if (symndx >= obj_conv_table_size (abfd)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: illegal symbol index in reloc: %ld"), - abfd, symndx); - continue; - } - - h = obj_coff_sym_hashes (abfd)[symndx]; - - /* If the relocation is against a static symbol it must be within - the current section and so cannot be a cross ARM/Thumb relocation. */ - if (h == NULL) - continue; - - switch (r_type) - { - case ARM_26: - /* This one is a call from arm code. We need to look up - the target of the call. If it is a thumb target, we - insert glue. */ - - if (h->symbol_class == C_THUMBEXTFUNC) - record_arm_to_thumb_glue (info, h); - break; - -#ifndef ARM_WINCE - case ARM_THUMB23: - /* This one is a call from thumb code. We used to look - for ARM_THUMB9 and ARM_THUMB12 as well. We need to look - up the target of the call. If it is an arm target, we - insert glue. If the symbol does not exist it will be - given a class of C_EXT and so we will generate a stub - for it. This is not really a problem, since the link - is doomed anyway. */ - - switch (h->symbol_class) - { - case C_EXT: - case C_STAT: - case C_LABEL: - record_thumb_to_arm_glue (info, h); - break; - default: - ; - } - break; -#endif - - default: - break; - } - } - } - - return TRUE; -} - -#endif /* ! defined (COFF_IMAGE_WITH_PE) */ - -#define coff_bfd_reloc_type_lookup coff_arm_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_arm_reloc_name_lookup -#define coff_relocate_section coff_arm_relocate_section -#define coff_bfd_is_local_label_name coff_arm_is_local_label_name -#define coff_adjust_symndx coff_arm_adjust_symndx -#define coff_link_output_has_begun coff_arm_link_output_has_begun -#define coff_final_link_postscript coff_arm_final_link_postscript -#define coff_bfd_merge_private_bfd_data coff_arm_merge_private_bfd_data -#define coff_bfd_print_private_bfd_data coff_arm_print_private_bfd_data -#define coff_bfd_set_private_flags _bfd_coff_arm_set_private_flags -#define coff_bfd_copy_private_bfd_data coff_arm_copy_private_bfd_data -#define coff_bfd_link_hash_table_create coff_arm_link_hash_table_create - -/* When doing a relocatable link, we want to convert ARM_26 relocs - into ARM_26D relocs. */ - -static bfd_boolean -coff_arm_adjust_symndx (bfd *obfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *ibfd, - asection *sec, - struct internal_reloc *irel, - bfd_boolean *adjustedp) -{ - if (irel->r_type == ARM_26) - { - struct coff_link_hash_entry *h; - - h = obj_coff_sym_hashes (ibfd)[irel->r_symndx]; - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section == sec->output_section) - irel->r_type = ARM_26D; - } - *adjustedp = FALSE; - return TRUE; -} - -/* Called when merging the private data areas of two BFDs. - This is important as it allows us to detect if we are - attempting to merge binaries compiled for different ARM - targets, eg different CPUs or different APCS's. */ - -static bfd_boolean -coff_arm_merge_private_bfd_data (bfd * ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - BFD_ASSERT (ibfd != NULL && obfd != NULL); - - if (ibfd == obfd) - return TRUE; - - /* If the two formats are different we cannot merge anything. - This is not an error, since it is permissable to change the - input and output formats. */ - if ( ibfd->xvec->flavour != bfd_target_coff_flavour - || obfd->xvec->flavour != bfd_target_coff_flavour) - return TRUE; - - /* Determine what should happen if the input ARM architecture - does not match the output ARM architecture. */ - if (! bfd_arm_merge_machines (ibfd, obfd)) - return FALSE; - - /* Verify that the APCS is the same for the two BFDs. */ - if (APCS_SET (ibfd)) - { - if (APCS_SET (obfd)) - { - /* If the src and dest have different APCS flag bits set, fail. */ - if (APCS_26_FLAG (obfd) != APCS_26_FLAG (ibfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("error: %B is compiled for APCS-%d, whereas %B is compiled for APCS-%d"), - ibfd, APCS_26_FLAG (ibfd) ? 26 : 32, - obfd, APCS_26_FLAG (obfd) ? 26 : 32 - ); - - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - if (APCS_FLOAT_FLAG (obfd) != APCS_FLOAT_FLAG (ibfd)) - { - if (APCS_FLOAT_FLAG (ibfd)) - /* xgettext: c-format */ - _bfd_error_handler (_("\ -error: %B passes floats in float registers, whereas %B passes them in integer registers"), - ibfd, obfd); - else - /* xgettext: c-format */ - _bfd_error_handler (_("\ -error: %B passes floats in integer registers, whereas %B passes them in float registers"), - ibfd, obfd); - - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - if (PIC_FLAG (obfd) != PIC_FLAG (ibfd)) - { - if (PIC_FLAG (ibfd)) - /* xgettext: c-format */ - _bfd_error_handler (_("\ -error: %B is compiled as position independent code, whereas target %B is absolute position"), - ibfd, obfd); - else - /* xgettext: c-format */ - _bfd_error_handler (_("\ -error: %B is compiled as absolute position code, whereas target %B is position independent"), - ibfd, obfd); - - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - } - else - { - SET_APCS_FLAGS (obfd, APCS_26_FLAG (ibfd) | APCS_FLOAT_FLAG (ibfd) | PIC_FLAG (ibfd)); - - /* Set up the arch and fields as well as these are probably wrong. */ - bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); - } - } - - /* Check the interworking support. */ - if (INTERWORK_SET (ibfd)) - { - if (INTERWORK_SET (obfd)) - { - /* If the src and dest differ in their interworking issue a warning. */ - if (INTERWORK_FLAG (obfd) != INTERWORK_FLAG (ibfd)) - { - if (INTERWORK_FLAG (ibfd)) - /* xgettext: c-format */ - _bfd_error_handler (_("\ -Warning: %B supports interworking, whereas %B does not"), - ibfd, obfd); - else - /* xgettext: c-format */ - _bfd_error_handler (_("\ -Warning: %B does not support interworking, whereas %B does"), - ibfd, obfd); - } - } - else - { - SET_INTERWORK_FLAG (obfd, INTERWORK_FLAG (ibfd)); - } - } - - return TRUE; -} - -/* Display the flags field. */ - -static bfd_boolean -coff_arm_print_private_bfd_data (bfd * abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - fprintf (file, _("private flags = %x:"), coff_data (abfd)->flags); - - if (APCS_SET (abfd)) - { - /* xgettext: APCS is ARM Procedure Call Standard, it should not be translated. */ - fprintf (file, " [APCS-%d]", APCS_26_FLAG (abfd) ? 26 : 32); - - if (APCS_FLOAT_FLAG (abfd)) - fprintf (file, _(" [floats passed in float registers]")); - else - fprintf (file, _(" [floats passed in integer registers]")); - - if (PIC_FLAG (abfd)) - fprintf (file, _(" [position independent]")); - else - fprintf (file, _(" [absolute position]")); - } - - if (! INTERWORK_SET (abfd)) - fprintf (file, _(" [interworking flag not initialised]")); - else if (INTERWORK_FLAG (abfd)) - fprintf (file, _(" [interworking supported]")); - else - fprintf (file, _(" [interworking not supported]")); - - fputc ('\n', file); - - return TRUE; -} - -/* Copies the given flags into the coff_tdata.flags field. - Typically these flags come from the f_flags[] field of - the COFF filehdr structure, which contains important, - target specific information. - Note: Although this function is static, it is explicitly - called from both coffcode.h and peicode.h. */ - -static bfd_boolean -_bfd_coff_arm_set_private_flags (bfd * abfd, flagword flags) -{ - flagword flag; - - BFD_ASSERT (abfd != NULL); - - flag = (flags & F_APCS26) ? F_APCS_26 : 0; - - /* Make sure that the APCS field has not been initialised to the opposite - value. */ - if (APCS_SET (abfd) - && ( (APCS_26_FLAG (abfd) != flag) - || (APCS_FLOAT_FLAG (abfd) != (flags & F_APCS_FLOAT)) - || (PIC_FLAG (abfd) != (flags & F_PIC)) - )) - return FALSE; - - flag |= (flags & (F_APCS_FLOAT | F_PIC)); - - SET_APCS_FLAGS (abfd, flag); - - flag = (flags & F_INTERWORK); - - /* If the BFD has already had its interworking flag set, but it - is different from the value that we have been asked to set, - then assume that that merged code will not support interworking - and set the flag accordingly. */ - if (INTERWORK_SET (abfd) && (INTERWORK_FLAG (abfd) != flag)) - { - if (flag) - _bfd_error_handler (_("Warning: Not setting interworking flag of %B since it has already been specified as non-interworking"), - abfd); - else - _bfd_error_handler (_("Warning: Clearing the interworking flag of %B due to outside request"), - abfd); - flag = 0; - } - - SET_INTERWORK_FLAG (abfd, flag); - - return TRUE; -} - -/* Copy the important parts of the target specific data - from one instance of a BFD to another. */ - -static bfd_boolean -coff_arm_copy_private_bfd_data (bfd * src, bfd * dest) -{ - BFD_ASSERT (src != NULL && dest != NULL); - - if (src == dest) - return TRUE; - - /* If the destination is not in the same format as the source, do not do - the copy. */ - if (src->xvec != dest->xvec) - return TRUE; - - /* Copy the flags field. */ - if (APCS_SET (src)) - { - if (APCS_SET (dest)) - { - /* If the src and dest have different APCS flag bits set, fail. */ - if (APCS_26_FLAG (dest) != APCS_26_FLAG (src)) - return FALSE; - - if (APCS_FLOAT_FLAG (dest) != APCS_FLOAT_FLAG (src)) - return FALSE; - - if (PIC_FLAG (dest) != PIC_FLAG (src)) - return FALSE; - } - else - SET_APCS_FLAGS (dest, APCS_26_FLAG (src) | APCS_FLOAT_FLAG (src) - | PIC_FLAG (src)); - } - - if (INTERWORK_SET (src)) - { - if (INTERWORK_SET (dest)) - { - /* If the src and dest have different interworking flags then turn - off the interworking bit. */ - if (INTERWORK_FLAG (dest) != INTERWORK_FLAG (src)) - { - if (INTERWORK_FLAG (dest)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("\ -Warning: Clearing the interworking flag of %B because non-interworking code in %B has been linked with it"), - dest, src); - } - - SET_INTERWORK_FLAG (dest, 0); - } - } - else - { - SET_INTERWORK_FLAG (dest, INTERWORK_FLAG (src)); - } - } - - return TRUE; -} - -/* Note: the definitions here of LOCAL_LABEL_PREFIX and USER_LABEL_PREIFX - *must* match the definitions in gcc/config/arm/{coff|semi|aout}.h. */ -#ifndef LOCAL_LABEL_PREFIX -#define LOCAL_LABEL_PREFIX "" -#endif -#ifndef USER_LABEL_PREFIX -#define USER_LABEL_PREFIX "_" -#endif - -/* Like _bfd_coff_is_local_label_name, but - a) test against USER_LABEL_PREFIX, to avoid stripping labels known to be - non-local. - b) Allow other prefixes than ".", e.g. an empty prefix would cause all - labels of the form Lxxx to be stripped. */ - -static bfd_boolean -coff_arm_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED, - const char * name) -{ -#ifdef USER_LABEL_PREFIX - if (USER_LABEL_PREFIX[0] != 0) - { - size_t len = strlen (USER_LABEL_PREFIX); - - if (strncmp (name, USER_LABEL_PREFIX, len) == 0) - return FALSE; - } -#endif - -#ifdef LOCAL_LABEL_PREFIX - /* If there is a prefix for local labels then look for this. - If the prefix exists, but it is empty, then ignore the test. */ - - if (LOCAL_LABEL_PREFIX[0] != 0) - { - size_t len = strlen (LOCAL_LABEL_PREFIX); - - if (strncmp (name, LOCAL_LABEL_PREFIX, len) != 0) - return FALSE; - - /* Perform the checks below for the rest of the name. */ - name += len; - } -#endif - - return name[0] == 'L'; -} - -/* This piece of machinery exists only to guarantee that the bfd that holds - the glue section is written last. - - This does depend on bfd_make_section attaching a new section to the - end of the section list for the bfd. */ - -static bfd_boolean -coff_arm_link_output_has_begun (bfd * sub, struct coff_final_link_info * info) -{ - return (sub->output_has_begun - || sub == coff_arm_hash_table (info->info)->bfd_of_glue_owner); -} - -static bfd_boolean -coff_arm_final_link_postscript (bfd * abfd ATTRIBUTE_UNUSED, - struct coff_final_link_info * pfinfo) -{ - struct coff_arm_link_hash_table * globals; - - globals = coff_arm_hash_table (pfinfo->info); - - BFD_ASSERT (globals != NULL); - - if (globals->bfd_of_glue_owner != NULL) - { - if (! _bfd_coff_link_input_bfd (pfinfo, globals->bfd_of_glue_owner)) - return FALSE; - - globals->bfd_of_glue_owner->output_has_begun = TRUE; - } - - return bfd_arm_update_notes (abfd, ARM_NOTE_SECTION); -} - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#ifndef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM arm_coff_le_vec -#endif -#ifndef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "coff-arm-little" -#endif -#ifndef TARGET_BIG_SYM -#define TARGET_BIG_SYM arm_coff_be_vec -#endif -#ifndef TARGET_BIG_NAME -#define TARGET_BIG_NAME "coff-arm-big" -#endif - -#ifndef TARGET_UNDERSCORE -#define TARGET_UNDERSCORE 0 -#endif - -#ifndef EXTRA_S_FLAGS -#ifdef COFF_WITH_PE -#define EXTRA_S_FLAGS (SEC_CODE | SEC_LINK_ONCE | SEC_LINK_DUPLICATES) -#else -#define EXTRA_S_FLAGS SEC_CODE -#endif -#endif - -/* Forward declaration for use initialising alternative_target field. */ -extern const bfd_target TARGET_BIG_SYM ; - -/* Target vectors. */ -CREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_BIG_SYM, COFF_SWAP_TABLE) -CREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_LITTLE_SYM, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-aux.c b/sdcc/support/sdbinutils/bfd/coff-aux.c deleted file mode 100644 index f55e6e0b5..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-aux.c +++ /dev/null @@ -1,145 +0,0 @@ -/* BFD back-end for Apple M68K COFF A/UX 3.x files. - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Written by Richard Henderson . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGET_SYM m68k_coff_aux_vec -#define TARGET_NAME "coff-m68k-aux" - -#ifndef TARG_AUX -#define TARG_AUX -#endif - -#define COFF_LONG_FILENAMES - -/* 4k pages */ -#define COFF_PAGE_SIZE 0x1000 - -/* On AUX, a STYP_NOLOAD|STYP_BSS section is part of a shared library. */ -#define BSS_NOLOAD_IS_SHARED_LIBRARY - -#define STATIC_RELOCS - -#define COFF_COMMON_ADDEND - -#include "sysdep.h" -#include "bfd.h" - -#define coff_link_add_one_symbol coff_m68k_aux_link_add_one_symbol -static bfd_boolean -coff_m68k_aux_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 **); - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coff/aux-coff.h" /* override coff/internal.h and coff/m68k.h */ -#include "coff-m68k.c" - -/* We need non-absolute symbols to override absolute symbols. This - mirrors Apple's "solution" to let a static library symbol override - a shared library symbol. On the whole not a good thing, given how - shared libraries work here, but can work if you are careful with - what you include in the shared object. */ - -static bfd_boolean -coff_m68k_aux_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) -{ - struct bfd_link_hash_entry *h, *inh, *t; - - if ((flags & (BSF_WARNING | BSF_CONSTRUCTOR | BSF_WEAK)) == 0 - && !bfd_is_und_section (section) - && !bfd_is_com_section (section)) - { - /* The new symbol is a definition or an indirect definition */ - - /* This bit copied from linker.c */ - if (hashp != NULL && *hashp != NULL) - h = *hashp; - else - { - h = bfd_link_hash_lookup (info->hash, name, TRUE, copy, FALSE); - if (h == NULL) - { - if (hashp != NULL) - *hashp = NULL; - return FALSE; - } - } - - if (hashp != (struct bfd_link_hash_entry **) NULL) - *hashp = h; - /* end duplication from linker.c */ - - t = h; - inh = NULL; - if (h->type == bfd_link_hash_indirect) - { - inh = h->u.i.link; - t = inh; - } - - if (t->type == bfd_link_hash_defined) - { - asection *msec = t->u.def.section; - bfd_boolean special = FALSE; - - if (bfd_is_abs_section (msec) && !bfd_is_abs_section (section)) - { - t->u.def.section = section; - t->u.def.value = value; - special = TRUE; - } - else if (bfd_is_abs_section (section) && !bfd_is_abs_section (msec)) - special = TRUE; - - if (special) - { - if (info->notice_all - || (info->notice_hash != NULL - && bfd_hash_lookup (info->notice_hash, name, - FALSE, FALSE) != NULL)) - { - if (!(*info->callbacks->notice) (info, h, inh, - abfd, section, value, flags)) - return FALSE; - } - - return TRUE; - } - } - } - - /* If we didn't exit early, finish processing in the generic routine */ - return _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, - value, string, copy, collect, - hashp); -} diff --git a/sdcc/support/sdbinutils/bfd/coff-go32.c b/sdcc/support/sdbinutils/bfd/coff-go32.c deleted file mode 100644 index e61e25647..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-go32.c +++ /dev/null @@ -1,45 +0,0 @@ -/* BFD back-end for Intel 386 COFF files (DJGPP variant). - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by DJ Delorie. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGET_SYM i386_coff_go32_vec -#define TARGET_NAME "coff-go32" -#define TARGET_UNDERSCORE '_' -#define COFF_LONG_SECTION_NAMES -#define COFF_SUPPORT_GNU_LINKONCE -#define COFF_LONG_FILENAMES - -#define COFF_SECTION_ALIGNMENT_ENTRIES \ -{ COFF_SECTION_NAME_EXACT_MATCH (".data"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".text"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.d"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.t"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.r"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } - -#include "coff-i386.c" diff --git a/sdcc/support/sdbinutils/bfd/coff-h8300.c b/sdcc/support/sdbinutils/bfd/coff-h8300.c deleted file mode 100644 index 3adcf5e76..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-h8300.c +++ /dev/null @@ -1,1387 +0,0 @@ -/* BFD back-end for Renesas H8/300 COFF binaries. - Copyright (C) 1990-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "genlink.h" -#include "coff/h8300.h" -#include "coff/internal.h" -#include "libcoff.h" -#include "libiberty.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) - -/* We derive a hash table from the basic BFD hash table to - hold entries in the function vector. Aside from the - info stored by the basic hash table, we need the offset - of a particular entry within the hash table as well as - the offset where we'll add the next entry. */ - -struct funcvec_hash_entry - { - /* The basic hash table entry. */ - struct bfd_hash_entry root; - - /* The offset within the vectors section where - this entry lives. */ - bfd_vma offset; - }; - -struct funcvec_hash_table - { - /* The basic hash table. */ - struct bfd_hash_table root; - - bfd *abfd; - - /* Offset at which we'll add the next entry. */ - unsigned int offset; - }; - - -/* To lookup a value in the function vector hash table. */ -#define funcvec_hash_lookup(table, string, create, copy) \ - ((struct funcvec_hash_entry *) \ - bfd_hash_lookup (&(table)->root, (string), (create), (copy))) - -/* The derived h8300 COFF linker table. Note it's derived from - the generic linker hash table, not the COFF backend linker hash - table! We use this to attach additional data structures we - need while linking on the h8300. */ -struct h8300_coff_link_hash_table { - /* The main hash table. */ - struct generic_link_hash_table root; - - /* Section for the vectors table. This gets attached to a - random input bfd, we keep it here for easy access. */ - asection *vectors_sec; - - /* Hash table of the functions we need to enter into the function - vector. */ - struct funcvec_hash_table *funcvec_hash_table; -}; - -static struct bfd_link_hash_table *h8300_coff_link_hash_table_create (bfd *); - -/* Get the H8/300 COFF linker hash table from a link_info structure. */ - -#define h8300_coff_hash_table(p) \ - ((struct h8300_coff_link_hash_table *) ((coff_hash_table (p)))) - -/* Initialize fields within a funcvec hash table entry. Called whenever - a new entry is added to the funcvec hash table. */ - -static struct bfd_hash_entry * -funcvec_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *gen_table, - const char *string) -{ - struct funcvec_hash_entry *ret; - struct funcvec_hash_table *table; - - ret = (struct funcvec_hash_entry *) entry; - table = (struct funcvec_hash_table *) gen_table; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = ((struct funcvec_hash_entry *) - bfd_hash_allocate (gen_table, - sizeof (struct funcvec_hash_entry))); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct funcvec_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, gen_table, string)); - - if (ret == NULL) - return NULL; - - /* Note where this entry will reside in the function vector table. */ - ret->offset = table->offset; - - /* Bump the offset at which we store entries in the function - vector. We'd like to bump up the size of the vectors section, - but it's not easily available here. */ - switch (bfd_get_mach (table->abfd)) - { - case bfd_mach_h8300: - case bfd_mach_h8300hn: - case bfd_mach_h8300sn: - table->offset += 2; - break; - case bfd_mach_h8300h: - case bfd_mach_h8300s: - table->offset += 4; - break; - default: - return NULL; - } - - /* Everything went OK. */ - return (struct bfd_hash_entry *) ret; -} - -/* Initialize the function vector hash table. */ - -static bfd_boolean -funcvec_hash_table_init (struct funcvec_hash_table *table, - bfd *abfd, - struct bfd_hash_entry *(*newfunc) - (struct bfd_hash_entry *, - struct bfd_hash_table *, - const char *), - unsigned int entsize) -{ - /* Initialize our local fields, then call the generic initialization - routine. */ - table->offset = 0; - table->abfd = abfd; - return (bfd_hash_table_init (&table->root, newfunc, entsize)); -} - -/* Create the derived linker hash table. We use a derived hash table - basically to hold "static" information during an H8/300 coff link - without using static variables. */ - -static struct bfd_link_hash_table * -h8300_coff_link_hash_table_create (bfd *abfd) -{ - struct h8300_coff_link_hash_table *ret; - bfd_size_type amt = sizeof (struct h8300_coff_link_hash_table); - - ret = (struct h8300_coff_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - if (!_bfd_link_hash_table_init (&ret->root.root, abfd, - _bfd_generic_link_hash_newfunc, - sizeof (struct generic_link_hash_entry))) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -/* Special handling for H8/300 relocs. - We only come here for pcrel stuff and return normally if not an -r link. - When doing -r, we can't do any arithmetic for the pcrel stuff, because - the code in reloc.c assumes that we can manipulate the targets of - the pcrel branches. This isn't so, since the H8/300 can do relaxing, - which means that the gap after the instruction may not be enough to - contain the offset required for the branch, so we have to use only - the addend until the final link. */ - -static bfd_reloc_status_type -special (bfd * abfd ATTRIBUTE_UNUSED, - arelent * reloc_entry ATTRIBUTE_UNUSED, - asymbol * symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection * input_section ATTRIBUTE_UNUSED, - bfd * output_bfd, - char ** error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - /* Adjust the reloc address to that in the output section. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -static reloc_howto_type howto_table[] = -{ - HOWTO (R_RELBYTE, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, special, "8", FALSE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_RELWORD, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, special, "16", FALSE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (R_RELLONG, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, special, "32", FALSE, 0xffffffff, 0xffffffff, FALSE), - HOWTO (R_PCRBYTE, 0, 0, 8, TRUE, 0, complain_overflow_signed, special, "DISP8", FALSE, 0x000000ff, 0x000000ff, TRUE), - HOWTO (R_PCRWORD, 0, 1, 16, TRUE, 0, complain_overflow_signed, special, "DISP16", FALSE, 0x0000ffff, 0x0000ffff, TRUE), - HOWTO (R_PCRLONG, 0, 2, 32, TRUE, 0, complain_overflow_signed, special, "DISP32", FALSE, 0xffffffff, 0xffffffff, TRUE), - HOWTO (R_MOV16B1, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, special, "relaxable mov.b:16", FALSE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (R_MOV16B2, 0, 1, 8, FALSE, 0, complain_overflow_bitfield, special, "relaxed mov.b:16", FALSE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_JMP1, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, special, "16/pcrel", FALSE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (R_JMP2, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, special, "pcrecl/16", FALSE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_JMPL1, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, special, "24/pcrell", FALSE, 0x00ffffff, 0x00ffffff, FALSE), - HOWTO (R_JMPL2, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, special, "pc8/24", FALSE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_MOV24B1, 0, 1, 32, FALSE, 0, complain_overflow_bitfield, special, "relaxable mov.b:24", FALSE, 0xffffffff, 0xffffffff, FALSE), - HOWTO (R_MOV24B2, 0, 1, 8, FALSE, 0, complain_overflow_bitfield, special, "relaxed mov.b:24", FALSE, 0x0000ffff, 0x0000ffff, FALSE), - - /* An indirect reference to a function. This causes the function's address - to be added to the function vector in lo-mem and puts the address of - the function vector's entry in the jsr instruction. */ - HOWTO (R_MEM_INDIRECT, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, special, "8/indirect", FALSE, 0x000000ff, 0x000000ff, FALSE), - - /* Internal reloc for relaxing. This is created when a 16-bit pc-relative - branch is turned into an 8-bit pc-relative branch. */ - HOWTO (R_PCRWORD_B, 0, 0, 8, TRUE, 0, complain_overflow_bitfield, special, "relaxed bCC:16", FALSE, 0x000000ff, 0x000000ff, FALSE), - - HOWTO (R_MOVL1, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,special, "32/24 relaxable move", FALSE, 0xffffffff, 0xffffffff, FALSE), - - HOWTO (R_MOVL2, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, special, "32/24 relaxed move", FALSE, 0x0000ffff, 0x0000ffff, FALSE), - - HOWTO (R_BCC_INV, 0, 0, 8, TRUE, 0, complain_overflow_signed, special, "DISP8 inverted", FALSE, 0x000000ff, 0x000000ff, TRUE), - - HOWTO (R_JMP_DEL, 0, 0, 8, TRUE, 0, complain_overflow_signed, special, "Deleted jump", FALSE, 0x000000ff, 0x000000ff, TRUE), -}; - -/* Turn a howto into a reloc number. */ - -#define SELECT_RELOC(x,howto) \ - { x.r_type = select_reloc (howto); } - -#define BADMAG(x) (H8300BADMAG (x) && H8300HBADMAG (x) && H8300SBADMAG (x) \ - && H8300HNBADMAG(x) && H8300SNBADMAG(x)) -#define H8300 1 /* Customize coffcode.h */ -#define __A_MAGIC_SET__ - -/* Code to swap in the reloc. */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ - dst->r_stuff[0] = 'S'; \ - dst->r_stuff[1] = 'C'; - -static int -select_reloc (reloc_howto_type *howto) -{ - return howto->type; -} - -/* Code to turn a r_type into a howto ptr, uses the above howto table. */ - -static void -rtype2howto (arelent *internal, struct internal_reloc *dst) -{ - switch (dst->r_type) - { - case R_RELBYTE: - internal->howto = howto_table + 0; - break; - case R_RELWORD: - internal->howto = howto_table + 1; - break; - case R_RELLONG: - internal->howto = howto_table + 2; - break; - case R_PCRBYTE: - internal->howto = howto_table + 3; - break; - case R_PCRWORD: - internal->howto = howto_table + 4; - break; - case R_PCRLONG: - internal->howto = howto_table + 5; - break; - case R_MOV16B1: - internal->howto = howto_table + 6; - break; - case R_MOV16B2: - internal->howto = howto_table + 7; - break; - case R_JMP1: - internal->howto = howto_table + 8; - break; - case R_JMP2: - internal->howto = howto_table + 9; - break; - case R_JMPL1: - internal->howto = howto_table + 10; - break; - case R_JMPL2: - internal->howto = howto_table + 11; - break; - case R_MOV24B1: - internal->howto = howto_table + 12; - break; - case R_MOV24B2: - internal->howto = howto_table + 13; - break; - case R_MEM_INDIRECT: - internal->howto = howto_table + 14; - break; - case R_PCRWORD_B: - internal->howto = howto_table + 15; - break; - case R_MOVL1: - internal->howto = howto_table + 16; - break; - case R_MOVL2: - internal->howto = howto_table + 17; - break; - case R_BCC_INV: - internal->howto = howto_table + 18; - break; - case R_JMP_DEL: - internal->howto = howto_table + 19; - break; - default: - internal->howto = NULL; - break; - } -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry) - -/* Perform any necessary magic to the addend in a reloc entry. */ - -#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ - cache_ptr->addend = ext_reloc.r_offset; - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing (relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent *relent, struct internal_reloc *reloc, - asymbol **symbols, bfd *abfd, asection *section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (((int) reloc->r_symndx) > 0) - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - else - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - relent->addend = reloc->r_offset; - relent->address -= section->vma; -} - -static bfd_boolean -h8300_symbol_address_p (bfd *abfd, asection *input_section, bfd_vma address) -{ - asymbol **s; - - s = _bfd_generic_link_get_symbols (abfd); - BFD_ASSERT (s != (asymbol **) NULL); - - /* Search all the symbols for one in INPUT_SECTION with - address ADDRESS. */ - while (*s) - { - asymbol *p = *s; - - if (p->section == input_section - && (input_section->output_section->vma - + input_section->output_offset - + p->value) == address) - return TRUE; - s++; - } - return FALSE; -} - -/* If RELOC represents a relaxable instruction/reloc, change it into - the relaxed reloc, notify the linker that symbol addresses - have changed (bfd_perform_slip) and return how much the current - section has shrunk by. - - FIXME: Much of this code has knowledge of the ordering of entries - in the howto table. This needs to be fixed. */ - -static int -h8300_reloc16_estimate (bfd *abfd, asection *input_section, arelent *reloc, - unsigned int shrink, struct bfd_link_info *link_info) -{ - bfd_vma value; - bfd_vma dot; - bfd_vma gap; - static asection *last_input_section = NULL; - static arelent *last_reloc = NULL; - - /* The address of the thing to be relocated will have moved back by - the size of the shrink - but we don't change reloc->address here, - since we need it to know where the relocation lives in the source - uncooked section. */ - bfd_vma address = reloc->address - shrink; - - if (input_section != last_input_section) - last_reloc = NULL; - - /* Only examine the relocs which might be relaxable. */ - switch (reloc->howto->type) - { - /* This is the 16-/24-bit absolute branch which could become an - 8-bit pc-relative branch. */ - case R_JMP1: - case R_JMPL1: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* Get the address of the next instruction (not the reloc). */ - dot = (input_section->output_section->vma - + input_section->output_offset + address); - - /* Adjust for R_JMP1 vs R_JMPL1. */ - dot += (reloc->howto->type == R_JMP1 ? 1 : 2); - - /* Compute the distance from this insn to the branch target. */ - gap = value - dot; - - /* If the distance is within -128..+128 inclusive, then we can relax - this jump. +128 is valid since the target will move two bytes - closer if we do relax this branch. */ - if ((int) gap >= -128 && (int) gap <= 128) - { - bfd_byte code; - - if (!bfd_get_section_contents (abfd, input_section, & code, - reloc->address, 1)) - break; - code = bfd_get_8 (abfd, & code); - - /* It's possible we may be able to eliminate this branch entirely; - if the previous instruction is a branch around this instruction, - and there's no label at this instruction, then we can reverse - the condition on the previous branch and eliminate this jump. - - original: new: - bCC lab1 bCC' lab2 - jmp lab2 - lab1: lab1: - - This saves 4 bytes instead of two, and should be relatively - common. - - Only perform this optimisation for jumps (code 0x5a) not - subroutine calls, as otherwise it could transform: - - mov.w r0,r0 - beq .L1 - jsr @_bar - .L1: rts - _bar: rts - into: - mov.w r0,r0 - bne _bar - rts - _bar: rts - - which changes the call (jsr) into a branch (bne). */ - if (code == 0x5a - && gap <= 126 - && last_reloc - && last_reloc->howto->type == R_PCRBYTE) - { - bfd_vma last_value; - last_value = bfd_coff_reloc16_get_value (last_reloc, link_info, - input_section) + 1; - - if (last_value == dot + 2 - && last_reloc->address + 1 == reloc->address - && !h8300_symbol_address_p (abfd, input_section, dot - 2)) - { - reloc->howto = howto_table + 19; - last_reloc->howto = howto_table + 18; - last_reloc->sym_ptr_ptr = reloc->sym_ptr_ptr; - last_reloc->addend = reloc->addend; - shrink += 4; - bfd_perform_slip (abfd, 4, input_section, address); - break; - } - } - - /* Change the reloc type. */ - reloc->howto = reloc->howto + 1; - - /* This shrinks this section by two bytes. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - break; - - /* This is the 16-bit pc-relative branch which could become an 8-bit - pc-relative branch. */ - case R_PCRWORD: - /* Get the address of the target of this branch, add one to the value - because the addend field in PCrel jumps is off by -1. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section) + 1; - - /* Get the address of the next instruction if we were to relax. */ - dot = input_section->output_section->vma + - input_section->output_offset + address; - - /* Compute the distance from this insn to the branch target. */ - gap = value - dot; - - /* If the distance is within -128..+128 inclusive, then we can relax - this jump. +128 is valid since the target will move two bytes - closer if we do relax this branch. */ - if ((int) gap >= -128 && (int) gap <= 128) - { - /* Change the reloc type. */ - reloc->howto = howto_table + 15; - - /* This shrinks this section by two bytes. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - break; - - /* This is a 16-bit absolute address in a mov.b insn, which can - become an 8-bit absolute address if it's in the right range. */ - case R_MOV16B1: - /* Get the address of the data referenced by this mov.b insn. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - value = bfd_h8300_pad_address (abfd, value); - - /* If the address is in the top 256 bytes of the address space - then we can relax this instruction. */ - if (value >= 0xffffff00u) - { - /* Change the reloc type. */ - reloc->howto = reloc->howto + 1; - - /* This shrinks this section by two bytes. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - break; - - /* Similarly for a 24-bit absolute address in a mov.b. Note that - if we can't relax this into an 8-bit absolute, we'll fall through - and try to relax it into a 16-bit absolute. */ - case R_MOV24B1: - /* Get the address of the data referenced by this mov.b insn. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - value = bfd_h8300_pad_address (abfd, value); - - if (value >= 0xffffff00u) - { - /* Change the reloc type. */ - reloc->howto = reloc->howto + 1; - - /* This shrinks this section by four bytes. */ - shrink += 4; - bfd_perform_slip (abfd, 4, input_section, address); - - /* Done with this reloc. */ - break; - } - /* Fall through. */ - - /* This is a 24-/32-bit absolute address in a mov insn, which can - become an 16-bit absolute address if it's in the right range. */ - case R_MOVL1: - /* Get the address of the data referenced by this mov insn. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - value = bfd_h8300_pad_address (abfd, value); - - /* If the address is a sign-extended 16-bit value then we can - relax this instruction. */ - if (value <= 0x7fff || value >= 0xffff8000u) - { - /* Change the reloc type. */ - reloc->howto = howto_table + 17; - - /* This shrinks this section by two bytes. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - break; - - /* No other reloc types represent relaxing opportunities. */ - default: - break; - } - - last_reloc = reloc; - last_input_section = input_section; - return shrink; -} - -/* Handle relocations for the H8/300, including relocs for relaxed - instructions. - - FIXME: Not all relocations check for overflow! */ - -static void -h8300_reloc16_extra_cases (bfd *abfd, struct bfd_link_info *link_info, - struct bfd_link_order *link_order, arelent *reloc, - bfd_byte *data, unsigned int *src_ptr, - unsigned int *dst_ptr) -{ - unsigned int src_address = *src_ptr; - unsigned int dst_address = *dst_ptr; - asection *input_section = link_order->u.indirect.section; - bfd_vma value; - bfd_vma dot; - int gap, tmp; - unsigned char temp_code; - - switch (reloc->howto->type) - { - /* Generic 8-bit pc-relative relocation. */ - case R_PCRBYTE: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - dot = (input_section->output_offset - + dst_address - + link_order->u.indirect.section->output_section->vma); - - gap = value - dot; - - /* Sanity check. */ - if (gap < -128 || gap > 126) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - /* Everything looks OK. Apply the relocation and update the - src/dst address appropriately. */ - bfd_put_8 (abfd, gap, data + dst_address); - dst_address++; - src_address++; - - /* All done. */ - break; - - /* Generic 16-bit pc-relative relocation. */ - case R_PCRWORD: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* Get the address of the instruction (not the reloc). */ - dot = (input_section->output_offset - + dst_address - + link_order->u.indirect.section->output_section->vma + 1); - - gap = value - dot; - - /* Sanity check. */ - if (gap > 32766 || gap < -32768) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - /* Everything looks OK. Apply the relocation and update the - src/dst address appropriately. */ - bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); - dst_address += 2; - src_address += 2; - - /* All done. */ - break; - - /* Generic 8-bit absolute relocation. */ - case R_RELBYTE: - /* Get the address of the object referenced by this insn. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - bfd_put_8 (abfd, value & 0xff, data + dst_address); - dst_address += 1; - src_address += 1; - - /* All done. */ - break; - - /* Various simple 16-bit absolute relocations. */ - case R_MOV16B1: - case R_JMP1: - case R_RELWORD: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_16 (abfd, value, data + dst_address); - dst_address += 2; - src_address += 2; - break; - - /* Various simple 24-/32-bit absolute relocations. */ - case R_MOV24B1: - case R_MOVL1: - case R_RELLONG: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_32 (abfd, value, data + dst_address); - dst_address += 4; - src_address += 4; - break; - - /* Another 24-/32-bit absolute relocation. */ - case R_JMPL1: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - value = ((value & 0x00ffffff) - | (bfd_get_32 (abfd, data + src_address) & 0xff000000)); - bfd_put_32 (abfd, value, data + dst_address); - dst_address += 4; - src_address += 4; - break; - - /* This is a 24-/32-bit absolute address in one of the following - instructions: - - "band", "bclr", "biand", "bild", "bior", "bist", "bixor", - "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", "ldc.w", - "stc.w" and "mov.[bwl]" - - We may relax this into an 16-bit absolute address if it's in - the right range. */ - case R_MOVL2: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - value = bfd_h8300_pad_address (abfd, value); - - /* Sanity check. */ - if (value <= 0x7fff || value >= 0xffff8000u) - { - /* Insert the 16-bit value into the proper location. */ - bfd_put_16 (abfd, value, data + dst_address); - - /* Fix the opcode. For all the instructions that belong to - this relaxation, we simply need to turn off bit 0x20 in - the previous byte. */ - data[dst_address - 1] &= ~0x20; - dst_address += 2; - src_address += 4; - } - else - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - break; - - /* A 16-bit absolute branch that is now an 8-bit pc-relative branch. */ - case R_JMP2: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* Get the address of the next instruction. */ - dot = (input_section->output_offset - + dst_address - + link_order->u.indirect.section->output_section->vma + 1); - - gap = value - dot; - - /* Sanity check. */ - if (gap < -128 || gap > 126) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - /* Now fix the instruction itself. */ - switch (data[dst_address - 1]) - { - case 0x5e: - /* jsr -> bsr */ - bfd_put_8 (abfd, 0x55, data + dst_address - 1); - break; - case 0x5a: - /* jmp -> bra */ - bfd_put_8 (abfd, 0x40, data + dst_address - 1); - break; - - default: - abort (); - } - - /* Write out the 8-bit value. */ - bfd_put_8 (abfd, gap, data + dst_address); - - dst_address += 1; - src_address += 3; - - break; - - /* A 16-bit pc-relative branch that is now an 8-bit pc-relative branch. */ - case R_PCRWORD_B: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* Get the address of the instruction (not the reloc). */ - dot = (input_section->output_offset - + dst_address - + link_order->u.indirect.section->output_section->vma - 1); - - gap = value - dot; - - /* Sanity check. */ - if (gap < -128 || gap > 126) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - /* Now fix the instruction. */ - switch (data[dst_address - 2]) - { - case 0x58: - /* bCC:16 -> bCC:8 */ - /* Get the second byte of the original insn, which contains - the condition code. */ - tmp = data[dst_address - 1]; - - /* Compute the fisrt byte of the relaxed instruction. The - original sequence 0x58 0xX0 is relaxed to 0x4X, where X - represents the condition code. */ - tmp &= 0xf0; - tmp >>= 4; - tmp |= 0x40; - - /* Write it. */ - bfd_put_8 (abfd, tmp, data + dst_address - 2); - break; - - case 0x5c: - /* bsr:16 -> bsr:8 */ - bfd_put_8 (abfd, 0x55, data + dst_address - 2); - break; - - default: - abort (); - } - - /* Output the target. */ - bfd_put_8 (abfd, gap, data + dst_address - 1); - - /* We don't advance dst_address -- the 8-bit reloc is applied at - dst_address - 1, so the next insn should begin at dst_address. */ - src_address += 2; - - break; - - /* Similarly for a 24-bit absolute that is now 8 bits. */ - case R_JMPL2: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* Get the address of the instruction (not the reloc). */ - dot = (input_section->output_offset - + dst_address - + link_order->u.indirect.section->output_section->vma + 2); - - gap = value - dot; - - /* Fix the instruction. */ - switch (data[src_address]) - { - case 0x5e: - /* jsr -> bsr */ - bfd_put_8 (abfd, 0x55, data + dst_address); - break; - case 0x5a: - /* jmp ->bra */ - bfd_put_8 (abfd, 0x40, data + dst_address); - break; - default: - abort (); - } - - bfd_put_8 (abfd, gap, data + dst_address + 1); - dst_address += 2; - src_address += 4; - - break; - - /* This is a 16-bit absolute address in one of the following - instructions: - - "band", "bclr", "biand", "bild", "bior", "bist", "bixor", - "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", and - "mov.b" - - We may relax this into an 8-bit absolute address if it's in - the right range. */ - case R_MOV16B2: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* All instructions with R_H8_DIR16B2 start with 0x6a. */ - if (data[dst_address - 2] != 0x6a) - abort (); - - temp_code = data[src_address - 1]; - - /* If this is a mov.b instruction, clear the lower nibble, which - contains the source/destination register number. */ - if ((temp_code & 0x10) != 0x10) - temp_code &= 0xf0; - - /* Fix up the opcode. */ - switch (temp_code) - { - case 0x00: - /* This is mov.b @aa:16,Rd. */ - data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x20; - break; - case 0x80: - /* This is mov.b Rs,@aa:16. */ - data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x30; - break; - case 0x18: - /* This is a bit-maniputation instruction that stores one - bit into memory, one of "bclr", "bist", "bnot", "bset", - and "bst". */ - data[dst_address - 2] = 0x7f; - break; - case 0x10: - /* This is a bit-maniputation instruction that loads one bit - from memory, one of "band", "biand", "bild", "bior", - "bixor", "bld", "bor", "btst", and "bxor". */ - data[dst_address - 2] = 0x7e; - break; - default: - abort (); - } - - bfd_put_8 (abfd, value & 0xff, data + dst_address - 1); - src_address += 2; - break; - - /* This is a 24-bit absolute address in one of the following - instructions: - - "band", "bclr", "biand", "bild", "bior", "bist", "bixor", - "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", and - "mov.b" - - We may relax this into an 8-bit absolute address if it's in - the right range. */ - case R_MOV24B2: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - /* All instructions with R_MOV24B2 start with 0x6a. */ - if (data[dst_address - 2] != 0x6a) - abort (); - - temp_code = data[src_address - 1]; - - /* If this is a mov.b instruction, clear the lower nibble, which - contains the source/destination register number. */ - if ((temp_code & 0x30) != 0x30) - temp_code &= 0xf0; - - /* Fix up the opcode. */ - switch (temp_code) - { - case 0x20: - /* This is mov.b @aa:24/32,Rd. */ - data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x20; - break; - case 0xa0: - /* This is mov.b Rs,@aa:24/32. */ - data[dst_address - 2] = (data[src_address - 1] & 0xf) | 0x30; - break; - case 0x38: - /* This is a bit-maniputation instruction that stores one - bit into memory, one of "bclr", "bist", "bnot", "bset", - and "bst". */ - data[dst_address - 2] = 0x7f; - break; - case 0x30: - /* This is a bit-maniputation instruction that loads one bit - from memory, one of "band", "biand", "bild", "bior", - "bixor", "bld", "bor", "btst", and "bxor". */ - data[dst_address - 2] = 0x7e; - break; - default: - abort (); - } - - bfd_put_8 (abfd, value & 0xff, data + dst_address - 1); - src_address += 4; - break; - - case R_BCC_INV: - /* Get the address of the target of this branch. */ - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - dot = (input_section->output_offset - + dst_address - + link_order->u.indirect.section->output_section->vma) + 1; - - gap = value - dot; - - /* Sanity check. */ - if (gap < -128 || gap > 126) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - /* Everything looks OK. Fix the condition in the instruction, apply - the relocation, and update the src/dst address appropriately. */ - - bfd_put_8 (abfd, bfd_get_8 (abfd, data + dst_address - 1) ^ 1, - data + dst_address - 1); - bfd_put_8 (abfd, gap, data + dst_address); - dst_address++; - src_address++; - - /* All done. */ - break; - - case R_JMP_DEL: - src_address += 4; - break; - - /* An 8-bit memory indirect instruction (jmp/jsr). - - There's several things that need to be done to handle - this relocation. - - If this is a reloc against the absolute symbol, then - we should handle it just R_RELBYTE. Likewise if it's - for a symbol with a value ge 0 and le 0xff. - - Otherwise it's a jump/call through the function vector, - and the linker is expected to set up the function vector - and put the right value into the jump/call instruction. */ - case R_MEM_INDIRECT: - { - /* We need to find the symbol so we can determine it's - address in the function vector table. */ - asymbol *symbol; - const char *name; - struct funcvec_hash_table *ftab; - struct funcvec_hash_entry *h; - struct h8300_coff_link_hash_table *htab; - asection *vectors_sec; - - if (link_info->output_bfd->xvec != abfd->xvec) - { - _bfd_error_handler - (_("cannot handle R_MEM_INDIRECT reloc when using %s output"), - link_info->output_bfd->xvec->name); - - /* What else can we do? This function doesn't allow return - of an error, and we don't want to call abort as that - indicates an internal error. */ -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif - xexit (EXIT_FAILURE); - } - htab = h8300_coff_hash_table (link_info); - vectors_sec = htab->vectors_sec; - - /* First see if this is a reloc against the absolute symbol - or against a symbol with a nonnegative value <= 0xff. */ - symbol = *(reloc->sym_ptr_ptr); - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - if (symbol == bfd_abs_section_ptr->symbol - || value <= 0xff) - { - /* This should be handled in a manner very similar to - R_RELBYTES. If the value is in range, then just slam - the value into the right location. Else trigger a - reloc overflow callback. */ - if (value <= 0xff) - { - bfd_put_8 (abfd, value, data + dst_address); - dst_address += 1; - src_address += 1; - } - else - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - break; - } - - /* This is a jump/call through a function vector, and we're - expected to create the function vector ourselves. - - First look up this symbol in the linker hash table -- we need - the derived linker symbol which holds this symbol's index - in the function vector. */ - name = symbol->name; - if (symbol->flags & BSF_LOCAL) - { - char *new_name = bfd_malloc ((bfd_size_type) strlen (name) + 10); - - if (new_name == NULL) - abort (); - - sprintf (new_name, "%s_%08x", name, symbol->section->id); - name = new_name; - } - - ftab = htab->funcvec_hash_table; - h = funcvec_hash_lookup (ftab, name, FALSE, FALSE); - - /* This shouldn't ever happen. If it does that means we've got - data corruption of some kind. Aborting seems like a reasonable - thing to do here. */ - if (h == NULL || vectors_sec == NULL) - abort (); - - /* Place the address of the function vector entry into the - reloc's address. */ - bfd_put_8 (abfd, - vectors_sec->output_offset + h->offset, - data + dst_address); - - dst_address++; - src_address++; - - /* Now create an entry in the function vector itself. */ - switch (bfd_get_mach (input_section->owner)) - { - case bfd_mach_h8300: - case bfd_mach_h8300hn: - case bfd_mach_h8300sn: - bfd_put_16 (abfd, - bfd_coff_reloc16_get_value (reloc, - link_info, - input_section), - vectors_sec->contents + h->offset); - break; - case bfd_mach_h8300h: - case bfd_mach_h8300s: - bfd_put_32 (abfd, - bfd_coff_reloc16_get_value (reloc, - link_info, - input_section), - vectors_sec->contents + h->offset); - break; - default: - abort (); - } - - /* Gross. We've already written the contents of the vector section - before we get here... So we write it again with the new data. */ - bfd_set_section_contents (vectors_sec->output_section->owner, - vectors_sec->output_section, - vectors_sec->contents, - (file_ptr) vectors_sec->output_offset, - vectors_sec->size); - break; - } - - default: - abort (); - break; - - } - - *src_ptr = src_address; - *dst_ptr = dst_address; -} - -/* Routine for the h8300 linker. - - This routine is necessary to handle the special R_MEM_INDIRECT - relocs on the h8300. It's responsible for generating a vectors - section and attaching it to an input bfd as well as sizing - the vectors section. It also creates our vectors hash table. - - It uses the generic linker routines to actually add the symbols. - from this BFD to the bfd linker hash table. It may add a few - selected static symbols to the bfd linker hash table. */ - -static bfd_boolean -h8300_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) -{ - asection *sec; - struct funcvec_hash_table *funcvec_hash_table; - bfd_size_type amt; - struct h8300_coff_link_hash_table *htab; - - /* Add the symbols using the generic code. */ - _bfd_generic_link_add_symbols (abfd, info); - - if (info->output_bfd->xvec != abfd->xvec) - return TRUE; - - htab = h8300_coff_hash_table (info); - - /* If we haven't created a vectors section, do so now. */ - if (!htab->vectors_sec) - { - flagword flags; - - /* Make sure the appropriate flags are set, including SEC_IN_MEMORY. */ - flags = (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY); - htab->vectors_sec = bfd_make_section_with_flags (abfd, ".vectors", - flags); - - /* If the section wasn't created, or we couldn't set the flags, - quit quickly now, rather than dying a painful death later. */ - if (!htab->vectors_sec) - return FALSE; - - /* Also create the vector hash table. */ - amt = sizeof (struct funcvec_hash_table); - funcvec_hash_table = (struct funcvec_hash_table *) bfd_alloc (abfd, amt); - - if (!funcvec_hash_table) - return FALSE; - - /* And initialize the funcvec hash table. */ - if (!funcvec_hash_table_init (funcvec_hash_table, abfd, - funcvec_hash_newfunc, - sizeof (struct funcvec_hash_entry))) - { - bfd_release (abfd, funcvec_hash_table); - return FALSE; - } - - /* Store away a pointer to the funcvec hash table. */ - htab->funcvec_hash_table = funcvec_hash_table; - } - - /* Load up the function vector hash table. */ - funcvec_hash_table = htab->funcvec_hash_table; - - /* Now scan the relocs for all the sections in this bfd; create - additional space in the .vectors section as needed. */ - for (sec = abfd->sections; sec; sec = sec->next) - { - long reloc_size, reloc_count, i; - asymbol **symbols; - arelent **relocs; - - /* Suck in the relocs, symbols & canonicalize them. */ - reloc_size = bfd_get_reloc_upper_bound (abfd, sec); - if (reloc_size <= 0) - continue; - - relocs = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); - if (!relocs) - return FALSE; - - /* The symbols should have been read in by _bfd_generic link_add_symbols - call abovec, so we can cheat and use the pointer to them that was - saved in the above call. */ - symbols = _bfd_generic_link_get_symbols(abfd); - reloc_count = bfd_canonicalize_reloc (abfd, sec, relocs, symbols); - if (reloc_count <= 0) - { - free (relocs); - continue; - } - - /* Now walk through all the relocations in this section. */ - for (i = 0; i < reloc_count; i++) - { - arelent *reloc = relocs[i]; - asymbol *symbol = *(reloc->sym_ptr_ptr); - const char *name; - - /* We've got an indirect reloc. See if we need to add it - to the function vector table. At this point, we have - to add a new entry for each unique symbol referenced - by an R_MEM_INDIRECT relocation except for a reloc - against the absolute section symbol. */ - if (reloc->howto->type == R_MEM_INDIRECT - && symbol != bfd_abs_section_ptr->symbol) - - { - struct funcvec_hash_table *ftab; - struct funcvec_hash_entry *h; - - name = symbol->name; - if (symbol->flags & BSF_LOCAL) - { - char *new_name; - - new_name = bfd_malloc ((bfd_size_type) strlen (name) + 10); - if (new_name == NULL) - abort (); - - sprintf (new_name, "%s_%08x", name, symbol->section->id); - name = new_name; - } - - /* Look this symbol up in the function vector hash table. */ - ftab = htab->funcvec_hash_table; - h = funcvec_hash_lookup (ftab, name, FALSE, FALSE); - - /* If this symbol isn't already in the hash table, add - it and bump up the size of the hash table. */ - if (h == NULL) - { - h = funcvec_hash_lookup (ftab, name, TRUE, TRUE); - if (h == NULL) - { - free (relocs); - return FALSE; - } - - /* Bump the size of the vectors section. Each vector - takes 2 bytes on the h8300 and 4 bytes on the h8300h. */ - switch (bfd_get_mach (abfd)) - { - case bfd_mach_h8300: - case bfd_mach_h8300hn: - case bfd_mach_h8300sn: - htab->vectors_sec->size += 2; - break; - case bfd_mach_h8300h: - case bfd_mach_h8300s: - htab->vectors_sec->size += 4; - break; - default: - abort (); - } - } - } - } - - /* We're done with the relocations, release them. */ - free (relocs); - } - - /* Now actually allocate some space for the function vector. It's - wasteful to do this more than once, but this is easier. */ - sec = htab->vectors_sec; - if (sec->size != 0) - { - /* Free the old contents. */ - if (sec->contents) - free (sec->contents); - - /* Allocate new contents. */ - sec->contents = bfd_malloc (sec->size); - } - - return TRUE; -} - -#define coff_reloc16_extra_cases h8300_reloc16_extra_cases -#define coff_reloc16_estimate h8300_reloc16_estimate -#define coff_bfd_link_add_symbols h8300_bfd_link_add_symbols -#define coff_bfd_link_hash_table_create h8300_coff_link_hash_table_create - -#define COFF_LONG_FILENAMES - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#undef coff_bfd_get_relocated_section_contents -#undef coff_bfd_relax_section -#define coff_bfd_get_relocated_section_contents \ - bfd_coff_reloc16_get_relocated_section_contents -#define coff_bfd_relax_section bfd_coff_reloc16_relax_section - -CREATE_BIG_COFF_TARGET_VEC (h8300_coff_vec, "coff-h8300", BFD_IS_RELAXABLE, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-h8500.c b/sdcc/support/sdbinutils/bfd/coff-h8500.c deleted file mode 100644 index a73fd46c2..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-h8500.c +++ /dev/null @@ -1,298 +0,0 @@ -/* BFD back-end for Renesas H8/500 COFF binaries. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Contributed by Cygnus Support. - 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "coff/h8500.h" -#include "coff/internal.h" -#include "libcoff.h" - - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) - -static reloc_howto_type r_imm8 = -HOWTO (R_H8500_IMM8, 0, 1, 8, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff, FALSE); - -static reloc_howto_type r_imm16 = -HOWTO (R_H8500_IMM16, 0, 1, 16, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm16", TRUE, 0x0000ffff, 0x0000ffff, FALSE); - -static reloc_howto_type r_imm24 = -HOWTO (R_H8500_IMM24, 0, 1, 24, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm24", TRUE, 0x00ffffff, 0x00ffffff, FALSE); - -static reloc_howto_type r_imm32 = -HOWTO (R_H8500_IMM32, 0, 1, 32, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm32", TRUE, 0xffffffff, 0xffffffff, FALSE); - -static reloc_howto_type r_high8 = -HOWTO (R_H8500_HIGH8, 0, 1, 8, FALSE, 0, - complain_overflow_dont, 0, "r_high8", TRUE, 0x000000ff, 0x000000ff, FALSE); - -static reloc_howto_type r_low16 = -HOWTO (R_H8500_LOW16, 0, 1, 16, FALSE, 0, - complain_overflow_dont, 0, "r_low16", TRUE, 0x0000ffff, 0x0000ffff, FALSE); - -static reloc_howto_type r_pcrel8 = -HOWTO (R_H8500_PCREL8, 0, 1, 8, TRUE, 0, complain_overflow_signed, 0, "r_pcrel8", TRUE, 0, 0, TRUE); - -static reloc_howto_type r_pcrel16 = -HOWTO (R_H8500_PCREL16, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "r_pcrel16", TRUE, 0, 0, TRUE); - -static reloc_howto_type r_high16 = -HOWTO (R_H8500_HIGH16, 0, 1, 8, FALSE, 0, - complain_overflow_dont, 0, "r_high16", TRUE, 0x000ffff, 0x0000ffff, FALSE); - -/* Turn a howto into a reloc number. */ - -static int -coff_h8500_select_reloc (reloc_howto_type *howto) -{ - return howto->type; -} - -#define SELECT_RELOC(x,howto) x.r_type = coff_h8500_select_reloc(howto) - -#define BADMAG(x) H8500BADMAG(x) -#define H8500 1 /* Customize coffcode.h */ - -#define __A_MAGIC_SET__ - -/* Code to swap in the reloc. */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ - dst->r_stuff[0] = 'S'; \ - dst->r_stuff[1] = 'C'; - -/* Code to turn a r_type into a howto ptr, uses the above howto table. */ - -static void -rtype2howto (arelent * internal, struct internal_reloc *dst) -{ - switch (dst->r_type) - { - default: - internal->howto = NULL; - break; - case R_H8500_IMM8: - internal->howto = &r_imm8; - break; - case R_H8500_IMM16: - internal->howto = &r_imm16; - break; - case R_H8500_IMM24: - internal->howto = &r_imm24; - break; - case R_H8500_IMM32: - internal->howto = &r_imm32; - break; - case R_H8500_PCREL8: - internal->howto = &r_pcrel8; - break; - case R_H8500_PCREL16: - internal->howto = &r_pcrel16; - break; - case R_H8500_HIGH8: - internal->howto = &r_high8; - break; - case R_H8500_HIGH16: - internal->howto = &r_high16; - break; - case R_H8500_LOW16: - internal->howto = &r_low16; - break; - } -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) - -/* Perform any necessary magic to the addend in a reloc entry. */ - -#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ - cache_ptr->addend = ext_reloc.r_offset; - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing(relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent * relent, - struct internal_reloc *reloc, - asymbol ** symbols, - bfd * abfd, - asection * section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (reloc->r_symndx > 0) - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - else - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - relent->addend = reloc->r_offset; - relent->address -= section->vma; -} - -static void -extra_case (bfd *in_abfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - arelent *reloc, - bfd_byte *data, - unsigned int *src_ptr, - unsigned int *dst_ptr) -{ - bfd_byte *d = data+*dst_ptr; - asection *input_section = link_order->u.indirect.section; - - switch (reloc->howto->type) - { - case R_H8500_IMM8: - bfd_put_8 (in_abfd, - bfd_coff_reloc16_get_value (reloc, link_info, input_section), - d); - (*dst_ptr) += 1; - (*src_ptr) += 1; - break; - - case R_H8500_HIGH8: - bfd_put_8 (in_abfd, - (bfd_coff_reloc16_get_value (reloc, link_info, input_section) - >> 16), - d); - (*dst_ptr) += 1; - (*src_ptr) += 1; - break; - - case R_H8500_IMM16: - bfd_put_16 (in_abfd, - bfd_coff_reloc16_get_value (reloc, link_info, input_section), - d); - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - - case R_H8500_LOW16: - bfd_put_16 (in_abfd, - bfd_coff_reloc16_get_value (reloc, link_info, input_section), - d); - - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - - case R_H8500_HIGH16: - bfd_put_16 (in_abfd, - (bfd_coff_reloc16_get_value (reloc, link_info, input_section) - >> 16), - d); - - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - - case R_H8500_IMM24: - { - int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - int o = bfd_get_32 (in_abfd, data+ *dst_ptr -1); - v = (v & 0x00ffffff) | (o & 0xff00000); - bfd_put_32 (in_abfd, (bfd_vma) v, data + *dst_ptr -1); - (*dst_ptr) += 3; - (*src_ptr) += 3; - } - break; - case R_H8500_IMM32: - { - int v = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_32 (in_abfd, (bfd_vma) v, data + *dst_ptr); - (*dst_ptr) += 4; - (*src_ptr) += 4; - } - break; - - case R_H8500_PCREL8: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 1; /* -1 since were in the odd byte of the - word and the pc's been incremented. */ - - if (gap > 128 || gap < -128) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_8 (in_abfd, gap, data + *dst_ptr); - (*dst_ptr)++; - (*src_ptr)++; - break; - } - case R_H8500_PCREL16: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 1; /* -1 since were in the odd byte of the - word and the pc's been incremented. */ - - if (gap > 32767 || gap < -32768) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_16 (in_abfd, (bfd_vma) gap, data + *dst_ptr); - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - } - - default: - abort (); - } -} - -#define coff_reloc16_extra_cases extra_case - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#undef coff_bfd_get_relocated_section_contents -#undef coff_bfd_relax_section -#define coff_bfd_get_relocated_section_contents \ - bfd_coff_reloc16_get_relocated_section_contents -#define coff_bfd_relax_section bfd_coff_reloc16_relax_section - -CREATE_BIG_COFF_TARGET_VEC (h8500_coff_vec, "coff-h8500", 0, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-i386.c b/sdcc/support/sdbinutils/bfd/coff-i386.c deleted file mode 100644 index 8b8f601f3..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-i386.c +++ /dev/null @@ -1,689 +0,0 @@ -/* BFD back-end for Intel 386 COFF files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#include "coff/i386.h" - -#include "coff/internal.h" - -#ifdef COFF_WITH_PE -#include "coff/pe.h" -#endif - -#ifdef COFF_GO32_EXE -#include "coff/go32exe.h" -#endif - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "libcoff.h" - -static reloc_howto_type *coff_i386_rtype_to_howto - (bfd *, asection *, struct internal_reloc *, - struct coff_link_hash_entry *, struct internal_syment *, - bfd_vma *); -static reloc_howto_type *coff_i386_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) -/* The page size is a guess based on ELF. */ - -#define COFF_PAGE_SIZE 0x1000 - -/* For some reason when using i386 COFF the value stored in the .text - section for a reference to a common symbol is the value itself plus - any desired offset. Ian Taylor, Cygnus Support. */ - -/* If we are producing relocatable output, we need to do some - adjustments to the object file that are not done by the - bfd_perform_relocation function. This function is called by every - reloc type to make any required adjustments. */ - -static bfd_reloc_status_type -coff_i386_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - symvalue diff; - -#ifndef COFF_WITH_PE - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; -#endif - - if (bfd_is_com_section (symbol->section)) - { -#ifndef COFF_WITH_PE - /* We are relocating a common symbol. The current value in the - object file is ORIG + OFFSET, where ORIG is the value of the - common symbol as seen by the object file when it was compiled - (this may be zero if the symbol was undefined) and OFFSET is - the offset into the common symbol (normally zero, but may be - non-zero when referring to a field in a common structure). - ORIG is the negative of reloc_entry->addend, which is set by - the CALC_ADDEND macro below. We want to replace the value in - the object file with NEW + OFFSET, where NEW is the value of - the common symbol which we are going to put in the final - object file. NEW is symbol->value. */ - diff = symbol->value + reloc_entry->addend; -#else - /* In PE mode, we do not offset the common symbol. */ - diff = reloc_entry->addend; -#endif - } - else - { - /* For some reason bfd_perform_relocation always effectively - ignores the addend for a COFF target when producing - relocatable output. This seems to be always wrong for 386 - COFF, so we handle the addend here instead. */ -#ifdef COFF_WITH_PE - if (output_bfd == (bfd *) NULL) - { - reloc_howto_type *howto = reloc_entry->howto; - - /* Although PC relative relocations are very similar between - PE and non-PE formats, but they are off by 1 << howto->size - bytes. For the external relocation, PE is very different - from others. See md_apply_fix3 () in gas/config/tc-i386.c. - When we link PE and non-PE object files together to - generate a non-PE executable, we have to compensate it - here. */ - if (howto->pc_relative && howto->pcrel_offset) - diff = -(1 << howto->size); - else if (symbol->flags & BSF_WEAK) - diff = reloc_entry->addend - symbol->value; - else - diff = -reloc_entry->addend; - } - else -#endif - diff = reloc_entry->addend; - } - -#ifdef COFF_WITH_PE - /* FIXME: How should this case be handled? */ - if (reloc_entry->howto->type == R_IMAGEBASE - && output_bfd != NULL - && bfd_get_flavour(output_bfd) == bfd_target_coff_flavour) - diff -= pe_data (output_bfd)->pe_opthdr.ImageBase; -#endif - -#define DOIT(x) \ - x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) - - if (diff != 0) - { - reloc_howto_type *howto = reloc_entry->howto; - unsigned char *addr = (unsigned char *) data + reloc_entry->address; - - if (! bfd_reloc_offset_in_range (howto, abfd, input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - switch (howto->size) - { - case 0: - { - char x = bfd_get_8 (abfd, addr); - DOIT (x); - bfd_put_8 (abfd, x, addr); - } - break; - - case 1: - { - short x = bfd_get_16 (abfd, addr); - DOIT (x); - bfd_put_16 (abfd, (bfd_vma) x, addr); - } - break; - - case 2: - { - long x = bfd_get_32 (abfd, addr); - DOIT (x); - bfd_put_32 (abfd, (bfd_vma) x, addr); - } - break; - - default: - abort (); - } - } - - /* Now let bfd_perform_relocation finish everything up. */ - return bfd_reloc_continue; -} - -#ifdef COFF_WITH_PE -/* Return TRUE if this relocation should appear in the output .reloc - section. */ - -static bfd_boolean in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, - reloc_howto_type *howto) -{ - return ! howto->pc_relative && howto->type != R_IMAGEBASE - && howto->type != R_SECREL32; -} -#endif /* COFF_WITH_PE */ - -#ifndef PCRELOFFSET -#define PCRELOFFSET FALSE -#endif - -static reloc_howto_type howto_table[] = -{ - EMPTY_HOWTO (0), - EMPTY_HOWTO (1), - EMPTY_HOWTO (2), - EMPTY_HOWTO (3), - EMPTY_HOWTO (4), - EMPTY_HOWTO (5), - HOWTO (R_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "dir32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - /* PE IMAGE_REL_I386_DIR32NB relocation (7). */ - HOWTO (R_IMAGEBASE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "rva32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (010), - EMPTY_HOWTO (011), - EMPTY_HOWTO (012), -#ifdef COFF_WITH_PE - /* 32-bit longword section relative relocation (013). */ - HOWTO (R_SECREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "secrel32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -#else - EMPTY_HOWTO (013), -#endif - EMPTY_HOWTO (014), - EMPTY_HOWTO (015), - EMPTY_HOWTO (016), - /* Byte relocation (017). */ - HOWTO (R_RELBYTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 16-bit word relocation (020). */ - HOWTO (R_RELWORD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 32-bit longword relocation (021). */ - HOWTO (R_RELLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* Byte PC relative relocation (022). */ - HOWTO (R_PCRBYTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "DISP8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 16-bit word PC relative relocation (023). */ - HOWTO (R_PCRWORD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "DISP16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 32-bit longword PC relative relocation (024). */ - HOWTO (R_PCRLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_i386_reloc, /* special_function */ - "DISP32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET) /* pcrel_offset */ -}; - -#define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0])) - -/* Turn a howto into a reloc nunmber */ - -#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } -#define BADMAG(x) I386BADMAG(x) -#define I386 1 /* Customize coffcode.h */ - -#define RTYPE2HOWTO(cache_ptr, dst) \ - ((cache_ptr)->howto = \ - ((dst)->r_type < NUM_HOWTOS \ - ? howto_table + (dst)->r_type \ - : NULL)) - -/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared - library. On some other COFF targets STYP_BSS is normally - STYP_NOLOAD. */ -#define BSS_NOLOAD_IS_SHARED_LIBRARY - -/* Compute the addend of a reloc. If the reloc is to a common symbol, - the object file contains the value of the common symbol. By the - time this is called, the linker may be using a different symbol - from a different object file with a different value. Therefore, we - hack wildly to locate the original symbol from this file so that we - can make the correct adjustment. This macro sets coffsym to the - symbol from the original file, and uses it to set the addend value - correctly. If this is not a common symbol, the usual addend - calculation is done, except that an additional tweak is needed for - PC relative relocs. - FIXME: This macro refers to symbols and asect; these are from the - calling function, not the macro arguments. */ - -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ - { \ - coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ - if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ - coffsym = (obj_symbols (abfd) \ - + (cache_ptr->sym_ptr_ptr - symbols)); \ - else if (ptr) \ - coffsym = coff_symbol_from (ptr); \ - if (coffsym != (coff_symbol_type *) NULL \ - && coffsym->native->u.syment.n_scnum == 0) \ - cache_ptr->addend = - coffsym->native->u.syment.n_value; \ - else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ - && ptr->section != (asection *) NULL) \ - cache_ptr->addend = - (ptr->section->vma + ptr->value); \ - else \ - cache_ptr->addend = 0; \ - if (ptr && reloc.r_type < NUM_HOWTOS \ - && howto_table[reloc.r_type].pc_relative) \ - cache_ptr->addend += asect->vma; \ - } - -/* We use the special COFF backend linker. For normal i386 COFF, we - can use the generic relocate_section routine. For PE, we need our - own routine. */ - -#ifndef COFF_WITH_PE - -#define coff_relocate_section _bfd_coff_generic_relocate_section - -#else /* COFF_WITH_PE */ - -/* The PE relocate section routine. The only difference between this - and the regular routine is that we don't want to do anything for a - relocatable link. */ - -static bfd_boolean -coff_pe_i386_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - if (bfd_link_relocatable (info)) - return TRUE; - - return _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd, - input_section, contents, - relocs, syms, sections); -} - -#define coff_relocate_section coff_pe_i386_relocate_section - -#endif /* COFF_WITH_PE */ - -/* Convert an rtype to howto for the COFF backend linker. */ - -static reloc_howto_type * -coff_i386_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h, - struct internal_syment *sym, - bfd_vma *addendp) -{ - reloc_howto_type *howto; - - if (rel->r_type >= NUM_HOWTOS) - { - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - howto = howto_table + rel->r_type; - -#ifdef COFF_WITH_PE - /* Cancel out code in _bfd_coff_generic_relocate_section. */ - *addendp = 0; -#endif - - if (howto->pc_relative) - *addendp += sec->vma; - - if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) - { - /* This is a common symbol. The section contents include the - size (sym->n_value) as an addend. The relocate_section - function will be adding in the final value of the symbol. We - need to subtract out the current size in order to get the - correct result. */ - - BFD_ASSERT (h != NULL); - -#ifndef COFF_WITH_PE - /* I think we *do* want to bypass this. If we don't, I have - seen some data parameters get the wrong relocation address. - If I link two versions with and without this section bypassed - and then do a binary comparison, the addresses which are - different can be looked up in the map. The case in which - this section has been bypassed has addresses which correspond - to values I can find in the map. */ - *addendp -= sym->n_value; -#endif - } - -#ifndef COFF_WITH_PE - /* If the output symbol is common (in which case this must be a - relocatable link), we need to add in the final size of the - common symbol. */ - if (h != NULL && h->root.type == bfd_link_hash_common) - *addendp += h->root.u.c.size; -#endif - -#ifdef COFF_WITH_PE - if (howto->pc_relative) - { - *addendp -= 4; - - /* If the symbol is defined, then the generic code is going to - add back the symbol value in order to cancel out an - adjustment it made to the addend. However, we set the addend - to 0 at the start of this function. We need to adjust here, - to avoid the adjustment the generic code will make. FIXME: - This is getting a bit hackish. */ - if (sym != NULL && sym->n_scnum != 0) - *addendp -= sym->n_value; - } - - if (rel->r_type == R_IMAGEBASE - && (bfd_get_flavour(sec->output_section->owner) - == bfd_target_coff_flavour)) - { - *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; - } - - /* PR 17099 - Absolute R_PCRLONG relocations do not need a symbol. */ - if (rel->r_type == R_PCRLONG && sym == NULL) - *addendp -= rel->r_vaddr; - else - BFD_ASSERT (sym != NULL); - - if (rel->r_type == R_SECREL32 && sym != NULL) - { - bfd_vma osect_vma; - - if (h && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - osect_vma = h->root.u.def.section->output_section->vma; - else - { - asection *s; - int i; - - /* Sigh, the only way to get the section to offset against - is to find it the hard way. */ - - for (s = abfd->sections, i = 1; i < sym->n_scnum; i++) - s = s->next; - - osect_vma = s->output_section->vma; - } - - *addendp -= osect_vma; - } -#endif - - return howto; -} - -#define coff_bfd_reloc_type_lookup coff_i386_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_i386_reloc_name_lookup - -static reloc_howto_type * -coff_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_RVA: - return howto_table + R_IMAGEBASE; - case BFD_RELOC_32: - return howto_table + R_DIR32; - case BFD_RELOC_32_PCREL: - return howto_table + R_PCRLONG; - case BFD_RELOC_16: - return howto_table + R_RELWORD; - case BFD_RELOC_16_PCREL: - return howto_table + R_PCRWORD; - case BFD_RELOC_8: - return howto_table + R_RELBYTE; - case BFD_RELOC_8_PCREL: - return howto_table + R_PCRBYTE; -#ifdef COFF_WITH_PE - case BFD_RELOC_32_SECREL: - return howto_table + R_SECREL32; -#endif - default: - BFD_FAIL (); - return 0; - } -} - -static reloc_howto_type * -coff_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < NUM_HOWTOS; i++) - if (howto_table[i].name != NULL - && strcasecmp (howto_table[i].name, r_name) == 0) - return &howto_table[i]; - - return NULL; -} - -#define coff_rtype_to_howto coff_i386_rtype_to_howto - -#ifdef TARGET_UNDERSCORE - -/* If i386 gcc uses underscores for symbol names, then it does not use - a leading dot for local labels, so if TARGET_UNDERSCORE is defined - we treat all symbols starting with L as local. */ - -static bfd_boolean -coff_i386_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == 'L') - return TRUE; - - return _bfd_coff_is_local_label_name (abfd, name); -} - -#define coff_bfd_is_local_label_name coff_i386_is_local_label_name - -#endif /* TARGET_UNDERSCORE */ - -#include "coffcode.h" - -const bfd_target -#ifdef TARGET_SYM - TARGET_SYM = -#else - i386_coff_vec = -#endif -{ -#ifdef TARGET_NAME - TARGET_NAME, -#else - "coff-i386", /* name */ -#endif - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */ -#ifdef COFF_WITH_PE - | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY | SEC_DEBUGGING -#endif - | SEC_CODE | SEC_DATA | SEC_EXCLUDE ), - -#ifdef TARGET_UNDERSCORE - TARGET_UNDERSCORE, /* leading underscore */ -#else - 0, /* leading underscore */ -#endif - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - -/* Note that we allow an object file to be treated as a core file as well. */ - /* bfd_check_format */ -#ifdef COFF_CHECK_FORMAT - {_bfd_dummy_target, COFF_CHECK_FORMAT, - bfd_generic_archive_p, COFF_CHECK_FORMAT}, -#else - {_bfd_dummy_target, coff_object_p, bfd_generic_archive_p, coff_object_p}, -#endif - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - COFF_SWAP_TABLE -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-i860.c b/sdcc/support/sdbinutils/bfd/coff-i860.c deleted file mode 100644 index 13c84af31..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-i860.c +++ /dev/null @@ -1,718 +0,0 @@ -/* BFD back-end for Intel i860 COFF files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Created mostly by substituting "860" for "386" in coff-i386.c - Harry Dolan , October 1995 - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#include "coff/i860.h" - -#include "coff/internal.h" - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "libcoff.h" - - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) -/* The page size is a guess based on ELF. */ - -#define COFF_PAGE_SIZE 0x1000 - -/* For some reason when using i860 COFF the value stored in the .text - section for a reference to a common symbol is the value itself plus - any desired offset. Ian Taylor, Cygnus Support. */ - -/* If we are producing relocatable output, we need to do some - adjustments to the object file that are not done by the - bfd_perform_relocation function. This function is called by every - reloc type to make any required adjustments. */ - -static bfd_reloc_status_type -coff_i860_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - symvalue diff; - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - if (bfd_is_com_section (symbol->section)) - { - /* We are relocating a common symbol. The current value in the - object file is ORIG + OFFSET, where ORIG is the value of the - common symbol as seen by the object file when it was compiled - (this may be zero if the symbol was undefined) and OFFSET is - the offset into the common symbol (normally zero, but may be - non-zero when referring to a field in a common structure). - ORIG is the negative of reloc_entry->addend, which is set by - the CALC_ADDEND macro below. We want to replace the value in - the object file with NEW + OFFSET, where NEW is the value of - the common symbol which we are going to put in the final - object file. NEW is symbol->value. */ - diff = symbol->value + reloc_entry->addend; - } - else - { - /* For some reason bfd_perform_relocation always effectively - ignores the addend for a COFF target when producing - relocatable output. This seems to be always wrong for 860 - COFF, so we handle the addend here instead. */ - diff = reloc_entry->addend; - } - -#define DOIT(x) \ - x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) - - if (diff != 0) - { - reloc_howto_type *howto = reloc_entry->howto; - unsigned char *addr = (unsigned char *) data + reloc_entry->address; - - if (! bfd_reloc_offset_in_range (howto, abfd, input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - switch (howto->size) - { - case 0: - { - char x = bfd_get_8 (abfd, addr); - DOIT (x); - bfd_put_8 (abfd, x, addr); - } - break; - - case 1: - { - short x = bfd_get_16 (abfd, addr); - DOIT (x); - bfd_put_16 (abfd, (bfd_vma) x, addr); - } - break; - - case 2: - { - long x = bfd_get_32 (abfd, addr); - DOIT (x); - bfd_put_32 (abfd, (bfd_vma) x, addr); - } - break; - - default: - abort (); - } - } - - /* Now let bfd_perform_relocation finish everything up. */ - return bfd_reloc_continue; -} - -/* This is just a temporary measure until we teach bfd to generate - these relocations. */ - -static bfd_reloc_status_type -coff_i860_reloc_nyi (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - reloc_howto_type *howto = reloc_entry->howto; - _bfd_error_handler (_("relocation `%s' not yet implemented"), howto->name); - return bfd_reloc_notsupported; -} - -#ifndef PCRELOFFSET -#define PCRELOFFSET FALSE -#endif - -static reloc_howto_type howto_table[] = -{ - EMPTY_HOWTO (0), - EMPTY_HOWTO (1), - EMPTY_HOWTO (2), - EMPTY_HOWTO (3), - EMPTY_HOWTO (4), - EMPTY_HOWTO (5), - HOWTO (R_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "dir32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - /* {7}, */ - HOWTO (R_IMAGEBASE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "rva32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (010), - EMPTY_HOWTO (011), - EMPTY_HOWTO (012), - EMPTY_HOWTO (013), - EMPTY_HOWTO (014), - EMPTY_HOWTO (015), - EMPTY_HOWTO (016), - HOWTO (R_RELBYTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_RELWORD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_RELLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_PCRBYTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "DISP8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_PCRWORD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "DISP16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_PCRLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "DISP32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - EMPTY_HOWTO (0x15), - EMPTY_HOWTO (0x16), - EMPTY_HOWTO (0x17), - EMPTY_HOWTO (0x18), - EMPTY_HOWTO (0x19), - EMPTY_HOWTO (0x1a), - EMPTY_HOWTO (0x1b), - HOWTO (COFF860_R_PAIR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc_nyi, /* special_function */ - "PAIR", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (0x1d), - HOWTO (COFF860_R_HIGH, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "HIGH", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_LOW0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "LOW0", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_LOW1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "LOW1", /* name */ - FALSE, /* partial_inplace */ - 0xfffe, /* src_mask */ - 0xfffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_LOW2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "LOW2", /* name */ - FALSE, /* partial_inplace */ - 0xfffc, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_LOW3, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "LOW3", /* name */ - FALSE, /* partial_inplace */ - 0xfff8, /* src_mask */ - 0xfff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_LOW4, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc, /* special_function */ - "LOW4", /* name */ - FALSE, /* partial_inplace */ - 0xfff0, /* src_mask */ - 0xfff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_SPLIT0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc_nyi, /* special_function */ - "SPLIT0", /* name */ - FALSE, /* partial_inplace */ - 0x1f07ff, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_SPLIT1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc_nyi, /* special_function */ - "SPLIT1", /* name */ - FALSE, /* partial_inplace */ - 0x1f07fe, /* src_mask */ - 0x1f07fe, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_SPLIT2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc_nyi, /* special_function */ - "SPLIT2", /* name */ - FALSE, /* partial_inplace */ - 0x1f07fc, /* src_mask */ - 0x1f07fc, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_HIGHADJ, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - coff_i860_reloc_nyi, /* special_function */ - "HIGHADJ", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (COFF860_R_BRADDR, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_i860_reloc_nyi, /* special_function */ - "BRADDR", /* name */ - FALSE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - TRUE) /* pcrel_offset */ -}; - -/* Turn a howto into a reloc number. */ - -#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } -#define BADMAG(x) I860BADMAG(x) -#define I860 1 /* Customize coffcode.h */ - -#define RTYPE2HOWTO(cache_ptr, dst) \ - ((cache_ptr)->howto = \ - ((dst)->r_type < sizeof (howto_table) / sizeof (howto_table[0]) \ - ? howto_table + (dst)->r_type \ - : NULL)) - -/* For 860 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared - library. On some other COFF targets STYP_BSS is normally - STYP_NOLOAD. */ -#define BSS_NOLOAD_IS_SHARED_LIBRARY - -/* Compute the addend of a reloc. If the reloc is to a common symbol, - the object file contains the value of the common symbol. By the - time this is called, the linker may be using a different symbol - from a different object file with a different value. Therefore, we - hack wildly to locate the original symbol from this file so that we - can make the correct adjustment. This macro sets coffsym to the - symbol from the original file, and uses it to set the addend value - correctly. If this is not a common symbol, the usual addend - calculation is done, except that an additional tweak is needed for - PC relative relocs. - FIXME: This macro refers to symbols and asect; these are from the - calling function, not the macro arguments. */ - -/* PR 17512: file: 0a38fb7c - Set an addend value, even if it is not going to be used. A tool - like coffdump might be used to print out the contents of the reloc. */ -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) (cache_ptr)->addend = 0 - -/* We use the special COFF backend linker. */ -#define coff_relocate_section _bfd_coff_generic_relocate_section - -static reloc_howto_type * -coff_i860_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h, - struct internal_syment *sym, - bfd_vma *addendp) -{ - - reloc_howto_type *howto; - - if (rel->r_type > sizeof (howto_table) / sizeof (howto_table[0])) - { - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - howto = howto_table + rel->r_type; - - if (howto->pc_relative) - *addendp += sec->vma; - - if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) - { - /* This is a common symbol. The section contents include the - size (sym->n_value) as an addend. The relocate_section - function will be adding in the final value of the symbol. We - need to subtract out the current size in order to get the - correct result. */ - - BFD_ASSERT (h != NULL); - - /* I think we *do* want to bypass this. If we don't, I have seen some data - parameters get the wrong relocation address. If I link two versions - with and without this section bypassed and then do a binary comparison, - the addresses which are different can be looked up in the map. The - case in which this section has been bypassed has addresses which correspond - to values I can find in the map. */ - *addendp -= sym->n_value; - } - - /* If the output symbol is common (in which case this must be a - relocatable link), we need to add in the final size of the - common symbol. */ - if (h != NULL && h->root.type == bfd_link_hash_common) - *addendp += h->root.u.c.size; - - return howto; -} - -static reloc_howto_type * -coff_i860_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_32: - return howto_table + R_DIR32; - case BFD_RELOC_860_PC26: - return howto_table + COFF860_R_BRADDR; - case BFD_RELOC_860_PC16: - /* ??? How to handle PC16 for COFF? SPLIT0 is close for now. */ - return howto_table + COFF860_R_SPLIT0; - case BFD_RELOC_860_LOW0: - return howto_table + COFF860_R_LOW0; - case BFD_RELOC_860_SPLIT0: - return howto_table + COFF860_R_SPLIT0; - case BFD_RELOC_860_LOW1: - return howto_table + COFF860_R_LOW1; - case BFD_RELOC_860_SPLIT1: - return howto_table + COFF860_R_SPLIT1; - case BFD_RELOC_860_LOW2: - return howto_table + COFF860_R_LOW2; - case BFD_RELOC_860_SPLIT2: - return howto_table + COFF860_R_SPLIT2; - case BFD_RELOC_860_LOW3: - return howto_table + COFF860_R_LOW3; - case BFD_RELOC_860_HIGHADJ: - return howto_table + COFF860_R_HIGHADJ; - case BFD_RELOC_860_HIGH: - return howto_table + COFF860_R_HIGH; - default: - BFD_FAIL (); - return 0; - } -} - -static reloc_howto_type * -coff_i860_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) - if (howto_table[i].name != NULL - && strcasecmp (howto_table[i].name, r_name) == 0) - return &howto_table[i]; - - return NULL; -} - -/* This is called from coff_slurp_reloc_table for each relocation - entry. This special handling is due to the `PAIR' relocation - which has a different meaning for the `r_symndx' field. */ - -static void -i860_reloc_processing (arelent *cache_ptr, struct internal_reloc *dst, - asymbol **symbols, bfd *abfd, asection *asect) -{ - if (dst->r_type == COFF860_R_PAIR) - { - /* Handle the PAIR relocation specially. */ - cache_ptr->howto = howto_table + dst->r_type; - cache_ptr->address = dst->r_vaddr; - cache_ptr->addend = dst->r_symndx; - cache_ptr->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr; - } - else - { - /* For every other relocation, do exactly what coff_slurp_reloc_table - would do (which this code is taken directly from). */ - asymbol *ptr = NULL; - cache_ptr->address = dst->r_vaddr; - - if (dst->r_symndx != -1) - { - if (dst->r_symndx < 0 || dst->r_symndx >= obj_conv_table_size (abfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: warning: illegal symbol index %ld in relocs"), - abfd, dst->r_symndx); - cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - ptr = NULL; - } - else - { - cache_ptr->sym_ptr_ptr = (symbols - + obj_convert (abfd)[dst->r_symndx]); - ptr = *(cache_ptr->sym_ptr_ptr); - } - } - else - { - cache_ptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - ptr = NULL; - } - - /* The symbols definitions that we have read in have been - relocated as if their sections started at 0. But the offsets - refering to the symbols in the raw data have not been - modified, so we have to have a negative addend to compensate. - - Note that symbols which used to be common must be left alone. */ - - /* Calculate any reloc addend by looking at the symbol. */ - CALC_ADDEND (abfd, ptr, (*dst), cache_ptr); - (void) ptr; - - cache_ptr->address -= asect->vma; - - /* Fill in the cache_ptr->howto field from dst->r_type. */ - RTYPE2HOWTO (cache_ptr, dst); - } -} - -#define coff_rtype_to_howto coff_i860_rtype_to_howto -#define coff_bfd_reloc_type_lookup coff_i860_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_i860_reloc_name_lookup - -#define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \ - i860_reloc_processing (relent, reloc, symbols, abfd, section) - -#include "coffcode.h" - -static const bfd_target * -i3coff_object_p(bfd *a) -{ - return coff_object_p (a); -} - -const bfd_target -#ifdef TARGET_SYM - TARGET_SYM = -#else - i860_coff_vec = -#endif -{ -#ifdef TARGET_NAME - TARGET_NAME, -#else - "coff-i860", /* name */ -#endif - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - -/* Note that we allow an object file to be treated as a core file as well. */ - {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, i3coff_object_p}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - COFF_SWAP_TABLE -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-i960.c b/sdcc/support/sdbinutils/bfd/coff-i960.c deleted file mode 100644 index 8b91bfe1c..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-i960.c +++ /dev/null @@ -1,654 +0,0 @@ -/* BFD back-end for Intel 960 COFF files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define I960 1 -#define BADMAG(x) I960BADMAG(x) - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/i960.h" -#include "coff/internal.h" - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "libcoff.h" /* To allow easier abstraction-breaking. */ - - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) -#define COFF_ALIGN_IN_SECTION_HEADER 1 - -#define GET_SCNHDR_ALIGN H_GET_32 -#define PUT_SCNHDR_ALIGN H_PUT_32 - -/* The i960 does not support an MMU, so COFF_PAGE_SIZE can be - arbitrarily small. */ -#define COFF_PAGE_SIZE 1 - -#define COFF_LONG_FILENAMES - -/* This set of local label names is taken from gas. */ - -static bfd_boolean -coff_i960_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - return (name[0] == 'L' - || (name[0] == '.' - && (name[1] == 'C' - || name[1] == 'I' - || name[1] == '.'))); -} - -/* This is just like the usual CALC_ADDEND, but it includes the - section VMA for PC relative relocs. */ -#ifndef CALC_ADDEND -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ - { \ - coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ - if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ - coffsym = (obj_symbols (abfd) \ - + (cache_ptr->sym_ptr_ptr - symbols)); \ - else if (ptr) \ - coffsym = coff_symbol_from (ptr); \ - if (coffsym != (coff_symbol_type *) NULL \ - && coffsym->native->u.syment.n_scnum == 0) \ - cache_ptr->addend = 0; \ - else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ - && ptr->section != (asection *) NULL) \ - cache_ptr->addend = - (ptr->section->vma + ptr->value); \ - else \ - cache_ptr->addend = 0; \ - if (ptr && (reloc.r_type == 25 || reloc.r_type == 27)) \ - cache_ptr->addend += asect->vma; \ - } -#endif - -#define CALLS 0x66003800 /* Template for 'calls' instruction */ -#define BAL 0x0b000000 /* Template for 'bal' instruction */ -#define BAL_MASK 0x00ffffff - -static bfd_reloc_status_type -optcall_callback (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol_in, - void * data, - asection *input_section, - bfd *ignore_bfd ATTRIBUTE_UNUSED, - char **error_message) -{ - /* This item has already been relocated correctly, but we may be - * able to patch in yet better code - done by digging out the - * correct info on this symbol */ - bfd_reloc_status_type result; - coff_symbol_type *cs = coffsymbol(symbol_in); - - /* Don't do anything with symbols which aren't tied up yet, - except move the reloc. */ - if (bfd_is_und_section (cs->symbol.section)) { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* So the target symbol has to be of coff type, and the symbol - has to have the correct native information within it */ - if ((bfd_asymbol_flavour(&cs->symbol) != bfd_target_coff_flavour) - || (cs->native == (combined_entry_type *)NULL)) - { - /* This is interesting, consider the case where we're outputting coff - from a mix n match input, linking from coff to a symbol defined in a - bout file will cause this match to be true. Should I complain? This - will only work if the bout symbol is non leaf. */ - *error_message = - (char *) _("uncertain calling convention for non-COFF symbol"); - result = bfd_reloc_dangerous; - } - else - { - switch (cs->native->u.syment.n_sclass) - { - case C_LEAFSTAT: - case C_LEAFEXT: - /* This is a call to a leaf procedure, replace instruction with a bal - to the correct location. */ - { - union internal_auxent *aux = &((cs->native+2)->u.auxent); - int word = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address); - int olf = (aux->x_bal.x_balntry - cs->native->u.syment.n_value); - BFD_ASSERT(cs->native->u.syment.n_numaux==2); - - /* We replace the original call instruction with a bal to - the bal entry point - the offset of which is described in - the 2nd auxent of the original symbol. We keep the native - sym and auxents untouched, so the delta between the two - is the offset of the bal entry point. */ - word = ((word + olf) & BAL_MASK) | BAL; - bfd_put_32 (abfd, (bfd_vma) word, - (bfd_byte *) data + reloc_entry->address); - } - result = bfd_reloc_ok; - break; - case C_SCALL: - /* This is a call to a system call, replace with a calls to # */ - BFD_ASSERT(0); - result = bfd_reloc_ok; - break; - default: - result = bfd_reloc_ok; - break; - } - } - return result; -} - -/* i960 COFF is used by VxWorks 5.1. However, VxWorks 5.1 does not - appear to correctly handle a reloc against a symbol defined in the - same object file. It appears to simply discard such relocs, rather - than adding their values into the object file. We handle this here - by converting all relocs against defined symbols into relocs - against the section symbol, when generating a relocatable output - file. - - Note that this function is only called if we are not using the COFF - specific backend linker. It only does something when doing a - relocatable link, which will almost certainly fail when not - generating COFF i960 output, so this function is actually no longer - useful. It was used before this target was converted to use the - COFF specific backend linker. */ - -static bfd_reloc_status_type -coff_i960_relocate (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - asection *osec; - - if (output_bfd == NULL) - { - /* Not generating relocatable output file. */ - return bfd_reloc_continue; - } - - if (bfd_is_und_section (bfd_get_section (symbol))) - { - /* Symbol is not defined, so no need to worry about it. */ - return bfd_reloc_continue; - } - - if (bfd_is_com_section (bfd_get_section (symbol))) - { - /* I don't really know what the right action is for a common - symbol. */ - return bfd_reloc_continue; - } - - /* Convert the reloc to use the section symbol. FIXME: This method - is ridiculous. */ - osec = bfd_get_section (symbol)->output_section; - if (coff_section_data (output_bfd, osec) != NULL - && coff_section_data (output_bfd, osec)->tdata != NULL) - reloc_entry->sym_ptr_ptr = - (asymbol **) coff_section_data (output_bfd, osec)->tdata; - else - { - const char *sec_name; - asymbol **syms, **sym_end; - - sec_name = bfd_get_section_name (output_bfd, osec); - syms = bfd_get_outsymbols (output_bfd); - sym_end = syms + bfd_get_symcount (output_bfd); - for (; syms < sym_end; syms++) - { - if (bfd_asymbol_name (*syms) != NULL - && (*syms)->value == 0 - && strcmp ((*syms)->section->output_section->name, - sec_name) == 0) - break; - } - - if (syms >= sym_end) - abort (); - - reloc_entry->sym_ptr_ptr = syms; - - if (coff_section_data (output_bfd, osec) == NULL) - { - bfd_size_type amt = sizeof (struct coff_section_tdata); - osec->used_by_bfd = bfd_zalloc (abfd, amt); - if (osec->used_by_bfd == NULL) - return bfd_reloc_overflow; - } - coff_section_data (output_bfd, osec)->tdata = syms; - } - - /* Let bfd_perform_relocation do its thing, which will include - stuffing the symbol addend into the object file. */ - return bfd_reloc_continue; -} - -static reloc_howto_type howto_rellong = - HOWTO ((unsigned int) R_RELLONG, 0, 2, 32,FALSE, 0, - complain_overflow_bitfield, coff_i960_relocate,"rellong", TRUE, - 0xffffffff, 0xffffffff, 0); -static reloc_howto_type howto_iprmed = - HOWTO (R_IPRMED, 0, 2, 24,TRUE,0, complain_overflow_signed, - coff_i960_relocate, "iprmed ", TRUE, 0x00ffffff, 0x00ffffff, 0); -static reloc_howto_type howto_optcall = - HOWTO (R_OPTCALL, 0,2,24,TRUE,0, complain_overflow_signed, - optcall_callback, "optcall", TRUE, 0x00ffffff, 0x00ffffff, 0); - -static reloc_howto_type * -coff_i960_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - default: - return 0; - case BFD_RELOC_I960_CALLJ: - return &howto_optcall; - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - return &howto_rellong; - case BFD_RELOC_24_PCREL: - return &howto_iprmed; - } -} - -static reloc_howto_type * -coff_i960_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - if (strcasecmp (howto_optcall.name, r_name) == 0) - return &howto_optcall; - if (strcasecmp (howto_rellong.name, r_name) == 0) - return &howto_rellong; - if (strcasecmp (howto_iprmed.name, r_name) == 0) - return &howto_iprmed; - - return NULL; -} - -/* The real code is in coffcode.h */ - -#define RTYPE2HOWTO(cache_ptr, dst) \ -{ \ - reloc_howto_type *howto_ptr; \ - switch ((dst)->r_type) { \ - case 17: howto_ptr = &howto_rellong; break; \ - case 25: howto_ptr = &howto_iprmed; break; \ - case 27: howto_ptr = &howto_optcall; break; \ - default: howto_ptr = 0; break; \ - } \ - (cache_ptr)->howto = howto_ptr; \ - } - -/* i960 COFF is used by VxWorks 5.1. However, VxWorks 5.1 does not - appear to correctly handle a reloc against a symbol defined in the - same object file. It appears to simply discard such relocs, rather - than adding their values into the object file. We handle this by - converting all relocs against global symbols into relocs against - internal symbols at the start of the section. This routine is - called at the start of the linking process, and it creates the - necessary symbols. */ - -static bfd_boolean -coff_i960_start_final_link (bfd *abfd, struct bfd_link_info *info) -{ - bfd_size_type symesz = bfd_coff_symesz (abfd); - asection *o; - bfd_byte *esym; - - if (! bfd_link_relocatable (info)) - return TRUE; - - esym = (bfd_byte *) bfd_malloc (symesz); - if (esym == NULL) - return FALSE; - - if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) - return FALSE; - - for (o = abfd->sections; o != NULL; o = o->next) - { - struct internal_syment isym; - - strncpy (isym._n._n_name, o->name, SYMNMLEN); - isym.n_value = 0; - isym.n_scnum = o->target_index; - isym.n_type = T_NULL; - isym.n_sclass = C_STAT; - isym.n_numaux = 0; - - bfd_coff_swap_sym_out (abfd, &isym, esym); - - if (bfd_bwrite (esym, symesz, abfd) != symesz) - { - free (esym); - return FALSE; - } - - obj_raw_syment_count (abfd) += 1; - } - - free (esym); - - return TRUE; -} - -/* The reloc processing routine for the optimized COFF linker. */ - -static bfd_boolean -coff_i960_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct coff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma addend; - bfd_vma val; - reloc_howto_type *howto; - bfd_reloc_status_type rstat = bfd_reloc_ok; - bfd_boolean done; - - symndx = rel->r_symndx; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else - { - h = obj_coff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - } - - if (sym != NULL && sym->n_scnum != 0) - addend = - sym->n_value; - else - addend = 0; - - switch (rel->r_type) - { - case 17: howto = &howto_rellong; break; - case 25: howto = &howto_iprmed; break; - case 27: howto = &howto_optcall; break; - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - val = 0; - - if (h == NULL) - { - asection *sec; - - if (symndx == -1) - { - sec = bfd_abs_section_ptr; - val = 0; - } - else - { - sec = sections[symndx]; - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value - - sec->vma); - } - } - else - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *sec; - - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else if (! bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - } - - done = FALSE; - - if (howto->type == R_OPTCALL && ! bfd_link_relocatable (info) && symndx != -1) - { - int class_val; - - if (h != NULL) - class_val = h->symbol_class; - else - class_val = sym->n_sclass; - - switch (class_val) - { - case C_NULL: - /* This symbol is apparently not from a COFF input file. - We warn, and then assume that it is not a leaf - function. */ - (*info->callbacks->reloc_dangerous) - (info, - _("uncertain calling convention for non-COFF symbol"), - input_bfd, input_section, - rel->r_vaddr - input_section->vma); - break; - case C_LEAFSTAT: - case C_LEAFEXT: - /* This is a call to a leaf procedure; use the bal - instruction. */ - { - long olf; - unsigned long word; - - if (h != NULL) - { - BFD_ASSERT (h->numaux == 2); - olf = h->aux[1].x_bal.x_balntry; - } - else - { - bfd_byte *esyms; - union internal_auxent aux; - - BFD_ASSERT (sym->n_numaux == 2); - esyms = (bfd_byte *) obj_coff_external_syms (input_bfd); - esyms += (symndx + 2) * bfd_coff_symesz (input_bfd); - bfd_coff_swap_aux_in (input_bfd, esyms, sym->n_type, - sym->n_sclass, 1, sym->n_numaux, - &aux); - olf = aux.x_bal.x_balntry; - } - - word = bfd_get_32 (input_bfd, - (contents - + (rel->r_vaddr - input_section->vma))); - word = ((word + olf - val) & BAL_MASK) | BAL; - bfd_put_32 (input_bfd, - (bfd_vma) word, - contents + (rel->r_vaddr - input_section->vma)); - done = TRUE; - } - break; - case C_SCALL: - BFD_ASSERT (0); - break; - } - } - - if (! done) - { - if (howto->pc_relative) - addend += input_section->vma; - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, - rel->r_vaddr - input_section->vma, - val, addend); - } - - switch (rstat) - { - default: - abort (); - case bfd_reloc_ok: - break; - case bfd_reloc_overflow: - { - const char *name; - char buf[SYMNMLEN + 1]; - - if (symndx == -1) - name = "*ABS*"; - else if (h != NULL) - name = NULL; - else - { - name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); - if (name == NULL) - return FALSE; - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - } - } - - return TRUE; -} - -/* Adjust the symbol index of any reloc against a global symbol to - instead be a reloc against the internal symbol we created specially - for the section. */ - -static bfd_boolean -coff_i960_adjust_symndx (bfd *obfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *ibfd, - asection *sec ATTRIBUTE_UNUSED, - struct internal_reloc *irel, - bfd_boolean *adjustedp) -{ - struct coff_link_hash_entry *h; - - *adjustedp = FALSE; - - h = obj_coff_sym_hashes (ibfd)[irel->r_symndx]; - if (h == NULL - || (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak)) - return TRUE; - - irel->r_symndx = h->root.u.def.section->output_section->target_index - 1; - *adjustedp = TRUE; - - return TRUE; -} - -#define coff_bfd_is_local_label_name coff_i960_is_local_label_name - -#define coff_start_final_link coff_i960_start_final_link - -#define coff_relocate_section coff_i960_relocate_section - -#define coff_adjust_symndx coff_i960_adjust_symndx - -#define coff_bfd_reloc_type_lookup coff_i960_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_i960_reloc_name_lookup - -#include "coffcode.h" - -extern const bfd_target icoff_be_vec; - -CREATE_LITTLE_COFF_TARGET_VEC (icoff_le_vec, "coff-Intel-little", 0, 0, '_', & icoff_be_vec, COFF_SWAP_TABLE) - -const bfd_target icoff_be_vec = -{ - "coff-Intel-big", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - -bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* 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, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, /* bfd_set_format */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & icoff_le_vec, - - COFF_SWAP_TABLE -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-ia64.c b/sdcc/support/sdbinutils/bfd/coff-ia64.c deleted file mode 100644 index 56100dd4c..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-ia64.c +++ /dev/null @@ -1,202 +0,0 @@ -/* BFD back-end for HP/Intel IA-64 COFF files. - Copyright (C) 1999-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/ia64.h" -#include "coff/internal.h" -#include "coff/pe.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) - -/* Windows ia64 uses 8K page size. */ -#define COFF_PAGE_SIZE 0x2000 - -static reloc_howto_type howto_table[] = -{ - EMPTY_HOWTO (0), -}; - -#define BADMAG(x) IA64BADMAG(x) -#define IA64 1 /* Customize coffcode.h */ - -#ifdef COFF_WITH_pep -# undef AOUTSZ -# define AOUTSZ PEPAOUTSZ -# define PEAOUTHDR PEPAOUTHDR -#endif - -#define RTYPE2HOWTO(cache_ptr, dst) \ - (cache_ptr)->howto = howto_table; - -#ifdef COFF_WITH_PE -/* Return TRUE if this relocation should - appear in the output .reloc section. */ - -static bfd_boolean -in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, - reloc_howto_type *howto ATTRIBUTE_UNUSED) -{ - return FALSE; /* We don't do relocs for now... */ -} -#endif - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -static const bfd_target * -ia64coff_object_p (bfd *abfd) -{ -#ifdef COFF_IMAGE_WITH_PE - { - struct external_PEI_DOS_hdr dos_hdr; - struct external_PEI_IMAGE_hdr image_hdr; - file_ptr offset; - - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 - || (bfd_bread (&dos_hdr, (bfd_size_type) sizeof (dos_hdr), abfd) - != sizeof (dos_hdr))) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - /* There are really two magic numbers involved; the magic number - that says this is a NT executable (PEI) and the magic number - that determines the architecture. The former is DOSMAGIC, - stored in the e_magic field. The latter is stored in the - f_magic field. If the NT magic number isn't valid, the - architecture magic number could be mimicked by some other - field (specifically, the number of relocs in section 3). Since - this routine can only be called correctly for a PEI file, check - the e_magic number here, and, if it doesn't match, clobber the - f_magic number so that we don't get a false match. */ - if (H_GET_16 (abfd, dos_hdr.e_magic) != DOSMAGIC) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - offset = H_GET_32 (abfd, dos_hdr.e_lfanew); - if (bfd_seek (abfd, offset, SEEK_SET) != 0 - || (bfd_bread (&image_hdr, (bfd_size_type) sizeof (image_hdr), abfd) - != sizeof (image_hdr))) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - if (H_GET_32 (abfd, image_hdr.nt_signature) - != 0x4550) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - /* Here is the hack. coff_object_p wants to read filhsz bytes to - pick up the COFF header for PE, see "struct external_PEI_filehdr" - in include/coff/pe.h. We adjust so that that will work. */ - if (bfd_seek (abfd, offset - sizeof (dos_hdr), SEEK_SET) != 0) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - } -#endif - - return coff_object_p (abfd); -} - -const bfd_target -#ifdef TARGET_SYM - TARGET_SYM = -#else - ia64coff_vec = -#endif -{ -#ifdef TARGET_NAME - TARGET_NAME, -#else - "coff-ia64", /* name */ -#endif - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - -#ifndef COFF_WITH_PE - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */ - | SEC_CODE | SEC_DATA), -#else - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */ - | SEC_CODE | SEC_DATA - | SEC_LINK_ONCE | SEC_LINK_DUPLICATES), -#endif - -#ifdef TARGET_UNDERSCORE - TARGET_UNDERSCORE, /* leading underscore */ -#else - 0, /* leading underscore */ -#endif - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - -/* Note that we allow an object file to be treated as a core file as well. */ - {_bfd_dummy_target, ia64coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, ia64coff_object_p}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - COFF_SWAP_TABLE -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-m68k.c b/sdcc/support/sdbinutils/bfd/coff-m68k.c deleted file mode 100644 index 0fbff2262..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-m68k.c +++ /dev/null @@ -1,548 +0,0 @@ -/* BFD back-end for Motorola 68000 COFF binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/m68k.h" -#include "coff/internal.h" -#include "libcoff.h" - -/* This source file is compiled multiple times for various m68k COFF - variants. The following macros control its behaviour: - - TARGET_SYM - The C name of the BFD target vector. The default is m68k_coff_vec. - TARGET_NAME - The user visible target name. The default is "coff-m68k". - NAMES_HAVE_UNDERSCORE - Whether symbol names have an underscore. - ONLY_DECLARE_RELOCS - Only declare the relocation howto array. Don't actually compile - it. The actual array will be picked up in another version of the - file. - STATIC_RELOCS - Make the relocation howto array, and associated functions, static. - COFF_COMMON_ADDEND - If this is defined, then, for a relocation against a common - symbol, the object file holds the value (the size) of the common - symbol. If this is not defined, then, for a relocation against a - common symbol, the object file holds zero. */ - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) - -#ifndef COFF_PAGE_SIZE -/* The page size is a guess based on ELF. */ -#define COFF_PAGE_SIZE 0x2000 -#endif - -#ifndef COFF_COMMON_ADDEND -#define RELOC_SPECIAL_FN 0 -#else -static bfd_reloc_status_type m68kcoff_common_addend_special_fn - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -#define RELOC_SPECIAL_FN m68kcoff_common_addend_special_fn -#endif - -static bfd_boolean m68k_coff_is_local_label_name (bfd *, const char *); - -/* On the delta, a symbol starting with L% is local. We won't see - such a symbol on other platforms, so it should be safe to always - consider it local here. */ - -static bfd_boolean -m68k_coff_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == 'L' && name[1] == '%') - return TRUE; - - return _bfd_coff_is_local_label_name (abfd, name); -} - -#ifndef STATIC_RELOCS -/* Clean up namespace. */ -#define m68kcoff_howto_table _bfd_m68kcoff_howto_table -#define m68k_rtype2howto _bfd_m68kcoff_rtype2howto -#define m68k_howto2rtype _bfd_m68kcoff_howto2rtype -#define m68k_reloc_type_lookup _bfd_m68kcoff_reloc_type_lookup -#define m68k_reloc_name_lookup _bfd_m68kcoff_reloc_name_lookup -#endif - -#ifdef ONLY_DECLARE_RELOCS -extern reloc_howto_type m68kcoff_howto_table[]; -#else -#ifdef STATIC_RELOCS -static -#endif -reloc_howto_type m68kcoff_howto_table[] = - { - HOWTO (R_RELBYTE, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, RELOC_SPECIAL_FN, "8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (R_RELWORD, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, RELOC_SPECIAL_FN, "16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (R_RELLONG, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, RELOC_SPECIAL_FN, "32", TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO (R_PCRBYTE, 0, 0, 8, TRUE, 0, complain_overflow_signed, RELOC_SPECIAL_FN, "DISP8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO (R_PCRWORD, 0, 1, 16, TRUE, 0, complain_overflow_signed, RELOC_SPECIAL_FN, "DISP16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO (R_PCRLONG, 0, 2, 32, TRUE, 0, complain_overflow_signed, RELOC_SPECIAL_FN, "DISP32", TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO (R_RELLONG_NEG, 0, -2, 32, FALSE, 0, complain_overflow_bitfield, RELOC_SPECIAL_FN, "-32", TRUE, 0xffffffff,0xffffffff, FALSE), - }; -#endif /* not ONLY_DECLARE_RELOCS */ - -#ifndef BADMAG -#define BADMAG(x) M68KBADMAG(x) -#endif -#define M68 1 /* Customize coffcode.h */ - -/* Turn a howto into a reloc number */ - -#ifdef ONLY_DECLARE_RELOCS -extern void m68k_rtype2howto (arelent *internal, int relocentry); -extern int m68k_howto2rtype (reloc_howto_type *); -extern reloc_howto_type * m68k_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -extern reloc_howto_type * m68k_reloc_name_lookup (bfd *, const char *); -#else - -#ifdef STATIC_RELOCS -#define STAT_REL static -#else -#define STAT_REL -#endif - -STAT_REL void m68k_rtype2howto (arelent *, int); -STAT_REL int m68k_howto2rtype (reloc_howto_type *); -STAT_REL reloc_howto_type * m68k_reloc_type_lookup (bfd *, bfd_reloc_code_real_type); -STAT_REL reloc_howto_type * m68k_reloc_name_lookup (bfd *, const char *); - -STAT_REL void -m68k_rtype2howto (arelent *internal, int relocentry) -{ - switch (relocentry) - { - case R_RELBYTE: internal->howto = m68kcoff_howto_table + 0; break; - case R_RELWORD: internal->howto = m68kcoff_howto_table + 1; break; - case R_RELLONG: internal->howto = m68kcoff_howto_table + 2; break; - case R_PCRBYTE: internal->howto = m68kcoff_howto_table + 3; break; - case R_PCRWORD: internal->howto = m68kcoff_howto_table + 4; break; - case R_PCRLONG: internal->howto = m68kcoff_howto_table + 5; break; - case R_RELLONG_NEG: internal->howto = m68kcoff_howto_table + 6; break; - default: internal->howto = NULL; break; - } -} - -STAT_REL int -m68k_howto2rtype (reloc_howto_type * internal) -{ - if (internal->pc_relative) - { - switch (internal->bitsize) - { - case 32: return R_PCRLONG; - case 16: return R_PCRWORD; - case 8: return R_PCRBYTE; - } - } - else - { - switch (internal->bitsize) - { - case 32: return R_RELLONG; - case 16: return R_RELWORD; - case 8: return R_RELBYTE; - } - } - return R_RELLONG; -} - -STAT_REL reloc_howto_type * -m68k_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - default: return NULL; - case BFD_RELOC_8: return m68kcoff_howto_table + 0; - case BFD_RELOC_16: return m68kcoff_howto_table + 1; - case BFD_RELOC_CTOR: - case BFD_RELOC_32: return m68kcoff_howto_table + 2; - case BFD_RELOC_8_PCREL: return m68kcoff_howto_table + 3; - case BFD_RELOC_16_PCREL: return m68kcoff_howto_table + 4; - case BFD_RELOC_32_PCREL: return m68kcoff_howto_table + 5; - /* FIXME: There doesn't seem to be a code for R_RELLONG_NEG. */ - } - /*NOTREACHED*/ -} - -STAT_REL reloc_howto_type * -m68k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (m68kcoff_howto_table) / sizeof (m68kcoff_howto_table[0]); - i++) - if (m68kcoff_howto_table[i].name != NULL - && strcasecmp (m68kcoff_howto_table[i].name, r_name) == 0) - return &m68kcoff_howto_table[i]; - - return NULL; -} - -#endif /* not ONLY_DECLARE_RELOCS */ - -#define RTYPE2HOWTO(internal, relocentry) \ - m68k_rtype2howto(internal, (relocentry)->r_type) - -#define SELECT_RELOC(external, internal) \ - external.r_type = m68k_howto2rtype (internal) - -#define coff_bfd_reloc_type_lookup m68k_reloc_type_lookup -#define coff_bfd_reloc_name_lookup m68k_reloc_name_lookup - -#ifndef COFF_COMMON_ADDEND -#ifndef coff_rtype_to_howto - -#define coff_rtype_to_howto m68kcoff_rtype_to_howto - -static reloc_howto_type * -m68kcoff_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - bfd_vma *addendp) -{ - arelent relent; - reloc_howto_type *howto; - - relent.howto = NULL; - RTYPE2HOWTO (&relent, rel); - - howto = relent.howto; - - if (howto != NULL && howto->pc_relative) - *addendp += sec->vma; - - return howto; -} - -#endif /* ! defined (coff_rtype_to_howto) */ -#endif /* ! defined (COFF_COMMON_ADDEND) */ - -#ifdef COFF_COMMON_ADDEND - -/* If COFF_COMMON_ADDEND is defined, then when using m68k COFF the - value stored in the .text section for a reference to a common - symbol is the value itself plus any desired offset. (taken from - work done by Ian Taylor, Cygnus Support, for I386 COFF). */ - -/* If we are producing relocatable output, we need to do some - adjustments to the object file that are not done by the - bfd_perform_relocation function. This function is called by every - reloc type to make any required adjustments. */ - -static bfd_reloc_status_type -m68kcoff_common_addend_special_fn (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - symvalue diff; - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - if (bfd_is_com_section (symbol->section)) - { - /* We are relocating a common symbol. The current value in the - object file is ORIG + OFFSET, where ORIG is the value of the - common symbol as seen by the object file when it was compiled - (this may be zero if the symbol was undefined) and OFFSET is - the offset into the common symbol (normally zero, but may be - non-zero when referring to a field in a common structure). - ORIG is the negative of reloc_entry->addend, which is set by - the CALC_ADDEND macro below. We want to replace the value in - the object file with NEW + OFFSET, where NEW is the value of - the common symbol which we are going to put in the final - object file. NEW is symbol->value. */ - diff = symbol->value + reloc_entry->addend; - } - else - { - /* For some reason bfd_perform_relocation always effectively - ignores the addend for a COFF target when producing - relocatable output. This seems to be always wrong for 386 - COFF, so we handle the addend here instead. */ - diff = reloc_entry->addend; - } - -#define DOIT(x) \ - x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) - - if (diff != 0) - { - reloc_howto_type *howto = reloc_entry->howto; - unsigned char *addr = (unsigned char *) data + reloc_entry->address; - - if (! bfd_reloc_offset_in_range (howto, abfd, input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - switch (howto->size) - { - case 0: - { - char x = bfd_get_8 (abfd, addr); - DOIT (x); - bfd_put_8 (abfd, x, addr); - } - break; - - case 1: - { - short x = bfd_get_16 (abfd, addr); - DOIT (x); - bfd_put_16 (abfd, (bfd_vma) x, addr); - } - break; - - case 2: - { - long x = bfd_get_32 (abfd, addr); - DOIT (x); - bfd_put_32 (abfd, (bfd_vma) x, addr); - } - break; - - default: - abort (); - } - } - - /* Now let bfd_perform_relocation finish everything up. */ - return bfd_reloc_continue; -} - -/* Compute the addend of a reloc. If the reloc is to a common symbol, - the object file contains the value of the common symbol. By the - time this is called, the linker may be using a different symbol - from a different object file with a different value. Therefore, we - hack wildly to locate the original symbol from this file so that we - can make the correct adjustment. This macro sets coffsym to the - symbol from the original file, and uses it to set the addend value - correctly. If this is not a common symbol, the usual addend - calculation is done, except that an additional tweak is needed for - PC relative relocs. - FIXME: This macro refers to symbols and asect; these are from the - calling function, not the macro arguments. */ - -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ - { \ - coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ - if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ - coffsym = (obj_symbols (abfd) \ - + (cache_ptr->sym_ptr_ptr - symbols)); \ - else if (ptr) \ - coffsym = coff_symbol_from (ptr); \ - if (coffsym != (coff_symbol_type *) NULL \ - && coffsym->native->u.syment.n_scnum == 0) \ - cache_ptr->addend = - coffsym->native->u.syment.n_value; \ - else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ - && ptr->section != (asection *) NULL) \ - cache_ptr->addend = - (ptr->section->vma + ptr->value); \ - else \ - cache_ptr->addend = 0; \ - if (ptr && (reloc.r_type == R_PCRBYTE \ - || reloc.r_type == R_PCRWORD \ - || reloc.r_type == R_PCRLONG)) \ - cache_ptr->addend += asect->vma; \ - } - -#ifndef coff_rtype_to_howto - -/* coff-m68k.c uses the special COFF backend linker. We need to - adjust common symbols. */ - -static reloc_howto_type * -m68kcoff_common_addend_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h, - struct internal_syment *sym, - bfd_vma *addendp) -{ - arelent relent; - reloc_howto_type *howto; - - relent.howto = NULL; - RTYPE2HOWTO (&relent, rel); - - howto = relent.howto; - - if (howto->pc_relative) - *addendp += sec->vma; - - if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) - { - /* This is a common symbol. The section contents include the - size (sym->n_value) as an addend. The relocate_section - function will be adding in the final value of the symbol. We - need to subtract out the current size in order to get the - correct result. */ - BFD_ASSERT (h != NULL); - *addendp -= sym->n_value; - } - - /* If the output symbol is common (in which case this must be a - relocatable link), we need to add in the final size of the - common symbol. */ - if (h != NULL && h->root.type == bfd_link_hash_common) - *addendp += h->root.u.c.size; - - return howto; -} - -#define coff_rtype_to_howto m68kcoff_common_addend_rtype_to_howto - -#endif /* ! defined (coff_rtype_to_howto) */ - -#endif /* COFF_COMMON_ADDEND */ - -#if !defined ONLY_DECLARE_RELOCS && ! defined STATIC_RELOCS -/* Given a .data section and a .emreloc in-memory section, store - relocation information into the .emreloc section which can be - used at runtime to relocate the section. This is called by the - linker when the --embedded-relocs switch is used. This is called - after the add_symbols entry point has been called for all the - objects, and before the final_link entry point is called. */ - -bfd_boolean -bfd_m68k_coff_create_embedded_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *datasec, - asection *relsec, - char **errmsg) -{ - char *extsyms; - bfd_size_type symesz; - struct internal_reloc *irel, *irelend; - bfd_byte *p; - bfd_size_type amt; - - BFD_ASSERT (! bfd_link_relocatable (info)); - - *errmsg = NULL; - - if (datasec->reloc_count == 0) - return TRUE; - - extsyms = obj_coff_external_syms (abfd); - symesz = bfd_coff_symesz (abfd); - - irel = _bfd_coff_read_internal_relocs (abfd, datasec, TRUE, NULL, FALSE, - NULL); - irelend = irel + datasec->reloc_count; - - amt = (bfd_size_type) datasec->reloc_count * 12; - relsec->contents = (bfd_byte *) bfd_alloc (abfd, amt); - if (relsec->contents == NULL) - return FALSE; - - p = relsec->contents; - - for (; irel < irelend; irel++, p += 12) - { - asection *targetsec; - - /* We are going to write a four byte longword into the runtime - reloc section. The longword will be the address in the data - section which must be relocated. It is followed by the name - of the target section NUL-padded or truncated to 8 - characters. */ - - /* We can only relocate absolute longword relocs at run time. */ - if (irel->r_type != R_RELLONG) - { - *errmsg = _("unsupported reloc type"); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (irel->r_symndx == -1) - targetsec = bfd_abs_section_ptr; - else - { - struct coff_link_hash_entry *h; - - h = obj_coff_sym_hashes (abfd)[irel->r_symndx]; - if (h == NULL) - { - struct internal_syment isym; - - bfd_coff_swap_sym_in (abfd, extsyms + symesz * irel->r_symndx, - &isym); - targetsec = coff_section_from_bfd_index (abfd, isym.n_scnum); - } - else if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - targetsec = h->root.u.def.section; - else - targetsec = NULL; - } - - bfd_put_32 (abfd, - (irel->r_vaddr - datasec->vma + datasec->output_offset), p); - memset (p + 4, 0, 8); - if (targetsec != NULL) - strncpy ((char *) p + 4, targetsec->output_section->name, 8); - } - - return TRUE; -} -#endif /* neither ONLY_DECLARE_RELOCS not STATIC_RELOCS */ - -#define coff_bfd_is_local_label_name m68k_coff_is_local_label_name - -#define coff_relocate_section _bfd_coff_generic_relocate_section - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#ifndef TARGET_SYM -#define TARGET_SYM m68k_coff_vec -#endif - -#ifndef TARGET_NAME -#define TARGET_NAME "coff-m68k" -#endif - -#ifdef NAMES_HAVE_UNDERSCORE -CREATE_BIG_COFF_TARGET_VEC (TARGET_SYM, TARGET_NAME, D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE) -#else -CREATE_BIG_COFF_TARGET_VEC (TARGET_SYM, TARGET_NAME, D_PAGED, 0, 0, NULL, COFF_SWAP_TABLE) -#endif diff --git a/sdcc/support/sdbinutils/bfd/coff-m88k.c b/sdcc/support/sdbinutils/bfd/coff-m88k.c deleted file mode 100644 index 93a2d4872..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-m88k.c +++ /dev/null @@ -1,291 +0,0 @@ -/* BFD back-end for Motorola 88000 COFF "Binary Compatibility Standard" files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define M88 1 /* Customize various include files */ -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/m88k.h" -#include "coff/internal.h" -#include "libcoff.h" - -static bfd_reloc_status_type m88k_special_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) - -#define GET_SCNHDR_NRELOC H_GET_32 -#define GET_SCNHDR_NLNNO H_GET_32 - -/* On coff-m88k, local labels start with '@'. */ - -#define coff_bfd_is_local_label_name m88k_is_local_label_name - -static bfd_boolean -m88k_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - return name[0] == '@'; -} - -static bfd_reloc_status_type -m88k_special_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - reloc_howto_type *howto = reloc_entry->howto; - - switch (howto->type) - { - case R_HVRT16: - case R_LVRT16: - if (output_bfd != (bfd *) NULL) - { - /* 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->address += input_section->output_offset; - } - else - { - bfd_vma output_base = 0; - bfd_vma addr = reloc_entry->address; - bfd_vma x; - asection *reloc_target_output_section; - long relocation = 0; - - if (! bfd_reloc_offset_in_range (howto, abfd, input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - x = bfd_get_16 (abfd, (bfd_byte *) data + addr); - - /* 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) - 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 << howto->bitsize) + x); - - reloc_entry->addend = 0; - - relocation >>= (bfd_vma) howto->rightshift; - - /* Shift everything up to where it's going to be used */ - - relocation <<= (bfd_vma) howto->bitpos; - - if (relocation) - bfd_put_16 (abfd, (bfd_vma) relocation, - (unsigned char *) data + addr); - } - - /* If we are not producing relocatable output, return an error if - the symbol is not defined. */ - if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - return bfd_reloc_ok; - - default: - if (output_bfd != (bfd *) NULL) - { - /* 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->address += input_section->output_offset; - return bfd_reloc_ok; - } - break; - } - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_ok; -} - -static reloc_howto_type howto_table[] = -{ - HOWTO (R_PCR16L, /* type */ - 02, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - m88k_special_reloc, /* special_function */ - "PCR16L", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_PCR26L, /* type */ - 02, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - m88k_special_reloc, /* special_function */ - "PCR26L", /* name */ - FALSE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_VRT16, /* type */ - 00, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - m88k_special_reloc, /* special_function */ - "VRT16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_HVRT16, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m88k_special_reloc, /* special_function */ - "HVRT16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_LVRT16, /* type */ - 00, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m88k_special_reloc, /* special_function */ - "LVRT16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_VRT32, /* type */ - 00, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - m88k_special_reloc, /* special_function */ - "VRT32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* Code to turn an external r_type into a pointer to an entry in the - above howto table. */ -static void -rtype2howto (arelent *cache_ptr, struct internal_reloc *dst) -{ - if (dst->r_type >= R_PCR16L && dst->r_type <= R_VRT32) - { - cache_ptr->howto = howto_table + dst->r_type - R_PCR16L; - } - else - { - BFD_ASSERT (0); - } -} - -#define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst) - -/* Code to swap in the reloc offset */ -#define SWAP_IN_RELOC_OFFSET H_GET_16 -#define SWAP_OUT_RELOC_OFFSET H_PUT_16 - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing(relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent *relent, - struct internal_reloc *reloc, - asymbol **symbols, - bfd *abfd, - asection *section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (((int) reloc->r_symndx) > 0) - { - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - } - else - { - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - } - - relent->addend = reloc->r_offset; - relent->address -= section->vma; -} - -#define BADMAG(x) MC88BADMAG(x) - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#undef coff_write_armap - -CREATE_BIG_COFF_TARGET_VEC (m88k_coff_bcs_vec, "coff-m88kbcs", 0, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-mcore.c b/sdcc/support/sdbinutils/bfd/coff-mcore.c deleted file mode 100644 index 80432d1ee..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-mcore.c +++ /dev/null @@ -1,561 +0,0 @@ -/* BFD back-end for Motorola MCore COFF/PE - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/mcore.h" -#include "coff/internal.h" -#include "coff/pe.h" -#include "libcoff.h" - -#ifdef BADMAG -#undef BADMAG -#endif -#define BADMAG(x) MCOREBADMAG(x) - -#ifndef NUM_ELEM -#define NUM_ELEM(A) (sizeof (A) / sizeof (A)[0]) -#endif - -/* This file is compiled more than once, but we only compile the - final_link routine once. */ -extern bfd_boolean mcore_bfd_coff_final_link - (bfd *, struct bfd_link_info *); -static bfd_reloc_status_type mcore_coff_unsupported_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - - -/* The NT loader points the toc register to &toc + 32768, in order to - use the complete range of a 16-bit displacement. We have to adjust - for this when we fix up loads displaced off the toc reg. */ -#define TOC_LOAD_ADJUSTMENT (-32768) -#define TOC_SECTION_NAME ".private.toc" - -/* The main body of code is in coffcode.h. */ -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2 - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -static reloc_howto_type mcore_coff_howto_table[] = -{ - /* Unused: */ - HOWTO (IMAGE_REL_MCORE_ABSOLUTE,/* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* dont complain_on_overflow */ - NULL, /* special_function */ - "ABSOLUTE", /* name */ - FALSE, /* partial_inplace */ - 0x00, /* src_mask */ - 0x00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (IMAGE_REL_MCORE_ADDR32,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - NULL, /* special_function */ - "ADDR32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 8 bits + 2 zero bits; jmpi/jsri/lrw instructions. - Should not appear in object files. */ - HOWTO (IMAGE_REL_MCORE_PCREL_IMM8BY4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mcore_coff_unsupported_reloc, /* special_function */ - "IMM8BY4", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* bsr/bt/bf/br instructions; 11 bits + 1 zero bit - Span 2k instructions == 4k bytes. - Only useful pieces at the relocated address are the opcode (5 bits) */ - HOWTO (IMAGE_REL_MCORE_PCREL_IMM11BY2,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - NULL, /* special_function */ - "IMM11BY2", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x7ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 4 bits + 1 zero bit; 'loopt' instruction only; unsupported. */ - HOWTO (IMAGE_REL_MCORE_PCREL_IMM4BY2, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 4, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mcore_coff_unsupported_reloc, /* special_function */ - "IMM4BY2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32-bit pc-relative. Eventually this will help support PIC code. */ - HOWTO (IMAGE_REL_MCORE_PCREL_32,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - NULL, /* special_function */ - "PCREL_32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like PCREL_IMM11BY2, this relocation indicates that there is a - 'jsri' at the specified address. There is a separate relocation - entry for the literal pool entry that it references, but we - might be able to change the jsri to a bsr if the target turns out - to be close enough [even though we won't reclaim the literal pool - entry, we'll get some runtime efficiency back]. Note that this - is a relocation that we are allowed to safely ignore. */ - HOWTO (IMAGE_REL_MCORE_PCREL_JSR_IMM11BY2,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - NULL, /* special_function */ - "JSR_IMM11BY2", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x7ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (IMAGE_REL_MCORE_RVA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - NULL, /* special_function */ - "MCORE_RVA", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE) /* pcrel_offset */ -}; - -/* Extend the coff_link_hash_table structure with a few M*Core specific fields. - This allows us to store global data here without actually creating any - global variables, which is a no-no in the BFD world. */ -typedef struct coff_mcore_link_hash_table -{ - /* The original coff_link_hash_table structure. MUST be first field. */ - struct coff_link_hash_table root; - - bfd * bfd_of_toc_owner; - long int global_toc_size; - long int import_table_size; - long int first_thunk_address; - long int thunk_size; -} -mcore_hash_table; - -/* Get the MCore coff linker hash table from a link_info structure. */ -#define coff_mcore_hash_table(info) \ - ((mcore_hash_table *) ((info)->hash)) - - -/* Add an entry to the base file. */ - -static bfd_boolean -mcore_emit_base_file_entry (struct bfd_link_info *info, - bfd *output_bfd, - asection *input_section, - bfd_vma reloc_offset) -{ - bfd_vma addr = reloc_offset - - input_section->vma - + input_section->output_offset - + input_section->output_section->vma; - - if (coff_data (output_bfd)->pe) - addr -= pe_data (output_bfd)->pe_opthdr.ImageBase; - - if (fwrite (&addr, sizeof (addr), 1, (FILE *) info->base_file) == 1) - return TRUE; - - bfd_set_error (bfd_error_system_call); - return FALSE; -} - -static bfd_reloc_status_type -mcore_coff_unsupported_reloc (bfd * abfd, - arelent * reloc_entry, - asymbol * symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection * input_section ATTRIBUTE_UNUSED, - bfd * output_bfd ATTRIBUTE_UNUSED, - char ** error_message ATTRIBUTE_UNUSED) -{ - BFD_ASSERT (reloc_entry->howto != (reloc_howto_type *)0); - - /* xgettext: c-format */ - _bfd_error_handler (_("%B: Relocation %s (%d) is not currently supported.\n"), - abfd, - reloc_entry->howto->name, - reloc_entry->howto->type); - - return bfd_reloc_notsupported; -} - -/* A cheesy little macro to make the code a little more readable. */ -#define HOW2MAP(bfd_rtype, mcore_rtype) \ - case bfd_rtype: return & mcore_coff_howto_table [mcore_rtype] - -static reloc_howto_type * -mcore_coff_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - HOW2MAP (BFD_RELOC_32, IMAGE_REL_MCORE_ADDR32); - HOW2MAP (BFD_RELOC_MCORE_PCREL_IMM8BY4, IMAGE_REL_MCORE_PCREL_IMM8BY4); - HOW2MAP (BFD_RELOC_MCORE_PCREL_IMM11BY2, IMAGE_REL_MCORE_PCREL_IMM11BY2); - HOW2MAP (BFD_RELOC_MCORE_PCREL_IMM4BY2, IMAGE_REL_MCORE_PCREL_IMM4BY2); - HOW2MAP (BFD_RELOC_32_PCREL, IMAGE_REL_MCORE_PCREL_32); - HOW2MAP (BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, IMAGE_REL_MCORE_PCREL_JSR_IMM11BY2); - HOW2MAP (BFD_RELOC_RVA, IMAGE_REL_MCORE_RVA); - default: - return NULL; - } - /*NOTREACHED*/ -} -#undef HOW2MAP - -#define NUM_HOWTOS NUM_ELEM (mcore_coff_howto_table) - -static reloc_howto_type * -mcore_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < NUM_HOWTOS; i++) - if (mcore_coff_howto_table[i].name != NULL - && strcasecmp (mcore_coff_howto_table[i].name, r_name) == 0) - return &mcore_coff_howto_table[i]; - - return NULL; -} - -#define RTYPE2HOWTO(cache_ptr, dst) \ - ((cache_ptr)->howto = \ - ((dst)->r_type < NUM_HOWTOS \ - ? mcore_coff_howto_table + (dst)->r_type \ - : NULL)) - -static reloc_howto_type * -coff_mcore_rtype_to_howto (bfd * abfd ATTRIBUTE_UNUSED, - asection * sec, - struct internal_reloc * rel, - struct coff_link_hash_entry * h ATTRIBUTE_UNUSED, - struct internal_syment * sym, - bfd_vma * addendp) -{ - reloc_howto_type * howto; - - if (rel->r_type >= NUM_HOWTOS) - return NULL; - - howto = mcore_coff_howto_table + rel->r_type; - - if (rel->r_type == IMAGE_REL_MCORE_RVA) - * addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; - - else if (howto->pc_relative) - { - * addendp = sec->vma - 2; /* XXX guess - is this right ? */ - - /* If the symbol is defined, then the generic code is going to - add back the symbol value in order to cancel out an - adjustment it made to the addend. However, we set the addend - to 0 at the start of this function. We need to adjust here, - to avoid the adjustment the generic code will make. FIXME: - This is getting a bit hackish. */ - if (sym != NULL && sym->n_scnum != 0) - * addendp -= sym->n_value; - } - else - * addendp = 0; - - return howto; -} - -/* Return TRUE if this relocation should appear in the output .reloc section. - This function is referenced in pe_mkobject in peicode.h. */ - -static bfd_boolean -in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, reloc_howto_type * howto) -{ - return ! howto->pc_relative && howto->type != IMAGE_REL_MCORE_RVA; -} - -/* The reloc processing routine for the optimized COFF linker. */ -static bfd_boolean -coff_mcore_relocate_section (bfd * output_bfd, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - struct internal_reloc * relocs, - struct internal_syment * syms, - asection ** sections) -{ - struct internal_reloc * rel; - struct internal_reloc * relend; - - /* If we are performing a relocatable link, we don't need to do a - thing. The caller will take care of adjusting the reloc - addresses and symbol indices. */ - if (bfd_link_relocatable (info)) - return TRUE; - - /* Check if we have the same endianness */ - if ( input_bfd->xvec->byteorder != output_bfd->xvec->byteorder - && output_bfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: compiled for a %s system and target is %s.\n"), - input_bfd, - bfd_big_endian (input_bfd) ? _("big endian") : _("little endian"), - bfd_big_endian (output_bfd) ? _("big endian") : _("little endian")); - - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - rel = relocs; - relend = rel + input_section->reloc_count; - - for (; rel < relend; rel++) - { - long symndx; - struct internal_syment * sym; - bfd_vma val; - bfd_vma addend; - bfd_reloc_status_type rstat; - bfd_byte * loc; - unsigned short r_type = rel->r_type; - reloc_howto_type * howto = NULL; - struct coff_link_hash_entry * h; - const char * my_name; - - symndx = rel->r_symndx; - loc = contents + rel->r_vaddr - input_section->vma; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else - { - h = obj_coff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - } - - addend = 0; - - /* Get the howto and initialise the addend. */ - howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h, - sym, & addend); - if (howto == NULL) - return FALSE; - - val = 0; - - if (h == NULL) - { - if (symndx == -1) - my_name = "*ABS*"; - else - { - asection * sec = sections[symndx]; - - val = (sym->n_value - + sec->output_section->vma - + sec->output_offset); - - if (sym == NULL) - my_name = "*unknown*"; - else if ( sym->_n._n_n._n_zeroes == 0 - && sym->_n._n_n._n_offset != 0) - my_name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset; - else - { - static char buf [SYMNMLEN + 1]; - - strncpy (buf, sym->_n._n_name, SYMNMLEN); - buf[SYMNMLEN] = '\0'; - my_name = buf; - } - } - } - else - { - if ( h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection * sec = h->root.u.def.section; - - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - - my_name = h->root.root.string; - } - - rstat = bfd_reloc_ok; - - /* Each case must do its own relocation, setting rstat appropriately. */ - switch (r_type) - { - default: - /* xgettext: c-format */ - _bfd_error_handler (_("%B: unsupported relocation type 0x%02x"), - input_bfd, r_type); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case IMAGE_REL_MCORE_ABSOLUTE: - _bfd_error_handler - /* xgettext: c-format */ - (_("Warning: unsupported reloc %s \n" - "sym %ld (%s), r_vaddr %Ld (%#Lx)"), - howto->name, input_bfd, input_section, - rel->r_symndx, my_name, rel->r_vaddr, rel->r_vaddr); - break; - - case IMAGE_REL_MCORE_PCREL_IMM8BY4: - case IMAGE_REL_MCORE_PCREL_IMM11BY2: - case IMAGE_REL_MCORE_PCREL_IMM4BY2: - case IMAGE_REL_MCORE_PCREL_32: - case IMAGE_REL_MCORE_PCREL_JSR_IMM11BY2: - case IMAGE_REL_MCORE_ADDR32: - /* XXX fixme - shouldn't this be like the code for the RVA reloc ? */ - rstat = _bfd_relocate_contents (howto, input_bfd, val, loc); - break; - - case IMAGE_REL_MCORE_RVA: - rstat = _bfd_final_link_relocate - (howto, input_bfd, - input_section, contents, rel->r_vaddr - input_section->vma, - val, addend); - break; - } - - /* Emit a reloc if the backend thinks it needs it. */ - if (info->base_file - && sym - && pe_data (output_bfd)->in_reloc_p (output_bfd, howto) - && !mcore_emit_base_file_entry (info, output_bfd, input_section, - rel->r_vaddr)) - return FALSE; - - switch (rstat) - { - default: - abort (); - - case bfd_reloc_ok: - break; - - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), my_name, howto->name, - (bfd_vma) 0, input_bfd, - input_section, rel->r_vaddr - input_section->vma); - } - } - - return TRUE; -} - -/* Tailor coffcode.h -- macro heaven. */ - -/* We use the special COFF backend linker, with our own special touch. */ - -#define coff_bfd_reloc_type_lookup mcore_coff_reloc_type_lookup -#define coff_bfd_reloc_name_lookup mcore_coff_reloc_name_lookup -#define coff_relocate_section coff_mcore_relocate_section -#define coff_rtype_to_howto coff_mcore_rtype_to_howto - -#define SELECT_RELOC(internal, howto) {internal.r_type = howto->type;} - -/* Make sure that the 'r_offset' field is copied properly - so that identical binaries will compare the same. */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 - -#define COFF_PAGE_SIZE 0x1000 - -#include "coffcode.h" - -/* Forward declaration to initialise alternative_target field. */ -extern const bfd_target TARGET_LITTLE_SYM; - -/* The transfer vectors that lead the outside world to all of the above. */ -CREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED, - (SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_READONLY | SEC_LINK_ONCE | SEC_LINK_DUPLICATES), - 0, & TARGET_LITTLE_SYM, COFF_SWAP_TABLE) -CREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED, - (SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_READONLY | SEC_LINK_ONCE | SEC_LINK_DUPLICATES), - 0, & TARGET_BIG_SYM, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-mips.c b/sdcc/support/sdbinutils/bfd/coff-mips.c deleted file mode 100644 index 28911339d..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-mips.c +++ /dev/null @@ -1,1502 +0,0 @@ -/* BFD back-end for MIPS Extended-Coff files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Original version by Per Bothner. - Full support added by Ian Lance Taylor, ian@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "coff/internal.h" -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/ecoff.h" -#include "coff/mips.h" -#include "libcoff.h" -#include "libecoff.h" - -/* Prototypes for static functions. */ -static bfd_reloc_status_type -mips_generic_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type -mips_refhi_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type -mips_reflo_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type -mips_gprel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - - -/* ECOFF has COFF sections, but the debugging information is stored in - a completely different format. ECOFF targets use some of the - swapping routines from coffswap.h, and some of the generic COFF - routines in coffgen.c, but, unlike the real COFF targets, do not - use coffcode.h itself. - - Get the generic COFF swapping routines, except for the reloc, - symbol, and lineno ones. Give them ECOFF names. */ -#define MIPSECOFF -#define NO_COFF_RELOCS -#define NO_COFF_SYMBOLS -#define NO_COFF_LINENOS -#define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in -#define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out -#define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in -#define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out -#define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in -#define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out - -#include "coffswap.h" - -/* Get the ECOFF swapping routines. */ -#define ECOFF_32 -#include "ecoffswap.h" - -/* How to process the various relocs types. */ - -static reloc_howto_type mips_howto_table[] = -{ - /* Reloc type 0 is ignored. The reloc reading code ensures that - this is a reference to the .abs section, which will cause - bfd_perform_relocation to do nothing. */ - HOWTO (MIPS_R_IGNORE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "IGNORE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit reference to a symbol, normally from a data section. */ - HOWTO (MIPS_R_REFHALF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_generic_reloc, /* special_function */ - "REFHALF", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit reference to a symbol, normally from a data section. */ - HOWTO (MIPS_R_REFWORD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_generic_reloc, /* special_function */ - "REFWORD", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 26 bit absolute jump address. */ - HOWTO (MIPS_R_JMPADDR, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - mips_generic_reloc, /* special_function */ - "JMPADDR", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high 16 bits of a symbol value. Handled by the function - mips_refhi_reloc. */ - HOWTO (MIPS_R_REFHI, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_refhi_reloc, /* special_function */ - "REFHI", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The low 16 bits of a symbol value. */ - HOWTO (MIPS_R_REFLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips_reflo_reloc, /* special_function */ - "REFLO", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A reference to an offset from the gp register. Handled by the - function mips_gprel_reloc. */ - HOWTO (MIPS_R_GPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_gprel_reloc, /* special_function */ - "GPREL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A reference to a literal using an offset from the gp register. - Handled by the function mips_gprel_reloc. */ - HOWTO (MIPS_R_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_gprel_reloc, /* special_function */ - "LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (8), - EMPTY_HOWTO (9), - EMPTY_HOWTO (10), - EMPTY_HOWTO (11), - - /* FIXME: This relocation is used (internally only) to represent branches - when assembling. It should never appear in output files, and - be removed. (It used to be used for embedded-PIC support.) */ - HOWTO (MIPS_R_PCREL16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_generic_reloc, /* special_function */ - "PCREL16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -#define MIPS_HOWTO_COUNT \ - (sizeof mips_howto_table / sizeof mips_howto_table[0]) - -/* See whether the magic number matches. */ - -static bfd_boolean -mips_ecoff_bad_format_hook (bfd * abfd, void * filehdr) -{ - struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; - - switch (internal_f->f_magic) - { - case MIPS_MAGIC_1: - /* I don't know what endianness this implies. */ - return TRUE; - - case MIPS_MAGIC_BIG: - case MIPS_MAGIC_BIG2: - case MIPS_MAGIC_BIG3: - return bfd_big_endian (abfd); - - case MIPS_MAGIC_LITTLE: - case MIPS_MAGIC_LITTLE2: - case MIPS_MAGIC_LITTLE3: - return bfd_little_endian (abfd); - - default: - return FALSE; - } -} - -/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in - external form. They use a bit which indicates whether the symbol - is external. */ - -/* Swap a reloc in. */ - -static void -mips_ecoff_swap_reloc_in (bfd * abfd, - void * ext_ptr, - struct internal_reloc *intern) -{ - const RELOC *ext = (RELOC *) ext_ptr; - - intern->r_vaddr = H_GET_32 (abfd, ext->r_vaddr); - if (bfd_header_big_endian (abfd)) - { - intern->r_symndx = (((int) ext->r_bits[0] - << RELOC_BITS0_SYMNDX_SH_LEFT_BIG) - | ((int) ext->r_bits[1] - << RELOC_BITS1_SYMNDX_SH_LEFT_BIG) - | ((int) ext->r_bits[2] - << RELOC_BITS2_SYMNDX_SH_LEFT_BIG)); - intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG) - >> RELOC_BITS3_TYPE_SH_BIG); - intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0; - } - else - { - intern->r_symndx = (((int) ext->r_bits[0] - << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE) - | ((int) ext->r_bits[1] - << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE) - | ((int) ext->r_bits[2] - << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE)); - intern->r_type = (((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE) - >> RELOC_BITS3_TYPE_SH_LITTLE) - | ((ext->r_bits[3] & RELOC_BITS3_TYPEHI_LITTLE) - << RELOC_BITS3_TYPEHI_SH_LITTLE)); - intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0; - } -} - -/* Swap a reloc out. */ - -static void -mips_ecoff_swap_reloc_out (bfd * abfd, - const struct internal_reloc * intern, - void * dst) -{ - RELOC *ext = (RELOC *) dst; - long r_symndx; - - BFD_ASSERT (intern->r_extern - || (intern->r_symndx >= 0 && intern->r_symndx <= 12)); - - r_symndx = intern->r_symndx; - - H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr); - if (bfd_header_big_endian (abfd)) - { - ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG; - ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG; - ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG; - ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG) - & RELOC_BITS3_TYPE_BIG) - | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0)); - } - else - { - ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE; - ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE; - ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE; - ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE) - & RELOC_BITS3_TYPE_LITTLE) - | ((intern->r_type >> RELOC_BITS3_TYPEHI_SH_LITTLE - & RELOC_BITS3_TYPEHI_LITTLE)) - | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0)); - } -} - -/* Finish canonicalizing a reloc. Part of this is generic to all - ECOFF targets, and that part is in ecoff.c. The rest is done in - this backend routine. It must fill in the howto field. */ - -static void -mips_adjust_reloc_in (bfd *abfd, - const struct internal_reloc *intern, - arelent *rptr) -{ - if (intern->r_type > MIPS_R_PCREL16) - abort (); - - if (! intern->r_extern - && (intern->r_type == MIPS_R_GPREL - || intern->r_type == MIPS_R_LITERAL)) - rptr->addend += ecoff_data (abfd)->gp; - - /* If the type is MIPS_R_IGNORE, make sure this is a reference to - the absolute section so that the reloc is ignored. */ - if (intern->r_type == MIPS_R_IGNORE) - rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - rptr->howto = &mips_howto_table[intern->r_type]; -} - -/* Make any adjustments needed to a reloc before writing it out. None - are needed for MIPS. */ - -static void -mips_adjust_reloc_out (bfd *abfd ATTRIBUTE_UNUSED, - const arelent *rel ATTRIBUTE_UNUSED, - struct internal_reloc *intern ATTRIBUTE_UNUSED) -{ -} - -/* ECOFF relocs are either against external symbols, or against - sections. 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. */ - -static bfd_reloc_status_type -mips_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 != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - return bfd_reloc_continue; -} - -/* Do a REFHI relocation. This has to be done in combination with a - REFLO reloc, because there is a carry from the REFLO to the REFHI. - Here we just save the information we need; we do the actual - relocation when we see the REFLO. MIPS ECOFF requires that the - REFLO immediately follow the REFHI. As a GNU extension, we permit - an arbitrary number of HI relocs to be associated with a single LO - reloc. This extension permits gcc to output the HI and LO relocs - itself. */ - -struct mips_hi -{ - struct mips_hi *next; - bfd_byte *addr; - bfd_vma addend; -}; - -/* FIXME: This should not be a static variable. */ - -static struct mips_hi *mips_refhi_list; - -static bfd_reloc_status_type -mips_refhi_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - struct mips_hi *n; - - /* If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - ret = bfd_reloc_ok; - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - ret = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Save the information, and let REFLO do the actual relocation. */ - n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n); - if (n == NULL) - return bfd_reloc_outofrange; - n->addr = (bfd_byte *) data + reloc_entry->address; - n->addend = relocation; - n->next = mips_refhi_list; - mips_refhi_list = n; - - if (output_bfd != (bfd *) NULL) - reloc_entry->address += input_section->output_offset; - - return ret; -} - -/* Do a REFLO relocation. This is a straightforward 16 bit inplace - relocation; this function exists in order to do the REFHI - relocation described above. */ - -static bfd_reloc_status_type -mips_reflo_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (mips_refhi_list != NULL) - { - struct mips_hi *l; - - l = mips_refhi_list; - while (l != NULL) - { - unsigned long insn; - unsigned long val; - unsigned long vallo; - struct mips_hi *next; - - if (! bfd_reloc_offset_in_range (reloc_entry->howto, abfd, - input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - /* Do the REFHI relocation. Note that we actually don't - need to know anything about the REFLO itself, except - where to find the low 16 bits of the addend needed by the - REFHI. */ - insn = bfd_get_32 (abfd, l->addr); - vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) - & 0xffff); - val = ((insn & 0xffff) << 16) + vallo; - val += l->addend; - - /* The low order 16 bits are always treated as a signed - value. Therefore, a negative value in the low order bits - requires an adjustment in the high order bits. We need - to make this adjustment in two ways: once for the bits we - took from the data, and once for the bits we are putting - back in to the data. */ - if ((vallo & 0x8000) != 0) - val -= 0x10000; - if ((val & 0x8000) != 0) - val += 0x10000; - - insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff); - bfd_put_32 (abfd, (bfd_vma) insn, l->addr); - - next = l->next; - free (l); - l = next; - } - - mips_refhi_list = NULL; - } - - /* Now do the REFLO reloc in the usual way. */ - return mips_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - -/* Do a GPREL relocation. This is a 16 bit value which must become - the offset from the gp register. */ - -static bfd_reloc_status_type -mips_gprel_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_boolean relocatable; - bfd_vma gp; - bfd_vma relocation; - unsigned long val; - unsigned long insn; - - /* If we're relocating, and this is an external symbol with no - addend, we don't want to change anything. We will only have an - addend if this is a newly created reloc, not read from an ECOFF - file. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != (bfd *) NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - if (bfd_is_und_section (symbol->section) && ! relocatable) - return bfd_reloc_undefined; - - /* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ECOFF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - gp = _bfd_get_gp_value (output_bfd); - if (gp == 0 - && (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - gp = symbol->section->output_section->vma + 0x4000; - _bfd_set_gp_value (output_bfd, gp); - } - else - { - unsigned int count; - asymbol **sym; - unsigned int i; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - if (sym == (asymbol **) NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - register const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - gp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, gp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - gp = 4; - _bfd_set_gp_value (output_bfd, gp); - *error_message = - (char *) _("GP relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - } - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - - /* Set val to the offset into the section or symbol. */ - val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; - if (val & 0x8000) - val -= 0x10000; - - /* Adjust val for the final section location and GP value. If we - are producing relocatable output, we don't want to do this for - an external symbol. */ - if (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0) - val += relocation - gp; - - insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff); - bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address); - - if (relocatable) - reloc_entry->address += input_section->output_offset; - - /* Make sure it fit in 16 bits. */ - if ((long) val >= 0x8000 || (long) val < -0x8000) - return bfd_reloc_overflow; - - return bfd_reloc_ok; -} - -/* Get the howto structure for a generic reloc type. */ - -static reloc_howto_type * -mips_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - int mips_type; - - switch (code) - { - case BFD_RELOC_16: - mips_type = MIPS_R_REFHALF; - break; - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - mips_type = MIPS_R_REFWORD; - break; - case BFD_RELOC_MIPS_JMP: - mips_type = MIPS_R_JMPADDR; - break; - case BFD_RELOC_HI16_S: - mips_type = MIPS_R_REFHI; - break; - case BFD_RELOC_LO16: - mips_type = MIPS_R_REFLO; - break; - case BFD_RELOC_GPREL16: - mips_type = MIPS_R_GPREL; - break; - case BFD_RELOC_MIPS_LITERAL: - mips_type = MIPS_R_LITERAL; - break; - case BFD_RELOC_16_PCREL_S2: - mips_type = MIPS_R_PCREL16; - break; - default: - return (reloc_howto_type *) NULL; - } - - return &mips_howto_table[mips_type]; -} - -static reloc_howto_type * -mips_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (mips_howto_table) / sizeof (mips_howto_table[0]); - i++) - if (mips_howto_table[i].name != NULL - && strcasecmp (mips_howto_table[i].name, r_name) == 0) - return &mips_howto_table[i]; - - return NULL; -} - -/* A helper routine for mips_relocate_section which handles the REFHI - relocations. The REFHI relocation must be followed by a REFLO - relocation, and the addend used is formed from the addends of both - instructions. */ - -static void -mips_relocate_hi (struct internal_reloc *refhi, - struct internal_reloc *reflo, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - bfd_vma relocation) -{ - unsigned long insn; - unsigned long val; - unsigned long vallo; - - if (refhi == NULL) - return; - - insn = bfd_get_32 (input_bfd, - contents + refhi->r_vaddr - input_section->vma); - if (reflo == NULL) - vallo = 0; - else - vallo = (bfd_get_32 (input_bfd, - contents + reflo->r_vaddr - input_section->vma) - & 0xffff); - - val = ((insn & 0xffff) << 16) + vallo; - val += relocation; - - /* The low order 16 bits are always treated as a signed value. - Therefore, a negative value in the low order bits requires an - adjustment in the high order bits. We need to make this - adjustment in two ways: once for the bits we took from the data, - and once for the bits we are putting back in to the data. */ - if ((vallo & 0x8000) != 0) - val -= 0x10000; - - if ((val & 0x8000) != 0) - val += 0x10000; - - insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff); - bfd_put_32 (input_bfd, (bfd_vma) insn, - contents + refhi->r_vaddr - input_section->vma); -} - -/* Relocate a section while linking a MIPS ECOFF file. */ - -static bfd_boolean -mips_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - void * external_relocs) -{ - asection **symndx_to_section; - struct ecoff_link_hash_entry **sym_hashes; - bfd_vma gp; - bfd_boolean gp_undefined; - struct external_reloc *ext_rel; - struct external_reloc *ext_rel_end; - unsigned int i; - bfd_boolean got_lo; - struct internal_reloc lo_int_rel; - bfd_size_type amt; - - BFD_ASSERT (input_bfd->xvec->byteorder - == output_bfd->xvec->byteorder); - - /* We keep a table mapping the symndx found in an internal reloc to - the appropriate section. This is faster than looking up the - section by name each time. */ - symndx_to_section = ecoff_data (input_bfd)->symndx_to_section; - if (symndx_to_section == (asection **) NULL) - { - amt = NUM_RELOC_SECTIONS * sizeof (asection *); - symndx_to_section = (asection **) bfd_alloc (input_bfd, amt); - if (!symndx_to_section) - return FALSE; - - symndx_to_section[RELOC_SECTION_NONE] = NULL; - symndx_to_section[RELOC_SECTION_TEXT] = - bfd_get_section_by_name (input_bfd, ".text"); - symndx_to_section[RELOC_SECTION_RDATA] = - bfd_get_section_by_name (input_bfd, ".rdata"); - symndx_to_section[RELOC_SECTION_DATA] = - bfd_get_section_by_name (input_bfd, ".data"); - symndx_to_section[RELOC_SECTION_SDATA] = - bfd_get_section_by_name (input_bfd, ".sdata"); - symndx_to_section[RELOC_SECTION_SBSS] = - bfd_get_section_by_name (input_bfd, ".sbss"); - symndx_to_section[RELOC_SECTION_BSS] = - bfd_get_section_by_name (input_bfd, ".bss"); - symndx_to_section[RELOC_SECTION_INIT] = - bfd_get_section_by_name (input_bfd, ".init"); - symndx_to_section[RELOC_SECTION_LIT8] = - bfd_get_section_by_name (input_bfd, ".lit8"); - symndx_to_section[RELOC_SECTION_LIT4] = - bfd_get_section_by_name (input_bfd, ".lit4"); - symndx_to_section[RELOC_SECTION_XDATA] = NULL; - symndx_to_section[RELOC_SECTION_PDATA] = NULL; - symndx_to_section[RELOC_SECTION_FINI] = - bfd_get_section_by_name (input_bfd, ".fini"); - symndx_to_section[RELOC_SECTION_LITA] = NULL; - symndx_to_section[RELOC_SECTION_ABS] = NULL; - - ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; - } - - sym_hashes = ecoff_data (input_bfd)->sym_hashes; - - gp = _bfd_get_gp_value (output_bfd); - if (gp == 0) - gp_undefined = TRUE; - else - gp_undefined = FALSE; - - got_lo = FALSE; - - ext_rel = (struct external_reloc *) external_relocs; - ext_rel_end = ext_rel + input_section->reloc_count; - for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++) - { - struct internal_reloc int_rel; - bfd_boolean use_lo = FALSE; - bfd_vma addend; - reloc_howto_type *howto; - struct ecoff_link_hash_entry *h = NULL; - asection *s = NULL; - bfd_vma relocation; - bfd_reloc_status_type r; - - if (! got_lo) - mips_ecoff_swap_reloc_in (input_bfd, ext_rel, &int_rel); - else - { - int_rel = lo_int_rel; - got_lo = FALSE; - } - - BFD_ASSERT (int_rel.r_type - < sizeof mips_howto_table / sizeof mips_howto_table[0]); - - /* The REFHI reloc requires special handling. It must be followed - by a REFLO reloc, and the addend is formed from both relocs. */ - if (int_rel.r_type == MIPS_R_REFHI) - { - struct external_reloc *lo_ext_rel; - - /* As a GNU extension, permit an arbitrary number of REFHI - relocs before the REFLO reloc. This permits gcc to emit - the HI and LO relocs itself. */ - for (lo_ext_rel = ext_rel + 1; - lo_ext_rel < ext_rel_end; - lo_ext_rel++) - { - mips_ecoff_swap_reloc_in (input_bfd, lo_ext_rel, - &lo_int_rel); - if (lo_int_rel.r_type != int_rel.r_type) - break; - } - - if (lo_ext_rel < ext_rel_end - && lo_int_rel.r_type == MIPS_R_REFLO - && int_rel.r_extern == lo_int_rel.r_extern - && int_rel.r_symndx == lo_int_rel.r_symndx) - { - use_lo = TRUE; - if (lo_ext_rel == ext_rel + 1) - got_lo = TRUE; - } - } - - howto = &mips_howto_table[int_rel.r_type]; - - if (int_rel.r_extern) - { - h = sym_hashes[int_rel.r_symndx]; - /* If h is NULL, that means that there is a reloc against an - external symbol which we thought was just a debugging - symbol. This should not happen. */ - if (h == (struct ecoff_link_hash_entry *) NULL) - abort (); - } - else - { - if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS) - s = NULL; - else - s = symndx_to_section[int_rel.r_symndx]; - - if (s == (asection *) NULL) - abort (); - } - - /* The GPREL reloc uses an addend: the difference in the GP - values. */ - if (int_rel.r_type != MIPS_R_GPREL - && int_rel.r_type != MIPS_R_LITERAL) - addend = 0; - else - { - if (gp_undefined) - { - (*info->callbacks->reloc_dangerous) - (info, _("GP relative relocation used when GP not defined"), - input_bfd, input_section, - int_rel.r_vaddr - input_section->vma); - /* Only give the error once per link. */ - gp = 4; - _bfd_set_gp_value (output_bfd, gp); - gp_undefined = FALSE; - } - if (! int_rel.r_extern) - { - /* This is a relocation against a section. The current - addend in the instruction is the difference between - INPUT_SECTION->vma and the GP value of INPUT_BFD. We - must change this to be the difference between the - final definition (which will end up in RELOCATION) - and the GP value of OUTPUT_BFD (which is in GP). */ - addend = ecoff_data (input_bfd)->gp - gp; - } - else if (! bfd_link_relocatable (info) - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - /* This is a relocation against a defined symbol. The - current addend in the instruction is simply the - desired offset into the symbol (normally zero). We - are going to change this into a relocation against a - defined symbol, so we want the instruction to hold - the difference between the final definition of the - symbol (which will end up in RELOCATION) and the GP - value of OUTPUT_BFD (which is in GP). */ - addend = - gp; - } - else - { - /* This is a relocation against an undefined or common - symbol. The current addend in the instruction is - simply the desired offset into the symbol (normally - zero). We are generating relocatable output, and we - aren't going to define this symbol, so we just leave - the instruction alone. */ - addend = 0; - } - } - - if (bfd_link_relocatable (info)) - { - /* We are generating relocatable output, and must convert - the existing reloc. */ - if (int_rel.r_extern) - { - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && ! bfd_is_abs_section (h->root.u.def.section)) - { - const char *name; - - /* This symbol is defined in the output. Convert - the reloc from being against the symbol to being - against the section. */ - - /* Clear the r_extern bit. */ - int_rel.r_extern = 0; - - /* Compute a new r_symndx value. */ - s = h->root.u.def.section; - name = bfd_get_section_name (output_bfd, - s->output_section); - - int_rel.r_symndx = -1; - switch (name[1]) - { - case 'b': - if (strcmp (name, ".bss") == 0) - int_rel.r_symndx = RELOC_SECTION_BSS; - break; - case 'd': - if (strcmp (name, ".data") == 0) - int_rel.r_symndx = RELOC_SECTION_DATA; - break; - case 'f': - if (strcmp (name, ".fini") == 0) - int_rel.r_symndx = RELOC_SECTION_FINI; - break; - case 'i': - if (strcmp (name, ".init") == 0) - int_rel.r_symndx = RELOC_SECTION_INIT; - break; - case 'l': - if (strcmp (name, ".lit8") == 0) - int_rel.r_symndx = RELOC_SECTION_LIT8; - else if (strcmp (name, ".lit4") == 0) - int_rel.r_symndx = RELOC_SECTION_LIT4; - break; - case 'r': - if (strcmp (name, ".rdata") == 0) - int_rel.r_symndx = RELOC_SECTION_RDATA; - break; - case 's': - if (strcmp (name, ".sdata") == 0) - int_rel.r_symndx = RELOC_SECTION_SDATA; - else if (strcmp (name, ".sbss") == 0) - int_rel.r_symndx = RELOC_SECTION_SBSS; - break; - case 't': - if (strcmp (name, ".text") == 0) - int_rel.r_symndx = RELOC_SECTION_TEXT; - break; - } - - if (int_rel.r_symndx == -1) - abort (); - - /* Add the section VMA and the symbol value. */ - relocation = (h->root.u.def.value - + s->output_section->vma - + s->output_offset); - - /* For a PC relative relocation, the object file - currently holds just the addend. We must adjust - by the address to get the right value. */ - if (howto->pc_relative) - relocation -= int_rel.r_vaddr - input_section->vma; - - h = NULL; - } - else - { - /* Change the symndx value to the right one for the - output BFD. */ - int_rel.r_symndx = h->indx; - if (int_rel.r_symndx == -1) - { - /* This symbol is not being written out. */ - (*info->callbacks->unattached_reloc) - (info, h->root.root.string, input_bfd, input_section, - int_rel.r_vaddr - input_section->vma); - int_rel.r_symndx = 0; - } - relocation = 0; - } - } - else - { - /* This is a relocation against a section. Adjust the - value by the amount the section moved. */ - relocation = (s->output_section->vma - + s->output_offset - - s->vma); - } - - relocation += addend; - addend = 0; - - /* Adjust a PC relative relocation by removing the reference - to the original address in the section and including the - reference to the new address. */ - if (howto->pc_relative) - relocation -= (input_section->output_section->vma - + input_section->output_offset - - input_section->vma); - - /* Adjust the contents. */ - if (relocation == 0) - r = bfd_reloc_ok; - else - { - if (int_rel.r_type != MIPS_R_REFHI) - r = _bfd_relocate_contents (howto, input_bfd, relocation, - (contents - + int_rel.r_vaddr - - input_section->vma)); - else - { - mips_relocate_hi (&int_rel, - use_lo ? &lo_int_rel : NULL, - input_bfd, input_section, contents, - relocation); - r = bfd_reloc_ok; - } - } - - /* Adjust the reloc address. */ - int_rel.r_vaddr += (input_section->output_section->vma - + input_section->output_offset - - input_section->vma); - - /* Save the changed reloc information. */ - mips_ecoff_swap_reloc_out (input_bfd, &int_rel, ext_rel); - } - else - { - /* We are producing a final executable. */ - if (int_rel.r_extern) - { - /* This is a reloc against a symbol. */ - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *hsec; - - hsec = h->root.u.def.section; - relocation = (h->root.u.def.value - + hsec->output_section->vma - + hsec->output_offset); - } - else - { - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - int_rel.r_vaddr - input_section->vma, TRUE); - relocation = 0; - } - } - else - { - /* This is a reloc against a section. */ - relocation = (s->output_section->vma - + s->output_offset - - s->vma); - - /* A PC relative reloc is already correct in the object - file. Make it look like a pcrel_offset relocation by - adding in the start address. */ - if (howto->pc_relative) - relocation += int_rel.r_vaddr; - } - - if (int_rel.r_type != MIPS_R_REFHI) - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - (int_rel.r_vaddr - - input_section->vma), - relocation, - addend); - else - { - mips_relocate_hi (&int_rel, - use_lo ? &lo_int_rel : NULL, - input_bfd, input_section, contents, - relocation); - r = bfd_reloc_ok; - } - } - - /* MIPS_R_JMPADDR requires peculiar overflow detection. The - instruction provides a 28 bit address (the two lower bits are - implicit zeroes) which is combined with the upper four bits - of the instruction address. */ - if (r == bfd_reloc_ok - && int_rel.r_type == MIPS_R_JMPADDR - && (((relocation - + addend - + (int_rel.r_extern ? 0 : s->vma)) - & 0xf0000000) - != ((input_section->output_section->vma - + input_section->output_offset - + (int_rel.r_vaddr - input_section->vma)) - & 0xf0000000))) - r = bfd_reloc_overflow; - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - { - const char *name; - - if (int_rel.r_extern) - name = NULL; - else - name = bfd_section_name (input_bfd, s); - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - int_rel.r_vaddr - input_section->vma); - } - break; - } - } - } - - return TRUE; -} - -/* This is the ECOFF backend structure. The backend field of the - target vector points to this. */ - -static const struct ecoff_backend_data mips_ecoff_backend_data = -{ - /* COFF backend structure. */ - { - (void (*) (bfd *,void *,int,int,int,int,void *)) bfd_void, /* aux_in */ - (void (*) (bfd *,void *,void *)) bfd_void, /* sym_in */ - (void (*) (bfd *,void *,void *)) bfd_void, /* lineno_in */ - (unsigned (*) (bfd *,void *,int,int,int,int,void *)) bfd_void,/*aux_out*/ - (unsigned (*) (bfd *,void *,void *)) bfd_void, /* sym_out */ - (unsigned (*) (bfd *,void *,void *)) bfd_void, /* lineno_out */ - (unsigned (*) (bfd *,void *,void *)) bfd_void, /* reloc_out */ - mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out, - mips_ecoff_swap_scnhdr_out, - FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE, - ECOFF_NO_LONG_SECTION_NAMES, 4, FALSE, 2, 32768, - mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in, - mips_ecoff_swap_scnhdr_in, NULL, - mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, - _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, - _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL - }, - /* Supported architecture. */ - bfd_arch_mips, - /* Initial portion of armap string. */ - "__________", - /* The page boundary used to align sections in a demand-paged - executable file. E.g., 0x1000. */ - 0x1000, - /* 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. */ - FALSE, - /* Bitsize of constructor entries. */ - 32, - /* Reloc to use for constructor entries. */ - &mips_howto_table[MIPS_R_REFWORD], - { - /* Symbol table magic number. */ - magicSym, - /* Alignment of debugging information. E.g., 4. */ - 4, - /* Sizes of external symbolic information. */ - sizeof (struct hdr_ext), - sizeof (struct dnr_ext), - sizeof (struct pdr_ext), - sizeof (struct sym_ext), - sizeof (struct opt_ext), - sizeof (struct fdr_ext), - sizeof (struct rfd_ext), - sizeof (struct ext_ext), - /* Functions to swap in external symbolic data. */ - ecoff_swap_hdr_in, - ecoff_swap_dnr_in, - ecoff_swap_pdr_in, - ecoff_swap_sym_in, - ecoff_swap_opt_in, - ecoff_swap_fdr_in, - ecoff_swap_rfd_in, - ecoff_swap_ext_in, - _bfd_ecoff_swap_tir_in, - _bfd_ecoff_swap_rndx_in, - /* Functions to swap out external symbolic data. */ - ecoff_swap_hdr_out, - ecoff_swap_dnr_out, - ecoff_swap_pdr_out, - ecoff_swap_sym_out, - ecoff_swap_opt_out, - ecoff_swap_fdr_out, - ecoff_swap_rfd_out, - ecoff_swap_ext_out, - _bfd_ecoff_swap_tir_out, - _bfd_ecoff_swap_rndx_out, - /* Function to read in symbolic data. */ - _bfd_ecoff_slurp_symbolic_info - }, - /* External reloc size. */ - RELSZ, - /* Reloc swapping functions. */ - mips_ecoff_swap_reloc_in, - mips_ecoff_swap_reloc_out, - /* Backend reloc tweaking. */ - mips_adjust_reloc_in, - mips_adjust_reloc_out, - /* Relocate section contents while linking. */ - mips_relocate_section, - /* Do final adjustments to filehdr and aouthdr. */ - NULL, - /* Read an element from an archive at a given file position. */ - _bfd_get_elt_at_filepos -}; - -/* Looking up a reloc type is MIPS specific. */ -#define _bfd_ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup -#define _bfd_ecoff_bfd_reloc_name_lookup mips_bfd_reloc_name_lookup - -/* Getting relocated section contents is generic. */ -#define _bfd_ecoff_bfd_get_relocated_section_contents \ - bfd_generic_get_relocated_section_contents - -/* Handling file windows is generic. */ -#define _bfd_ecoff_get_section_contents_in_window \ - _bfd_generic_get_section_contents_in_window - -/* Relaxing sections is MIPS specific. */ -#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section - -/* GC of sections is not done. */ -#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections - -/* Input section flags is not implemented. */ -#define _bfd_ecoff_bfd_lookup_section_flags bfd_generic_lookup_section_flags - -/* Merging of sections is not done. */ -#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections - -#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section -#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group -#define _bfd_ecoff_section_already_linked \ - _bfd_coff_section_already_linked -#define _bfd_ecoff_bfd_define_common_symbol bfd_generic_define_common_symbol -#define _bfd_ecoff_bfd_define_start_stop bfd_generic_define_start_stop -#define _bfd_ecoff_set_reloc _bfd_generic_set_reloc - -extern const bfd_target mips_ecoff_be_vec; - -const bfd_target mips_ecoff_le_vec = -{ - "ecoff-littlemips", /* name */ - bfd_target_ecoff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - 0, /* leading underscore */ - ' ', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), - BFD_JUMP_TABLE_COPY (_bfd_ecoff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), - BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), - BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), - BFD_JUMP_TABLE_WRITE (_bfd_ecoff), - BFD_JUMP_TABLE_LINK (_bfd_ecoff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & mips_ecoff_be_vec, - - & mips_ecoff_backend_data -}; - -const bfd_target mips_ecoff_be_vec = -{ - "ecoff-bigmips", /* name */ - bfd_target_ecoff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - 0, /* leading underscore */ - ' ', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - 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_getb64, bfd_getb_signed_64, bfd_putb64, - bfd_getb32, bfd_getb_signed_32, bfd_putb32, - bfd_getb16, bfd_getb_signed_16, bfd_putb16, - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), - BFD_JUMP_TABLE_COPY (_bfd_ecoff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), - BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), - BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), - BFD_JUMP_TABLE_WRITE (_bfd_ecoff), - BFD_JUMP_TABLE_LINK (_bfd_ecoff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & mips_ecoff_le_vec, - - & mips_ecoff_backend_data -}; - -const bfd_target mips_ecoff_bele_vec = -{ - "ecoff-biglittlemips", /* name */ - bfd_target_ecoff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), - 0, /* leading underscore */ - ' ', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* 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, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ - _bfd_generic_mkarchive, bfd_false}, - {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), - BFD_JUMP_TABLE_COPY (_bfd_ecoff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), - BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), - BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), - BFD_JUMP_TABLE_WRITE (_bfd_ecoff), - BFD_JUMP_TABLE_LINK (_bfd_ecoff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - & mips_ecoff_backend_data -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-ppc.c b/sdcc/support/sdbinutils/bfd/coff-ppc.c deleted file mode 100644 index 74f93d584..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-ppc.c +++ /dev/null @@ -1,2596 +0,0 @@ -/* BFD back-end for PowerPC Microsoft Portable Executable files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - - Original version pieced together by Kim Knuttila (krk@cygnus.com) - - There is nothing new under the sun. This file draws a lot on other - coff files, in particular, those for the rs/6000, alpha, mips, and - intel backends, and the PE work for the arm. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* Current State: - - objdump works - - relocs generated by gas - - ld will link files, but they do not run. - - dlltool will not produce correct output in some .reloc cases, and will - not produce the right glue code for dll function calls. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#include "coff/powerpc.h" -#include "coff/internal.h" - -#include "coff/pe.h" - -#ifdef BADMAG -#undef BADMAG -#endif - -#define BADMAG(x) PPCBADMAG(x) - -#include "libcoff.h" - -/* This file is compiled more than once, but we only compile the - final_link routine once. */ -extern bfd_boolean ppc_bfd_coff_final_link (bfd *, struct bfd_link_info *); -extern void dump_toc (void *); - -/* The toc is a set of bfd_vma fields. We use the fact that valid - addresses are even (i.e. the bit representing "1" is off) to allow - us to encode a little extra information in the field - - Unallocated addresses are initialized to 1. - - Allocated addresses are even numbers. - The first time we actually write a reference to the toc in the bfd, - we want to record that fact in a fixup file (if it is asked for), so - we keep track of whether or not an address has been written by marking - the low order bit with a "1" upon writing. */ - -#define SET_UNALLOCATED(x) ((x) = 1) -#define IS_UNALLOCATED(x) ((x) == 1) - -#define IS_WRITTEN(x) ((x) & 1) -#define MARK_AS_WRITTEN(x) ((x) |= 1) -#define MAKE_ADDR_AGAIN(x) ((x) &= ~1) - -/* Turn on this check if you suspect something amiss in the hash tables. */ -#ifdef DEBUG_HASH - -/* Need a 7 char string for an eye catcher. */ -#define EYE "krkjunk" - -#define HASH_CHECK_DCL char eye_catcher[8]; -#define HASH_CHECK_INIT(ret) strcpy(ret->eye_catcher, EYE) -#define HASH_CHECK(addr) \ - if (strcmp (addr->eye_catcher, EYE) != 0) \ - { \ - fprintf (stderr,\ - /* xgettext: c-format */ \ - _("File %s, line %d, Hash check failure, bad eye %8s\n"), \ - __FILE__, __LINE__, addr->eye_catcher); \ - abort (); \ - } - -#else - -#define HASH_CHECK_DCL -#define HASH_CHECK_INIT(ret) -#define HASH_CHECK(addr) - -#endif - -/* In order not to add an int to every hash table item for every coff - linker, we define our own hash table, derived from the coff one. */ - -/* PE linker hash table entries. */ - -struct ppc_coff_link_hash_entry -{ - struct coff_link_hash_entry root; /* First entry, as required. */ - - /* As we wonder around the relocs, we'll keep the assigned toc_offset - here. */ - bfd_vma toc_offset; /* Our addition, as required. */ - int symbol_is_glue; - unsigned long int glue_insn; - - HASH_CHECK_DCL -}; - -/* PE linker hash table. */ - -struct ppc_coff_link_hash_table -{ - struct coff_link_hash_table root; /* First entry, as required. */ -}; - -/* Routine to create an entry in the link hash table. */ - -static struct bfd_hash_entry * -ppc_coff_link_hash_newfunc (struct bfd_hash_entry * entry, - struct bfd_hash_table * table, - const char * string) -{ - struct ppc_coff_link_hash_entry *ret = - (struct ppc_coff_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct ppc_coff_link_hash_entry *) NULL) - ret = (struct ppc_coff_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct ppc_coff_link_hash_entry)); - - if (ret == (struct ppc_coff_link_hash_entry *) NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct ppc_coff_link_hash_entry *) - _bfd_coff_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - - if (ret) - { - /* Initialize the local fields. */ - SET_UNALLOCATED (ret->toc_offset); - ret->symbol_is_glue = 0; - ret->glue_insn = 0; - - HASH_CHECK_INIT (ret); - } - - return (struct bfd_hash_entry *) ret; -} - -/* Initialize a PE linker hash table. */ - -static bfd_boolean -ppc_coff_link_hash_table_init (struct ppc_coff_link_hash_table *table, - bfd *abfd, - struct bfd_hash_entry *(*newfunc) - (struct bfd_hash_entry *, - struct bfd_hash_table *, - const char *), - unsigned int entsize) -{ - return _bfd_coff_link_hash_table_init (&table->root, abfd, newfunc, entsize); -} - -/* Create a PE linker hash table. */ - -static struct bfd_link_hash_table * -ppc_coff_link_hash_table_create (bfd *abfd) -{ - struct ppc_coff_link_hash_table *ret; - bfd_size_type amt = sizeof (struct ppc_coff_link_hash_table); - - ret = (struct ppc_coff_link_hash_table *) bfd_malloc (amt); - if (ret == NULL) - return NULL; - if (!ppc_coff_link_hash_table_init (ret, abfd, - ppc_coff_link_hash_newfunc, - sizeof (struct ppc_coff_link_hash_entry))) - { - free (ret); - return (struct bfd_link_hash_table *) NULL; - } - return &ret->root.root; -} - -/* Now, tailor coffcode.h to use our hash stuff. */ - -#define coff_bfd_link_hash_table_create ppc_coff_link_hash_table_create - -/* The nt loader points the toc register to &toc + 32768, in order to - use the complete range of a 16-bit displacement. We have to adjust - for this when we fix up loads displaced off the toc reg. */ -#define TOC_LOAD_ADJUSTMENT (-32768) -#define TOC_SECTION_NAME ".private.toc" - -/* The main body of code is in coffcode.h. */ - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -/* These should definitely go in a header file somewhere... */ - -/* NOP */ -#define IMAGE_REL_PPC_ABSOLUTE 0x0000 - -/* 64-bit address */ -#define IMAGE_REL_PPC_ADDR64 0x0001 - -/* 32-bit address */ -#define IMAGE_REL_PPC_ADDR32 0x0002 - -/* 26-bit address, shifted left 2 (branch absolute) */ -#define IMAGE_REL_PPC_ADDR24 0x0003 - -/* 16-bit address */ -#define IMAGE_REL_PPC_ADDR16 0x0004 - -/* 16-bit address, shifted left 2 (load doubleword) */ -#define IMAGE_REL_PPC_ADDR14 0x0005 - -/* 26-bit PC-relative offset, shifted left 2 (branch relative) */ -#define IMAGE_REL_PPC_REL24 0x0006 - -/* 16-bit PC-relative offset, shifted left 2 (br cond relative) */ -#define IMAGE_REL_PPC_REL14 0x0007 - -/* 16-bit offset from TOC base */ -#define IMAGE_REL_PPC_TOCREL16 0x0008 - -/* 16-bit offset from TOC base, shifted left 2 (load doubleword) */ -#define IMAGE_REL_PPC_TOCREL14 0x0009 - -/* 32-bit addr w/o image base */ -#define IMAGE_REL_PPC_ADDR32NB 0x000A - -/* va of containing section (as in an image sectionhdr) */ -#define IMAGE_REL_PPC_SECREL 0x000B - -/* sectionheader number */ -#define IMAGE_REL_PPC_SECTION 0x000C - -/* substitute TOC restore instruction iff symbol is glue code */ -#define IMAGE_REL_PPC_IFGLUE 0x000D - -/* symbol is glue code; virtual address is TOC restore instruction */ -#define IMAGE_REL_PPC_IMGLUE 0x000E - -/* va of containing section (limited to 16 bits) */ -#define IMAGE_REL_PPC_SECREL16 0x000F - -/* Stuff to handle immediate data when the number of bits in the - data is greater than the number of bits in the immediate field - We need to do (usually) 32 bit arithmetic on 16 bit chunks. */ -#define IMAGE_REL_PPC_REFHI 0x0010 -#define IMAGE_REL_PPC_REFLO 0x0011 -#define IMAGE_REL_PPC_PAIR 0x0012 - -/* This is essentially the same as tocrel16, with TOCDEFN assumed. */ -#define IMAGE_REL_PPC_TOCREL16_DEFN 0x0013 - -/* Flag bits in IMAGE_RELOCATION.TYPE. */ - -/* Subtract reloc value rather than adding it. */ -#define IMAGE_REL_PPC_NEG 0x0100 - -/* Fix branch prediction bit to predict branch taken. */ -#define IMAGE_REL_PPC_BRTAKEN 0x0200 - -/* Fix branch prediction bit to predict branch not taken. */ -#define IMAGE_REL_PPC_BRNTAKEN 0x0400 - -/* TOC slot defined in file (or, data in toc). */ -#define IMAGE_REL_PPC_TOCDEFN 0x0800 - -/* Masks to isolate above values in IMAGE_RELOCATION.Type. */ -#define IMAGE_REL_PPC_TYPEMASK 0x00FF -#define IMAGE_REL_PPC_FLAGMASK 0x0F00 - -#define EXTRACT_TYPE(x) ((x) & IMAGE_REL_PPC_TYPEMASK) -#define EXTRACT_FLAGS(x) ((x) & IMAGE_REL_PPC_FLAGMASK) -#define EXTRACT_JUNK(x) \ - ((x) & ~(IMAGE_REL_PPC_TYPEMASK | IMAGE_REL_PPC_FLAGMASK)) - -/* Static helper functions to make relocation work. */ -/* (Work In Progress) */ - -static bfd_reloc_status_type ppc_refhi_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc_pair_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc_toc16_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc_section_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc_secrel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc_imglue_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -/* FIXME: It'll take a while to get through all of these. I only need a few to - get us started, so those I'll make sure work. Those marked FIXME are either - completely unverified or have a specific unknown marked in the comment. */ - -/* Relocation entries for Windows/NT on PowerPC. - - From the document "" we find the following listed as used relocs: - - ABSOLUTE : The noop - ADDR[64|32|16] : fields that hold addresses in data fields or the - 16 bit displacement field on a load/store. - ADDR[24|14] : fields that hold addresses in branch and cond - branches. These represent [26|16] bit addresses. - The low order 2 bits are preserved. - REL[24|14] : branches relative to the Instruction Address - register. These represent [26|16] bit addresses, - as before. The instruction field will be zero, and - the address of the SYM will be inserted at link time. - TOCREL16 : 16 bit displacement field referring to a slot in - toc. - TOCREL14 : 16 bit displacement field, similar to REL14 or ADDR14. - ADDR32NB : 32 bit address relative to the virtual origin. - (On the alpha, this is always a linker generated thunk) - (i.e. 32bit addr relative to the image base) - SECREL : The value is relative to the start of the section - containing the symbol. - SECTION : access to the header containing the item. Supports the - codeview debugger. - - In particular, note that the document does not indicate that the - relocations listed in the header file are used. */ - - -static reloc_howto_type ppc_coff_howto_table[] = -{ - /* IMAGE_REL_PPC_ABSOLUTE 0x0000 NOP */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_ABSOLUTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* dont complain_on_overflow */ - 0, /* special_function */ - "ABSOLUTE", /* name */ - FALSE, /* partial_inplace */ - 0x00, /* src_mask */ - 0x00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_ADDR64 0x0001 64-bit address */ - /* Unused: */ - HOWTO(IMAGE_REL_PPC_ADDR64, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_ADDR32 0x0002 32-bit address */ - /* Used: */ - HOWTO (IMAGE_REL_PPC_ADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_ADDR24 0x0003 26-bit address, shifted left 2 (branch absolute) */ - /* the LI field is in bit 6 through bit 29 is 24 bits, + 2 for the shift */ - /* Of course, That's the IBM approved bit numbering, which is not what */ - /* anyone else uses.... The li field is in bit 2 thru 25 */ - /* Used: */ - HOWTO (IMAGE_REL_PPC_ADDR24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR24", /* name */ - TRUE, /* partial_inplace */ - 0x07fffffc, /* src_mask */ - 0x07fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_ADDR16 0x0004 16-bit address */ - /* Used: */ - HOWTO (IMAGE_REL_PPC_ADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_ADDR14 0x0005 */ - /* 16-bit address, shifted left 2 (load doubleword) */ - /* FIXME: the mask is likely wrong, and the bit position may be as well */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_ADDR14, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_REL24 0x0006 */ - /* 26-bit PC-relative offset, shifted left 2 (branch relative) */ - /* Used: */ - HOWTO (IMAGE_REL_PPC_REL24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "REL24", /* name */ - TRUE, /* partial_inplace */ - 0x3fffffc, /* src_mask */ - 0x3fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_REL14 0x0007 */ - /* 16-bit PC-relative offset, shifted left 2 (br cond relative) */ - /* FIXME: the mask is likely wrong, and the bit position may be as well */ - /* FIXME: how does it know how far to shift? */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_ADDR14, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_TOCREL16 0x0008 */ - /* 16-bit offset from TOC base */ - /* Used: */ - HOWTO (IMAGE_REL_PPC_TOCREL16,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_toc16_reloc, /* special_function */ - "TOCREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_TOCREL14 0x0009 */ - /* 16-bit offset from TOC base, shifted left 2 (load doubleword) */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_TOCREL14,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "TOCREL14", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_ADDR32NB 0x000A */ - /* 32-bit addr w/ image base */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_ADDR32NB,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "ADDR32NB", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_SECREL 0x000B */ - /* va of containing section (as in an image sectionhdr) */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_SECREL,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_secrel_reloc, /* special_function */ - "SECREL", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_SECTION 0x000C */ - /* sectionheader number */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_SECTION,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_section_reloc, /* special_function */ - "SECTION", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_IFGLUE 0x000D */ - /* substitute TOC restore instruction iff symbol is glue code */ - /* Used: */ - HOWTO (IMAGE_REL_PPC_IFGLUE,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "IFGLUE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_IMGLUE 0x000E */ - /* symbol is glue code; virtual address is TOC restore instruction */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_IMGLUE,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_imglue_reloc, /* special_function */ - "IMGLUE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_SECREL16 0x000F */ - /* va of containing section (limited to 16 bits) */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_SECREL16,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "SECREL16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_REFHI 0x0010 */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_REFHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_refhi_reloc, /* special_function */ - "REFHI", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_REFLO 0x0011 */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_REFLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_refhi_reloc, /* special_function */ - "REFLO", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_PAIR 0x0012 */ - /* Unused: */ - HOWTO (IMAGE_REL_PPC_PAIR, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_pair_reloc, /* special_function */ - "PAIR", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* IMAGE_REL_PPC_TOCREL16_DEFN 0x0013 */ - /* 16-bit offset from TOC base, without causing a definition */ - /* Used: */ - HOWTO ( (IMAGE_REL_PPC_TOCREL16 | IMAGE_REL_PPC_TOCDEFN), /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "TOCREL16, TOCDEFN", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Some really cheezy macros that can be turned on to test stderr :-) */ - -#ifdef DEBUG_RELOC -#define UN_IMPL(x) \ -{ \ - static int i; \ - if (i == 0) \ - { \ - i = 1; \ - fprintf (stderr,_("Unimplemented Relocation -- %s\n"),x); \ - } \ -} - -#define DUMP_RELOC(n,r) \ -{ \ - fprintf (stderr,"%s sym %d, addr %d, addend %d\n", \ - n, (*(r->sym_ptr_ptr))->name, \ - r->address, r->addend); \ -} - -/* Given a reloc name, n, and a pointer to an internal_reloc, - dump out interesting information on the contents - -#define n_name _n._n_name -#define n_zeroes _n._n_n._n_zeroes -#define n_offset _n._n_n._n_offset */ - -#define DUMP_RELOC2(n,r) \ -{ \ - fprintf (stderr,"%s sym %d, r_vaddr %d %s\n", \ - n, r->r_symndx, r->r_vaddr, \ - (((r->r_type) & IMAGE_REL_PPC_TOCDEFN) == 0) \ - ?" ":" TOCDEFN" ); \ -} - -#else -#define UN_IMPL(x) -#define DUMP_RELOC(n,r) -#define DUMP_RELOC2(n,r) -#endif - -/* TOC construction and management routines. */ - -/* This file is compiled twice, and these variables are defined in one - of the compilations. FIXME: This is confusing and weird. Also, - BFD should not use global variables. */ -extern bfd * bfd_of_toc_owner; -extern long int global_toc_size; -extern long int import_table_size; -extern long int first_thunk_address; -extern long int thunk_size; - -enum toc_type -{ - default_toc, - toc_32, - toc_64 -}; - -enum ref_category -{ - priv, - pub, - tocdata -}; - -struct list_ele -{ - struct list_ele *next; - bfd_vma addr; - enum ref_category cat; - int offset; - const char *name; -}; - -extern struct list_ele *head; -extern struct list_ele *tail; - -static void -record_toc (asection *toc_section, - bfd_signed_vma our_toc_offset, - enum ref_category cat, - const char *name) -{ - /* Add this entry to our toc addr-offset-name list. */ - bfd_size_type amt = sizeof (struct list_ele); - struct list_ele *t = (struct list_ele *) bfd_malloc (amt); - - if (t == NULL) - abort (); - t->next = 0; - t->offset = our_toc_offset; - t->name = name; - t->cat = cat; - t->addr = toc_section->output_offset + our_toc_offset; - - if (head == 0) - { - head = t; - tail = t; - } - else - { - tail->next = t; - tail = t; - } -} - -#ifdef COFF_IMAGE_WITH_PE - -/* Record a toc offset against a symbol. */ -static bfd_boolean -ppc_record_toc_entry (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - int sym, - enum toc_type toc_kind ATTRIBUTE_UNUSED) -{ - struct ppc_coff_link_hash_entry *h; - int *local_syms; - - h = 0; - - h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); - if (h != 0) - { - HASH_CHECK(h); - } - - if (h == 0) - { - local_syms = obj_coff_local_toc_table(abfd); - - if (local_syms == 0) - { - unsigned int i; - bfd_size_type amt; - - /* allocate a table */ - amt = (bfd_size_type) obj_raw_syment_count (abfd) * sizeof (int); - local_syms = (int *) bfd_zalloc (abfd, amt); - if (local_syms == 0) - return FALSE; - obj_coff_local_toc_table (abfd) = local_syms; - - for (i = 0; i < obj_raw_syment_count (abfd); ++i) - { - SET_UNALLOCATED (local_syms[i]); - } - } - - if (IS_UNALLOCATED(local_syms[sym])) - { - local_syms[sym] = global_toc_size; - global_toc_size += 4; - - /* The size must fit in a 16-bit displacement. */ - if (global_toc_size > 65535) - { - _bfd_error_handler (_("TOC overflow")); - bfd_set_error (bfd_error_file_too_big); - return FALSE; - } - } - } - else - { - /* Check to see if there's a toc slot allocated. If not, do it - here. It will be used in relocate_section. */ - if (IS_UNALLOCATED(h->toc_offset)) - { - h->toc_offset = global_toc_size; - global_toc_size += 4; - - /* The size must fit in a 16-bit displacement. */ - if (global_toc_size >= 65535) - { - _bfd_error_handler (_("TOC overflow")); - bfd_set_error (bfd_error_file_too_big); - return FALSE; - } - } - } - - return TRUE; -} - -/* Record a toc offset against a symbol. */ -static void -ppc_mark_symbol_as_glue (bfd *abfd, - int sym, - struct internal_reloc *rel) -{ - struct ppc_coff_link_hash_entry *h; - - h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); - - HASH_CHECK(h); - - h->symbol_is_glue = 1; - h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr); - - return; -} - -#endif /* COFF_IMAGE_WITH_PE */ - -/* Return TRUE if this relocation should - appear in the output .reloc section. */ - -static bfd_boolean -in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, - reloc_howto_type *howto) -{ - return - (! howto->pc_relative) - && (howto->type != IMAGE_REL_PPC_ADDR32NB) - && (howto->type != IMAGE_REL_PPC_TOCREL16) - && (howto->type != IMAGE_REL_PPC_IMGLUE) - && (howto->type != IMAGE_REL_PPC_IFGLUE) - && (howto->type != IMAGE_REL_PPC_SECREL) - && (howto->type != IMAGE_REL_PPC_SECTION) - && (howto->type != IMAGE_REL_PPC_SECREL16) - && (howto->type != IMAGE_REL_PPC_REFHI) - && (howto->type != IMAGE_REL_PPC_REFLO) - && (howto->type != IMAGE_REL_PPC_PAIR) - && (howto->type != IMAGE_REL_PPC_TOCREL16_DEFN) ; -} - -static bfd_boolean -write_base_file_entry (bfd *obfd, struct bfd_link_info *info, bfd_vma addr) -{ - if (coff_data (obfd)->pe) - addr -= pe_data (obfd)->pe_opthdr.ImageBase; - if (fwrite (&addr, sizeof (addr), 1, (FILE *) info->base_file) == 1) - return TRUE; - - bfd_set_error (bfd_error_system_call); - return FALSE; -} - -/* The reloc processing routine for the optimized COFF linker. */ - -static bfd_boolean -coff_ppc_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - asection *toc_section = 0; - bfd_vma relocation; - reloc_howto_type *howto = 0; - - /* If we are performing a relocatable link, we don't need to do a - thing. The caller will take care of adjusting the reloc - addresses and symbol indices. */ - if (bfd_link_relocatable (info)) - return TRUE; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct ppc_coff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma val; - - asection *sec; - bfd_reloc_status_type rstat; - bfd_byte *loc; - - unsigned short r_type = EXTRACT_TYPE (rel->r_type); - unsigned short r_flags = EXTRACT_FLAGS(rel->r_type); - - symndx = rel->r_symndx; - loc = contents + rel->r_vaddr - input_section->vma; - - /* FIXME: check bounds on r_type */ - howto = ppc_coff_howto_table + r_type; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else - { - h = (struct ppc_coff_link_hash_entry *) - (obj_coff_sym_hashes (input_bfd)[symndx]); - if (h != 0) - { - HASH_CHECK(h); - } - - sym = syms + symndx; - } - - if (r_type == IMAGE_REL_PPC_IMGLUE && h == 0) - { - /* An IMGLUE reloc must have a name. Something is very wrong. */ - abort (); - } - - sec = NULL; - val = 0; - - /* FIXME: PAIR unsupported in the following code. */ - if (h == NULL) - { - if (symndx == -1) - sec = bfd_abs_section_ptr; - else - { - sec = sections[symndx]; - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value); - if (! obj_pe (output_bfd)) - val -= sec->vma; - } - } - else - { - HASH_CHECK(h); - - if (h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - { - sec = h->root.root.u.def.section; - val = (h->root.root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else - (*info->callbacks->undefined_symbol) - (info, h->root.root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - } - - rstat = bfd_reloc_ok; - - /* Each case must do its own relocation, setting rstat appropriately. */ - switch (r_type) - { - default: - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: unsupported relocation type 0x%02x"), input_bfd, r_type); - bfd_set_error (bfd_error_bad_value); - return FALSE; - case IMAGE_REL_PPC_TOCREL16: - { - bfd_signed_vma our_toc_offset; - int fixit; - - DUMP_RELOC2(howto->name, rel); - - if (toc_section == 0) - { - toc_section = bfd_get_section_by_name (bfd_of_toc_owner, - TOC_SECTION_NAME); - - if ( toc_section == NULL ) - { - /* There is no toc section. Something is very wrong. */ - abort (); - } - } - - /* Amazing bit tricks present. As we may have seen earlier, we - use the 1 bit to tell us whether or not a toc offset has been - allocated. Now that they've all been allocated, we will use - the 1 bit to tell us if we've written this particular toc - entry out. */ - fixit = FALSE; - if (h == 0) - { - /* It is a file local symbol. */ - int *local_toc_table; - char name[SYMNMLEN + 1]; - - sym = syms + symndx; - strncpy (name, sym->_n._n_name, SYMNMLEN); - name[SYMNMLEN] = '\0'; - - local_toc_table = obj_coff_local_toc_table(input_bfd); - our_toc_offset = local_toc_table[symndx]; - - if (IS_WRITTEN(our_toc_offset)) - { - /* If it has been written out, it is marked with the - 1 bit. Fix up our offset, but do not write it out - again. */ - MAKE_ADDR_AGAIN(our_toc_offset); - } - else - { - /* Write out the toc entry. */ - record_toc (toc_section, our_toc_offset, priv, - strdup (name)); - - bfd_put_32 (output_bfd, val, - toc_section->contents + our_toc_offset); - - MARK_AS_WRITTEN(local_toc_table[symndx]); - fixit = TRUE; - } - } - else - { - const char *name = h->root.root.root.string; - our_toc_offset = h->toc_offset; - - if ((r_flags & IMAGE_REL_PPC_TOCDEFN) - == IMAGE_REL_PPC_TOCDEFN ) - { - /* This is unbelievable cheese. Some knowledgable asm - hacker has decided to use r2 as a base for loading - a value. He/She does this by setting the tocdefn bit, - and not supplying a toc definition. The behaviour is - then to use the difference between the value of the - symbol and the actual location of the toc as the toc - index. - - In fact, what is usually happening is, because the - Import Address Table is mapped immediately following - the toc, some trippy library code trying for speed on - dll linkage, takes advantage of that and considers - the IAT to be part of the toc, thus saving a load. */ - - our_toc_offset = val - (toc_section->output_section->vma - + toc_section->output_offset); - - /* The size must still fit in a 16-bit displacement. */ - if ((bfd_vma) our_toc_offset >= 65535) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: Relocation for %s of %#Lx exceeds " - "Toc size limit"), - input_bfd, name, our_toc_offset); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - record_toc (toc_section, our_toc_offset, pub, - strdup (name)); - } - else if (IS_WRITTEN (our_toc_offset)) - { - /* If it has been written out, it is marked with the - 1 bit. Fix up our offset, but do not write it out - again. */ - MAKE_ADDR_AGAIN(our_toc_offset); - } - else - { - record_toc(toc_section, our_toc_offset, pub, - strdup (name)); - - /* Write out the toc entry. */ - bfd_put_32 (output_bfd, val, - toc_section->contents + our_toc_offset); - - MARK_AS_WRITTEN(h->toc_offset); - /* The tricky part is that this is the address that - needs a .reloc entry for it. */ - fixit = TRUE; - } - } - - if (fixit && info->base_file) - { - /* So if this is non pcrelative, and is referenced - to a section or a common symbol, then it needs a reloc. */ - - /* Relocation to a symbol in a section which - isn't absolute - we output the address here - to a file. */ - bfd_vma addr = (toc_section->output_section->vma - + toc_section->output_offset + our_toc_offset); - - if (!write_base_file_entry (output_bfd, info, addr)) - return FALSE; - } - - /* FIXME: this test is conservative. */ - if ((r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN - && (bfd_vma) our_toc_offset > toc_section->size) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: Relocation exceeds allocated TOC (%#Lx)"), - input_bfd, toc_section->size); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Now we know the relocation for this toc reference. */ - relocation = our_toc_offset + TOC_LOAD_ADJUSTMENT; - rstat = _bfd_relocate_contents (howto, input_bfd, relocation, loc); - } - break; - case IMAGE_REL_PPC_IFGLUE: - { - /* To solve this, we need to know whether or not the symbol - appearing on the call instruction is a glue function or not. - A glue function must announce itself via a IMGLUE reloc, and - the reloc contains the required toc restore instruction. */ - DUMP_RELOC2 (howto->name, rel); - - if (h != 0) - { - if (h->symbol_is_glue == 1) - { - bfd_put_32 (input_bfd, (bfd_vma) h->glue_insn, loc); - } - } - } - break; - case IMAGE_REL_PPC_SECREL: - /* Unimplemented: codeview debugging information. */ - /* For fast access to the header of the section - containing the item. */ - break; - case IMAGE_REL_PPC_SECTION: - /* Unimplemented: codeview debugging information. */ - /* Is used to indicate that the value should be relative - to the beginning of the section that contains the - symbol. */ - break; - case IMAGE_REL_PPC_ABSOLUTE: - { - const char *my_name; - char buf[SYMNMLEN + 1]; - - if (h == 0) - { - strncpy (buf, (syms+symndx)->_n._n_name, SYMNMLEN); - buf[SYMNMLEN] = '\0'; - my_name = buf; - } - else - my_name = h->root.root.root.string; - - _bfd_error_handler - /* xgettext: c-format */ - (_("Warning: unsupported reloc %s \n" - "sym %ld (%s), r_vaddr %Ld (%#Lx)"), - howto->name, input_bfd, input_section, - rel->r_symndx, my_name, rel->r_vaddr, rel->r_vaddr); - } - break; - case IMAGE_REL_PPC_IMGLUE: - { - /* There is nothing to do now. This reloc was noted in the first - pass over the relocs, and the glue instruction extracted. */ - const char *my_name; - - if (h->symbol_is_glue == 1) - break; - my_name = h->root.root.root.string; - - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: Out of order IMGLUE reloc for %s"), input_bfd, my_name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - case IMAGE_REL_PPC_ADDR32NB: - { - const char *name = 0; - - DUMP_RELOC2 (howto->name, rel); - - if (CONST_STRNEQ (input_section->name, ".idata$2") && first_thunk_address == 0) - { - /* Set magic values. */ - int idata5offset; - struct coff_link_hash_entry *myh; - - myh = coff_link_hash_lookup (coff_hash_table (info), - "__idata5_magic__", - FALSE, FALSE, TRUE); - first_thunk_address = myh->root.u.def.value + - sec->output_section->vma + - sec->output_offset - - pe_data(output_bfd)->pe_opthdr.ImageBase; - - idata5offset = myh->root.u.def.value; - myh = coff_link_hash_lookup (coff_hash_table (info), - "__idata6_magic__", - FALSE, FALSE, TRUE); - - thunk_size = myh->root.u.def.value - idata5offset; - myh = coff_link_hash_lookup (coff_hash_table (info), - "__idata4_magic__", - FALSE, FALSE, TRUE); - import_table_size = myh->root.u.def.value; - } - - if (h == 0) - /* It is a file local symbol. */ - sym = syms + symndx; - else - { - char *target = 0; - - name = h->root.root.root.string; - if (strcmp (".idata$2", name) == 0) - target = "__idata2_magic__"; - else if (strcmp (".idata$4", name) == 0) - target = "__idata4_magic__"; - else if (strcmp (".idata$5", name) == 0) - target = "__idata5_magic__"; - - if (target != 0) - { - struct coff_link_hash_entry *myh; - - myh = coff_link_hash_lookup (coff_hash_table (info), - target, - FALSE, FALSE, TRUE); - if (myh == 0) - { - /* Missing magic cookies. Something is very wrong. */ - abort (); - } - - val = myh->root.u.def.value + - sec->output_section->vma + sec->output_offset; - if (first_thunk_address == 0) - { - int idata5offset; - myh = coff_link_hash_lookup (coff_hash_table (info), - "__idata5_magic__", - FALSE, FALSE, TRUE); - first_thunk_address = myh->root.u.def.value + - sec->output_section->vma + - sec->output_offset - - pe_data(output_bfd)->pe_opthdr.ImageBase; - - idata5offset = myh->root.u.def.value; - myh = coff_link_hash_lookup (coff_hash_table (info), - "__idata6_magic__", - FALSE, FALSE, TRUE); - - thunk_size = myh->root.u.def.value - idata5offset; - myh = coff_link_hash_lookup (coff_hash_table (info), - "__idata4_magic__", - FALSE, FALSE, TRUE); - import_table_size = myh->root.u.def.value; - } - } - } - - rstat = _bfd_relocate_contents (howto, - input_bfd, - val - - pe_data (output_bfd)->pe_opthdr.ImageBase, - loc); - } - break; - - case IMAGE_REL_PPC_REL24: - DUMP_RELOC2(howto->name, rel); - val -= (input_section->output_section->vma - + input_section->output_offset); - - rstat = _bfd_relocate_contents (howto, - input_bfd, - val, - loc); - break; - case IMAGE_REL_PPC_ADDR16: - case IMAGE_REL_PPC_ADDR24: - case IMAGE_REL_PPC_ADDR32: - DUMP_RELOC2(howto->name, rel); - rstat = _bfd_relocate_contents (howto, - input_bfd, - val, - loc); - break; - } - - if (info->base_file) - { - /* So if this is non pcrelative, and is referenced - to a section or a common symbol, then it needs a reloc. */ - if (sym && pe_data(output_bfd)->in_reloc_p (output_bfd, howto)) - { - /* Relocation to a symbol in a section which - isn't absolute - we output the address here - to a file. */ - bfd_vma addr = (rel->r_vaddr - - input_section->vma - + input_section->output_offset - + input_section->output_section->vma); - - if (!write_base_file_entry (output_bfd, info, addr)) - return FALSE; - } - } - - switch (rstat) - { - default: - abort (); - case bfd_reloc_ok: - break; - case bfd_reloc_overflow: - { - const char *name; - char buf[SYMNMLEN + 1]; - - if (symndx == -1) - name = "*ABS*"; - else if (h != NULL) - name = NULL; - else if (sym == NULL) - name = "*unknown*"; - else if (sym->_n._n_n._n_zeroes == 0 - && sym->_n._n_n._n_offset != 0) - name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset; - else - { - strncpy (buf, sym->_n._n_name, SYMNMLEN); - buf[SYMNMLEN] = '\0'; - name = buf; - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root.root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - } - } - - return TRUE; -} - -#ifdef COFF_IMAGE_WITH_PE - -/* FIXME: BFD should not use global variables. This file is compiled - twice, and these variables are shared. This is confusing and - weird. */ - -long int global_toc_size = 4; - -bfd* bfd_of_toc_owner = 0; - -long int import_table_size; -long int first_thunk_address; -long int thunk_size; - -struct list_ele *head; -struct list_ele *tail; - -static char * -h1 = N_("\n\t\t\tTOC MAPPING\n\n"); -static char * -h2 = N_(" TOC disassembly Comments Name\n"); -static char * -h3 = N_(" Offset spelling (if present)\n"); - -void -dump_toc (void * vfile) -{ - FILE *file = (FILE *) vfile; - struct list_ele *t; - - fputs (_(h1), file); - fputs (_(h2), file); - fputs (_(h3), file); - - for (t = head; t != 0; t=t->next) - { - const char *cat = ""; - - if (t->cat == priv) - cat = _("private "); - else if (t->cat == pub) - cat = _("public "); - else if (t->cat == tocdata) - cat = _("data-in-toc "); - - if (t->offset > global_toc_size) - { - if (t->offset <= global_toc_size + thunk_size) - cat = _("IAT reference "); - else - { - fprintf (file, - /* xgettext: c-format */ - _("**** global_toc_size %ld(%lx), thunk_size %ld(%lx)\n"), - global_toc_size, (unsigned long) global_toc_size, - thunk_size, (unsigned long) thunk_size); - cat = _("Out of bounds!"); - } - } - - fprintf (file, - " %04lx (%d)", (unsigned long) t->offset, t->offset - 32768); - fprintf (file, - " %s %s\n", - cat, t->name); - - } - - fprintf (file, "\n"); -} - -bfd_boolean -ppc_allocate_toc_section (struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - asection *s; - bfd_byte *foo; - bfd_size_type amt; - static char test_char = '1'; - - if ( global_toc_size == 0 ) /* FIXME: does this get me in trouble? */ - return TRUE; - - if (bfd_of_toc_owner == 0) - /* No toc owner? Something is very wrong. */ - abort (); - - s = bfd_get_section_by_name ( bfd_of_toc_owner , TOC_SECTION_NAME); - if (s == NULL) - /* No toc section? Something is very wrong. */ - abort (); - - amt = global_toc_size; - foo = (bfd_byte *) bfd_alloc (bfd_of_toc_owner, amt); - memset(foo, test_char, (size_t) global_toc_size); - - s->size = global_toc_size; - s->contents = foo; - - return TRUE; -} - -bfd_boolean -ppc_process_before_allocation (bfd *abfd, - struct bfd_link_info *info) -{ - asection *sec; - struct internal_reloc *i, *rel; - - /* Here we have a bfd that is to be included on the link. We have a hook - to do reloc rummaging, before section sizes are nailed down. */ - _bfd_coff_get_external_symbols (abfd); - - /* Rummage around all the relocs and map the toc. */ - sec = abfd->sections; - - if (sec == 0) - return TRUE; - - for (; sec != 0; sec = sec->next) - { - if (sec->reloc_count == 0) - continue; - - /* load the relocs */ - /* FIXME: there may be a storage leak here */ - i=_bfd_coff_read_internal_relocs(abfd,sec,1,0,0,0); - - if (i == 0) - abort (); - - for (rel = i; rel < i + sec->reloc_count; ++rel) - { - unsigned short r_type = EXTRACT_TYPE (rel->r_type); - unsigned short r_flags = EXTRACT_FLAGS (rel->r_type); - bfd_boolean ok = TRUE; - - DUMP_RELOC2 (ppc_coff_howto_table[r_type].name, rel); - - switch(r_type) - { - case IMAGE_REL_PPC_TOCREL16: - /* If TOCDEFN is on, ignore as someone else has allocated the - toc entry. */ - if ((r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN) - ok = ppc_record_toc_entry(abfd, info, sec, - rel->r_symndx, default_toc); - if (!ok) - return FALSE; - break; - case IMAGE_REL_PPC_IMGLUE: - ppc_mark_symbol_as_glue (abfd, rel->r_symndx, rel); - break; - default: - break; - } - } - } - - return TRUE; -} - -#endif - -static bfd_reloc_status_type -ppc_refhi_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - UN_IMPL("REFHI"); - DUMP_RELOC("REFHI",reloc_entry); - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_undefined; -} - -static bfd_reloc_status_type -ppc_pair_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - UN_IMPL("PAIR"); - DUMP_RELOC("PAIR",reloc_entry); - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_undefined; -} - -static bfd_reloc_status_type -ppc_toc16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - UN_IMPL ("TOCREL16"); - DUMP_RELOC ("TOCREL16",reloc_entry); - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -ppc_secrel_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - UN_IMPL("SECREL"); - DUMP_RELOC("SECREL",reloc_entry); - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -ppc_section_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - UN_IMPL("SECTION"); - DUMP_RELOC("SECTION",reloc_entry); - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -ppc_imglue_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) - -{ - UN_IMPL("IMGLUE"); - DUMP_RELOC("IMGLUE",reloc_entry); - - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - return bfd_reloc_ok; -} - -#define MAX_RELOC_INDEX \ - (sizeof (ppc_coff_howto_table) / sizeof (ppc_coff_howto_table[0]) - 1) - -/* FIXME: There is a possibility that when we read in a reloc from a file, - that there are some bits encoded in the upper portion of the - type field. Not yet implemented. */ - -static void -ppc_coff_rtype2howto (arelent *relent, struct internal_reloc *internal) -{ - /* We can encode one of three things in the type field, aside from the - type: - 1. IMAGE_REL_PPC_NEG - indicates the value field is a subtraction - value, rather than an addition value - 2. IMAGE_REL_PPC_BRTAKEN, IMAGE_REL_PPC_BRNTAKEN - indicates that - the branch is expected to be taken or not. - 3. IMAGE_REL_PPC_TOCDEFN - toc slot definition in the file - For now, we just strip this stuff to find the type, and ignore it other - than that. */ - reloc_howto_type *howto; - unsigned short r_type = EXTRACT_TYPE (internal->r_type); - unsigned short r_flags = EXTRACT_FLAGS(internal->r_type); - unsigned short junk = EXTRACT_JUNK (internal->r_type); - - /* The masking process only slices off the bottom byte for r_type. */ - if ( r_type > MAX_RELOC_INDEX ) - abort (); - - /* Check for absolute crap. */ - if (junk != 0) - abort (); - - switch(r_type) - { - case IMAGE_REL_PPC_ADDR16: - case IMAGE_REL_PPC_REL24: - case IMAGE_REL_PPC_ADDR24: - case IMAGE_REL_PPC_ADDR32: - case IMAGE_REL_PPC_IFGLUE: - case IMAGE_REL_PPC_ADDR32NB: - case IMAGE_REL_PPC_SECTION: - case IMAGE_REL_PPC_SECREL: - DUMP_RELOC2 (ppc_coff_howto_table[r_type].name, internal); - howto = ppc_coff_howto_table + r_type; - break; - case IMAGE_REL_PPC_IMGLUE: - DUMP_RELOC2 (ppc_coff_howto_table[r_type].name, internal); - howto = ppc_coff_howto_table + r_type; - break; - case IMAGE_REL_PPC_TOCREL16: - DUMP_RELOC2 (ppc_coff_howto_table[r_type].name, internal); - if (r_flags & IMAGE_REL_PPC_TOCDEFN) - howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN; - else - howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16; - break; - default: - _bfd_error_handler - /* xgettext: c-format */ - (_("warning: unsupported reloc %s [%d] used -- it may not work"), - ppc_coff_howto_table[r_type].name, r_type); - howto = ppc_coff_howto_table + r_type; - break; - } - - relent->howto = howto; -} - -static reloc_howto_type * -coff_ppc_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - bfd_vma *addendp) -{ - reloc_howto_type *howto; - - /* We can encode one of three things in the type field, aside from the - type: - 1. IMAGE_REL_PPC_NEG - indicates the value field is a subtraction - value, rather than an addition value - 2. IMAGE_REL_PPC_BRTAKEN, IMAGE_REL_PPC_BRNTAKEN - indicates that - the branch is expected to be taken or not. - 3. IMAGE_REL_PPC_TOCDEFN - toc slot definition in the file - For now, we just strip this stuff to find the type, and ignore it other - than that. */ - - unsigned short r_type = EXTRACT_TYPE (rel->r_type); - unsigned short r_flags = EXTRACT_FLAGS (rel->r_type); - unsigned short junk = EXTRACT_JUNK (rel->r_type); - - /* The masking process only slices off the bottom byte for r_type. */ - if (r_type > MAX_RELOC_INDEX) - abort (); - - /* Check for absolute crap. */ - if (junk != 0) - abort (); - - switch(r_type) - { - case IMAGE_REL_PPC_ADDR32NB: - DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); - *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase; - howto = ppc_coff_howto_table + r_type; - break; - case IMAGE_REL_PPC_TOCREL16: - DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); - if (r_flags & IMAGE_REL_PPC_TOCDEFN) - howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN; - else - howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16; - break; - case IMAGE_REL_PPC_ADDR16: - case IMAGE_REL_PPC_REL24: - case IMAGE_REL_PPC_ADDR24: - case IMAGE_REL_PPC_ADDR32: - case IMAGE_REL_PPC_IFGLUE: - case IMAGE_REL_PPC_SECTION: - case IMAGE_REL_PPC_SECREL: - DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); - howto = ppc_coff_howto_table + r_type; - break; - case IMAGE_REL_PPC_IMGLUE: - DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); - howto = ppc_coff_howto_table + r_type; - break; - default: - _bfd_error_handler - /* xgettext: c-format */ - (_("warning: unsupported reloc %s [%d] used -- it may not work"), - ppc_coff_howto_table[r_type].name, r_type); - howto = ppc_coff_howto_table + r_type; - break; - } - - return howto; -} - -/* A cheesy little macro to make the code a little more readable. */ -#define HOW2MAP(bfd_rtype,ppc_rtype) \ - case bfd_rtype: return &ppc_coff_howto_table[ppc_rtype] - -static reloc_howto_type * -ppc_coff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - HOW2MAP(BFD_RELOC_32_GOTOFF, IMAGE_REL_PPC_IMGLUE); - HOW2MAP(BFD_RELOC_16_GOT_PCREL, IMAGE_REL_PPC_IFGLUE); - HOW2MAP(BFD_RELOC_16, IMAGE_REL_PPC_ADDR16); - HOW2MAP(BFD_RELOC_PPC_B26, IMAGE_REL_PPC_REL24); - HOW2MAP(BFD_RELOC_PPC_BA26, IMAGE_REL_PPC_ADDR24); - HOW2MAP(BFD_RELOC_PPC_TOC16, IMAGE_REL_PPC_TOCREL16); - HOW2MAP(BFD_RELOC_16_GOTOFF, IMAGE_REL_PPC_TOCREL16_DEFN); - HOW2MAP(BFD_RELOC_32, IMAGE_REL_PPC_ADDR32); - HOW2MAP(BFD_RELOC_RVA, IMAGE_REL_PPC_ADDR32NB); - default: - return NULL; - } -} -#undef HOW2MAP - -static reloc_howto_type * -ppc_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (ppc_coff_howto_table) / sizeof (ppc_coff_howto_table[0]); - i++) - if (ppc_coff_howto_table[i].name != NULL - && strcasecmp (ppc_coff_howto_table[i].name, r_name) == 0) - return &ppc_coff_howto_table[i]; - - return NULL; -} - -/* Tailor coffcode.h -- macro heaven. */ - -#define RTYPE2HOWTO(cache_ptr, dst) ppc_coff_rtype2howto (cache_ptr, dst) - -/* We use the special COFF backend linker, with our own special touch. */ - -#define coff_bfd_reloc_type_lookup ppc_coff_reloc_type_lookup -#define coff_bfd_reloc_name_lookup ppc_coff_reloc_name_lookup -#define coff_rtype_to_howto coff_ppc_rtype_to_howto -#define coff_relocate_section coff_ppc_relocate_section -#define coff_bfd_final_link ppc_bfd_coff_final_link - -#ifndef COFF_IMAGE_WITH_PE -#endif - -#define SELECT_RELOC(internal, howto) {internal.r_type=howto->type;} - -#define COFF_PAGE_SIZE 0x1000 - -/* FIXME: This controls some code that used to be in peicode.h and is - now in peigen.c. It will not control the code in peigen.c. If - anybody wants to get this working, you will need to fix that. */ -#define POWERPC_LE_PE - -#define COFF_SECTION_ALIGNMENT_ENTRIES \ -{ COFF_SECTION_NAME_EXACT_MATCH (".idata$2"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".idata$3"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".idata$4"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".idata$5"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".idata$6"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 1 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".reloc"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 1 } - -#include "coffcode.h" - -#ifndef COFF_IMAGE_WITH_PE - -static bfd_boolean -ppc_do_last (bfd *abfd) -{ - if (abfd == bfd_of_toc_owner) - return TRUE; - else - return FALSE; -} - -static bfd * -ppc_get_last (void) -{ - return bfd_of_toc_owner; -} - -/* This piece of machinery exists only to guarantee that the bfd that holds - the toc section is written last. - - This does depend on bfd_make_section attaching a new section to the - end of the section list for the bfd. - - This is otherwise intended to be functionally the same as - cofflink.c:_bfd_coff_final_link(). It is specifically different only - where the POWERPC_LE_PE macro modifies the code. It is left in as a - precise form of comment. krk@cygnus.com */ - -/* Do the final link step. */ - -bfd_boolean -ppc_bfd_coff_final_link (bfd *abfd, struct bfd_link_info *info) -{ - bfd_size_type symesz; - struct coff_final_link_info flaginfo; - bfd_boolean debug_merge_allocated; - asection *o; - struct bfd_link_order *p; - bfd_size_type max_sym_count; - bfd_size_type max_lineno_count; - bfd_size_type max_reloc_count; - bfd_size_type max_output_reloc_count; - bfd_size_type max_contents_size; - file_ptr rel_filepos; - unsigned int relsz; - file_ptr line_filepos; - unsigned int linesz; - bfd *sub; - bfd_byte *external_relocs = NULL; - char strbuf[STRING_SIZE_SIZE]; - bfd_size_type amt; - - symesz = bfd_coff_symesz (abfd); - - flaginfo.info = info; - flaginfo.output_bfd = abfd; - flaginfo.strtab = NULL; - flaginfo.section_info = NULL; - flaginfo.last_file_index = -1; - flaginfo.last_bf_index = -1; - flaginfo.internal_syms = NULL; - flaginfo.sec_ptrs = NULL; - flaginfo.sym_indices = NULL; - flaginfo.outsyms = NULL; - flaginfo.linenos = NULL; - flaginfo.contents = NULL; - flaginfo.external_relocs = NULL; - flaginfo.internal_relocs = NULL; - debug_merge_allocated = FALSE; - - coff_data (abfd)->link_info = info; - - flaginfo.strtab = _bfd_stringtab_init (); - if (flaginfo.strtab == NULL) - goto error_return; - - if (! coff_debug_merge_hash_table_init (&flaginfo.debug_merge)) - goto error_return; - debug_merge_allocated = TRUE; - - /* Compute the file positions for all the sections. */ - if (! abfd->output_has_begun) - { - if (! bfd_coff_compute_section_file_positions (abfd)) - return FALSE; - } - - /* Count the line numbers and relocation entries required for the - output file. Set the file positions for the relocs. */ - rel_filepos = obj_relocbase (abfd); - relsz = bfd_coff_relsz (abfd); - max_contents_size = 0; - max_lineno_count = 0; - max_reloc_count = 0; - - for (o = abfd->sections; o != NULL; o = o->next) - { - o->reloc_count = 0; - o->lineno_count = 0; - - for (p = o->map_head.link_order; p != NULL; p = p->next) - { - if (p->type == bfd_indirect_link_order) - { - asection *sec; - - sec = p->u.indirect.section; - - /* 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 (info->strip == strip_none - || info->strip == strip_some) - o->lineno_count += sec->lineno_count; - - if (bfd_link_relocatable (info)) - o->reloc_count += sec->reloc_count; - - if (sec->rawsize > max_contents_size) - max_contents_size = sec->rawsize; - if (sec->size > max_contents_size) - max_contents_size = sec->size; - if (sec->lineno_count > max_lineno_count) - max_lineno_count = sec->lineno_count; - if (sec->reloc_count > max_reloc_count) - max_reloc_count = sec->reloc_count; - } - else if (bfd_link_relocatable (info) - && (p->type == bfd_section_reloc_link_order - || p->type == bfd_symbol_reloc_link_order)) - ++o->reloc_count; - } - if (o->reloc_count == 0) - o->rel_filepos = 0; - else - { - o->flags |= SEC_RELOC; - o->rel_filepos = rel_filepos; - rel_filepos += o->reloc_count * relsz; - } - } - - /* If doing a relocatable link, allocate space for the pointers we - need to keep. */ - if (bfd_link_relocatable (info)) - { - unsigned int i; - - /* We use section_count + 1, rather than section_count, because - the target_index fields are 1 based. */ - amt = abfd->section_count + 1; - amt *= sizeof (struct coff_link_section_info); - flaginfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt); - - if (flaginfo.section_info == NULL) - goto error_return; - - for (i = 0; i <= abfd->section_count; i++) - { - flaginfo.section_info[i].relocs = NULL; - flaginfo.section_info[i].rel_hashes = NULL; - } - } - - /* We now know the size of the relocs, so we can determine the file - positions of the line numbers. */ - line_filepos = rel_filepos; - linesz = bfd_coff_linesz (abfd); - max_output_reloc_count = 0; - - for (o = abfd->sections; o != NULL; o = o->next) - { - if (o->lineno_count == 0) - o->line_filepos = 0; - else - { - o->line_filepos = line_filepos; - line_filepos += o->lineno_count * linesz; - } - - if (o->reloc_count != 0) - { - /* We don't know the indices of global symbols until we have - written out all the local symbols. For each section in - the output file, we keep an array of pointers to hash - table entries. Each entry in the array corresponds to a - reloc. When we find a reloc against a global symbol, we - set the corresponding entry in this array so that we can - fix up the symbol index after we have written out all the - local symbols. - - Because of this problem, we also keep the relocs in - memory until the end of the link. This wastes memory, - but only when doing a relocatable link, which is not the - common case. */ - BFD_ASSERT (bfd_link_relocatable (info)); - amt = o->reloc_count; - amt *= sizeof (struct internal_reloc); - flaginfo.section_info[o->target_index].relocs = - (struct internal_reloc *) bfd_malloc (amt); - amt = o->reloc_count; - amt *= sizeof (struct coff_link_hash_entry *); - flaginfo.section_info[o->target_index].rel_hashes = - (struct coff_link_hash_entry **) bfd_malloc (amt); - if (flaginfo.section_info[o->target_index].relocs == NULL - || flaginfo.section_info[o->target_index].rel_hashes == NULL) - goto error_return; - - if (o->reloc_count > max_output_reloc_count) - max_output_reloc_count = o->reloc_count; - } - - /* Reset the reloc and lineno counts, so that we can use them to - count the number of entries we have output so far. */ - o->reloc_count = 0; - o->lineno_count = 0; - } - - obj_sym_filepos (abfd) = line_filepos; - - /* Figure out the largest number of symbols in an input BFD. Take - the opportunity to clear the output_has_begun fields of all the - input BFD's. */ - max_sym_count = 0; - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - bfd_size_type sz; - - sub->output_has_begun = FALSE; - sz = obj_raw_syment_count (sub); - if (sz > max_sym_count) - max_sym_count = sz; - } - - /* Allocate some buffers used while linking. */ - amt = max_sym_count * sizeof (struct internal_syment); - flaginfo.internal_syms = (struct internal_syment *) bfd_malloc (amt); - amt = max_sym_count * sizeof (asection *); - flaginfo.sec_ptrs = (asection **) bfd_malloc (amt); - amt = max_sym_count * sizeof (long); - flaginfo.sym_indices = (long *) bfd_malloc (amt); - amt = (max_sym_count + 1) * symesz; - flaginfo.outsyms = (bfd_byte *) bfd_malloc (amt); - amt = max_lineno_count * bfd_coff_linesz (abfd); - flaginfo.linenos = (bfd_byte *) bfd_malloc (amt); - flaginfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); - flaginfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz); - if (! bfd_link_relocatable (info)) - { - amt = max_reloc_count * sizeof (struct internal_reloc); - flaginfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt); - } - if ((flaginfo.internal_syms == NULL && max_sym_count > 0) - || (flaginfo.sec_ptrs == NULL && max_sym_count > 0) - || (flaginfo.sym_indices == NULL && max_sym_count > 0) - || flaginfo.outsyms == NULL - || (flaginfo.linenos == NULL && max_lineno_count > 0) - || (flaginfo.contents == NULL && max_contents_size > 0) - || (flaginfo.external_relocs == NULL && max_reloc_count > 0) - || (! bfd_link_relocatable (info) - && flaginfo.internal_relocs == NULL - && max_reloc_count > 0)) - goto error_return; - - /* We now know the position of everything in the file, except that - we don't know the size of the symbol table and therefore we don't - know where the string table starts. We just build the string - table in memory as we go along. We process all the relocations - for a single input file at once. */ - obj_raw_syment_count (abfd) = 0; - - if (coff_backend_info (abfd)->_bfd_coff_start_final_link) - { - if (! bfd_coff_start_final_link (abfd, info)) - goto error_return; - } - - 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 (p->u.indirect.section->owner) - == bfd_target_coff_flavour)) - { - sub = p->u.indirect.section->owner; -#ifdef POWERPC_LE_PE - if (! sub->output_has_begun && !ppc_do_last(sub)) -#else - if (! sub->output_has_begun) -#endif - { - if (! _bfd_coff_link_input_bfd (&flaginfo, 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 (! _bfd_coff_reloc_link_order (abfd, &flaginfo, o, p)) - goto error_return; - } - else - { - if (! _bfd_default_link_order (abfd, info, o, p)) - goto error_return; - } - } - } - -#ifdef POWERPC_LE_PE - { - bfd* last_one = ppc_get_last(); - if (last_one) - { - if (! _bfd_coff_link_input_bfd (&flaginfo, last_one)) - goto error_return; - } - last_one->output_has_begun = TRUE; - } -#endif - - /* Free up the buffers used by _bfd_coff_link_input_bfd. */ - coff_debug_merge_hash_table_free (&flaginfo.debug_merge); - debug_merge_allocated = FALSE; - - if (flaginfo.internal_syms != NULL) - { - free (flaginfo.internal_syms); - flaginfo.internal_syms = NULL; - } - if (flaginfo.sec_ptrs != NULL) - { - free (flaginfo.sec_ptrs); - flaginfo.sec_ptrs = NULL; - } - if (flaginfo.sym_indices != NULL) - { - free (flaginfo.sym_indices); - flaginfo.sym_indices = NULL; - } - if (flaginfo.linenos != NULL) - { - free (flaginfo.linenos); - flaginfo.linenos = NULL; - } - if (flaginfo.contents != NULL) - { - free (flaginfo.contents); - flaginfo.contents = NULL; - } - if (flaginfo.external_relocs != NULL) - { - free (flaginfo.external_relocs); - flaginfo.external_relocs = NULL; - } - if (flaginfo.internal_relocs != NULL) - { - free (flaginfo.internal_relocs); - flaginfo.internal_relocs = NULL; - } - - /* The value of the last C_FILE symbol is supposed to be the symbol - index of the first external symbol. Write it out again if - necessary. */ - if (flaginfo.last_file_index != -1 - && (unsigned int) flaginfo.last_file.n_value != obj_raw_syment_count (abfd)) - { - file_ptr pos; - - flaginfo.last_file.n_value = obj_raw_syment_count (abfd); - bfd_coff_swap_sym_out (abfd, &flaginfo.last_file, - flaginfo.outsyms); - pos = obj_sym_filepos (abfd) + flaginfo.last_file_index * symesz; - if (bfd_seek (abfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz) - return FALSE; - } - - /* Write out the global symbols. */ - flaginfo.failed = FALSE; - bfd_hash_traverse (&info->hash->table, _bfd_coff_write_global_sym, &flaginfo); - if (flaginfo.failed) - goto error_return; - - /* The outsyms buffer is used by _bfd_coff_write_global_sym. */ - if (flaginfo.outsyms != NULL) - { - free (flaginfo.outsyms); - flaginfo.outsyms = NULL; - } - - if (bfd_link_relocatable (info)) - { - /* Now that we have written out all the global symbols, we know - the symbol indices to use for relocs against them, and we can - finally write out the relocs. */ - amt = max_output_reloc_count * relsz; - external_relocs = (bfd_byte *) bfd_malloc (amt); - if (external_relocs == NULL) - goto error_return; - - for (o = abfd->sections; o != NULL; o = o->next) - { - struct internal_reloc *irel; - struct internal_reloc *irelend; - struct coff_link_hash_entry **rel_hash; - bfd_byte *erel; - - if (o->reloc_count == 0) - continue; - - irel = flaginfo.section_info[o->target_index].relocs; - irelend = irel + o->reloc_count; - rel_hash = flaginfo.section_info[o->target_index].rel_hashes; - erel = external_relocs; - for (; irel < irelend; irel++, rel_hash++, erel += relsz) - { - if (*rel_hash != NULL) - { - BFD_ASSERT ((*rel_hash)->indx >= 0); - irel->r_symndx = (*rel_hash)->indx; - } - bfd_coff_swap_reloc_out (abfd, irel, erel); - } - - amt = relsz * o->reloc_count; - if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0 - || bfd_bwrite (external_relocs, amt, abfd) != amt) - goto error_return; - } - - free (external_relocs); - external_relocs = NULL; - } - - /* Free up the section information. */ - if (flaginfo.section_info != NULL) - { - unsigned int i; - - for (i = 0; i < abfd->section_count; i++) - { - if (flaginfo.section_info[i].relocs != NULL) - free (flaginfo.section_info[i].relocs); - if (flaginfo.section_info[i].rel_hashes != NULL) - free (flaginfo.section_info[i].rel_hashes); - } - free (flaginfo.section_info); - flaginfo.section_info = NULL; - } - - /* If we have optimized stabs strings, output them. */ - if (coff_hash_table (info)->stab_info.stabstr != NULL) - { - if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info)) - return FALSE; - } - - /* Write out the string table. */ - if (obj_raw_syment_count (abfd) != 0) - { - file_ptr pos; - - pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz; - if (bfd_seek (abfd, pos, SEEK_SET) != 0) - return FALSE; - -#if STRING_SIZE_SIZE == 4 - H_PUT_32 (abfd, - _bfd_stringtab_size (flaginfo.strtab) + STRING_SIZE_SIZE, - strbuf); -#else - #error Change H_PUT_32 above -#endif - - if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd) - != STRING_SIZE_SIZE) - return FALSE; - - if (! _bfd_stringtab_emit (abfd, flaginfo.strtab)) - return FALSE; - } - - _bfd_stringtab_free (flaginfo.strtab); - - /* Setting bfd_get_symcount to 0 will cause write_object_contents to - not try to write out the symbols. */ - bfd_get_symcount (abfd) = 0; - - return TRUE; - - error_return: - if (debug_merge_allocated) - coff_debug_merge_hash_table_free (&flaginfo.debug_merge); - if (flaginfo.strtab != NULL) - _bfd_stringtab_free (flaginfo.strtab); - if (flaginfo.section_info != NULL) - { - unsigned int i; - - for (i = 0; i < abfd->section_count; i++) - { - if (flaginfo.section_info[i].relocs != NULL) - free (flaginfo.section_info[i].relocs); - if (flaginfo.section_info[i].rel_hashes != NULL) - free (flaginfo.section_info[i].rel_hashes); - } - free (flaginfo.section_info); - } - if (flaginfo.internal_syms != NULL) - free (flaginfo.internal_syms); - if (flaginfo.sec_ptrs != NULL) - free (flaginfo.sec_ptrs); - if (flaginfo.sym_indices != NULL) - free (flaginfo.sym_indices); - if (flaginfo.outsyms != NULL) - free (flaginfo.outsyms); - if (flaginfo.linenos != NULL) - free (flaginfo.linenos); - if (flaginfo.contents != NULL) - free (flaginfo.contents); - if (flaginfo.external_relocs != NULL) - free (flaginfo.external_relocs); - if (flaginfo.internal_relocs != NULL) - free (flaginfo.internal_relocs); - if (external_relocs != NULL) - free (external_relocs); - return FALSE; -} -#endif - -/* Forward declaration for use by alternative_target field. */ -#ifdef TARGET_BIG_SYM -extern const bfd_target TARGET_BIG_SYM; -#endif - -/* The transfer vectors that lead the outside world to all of the above. */ - -#ifdef TARGET_LITTLE_SYM -const bfd_target TARGET_LITTLE_SYM = -{ - TARGET_LITTLE_NAME, /* name or coff-arm-little */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* FIXME: object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - -#ifndef COFF_WITH_PE - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY - | SEC_RELOC), /* section flags */ -#else - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY - | SEC_RELOC | SEC_LINK_ONCE | SEC_LINK_DUPLICATES), -#endif - - 0, /* leading char */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen??? FIXMEmgo */ - 0, /* match priority. */ - - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, /* _bfd_dummy_target */ coff_object_p }, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - /* Alternative_target. */ -#ifdef TARGET_BIG_SYM - & TARGET_BIG_SYM, -#else - NULL, -#endif - - COFF_SWAP_TABLE -}; -#endif - -#ifdef TARGET_BIG_SYM -const bfd_target TARGET_BIG_SYM = -{ - TARGET_BIG_NAME, - bfd_target_coff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* FIXME: object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), - -#ifndef COFF_WITH_PE - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY - | SEC_RELOC), /* section flags */ -#else - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY - | SEC_RELOC | SEC_LINK_ONCE | SEC_LINK_DUPLICATES), -#endif - - 0, /* leading char */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen??? FIXMEmgo */ - 0, /* match priority. */ - - 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, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, /* _bfd_dummy_target */ coff_object_p }, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - /* Alternative_target. */ -#ifdef TARGET_LITTLE_SYM - & TARGET_LITTLE_SYM, -#else - NULL, -#endif - - COFF_SWAP_TABLE -}; - -#endif diff --git a/sdcc/support/sdbinutils/bfd/coff-rs6000.c b/sdcc/support/sdbinutils/bfd/coff-rs6000.c deleted file mode 100644 index 2fc1feb1c..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-rs6000.c +++ /dev/null @@ -1,4406 +0,0 @@ -/* BFD back-end for IBM RS/6000 "XCOFF" files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Metin G. Ozisik, Mimi Phuong-Thao Vo, and John Gilmore. - Archive support from Damon A. Permezel. - Contributed by IBM Corporation and Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "libiberty.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "coff/internal.h" -#include "coff/xcoff.h" -#include "coff/rs6000.h" -#include "libcoff.h" -#include "libxcoff.h" - -extern bfd_boolean _bfd_xcoff_mkobject (bfd *); -extern bfd_boolean _bfd_xcoff_copy_private_bfd_data (bfd *, bfd *); -extern bfd_boolean _bfd_xcoff_is_local_label_name (bfd *, const char *); -extern reloc_howto_type *_bfd_xcoff_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -extern bfd_boolean _bfd_xcoff_slurp_armap (bfd *); -extern const bfd_target *_bfd_xcoff_archive_p (bfd *); -extern void * _bfd_xcoff_read_ar_hdr (bfd *); -extern bfd *_bfd_xcoff_openr_next_archived_file (bfd *, bfd *); -extern int _bfd_xcoff_stat_arch_elt (bfd *, struct stat *); -extern bfd_boolean _bfd_xcoff_write_armap - (bfd *, unsigned int, struct orl *, unsigned int, int); -extern bfd_boolean _bfd_xcoff_write_archive_contents (bfd *); -extern int _bfd_xcoff_sizeof_headers (bfd *, struct bfd_link_info *); -extern void _bfd_xcoff_swap_sym_in (bfd *, void *, void *); -extern unsigned int _bfd_xcoff_swap_sym_out (bfd *, void *, void *); -extern void _bfd_xcoff_swap_aux_in (bfd *, void *, int, int, int, int, void *); -extern unsigned int _bfd_xcoff_swap_aux_out - (bfd *, void *, int, int, int, int, void *); -static void xcoff_swap_reloc_in (bfd *, void *, void *); -static unsigned int xcoff_swap_reloc_out (bfd *, void *, void *); - -/* Forward declare xcoff_rtype2howto for coffcode.h macro. */ -void xcoff_rtype2howto (arelent *, struct internal_reloc *); - -/* coffcode.h needs these to be defined. */ -#define RS6000COFF_C 1 - -#define SELECT_RELOC(internal, howto) \ - { \ - internal.r_type = howto->type; \ - internal.r_size = \ - ((howto->complain_on_overflow == complain_overflow_signed \ - ? 0x80 \ - : 0) \ - | (howto->bitsize - 1)); \ - } - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) -#define COFF_LONG_FILENAMES -#define NO_COFF_SYMBOLS -#define RTYPE2HOWTO(cache_ptr, dst) xcoff_rtype2howto (cache_ptr, dst) -#define coff_mkobject _bfd_xcoff_mkobject -#define coff_bfd_is_local_label_name _bfd_xcoff_is_local_label_name -#ifdef AIX_CORE -extern const bfd_target * rs6000coff_core_p (bfd *abfd); -extern bfd_boolean rs6000coff_core_file_matches_executable_p - (bfd *cbfd, bfd *ebfd); -extern char *rs6000coff_core_file_failing_command (bfd *abfd); -extern int rs6000coff_core_file_failing_signal (bfd *abfd); -#define CORE_FILE_P rs6000coff_core_p -#define coff_core_file_failing_command \ - rs6000coff_core_file_failing_command -#define coff_core_file_failing_signal \ - rs6000coff_core_file_failing_signal -#define coff_core_file_matches_executable_p \ - rs6000coff_core_file_matches_executable_p -#define coff_core_file_pid \ - _bfd_nocore_core_file_pid -#else -#define CORE_FILE_P _bfd_dummy_target -#define coff_core_file_failing_command \ - _bfd_nocore_core_file_failing_command -#define coff_core_file_failing_signal \ - _bfd_nocore_core_file_failing_signal -#define coff_core_file_matches_executable_p \ - _bfd_nocore_core_file_matches_executable_p -#define coff_core_file_pid \ - _bfd_nocore_core_file_pid -#endif -#define coff_SWAP_sym_in _bfd_xcoff_swap_sym_in -#define coff_SWAP_sym_out _bfd_xcoff_swap_sym_out -#define coff_SWAP_aux_in _bfd_xcoff_swap_aux_in -#define coff_SWAP_aux_out _bfd_xcoff_swap_aux_out -#define coff_swap_reloc_in xcoff_swap_reloc_in -#define coff_swap_reloc_out xcoff_swap_reloc_out -#define NO_COFF_RELOCS - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include -#include "coffcode.h" - -/* The main body of code is in coffcode.h. */ - -static const char *normalize_filename (bfd *); -static bfd_boolean xcoff_write_armap_old - (bfd *, unsigned int, struct orl *, unsigned int, int); -static bfd_boolean xcoff_write_armap_big - (bfd *, unsigned int, struct orl *, unsigned int, int); -static bfd_boolean xcoff_write_archive_contents_old (bfd *); -static bfd_boolean xcoff_write_archive_contents_big (bfd *); -static void xcoff_swap_ldhdr_in (bfd *, const void *, struct internal_ldhdr *); -static void xcoff_swap_ldhdr_out (bfd *, const struct internal_ldhdr *, void *); -static void xcoff_swap_ldsym_in (bfd *, const void *, struct internal_ldsym *); -static void xcoff_swap_ldsym_out (bfd *, const struct internal_ldsym *, void *); -static void xcoff_swap_ldrel_in (bfd *, const void *, struct internal_ldrel *); -static void xcoff_swap_ldrel_out (bfd *, const struct internal_ldrel *, void *); -static bfd_boolean xcoff_ppc_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, - struct internal_reloc *, struct internal_syment *, asection **); -static bfd_boolean _bfd_xcoff_put_ldsymbol_name - (bfd *, struct xcoff_loader_info *, struct internal_ldsym *, const char *); -static asection *xcoff_create_csect_from_smclas - (bfd *, union internal_auxent *, const char *); -static bfd_boolean xcoff_is_lineno_count_overflow (bfd *, bfd_vma); -static bfd_boolean xcoff_is_reloc_count_overflow (bfd *, bfd_vma); -static bfd_vma xcoff_loader_symbol_offset (bfd *, struct internal_ldhdr *); -static bfd_vma xcoff_loader_reloc_offset (bfd *, struct internal_ldhdr *); -static bfd_boolean xcoff_generate_rtinit - (bfd *, const char *, const char *, bfd_boolean); -static bfd_boolean do_pad (bfd *, unsigned int); -static bfd_boolean do_copy (bfd *, bfd *); - -/* Relocation functions */ -static bfd_boolean xcoff_reloc_type_br (XCOFF_RELOC_FUNCTION_ARGS); - -static bfd_boolean xcoff_complain_overflow_dont_func - (XCOFF_COMPLAIN_FUNCTION_ARGS); -static bfd_boolean xcoff_complain_overflow_bitfield_func - (XCOFF_COMPLAIN_FUNCTION_ARGS); -static bfd_boolean xcoff_complain_overflow_signed_func - (XCOFF_COMPLAIN_FUNCTION_ARGS); -static bfd_boolean xcoff_complain_overflow_unsigned_func - (XCOFF_COMPLAIN_FUNCTION_ARGS); - -bfd_boolean (*xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION]) - (XCOFF_RELOC_FUNCTION_ARGS) = -{ - xcoff_reloc_type_pos, /* R_POS (0x00) */ - xcoff_reloc_type_neg, /* R_NEG (0x01) */ - xcoff_reloc_type_rel, /* R_REL (0x02) */ - xcoff_reloc_type_toc, /* R_TOC (0x03) */ - xcoff_reloc_type_fail, /* R_RTB (0x04) */ - xcoff_reloc_type_toc, /* R_GL (0x05) */ - xcoff_reloc_type_toc, /* R_TCL (0x06) */ - xcoff_reloc_type_fail, /* (0x07) */ - xcoff_reloc_type_ba, /* R_BA (0x08) */ - xcoff_reloc_type_fail, /* (0x09) */ - xcoff_reloc_type_br, /* R_BR (0x0a) */ - xcoff_reloc_type_fail, /* (0x0b) */ - xcoff_reloc_type_pos, /* R_RL (0x0c) */ - xcoff_reloc_type_pos, /* R_RLA (0x0d) */ - xcoff_reloc_type_fail, /* (0x0e) */ - xcoff_reloc_type_noop, /* R_REF (0x0f) */ - xcoff_reloc_type_fail, /* (0x10) */ - xcoff_reloc_type_fail, /* (0x11) */ - xcoff_reloc_type_toc, /* R_TRL (0x12) */ - xcoff_reloc_type_toc, /* R_TRLA (0x13) */ - xcoff_reloc_type_fail, /* R_RRTBI (0x14) */ - xcoff_reloc_type_fail, /* R_RRTBA (0x15) */ - xcoff_reloc_type_ba, /* R_CAI (0x16) */ - xcoff_reloc_type_crel, /* R_CREL (0x17) */ - xcoff_reloc_type_ba, /* R_RBA (0x18) */ - xcoff_reloc_type_ba, /* R_RBAC (0x19) */ - xcoff_reloc_type_br, /* R_RBR (0x1a) */ - xcoff_reloc_type_ba, /* R_RBRC (0x1b) */ -}; - -bfd_boolean (*xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW]) - (XCOFF_COMPLAIN_FUNCTION_ARGS) = -{ - xcoff_complain_overflow_dont_func, - xcoff_complain_overflow_bitfield_func, - xcoff_complain_overflow_signed_func, - xcoff_complain_overflow_unsigned_func, -}; - -/* Information about one member of an archive. */ -struct member_layout -{ - /* The archive member that this structure describes. */ - bfd *member; - - /* The number of bytes of padding that must be inserted before the - start of the member in order to ensure that the section contents - are correctly aligned. */ - unsigned int leading_padding; - - /* The offset of MEMBER from the start of the archive (i.e. the end - of the leading padding). */ - file_ptr offset; - - /* The normalized name of MEMBER. */ - const char *name; - - /* The length of NAME, without padding. */ - bfd_size_type namlen; - - /* The length of NAME, with padding. */ - bfd_size_type padded_namlen; - - /* The size of MEMBER's header, including the name and magic sequence. */ - bfd_size_type header_size; - - /* The size of the MEMBER's contents. */ - bfd_size_type contents_size; - - /* The number of bytes of padding that must be inserted after MEMBER - in order to preserve even alignment. */ - bfd_size_type trailing_padding; -}; - -/* A structure used for iterating over the members of an archive. */ -struct archive_iterator -{ - /* The archive itself. */ - bfd *archive; - - /* Information about the current archive member. */ - struct member_layout current; - - /* Information about the next archive member. MEMBER is null if there - are no more archive members, in which case OFFSET is the offset of - the first unused byte. */ - struct member_layout next; -}; - -/* Initialize INFO so that it describes member MEMBER of archive ARCHIVE. - OFFSET is the even-padded offset of MEMBER, not including any leading - padding needed for section alignment. */ - -static void -member_layout_init (struct member_layout *info, bfd *archive, - bfd *member, file_ptr offset) -{ - info->member = member; - info->leading_padding = 0; - if (member) - { - info->name = normalize_filename (member); - info->namlen = strlen (info->name); - info->padded_namlen = info->namlen + (info->namlen & 1); - if (xcoff_big_format_p (archive)) - info->header_size = SIZEOF_AR_HDR_BIG; - else - info->header_size = SIZEOF_AR_HDR; - info->header_size += info->padded_namlen + SXCOFFARFMAG; - info->contents_size = arelt_size (member); - info->trailing_padding = info->contents_size & 1; - - if (bfd_check_format (member, bfd_object) - && bfd_get_flavour (member) == bfd_target_xcoff_flavour - && (member->flags & DYNAMIC) != 0) - info->leading_padding - = (-(offset + info->header_size) - & ((1 << bfd_xcoff_text_align_power (member)) - 1)); - } - info->offset = offset + info->leading_padding; -} - -/* Set up ITERATOR to iterate through archive ARCHIVE. */ - -static void -archive_iterator_begin (struct archive_iterator *iterator, - bfd *archive) -{ - iterator->archive = archive; - member_layout_init (&iterator->next, archive, archive->archive_head, - xcoff_big_format_p (archive) - ? SIZEOF_AR_FILE_HDR_BIG - : SIZEOF_AR_FILE_HDR); -} - -/* Make ITERATOR visit the first unvisited archive member. Return true - on success; return false if all members have been visited. */ - -static bfd_boolean -archive_iterator_next (struct archive_iterator *iterator) -{ - if (!iterator->next.member) - return FALSE; - - iterator->current = iterator->next; - member_layout_init (&iterator->next, iterator->archive, - iterator->current.member->archive_next, - iterator->current.offset - + iterator->current.header_size - + iterator->current.contents_size - + iterator->current.trailing_padding); - return TRUE; -} - -/* We use our own tdata type. Its first field is the COFF tdata type, - so the COFF routines are compatible. */ - -bfd_boolean -_bfd_xcoff_mkobject (bfd *abfd) -{ - coff_data_type *coff; - bfd_size_type amt = sizeof (struct xcoff_tdata); - - abfd->tdata.xcoff_obj_data = (struct xcoff_tdata *) bfd_zalloc (abfd, amt); - if (abfd->tdata.xcoff_obj_data == NULL) - return FALSE; - coff = coff_data (abfd); - coff->symbols = (coff_symbol_type *) NULL; - coff->conversion_table = (unsigned int *) NULL; - coff->raw_syments = (struct coff_ptr_struct *) NULL; - coff->relocbase = 0; - - xcoff_data (abfd)->modtype = ('1' << 8) | 'L'; - - /* We set cputype to -1 to indicate that it has not been - initialized. */ - xcoff_data (abfd)->cputype = -1; - - xcoff_data (abfd)->csects = NULL; - xcoff_data (abfd)->debug_indices = NULL; - - /* text section alignment is different than the default */ - bfd_xcoff_text_align_power (abfd) = 2; - - return TRUE; -} - -/* Copy XCOFF data from one BFD to another. */ - -bfd_boolean -_bfd_xcoff_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - struct xcoff_tdata *ix, *ox; - asection *sec; - - if (ibfd->xvec != obfd->xvec) - return TRUE; - ix = xcoff_data (ibfd); - ox = xcoff_data (obfd); - ox->full_aouthdr = ix->full_aouthdr; - ox->toc = ix->toc; - if (ix->sntoc == 0) - ox->sntoc = 0; - else - { - sec = coff_section_from_bfd_index (ibfd, ix->sntoc); - if (sec == NULL) - ox->sntoc = 0; - else - ox->sntoc = sec->output_section->target_index; - } - if (ix->snentry == 0) - ox->snentry = 0; - else - { - sec = coff_section_from_bfd_index (ibfd, ix->snentry); - if (sec == NULL) - ox->snentry = 0; - else - ox->snentry = sec->output_section->target_index; - } - bfd_xcoff_text_align_power (obfd) = bfd_xcoff_text_align_power (ibfd); - bfd_xcoff_data_align_power (obfd) = bfd_xcoff_data_align_power (ibfd); - ox->modtype = ix->modtype; - ox->cputype = ix->cputype; - ox->maxdata = ix->maxdata; - ox->maxstack = ix->maxstack; - return TRUE; -} - -/* I don't think XCOFF really has a notion of local labels based on - name. This will mean that ld -X doesn't actually strip anything. - The AIX native linker does not have a -X option, and it ignores the - -x option. */ - -bfd_boolean -_bfd_xcoff_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED) -{ - return FALSE; -} - -void -_bfd_xcoff_swap_sym_in (bfd *abfd, void * ext1, void * in1) -{ - SYMENT *ext = (SYMENT *)ext1; - struct internal_syment * in = (struct internal_syment *)in1; - - if (ext->e.e_name[0] != 0) - { - memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN); - } - else - { - in->_n._n_n._n_zeroes = 0; - in->_n._n_n._n_offset = H_GET_32 (abfd, ext->e.e.e_offset); - } - - in->n_value = H_GET_32 (abfd, ext->e_value); - in->n_scnum = (short) H_GET_16 (abfd, ext->e_scnum); - in->n_type = H_GET_16 (abfd, ext->e_type); - in->n_sclass = H_GET_8 (abfd, ext->e_sclass); - in->n_numaux = H_GET_8 (abfd, ext->e_numaux); -} - -unsigned int -_bfd_xcoff_swap_sym_out (bfd *abfd, void * inp, void * extp) -{ - struct internal_syment *in = (struct internal_syment *)inp; - SYMENT *ext =(SYMENT *)extp; - - if (in->_n._n_name[0] != 0) - { - memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN); - } - else - { - H_PUT_32 (abfd, 0, ext->e.e.e_zeroes); - H_PUT_32 (abfd, in->_n._n_n._n_offset, ext->e.e.e_offset); - } - - H_PUT_32 (abfd, in->n_value, ext->e_value); - H_PUT_16 (abfd, in->n_scnum, ext->e_scnum); - H_PUT_16 (abfd, in->n_type, ext->e_type); - H_PUT_8 (abfd, in->n_sclass, ext->e_sclass); - H_PUT_8 (abfd, in->n_numaux, ext->e_numaux); - return bfd_coff_symesz (abfd); -} - -void -_bfd_xcoff_swap_aux_in (bfd *abfd, void * ext1, int type, int in_class, - int indx, int numaux, void * in1) -{ - AUXENT * ext = (AUXENT *)ext1; - union internal_auxent *in = (union internal_auxent *)in1; - - switch (in_class) - { - case C_FILE: - if (ext->x_file.x_n.x_fname[0] == 0) - { - in->x_file.x_n.x_zeroes = 0; - in->x_file.x_n.x_offset = - H_GET_32 (abfd, ext->x_file.x_n.x_n.x_offset); - } - else - { - if (numaux > 1) - { - if (indx == 0) - memcpy (in->x_file.x_fname, ext->x_file.x_n.x_fname, - numaux * sizeof (AUXENT)); - } - else - { - memcpy (in->x_file.x_fname, ext->x_file.x_n.x_fname, FILNMLEN); - } - } - goto end; - - /* RS/6000 "csect" auxents */ - case C_EXT: - case C_AIX_WEAKEXT: - case C_HIDEXT: - if (indx + 1 == numaux) - { - in->x_csect.x_scnlen.l = H_GET_32 (abfd, ext->x_csect.x_scnlen); - in->x_csect.x_parmhash = H_GET_32 (abfd, ext->x_csect.x_parmhash); - in->x_csect.x_snhash = H_GET_16 (abfd, ext->x_csect.x_snhash); - /* We don't have to hack bitfields in x_smtyp because it's - defined by shifts-and-ands, which are equivalent on all - byte orders. */ - in->x_csect.x_smtyp = H_GET_8 (abfd, ext->x_csect.x_smtyp); - in->x_csect.x_smclas = H_GET_8 (abfd, ext->x_csect.x_smclas); - in->x_csect.x_stab = H_GET_32 (abfd, ext->x_csect.x_stab); - in->x_csect.x_snstab = H_GET_16 (abfd, ext->x_csect.x_snstab); - goto end; - } - break; - - case C_STAT: - case C_LEAFSTAT: - case C_HIDDEN: - if (type == T_NULL) - { - in->x_scn.x_scnlen = H_GET_32 (abfd, ext->x_scn.x_scnlen); - in->x_scn.x_nreloc = H_GET_16 (abfd, ext->x_scn.x_nreloc); - in->x_scn.x_nlinno = H_GET_16 (abfd, ext->x_scn.x_nlinno); - /* PE defines some extra fields; we zero them out for - safety. */ - in->x_scn.x_checksum = 0; - in->x_scn.x_associated = 0; - in->x_scn.x_comdat = 0; - - goto end; - } - break; - } - - in->x_sym.x_tagndx.l = H_GET_32 (abfd, ext->x_sym.x_tagndx); - in->x_sym.x_tvndx = H_GET_16 (abfd, ext->x_sym.x_tvndx); - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - in->x_sym.x_fcnary.x_fcn.x_lnnoptr = - H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr); - in->x_sym.x_fcnary.x_fcn.x_endndx.l = - H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_endndx); - } - else - { - in->x_sym.x_fcnary.x_ary.x_dimen[0] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[0]); - in->x_sym.x_fcnary.x_ary.x_dimen[1] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[1]); - in->x_sym.x_fcnary.x_ary.x_dimen[2] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[2]); - in->x_sym.x_fcnary.x_ary.x_dimen[3] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[3]); - } - - if (ISFCN (type)) - { - in->x_sym.x_misc.x_fsize = H_GET_32 (abfd, ext->x_sym.x_misc.x_fsize); - } - else - { - in->x_sym.x_misc.x_lnsz.x_lnno = - H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_lnno); - in->x_sym.x_misc.x_lnsz.x_size = - H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_size); - } - - end: ; - /* The semicolon is because MSVC doesn't like labels at - end of block. */ -} - -unsigned int -_bfd_xcoff_swap_aux_out (bfd *abfd, void * inp, int type, int in_class, - int indx ATTRIBUTE_UNUSED, - int numaux ATTRIBUTE_UNUSED, - void * extp) -{ - union internal_auxent *in = (union internal_auxent *)inp; - AUXENT *ext = (AUXENT *)extp; - - memset (ext, 0, bfd_coff_auxesz (abfd)); - switch (in_class) - { - case C_FILE: - if (in->x_file.x_fname[0] == 0) - { - H_PUT_32 (abfd, 0, ext->x_file.x_n.x_n.x_zeroes); - H_PUT_32 (abfd, in->x_file.x_n.x_offset, - ext->x_file.x_n.x_n.x_offset); - } - else - { - memcpy (ext->x_file.x_n.x_fname, in->x_file.x_fname, FILNMLEN); - } - goto end; - - /* RS/6000 "csect" auxents */ - case C_EXT: - case C_AIX_WEAKEXT: - case C_HIDEXT: - if (indx + 1 == numaux) - { - H_PUT_32 (abfd, in->x_csect.x_scnlen.l, ext->x_csect.x_scnlen); - H_PUT_32 (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash); - H_PUT_16 (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash); - /* We don't have to hack bitfields in x_smtyp because it's - defined by shifts-and-ands, which are equivalent on all - byte orders. */ - H_PUT_8 (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp); - H_PUT_8 (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas); - H_PUT_32 (abfd, in->x_csect.x_stab, ext->x_csect.x_stab); - H_PUT_16 (abfd, in->x_csect.x_snstab, ext->x_csect.x_snstab); - goto end; - } - break; - - case C_STAT: - case C_LEAFSTAT: - case C_HIDDEN: - if (type == T_NULL) - { - H_PUT_32 (abfd, in->x_scn.x_scnlen, ext->x_scn.x_scnlen); - H_PUT_16 (abfd, in->x_scn.x_nreloc, ext->x_scn.x_nreloc); - H_PUT_16 (abfd, in->x_scn.x_nlinno, ext->x_scn.x_nlinno); - goto end; - } - break; - } - - H_PUT_32 (abfd, in->x_sym.x_tagndx.l, ext->x_sym.x_tagndx); - H_PUT_16 (abfd, in->x_sym.x_tvndx, ext->x_sym.x_tvndx); - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, - ext->x_sym.x_fcnary.x_fcn.x_lnnoptr); - H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, - ext->x_sym.x_fcnary.x_fcn.x_endndx); - } - else - { - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], - ext->x_sym.x_fcnary.x_ary.x_dimen[0]); - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], - ext->x_sym.x_fcnary.x_ary.x_dimen[1]); - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], - ext->x_sym.x_fcnary.x_ary.x_dimen[2]); - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], - ext->x_sym.x_fcnary.x_ary.x_dimen[3]); - } - - if (ISFCN (type)) - H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, ext->x_sym.x_misc.x_fsize); - else - { - H_PUT_16 (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, - ext->x_sym.x_misc.x_lnsz.x_lnno); - H_PUT_16 (abfd, in->x_sym.x_misc.x_lnsz.x_size, - ext->x_sym.x_misc.x_lnsz.x_size); - } - -end: - return bfd_coff_auxesz (abfd); -} - -/* The XCOFF reloc table. Actually, XCOFF relocations specify the - bitsize and whether they are signed or not, along with a - conventional type. This table is for the types, which are used for - different algorithms for putting in the reloc. Many of these - relocs need special_function entries, which I have not written. */ - -reloc_howto_type xcoff_howto_table[] = -{ - /* 0x00: Standard 32 bit relocation. */ - HOWTO (R_POS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_POS", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x01: 32 bit relocation, but store negative value. */ - HOWTO (R_NEG, /* type */ - 0, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_NEG", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x02: 32 bit PC relative relocation. */ - HOWTO (R_REL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_REL", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x03: 16 bit TOC relative relocation. */ - HOWTO (R_TOC, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TOC", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x04: I don't really know what this is. */ - HOWTO (R_RTB, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RTB", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x05: External TOC relative symbol. */ - HOWTO (R_GL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_GL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x06: Local TOC relative symbol. */ - HOWTO (R_TCL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TCL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (7), - - /* 0x08: Non modifiable absolute branch. */ - HOWTO (R_BA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_BA_26", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (9), - - /* 0x0a: Non modifiable relative branch. */ - HOWTO (R_BR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_BR", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0xb), - - /* 0x0c: Indirect load. */ - HOWTO (R_RL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x0d: Load address. */ - HOWTO (R_RLA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RLA", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0xe), - - /* 0x0f: Non-relocating reference. Bitsize is 1 so that r_rsize is 0. */ - HOWTO (R_REF, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 1, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "R_REF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0x10), - EMPTY_HOWTO (0x11), - - /* 0x12: TOC relative indirect load. */ - HOWTO (R_TRL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TRL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x13: TOC relative load address. */ - HOWTO (R_TRLA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TRLA", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x14: Modifiable relative branch. */ - HOWTO (R_RRTBI, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RRTBI", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x15: Modifiable absolute branch. */ - HOWTO (R_RRTBA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RRTBA", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x16: Modifiable call absolute indirect. */ - HOWTO (R_CAI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_CAI", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x17: Modifiable call relative. */ - HOWTO (R_CREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_CREL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x18: Modifiable branch absolute. */ - HOWTO (R_RBA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBA", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x19: Modifiable branch absolute. */ - HOWTO (R_RBAC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBAC", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1a: Modifiable branch relative. */ - HOWTO (R_RBR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBR_26", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1b: Modifiable branch absolute. */ - HOWTO (R_RBRC, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBRC", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1c: 16 bit Non modifiable absolute branch. */ - HOWTO (R_BA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_BA_16", /* name */ - TRUE, /* partial_inplace */ - 0xfffc, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1d: Modifiable branch relative. */ - HOWTO (R_RBR, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBR_16", /* name */ - TRUE, /* partial_inplace */ - 0xfffc, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1e: Modifiable branch relative. */ - HOWTO (R_RBA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBA_16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -void -xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal) -{ - if (internal->r_type > R_RBRC) - abort (); - - /* Default howto layout works most of the time */ - relent->howto = &xcoff_howto_table[internal->r_type]; - - /* Special case some 16 bit reloc */ - if (15 == (internal->r_size & 0x1f)) - { - if (R_BA == internal->r_type) - relent->howto = &xcoff_howto_table[0x1c]; - else if (R_RBR == internal->r_type) - relent->howto = &xcoff_howto_table[0x1d]; - else if (R_RBA == internal->r_type) - relent->howto = &xcoff_howto_table[0x1e]; - } - - /* The r_size field of an XCOFF reloc encodes the bitsize of the - relocation, as well as indicating whether it is signed or not. - Doublecheck that the relocation information gathered from the - type matches this information. The bitsize is not significant - for R_REF relocs. */ - if (relent->howto->dst_mask != 0 - && (relent->howto->bitsize - != ((unsigned int) internal->r_size & 0x1f) + 1)) - abort (); -} - -reloc_howto_type * -_bfd_xcoff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_PPC_B26: - return &xcoff_howto_table[0xa]; - case BFD_RELOC_PPC_BA16: - return &xcoff_howto_table[0x1c]; - case BFD_RELOC_PPC_BA26: - return &xcoff_howto_table[8]; - case BFD_RELOC_PPC_TOC16: - return &xcoff_howto_table[3]; - case BFD_RELOC_16: - /* Note that this relocation is only internally used by gas. */ - return &xcoff_howto_table[0xc]; - case BFD_RELOC_PPC_B16: - return &xcoff_howto_table[0x1d]; - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - return &xcoff_howto_table[0]; - case BFD_RELOC_NONE: - return &xcoff_howto_table[0xf]; - default: - return NULL; - } -} - -static reloc_howto_type * -_bfd_xcoff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (xcoff_howto_table) / sizeof (xcoff_howto_table[0]); - i++) - if (xcoff_howto_table[i].name != NULL - && strcasecmp (xcoff_howto_table[i].name, r_name) == 0) - return &xcoff_howto_table[i]; - - return NULL; -} - -/* XCOFF archive support. The original version of this code was by - Damon A. Permezel. It was enhanced to permit cross support, and - writing archive files, by Ian Lance Taylor, Cygnus Support. - - XCOFF uses its own archive format. Everything is hooked together - with file offset links, so it is possible to rapidly update an - archive in place. Of course, we don't do that. An XCOFF archive - has a real file header, not just an ARMAG string. The structure of - the file header and of each archive header appear below. - - An XCOFF archive also has a member table, which is a list of - elements in the archive (you can get that by looking through the - linked list, but you have to read a lot more of the file). The - member table has a normal archive header with an empty name. It is - normally (and perhaps must be) the second to last entry in the - archive. The member table data is almost printable ASCII. It - starts with a 12 character decimal string which is the number of - entries in the table. For each entry it has a 12 character decimal - string which is the offset in the archive of that member. These - entries are followed by a series of null terminated strings which - are the member names for each entry. - - Finally, an XCOFF archive has a global symbol table, which is what - we call the armap. The global symbol table has a normal archive - header with an empty name. It is normally (and perhaps must be) - the last entry in the archive. The contents start with a four byte - binary number which is the number of entries. This is followed by - a that many four byte binary numbers; each is the file offset of an - entry in the archive. These numbers are followed by a series of - null terminated strings, which are symbol names. - - AIX 4.3 introduced a new archive format which can handle larger - files and also 32- and 64-bit objects in the same archive. The - things said above remain true except that there is now more than - one global symbol table. The one is used to index 32-bit objects, - the other for 64-bit objects. - - The new archives (recognizable by the new ARMAG string) has larger - field lengths so that we cannot really share any code. Also we have - to take care that we are not generating the new form of archives - on AIX 4.2 or earlier systems. */ - -/* XCOFF archives use this as a magic string. Note that both strings - have the same length. */ - -/* Set the magic for archive. */ - -bfd_boolean -bfd_xcoff_ar_archive_set_magic (bfd *abfd ATTRIBUTE_UNUSED, - char *magic ATTRIBUTE_UNUSED) -{ - /* Not supported yet. */ - return FALSE; - /* bfd_xcoff_archive_set_magic (abfd, magic); */ -} - -/* PR 21786: The PE/COFF standard does not require NUL termination for any of - the ASCII fields in the archive headers. So in order to be able to extract - numerical values we provide our own versions of strtol and strtoll which - take a maximum length as an additional parameter. Also - just to save space, - we omit the endptr return parameter, since we know that it is never used. */ - -static long -_bfd_strntol (const char * nptr, int base, unsigned int maxlen) -{ - char buf[24]; /* Should be enough. */ - - BFD_ASSERT (maxlen < (sizeof (buf) - 1)); - - memcpy (buf, nptr, maxlen); - buf[maxlen] = 0; - return strtol (buf, NULL, base); -} - -static long long -_bfd_strntoll (const char * nptr, int base, unsigned int maxlen) -{ - char buf[32]; /* Should be enough. */ - - BFD_ASSERT (maxlen < (sizeof (buf) - 1)); - - memcpy (buf, nptr, maxlen); - buf[maxlen] = 0; - return strtoll (buf, NULL, base); -} - -/* Macro to read an ASCII value stored in an archive header field. */ -#define GET_VALUE_IN_FIELD(VAR, FIELD) \ - do \ - { \ - (VAR) = sizeof (VAR) > sizeof (long) \ - ? _bfd_strntoll (FIELD, 10, sizeof FIELD) \ - : _bfd_strntol (FIELD, 10, sizeof FIELD); \ - } \ - while (0) - -#define EQ_VALUE_IN_FIELD(VAR, FIELD) \ - (sizeof (VAR) > sizeof (long) \ - ? (VAR) ==_bfd_strntoll (FIELD, 10, sizeof FIELD) \ - : (VAR) == _bfd_strntol (FIELD, 10, sizeof FIELD)) - -/* Read in the armap of an XCOFF archive. */ - -bfd_boolean -_bfd_xcoff_slurp_armap (bfd *abfd) -{ - file_ptr off; - size_t namlen; - bfd_size_type sz; - bfd_byte *contents, *cend; - bfd_vma c, i; - carsym *arsym; - bfd_byte *p; - - if (xcoff_ardata (abfd) == NULL) - { - bfd_has_map (abfd) = FALSE; - return TRUE; - } - - if (! xcoff_big_format_p (abfd)) - { - /* This is for the old format. */ - struct xcoff_ar_hdr hdr; - - GET_VALUE_IN_FIELD (off, xcoff_ardata (abfd)->symoff); - if (off == 0) - { - bfd_has_map (abfd) = FALSE; - return TRUE; - } - - if (bfd_seek (abfd, off, SEEK_SET) != 0) - return FALSE; - - /* The symbol table starts with a normal archive header. */ - if (bfd_bread (&hdr, (bfd_size_type) SIZEOF_AR_HDR, abfd) - != SIZEOF_AR_HDR) - return FALSE; - - /* Skip the name (normally empty). */ - GET_VALUE_IN_FIELD (namlen, hdr.namlen); - off = ((namlen + 1) & ~ (size_t) 1) + SXCOFFARFMAG; - if (bfd_seek (abfd, off, SEEK_CUR) != 0) - return FALSE; - - GET_VALUE_IN_FIELD (sz, hdr.size); - - /* Read in the entire symbol table. */ - contents = (bfd_byte *) bfd_alloc (abfd, sz); - if (contents == NULL) - return FALSE; - if (bfd_bread (contents, sz, abfd) != sz) - return FALSE; - - /* The symbol table starts with a four byte count. */ - c = H_GET_32 (abfd, contents); - - if (c * 4 >= sz) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - bfd_ardata (abfd)->symdefs = - ((carsym *) bfd_alloc (abfd, c * sizeof (carsym))); - if (bfd_ardata (abfd)->symdefs == NULL) - return FALSE; - - /* After the count comes a list of four byte file offsets. */ - for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 4; - i < c; - ++i, ++arsym, p += 4) - arsym->file_offset = H_GET_32 (abfd, p); - } - else - { - /* This is for the new format. */ - struct xcoff_ar_hdr_big hdr; - - GET_VALUE_IN_FIELD (off, xcoff_ardata_big (abfd)->symoff); - if (off == 0) - { - bfd_has_map (abfd) = FALSE; - return TRUE; - } - - if (bfd_seek (abfd, off, SEEK_SET) != 0) - return FALSE; - - /* The symbol table starts with a normal archive header. */ - if (bfd_bread (&hdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd) - != SIZEOF_AR_HDR_BIG) - return FALSE; - - /* Skip the name (normally empty). */ - GET_VALUE_IN_FIELD (namlen, hdr.namlen); - off = ((namlen + 1) & ~ (size_t) 1) + SXCOFFARFMAG; - if (bfd_seek (abfd, off, SEEK_CUR) != 0) - return FALSE; - - GET_VALUE_IN_FIELD (sz, hdr.size); - - /* Read in the entire symbol table. */ - contents = (bfd_byte *) bfd_alloc (abfd, sz); - if (contents == NULL) - return FALSE; - if (bfd_bread (contents, sz, abfd) != sz) - return FALSE; - - /* The symbol table starts with an eight byte count. */ - c = H_GET_64 (abfd, contents); - - if (c * 8 >= sz) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - bfd_ardata (abfd)->symdefs = - ((carsym *) bfd_alloc (abfd, c * sizeof (carsym))); - if (bfd_ardata (abfd)->symdefs == NULL) - return FALSE; - - /* After the count comes a list of eight byte file offsets. */ - for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 8; - i < c; - ++i, ++arsym, p += 8) - arsym->file_offset = H_GET_64 (abfd, p); - } - - /* After the file offsets come null terminated symbol names. */ - cend = contents + sz; - for (i = 0, arsym = bfd_ardata (abfd)->symdefs; - i < c; - ++i, ++arsym, p += strlen ((char *) p) + 1) - { - if (p >= cend) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - arsym->name = (char *) p; - } - - bfd_ardata (abfd)->symdef_count = c; - bfd_has_map (abfd) = TRUE; - - return TRUE; -} - -/* See if this is an XCOFF archive. */ - -const bfd_target * -_bfd_xcoff_archive_p (bfd *abfd) -{ - struct artdata *tdata_hold; - char magic[SXCOFFARMAG]; - bfd_size_type amt = SXCOFFARMAG; - - if (bfd_bread (magic, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - if (strncmp (magic, XCOFFARMAG, SXCOFFARMAG) != 0 - && strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - tdata_hold = bfd_ardata (abfd); - - amt = sizeof (struct artdata); - bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt); - if (bfd_ardata (abfd) == (struct artdata *) NULL) - goto error_ret_restore; - - /* 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; */ - - /* Now handle the two formats. */ - if (magic[1] != 'b') - { - /* This is the old format. */ - struct xcoff_ar_file_hdr hdr; - - /* Copy over the magic string. */ - memcpy (hdr.magic, magic, SXCOFFARMAG); - - /* Now read the rest of the file header. */ - amt = SIZEOF_AR_FILE_HDR - SXCOFFARMAG; - if (bfd_bread (&hdr.memoff, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - goto error_ret; - } - - GET_VALUE_IN_FIELD (bfd_ardata (abfd)->first_file_filepos, - hdr.firstmemoff); - - amt = SIZEOF_AR_FILE_HDR; - bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt); - if (bfd_ardata (abfd)->tdata == NULL) - goto error_ret; - - memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR); - } - else - { - /* This is the new format. */ - struct xcoff_ar_file_hdr_big hdr; - - /* Copy over the magic string. */ - memcpy (hdr.magic, magic, SXCOFFARMAG); - - /* Now read the rest of the file header. */ - amt = SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG; - if (bfd_bread (&hdr.memoff, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - goto error_ret; - } - - bfd_ardata (abfd)->first_file_filepos = bfd_scan_vma (hdr.firstmemoff, - (const char **) 0, - 10); - - amt = SIZEOF_AR_FILE_HDR_BIG; - bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt); - if (bfd_ardata (abfd)->tdata == NULL) - goto error_ret; - - memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG); - } - - if (! _bfd_xcoff_slurp_armap (abfd)) - { - error_ret: - bfd_release (abfd, bfd_ardata (abfd)); - error_ret_restore: - bfd_ardata (abfd) = tdata_hold; - return NULL; - } - - return abfd->xvec; -} - -/* Read the archive header in an XCOFF archive. */ - -void * -_bfd_xcoff_read_ar_hdr (bfd *abfd) -{ - bfd_size_type namlen; - struct areltdata *ret; - bfd_size_type amt = sizeof (struct areltdata); - - ret = (struct areltdata *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (! xcoff_big_format_p (abfd)) - { - struct xcoff_ar_hdr hdr; - struct xcoff_ar_hdr *hdrp; - - if (bfd_bread (&hdr, (bfd_size_type) SIZEOF_AR_HDR, abfd) - != SIZEOF_AR_HDR) - { - free (ret); - return NULL; - } - - GET_VALUE_IN_FIELD (namlen, hdr.namlen); - amt = SIZEOF_AR_HDR + namlen + 1; - hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd, amt); - if (hdrp == NULL) - { - free (ret); - return NULL; - } - memcpy (hdrp, &hdr, SIZEOF_AR_HDR); - if (bfd_bread ((char *) hdrp + SIZEOF_AR_HDR, namlen, abfd) != namlen) - { - free (ret); - return NULL; - } - ((char *) hdrp)[SIZEOF_AR_HDR + namlen] = '\0'; - - ret->arch_header = (char *) hdrp; - GET_VALUE_IN_FIELD (ret->parsed_size, hdr.size); - ret->filename = (char *) hdrp + SIZEOF_AR_HDR; - } - else - { - struct xcoff_ar_hdr_big hdr; - struct xcoff_ar_hdr_big *hdrp; - - if (bfd_bread (&hdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd) - != SIZEOF_AR_HDR_BIG) - { - free (ret); - return NULL; - } - - GET_VALUE_IN_FIELD (namlen, hdr.namlen); - amt = SIZEOF_AR_HDR_BIG + namlen + 1; - hdrp = (struct xcoff_ar_hdr_big *) bfd_alloc (abfd, amt); - if (hdrp == NULL) - { - free (ret); - return NULL; - } - memcpy (hdrp, &hdr, SIZEOF_AR_HDR_BIG); - if (bfd_bread ((char *) hdrp + SIZEOF_AR_HDR_BIG, namlen, abfd) != namlen) - { - free (ret); - return NULL; - } - ((char *) hdrp)[SIZEOF_AR_HDR_BIG + namlen] = '\0'; - - ret->arch_header = (char *) hdrp; - GET_VALUE_IN_FIELD (ret->parsed_size, hdr.size); - ret->filename = (char *) hdrp + SIZEOF_AR_HDR_BIG; - } - - /* Skip over the XCOFFARFMAG at the end of the file name. */ - if (bfd_seek (abfd, (file_ptr) ((namlen & 1) + SXCOFFARFMAG), SEEK_CUR) != 0) - return NULL; - - return ret; -} - -/* Open the next element in an XCOFF archive. */ - -bfd * -_bfd_xcoff_openr_next_archived_file (bfd *archive, bfd *last_file) -{ - file_ptr filestart; - - if (xcoff_ardata (archive) == NULL) - { - bfd_set_error (bfd_error_invalid_operation); - return NULL; - } - - if (! xcoff_big_format_p (archive)) - { - if (last_file == NULL) - filestart = bfd_ardata (archive)->first_file_filepos; - else - GET_VALUE_IN_FIELD (filestart, arch_xhdr (last_file)->nextoff); - - if (filestart == 0 - || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata (archive)->memoff) - || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata (archive)->symoff)) - { - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; - } - } - else - { - if (last_file == NULL) - filestart = bfd_ardata (archive)->first_file_filepos; - else - GET_VALUE_IN_FIELD (filestart, arch_xhdr_big (last_file)->nextoff); - - if (filestart == 0 - || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata_big (archive)->memoff) - || EQ_VALUE_IN_FIELD (filestart, xcoff_ardata_big (archive)->symoff)) - { - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; - } - } - - return _bfd_get_elt_at_filepos (archive, filestart); -} - -/* Stat an element in an XCOFF archive. */ - -int -_bfd_xcoff_stat_arch_elt (bfd *abfd, struct stat *s) -{ - if (abfd->arelt_data == NULL) - { - bfd_set_error (bfd_error_invalid_operation); - return -1; - } - - if (! xcoff_big_format_p (abfd->my_archive)) - { - struct xcoff_ar_hdr *hdrp = arch_xhdr (abfd); - - GET_VALUE_IN_FIELD (s->st_mtime, hdrp->date); - GET_VALUE_IN_FIELD (s->st_uid, hdrp->uid); - GET_VALUE_IN_FIELD (s->st_gid, hdrp->gid); - GET_VALUE_IN_FIELD (s->st_mode, hdrp->mode); - s->st_size = arch_eltdata (abfd)->parsed_size; - } - else - { - struct xcoff_ar_hdr_big *hdrp = arch_xhdr_big (abfd); - - GET_VALUE_IN_FIELD (s->st_mtime, hdrp->date); - GET_VALUE_IN_FIELD (s->st_uid, hdrp->uid); - GET_VALUE_IN_FIELD (s->st_gid, hdrp->gid); - GET_VALUE_IN_FIELD (s->st_mode, hdrp->mode); - s->st_size = arch_eltdata (abfd)->parsed_size; - } - - return 0; -} - -/* Normalize a file name for inclusion in an archive. */ - -static const char * -normalize_filename (bfd *abfd) -{ - const char *file; - const char *filename; - - file = bfd_get_filename (abfd); - filename = strrchr (file, '/'); - if (filename != NULL) - filename++; - else - filename = file; - return filename; -} - -/* Write out an XCOFF armap. */ - -static bfd_boolean -xcoff_write_armap_old (bfd *abfd, unsigned int elength ATTRIBUTE_UNUSED, - struct orl *map, unsigned int orl_count, int stridx) -{ - struct archive_iterator iterator; - struct xcoff_ar_hdr hdr; - char *p; - unsigned char buf[4]; - unsigned int i; - - memset (&hdr, 0, sizeof hdr); - sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx)); - sprintf (hdr.nextoff, "%d", 0); - memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, XCOFFARMAG_ELEMENT_SIZE); - sprintf (hdr.date, "%d", 0); - sprintf (hdr.uid, "%d", 0); - sprintf (hdr.gid, "%d", 0); - sprintf (hdr.mode, "%d", 0); - sprintf (hdr.namlen, "%d", 0); - - /* We need spaces, not null bytes, in the header. */ - for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR; p++) - if (*p == '\0') - *p = ' '; - - if (bfd_bwrite (&hdr, (bfd_size_type) SIZEOF_AR_HDR, abfd) - != SIZEOF_AR_HDR - || (bfd_bwrite (XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd) - != SXCOFFARFMAG)) - return FALSE; - - H_PUT_32 (abfd, orl_count, buf); - if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4) - return FALSE; - - i = 0; - archive_iterator_begin (&iterator, abfd); - while (i < orl_count && archive_iterator_next (&iterator)) - while (map[i].u.abfd == iterator.current.member) - { - H_PUT_32 (abfd, iterator.current.offset, buf); - if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4) - return FALSE; - ++i; - } - - for (i = 0; i < orl_count; i++) - { - const char *name; - size_t namlen; - - name = *map[i].name; - namlen = strlen (name); - if (bfd_bwrite (name, (bfd_size_type) (namlen + 1), abfd) != namlen + 1) - return FALSE; - } - - if ((stridx & 1) != 0) - { - char b; - - b = '\0'; - if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1) - return FALSE; - } - - return TRUE; -} - -static char buff20[XCOFFARMAGBIG_ELEMENT_SIZE + 1]; -#if BFD_HOST_64BIT_LONG -#define FMT20 "%-20ld" -#elif defined (__MSVCRT__) -#define FMT20 "%-20I64d" -#else -#define FMT20 "%-20lld" -#endif -#define FMT12 "%-12d" -#define FMT12_OCTAL "%-12o" -#define FMT4 "%-4d" -#define PRINT20(d, v) \ - sprintf (buff20, FMT20, (bfd_uint64_t)(v)), \ - memcpy ((void *) (d), buff20, 20) - -#define PRINT12(d, v) \ - sprintf (buff20, FMT12, (int)(v)), \ - memcpy ((void *) (d), buff20, 12) - -#define PRINT12_OCTAL(d, v) \ - sprintf (buff20, FMT12_OCTAL, (unsigned int)(v)), \ - memcpy ((void *) (d), buff20, 12) - -#define PRINT4(d, v) \ - sprintf (buff20, FMT4, (int)(v)), \ - memcpy ((void *) (d), buff20, 4) - -#define READ20(d, v) \ - buff20[20] = 0, \ - memcpy (buff20, (d), 20), \ - (v) = bfd_scan_vma (buff20, (const char **) NULL, 10) - -static bfd_boolean -do_pad (bfd *abfd, unsigned int number) -{ - bfd_byte b = 0; - - /* Limit pad to <= 4096. */ - if (number > 4096) - return FALSE; - - while (number--) - if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1) - return FALSE; - - return TRUE; -} - -static bfd_boolean -do_copy (bfd *out_bfd, bfd *in_bfd) -{ - bfd_size_type remaining; - bfd_byte buffer[DEFAULT_BUFFERSIZE]; - - if (bfd_seek (in_bfd, (file_ptr) 0, SEEK_SET) != 0) - return FALSE; - - remaining = arelt_size (in_bfd); - - while (remaining >= DEFAULT_BUFFERSIZE) - { - if (bfd_bread (buffer, DEFAULT_BUFFERSIZE, in_bfd) != DEFAULT_BUFFERSIZE - || bfd_bwrite (buffer, DEFAULT_BUFFERSIZE, out_bfd) != DEFAULT_BUFFERSIZE) - return FALSE; - - remaining -= DEFAULT_BUFFERSIZE; - } - - if (remaining) - { - if (bfd_bread (buffer, remaining, in_bfd) != remaining - || bfd_bwrite (buffer, remaining, out_bfd) != remaining) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -xcoff_write_armap_big (bfd *abfd, unsigned int elength ATTRIBUTE_UNUSED, - struct orl *map, unsigned int orl_count, int stridx) -{ - struct archive_iterator iterator; - struct xcoff_ar_file_hdr_big *fhdr; - bfd_vma i, sym_32, sym_64, str_32, str_64; - const bfd_arch_info_type *arch_info; - bfd *current_bfd; - size_t string_length; - file_ptr nextoff, prevoff; - - /* First, we look through the symbols and work out which are - from 32-bit objects and which from 64-bit ones. */ - sym_32 = sym_64 = str_32 = str_64 = 0; - - i = 0; - for (current_bfd = abfd->archive_head; - current_bfd != NULL && i < orl_count; - current_bfd = current_bfd->archive_next) - { - arch_info = bfd_get_arch_info (current_bfd); - while (map[i].u.abfd == current_bfd) - { - string_length = strlen (*map[i].name) + 1; - if (arch_info->bits_per_address == 64) - { - sym_64++; - str_64 += string_length; - } - else - { - sym_32++; - str_32 += string_length; - } - i++; - } - } - - /* A quick sanity check... */ - BFD_ASSERT (sym_64 + sym_32 == orl_count); - /* Explicit cast to int for compiler. */ - BFD_ASSERT ((int)(str_64 + str_32) == stridx); - - fhdr = xcoff_ardata_big (abfd); - - /* xcoff_write_archive_contents_big passes nextoff in symoff. */ - READ20 (fhdr->memoff, prevoff); - READ20 (fhdr->symoff, nextoff); - - BFD_ASSERT (nextoff == bfd_tell (abfd)); - - /* Write out the symbol table. - Layout : - - standard big archive header - 0x0000 ar_size [0x14] - 0x0014 ar_nxtmem [0x14] - 0x0028 ar_prvmem [0x14] - 0x003C ar_date [0x0C] - 0x0048 ar_uid [0x0C] - 0x0054 ar_gid [0x0C] - 0x0060 ar_mod [0x0C] - 0x006C ar_namelen[0x04] - 0x0070 ar_fmag [SXCOFFARFMAG] - - Symbol table - 0x0072 num_syms [0x08], binary - 0x0078 offsets [0x08 * num_syms], binary - 0x0086 + 0x08 * num_syms names [??] - ?? pad to even bytes. - */ - - if (sym_32) - { - struct xcoff_ar_hdr_big *hdr; - char *symbol_table; - char *st; - - bfd_vma symbol_table_size = - SIZEOF_AR_HDR_BIG - + SXCOFFARFMAG - + 8 - + 8 * sym_32 - + str_32 + (str_32 & 1); - - symbol_table = bfd_zmalloc (symbol_table_size); - if (symbol_table == NULL) - return FALSE; - - hdr = (struct xcoff_ar_hdr_big *) symbol_table; - - PRINT20 (hdr->size, 8 + 8 * sym_32 + str_32 + (str_32 & 1)); - - if (sym_64) - PRINT20 (hdr->nextoff, nextoff + symbol_table_size); - else - PRINT20 (hdr->nextoff, 0); - - PRINT20 (hdr->prevoff, prevoff); - PRINT12 (hdr->date, 0); - PRINT12 (hdr->uid, 0); - PRINT12 (hdr->gid, 0); - PRINT12 (hdr->mode, 0); - PRINT4 (hdr->namlen, 0) ; - - st = symbol_table + SIZEOF_AR_HDR_BIG; - memcpy (st, XCOFFARFMAG, SXCOFFARFMAG); - st += SXCOFFARFMAG; - - bfd_h_put_64 (abfd, sym_32, st); - st += 8; - - /* loop over the 32 bit offsets */ - i = 0; - archive_iterator_begin (&iterator, abfd); - while (i < orl_count && archive_iterator_next (&iterator)) - { - arch_info = bfd_get_arch_info (iterator.current.member); - while (map[i].u.abfd == iterator.current.member) - { - if (arch_info->bits_per_address == 32) - { - bfd_h_put_64 (abfd, iterator.current.offset, st); - st += 8; - } - i++; - } - } - - /* loop over the 32 bit symbol names */ - i = 0; - for (current_bfd = abfd->archive_head; - current_bfd != NULL && i < orl_count; - current_bfd = current_bfd->archive_next) - { - arch_info = bfd_get_arch_info (current_bfd); - while (map[i].u.abfd == current_bfd) - { - if (arch_info->bits_per_address == 32) - { - string_length = sprintf (st, "%s", *map[i].name); - st += string_length + 1; - } - i++; - } - } - - bfd_bwrite (symbol_table, symbol_table_size, abfd); - - free (symbol_table); - - prevoff = nextoff; - nextoff = nextoff + symbol_table_size; - } - else - PRINT20 (fhdr->symoff, 0); - - if (sym_64) - { - struct xcoff_ar_hdr_big *hdr; - char *symbol_table; - char *st; - - bfd_vma symbol_table_size = - SIZEOF_AR_HDR_BIG - + SXCOFFARFMAG - + 8 - + 8 * sym_64 - + str_64 + (str_64 & 1); - - symbol_table = bfd_zmalloc (symbol_table_size); - if (symbol_table == NULL) - return FALSE; - - hdr = (struct xcoff_ar_hdr_big *) symbol_table; - - PRINT20 (hdr->size, 8 + 8 * sym_64 + str_64 + (str_64 & 1)); - PRINT20 (hdr->nextoff, 0); - PRINT20 (hdr->prevoff, prevoff); - PRINT12 (hdr->date, 0); - PRINT12 (hdr->uid, 0); - PRINT12 (hdr->gid, 0); - PRINT12 (hdr->mode, 0); - PRINT4 (hdr->namlen, 0); - - st = symbol_table + SIZEOF_AR_HDR_BIG; - memcpy (st, XCOFFARFMAG, SXCOFFARFMAG); - st += SXCOFFARFMAG; - - bfd_h_put_64 (abfd, sym_64, st); - st += 8; - - /* loop over the 64 bit offsets */ - i = 0; - archive_iterator_begin (&iterator, abfd); - while (i < orl_count && archive_iterator_next (&iterator)) - { - arch_info = bfd_get_arch_info (iterator.current.member); - while (map[i].u.abfd == iterator.current.member) - { - if (arch_info->bits_per_address == 64) - { - bfd_h_put_64 (abfd, iterator.current.offset, st); - st += 8; - } - i++; - } - } - - /* loop over the 64 bit symbol names */ - i = 0; - for (current_bfd = abfd->archive_head; - current_bfd != NULL && i < orl_count; - current_bfd = current_bfd->archive_next) - { - arch_info = bfd_get_arch_info (current_bfd); - while (map[i].u.abfd == current_bfd) - { - if (arch_info->bits_per_address == 64) - { - string_length = sprintf (st, "%s", *map[i].name); - st += string_length + 1; - } - i++; - } - } - - bfd_bwrite (symbol_table, symbol_table_size, abfd); - - free (symbol_table); - - PRINT20 (fhdr->symoff64, nextoff); - } - else - PRINT20 (fhdr->symoff64, 0); - - return TRUE; -} - -bfd_boolean -_bfd_xcoff_write_armap (bfd *abfd, unsigned int elength ATTRIBUTE_UNUSED, - struct orl *map, unsigned int orl_count, int stridx) -{ - if (! xcoff_big_format_p (abfd)) - return xcoff_write_armap_old (abfd, elength, map, orl_count, stridx); - else - return xcoff_write_armap_big (abfd, elength, map, orl_count, stridx); -} - -/* Write out an XCOFF archive. We always write an entire archive, - rather than fussing with the freelist and so forth. */ - -static bfd_boolean -xcoff_write_archive_contents_old (bfd *abfd) -{ - struct archive_iterator iterator; - struct xcoff_ar_file_hdr fhdr; - bfd_size_type count; - bfd_size_type total_namlen; - file_ptr *offsets; - bfd_boolean makemap; - bfd_boolean hasobjects; - file_ptr prevoff, nextoff; - bfd *sub; - size_t i; - struct xcoff_ar_hdr ahdr; - bfd_size_type size; - char *p; - char decbuf[XCOFFARMAG_ELEMENT_SIZE + 1]; - - memset (&fhdr, 0, sizeof fhdr); - (void) strncpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG); - sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR); - sprintf (fhdr.freeoff, "%d", 0); - - count = 0; - total_namlen = 0; - for (sub = abfd->archive_head; sub != NULL; sub = sub->archive_next) - { - ++count; - total_namlen += strlen (normalize_filename (sub)) + 1; - if (sub->arelt_data == NULL) - { - sub->arelt_data = bfd_zmalloc (sizeof (struct areltdata)); - if (sub->arelt_data == NULL) - return FALSE; - } - if (arch_xhdr (sub) == NULL) - { - struct xcoff_ar_hdr *ahdrp; - struct stat s; - - if (stat (bfd_get_filename (sub), &s) != 0) - { - bfd_set_error (bfd_error_system_call); - return FALSE; - } - - ahdrp = bfd_zalloc (sub, sizeof (*ahdrp)); - if (ahdrp == NULL) - return FALSE; - - sprintf (ahdrp->size, "%ld", (long) s.st_size); - sprintf (ahdrp->date, "%ld", (long) s.st_mtime); - sprintf (ahdrp->uid, "%ld", (long) s.st_uid); - sprintf (ahdrp->gid, "%ld", (long) s.st_gid); - sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode); - - arch_eltdata (sub)->arch_header = (char *) ahdrp; - arch_eltdata (sub)->parsed_size = s.st_size; - } - } - offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr)); - if (offsets == NULL) - return FALSE; - - if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR, SEEK_SET) != 0) - return FALSE; - - makemap = bfd_has_map (abfd); - hasobjects = FALSE; - prevoff = 0; - for (archive_iterator_begin (&iterator, abfd), i = 0; - archive_iterator_next (&iterator); - i++) - { - bfd_size_type namlen; - struct xcoff_ar_hdr *ahdrp; - - if (makemap && ! hasobjects) - { - if (bfd_check_format (iterator.current.member, bfd_object)) - hasobjects = TRUE; - } - - ahdrp = arch_xhdr (iterator.current.member); - sprintf (ahdrp->prevoff, "%ld", (long) prevoff); - sprintf (ahdrp->namlen, "%ld", (long) iterator.current.namlen); - sprintf (ahdrp->nextoff, "%ld", (long) iterator.next.offset); - - /* We need spaces, not null bytes, in the header. */ - for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR; p++) - if (*p == '\0') - *p = ' '; - - if (!do_pad (abfd, iterator.current.leading_padding)) - return FALSE; - - BFD_ASSERT (iterator.current.offset == bfd_tell (abfd)); - namlen = iterator.current.padded_namlen; - if (bfd_bwrite (ahdrp, SIZEOF_AR_HDR, abfd) != SIZEOF_AR_HDR - || bfd_bwrite (iterator.current.name, namlen, abfd) != namlen - || bfd_bwrite (XCOFFARFMAG, SXCOFFARFMAG, abfd) != SXCOFFARFMAG - || bfd_seek (iterator.current.member, 0, SEEK_SET) != 0 - || !do_copy (abfd, iterator.current.member) - || !do_pad (abfd, iterator.current.trailing_padding)) - return FALSE; - - offsets[i] = iterator.current.offset; - prevoff = iterator.current.offset; - } - - sprintf (fhdr.lastmemoff, "%ld", (long) prevoff); - - /* Write out the member table. */ - - nextoff = iterator.next.offset; - BFD_ASSERT (nextoff == bfd_tell (abfd)); - sprintf (fhdr.memoff, "%ld", (long) nextoff); - - memset (&ahdr, 0, sizeof ahdr); - sprintf (ahdr.size, "%ld", (long) (XCOFFARMAG_ELEMENT_SIZE - + count * XCOFFARMAG_ELEMENT_SIZE - + total_namlen)); - sprintf (ahdr.prevoff, "%ld", (long) prevoff); - sprintf (ahdr.date, "%d", 0); - sprintf (ahdr.uid, "%d", 0); - sprintf (ahdr.gid, "%d", 0); - sprintf (ahdr.mode, "%d", 0); - sprintf (ahdr.namlen, "%d", 0); - - size = (SIZEOF_AR_HDR - + XCOFFARMAG_ELEMENT_SIZE - + count * XCOFFARMAG_ELEMENT_SIZE - + total_namlen - + SXCOFFARFMAG); - - prevoff = nextoff; - nextoff += size + (size & 1); - - if (makemap && hasobjects) - sprintf (ahdr.nextoff, "%ld", (long) nextoff); - else - sprintf (ahdr.nextoff, "%d", 0); - - /* We need spaces, not null bytes, in the header. */ - for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR; p++) - if (*p == '\0') - *p = ' '; - - if ((bfd_bwrite (&ahdr, (bfd_size_type) SIZEOF_AR_HDR, abfd) - != SIZEOF_AR_HDR) - || (bfd_bwrite (XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd) - != SXCOFFARFMAG)) - return FALSE; - - sprintf (decbuf, "%-12ld", (long) count); - if (bfd_bwrite (decbuf, (bfd_size_type) XCOFFARMAG_ELEMENT_SIZE, abfd) - != XCOFFARMAG_ELEMENT_SIZE) - return FALSE; - for (i = 0; i < (size_t) count; i++) - { - sprintf (decbuf, "%-12ld", (long) offsets[i]); - if (bfd_bwrite (decbuf, (bfd_size_type) XCOFFARMAG_ELEMENT_SIZE, - abfd) != XCOFFARMAG_ELEMENT_SIZE) - return FALSE; - } - for (sub = abfd->archive_head; sub != NULL; sub = sub->archive_next) - { - const char *name; - bfd_size_type namlen; - - name = normalize_filename (sub); - namlen = strlen (name); - if (bfd_bwrite (name, namlen + 1, abfd) != namlen + 1) - return FALSE; - } - - if (! do_pad (abfd, size & 1)) - return FALSE; - - /* Write out the armap, if appropriate. */ - if (! makemap || ! hasobjects) - sprintf (fhdr.symoff, "%d", 0); - else - { - BFD_ASSERT (nextoff == bfd_tell (abfd)); - sprintf (fhdr.symoff, "%ld", (long) nextoff); - bfd_ardata (abfd)->tdata = &fhdr; - if (! _bfd_compute_and_write_armap (abfd, 0)) - return FALSE; - } - - /* Write out the archive file header. */ - - /* We need spaces, not null bytes, in the header. */ - for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR; p++) - if (*p == '\0') - *p = ' '; - - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 - || (bfd_bwrite (&fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR, abfd) - != SIZEOF_AR_FILE_HDR)) - return FALSE; - - return TRUE; -} - -static bfd_boolean -xcoff_write_archive_contents_big (bfd *abfd) -{ - struct xcoff_ar_file_hdr_big fhdr; - bfd_size_type count; - bfd_size_type total_namlen; - file_ptr *offsets; - bfd_boolean makemap; - bfd_boolean hasobjects; - file_ptr prevoff, nextoff; - bfd *current_bfd; - size_t i; - struct xcoff_ar_hdr_big *hdr; - bfd_size_type size; - char *member_table, *mt; - bfd_vma member_table_size; - struct archive_iterator iterator; - - memset (&fhdr, 0, SIZEOF_AR_FILE_HDR_BIG); - memcpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG); - - if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0) - return FALSE; - - /* Calculate count and total_namlen. */ - makemap = bfd_has_map (abfd); - hasobjects = FALSE; - for (current_bfd = abfd->archive_head, count = 0, total_namlen = 0; - current_bfd != NULL; - current_bfd = current_bfd->archive_next, count++) - { - total_namlen += strlen (normalize_filename (current_bfd)) + 1; - - if (makemap - && ! hasobjects - && bfd_check_format (current_bfd, bfd_object)) - hasobjects = TRUE; - - if (current_bfd->arelt_data == NULL) - { - size = sizeof (struct areltdata); - current_bfd->arelt_data = bfd_zmalloc (size); - if (current_bfd->arelt_data == NULL) - return FALSE; - } - - if (arch_xhdr_big (current_bfd) == NULL) - { - struct xcoff_ar_hdr_big *ahdrp; - struct stat s; - - /* XXX This should actually be a call to stat64 (at least on - 32-bit machines). - XXX This call will fail if the original object is not found. */ - if (stat (bfd_get_filename (current_bfd), &s) != 0) - { - bfd_set_error (bfd_error_system_call); - return FALSE; - } - - ahdrp = bfd_zalloc (current_bfd, sizeof (*ahdrp)); - if (ahdrp == NULL) - return FALSE; - - PRINT20 (ahdrp->size, s.st_size); - PRINT12 (ahdrp->date, s.st_mtime); - PRINT12 (ahdrp->uid, s.st_uid); - PRINT12 (ahdrp->gid, s.st_gid); - PRINT12_OCTAL (ahdrp->mode, s.st_mode); - - arch_eltdata (current_bfd)->arch_header = (char *) ahdrp; - arch_eltdata (current_bfd)->parsed_size = s.st_size; - } - } - - offsets = NULL; - if (count) - { - offsets = (file_ptr *) bfd_malloc (count * sizeof (file_ptr)); - if (offsets == NULL) - return FALSE; - } - - prevoff = 0; - for (archive_iterator_begin (&iterator, abfd), i = 0; - archive_iterator_next (&iterator); - i++) - { - bfd_size_type namlen; - struct xcoff_ar_hdr_big *ahdrp; - - ahdrp = arch_xhdr_big (iterator.current.member); - PRINT20 (ahdrp->prevoff, prevoff); - PRINT4 (ahdrp->namlen, iterator.current.namlen); - PRINT20 (ahdrp->nextoff, iterator.next.offset); - - if (!do_pad (abfd, iterator.current.leading_padding)) - { - free (offsets); - return FALSE; - } - - BFD_ASSERT (iterator.current.offset == bfd_tell (abfd)); - namlen = iterator.current.padded_namlen; - if (bfd_bwrite (ahdrp, SIZEOF_AR_HDR_BIG, abfd) != SIZEOF_AR_HDR_BIG - || bfd_bwrite (iterator.current.name, namlen, abfd) != namlen - || bfd_bwrite (XCOFFARFMAG, SXCOFFARFMAG, abfd) != SXCOFFARFMAG - || bfd_seek (iterator.current.member, 0, SEEK_SET) != 0 - || !do_copy (abfd, iterator.current.member) - || !do_pad (abfd, iterator.current.trailing_padding)) - { - free (offsets); - return FALSE; - } - - offsets[i] = iterator.current.offset; - prevoff = iterator.current.offset; - } - - if (count) - { - PRINT20 (fhdr.firstmemoff, offsets[0]); - PRINT20 (fhdr.lastmemoff, prevoff); - } - - /* Write out the member table. - Layout : - - standard big archive header - 0x0000 ar_size [0x14] - 0x0014 ar_nxtmem [0x14] - 0x0028 ar_prvmem [0x14] - 0x003C ar_date [0x0C] - 0x0048 ar_uid [0x0C] - 0x0054 ar_gid [0x0C] - 0x0060 ar_mod [0x0C] - 0x006C ar_namelen[0x04] - 0x0070 ar_fmag [0x02] - - Member table - 0x0072 count [0x14] - 0x0086 offsets [0x14 * counts] - 0x0086 + 0x14 * counts names [??] - ?? pad to even bytes. - */ - - nextoff = iterator.next.offset; - BFD_ASSERT (nextoff == bfd_tell (abfd)); - - member_table_size = (SIZEOF_AR_HDR_BIG - + SXCOFFARFMAG - + XCOFFARMAGBIG_ELEMENT_SIZE - + count * XCOFFARMAGBIG_ELEMENT_SIZE - + total_namlen); - - member_table_size += member_table_size & 1; - member_table = bfd_zmalloc (member_table_size); - if (member_table == NULL) - { - free (offsets); - return FALSE; - } - - hdr = (struct xcoff_ar_hdr_big *) member_table; - - PRINT20 (hdr->size, (XCOFFARMAGBIG_ELEMENT_SIZE - + count * XCOFFARMAGBIG_ELEMENT_SIZE - + total_namlen + (total_namlen & 1))); - if (makemap && hasobjects) - PRINT20 (hdr->nextoff, nextoff + member_table_size); - else - PRINT20 (hdr->nextoff, 0); - PRINT20 (hdr->prevoff, prevoff); - PRINT12 (hdr->date, 0); - PRINT12 (hdr->uid, 0); - PRINT12 (hdr->gid, 0); - PRINT12 (hdr->mode, 0); - PRINT4 (hdr->namlen, 0); - - mt = member_table + SIZEOF_AR_HDR_BIG; - memcpy (mt, XCOFFARFMAG, SXCOFFARFMAG); - mt += SXCOFFARFMAG; - - PRINT20 (mt, count); - mt += XCOFFARMAGBIG_ELEMENT_SIZE; - for (i = 0; i < (size_t) count; i++) - { - PRINT20 (mt, offsets[i]); - mt += XCOFFARMAGBIG_ELEMENT_SIZE; - } - - if (count) - { - free (offsets); - offsets = NULL; - } - - for (current_bfd = abfd->archive_head; - current_bfd != NULL; - current_bfd = current_bfd->archive_next) - { - const char *name; - size_t namlen; - - name = normalize_filename (current_bfd); - namlen = sprintf (mt, "%s", name); - mt += namlen + 1; - } - - if (bfd_bwrite (member_table, member_table_size, abfd) != member_table_size) - return FALSE; - - free (member_table); - - PRINT20 (fhdr.memoff, nextoff); - - prevoff = nextoff; - nextoff += member_table_size; - - /* Write out the armap, if appropriate. */ - - if (! makemap || ! hasobjects) - PRINT20 (fhdr.symoff, 0); - else - { - BFD_ASSERT (nextoff == bfd_tell (abfd)); - - /* Save nextoff in fhdr.symoff so the armap routine can use it. */ - PRINT20 (fhdr.symoff, nextoff); - - bfd_ardata (abfd)->tdata = &fhdr; - if (! _bfd_compute_and_write_armap (abfd, 0)) - return FALSE; - } - - /* Write out the archive file header. */ - - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 - || (bfd_bwrite (&fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR_BIG, - abfd) != SIZEOF_AR_FILE_HDR_BIG)) - return FALSE; - - return TRUE; -} - -bfd_boolean -_bfd_xcoff_write_archive_contents (bfd *abfd) -{ - if (! xcoff_big_format_p (abfd)) - return xcoff_write_archive_contents_old (abfd); - else - return xcoff_write_archive_contents_big (abfd); -} - -/* We can't use the usual coff_sizeof_headers routine, because AIX - always uses an a.out header. */ - -int -_bfd_xcoff_sizeof_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - int size; - - size = FILHSZ; - if (xcoff_data (abfd)->full_aouthdr) - size += AOUTSZ; - else - size += SMALL_AOUTSZ; - size += abfd->section_count * SCNHSZ; - - if (info->strip != strip_all) - { - /* There can be additional sections just for dealing with overflow in - reloc and lineno counts. But the numbers of relocs and lineno aren't - known when bfd_sizeof_headers is called, so we compute them by - summing the numbers from input sections. */ - struct nbr_reloc_lineno - { - unsigned int reloc_count; - unsigned int lineno_count; - }; - struct nbr_reloc_lineno *n_rl; - bfd *sub; - unsigned int max_index; - asection *s; - - /* Although the number of sections is known, the maximum value of - section->index isn't (because some sections may have been removed). - Don't try to renumber sections, just compute the upper bound. */ - max_index = 0; - for (s = abfd->sections; s != NULL; s = s->next) - if (s->index > max_index) - max_index = s->index; - - /* Allocate the per section counters. It could be possible to use a - preallocated array as the number of sections is limited on XCOFF, - but this creates a maintainance issue. */ - n_rl = bfd_zmalloc ((max_index + 1) * sizeof (*n_rl)); - if (n_rl == NULL) - return -1; - - /* Sum. */ - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - for (s = sub->sections; s != NULL; s = s->next) - { - struct nbr_reloc_lineno *e = &n_rl[s->output_section->index]; - e->reloc_count += s->reloc_count; - e->lineno_count += s->lineno_count; - } - - /* Add the size of a section for each section with an overflow. */ - for (s = abfd->sections; s != NULL; s = s->next) - { - struct nbr_reloc_lineno *e = &n_rl[s->index]; - - if (e->reloc_count >= 0xffff - || (e->lineno_count >= 0xffff && info->strip != strip_debugger)) - size += SCNHSZ; - } - - free (n_rl); - } - - return size; -} - -/* Routines to swap information in the XCOFF .loader section. If we - ever need to write an XCOFF loader, this stuff will need to be - moved to another file shared by the linker (which XCOFF calls the - ``binder'') and the loader. */ - -/* Swap in the ldhdr structure. */ - -static void -xcoff_swap_ldhdr_in (bfd *abfd, const void * s, struct internal_ldhdr *dst) -{ - const struct external_ldhdr *src = (const struct external_ldhdr *) s; - - dst->l_version = bfd_get_32 (abfd, src->l_version); - dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms); - dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc); - dst->l_istlen = bfd_get_32 (abfd, src->l_istlen); - dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid); - dst->l_impoff = bfd_get_32 (abfd, src->l_impoff); - dst->l_stlen = bfd_get_32 (abfd, src->l_stlen); - dst->l_stoff = bfd_get_32 (abfd, src->l_stoff); -} - -/* Swap out the ldhdr structure. */ - -static void -xcoff_swap_ldhdr_out (bfd *abfd, const struct internal_ldhdr *src, void * d) -{ - struct external_ldhdr *dst = (struct external_ldhdr *) d; - - bfd_put_32 (abfd, (bfd_vma) src->l_version, dst->l_version); - bfd_put_32 (abfd, src->l_nsyms, dst->l_nsyms); - bfd_put_32 (abfd, src->l_nreloc, dst->l_nreloc); - bfd_put_32 (abfd, src->l_istlen, dst->l_istlen); - bfd_put_32 (abfd, src->l_nimpid, dst->l_nimpid); - bfd_put_32 (abfd, src->l_impoff, dst->l_impoff); - bfd_put_32 (abfd, src->l_stlen, dst->l_stlen); - bfd_put_32 (abfd, src->l_stoff, dst->l_stoff); -} - -/* Swap in the ldsym structure. */ - -static void -xcoff_swap_ldsym_in (bfd *abfd, const void * s, struct internal_ldsym *dst) -{ - const struct external_ldsym *src = (const struct external_ldsym *) s; - - if (bfd_get_32 (abfd, src->_l._l_l._l_zeroes) != 0) { - memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN); - } else { - dst->_l._l_l._l_zeroes = 0; - dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->_l._l_l._l_offset); - } - dst->l_value = bfd_get_32 (abfd, src->l_value); - dst->l_scnum = bfd_get_16 (abfd, src->l_scnum); - dst->l_smtype = bfd_get_8 (abfd, src->l_smtype); - dst->l_smclas = bfd_get_8 (abfd, src->l_smclas); - dst->l_ifile = bfd_get_32 (abfd, src->l_ifile); - dst->l_parm = bfd_get_32 (abfd, src->l_parm); -} - -/* Swap out the ldsym structure. */ - -static void -xcoff_swap_ldsym_out (bfd *abfd, const struct internal_ldsym *src, void * d) -{ - struct external_ldsym *dst = (struct external_ldsym *) d; - - if (src->_l._l_l._l_zeroes != 0) - memcpy (dst->_l._l_name, src->_l._l_name, SYMNMLEN); - else - { - bfd_put_32 (abfd, (bfd_vma) 0, dst->_l._l_l._l_zeroes); - bfd_put_32 (abfd, (bfd_vma) src->_l._l_l._l_offset, - dst->_l._l_l._l_offset); - } - bfd_put_32 (abfd, src->l_value, dst->l_value); - bfd_put_16 (abfd, (bfd_vma) src->l_scnum, dst->l_scnum); - bfd_put_8 (abfd, src->l_smtype, dst->l_smtype); - bfd_put_8 (abfd, src->l_smclas, dst->l_smclas); - bfd_put_32 (abfd, src->l_ifile, dst->l_ifile); - bfd_put_32 (abfd, src->l_parm, dst->l_parm); -} - -static void -xcoff_swap_reloc_in (bfd *abfd, void * s, void * d) -{ - struct external_reloc *src = (struct external_reloc *) s; - struct internal_reloc *dst = (struct internal_reloc *) d; - - memset (dst, 0, sizeof (struct internal_reloc)); - - dst->r_vaddr = bfd_get_32 (abfd, src->r_vaddr); - dst->r_symndx = bfd_get_32 (abfd, src->r_symndx); - dst->r_size = bfd_get_8 (abfd, src->r_size); - dst->r_type = bfd_get_8 (abfd, src->r_type); -} - -static unsigned int -xcoff_swap_reloc_out (bfd *abfd, void * s, void * d) -{ - struct internal_reloc *src = (struct internal_reloc *) s; - struct external_reloc *dst = (struct external_reloc *) d; - - bfd_put_32 (abfd, src->r_vaddr, dst->r_vaddr); - bfd_put_32 (abfd, src->r_symndx, dst->r_symndx); - bfd_put_8 (abfd, src->r_type, dst->r_type); - bfd_put_8 (abfd, src->r_size, dst->r_size); - - return bfd_coff_relsz (abfd); -} - -/* Swap in the ldrel structure. */ - -static void -xcoff_swap_ldrel_in (bfd *abfd, const void * s, struct internal_ldrel *dst) -{ - const struct external_ldrel *src = (const struct external_ldrel *) s; - - dst->l_vaddr = bfd_get_32 (abfd, src->l_vaddr); - dst->l_symndx = bfd_get_32 (abfd, src->l_symndx); - dst->l_rtype = bfd_get_16 (abfd, src->l_rtype); - dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm); -} - -/* Swap out the ldrel structure. */ - -static void -xcoff_swap_ldrel_out (bfd *abfd, const struct internal_ldrel *src, void * d) -{ - struct external_ldrel *dst = (struct external_ldrel *) d; - - bfd_put_32 (abfd, src->l_vaddr, dst->l_vaddr); - bfd_put_32 (abfd, src->l_symndx, dst->l_symndx); - bfd_put_16 (abfd, (bfd_vma) src->l_rtype, dst->l_rtype); - bfd_put_16 (abfd, (bfd_vma) src->l_rsecnm, dst->l_rsecnm); -} - - -bfd_boolean -xcoff_reloc_type_noop (bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto ATTRIBUTE_UNUSED, - bfd_vma val ATTRIBUTE_UNUSED, - bfd_vma addend ATTRIBUTE_UNUSED, - bfd_vma *relocation ATTRIBUTE_UNUSED, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -bfd_boolean -xcoff_reloc_type_fail (bfd *input_bfd, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto ATTRIBUTE_UNUSED, - bfd_vma val ATTRIBUTE_UNUSED, - bfd_vma addend ATTRIBUTE_UNUSED, - bfd_vma *relocation ATTRIBUTE_UNUSED, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: unsupported relocation type 0x%02x"), - input_bfd, (unsigned int) rel->r_type); - bfd_set_error (bfd_error_bad_value); - return FALSE; -} - -bfd_boolean -xcoff_reloc_type_pos (bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto ATTRIBUTE_UNUSED, - bfd_vma val, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - *relocation = val + addend; - return TRUE; -} - -bfd_boolean -xcoff_reloc_type_neg (bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto ATTRIBUTE_UNUSED, - bfd_vma val, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - *relocation = addend - val; - return TRUE; -} - -bfd_boolean -xcoff_reloc_type_rel (bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto, - bfd_vma val, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - howto->pc_relative = TRUE; - - /* A PC relative reloc includes the section address. */ - addend += input_section->vma; - - *relocation = val + addend; - *relocation -= (input_section->output_section->vma - + input_section->output_offset); - return TRUE; -} - -bfd_boolean -xcoff_reloc_type_toc (bfd *input_bfd, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - struct internal_reloc *rel, - struct internal_syment *sym, - struct reloc_howto_struct *howto ATTRIBUTE_UNUSED, - bfd_vma val, - bfd_vma addend ATTRIBUTE_UNUSED, - bfd_vma *relocation, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - struct xcoff_link_hash_entry *h; - - if (0 > rel->r_symndx) - return FALSE; - - h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx]; - - if (h != NULL && h->smclas != XMC_TD) - { - if (h->toc_section == NULL) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: TOC reloc at %#Lx to symbol `%s' with no TOC entry"), - input_bfd, rel->r_vaddr, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0); - val = (h->toc_section->output_section->vma - + h->toc_section->output_offset); - } - - *relocation = ((val - xcoff_data (output_bfd)->toc) - - (sym->n_value - xcoff_data (input_bfd)->toc)); - return TRUE; -} - -bfd_boolean -xcoff_reloc_type_ba (bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto, - bfd_vma val, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - howto->src_mask &= ~3; - howto->dst_mask = howto->src_mask; - - *relocation = val + addend; - - return TRUE; -} - -static bfd_boolean -xcoff_reloc_type_br (bfd *input_bfd, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto, - bfd_vma val, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents) -{ - struct xcoff_link_hash_entry *h; - bfd_vma section_offset; - - if (0 > rel->r_symndx) - return FALSE; - - h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx]; - section_offset = rel->r_vaddr - input_section->vma; - - /* If we see an R_BR or R_RBR reloc which is jumping to global - linkage code, and it is followed by an appropriate cror nop - instruction, we replace the cror with lwz r2,20(r1). This - restores the TOC after the glink code. Contrariwise, if the - call is followed by a lwz r2,20(r1), but the call is not - going to global linkage code, we can replace the load with a - cror. */ - if (NULL != h - && (bfd_link_hash_defined == h->root.type - || bfd_link_hash_defweak == h->root.type) - && section_offset + 8 <= input_section->size) - { - bfd_byte *pnext; - unsigned long next; - - pnext = contents + section_offset + 4; - next = bfd_get_32 (input_bfd, pnext); - - /* The _ptrgl function is magic. It is used by the AIX - compiler to call a function through a pointer. */ - if (h->smclas == XMC_GL || strcmp (h->root.root.string, "._ptrgl") == 0) - { - if (next == 0x4def7b82 /* cror 15,15,15 */ - || next == 0x4ffffb82 /* cror 31,31,31 */ - || next == 0x60000000) /* ori r0,r0,0 */ - bfd_put_32 (input_bfd, 0x80410014, pnext); /* lwz r2,20(r1) */ - - } - else - { - if (next == 0x80410014) /* lwz r2,20(r1) */ - bfd_put_32 (input_bfd, 0x60000000, pnext); /* ori r0,r0,0 */ - } - } - else if (NULL != h && bfd_link_hash_undefined == h->root.type) - { - /* Normally, this relocation is against a defined symbol. In the - case where this is a partial link and the output section offset - is greater than 2^25, the linker will return an invalid error - message that the relocation has been truncated. Yes it has been - truncated but no it not important. For this case, disable the - overflow checking. */ - - howto->complain_on_overflow = complain_overflow_dont; - } - - /* The original PC-relative relocation is biased by -r_vaddr, so adding - the value below will give the absolute target address. */ - *relocation = val + addend + rel->r_vaddr; - - howto->src_mask &= ~3; - howto->dst_mask = howto->src_mask; - - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && bfd_is_abs_section (h->root.u.def.section) - && section_offset + 4 <= input_section->size) - { - bfd_byte *ptr; - bfd_vma insn; - - /* Turn the relative branch into an absolute one by setting the - AA bit. */ - ptr = contents + section_offset; - insn = bfd_get_32 (input_bfd, ptr); - insn |= 2; - bfd_put_32 (input_bfd, insn, ptr); - - /* Make the howto absolute too. */ - howto->pc_relative = FALSE; - howto->complain_on_overflow = complain_overflow_bitfield; - } - else - { - /* Use a PC-relative howto and subtract the instruction's address - from the target address we calculated above. */ - howto->pc_relative = TRUE; - *relocation -= (input_section->output_section->vma - + input_section->output_offset - + section_offset); - } - return TRUE; -} - -bfd_boolean -xcoff_reloc_type_crel (bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto, - bfd_vma val ATTRIBUTE_UNUSED, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - howto->pc_relative = TRUE; - howto->src_mask &= ~3; - howto->dst_mask = howto->src_mask; - - /* A PC relative reloc includes the section address. */ - addend += input_section->vma; - - *relocation = val + addend; - *relocation -= (input_section->output_section->vma - + input_section->output_offset); - return TRUE; -} - -static bfd_boolean -xcoff_complain_overflow_dont_func (bfd *input_bfd ATTRIBUTE_UNUSED, - bfd_vma val ATTRIBUTE_UNUSED, - bfd_vma relocation ATTRIBUTE_UNUSED, - struct reloc_howto_struct * - howto ATTRIBUTE_UNUSED) -{ - return FALSE; -} - -static bfd_boolean -xcoff_complain_overflow_bitfield_func (bfd *input_bfd, - bfd_vma val, - bfd_vma relocation, - struct reloc_howto_struct *howto) -{ - bfd_vma 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); - a = relocation; - b = val & howto->src_mask; - - /* Much like unsigned, except no trimming with addrmask. In - addition, the sum overflows if there is a carry out of - the bfd_vma, i.e., the sum is less than either input - operand. */ - a >>= howto->rightshift; - b >>= howto->bitpos; - - /* Bitfields are sometimes used for signed numbers; for - example, a 13-bit field sometimes represents values in - 0..8191 and sometimes represents values in -4096..4095. - If the field is signed and a is -4095 (0x1001) and b is - -1 (0x1fff), the sum is -4096 (0x1000), but (0x1001 + - 0x1fff is 0x3000). It's not clear how to handle this - everywhere, since there is not way to know how many bits - are significant in the relocation, but the original code - assumed that it was fully sign extended, and we will keep - that assumption. */ - signmask = (fieldmask >> 1) + 1; - - if ((a & ~ fieldmask) != 0) - { - /* Some bits out of the field are set. This might not - be a problem: if this is a signed bitfield, it is OK - iff all the high bits are set, including the sign - bit. We'll try setting all but the most significant - bit in the original relocation value: if this is all - ones, we are OK, assuming a signed bitfield. */ - ss = (signmask << howto->rightshift) - 1; - if ((ss | relocation) != ~ (bfd_vma) 0) - return TRUE; - a &= fieldmask; - } - - /* We just assume (b & ~ fieldmask) == 0. */ - - /* We explicitly permit wrap around if this relocation - covers the high bit of an address. 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 (howto->bitsize + howto->rightshift - == bfd_arch_bits_per_address (input_bfd)) - return FALSE; - - sum = a + b; - if (sum < a || (sum & ~ fieldmask) != 0) - { - /* There was a carry out, or the field overflow. Test - for signed operands again. Here is the overflow test - is as for complain_overflow_signed. */ - if (((~ (a ^ b)) & (a ^ sum)) & signmask) - return TRUE; - } - - return FALSE; -} - -static bfd_boolean -xcoff_complain_overflow_signed_func (bfd *input_bfd, - bfd_vma val, - bfd_vma relocation, - struct reloc_howto_struct *howto) -{ - bfd_vma addrmask, fieldmask, signmask, ss; - bfd_vma a, b, sum; - - /* Get the values to be added together. For signed and unsigned - relocations, we assume that all values should be truncated to - the size of an address. For bitfields, all the bits matter. - See also bfd_check_overflow. */ - fieldmask = N_ONES (howto->bitsize); - addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; - a = relocation; - b = val & howto->src_mask; - - a = (a & addrmask) >> howto->rightshift; - - /* If any sign bits are set, all sign bits must be set. - That is, A must be a valid negative address after - shifting. */ - signmask = ~ (fieldmask >> 1); - ss = a & signmask; - if (ss != 0 && ss != ((addrmask >> howto->rightshift) & signmask)) - return TRUE; - - /* We only need this next bit of code if the sign bit of B - is below the sign bit of A. This would only happen if - SRC_MASK had fewer bits than BITSIZE. Note that if - SRC_MASK has more bits than BITSIZE, we can get into - trouble; we would need to verify that B is in range, as - we do for A above. */ - signmask = ((~ howto->src_mask) >> 1) & howto->src_mask; - if ((b & signmask) != 0) - { - /* Set all the bits above the sign bit. */ - b -= signmask <<= 1; - } - - b = (b & addrmask) >> howto->bitpos; - - /* Now we can do the addition. */ - sum = a + b; - - /* See if the result has the correct sign. Bits above the - sign bit are junk now; ignore them. If the sum is - positive, make sure we did not have all negative inputs; - if the sum is negative, make sure we did not have all - positive inputs. The test below looks only at the sign - bits, and it really just - SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM) - */ - signmask = (fieldmask >> 1) + 1; - if (((~ (a ^ b)) & (a ^ sum)) & signmask) - return TRUE; - - return FALSE; -} - -static bfd_boolean -xcoff_complain_overflow_unsigned_func (bfd *input_bfd, - bfd_vma val, - bfd_vma relocation, - struct reloc_howto_struct *howto) -{ - bfd_vma addrmask, fieldmask; - bfd_vma a, b, sum; - - /* Get the values to be added together. For signed and unsigned - relocations, we assume that all values should be truncated to - the size of an address. For bitfields, all the bits matter. - See also bfd_check_overflow. */ - fieldmask = N_ONES (howto->bitsize); - addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; - a = relocation; - b = val & howto->src_mask; - - /* Checking for an unsigned overflow is relatively easy: - trim the addresses and add, and trim the result as well. - Overflow is normally indicated when the result does not - fit in the field. However, we also need to consider the - case when, e.g., fieldmask is 0x7fffffff or smaller, an - input is 0x80000000, and bfd_vma is only 32 bits; then we - will get sum == 0, but there is an overflow, since the - inputs did not fit in the field. Instead of doing a - separate test, we can check for this by or-ing in the - operands when testing for the sum overflowing its final - field. */ - a = (a & addrmask) >> howto->rightshift; - b = (b & addrmask) >> howto->bitpos; - sum = (a + b) & addrmask; - if ((a | b | sum) & ~ fieldmask) - return TRUE; - - return FALSE; -} - -/* This is the relocation function for the RS/6000/POWER/PowerPC. - This is currently the only processor which uses XCOFF; I hope that - will never change. - - I took the relocation type definitions from two documents: - the PowerPC AIX Version 4 Application Binary Interface, First - Edition (April 1992), and the PowerOpen ABI, Big-Endian - 32-Bit Hardware Implementation (June 30, 1994). Differences - between the documents are noted below. - - Unsupported r_type's - - R_RTB: - R_RRTBI: - R_RRTBA: - - These relocs are defined by the PowerPC ABI to be - relative branches which use half of the difference - between the symbol and the program counter. I can't - quite figure out when this is useful. These relocs are - not defined by the PowerOpen ABI. - - Supported r_type's - - R_POS: - Simple positive relocation. - - R_NEG: - Simple negative relocation. - - R_REL: - Simple PC relative relocation. - - R_TOC: - TOC relative relocation. The value in the instruction in - the input file is the offset from the input file TOC to - the desired location. We want the offset from the final - TOC to the desired location. We have: - isym = iTOC + in - iinsn = in + o - osym = oTOC + on - oinsn = on + o - so we must change insn by on - in. - - R_GL: - GL linkage relocation. The value of this relocation - is the address of the entry in the TOC section. - - R_TCL: - Local object TOC address. I can't figure out the - difference between this and case R_GL. - - R_TRL: - TOC relative relocation. A TOC relative load instruction - which may be changed to a load address instruction. - FIXME: We don't currently implement this optimization. - - R_TRLA: - TOC relative relocation. This is a TOC relative load - address instruction which may be changed to a load - instruction. FIXME: I don't know if this is the correct - implementation. - - R_BA: - Absolute branch. We don't want to mess with the lower - two bits of the instruction. - - R_CAI: - The PowerPC ABI defines this as an absolute call which - may be modified to become a relative call. The PowerOpen - ABI does not define this relocation type. - - R_RBA: - Absolute branch which may be modified to become a - relative branch. - - R_RBAC: - The PowerPC ABI defines this as an absolute branch to a - fixed address which may be modified to an absolute branch - to a symbol. The PowerOpen ABI does not define this - relocation type. - - R_RBRC: - The PowerPC ABI defines this as an absolute branch to a - fixed address which may be modified to a relative branch. - The PowerOpen ABI does not define this relocation type. - - R_BR: - Relative branch. We don't want to mess with the lower - two bits of the instruction. - - R_CREL: - The PowerPC ABI defines this as a relative call which may - be modified to become an absolute call. The PowerOpen - ABI does not define this relocation type. - - R_RBR: - A relative branch which may be modified to become an - absolute branch. - - R_RL: - The PowerPC AIX ABI describes this as a load which may be - changed to a load address. The PowerOpen ABI says this - is the same as case R_POS. - - R_RLA: - The PowerPC AIX ABI describes this as a load address - which may be changed to a load. The PowerOpen ABI says - this is the same as R_POS. -*/ - -bfd_boolean -xcoff_ppc_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct xcoff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma addend; - bfd_vma val; - struct reloc_howto_struct howto; - bfd_vma relocation; - bfd_vma value_to_relocate; - bfd_vma address; - bfd_byte *location; - - /* Relocation type R_REF is a special relocation type which is - merely used to prevent garbage collection from occurring for - the csect including the symbol which it references. */ - if (rel->r_type == R_REF) - continue; - - /* howto */ - howto.type = rel->r_type; - howto.rightshift = 0; - howto.bitsize = (rel->r_size & 0x1f) + 1; - howto.size = howto.bitsize > 16 ? 2 : 1; - howto.pc_relative = FALSE; - howto.bitpos = 0; - howto.complain_on_overflow = (rel->r_size & 0x80 - ? complain_overflow_signed - : complain_overflow_bitfield); - howto.special_function = NULL; - howto.name = "internal"; - howto.partial_inplace = TRUE; - howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize); - howto.pcrel_offset = FALSE; - - /* symbol */ - val = 0; - addend = 0; - h = NULL; - sym = NULL; - symndx = rel->r_symndx; - - if (-1 != symndx) - { - asection *sec; - - h = obj_xcoff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - addend = - sym->n_value; - - if (NULL == h) - { - sec = sections[symndx]; - /* Hack to make sure we use the right TOC anchor value - if this reloc is against the TOC anchor. */ - if (sec->name[3] == '0' - && strcmp (sec->name, ".tc0") == 0) - val = xcoff_data (output_bfd)->toc; - else - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value - - sec->vma); - } - else - { - if (info->unresolved_syms_in_objects != RM_IGNORE - && (h->flags & XCOFF_WAS_UNDEFINED) != 0) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, - input_bfd, input_section, - rel->r_vaddr - input_section->vma, - info->unresolved_syms_in_objects == RM_GENERATE_ERROR); - - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else if (h->root.type == bfd_link_hash_common) - { - sec = h->root.u.c.p->section; - val = (sec->output_section->vma - + sec->output_offset); - - } - else - { - BFD_ASSERT (bfd_link_relocatable (info) - || (info->static_link - && (h->flags & XCOFF_WAS_UNDEFINED) != 0) - || (h->flags & XCOFF_DEF_DYNAMIC) != 0 - || (h->flags & XCOFF_IMPORT) != 0); - } - } - } - - if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION - || !((*xcoff_calculate_relocation[rel->r_type]) - (input_bfd, input_section, output_bfd, rel, sym, &howto, val, - addend, &relocation, contents))) - return FALSE; - - /* address */ - address = rel->r_vaddr - input_section->vma; - location = contents + address; - - if (address > input_section->size) - abort (); - - /* Get the value we are going to relocate. */ - if (1 == howto.size) - value_to_relocate = bfd_get_16 (input_bfd, location); - else - value_to_relocate = bfd_get_32 (input_bfd, location); - - /* 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. */ - - if ((unsigned int) howto.complain_on_overflow - >= XCOFF_MAX_COMPLAIN_OVERFLOW) - abort (); - - if (((*xcoff_complain_overflow[howto.complain_on_overflow]) - (input_bfd, value_to_relocate, relocation, &howto))) - { - const char *name; - char buf[SYMNMLEN + 1]; - char reloc_type_name[10]; - - if (symndx == -1) - { - name = "*ABS*"; - } - else if (h != NULL) - { - name = NULL; - } - else - { - name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); - if (name == NULL) - name = "UNKNOWN"; - } - sprintf (reloc_type_name, "0x%02x", rel->r_type); - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, reloc_type_name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - - /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE. */ - value_to_relocate = ((value_to_relocate & ~howto.dst_mask) - | (((value_to_relocate & howto.src_mask) - + relocation) & howto.dst_mask)); - - /* Put the value back in the object file. */ - if (1 == howto.size) - bfd_put_16 (input_bfd, value_to_relocate, location); - else - bfd_put_32 (input_bfd, value_to_relocate, location); - } - - return TRUE; -} - -static bfd_boolean -_bfd_xcoff_put_ldsymbol_name (bfd *abfd ATTRIBUTE_UNUSED, - struct xcoff_loader_info *ldinfo, - struct internal_ldsym *ldsym, - const char *name) -{ - size_t len; - len = strlen (name); - - if (len <= SYMNMLEN) - strncpy (ldsym->_l._l_name, name, SYMNMLEN); - else - { - if (ldinfo->string_size + len + 3 > ldinfo->string_alc) - { - bfd_size_type newalc; - char *newstrings; - - newalc = ldinfo->string_alc * 2; - if (newalc == 0) - newalc = 32; - while (ldinfo->string_size + len + 3 > newalc) - newalc *= 2; - - newstrings = bfd_realloc (ldinfo->strings, newalc); - if (newstrings == NULL) - { - ldinfo->failed = TRUE; - return FALSE; - } - ldinfo->string_alc = newalc; - ldinfo->strings = newstrings; - } - - bfd_put_16 (ldinfo->output_bfd, (bfd_vma) (len + 1), - ldinfo->strings + ldinfo->string_size); - strcpy (ldinfo->strings + ldinfo->string_size + 2, name); - ldsym->_l._l_l._l_zeroes = 0; - ldsym->_l._l_l._l_offset = ldinfo->string_size + 2; - ldinfo->string_size += len + 3; - } - - return TRUE; -} - -static bfd_boolean -_bfd_xcoff_put_symbol_name (struct bfd_link_info *info, - struct bfd_strtab_hash *strtab, - struct internal_syment *sym, - const char *name) -{ - if (strlen (name) <= SYMNMLEN) - { - strncpy (sym->_n._n_name, name, SYMNMLEN); - } - else - { - bfd_boolean hash; - bfd_size_type indx; - - hash = !info->traditional_format; - indx = _bfd_stringtab_add (strtab, name, hash, FALSE); - if (indx == (bfd_size_type) -1) - return FALSE; - sym->_n._n_n._n_zeroes = 0; - sym->_n._n_n._n_offset = STRING_SIZE_SIZE + indx; - } - return TRUE; -} - -static asection * -xcoff_create_csect_from_smclas (bfd *abfd, - union internal_auxent *aux, - const char *symbol_name) -{ - asection *return_value = NULL; - - /* .sv64 = x_smclas == 17 - This is an invalid csect for 32 bit apps. */ - static const char * const names[] = - { - ".pr", ".ro", ".db", ".tc", ".ua", ".rw", ".gl", ".xo", /* 0 - 7 */ - ".sv", ".bs", ".ds", ".uc", ".ti", ".tb", NULL, ".tc0", /* 8 - 15 */ - ".td", NULL, ".sv3264", NULL, ".tl", ".ul", ".te" - }; - - if ((aux->x_csect.x_smclas < ARRAY_SIZE (names)) - && (NULL != names[aux->x_csect.x_smclas])) - { - return_value = bfd_make_section_anyway - (abfd, names[aux->x_csect.x_smclas]); - } - else - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: symbol `%s' has unrecognized smclas %d"), - abfd, symbol_name, aux->x_csect.x_smclas); - bfd_set_error (bfd_error_bad_value); - } - - return return_value; -} - -static bfd_boolean -xcoff_is_lineno_count_overflow (bfd *abfd ATTRIBUTE_UNUSED, bfd_vma value) -{ - if (0xffff <= value) - return TRUE; - - return FALSE; -} - -static bfd_boolean -xcoff_is_reloc_count_overflow (bfd *abfd ATTRIBUTE_UNUSED, bfd_vma value) -{ - if (0xffff <= value) - return TRUE; - - return FALSE; -} - -static bfd_vma -xcoff_loader_symbol_offset (bfd *abfd, - struct internal_ldhdr *ldhdr ATTRIBUTE_UNUSED) -{ - return bfd_xcoff_ldhdrsz (abfd); -} - -static bfd_vma -xcoff_loader_reloc_offset (bfd *abfd, struct internal_ldhdr *ldhdr) -{ - return bfd_xcoff_ldhdrsz (abfd) + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (abfd); -} - -static bfd_boolean -xcoff_generate_rtinit (bfd *abfd, const char *init, const char *fini, - bfd_boolean rtld) -{ - bfd_byte filehdr_ext[FILHSZ]; - bfd_byte scnhdr_ext[SCNHSZ]; - bfd_byte syment_ext[SYMESZ * 10]; - bfd_byte reloc_ext[RELSZ * 3]; - bfd_byte *data_buffer; - bfd_size_type data_buffer_size; - bfd_byte *string_table = NULL, *st_tmp = NULL; - bfd_size_type string_table_size; - bfd_vma val; - size_t initsz, finisz; - struct internal_filehdr filehdr; - struct internal_scnhdr scnhdr; - struct internal_syment syment; - union internal_auxent auxent; - struct internal_reloc reloc; - - char *data_name = ".data"; - char *rtinit_name = "__rtinit"; - char *rtld_name = "__rtld"; - - if (! bfd_xcoff_rtinit_size (abfd)) - return FALSE; - - initsz = (init == NULL ? 0 : 1 + strlen (init)); - finisz = (fini == NULL ? 0 : 1 + strlen (fini)); - - /* file header */ - memset (filehdr_ext, 0, FILHSZ); - memset (&filehdr, 0, sizeof (struct internal_filehdr)); - filehdr.f_magic = bfd_xcoff_magic_number (abfd); - filehdr.f_nscns = 1; - filehdr.f_timdat = 0; - filehdr.f_nsyms = 0; /* at least 6, no more than 10 */ - filehdr.f_symptr = 0; /* set below */ - filehdr.f_opthdr = 0; - filehdr.f_flags = 0; - - /* section header */ - memset (scnhdr_ext, 0, SCNHSZ); - memset (&scnhdr, 0, sizeof (struct internal_scnhdr)); - memcpy (scnhdr.s_name, data_name, strlen (data_name)); - scnhdr.s_paddr = 0; - scnhdr.s_vaddr = 0; - scnhdr.s_size = 0; /* set below */ - scnhdr.s_scnptr = FILHSZ + SCNHSZ; - scnhdr.s_relptr = 0; /* set below */ - scnhdr.s_lnnoptr = 0; - scnhdr.s_nreloc = 0; /* either 1 or 2 */ - scnhdr.s_nlnno = 0; - scnhdr.s_flags = STYP_DATA; - - /* .data - 0x0000 0x00000000 : rtl - 0x0004 0x00000010 : offset to init, or 0 - 0x0008 0x00000028 : offset to fini, or 0 - 0x000C 0x0000000C : size of descriptor - 0x0010 0x00000000 : init, needs a reloc - 0x0014 0x00000040 : offset to init name - 0x0018 0x00000000 : flags, padded to a word - 0x001C 0x00000000 : empty init - 0x0020 0x00000000 : - 0x0024 0x00000000 : - 0x0028 0x00000000 : fini, needs a reloc - 0x002C 0x00000??? : offset to fini name - 0x0030 0x00000000 : flags, padded to a word - 0x0034 0x00000000 : empty fini - 0x0038 0x00000000 : - 0x003C 0x00000000 : - 0x0040 init name - 0x0040 + initsz fini name */ - - data_buffer_size = 0x0040 + initsz + finisz; - data_buffer_size = (data_buffer_size + 7) &~ (bfd_size_type) 7; - data_buffer = NULL; - data_buffer = (bfd_byte *) bfd_zmalloc (data_buffer_size); - if (data_buffer == NULL) - return FALSE; - - if (initsz) - { - val = 0x10; - bfd_h_put_32 (abfd, val, &data_buffer[0x04]); - val = 0x40; - bfd_h_put_32 (abfd, val, &data_buffer[0x14]); - memcpy (&data_buffer[val], init, initsz); - } - - if (finisz) - { - val = 0x28; - bfd_h_put_32 (abfd, val, &data_buffer[0x08]); - val = 0x40 + initsz; - bfd_h_put_32 (abfd, val, &data_buffer[0x2C]); - memcpy (&data_buffer[val], fini, finisz); - } - - val = 0x0C; - bfd_h_put_32 (abfd, val, &data_buffer[0x0C]); - - scnhdr.s_size = data_buffer_size; - - /* string table */ - string_table_size = 0; - if (initsz > 9) - string_table_size += initsz; - if (finisz > 9) - string_table_size += finisz; - if (string_table_size) - { - string_table_size += 4; - string_table = (bfd_byte *) bfd_zmalloc (string_table_size); - if (string_table == NULL) - return FALSE; - - val = string_table_size; - bfd_h_put_32 (abfd, val, &string_table[0]); - st_tmp = string_table + 4; - } - - /* symbols - 0. .data csect - 2. __rtinit - 4. init function - 6. fini function - 8. __rtld */ - memset (syment_ext, 0, 10 * SYMESZ); - memset (reloc_ext, 0, 3 * RELSZ); - - /* .data csect */ - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - memcpy (syment._n._n_name, data_name, strlen (data_name)); - syment.n_scnum = 1; - syment.n_sclass = C_HIDEXT; - syment.n_numaux = 1; - auxent.x_csect.x_scnlen.l = data_buffer_size; - auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD; - auxent.x_csect.x_smclas = XMC_RW; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - filehdr.f_nsyms += 2; - - /* __rtinit */ - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - memcpy (syment._n._n_name, rtinit_name, strlen (rtinit_name)); - syment.n_scnum = 1; - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - auxent.x_csect.x_smtyp = XTY_LD; - auxent.x_csect.x_smclas = XMC_RW; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - filehdr.f_nsyms += 2; - - /* init */ - if (initsz) - { - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - - if (initsz > 9) - { - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, init, initsz); - st_tmp += initsz; - } - else - memcpy (syment._n._n_name, init, initsz - 1); - - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - - /* reloc */ - memset (&reloc, 0, sizeof (struct internal_reloc)); - reloc.r_vaddr = 0x0010; - reloc.r_symndx = filehdr.f_nsyms; - reloc.r_type = R_POS; - reloc.r_size = 31; - bfd_coff_swap_reloc_out (abfd, &reloc, &reloc_ext[0]); - - filehdr.f_nsyms += 2; - scnhdr.s_nreloc += 1; - } - - /* fini */ - if (finisz) - { - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - - if (finisz > 9) - { - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, fini, finisz); - st_tmp += finisz; - } - else - memcpy (syment._n._n_name, fini, finisz - 1); - - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - - /* reloc */ - memset (&reloc, 0, sizeof (struct internal_reloc)); - reloc.r_vaddr = 0x0028; - reloc.r_symndx = filehdr.f_nsyms; - reloc.r_type = R_POS; - reloc.r_size = 31; - bfd_coff_swap_reloc_out (abfd, &reloc, - &reloc_ext[scnhdr.s_nreloc * RELSZ]); - - filehdr.f_nsyms += 2; - scnhdr.s_nreloc += 1; - } - - if (rtld) - { - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - memcpy (syment._n._n_name, rtld_name, strlen (rtld_name)); - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - - /* reloc */ - memset (&reloc, 0, sizeof (struct internal_reloc)); - reloc.r_vaddr = 0x0000; - reloc.r_symndx = filehdr.f_nsyms; - reloc.r_type = R_POS; - reloc.r_size = 31; - bfd_coff_swap_reloc_out (abfd, &reloc, - &reloc_ext[scnhdr.s_nreloc * RELSZ]); - - filehdr.f_nsyms += 2; - scnhdr.s_nreloc += 1; - } - - scnhdr.s_relptr = scnhdr.s_scnptr + data_buffer_size; - filehdr.f_symptr = scnhdr.s_relptr + scnhdr.s_nreloc * RELSZ; - - bfd_coff_swap_filehdr_out (abfd, &filehdr, filehdr_ext); - bfd_bwrite (filehdr_ext, FILHSZ, abfd); - bfd_coff_swap_scnhdr_out (abfd, &scnhdr, scnhdr_ext); - bfd_bwrite (scnhdr_ext, SCNHSZ, abfd); - bfd_bwrite (data_buffer, data_buffer_size, abfd); - bfd_bwrite (reloc_ext, scnhdr.s_nreloc * RELSZ, abfd); - bfd_bwrite (syment_ext, filehdr.f_nsyms * SYMESZ, abfd); - bfd_bwrite (string_table, string_table_size, abfd); - - free (data_buffer); - data_buffer = NULL; - - return TRUE; -} - - -static reloc_howto_type xcoff_dynamic_reloc = -HOWTO (0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_POS", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* glink - - The first word of global linkage code must be modified by filling in - the correct TOC offset. */ - -static unsigned long xcoff_glink_code[9] = - { - 0x81820000, /* lwz r12,0(r2) */ - 0x90410014, /* stw r2,20(r1) */ - 0x800c0000, /* lwz r0,0(r12) */ - 0x804c0004, /* lwz r2,4(r12) */ - 0x7c0903a6, /* mtctr r0 */ - 0x4e800420, /* bctr */ - 0x00000000, /* start of traceback table */ - 0x000c8000, /* traceback table */ - 0x00000000, /* traceback table */ - }; - -/* Table to convert DWARF flags to section names. */ - -const struct xcoff_dwsect_name xcoff_dwsect_names[] = { - { SSUBTYP_DWINFO, ".dwinfo", TRUE }, - { SSUBTYP_DWLINE, ".dwline", TRUE }, - { SSUBTYP_DWPBNMS, ".dwpbnms", TRUE }, - { SSUBTYP_DWPBTYP, ".dwpbtyp", TRUE }, - { SSUBTYP_DWARNGE, ".dwarnge", TRUE }, - { SSUBTYP_DWABREV, ".dwabrev", FALSE }, - { SSUBTYP_DWSTR, ".dwstr", TRUE }, - { SSUBTYP_DWRNGES, ".dwrnges", TRUE } -}; - -/* For generic entry points. */ -#define _bfd_xcoff_close_and_cleanup _bfd_archive_close_and_cleanup -#define _bfd_xcoff_bfd_free_cached_info bfd_true -#define _bfd_xcoff_new_section_hook coff_new_section_hook -#define _bfd_xcoff_get_section_contents _bfd_generic_get_section_contents -#define _bfd_xcoff_get_section_contents_in_window \ - _bfd_generic_get_section_contents_in_window - -/* For copy private data entry points. */ -#define _bfd_xcoff_bfd_copy_private_bfd_data \ - _bfd_xcoff_copy_private_bfd_data -#define _bfd_xcoff_bfd_merge_private_bfd_data \ - _bfd_generic_bfd_merge_private_bfd_data -#define _bfd_xcoff_bfd_copy_private_section_data \ - _bfd_generic_bfd_copy_private_section_data -#define _bfd_xcoff_bfd_copy_private_symbol_data \ - _bfd_generic_bfd_copy_private_symbol_data -#define _bfd_xcoff_bfd_copy_private_header_data \ - _bfd_generic_bfd_copy_private_header_data -#define _bfd_xcoff_bfd_set_private_flags \ - _bfd_generic_bfd_set_private_flags -#define _bfd_xcoff_bfd_print_private_bfd_data \ - _bfd_generic_bfd_print_private_bfd_data - -/* For archive entry points. */ -#define _bfd_xcoff_slurp_extended_name_table \ - _bfd_noarchive_slurp_extended_name_table -#define _bfd_xcoff_construct_extended_name_table \ - _bfd_noarchive_construct_extended_name_table -#define _bfd_xcoff_truncate_arname bfd_dont_truncate_arname -#define _bfd_xcoff_write_ar_hdr _bfd_generic_write_ar_hdr -#define _bfd_xcoff_get_elt_at_index _bfd_generic_get_elt_at_index -#define _bfd_xcoff_generic_stat_arch_elt _bfd_xcoff_stat_arch_elt -#define _bfd_xcoff_update_armap_timestamp bfd_true - -/* For symbols entry points. */ -#define _bfd_xcoff_get_symtab_upper_bound coff_get_symtab_upper_bound -#define _bfd_xcoff_canonicalize_symtab coff_canonicalize_symtab -#define _bfd_xcoff_make_empty_symbol coff_make_empty_symbol -#define _bfd_xcoff_print_symbol coff_print_symbol -#define _bfd_xcoff_get_symbol_info coff_get_symbol_info -#define _bfd_xcoff_get_symbol_version_string \ - _bfd_nosymbols_get_symbol_version_string -#define _bfd_xcoff_bfd_is_local_label_name _bfd_xcoff_is_local_label_name -#define _bfd_xcoff_bfd_is_target_special_symbol \ - coff_bfd_is_target_special_symbol -#define _bfd_xcoff_get_lineno coff_get_lineno -#define _bfd_xcoff_find_nearest_line coff_find_nearest_line -#define _bfd_xcoff_find_line coff_find_line -#define _bfd_xcoff_find_inliner_info coff_find_inliner_info -#define _bfd_xcoff_bfd_make_debug_symbol coff_bfd_make_debug_symbol -#define _bfd_xcoff_read_minisymbols _bfd_generic_read_minisymbols -#define _bfd_xcoff_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol - -/* For reloc entry points. */ -#define _bfd_xcoff_get_reloc_upper_bound coff_get_reloc_upper_bound -#define _bfd_xcoff_canonicalize_reloc coff_canonicalize_reloc -#define _bfd_xcoff_set_reloc _bfd_generic_set_reloc -#define _bfd_xcoff_bfd_reloc_type_lookup _bfd_xcoff_reloc_type_lookup -#define _bfd_xcoff_bfd_reloc_name_lookup _bfd_xcoff_reloc_name_lookup - -/* For link entry points. */ -#define _bfd_xcoff_bfd_get_relocated_section_contents \ - bfd_generic_get_relocated_section_contents -#define _bfd_xcoff_bfd_relax_section bfd_generic_relax_section -#define _bfd_xcoff_bfd_link_hash_table_free _bfd_generic_link_hash_table_free -#define _bfd_xcoff_bfd_link_just_syms _bfd_generic_link_just_syms -#define _bfd_xcoff_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type -#define _bfd_xcoff_bfd_link_split_section _bfd_generic_link_split_section -#define _bfd_xcoff_bfd_gc_sections bfd_generic_gc_sections -#define _bfd_xcoff_bfd_lookup_section_flags bfd_generic_lookup_section_flags -#define _bfd_xcoff_bfd_merge_sections bfd_generic_merge_sections -#define _bfd_xcoff_bfd_is_group_section bfd_generic_is_group_section -#define _bfd_xcoff_bfd_discard_group bfd_generic_discard_group -#define _bfd_xcoff_section_already_linked _bfd_generic_section_already_linked -#define _bfd_xcoff_bfd_define_common_symbol _bfd_xcoff_define_common_symbol -#define _bfd_xcoff_bfd_define_start_stop bfd_generic_define_start_stop -#define _bfd_xcoff_bfd_link_check_relocs _bfd_generic_link_check_relocs - -/* For dynamic symbols and relocs entry points. */ -#define _bfd_xcoff_get_synthetic_symtab _bfd_nodynamic_get_synthetic_symtab - -static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = - { - { /* COFF backend, defined in libcoff.h. */ - _bfd_xcoff_swap_aux_in, - _bfd_xcoff_swap_sym_in, - coff_swap_lineno_in, - _bfd_xcoff_swap_aux_out, - _bfd_xcoff_swap_sym_out, - coff_swap_lineno_out, - xcoff_swap_reloc_out, - coff_swap_filehdr_out, - coff_swap_aouthdr_out, - coff_swap_scnhdr_out, - FILHSZ, - AOUTSZ, - SCNHSZ, - SYMESZ, - AUXESZ, - RELSZ, - LINESZ, - FILNMLEN, - TRUE, /* _bfd_coff_long_filenames */ - XCOFF_NO_LONG_SECTION_NAMES, /* _bfd_coff_long_section_names */ - 3, /* _bfd_coff_default_section_alignment_power */ - FALSE, /* _bfd_coff_force_symnames_in_strings */ - 2, /* _bfd_coff_debug_string_prefix_length */ - 32768, /* _bfd_coff_max_nscns */ - coff_swap_filehdr_in, - coff_swap_aouthdr_in, - coff_swap_scnhdr_in, - xcoff_swap_reloc_in, - coff_bad_format_hook, - coff_set_arch_mach_hook, - coff_mkobject_hook, - styp_to_sec_flags, - coff_set_alignment_hook, - coff_slurp_symbol_table, - symname_in_debug_hook, - coff_pointerize_aux_hook, - coff_print_aux, - dummy_reloc16_extra_cases, - dummy_reloc16_estimate, - NULL, /* bfd_coff_sym_is_global */ - coff_compute_section_file_positions, - NULL, /* _bfd_coff_start_final_link */ - xcoff_ppc_relocate_section, - coff_rtype_to_howto, - NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, - coff_link_output_has_begun, - coff_final_link_postscript, - NULL /* print_pdata. */ - }, - - 0x01DF, /* magic number */ - bfd_arch_rs6000, - bfd_mach_rs6k, - - /* Function pointers to xcoff specific swap routines. */ - xcoff_swap_ldhdr_in, - xcoff_swap_ldhdr_out, - xcoff_swap_ldsym_in, - xcoff_swap_ldsym_out, - xcoff_swap_ldrel_in, - xcoff_swap_ldrel_out, - - /* Sizes. */ - LDHDRSZ, - LDSYMSZ, - LDRELSZ, - 12, /* _xcoff_function_descriptor_size */ - SMALL_AOUTSZ, - - /* Versions. */ - 1, /* _xcoff_ldhdr_version */ - - _bfd_xcoff_put_symbol_name, - _bfd_xcoff_put_ldsymbol_name, - &xcoff_dynamic_reloc, - xcoff_create_csect_from_smclas, - - /* Lineno and reloc count overflow. */ - xcoff_is_lineno_count_overflow, - xcoff_is_reloc_count_overflow, - - xcoff_loader_symbol_offset, - xcoff_loader_reloc_offset, - - /* glink. */ - &xcoff_glink_code[0], - 36, /* _xcoff_glink_size */ - - /* rtinit */ - 64, /* _xcoff_rtinit_size */ - xcoff_generate_rtinit, - }; - -/* The transfer vector that leads the outside world to all of the above. */ -const bfd_target rs6000_xcoff_vec = - { - "aixcoff-rs6000", - bfd_target_xcoff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC - | HAS_SYMS | HAS_LOCALS | WP_TEXT), - - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, - 0, /* leading char */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - /* 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_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 */ - _bfd_dummy_target, - coff_object_p, - _bfd_xcoff_archive_p, - CORE_FILE_P - }, - - { /* bfd_set_format */ - bfd_false, - coff_mkobject, - _bfd_generic_mkarchive, - bfd_false - }, - - {/* bfd_write_contents */ - bfd_false, - coff_write_object_contents, - _bfd_xcoff_write_archive_contents, - bfd_false - }, - - BFD_JUMP_TABLE_GENERIC (_bfd_xcoff), - BFD_JUMP_TABLE_COPY (_bfd_xcoff), - BFD_JUMP_TABLE_CORE (coff), - BFD_JUMP_TABLE_ARCHIVE (_bfd_xcoff), - BFD_JUMP_TABLE_SYMBOLS (_bfd_xcoff), - BFD_JUMP_TABLE_RELOCS (_bfd_xcoff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (_bfd_xcoff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_xcoff), - - /* Opposite endian version, none exists */ - NULL, - - & bfd_xcoff_backend_data, - }; - -/* xcoff-powermac target - Old target. - Only difference between this target and the rs6000 target is the - the default architecture and machine type used in coffcode.h - - PowerPC Macs use the same magic numbers as RS/6000 - (because that's how they were bootstrapped originally), - but they are always PowerPC architecture. */ -static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data = - { - { /* COFF backend, defined in libcoff.h. */ - _bfd_xcoff_swap_aux_in, - _bfd_xcoff_swap_sym_in, - coff_swap_lineno_in, - _bfd_xcoff_swap_aux_out, - _bfd_xcoff_swap_sym_out, - coff_swap_lineno_out, - xcoff_swap_reloc_out, - coff_swap_filehdr_out, - coff_swap_aouthdr_out, - coff_swap_scnhdr_out, - FILHSZ, - AOUTSZ, - SCNHSZ, - SYMESZ, - AUXESZ, - RELSZ, - LINESZ, - FILNMLEN, - TRUE, /* _bfd_coff_long_filenames */ - XCOFF_NO_LONG_SECTION_NAMES, /* _bfd_coff_long_section_names */ - 3, /* _bfd_coff_default_section_alignment_power */ - FALSE, /* _bfd_coff_force_symnames_in_strings */ - 2, /* _bfd_coff_debug_string_prefix_length */ - 32768, /* _bfd_coff_max_nscns */ - coff_swap_filehdr_in, - coff_swap_aouthdr_in, - coff_swap_scnhdr_in, - xcoff_swap_reloc_in, - coff_bad_format_hook, - coff_set_arch_mach_hook, - coff_mkobject_hook, - styp_to_sec_flags, - coff_set_alignment_hook, - coff_slurp_symbol_table, - symname_in_debug_hook, - coff_pointerize_aux_hook, - coff_print_aux, - dummy_reloc16_extra_cases, - dummy_reloc16_estimate, - NULL, /* bfd_coff_sym_is_global */ - coff_compute_section_file_positions, - NULL, /* _bfd_coff_start_final_link */ - xcoff_ppc_relocate_section, - coff_rtype_to_howto, - NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, - coff_link_output_has_begun, - coff_final_link_postscript, - NULL /* print_pdata. */ - }, - - 0x01DF, /* magic number */ - bfd_arch_powerpc, - bfd_mach_ppc, - - /* Function pointers to xcoff specific swap routines. */ - xcoff_swap_ldhdr_in, - xcoff_swap_ldhdr_out, - xcoff_swap_ldsym_in, - xcoff_swap_ldsym_out, - xcoff_swap_ldrel_in, - xcoff_swap_ldrel_out, - - /* Sizes. */ - LDHDRSZ, - LDSYMSZ, - LDRELSZ, - 12, /* _xcoff_function_descriptor_size */ - SMALL_AOUTSZ, - - /* Versions. */ - 1, /* _xcoff_ldhdr_version */ - - _bfd_xcoff_put_symbol_name, - _bfd_xcoff_put_ldsymbol_name, - &xcoff_dynamic_reloc, - xcoff_create_csect_from_smclas, - - /* Lineno and reloc count overflow. */ - xcoff_is_lineno_count_overflow, - xcoff_is_reloc_count_overflow, - - xcoff_loader_symbol_offset, - xcoff_loader_reloc_offset, - - /* glink. */ - &xcoff_glink_code[0], - 36, /* _xcoff_glink_size */ - - /* rtinit */ - 0, /* _xcoff_rtinit_size */ - xcoff_generate_rtinit, - }; - -/* The transfer vector that leads the outside world to all of the above. */ -const bfd_target powerpc_xcoff_vec = - { - "xcoff-powermac", - bfd_target_xcoff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC - | HAS_SYMS | HAS_LOCALS | WP_TEXT), - - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, - 0, /* leading char */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - /* 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_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 */ - _bfd_dummy_target, - coff_object_p, - _bfd_xcoff_archive_p, - CORE_FILE_P - }, - - { /* bfd_set_format */ - bfd_false, - coff_mkobject, - _bfd_generic_mkarchive, - bfd_false - }, - - {/* bfd_write_contents */ - bfd_false, - coff_write_object_contents, - _bfd_xcoff_write_archive_contents, - bfd_false - }, - - BFD_JUMP_TABLE_GENERIC (_bfd_xcoff), - BFD_JUMP_TABLE_COPY (_bfd_xcoff), - BFD_JUMP_TABLE_CORE (coff), - BFD_JUMP_TABLE_ARCHIVE (_bfd_xcoff), - BFD_JUMP_TABLE_SYMBOLS (_bfd_xcoff), - BFD_JUMP_TABLE_RELOCS (_bfd_xcoff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (_bfd_xcoff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_xcoff), - - /* Opposite endian version, none exists */ - NULL, - - & bfd_pmac_xcoff_backend_data, - }; diff --git a/sdcc/support/sdbinutils/bfd/coff-sh.c b/sdcc/support/sdbinutils/bfd/coff-sh.c deleted file mode 100644 index 3a921fd02..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-sh.c +++ /dev/null @@ -1,3215 +0,0 @@ -/* BFD back-end for Renesas Super-H COFF binaries. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Contributed by Cygnus Support. - Written by Steve Chamberlain, . - Relaxing code written by Ian Lance Taylor, . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libiberty.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "coff/sh.h" -#include "coff/internal.h" - -#undef bfd_pe_print_pdata - -#ifdef COFF_WITH_PE -#include "coff/pe.h" - -#ifndef COFF_IMAGE_WITH_PE -static bfd_boolean 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 *); - -#define _bfd_sh_align_load_span sh_align_load_span -#endif - -#define bfd_pe_print_pdata _bfd_pe_print_ce_compressed_pdata - -#else - -#define bfd_pe_print_pdata NULL - -#endif /* COFF_WITH_PE. */ - -#include "libcoff.h" - -/* Internal functions. */ - -#ifdef COFF_WITH_PE -/* Can't build import tables with 2**4 alignment. */ -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 2 -#else -/* Default section alignment to 2**4. */ -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 4 -#endif - -#ifdef COFF_IMAGE_WITH_PE -/* Align PE executables. */ -#define COFF_PAGE_SIZE 0x1000 -#endif - -/* Generate long file names. */ -#define COFF_LONG_FILENAMES - -#ifdef COFF_WITH_PE -/* Return TRUE if this relocation should - appear in the output .reloc section. */ - -static bfd_boolean -in_reloc_p (bfd * abfd ATTRIBUTE_UNUSED, - reloc_howto_type * howto) -{ - return ! howto->pc_relative && howto->type != R_SH_IMAGEBASE; -} -#endif - -static bfd_reloc_status_type -sh_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_boolean -sh_relocate_section (bfd *, struct bfd_link_info *, bfd *, asection *, - bfd_byte *, struct internal_reloc *, - struct internal_syment *, asection **); -static bfd_boolean -sh_align_loads (bfd *, asection *, struct internal_reloc *, - bfd_byte *, bfd_boolean *); - -/* The supported relocations. There are a lot of relocations defined - in coff/internal.h which we do not expect to ever see. */ -static reloc_howto_type sh_coff_howtos[] = -{ - EMPTY_HOWTO (0), - EMPTY_HOWTO (1), -#ifdef COFF_WITH_PE - /* Windows CE */ - HOWTO (R_SH_IMM32CE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_imm32ce", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#else - EMPTY_HOWTO (2), -#endif - EMPTY_HOWTO (3), /* R_SH_PCREL8 */ - EMPTY_HOWTO (4), /* R_SH_PCREL16 */ - EMPTY_HOWTO (5), /* R_SH_HIGH8 */ - EMPTY_HOWTO (6), /* R_SH_IMM24 */ - EMPTY_HOWTO (7), /* R_SH_LOW16 */ - EMPTY_HOWTO (8), - EMPTY_HOWTO (9), /* R_SH_PCDISP8BY4 */ - - HOWTO (R_SH_PCDISP8BY2, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_pcdisp8by2", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (11), /* R_SH_PCDISP8 */ - - HOWTO (R_SH_PCDISP, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_pcdisp12by2", /* name */ - TRUE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (13), - - HOWTO (R_SH_IMM32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_imm32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (15), -#ifdef COFF_WITH_PE - HOWTO (R_SH_IMAGEBASE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "rva32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#else - EMPTY_HOWTO (16), /* R_SH_IMM8 */ -#endif - EMPTY_HOWTO (17), /* R_SH_IMM8BY2 */ - EMPTY_HOWTO (18), /* R_SH_IMM8BY4 */ - EMPTY_HOWTO (19), /* R_SH_IMM4 */ - EMPTY_HOWTO (20), /* R_SH_IMM4BY2 */ - EMPTY_HOWTO (21), /* R_SH_IMM4BY4 */ - - HOWTO (R_SH_PCRELIMM8BY2, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_pcrelimm8by2", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_SH_PCRELIMM8BY4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_pcrelimm8by4", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_SH_IMM16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_imm16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_SWITCH16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_switch16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_SWITCH32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_switch32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_USES, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_uses", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_COUNT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_count", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_ALIGN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_align", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_CODE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_code", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DATA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_data", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_LABEL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_label", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_SWITCH8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_reloc, /* special_function */ - "r_switch8", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -#define SH_COFF_HOWTO_COUNT (sizeof sh_coff_howtos / sizeof sh_coff_howtos[0]) - -/* Check for a bad magic number. */ -#define BADMAG(x) SHBADMAG(x) - -/* Customize coffcode.h (this is not currently used). */ -#define SH 1 - -/* FIXME: This should not be set here. */ -#define __A_MAGIC_SET__ - -#ifndef COFF_WITH_PE -/* Swap the r_offset field in and out. */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 - -/* Swap out extra information in the reloc structure. */ -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ - do \ - { \ - dst->r_stuff[0] = 'S'; \ - dst->r_stuff[1] = 'C'; \ - } \ - while (0) -#endif - -/* Get the value of a symbol, when performing a relocation. */ - -static long -get_symbol_value (asymbol *symbol) -{ - bfd_vma relocation; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = (symbol->value + - symbol->section->output_section->vma + - symbol->section->output_offset); - - return relocation; -} - -#ifdef COFF_WITH_PE -/* Convert an rtype to howto for the COFF backend linker. - Copied from coff-i386. */ -#define coff_rtype_to_howto coff_sh_rtype_to_howto - - -static reloc_howto_type * -coff_sh_rtype_to_howto (bfd * abfd ATTRIBUTE_UNUSED, - asection * sec, - struct internal_reloc * rel, - struct coff_link_hash_entry * h, - struct internal_syment * sym, - bfd_vma * addendp) -{ - reloc_howto_type * howto; - - howto = sh_coff_howtos + rel->r_type; - - *addendp = 0; - - if (howto->pc_relative) - *addendp += sec->vma; - - if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) - { - /* This is a common symbol. The section contents include the - size (sym->n_value) as an addend. The relocate_section - function will be adding in the final value of the symbol. We - need to subtract out the current size in order to get the - correct result. */ - BFD_ASSERT (h != NULL); - } - - if (howto->pc_relative) - { - *addendp -= 4; - - /* If the symbol is defined, then the generic code is going to - add back the symbol value in order to cancel out an - adjustment it made to the addend. However, we set the addend - to 0 at the start of this function. We need to adjust here, - to avoid the adjustment the generic code will make. FIXME: - This is getting a bit hackish. */ - if (sym != NULL && sym->n_scnum != 0) - *addendp -= sym->n_value; - } - - if (rel->r_type == R_SH_IMAGEBASE) - *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; - - return howto; -} - -#endif /* COFF_WITH_PE */ - -/* This structure is used to map BFD reloc codes to SH PE relocs. */ -struct shcoff_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char shcoff_reloc_val; -}; - -#ifdef COFF_WITH_PE -/* An array mapping BFD reloc codes to SH PE relocs. */ -static const struct shcoff_reloc_map sh_reloc_map[] = -{ - { BFD_RELOC_32, R_SH_IMM32CE }, - { BFD_RELOC_RVA, R_SH_IMAGEBASE }, - { BFD_RELOC_CTOR, R_SH_IMM32CE }, -}; -#else -/* An array mapping BFD reloc codes to SH PE relocs. */ -static const struct shcoff_reloc_map sh_reloc_map[] = -{ - { BFD_RELOC_32, R_SH_IMM32 }, - { BFD_RELOC_CTOR, R_SH_IMM32 }, -}; -#endif - -/* Given a BFD reloc code, return the howto structure for the - corresponding SH PE reloc. */ -#define coff_bfd_reloc_type_lookup sh_coff_reloc_type_lookup -#define coff_bfd_reloc_name_lookup sh_coff_reloc_name_lookup - -static reloc_howto_type * -sh_coff_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (sh_reloc_map); i--;) - if (sh_reloc_map[i].bfd_reloc_val == code) - return &sh_coff_howtos[(int) sh_reloc_map[i].shcoff_reloc_val]; - - _bfd_error_handler (_("SH Error: unknown reloc type %d"), code); - return NULL; -} - -static reloc_howto_type * -sh_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (sh_coff_howtos) / sizeof (sh_coff_howtos[0]); i++) - if (sh_coff_howtos[i].name != NULL - && strcasecmp (sh_coff_howtos[i].name, r_name) == 0) - return &sh_coff_howtos[i]; - - return NULL; -} - -/* This macro is used in coffcode.h to get the howto corresponding to - an internal reloc. */ - -#define RTYPE2HOWTO(relent, internal) \ - ((relent)->howto = \ - ((internal)->r_type < SH_COFF_HOWTO_COUNT \ - ? &sh_coff_howtos[(internal)->r_type] \ - : (reloc_howto_type *) NULL)) - -/* This is the same as the macro in coffcode.h, except that it copies - r_offset into reloc_entry->addend for some relocs. */ -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ - { \ - coff_symbol_type *coffsym = (coff_symbol_type *) NULL; \ - if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ - coffsym = (obj_symbols (abfd) \ - + (cache_ptr->sym_ptr_ptr - symbols)); \ - else if (ptr) \ - coffsym = coff_symbol_from (ptr); \ - if (coffsym != (coff_symbol_type *) NULL \ - && coffsym->native->u.syment.n_scnum == 0) \ - cache_ptr->addend = 0; \ - else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ - && ptr->section != (asection *) NULL) \ - cache_ptr->addend = - (ptr->section->vma + ptr->value); \ - else \ - cache_ptr->addend = 0; \ - if ((reloc).r_type == R_SH_SWITCH8 \ - || (reloc).r_type == R_SH_SWITCH16 \ - || (reloc).r_type == R_SH_SWITCH32 \ - || (reloc).r_type == R_SH_USES \ - || (reloc).r_type == R_SH_COUNT \ - || (reloc).r_type == R_SH_ALIGN) \ - cache_ptr->addend = (reloc).r_offset; \ - } - -/* This is the howto function for the SH relocations. */ - -static bfd_reloc_status_type -sh_reloc (bfd * abfd, - arelent * reloc_entry, - asymbol * symbol_in, - void * data, - asection * input_section, - bfd * output_bfd, - char ** error_message ATTRIBUTE_UNUSED) -{ - unsigned long insn; - bfd_vma sym_value; - unsigned short r_type; - bfd_vma addr = reloc_entry->address; - bfd_byte *hit_data = addr + (bfd_byte *) data; - - r_type = reloc_entry->howto->type; - - if (output_bfd != NULL) - { - /* Partial linking--do nothing. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Almost all relocs have to do with relaxing. If any work must be - done for them, it has been done in sh_relax_section. */ - if (r_type != R_SH_IMM32 -#ifdef COFF_WITH_PE - && r_type != R_SH_IMM32CE - && r_type != R_SH_IMAGEBASE -#endif - && (r_type != R_SH_PCDISP - || (symbol_in->flags & BSF_LOCAL) != 0)) - return bfd_reloc_ok; - - if (symbol_in != NULL - && bfd_is_und_section (symbol_in->section)) - return bfd_reloc_undefined; - - if (addr > input_section->size) - return bfd_reloc_outofrange; - - sym_value = get_symbol_value (symbol_in); - - switch (r_type) - { - case R_SH_IMM32: -#ifdef COFF_WITH_PE - case R_SH_IMM32CE: -#endif - insn = bfd_get_32 (abfd, hit_data); - insn += sym_value + reloc_entry->addend; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); - break; -#ifdef COFF_WITH_PE - case R_SH_IMAGEBASE: - insn = bfd_get_32 (abfd, hit_data); - insn += sym_value + reloc_entry->addend; - insn -= pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); - break; -#endif - case R_SH_PCDISP: - insn = bfd_get_16 (abfd, hit_data); - sym_value += reloc_entry->addend; - sym_value -= (input_section->output_section->vma - + input_section->output_offset - + addr - + 4); - sym_value += (insn & 0xfff) << 1; - if (insn & 0x800) - sym_value -= 0x1000; - insn = (insn & 0xf000) | (sym_value & 0xfff); - bfd_put_16 (abfd, (bfd_vma) insn, hit_data); - if (sym_value < (bfd_vma) -0x1000 || sym_value >= 0x1000) - return bfd_reloc_overflow; - break; - default: - abort (); - break; - } - - return bfd_reloc_ok; -} - -#define coff_bfd_merge_private_bfd_data _bfd_generic_verify_endian_match - -/* We can do relaxing. */ -#define coff_bfd_relax_section sh_relax_section - -/* We use the special COFF backend linker. */ -#define coff_relocate_section sh_relocate_section - -/* When relaxing, we need to use special code to get the relocated - section contents. */ -#define coff_bfd_get_relocated_section_contents \ - sh_coff_get_relocated_section_contents - -#include "coffcode.h" - -static bfd_boolean -sh_relax_delete_bytes (bfd *, asection *, bfd_vma, int); - -/* This function handles relaxing on the SH. - - Function calls on the SH look like this: - - movl L1,r0 - ... - jsr @r0 - ... - L1: - .long function - - The compiler and assembler will cooperate to create R_SH_USES - relocs on the jsr instructions. The r_offset field of the - R_SH_USES reloc is the PC relative offset to the instruction which - loads the register (the r_offset field is computed as though it - were a jump instruction, so the offset value is actually from four - bytes past the instruction). The linker can use this reloc to - determine just which function is being called, and thus decide - whether it is possible to replace the jsr with a bsr. - - If multiple function calls are all based on a single register load - (i.e., the same function is called multiple times), the compiler - guarantees that each function call will have an R_SH_USES reloc. - Therefore, if the linker is able to convert each R_SH_USES reloc - which refers to that address, it can safely eliminate the register - load. - - When the assembler creates an R_SH_USES reloc, it examines it to - determine which address is being loaded (L1 in the above example). - It then counts the number of references to that address, and - creates an R_SH_COUNT reloc at that address. The r_offset field of - the R_SH_COUNT reloc will be the number of references. If the - linker is able to eliminate a register load, it can use the - R_SH_COUNT reloc to see whether it can also eliminate the function - address. - - SH relaxing also handles another, unrelated, matter. On the SH, if - a load or store instruction is not aligned on a four byte boundary, - the memory cycle interferes with the 32 bit instruction fetch, - causing a one cycle bubble in the pipeline. Therefore, we try to - align load and store instructions on four byte boundaries if we - can, by swapping them with one of the adjacent instructions. */ - -static bfd_boolean -sh_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - struct internal_reloc *internal_relocs; - bfd_boolean have_code; - struct internal_reloc *irel, *irelend; - bfd_byte *contents = NULL; - - *again = FALSE; - - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0) - return TRUE; - - if (coff_section_data (abfd, sec) == NULL) - { - bfd_size_type amt = sizeof (struct coff_section_tdata); - sec->used_by_bfd = bfd_zalloc (abfd, amt); - if (sec->used_by_bfd == NULL) - return FALSE; - } - - internal_relocs = (_bfd_coff_read_internal_relocs - (abfd, sec, link_info->keep_memory, - (bfd_byte *) NULL, FALSE, - (struct internal_reloc *) NULL)); - if (internal_relocs == NULL) - goto error_return; - - have_code = FALSE; - - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma laddr, paddr, symval; - unsigned short insn; - struct internal_reloc *irelfn, *irelscan, *irelcount; - struct internal_syment sym; - bfd_signed_vma foff; - - if (irel->r_type == R_SH_CODE) - have_code = TRUE; - - if (irel->r_type != R_SH_USES) - continue; - - /* Get the section contents. */ - if (contents == NULL) - { - if (coff_section_data (abfd, sec)->contents != NULL) - contents = coff_section_data (abfd, sec)->contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* The r_offset field of the R_SH_USES reloc will point us to - the register load. The 4 is because the r_offset field is - computed as though it were a jump offset, which are based - from 4 bytes after the jump instruction. */ - laddr = irel->r_vaddr - sec->vma + 4; - /* Careful to sign extend the 32-bit offset. */ - laddr += ((irel->r_offset & 0xffffffff) ^ 0x80000000) - 0x80000000; - if (laddr >= sec->size) - { - /* xgettext: c-format */ - _bfd_error_handler (_("%B: %#Lx: warning: bad R_SH_USES offset"), - abfd, irel->r_vaddr); - continue; - } - insn = bfd_get_16 (abfd, contents + laddr); - - /* If the instruction is not mov.l NN,rN, we don't know what to do. */ - if ((insn & 0xf000) != 0xd000) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: warning: R_SH_USES points to unrecognized insn %#x"), - abfd, irel->r_vaddr, insn); - continue; - } - - /* Get the address from which the register is being loaded. The - displacement in the mov.l instruction is quadrupled. It is a - displacement from four bytes after the movl instruction, but, - before adding in the PC address, two least significant bits - of the PC are cleared. We assume that the section is aligned - on a four byte boundary. */ - paddr = insn & 0xff; - paddr *= 4; - paddr += (laddr + 4) &~ (bfd_vma) 3; - if (paddr >= sec->size) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: warning: bad R_SH_USES load offset"), - abfd, irel->r_vaddr); - continue; - } - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - paddr += sec->vma; - for (irelfn = internal_relocs; irelfn < irelend; irelfn++) - if (irelfn->r_vaddr == paddr -#ifdef COFF_WITH_PE - && (irelfn->r_type == R_SH_IMM32 - || irelfn->r_type == R_SH_IMM32CE - || irelfn->r_type == R_SH_IMAGEBASE) - -#else - && irelfn->r_type == R_SH_IMM32 -#endif - ) - break; - if (irelfn >= irelend) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: warning: could not find expected reloc"), - abfd, paddr); - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (! _bfd_coff_get_external_symbols (abfd)) - goto error_return; - bfd_coff_swap_sym_in (abfd, - ((bfd_byte *) obj_coff_external_syms (abfd) - + (irelfn->r_symndx - * bfd_coff_symesz (abfd))), - &sym); - if (sym.n_scnum != 0 && sym.n_scnum != sec->target_index) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: warning: symbol in unexpected section"), - abfd, paddr); - continue; - } - - if (sym.n_sclass != C_EXT) - { - symval = (sym.n_value - - sec->vma - + sec->output_section->vma - + sec->output_offset); - } - else - { - struct coff_link_hash_entry *h; - - h = obj_coff_sym_hashes (abfd)[irelfn->r_symndx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - } - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - symval += bfd_get_32 (abfd, contents + paddr - sec->vma); - - /* See if this function call can be shortened. */ - foff = (symval - - (irel->r_vaddr - - sec->vma - + sec->output_section->vma - + sec->output_offset - + 4)); - if (foff < -0x1000 || foff >= 0x1000) - { - /* After all that work, we can't shorten this function call. */ - continue; - } - - /* Shorten the function call. */ - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - coff_section_data (abfd, sec)->relocs = internal_relocs; - coff_section_data (abfd, sec)->keep_relocs = TRUE; - - coff_section_data (abfd, sec)->contents = contents; - coff_section_data (abfd, sec)->keep_contents = TRUE; - - obj_coff_keep_syms (abfd) = TRUE; - - /* Replace the jsr with a bsr. */ - - /* Change the R_SH_USES reloc into an R_SH_PCDISP reloc, and - replace the jsr with a bsr. */ - irel->r_type = R_SH_PCDISP; - irel->r_symndx = irelfn->r_symndx; - if (sym.n_sclass != C_EXT) - { - /* If this needs to be changed because of future relaxing, - it will be handled here like other internal PCDISP - relocs. */ - bfd_put_16 (abfd, - (bfd_vma) 0xb000 | ((foff >> 1) & 0xfff), - contents + irel->r_vaddr - sec->vma); - } - else - { - /* We can't fully resolve this yet, because the external - symbol value may be changed by future relaxing. We let - the final link phase handle it. */ - bfd_put_16 (abfd, (bfd_vma) 0xb000, - contents + irel->r_vaddr - sec->vma); - } - - /* See if there is another R_SH_USES reloc referring to the same - register load. */ - for (irelscan = internal_relocs; irelscan < irelend; irelscan++) - if (irelscan->r_type == R_SH_USES - && laddr == irelscan->r_vaddr - sec->vma + 4 + irelscan->r_offset) - break; - if (irelscan < irelend) - { - /* Some other function call depends upon this register load, - and we have not yet converted that function call. - Indeed, we may never be able to convert it. There is - nothing else we can do at this point. */ - continue; - } - - /* Look for a R_SH_COUNT reloc on the location where the - function address is stored. Do this before deleting any - bytes, to avoid confusion about the address. */ - for (irelcount = internal_relocs; irelcount < irelend; irelcount++) - if (irelcount->r_vaddr == paddr - && irelcount->r_type == R_SH_COUNT) - break; - - /* Delete the register load. */ - if (! sh_relax_delete_bytes (abfd, sec, laddr, 2)) - goto error_return; - - /* That will change things, so, just in case it permits some - other function call to come within range, we should relax - again. Note that this is not required, and it may be slow. */ - *again = TRUE; - - /* Now check whether we got a COUNT reloc. */ - if (irelcount >= irelend) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: warning: could not find expected COUNT reloc"), - abfd, paddr); - continue; - } - - /* The number of uses is stored in the r_offset field. We've - just deleted one. */ - if (irelcount->r_offset == 0) - { - /* xgettext: c-format */ - _bfd_error_handler (_("%B: %#Lx: warning: bad count"), - abfd, paddr); - continue; - } - - --irelcount->r_offset; - - /* If there are no more uses, we can delete the address. Reload - the address from irelfn, in case it was changed by the - previous call to sh_relax_delete_bytes. */ - if (irelcount->r_offset == 0) - { - if (! sh_relax_delete_bytes (abfd, sec, - irelfn->r_vaddr - sec->vma, 4)) - goto error_return; - } - - /* We've done all we can with that function call. */ - } - - /* Look for load and store instructions that we can align on four - byte boundaries. */ - if (have_code) - { - bfd_boolean swapped; - - /* Get the section contents. */ - if (contents == NULL) - { - if (coff_section_data (abfd, sec)->contents != NULL) - contents = coff_section_data (abfd, sec)->contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - if (! sh_align_loads (abfd, sec, internal_relocs, contents, &swapped)) - goto error_return; - - if (swapped) - { - coff_section_data (abfd, sec)->relocs = internal_relocs; - coff_section_data (abfd, sec)->keep_relocs = TRUE; - - coff_section_data (abfd, sec)->contents = contents; - coff_section_data (abfd, sec)->keep_contents = TRUE; - - obj_coff_keep_syms (abfd) = TRUE; - } - } - - if (internal_relocs != NULL - && internal_relocs != coff_section_data (abfd, sec)->relocs) - { - if (! link_info->keep_memory) - free (internal_relocs); - else - coff_section_data (abfd, sec)->relocs = internal_relocs; - } - - if (contents != NULL && contents != coff_section_data (abfd, sec)->contents) - { - if (! link_info->keep_memory) - free (contents); - else - /* Cache the section contents for coff_link_input_bfd. */ - coff_section_data (abfd, sec)->contents = contents; - } - - return TRUE; - - error_return: - if (internal_relocs != NULL - && internal_relocs != coff_section_data (abfd, sec)->relocs) - free (internal_relocs); - if (contents != NULL && contents != coff_section_data (abfd, sec)->contents) - free (contents); - return FALSE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -sh_relax_delete_bytes (bfd *abfd, - asection *sec, - bfd_vma addr, - int count) -{ - bfd_byte *contents; - struct internal_reloc *irel, *irelend; - struct internal_reloc *irelalign; - bfd_vma toaddr; - bfd_byte *esym, *esymend; - bfd_size_type symesz; - struct coff_link_hash_entry **sym_hash; - asection *o; - - contents = coff_section_data (abfd, sec)->contents; - - /* The deletion must stop at the next ALIGN reloc for an alignment - power larger than the number of bytes we are deleting. */ - - irelalign = NULL; - toaddr = sec->size; - - irel = coff_section_data (abfd, sec)->relocs; - irelend = irel + sec->reloc_count; - for (; irel < irelend; irel++) - { - if (irel->r_type == R_SH_ALIGN - && irel->r_vaddr - sec->vma > addr - && count < (1 << irel->r_offset)) - { - irelalign = irel; - toaddr = irel->r_vaddr - sec->vma; - break; - } - } - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - if (irelalign == NULL) - sec->size -= count; - else - { - int i; - -#define NOP_OPCODE (0x0009) - - BFD_ASSERT ((count & 1) == 0); - for (i = 0; i < count; i += 2) - bfd_put_16 (abfd, (bfd_vma) NOP_OPCODE, contents + toaddr - count + i); - } - - /* Adjust all the relocs. */ - for (irel = coff_section_data (abfd, sec)->relocs; irel < irelend; irel++) - { - bfd_vma nraddr, stop; - bfd_vma start = 0; - int insn = 0; - struct internal_syment sym; - int off, adjust, oinsn; - bfd_signed_vma voff = 0; - bfd_boolean overflow; - - /* Get the new reloc address. */ - nraddr = irel->r_vaddr - sec->vma; - if ((irel->r_vaddr - sec->vma > addr - && irel->r_vaddr - sec->vma < toaddr) - || (irel->r_type == R_SH_ALIGN - && irel->r_vaddr - sec->vma == toaddr)) - nraddr -= count; - - /* See if this reloc was for the bytes we have deleted, in which - case we no longer care about it. Don't delete relocs which - represent addresses, though. */ - if (irel->r_vaddr - sec->vma >= addr - && irel->r_vaddr - sec->vma < addr + count - && irel->r_type != R_SH_ALIGN - && irel->r_type != R_SH_CODE - && irel->r_type != R_SH_DATA - && irel->r_type != R_SH_LABEL) - irel->r_type = R_SH_UNUSED; - - /* If this is a PC relative reloc, see if the range it covers - includes the bytes we have deleted. */ - switch (irel->r_type) - { - default: - break; - - case R_SH_PCDISP8BY2: - case R_SH_PCDISP: - case R_SH_PCRELIMM8BY2: - case R_SH_PCRELIMM8BY4: - start = irel->r_vaddr - sec->vma; - insn = bfd_get_16 (abfd, contents + nraddr); - break; - } - - switch (irel->r_type) - { - default: - start = stop = addr; - break; - - case R_SH_IMM32: -#ifdef COFF_WITH_PE - case R_SH_IMM32CE: - case R_SH_IMAGEBASE: -#endif - /* If this reloc is against a symbol defined in this - section, and the symbol will not be adjusted below, we - must check the addend to see it will put the value in - range to be adjusted, and hence must be changed. */ - bfd_coff_swap_sym_in (abfd, - ((bfd_byte *) obj_coff_external_syms (abfd) - + (irel->r_symndx - * bfd_coff_symesz (abfd))), - &sym); - if (sym.n_sclass != C_EXT - && sym.n_scnum == sec->target_index - && ((bfd_vma) sym.n_value <= addr - || (bfd_vma) sym.n_value >= toaddr)) - { - bfd_vma val; - - val = bfd_get_32 (abfd, contents + nraddr); - val += sym.n_value; - if (val > addr && val < toaddr) - bfd_put_32 (abfd, val - count, contents + nraddr); - } - start = stop = addr; - break; - - case R_SH_PCDISP8BY2: - off = insn & 0xff; - if (off & 0x80) - off -= 0x100; - stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); - break; - - case R_SH_PCDISP: - bfd_coff_swap_sym_in (abfd, - ((bfd_byte *) obj_coff_external_syms (abfd) - + (irel->r_symndx - * bfd_coff_symesz (abfd))), - &sym); - if (sym.n_sclass == C_EXT) - start = stop = addr; - else - { - off = insn & 0xfff; - if (off & 0x800) - off -= 0x1000; - stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); - } - break; - - case R_SH_PCRELIMM8BY2: - off = insn & 0xff; - stop = start + 4 + off * 2; - break; - - case R_SH_PCRELIMM8BY4: - off = insn & 0xff; - stop = (start &~ (bfd_vma) 3) + 4 + off * 4; - break; - - case R_SH_SWITCH8: - case R_SH_SWITCH16: - case R_SH_SWITCH32: - /* These relocs types represent - .word L2-L1 - The r_offset field holds the difference between the reloc - address and L1. That is the start of the reloc, and - adding in the contents gives us the top. We must adjust - both the r_offset field and the section contents. */ - - start = irel->r_vaddr - sec->vma; - stop = (bfd_vma) ((bfd_signed_vma) start - (long) irel->r_offset); - - if (start > addr - && start < toaddr - && (stop <= addr || stop >= toaddr)) - irel->r_offset += count; - else if (stop > addr - && stop < toaddr - && (start <= addr || start >= toaddr)) - irel->r_offset -= count; - - start = stop; - - if (irel->r_type == R_SH_SWITCH16) - voff = bfd_get_signed_16 (abfd, contents + nraddr); - else if (irel->r_type == R_SH_SWITCH8) - voff = bfd_get_8 (abfd, contents + nraddr); - else - voff = bfd_get_signed_32 (abfd, contents + nraddr); - stop = (bfd_vma) ((bfd_signed_vma) start + voff); - - break; - - case R_SH_USES: - start = irel->r_vaddr - sec->vma; - stop = (bfd_vma) ((bfd_signed_vma) start - + (long) irel->r_offset - + 4); - break; - } - - if (start > addr - && start < toaddr - && (stop <= addr || stop >= toaddr)) - adjust = count; - else if (stop > addr - && stop < toaddr - && (start <= addr || start >= toaddr)) - adjust = - count; - else - adjust = 0; - - if (adjust != 0) - { - oinsn = insn; - overflow = FALSE; - switch (irel->r_type) - { - default: - abort (); - break; - - case R_SH_PCDISP8BY2: - case R_SH_PCRELIMM8BY2: - insn += adjust / 2; - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr); - break; - - case R_SH_PCDISP: - insn += adjust / 2; - if ((oinsn & 0xf000) != (insn & 0xf000)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr); - break; - - case R_SH_PCRELIMM8BY4: - BFD_ASSERT (adjust == count || count >= 4); - if (count >= 4) - insn += adjust / 4; - else - { - if ((irel->r_vaddr & 3) == 0) - ++insn; - } - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr); - break; - - case R_SH_SWITCH8: - voff += adjust; - if (voff < 0 || voff >= 0xff) - overflow = TRUE; - bfd_put_8 (abfd, (bfd_vma) voff, contents + nraddr); - break; - - case R_SH_SWITCH16: - voff += adjust; - if (voff < - 0x8000 || voff >= 0x8000) - overflow = TRUE; - bfd_put_signed_16 (abfd, (bfd_vma) voff, contents + nraddr); - break; - - case R_SH_SWITCH32: - voff += adjust; - bfd_put_signed_32 (abfd, (bfd_vma) voff, contents + nraddr); - break; - - case R_SH_USES: - irel->r_offset += adjust; - break; - } - - if (overflow) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: fatal: reloc overflow while relaxing"), - abfd, irel->r_vaddr); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - irel->r_vaddr = nraddr + sec->vma; - } - - /* Look through all the other sections. If there contain any IMM32 - relocs against internal symbols which we are not going to adjust - below, we may need to adjust the addends. */ - for (o = abfd->sections; o != NULL; o = o->next) - { - struct internal_reloc *internal_relocs; - struct internal_reloc *irelscan, *irelscanend; - bfd_byte *ocontents; - - if (o == sec - || (o->flags & SEC_RELOC) == 0 - || o->reloc_count == 0) - continue; - - /* We always cache the relocs. Perhaps, if info->keep_memory is - FALSE, we should free them, if we are permitted to, when we - leave sh_coff_relax_section. */ - internal_relocs = (_bfd_coff_read_internal_relocs - (abfd, o, TRUE, (bfd_byte *) NULL, FALSE, - (struct internal_reloc *) NULL)); - if (internal_relocs == NULL) - return FALSE; - - ocontents = NULL; - irelscanend = internal_relocs + o->reloc_count; - for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++) - { - struct internal_syment sym; - -#ifdef COFF_WITH_PE - if (irelscan->r_type != R_SH_IMM32 - && irelscan->r_type != R_SH_IMAGEBASE - && irelscan->r_type != R_SH_IMM32CE) -#else - if (irelscan->r_type != R_SH_IMM32) -#endif - continue; - - bfd_coff_swap_sym_in (abfd, - ((bfd_byte *) obj_coff_external_syms (abfd) - + (irelscan->r_symndx - * bfd_coff_symesz (abfd))), - &sym); - if (sym.n_sclass != C_EXT - && sym.n_scnum == sec->target_index - && ((bfd_vma) sym.n_value <= addr - || (bfd_vma) sym.n_value >= toaddr)) - { - bfd_vma val; - - if (ocontents == NULL) - { - if (coff_section_data (abfd, o)->contents != NULL) - ocontents = coff_section_data (abfd, o)->contents; - else - { - if (!bfd_malloc_and_get_section (abfd, o, &ocontents)) - return FALSE; - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to, - when we leave sh_coff_relax_section. */ - coff_section_data (abfd, o)->contents = ocontents; - } - } - - val = bfd_get_32 (abfd, ocontents + irelscan->r_vaddr - o->vma); - val += sym.n_value; - if (val > addr && val < toaddr) - bfd_put_32 (abfd, val - count, - ocontents + irelscan->r_vaddr - o->vma); - - coff_section_data (abfd, o)->keep_contents = TRUE; - } - } - } - - /* Adjusting the internal symbols will not work if something has - already retrieved the generic symbols. It would be possible to - make this work by adjusting the generic symbols at the same time. - However, this case should not arise in normal usage. */ - if (obj_symbols (abfd) != NULL - || obj_raw_syments (abfd) != NULL) - { - _bfd_error_handler - (_("%B: fatal: generic symbols retrieved before relaxing"), abfd); - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - /* Adjust all the symbols. */ - sym_hash = obj_coff_sym_hashes (abfd); - symesz = bfd_coff_symesz (abfd); - esym = (bfd_byte *) obj_coff_external_syms (abfd); - esymend = esym + obj_raw_syment_count (abfd) * symesz; - while (esym < esymend) - { - struct internal_syment isym; - - bfd_coff_swap_sym_in (abfd, esym, &isym); - - if (isym.n_scnum == sec->target_index - && (bfd_vma) isym.n_value > addr - && (bfd_vma) isym.n_value < toaddr) - { - isym.n_value -= count; - - bfd_coff_swap_sym_out (abfd, &isym, esym); - - if (*sym_hash != NULL) - { - BFD_ASSERT ((*sym_hash)->root.type == bfd_link_hash_defined - || (*sym_hash)->root.type == bfd_link_hash_defweak); - BFD_ASSERT ((*sym_hash)->root.u.def.value >= addr - && (*sym_hash)->root.u.def.value < toaddr); - (*sym_hash)->root.u.def.value -= count; - } - } - - esym += (isym.n_numaux + 1) * symesz; - sym_hash += isym.n_numaux + 1; - } - - /* See if we can move the ALIGN reloc forward. We have adjusted - r_vaddr for it already. */ - if (irelalign != NULL) - { - bfd_vma alignto, alignaddr; - - alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_offset); - alignaddr = BFD_ALIGN (irelalign->r_vaddr - sec->vma, - 1 << irelalign->r_offset); - if (alignto != alignaddr) - { - /* Tail recursion. */ - return sh_relax_delete_bytes (abfd, sec, alignaddr, - (int) (alignto - alignaddr)); - } - } - - return TRUE; -} - -/* This is yet another version of the SH opcode table, used to rapidly - get information about a particular instruction. */ - -/* The opcode map is represented by an array of these structures. The - array is indexed by the high order four bits in the instruction. */ - -struct sh_major_opcode -{ - /* A pointer to the instruction list. This is an array which - contains all the instructions with this major opcode. */ - const struct sh_minor_opcode *minor_opcodes; - /* The number of elements in minor_opcodes. */ - unsigned short count; -}; - -/* This structure holds information for a set of SH opcodes. The - instruction code is anded with the mask value, and the resulting - value is used to search the order opcode list. */ - -struct sh_minor_opcode -{ - /* The sorted opcode list. */ - const struct sh_opcode *opcodes; - /* The number of elements in opcodes. */ - unsigned short count; - /* The mask value to use when searching the opcode list. */ - unsigned short mask; -}; - -/* This structure holds information for an SH instruction. An array - of these structures is sorted in order by opcode. */ - -struct sh_opcode -{ - /* The code for this instruction, after it has been anded with the - mask value in the sh_major_opcode structure. */ - unsigned short opcode; - /* Flags for this instruction. */ - unsigned long flags; -}; - -/* Flag which appear in the sh_opcode structure. */ - -/* This instruction loads a value from memory. */ -#define LOAD (0x1) - -/* This instruction stores a value to memory. */ -#define STORE (0x2) - -/* This instruction is a branch. */ -#define BRANCH (0x4) - -/* This instruction has a delay slot. */ -#define DELAY (0x8) - -/* This instruction uses the value in the register in the field at - mask 0x0f00 of the instruction. */ -#define USES1 (0x10) -#define USES1_REG(x) ((x & 0x0f00) >> 8) - -/* This instruction uses the value in the register in the field at - mask 0x00f0 of the instruction. */ -#define USES2 (0x20) -#define USES2_REG(x) ((x & 0x00f0) >> 4) - -/* This instruction uses the value in register 0. */ -#define USESR0 (0x40) - -/* This instruction sets the value in the register in the field at - mask 0x0f00 of the instruction. */ -#define SETS1 (0x80) -#define SETS1_REG(x) ((x & 0x0f00) >> 8) - -/* This instruction sets the value in the register in the field at - mask 0x00f0 of the instruction. */ -#define SETS2 (0x100) -#define SETS2_REG(x) ((x & 0x00f0) >> 4) - -/* This instruction sets register 0. */ -#define SETSR0 (0x200) - -/* This instruction sets a special register. */ -#define SETSSP (0x400) - -/* This instruction uses a special register. */ -#define USESSP (0x800) - -/* This instruction uses the floating point register in the field at - mask 0x0f00 of the instruction. */ -#define USESF1 (0x1000) -#define USESF1_REG(x) ((x & 0x0f00) >> 8) - -/* This instruction uses the floating point register in the field at - mask 0x00f0 of the instruction. */ -#define USESF2 (0x2000) -#define USESF2_REG(x) ((x & 0x00f0) >> 4) - -/* This instruction uses floating point register 0. */ -#define USESF0 (0x4000) - -/* This instruction sets the floating point register in the field at - mask 0x0f00 of the instruction. */ -#define SETSF1 (0x8000) -#define SETSF1_REG(x) ((x & 0x0f00) >> 8) - -#define USESAS (0x10000) -#define USESAS_REG(x) (((((x) >> 8) - 2) & 3) + 2) -#define USESR8 (0x20000) -#define SETSAS (0x40000) -#define SETSAS_REG(x) USESAS_REG (x) - -#define MAP(a) a, sizeof a / sizeof a[0] - -#ifndef COFF_IMAGE_WITH_PE - -/* The opcode maps. */ - -static const struct sh_opcode sh_opcode00[] = -{ - { 0x0008, SETSSP }, /* clrt */ - { 0x0009, 0 }, /* nop */ - { 0x000b, BRANCH | DELAY | USESSP }, /* rts */ - { 0x0018, SETSSP }, /* sett */ - { 0x0019, SETSSP }, /* div0u */ - { 0x001b, 0 }, /* sleep */ - { 0x0028, SETSSP }, /* clrmac */ - { 0x002b, BRANCH | DELAY | SETSSP }, /* rte */ - { 0x0038, USESSP | SETSSP }, /* ldtlb */ - { 0x0048, SETSSP }, /* clrs */ - { 0x0058, SETSSP } /* sets */ -}; - -static const struct sh_opcode sh_opcode01[] = -{ - { 0x0003, BRANCH | DELAY | USES1 | SETSSP }, /* bsrf rn */ - { 0x000a, SETS1 | USESSP }, /* sts mach,rn */ - { 0x001a, SETS1 | USESSP }, /* sts macl,rn */ - { 0x0023, BRANCH | DELAY | USES1 }, /* braf rn */ - { 0x0029, SETS1 | USESSP }, /* movt rn */ - { 0x002a, SETS1 | USESSP }, /* sts pr,rn */ - { 0x005a, SETS1 | USESSP }, /* sts fpul,rn */ - { 0x006a, SETS1 | USESSP }, /* sts fpscr,rn / sts dsr,rn */ - { 0x0083, LOAD | USES1 }, /* pref @rn */ - { 0x007a, SETS1 | USESSP }, /* sts a0,rn */ - { 0x008a, SETS1 | USESSP }, /* sts x0,rn */ - { 0x009a, SETS1 | USESSP }, /* sts x1,rn */ - { 0x00aa, SETS1 | USESSP }, /* sts y0,rn */ - { 0x00ba, SETS1 | USESSP } /* sts y1,rn */ -}; - -static const struct sh_opcode sh_opcode02[] = -{ - { 0x0002, SETS1 | USESSP }, /* stc ,rn */ - { 0x0004, STORE | USES1 | USES2 | USESR0 }, /* mov.b rm,@(r0,rn) */ - { 0x0005, STORE | USES1 | USES2 | USESR0 }, /* mov.w rm,@(r0,rn) */ - { 0x0006, STORE | USES1 | USES2 | USESR0 }, /* mov.l rm,@(r0,rn) */ - { 0x0007, SETSSP | USES1 | USES2 }, /* mul.l rm,rn */ - { 0x000c, LOAD | SETS1 | USES2 | USESR0 }, /* mov.b @(r0,rm),rn */ - { 0x000d, LOAD | SETS1 | USES2 | USESR0 }, /* mov.w @(r0,rm),rn */ - { 0x000e, LOAD | SETS1 | USES2 | USESR0 }, /* mov.l @(r0,rm),rn */ - { 0x000f, LOAD|SETS1|SETS2|SETSSP|USES1|USES2|USESSP }, /* mac.l @rm+,@rn+ */ -}; - -static const struct sh_minor_opcode sh_opcode0[] = -{ - { MAP (sh_opcode00), 0xffff }, - { MAP (sh_opcode01), 0xf0ff }, - { MAP (sh_opcode02), 0xf00f } -}; - -static const struct sh_opcode sh_opcode10[] = -{ - { 0x1000, STORE | USES1 | USES2 } /* mov.l rm,@(disp,rn) */ -}; - -static const struct sh_minor_opcode sh_opcode1[] = -{ - { MAP (sh_opcode10), 0xf000 } -}; - -static const struct sh_opcode sh_opcode20[] = -{ - { 0x2000, STORE | USES1 | USES2 }, /* mov.b rm,@rn */ - { 0x2001, STORE | USES1 | USES2 }, /* mov.w rm,@rn */ - { 0x2002, STORE | USES1 | USES2 }, /* mov.l rm,@rn */ - { 0x2004, STORE | SETS1 | USES1 | USES2 }, /* mov.b rm,@-rn */ - { 0x2005, STORE | SETS1 | USES1 | USES2 }, /* mov.w rm,@-rn */ - { 0x2006, STORE | SETS1 | USES1 | USES2 }, /* mov.l rm,@-rn */ - { 0x2007, SETSSP | USES1 | USES2 | USESSP }, /* div0s */ - { 0x2008, SETSSP | USES1 | USES2 }, /* tst rm,rn */ - { 0x2009, SETS1 | USES1 | USES2 }, /* and rm,rn */ - { 0x200a, SETS1 | USES1 | USES2 }, /* xor rm,rn */ - { 0x200b, SETS1 | USES1 | USES2 }, /* or rm,rn */ - { 0x200c, SETSSP | USES1 | USES2 }, /* cmp/str rm,rn */ - { 0x200d, SETS1 | USES1 | USES2 }, /* xtrct rm,rn */ - { 0x200e, SETSSP | USES1 | USES2 }, /* mulu.w rm,rn */ - { 0x200f, SETSSP | USES1 | USES2 } /* muls.w rm,rn */ -}; - -static const struct sh_minor_opcode sh_opcode2[] = -{ - { MAP (sh_opcode20), 0xf00f } -}; - -static const struct sh_opcode sh_opcode30[] = -{ - { 0x3000, SETSSP | USES1 | USES2 }, /* cmp/eq rm,rn */ - { 0x3002, SETSSP | USES1 | USES2 }, /* cmp/hs rm,rn */ - { 0x3003, SETSSP | USES1 | USES2 }, /* cmp/ge rm,rn */ - { 0x3004, SETSSP | USESSP | USES1 | USES2 }, /* div1 rm,rn */ - { 0x3005, SETSSP | USES1 | USES2 }, /* dmulu.l rm,rn */ - { 0x3006, SETSSP | USES1 | USES2 }, /* cmp/hi rm,rn */ - { 0x3007, SETSSP | USES1 | USES2 }, /* cmp/gt rm,rn */ - { 0x3008, SETS1 | USES1 | USES2 }, /* sub rm,rn */ - { 0x300a, SETS1 | SETSSP | USES1 | USES2 | USESSP }, /* subc rm,rn */ - { 0x300b, SETS1 | SETSSP | USES1 | USES2 }, /* subv rm,rn */ - { 0x300c, SETS1 | USES1 | USES2 }, /* add rm,rn */ - { 0x300d, SETSSP | USES1 | USES2 }, /* dmuls.l rm,rn */ - { 0x300e, SETS1 | SETSSP | USES1 | USES2 | USESSP }, /* addc rm,rn */ - { 0x300f, SETS1 | SETSSP | USES1 | USES2 } /* addv rm,rn */ -}; - -static const struct sh_minor_opcode sh_opcode3[] = -{ - { MAP (sh_opcode30), 0xf00f } -}; - -static const struct sh_opcode sh_opcode40[] = -{ - { 0x4000, SETS1 | SETSSP | USES1 }, /* shll rn */ - { 0x4001, SETS1 | SETSSP | USES1 }, /* shlr rn */ - { 0x4002, STORE | SETS1 | USES1 | USESSP }, /* sts.l mach,@-rn */ - { 0x4004, SETS1 | SETSSP | USES1 }, /* rotl rn */ - { 0x4005, SETS1 | SETSSP | USES1 }, /* rotr rn */ - { 0x4006, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,mach */ - { 0x4008, SETS1 | USES1 }, /* shll2 rn */ - { 0x4009, SETS1 | USES1 }, /* shlr2 rn */ - { 0x400a, SETSSP | USES1 }, /* lds rm,mach */ - { 0x400b, BRANCH | DELAY | USES1 }, /* jsr @rn */ - { 0x4010, SETS1 | SETSSP | USES1 }, /* dt rn */ - { 0x4011, SETSSP | USES1 }, /* cmp/pz rn */ - { 0x4012, STORE | SETS1 | USES1 | USESSP }, /* sts.l macl,@-rn */ - { 0x4014, SETSSP | USES1 }, /* setrc rm */ - { 0x4015, SETSSP | USES1 }, /* cmp/pl rn */ - { 0x4016, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,macl */ - { 0x4018, SETS1 | USES1 }, /* shll8 rn */ - { 0x4019, SETS1 | USES1 }, /* shlr8 rn */ - { 0x401a, SETSSP | USES1 }, /* lds rm,macl */ - { 0x401b, LOAD | SETSSP | USES1 }, /* tas.b @rn */ - { 0x4020, SETS1 | SETSSP | USES1 }, /* shal rn */ - { 0x4021, SETS1 | SETSSP | USES1 }, /* shar rn */ - { 0x4022, STORE | SETS1 | USES1 | USESSP }, /* sts.l pr,@-rn */ - { 0x4024, SETS1 | SETSSP | USES1 | USESSP }, /* rotcl rn */ - { 0x4025, SETS1 | SETSSP | USES1 | USESSP }, /* rotcr rn */ - { 0x4026, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,pr */ - { 0x4028, SETS1 | USES1 }, /* shll16 rn */ - { 0x4029, SETS1 | USES1 }, /* shlr16 rn */ - { 0x402a, SETSSP | USES1 }, /* lds rm,pr */ - { 0x402b, BRANCH | DELAY | USES1 }, /* jmp @rn */ - { 0x4052, STORE | SETS1 | USES1 | USESSP }, /* sts.l fpul,@-rn */ - { 0x4056, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,fpul */ - { 0x405a, SETSSP | USES1 }, /* lds.l rm,fpul */ - { 0x4062, STORE | SETS1 | USES1 | USESSP }, /* sts.l fpscr / dsr,@-rn */ - { 0x4066, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,fpscr / dsr */ - { 0x406a, SETSSP | USES1 }, /* lds rm,fpscr / lds rm,dsr */ - { 0x4072, STORE | SETS1 | USES1 | USESSP }, /* sts.l a0,@-rn */ - { 0x4076, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,a0 */ - { 0x407a, SETSSP | USES1 }, /* lds.l rm,a0 */ - { 0x4082, STORE | SETS1 | USES1 | USESSP }, /* sts.l x0,@-rn */ - { 0x4086, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,x0 */ - { 0x408a, SETSSP | USES1 }, /* lds.l rm,x0 */ - { 0x4092, STORE | SETS1 | USES1 | USESSP }, /* sts.l x1,@-rn */ - { 0x4096, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,x1 */ - { 0x409a, SETSSP | USES1 }, /* lds.l rm,x1 */ - { 0x40a2, STORE | SETS1 | USES1 | USESSP }, /* sts.l y0,@-rn */ - { 0x40a6, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,y0 */ - { 0x40aa, SETSSP | USES1 }, /* lds.l rm,y0 */ - { 0x40b2, STORE | SETS1 | USES1 | USESSP }, /* sts.l y1,@-rn */ - { 0x40b6, LOAD | SETS1 | SETSSP | USES1 }, /* lds.l @rm+,y1 */ - { 0x40ba, SETSSP | USES1 } /* lds.l rm,y1 */ -}; - -static const struct sh_opcode sh_opcode41[] = -{ - { 0x4003, STORE | SETS1 | USES1 | USESSP }, /* stc.l ,@-rn */ - { 0x4007, LOAD | SETS1 | SETSSP | USES1 }, /* ldc.l @rm+, */ - { 0x400c, SETS1 | USES1 | USES2 }, /* shad rm,rn */ - { 0x400d, SETS1 | USES1 | USES2 }, /* shld rm,rn */ - { 0x400e, SETSSP | USES1 }, /* ldc rm, */ - { 0x400f, LOAD|SETS1|SETS2|SETSSP|USES1|USES2|USESSP }, /* mac.w @rm+,@rn+ */ -}; - -static const struct sh_minor_opcode sh_opcode4[] = -{ - { MAP (sh_opcode40), 0xf0ff }, - { MAP (sh_opcode41), 0xf00f } -}; - -static const struct sh_opcode sh_opcode50[] = -{ - { 0x5000, LOAD | SETS1 | USES2 } /* mov.l @(disp,rm),rn */ -}; - -static const struct sh_minor_opcode sh_opcode5[] = -{ - { MAP (sh_opcode50), 0xf000 } -}; - -static const struct sh_opcode sh_opcode60[] = -{ - { 0x6000, LOAD | SETS1 | USES2 }, /* mov.b @rm,rn */ - { 0x6001, LOAD | SETS1 | USES2 }, /* mov.w @rm,rn */ - { 0x6002, LOAD | SETS1 | USES2 }, /* mov.l @rm,rn */ - { 0x6003, SETS1 | USES2 }, /* mov rm,rn */ - { 0x6004, LOAD | SETS1 | SETS2 | USES2 }, /* mov.b @rm+,rn */ - { 0x6005, LOAD | SETS1 | SETS2 | USES2 }, /* mov.w @rm+,rn */ - { 0x6006, LOAD | SETS1 | SETS2 | USES2 }, /* mov.l @rm+,rn */ - { 0x6007, SETS1 | USES2 }, /* not rm,rn */ - { 0x6008, SETS1 | USES2 }, /* swap.b rm,rn */ - { 0x6009, SETS1 | USES2 }, /* swap.w rm,rn */ - { 0x600a, SETS1 | SETSSP | USES2 | USESSP }, /* negc rm,rn */ - { 0x600b, SETS1 | USES2 }, /* neg rm,rn */ - { 0x600c, SETS1 | USES2 }, /* extu.b rm,rn */ - { 0x600d, SETS1 | USES2 }, /* extu.w rm,rn */ - { 0x600e, SETS1 | USES2 }, /* exts.b rm,rn */ - { 0x600f, SETS1 | USES2 } /* exts.w rm,rn */ -}; - -static const struct sh_minor_opcode sh_opcode6[] = -{ - { MAP (sh_opcode60), 0xf00f } -}; - -static const struct sh_opcode sh_opcode70[] = -{ - { 0x7000, SETS1 | USES1 } /* add #imm,rn */ -}; - -static const struct sh_minor_opcode sh_opcode7[] = -{ - { MAP (sh_opcode70), 0xf000 } -}; - -static const struct sh_opcode sh_opcode80[] = -{ - { 0x8000, STORE | USES2 | USESR0 }, /* mov.b r0,@(disp,rn) */ - { 0x8100, STORE | USES2 | USESR0 }, /* mov.w r0,@(disp,rn) */ - { 0x8200, SETSSP }, /* setrc #imm */ - { 0x8400, LOAD | SETSR0 | USES2 }, /* mov.b @(disp,rm),r0 */ - { 0x8500, LOAD | SETSR0 | USES2 }, /* mov.w @(disp,rn),r0 */ - { 0x8800, SETSSP | USESR0 }, /* cmp/eq #imm,r0 */ - { 0x8900, BRANCH | USESSP }, /* bt label */ - { 0x8b00, BRANCH | USESSP }, /* bf label */ - { 0x8c00, SETSSP }, /* ldrs @(disp,pc) */ - { 0x8d00, BRANCH | DELAY | USESSP }, /* bt/s label */ - { 0x8e00, SETSSP }, /* ldre @(disp,pc) */ - { 0x8f00, BRANCH | DELAY | USESSP } /* bf/s label */ -}; - -static const struct sh_minor_opcode sh_opcode8[] = -{ - { MAP (sh_opcode80), 0xff00 } -}; - -static const struct sh_opcode sh_opcode90[] = -{ - { 0x9000, LOAD | SETS1 } /* mov.w @(disp,pc),rn */ -}; - -static const struct sh_minor_opcode sh_opcode9[] = -{ - { MAP (sh_opcode90), 0xf000 } -}; - -static const struct sh_opcode sh_opcodea0[] = -{ - { 0xa000, BRANCH | DELAY } /* bra label */ -}; - -static const struct sh_minor_opcode sh_opcodea[] = -{ - { MAP (sh_opcodea0), 0xf000 } -}; - -static const struct sh_opcode sh_opcodeb0[] = -{ - { 0xb000, BRANCH | DELAY } /* bsr label */ -}; - -static const struct sh_minor_opcode sh_opcodeb[] = -{ - { MAP (sh_opcodeb0), 0xf000 } -}; - -static const struct sh_opcode sh_opcodec0[] = -{ - { 0xc000, STORE | USESR0 | USESSP }, /* mov.b r0,@(disp,gbr) */ - { 0xc100, STORE | USESR0 | USESSP }, /* mov.w r0,@(disp,gbr) */ - { 0xc200, STORE | USESR0 | USESSP }, /* mov.l r0,@(disp,gbr) */ - { 0xc300, BRANCH | USESSP }, /* trapa #imm */ - { 0xc400, LOAD | SETSR0 | USESSP }, /* mov.b @(disp,gbr),r0 */ - { 0xc500, LOAD | SETSR0 | USESSP }, /* mov.w @(disp,gbr),r0 */ - { 0xc600, LOAD | SETSR0 | USESSP }, /* mov.l @(disp,gbr),r0 */ - { 0xc700, SETSR0 }, /* mova @(disp,pc),r0 */ - { 0xc800, SETSSP | USESR0 }, /* tst #imm,r0 */ - { 0xc900, SETSR0 | USESR0 }, /* and #imm,r0 */ - { 0xca00, SETSR0 | USESR0 }, /* xor #imm,r0 */ - { 0xcb00, SETSR0 | USESR0 }, /* or #imm,r0 */ - { 0xcc00, LOAD | SETSSP | USESR0 | USESSP }, /* tst.b #imm,@(r0,gbr) */ - { 0xcd00, LOAD | STORE | USESR0 | USESSP }, /* and.b #imm,@(r0,gbr) */ - { 0xce00, LOAD | STORE | USESR0 | USESSP }, /* xor.b #imm,@(r0,gbr) */ - { 0xcf00, LOAD | STORE | USESR0 | USESSP } /* or.b #imm,@(r0,gbr) */ -}; - -static const struct sh_minor_opcode sh_opcodec[] = -{ - { MAP (sh_opcodec0), 0xff00 } -}; - -static const struct sh_opcode sh_opcoded0[] = -{ - { 0xd000, LOAD | SETS1 } /* mov.l @(disp,pc),rn */ -}; - -static const struct sh_minor_opcode sh_opcoded[] = -{ - { MAP (sh_opcoded0), 0xf000 } -}; - -static const struct sh_opcode sh_opcodee0[] = -{ - { 0xe000, SETS1 } /* mov #imm,rn */ -}; - -static const struct sh_minor_opcode sh_opcodee[] = -{ - { MAP (sh_opcodee0), 0xf000 } -}; - -static const struct sh_opcode sh_opcodef0[] = -{ - { 0xf000, SETSF1 | USESF1 | USESF2 }, /* fadd fm,fn */ - { 0xf001, SETSF1 | USESF1 | USESF2 }, /* fsub fm,fn */ - { 0xf002, SETSF1 | USESF1 | USESF2 }, /* fmul fm,fn */ - { 0xf003, SETSF1 | USESF1 | USESF2 }, /* fdiv fm,fn */ - { 0xf004, SETSSP | USESF1 | USESF2 }, /* fcmp/eq fm,fn */ - { 0xf005, SETSSP | USESF1 | USESF2 }, /* fcmp/gt fm,fn */ - { 0xf006, LOAD | SETSF1 | USES2 | USESR0 }, /* fmov.s @(r0,rm),fn */ - { 0xf007, STORE | USES1 | USESF2 | USESR0 }, /* fmov.s fm,@(r0,rn) */ - { 0xf008, LOAD | SETSF1 | USES2 }, /* fmov.s @rm,fn */ - { 0xf009, LOAD | SETS2 | SETSF1 | USES2 }, /* fmov.s @rm+,fn */ - { 0xf00a, STORE | USES1 | USESF2 }, /* fmov.s fm,@rn */ - { 0xf00b, STORE | SETS1 | USES1 | USESF2 }, /* fmov.s fm,@-rn */ - { 0xf00c, SETSF1 | USESF2 }, /* fmov fm,fn */ - { 0xf00e, SETSF1 | USESF1 | USESF2 | USESF0 } /* fmac f0,fm,fn */ -}; - -static const struct sh_opcode sh_opcodef1[] = -{ - { 0xf00d, SETSF1 | USESSP }, /* fsts fpul,fn */ - { 0xf01d, SETSSP | USESF1 }, /* flds fn,fpul */ - { 0xf02d, SETSF1 | USESSP }, /* float fpul,fn */ - { 0xf03d, SETSSP | USESF1 }, /* ftrc fn,fpul */ - { 0xf04d, SETSF1 | USESF1 }, /* fneg fn */ - { 0xf05d, SETSF1 | USESF1 }, /* fabs fn */ - { 0xf06d, SETSF1 | USESF1 }, /* fsqrt fn */ - { 0xf07d, SETSSP | USESF1 }, /* ftst/nan fn */ - { 0xf08d, SETSF1 }, /* fldi0 fn */ - { 0xf09d, SETSF1 } /* fldi1 fn */ -}; - -static const struct sh_minor_opcode sh_opcodef[] = -{ - { MAP (sh_opcodef0), 0xf00f }, - { MAP (sh_opcodef1), 0xf0ff } -}; - -static struct sh_major_opcode sh_opcodes[] = -{ - { MAP (sh_opcode0) }, - { MAP (sh_opcode1) }, - { MAP (sh_opcode2) }, - { MAP (sh_opcode3) }, - { MAP (sh_opcode4) }, - { MAP (sh_opcode5) }, - { MAP (sh_opcode6) }, - { MAP (sh_opcode7) }, - { MAP (sh_opcode8) }, - { MAP (sh_opcode9) }, - { MAP (sh_opcodea) }, - { MAP (sh_opcodeb) }, - { MAP (sh_opcodec) }, - { MAP (sh_opcoded) }, - { MAP (sh_opcodee) }, - { MAP (sh_opcodef) } -}; - -/* The double data transfer / parallel processing insns are not - described here. This will cause sh_align_load_span to leave them alone. */ - -static const struct sh_opcode sh_dsp_opcodef0[] = -{ - { 0xf400, USESAS | SETSAS | LOAD | SETSSP }, /* movs.x @-as,ds */ - { 0xf401, USESAS | SETSAS | STORE | USESSP }, /* movs.x ds,@-as */ - { 0xf404, USESAS | LOAD | SETSSP }, /* movs.x @as,ds */ - { 0xf405, USESAS | STORE | USESSP }, /* movs.x ds,@as */ - { 0xf408, USESAS | SETSAS | LOAD | SETSSP }, /* movs.x @as+,ds */ - { 0xf409, USESAS | SETSAS | STORE | USESSP }, /* movs.x ds,@as+ */ - { 0xf40c, USESAS | SETSAS | LOAD | SETSSP | USESR8 }, /* movs.x @as+r8,ds */ - { 0xf40d, USESAS | SETSAS | STORE | USESSP | USESR8 } /* movs.x ds,@as+r8 */ -}; - -static const struct sh_minor_opcode sh_dsp_opcodef[] = -{ - { MAP (sh_dsp_opcodef0), 0xfc0d } -}; - -/* Given an instruction, return a pointer to the corresponding - sh_opcode structure. Return NULL if the instruction is not - recognized. */ - -static const struct sh_opcode * -sh_insn_info (unsigned int insn) -{ - const struct sh_major_opcode *maj; - const struct sh_minor_opcode *min, *minend; - - maj = &sh_opcodes[(insn & 0xf000) >> 12]; - min = maj->minor_opcodes; - minend = min + maj->count; - for (; min < minend; min++) - { - unsigned int l; - const struct sh_opcode *op, *opend; - - l = insn & min->mask; - op = min->opcodes; - opend = op + min->count; - - /* Since the opcodes tables are sorted, we could use a binary - search here if the count were above some cutoff value. */ - for (; op < opend; op++) - if (op->opcode == l) - return op; - } - - return NULL; -} - -/* See whether an instruction uses a general purpose register. */ - -static bfd_boolean -sh_insn_uses_reg (unsigned int insn, - const struct sh_opcode *op, - unsigned int reg) -{ - unsigned int f; - - f = op->flags; - - if ((f & USES1) != 0 - && USES1_REG (insn) == reg) - return TRUE; - if ((f & USES2) != 0 - && USES2_REG (insn) == reg) - return TRUE; - if ((f & USESR0) != 0 - && reg == 0) - return TRUE; - if ((f & USESAS) && reg == USESAS_REG (insn)) - return TRUE; - if ((f & USESR8) && reg == 8) - return TRUE; - - return FALSE; -} - -/* See whether an instruction sets a general purpose register. */ - -static bfd_boolean -sh_insn_sets_reg (unsigned int insn, - const struct sh_opcode *op, - unsigned int reg) -{ - unsigned int f; - - f = op->flags; - - if ((f & SETS1) != 0 - && SETS1_REG (insn) == reg) - return TRUE; - if ((f & SETS2) != 0 - && SETS2_REG (insn) == reg) - return TRUE; - if ((f & SETSR0) != 0 - && reg == 0) - return TRUE; - if ((f & SETSAS) && reg == SETSAS_REG (insn)) - return TRUE; - - return FALSE; -} - -/* See whether an instruction uses or sets a general purpose register */ - -static bfd_boolean -sh_insn_uses_or_sets_reg (unsigned int insn, - const struct sh_opcode *op, - unsigned int reg) -{ - if (sh_insn_uses_reg (insn, op, reg)) - return TRUE; - - return sh_insn_sets_reg (insn, op, reg); -} - -/* See whether an instruction uses a floating point register. */ - -static bfd_boolean -sh_insn_uses_freg (unsigned int insn, - const struct sh_opcode *op, - unsigned int freg) -{ - unsigned int f; - - f = op->flags; - - /* We can't tell if this is a double-precision insn, so just play safe - and assume that it might be. So not only have we test FREG against - itself, but also even FREG against FREG+1 - if the using insn uses - just the low part of a double precision value - but also an odd - FREG against FREG-1 - if the setting insn sets just the low part - of a double precision value. - So what this all boils down to is that we have to ignore the lowest - bit of the register number. */ - - if ((f & USESF1) != 0 - && (USESF1_REG (insn) & 0xe) == (freg & 0xe)) - return TRUE; - if ((f & USESF2) != 0 - && (USESF2_REG (insn) & 0xe) == (freg & 0xe)) - return TRUE; - if ((f & USESF0) != 0 - && freg == 0) - return TRUE; - - return FALSE; -} - -/* See whether an instruction sets a floating point register. */ - -static bfd_boolean -sh_insn_sets_freg (unsigned int insn, - const struct sh_opcode *op, - unsigned int freg) -{ - unsigned int f; - - f = op->flags; - - /* We can't tell if this is a double-precision insn, so just play safe - and assume that it might be. So not only have we test FREG against - itself, but also even FREG against FREG+1 - if the using insn uses - just the low part of a double precision value - but also an odd - FREG against FREG-1 - if the setting insn sets just the low part - of a double precision value. - So what this all boils down to is that we have to ignore the lowest - bit of the register number. */ - - if ((f & SETSF1) != 0 - && (SETSF1_REG (insn) & 0xe) == (freg & 0xe)) - return TRUE; - - return FALSE; -} - -/* See whether an instruction uses or sets a floating point register */ - -static bfd_boolean -sh_insn_uses_or_sets_freg (unsigned int insn, - const struct sh_opcode *op, - unsigned int reg) -{ - if (sh_insn_uses_freg (insn, op, reg)) - return TRUE; - - return sh_insn_sets_freg (insn, op, reg); -} - -/* See whether instructions I1 and I2 conflict, assuming I1 comes - before I2. OP1 and OP2 are the corresponding sh_opcode structures. - This should return TRUE if there is a conflict, or FALSE if the - instructions can be swapped safely. */ - -static bfd_boolean -sh_insns_conflict (unsigned int i1, - const struct sh_opcode *op1, - unsigned int i2, - const struct sh_opcode *op2) -{ - unsigned int f1, f2; - - f1 = op1->flags; - f2 = op2->flags; - - /* Load of fpscr conflicts with floating point operations. - FIXME: shouldn't test raw opcodes here. */ - if (((i1 & 0xf0ff) == 0x4066 && (i2 & 0xf000) == 0xf000) - || ((i2 & 0xf0ff) == 0x4066 && (i1 & 0xf000) == 0xf000)) - return TRUE; - - if ((f1 & (BRANCH | DELAY)) != 0 - || (f2 & (BRANCH | DELAY)) != 0) - return TRUE; - - if (((f1 | f2) & SETSSP) - && (f1 & (SETSSP | USESSP)) - && (f2 & (SETSSP | USESSP))) - return TRUE; - - if ((f1 & SETS1) != 0 - && sh_insn_uses_or_sets_reg (i2, op2, SETS1_REG (i1))) - return TRUE; - if ((f1 & SETS2) != 0 - && sh_insn_uses_or_sets_reg (i2, op2, SETS2_REG (i1))) - return TRUE; - if ((f1 & SETSR0) != 0 - && sh_insn_uses_or_sets_reg (i2, op2, 0)) - return TRUE; - if ((f1 & SETSAS) - && sh_insn_uses_or_sets_reg (i2, op2, SETSAS_REG (i1))) - return TRUE; - if ((f1 & SETSF1) != 0 - && sh_insn_uses_or_sets_freg (i2, op2, SETSF1_REG (i1))) - return TRUE; - - if ((f2 & SETS1) != 0 - && sh_insn_uses_or_sets_reg (i1, op1, SETS1_REG (i2))) - return TRUE; - if ((f2 & SETS2) != 0 - && sh_insn_uses_or_sets_reg (i1, op1, SETS2_REG (i2))) - return TRUE; - if ((f2 & SETSR0) != 0 - && sh_insn_uses_or_sets_reg (i1, op1, 0)) - return TRUE; - if ((f2 & SETSAS) - && sh_insn_uses_or_sets_reg (i1, op1, SETSAS_REG (i2))) - return TRUE; - if ((f2 & SETSF1) != 0 - && sh_insn_uses_or_sets_freg (i1, op1, SETSF1_REG (i2))) - return TRUE; - - /* The instructions do not conflict. */ - return FALSE; -} - -/* I1 is a load instruction, and I2 is some other instruction. Return - TRUE if I1 loads a register which I2 uses. */ - -static bfd_boolean -sh_load_use (unsigned int i1, - const struct sh_opcode *op1, - unsigned int i2, - const struct sh_opcode *op2) -{ - unsigned int f1; - - f1 = op1->flags; - - if ((f1 & LOAD) == 0) - return FALSE; - - /* If both SETS1 and SETSSP are set, that means a load to a special - register using postincrement addressing mode, which we don't care - about here. */ - if ((f1 & SETS1) != 0 - && (f1 & SETSSP) == 0 - && sh_insn_uses_reg (i2, op2, (i1 & 0x0f00) >> 8)) - return TRUE; - - if ((f1 & SETSR0) != 0 - && sh_insn_uses_reg (i2, op2, 0)) - return TRUE; - - if ((f1 & SETSF1) != 0 - && sh_insn_uses_freg (i2, op2, (i1 & 0x0f00) >> 8)) - return TRUE; - - return FALSE; -} - -/* Try to align loads and stores within a span of memory. This is - called by both the ELF and the COFF sh targets. ABFD and SEC are - the BFD and section we are examining. CONTENTS is the contents of - the section. SWAP is the routine to call to swap two instructions. - RELOCS is a pointer to the internal relocation information, to be - passed to SWAP. PLABEL is a pointer to the current label in a - sorted list of labels; LABEL_END is the end of the list. START and - STOP are the range of memory to examine. If a swap is made, - *PSWAPPED is set to TRUE. */ - -#ifdef COFF_WITH_PE -static -#endif -bfd_boolean -_bfd_sh_align_load_span (bfd *abfd, - asection *sec, - bfd_byte *contents, - bfd_boolean (*swap) (bfd *, asection *, void *, bfd_byte *, bfd_vma), - void * relocs, - bfd_vma **plabel, - bfd_vma *label_end, - bfd_vma start, - bfd_vma stop, - bfd_boolean *pswapped) -{ - int dsp = (abfd->arch_info->mach == bfd_mach_sh_dsp - || abfd->arch_info->mach == bfd_mach_sh3_dsp); - bfd_vma i; - - /* The SH4 has a Harvard architecture, hence aligning loads is not - desirable. In fact, it is counter-productive, since it interferes - with the schedules generated by the compiler. */ - if (abfd->arch_info->mach == bfd_mach_sh4) - return TRUE; - - /* If we are linking sh[3]-dsp code, swap the FPU instructions for DSP - instructions. */ - if (dsp) - { - sh_opcodes[0xf].minor_opcodes = sh_dsp_opcodef; - sh_opcodes[0xf].count = sizeof sh_dsp_opcodef / sizeof sh_dsp_opcodef [0]; - } - - /* Instructions should be aligned on 2 byte boundaries. */ - if ((start & 1) == 1) - ++start; - - /* Now look through the unaligned addresses. */ - i = start; - if ((i & 2) == 0) - i += 2; - for (; i < stop; i += 4) - { - unsigned int insn; - const struct sh_opcode *op; - unsigned int prev_insn = 0; - const struct sh_opcode *prev_op = NULL; - - insn = bfd_get_16 (abfd, contents + i); - op = sh_insn_info (insn); - if (op == NULL - || (op->flags & (LOAD | STORE)) == 0) - continue; - - /* This is a load or store which is not on a four byte boundary. */ - - while (*plabel < label_end && **plabel < i) - ++*plabel; - - if (i > start) - { - prev_insn = bfd_get_16 (abfd, contents + i - 2); - /* If INSN is the field b of a parallel processing insn, it is not - a load / store after all. Note that the test here might mistake - the field_b of a pcopy insn for the starting code of a parallel - processing insn; this might miss a swapping opportunity, but at - least we're on the safe side. */ - if (dsp && (prev_insn & 0xfc00) == 0xf800) - continue; - - /* Check if prev_insn is actually the field b of a parallel - processing insn. Again, this can give a spurious match - after a pcopy. */ - if (dsp && i - 2 > start) - { - unsigned pprev_insn = bfd_get_16 (abfd, contents + i - 4); - - if ((pprev_insn & 0xfc00) == 0xf800) - prev_op = NULL; - else - prev_op = sh_insn_info (prev_insn); - } - else - prev_op = sh_insn_info (prev_insn); - - /* If the load/store instruction is in a delay slot, we - can't swap. */ - if (prev_op == NULL - || (prev_op->flags & DELAY) != 0) - continue; - } - if (i > start - && (*plabel >= label_end || **plabel != i) - && prev_op != NULL - && (prev_op->flags & (LOAD | STORE)) == 0 - && ! sh_insns_conflict (prev_insn, prev_op, insn, op)) - { - bfd_boolean ok; - - /* The load/store instruction does not have a label, and - there is a previous instruction; PREV_INSN is not - itself a load/store instruction, and PREV_INSN and - INSN do not conflict. */ - - ok = TRUE; - - if (i >= start + 4) - { - unsigned int prev2_insn; - const struct sh_opcode *prev2_op; - - prev2_insn = bfd_get_16 (abfd, contents + i - 4); - prev2_op = sh_insn_info (prev2_insn); - - /* If the instruction before PREV_INSN has a delay - slot--that is, PREV_INSN is in a delay slot--we - can not swap. */ - if (prev2_op == NULL - || (prev2_op->flags & DELAY) != 0) - ok = FALSE; - - /* If the instruction before PREV_INSN is a load, - and it sets a register which INSN uses, then - putting INSN immediately after PREV_INSN will - cause a pipeline bubble, so there is no point to - making the swap. */ - if (ok - && (prev2_op->flags & LOAD) != 0 - && sh_load_use (prev2_insn, prev2_op, insn, op)) - ok = FALSE; - } - - if (ok) - { - if (! (*swap) (abfd, sec, relocs, contents, i - 2)) - return FALSE; - *pswapped = TRUE; - continue; - } - } - - while (*plabel < label_end && **plabel < i + 2) - ++*plabel; - - if (i + 2 < stop - && (*plabel >= label_end || **plabel != i + 2)) - { - unsigned int next_insn; - const struct sh_opcode *next_op; - - /* There is an instruction after the load/store - instruction, and it does not have a label. */ - next_insn = bfd_get_16 (abfd, contents + i + 2); - next_op = sh_insn_info (next_insn); - if (next_op != NULL - && (next_op->flags & (LOAD | STORE)) == 0 - && ! sh_insns_conflict (insn, op, next_insn, next_op)) - { - bfd_boolean ok; - - /* NEXT_INSN is not itself a load/store instruction, - and it does not conflict with INSN. */ - - ok = TRUE; - - /* If PREV_INSN is a load, and it sets a register - which NEXT_INSN uses, then putting NEXT_INSN - immediately after PREV_INSN will cause a pipeline - bubble, so there is no reason to make this swap. */ - if (prev_op != NULL - && (prev_op->flags & LOAD) != 0 - && sh_load_use (prev_insn, prev_op, next_insn, next_op)) - ok = FALSE; - - /* If INSN is a load, and it sets a register which - the insn after NEXT_INSN uses, then doing the - swap will cause a pipeline bubble, so there is no - reason to make the swap. However, if the insn - after NEXT_INSN is itself a load or store - instruction, then it is misaligned, so - optimistically hope that it will be swapped - itself, and just live with the pipeline bubble if - it isn't. */ - if (ok - && i + 4 < stop - && (op->flags & LOAD) != 0) - { - unsigned int next2_insn; - const struct sh_opcode *next2_op; - - next2_insn = bfd_get_16 (abfd, contents + i + 4); - next2_op = sh_insn_info (next2_insn); - if (next2_op == NULL - || ((next2_op->flags & (LOAD | STORE)) == 0 - && sh_load_use (insn, op, next2_insn, next2_op))) - ok = FALSE; - } - - if (ok) - { - if (! (*swap) (abfd, sec, relocs, contents, i)) - return FALSE; - *pswapped = TRUE; - continue; - } - } - } - } - - return TRUE; -} -#endif /* not COFF_IMAGE_WITH_PE */ - -/* Swap two SH instructions. */ - -static bfd_boolean -sh_swap_insns (bfd * abfd, - asection * sec, - void * relocs, - bfd_byte * contents, - bfd_vma addr) -{ - struct internal_reloc *internal_relocs = (struct internal_reloc *) relocs; - unsigned short i1, i2; - struct internal_reloc *irel, *irelend; - - /* Swap the instructions themselves. */ - i1 = bfd_get_16 (abfd, contents + addr); - i2 = bfd_get_16 (abfd, contents + addr + 2); - bfd_put_16 (abfd, (bfd_vma) i2, contents + addr); - bfd_put_16 (abfd, (bfd_vma) i1, contents + addr + 2); - - /* Adjust all reloc addresses. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - int type, add; - - /* There are a few special types of relocs that we don't want to - adjust. These relocs do not apply to the instruction itself, - but are only associated with the address. */ - type = irel->r_type; - if (type == R_SH_ALIGN - || type == R_SH_CODE - || type == R_SH_DATA - || type == R_SH_LABEL) - continue; - - /* If an R_SH_USES reloc points to one of the addresses being - swapped, we must adjust it. It would be incorrect to do this - for a jump, though, since we want to execute both - instructions after the jump. (We have avoided swapping - around a label, so the jump will not wind up executing an - instruction it shouldn't). */ - if (type == R_SH_USES) - { - bfd_vma off; - - off = irel->r_vaddr - sec->vma + 4 + irel->r_offset; - if (off == addr) - irel->r_offset += 2; - else if (off == addr + 2) - irel->r_offset -= 2; - } - - if (irel->r_vaddr - sec->vma == addr) - { - irel->r_vaddr += 2; - add = -2; - } - else if (irel->r_vaddr - sec->vma == addr + 2) - { - irel->r_vaddr -= 2; - add = 2; - } - else - add = 0; - - if (add != 0) - { - bfd_byte *loc; - unsigned short insn, oinsn; - bfd_boolean overflow; - - loc = contents + irel->r_vaddr - sec->vma; - overflow = FALSE; - switch (type) - { - default: - break; - - case R_SH_PCDISP8BY2: - case R_SH_PCRELIMM8BY2: - insn = bfd_get_16 (abfd, loc); - oinsn = insn; - insn += add / 2; - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, loc); - break; - - case R_SH_PCDISP: - insn = bfd_get_16 (abfd, loc); - oinsn = insn; - insn += add / 2; - if ((oinsn & 0xf000) != (insn & 0xf000)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, loc); - break; - - case R_SH_PCRELIMM8BY4: - /* This reloc ignores the least significant 3 bits of - the program counter before adding in the offset. - This means that if ADDR is at an even address, the - swap will not affect the offset. If ADDR is an at an - odd address, then the instruction will be crossing a - four byte boundary, and must be adjusted. */ - if ((addr & 3) != 0) - { - insn = bfd_get_16 (abfd, loc); - oinsn = insn; - insn += add / 2; - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, loc); - } - - break; - } - - if (overflow) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %#Lx: fatal: reloc overflow while relaxing"), - abfd, irel->r_vaddr); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - } - - return TRUE; -} - -/* Look for loads and stores which we can align to four byte - boundaries. See the longer comment above sh_relax_section for why - this is desirable. This sets *PSWAPPED if some instruction was - swapped. */ - -static bfd_boolean -sh_align_loads (bfd *abfd, - asection *sec, - struct internal_reloc *internal_relocs, - bfd_byte *contents, - bfd_boolean *pswapped) -{ - struct internal_reloc *irel, *irelend; - bfd_vma *labels = NULL; - bfd_vma *label, *label_end; - bfd_size_type amt; - - *pswapped = FALSE; - - irelend = internal_relocs + sec->reloc_count; - - /* Get all the addresses with labels on them. */ - amt = (bfd_size_type) sec->reloc_count * sizeof (bfd_vma); - labels = (bfd_vma *) bfd_malloc (amt); - if (labels == NULL) - goto error_return; - label_end = labels; - for (irel = internal_relocs; irel < irelend; irel++) - { - if (irel->r_type == R_SH_LABEL) - { - *label_end = irel->r_vaddr - sec->vma; - ++label_end; - } - } - - /* Note that the assembler currently always outputs relocs in - address order. If that ever changes, this code will need to sort - the label values and the relocs. */ - - label = labels; - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma start, stop; - - if (irel->r_type != R_SH_CODE) - continue; - - start = irel->r_vaddr - sec->vma; - - for (irel++; irel < irelend; irel++) - if (irel->r_type == R_SH_DATA) - break; - if (irel < irelend) - stop = irel->r_vaddr - sec->vma; - else - stop = sec->size; - - if (! _bfd_sh_align_load_span (abfd, sec, contents, sh_swap_insns, - internal_relocs, &label, - label_end, start, stop, pswapped)) - goto error_return; - } - - free (labels); - - return TRUE; - - error_return: - if (labels != NULL) - free (labels); - return FALSE; -} - -/* This is a modification of _bfd_coff_generic_relocate_section, which - will handle SH relaxing. */ - -static bfd_boolean -sh_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct coff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma addend; - bfd_vma val; - reloc_howto_type *howto; - bfd_reloc_status_type rstat; - - /* Almost all relocs have to do with relaxing. If any work must - be done for them, it has been done in sh_relax_section. */ - if (rel->r_type != R_SH_IMM32 -#ifdef COFF_WITH_PE - && rel->r_type != R_SH_IMM32CE - && rel->r_type != R_SH_IMAGEBASE -#endif - && rel->r_type != R_SH_PCDISP) - continue; - - symndx = rel->r_symndx; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else - { - if (symndx < 0 - || (unsigned long) symndx >= obj_raw_syment_count (input_bfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: illegal symbol index %ld in relocs"), - input_bfd, symndx); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - h = obj_coff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - } - - if (sym != NULL && sym->n_scnum != 0) - addend = - sym->n_value; - else - addend = 0; - - if (rel->r_type == R_SH_PCDISP) - addend -= 4; - - if (rel->r_type >= SH_COFF_HOWTO_COUNT) - howto = NULL; - else - howto = &sh_coff_howtos[rel->r_type]; - - if (howto == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - -#ifdef COFF_WITH_PE - if (rel->r_type == R_SH_IMAGEBASE) - addend -= pe_data (input_section->output_section->owner)->pe_opthdr.ImageBase; -#endif - - val = 0; - - if (h == NULL) - { - asection *sec; - - /* There is nothing to do for an internal PCDISP reloc. */ - if (rel->r_type == R_SH_PCDISP) - continue; - - if (symndx == -1) - { - sec = bfd_abs_section_ptr; - val = 0; - } - else - { - sec = sections[symndx]; - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value - - sec->vma); - } - } - else - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *sec; - - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else if (! bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - } - - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, - rel->r_vaddr - input_section->vma, - val, addend); - - switch (rstat) - { - default: - abort (); - case bfd_reloc_ok: - break; - case bfd_reloc_overflow: - { - const char *name; - char buf[SYMNMLEN + 1]; - - if (symndx == -1) - name = "*ABS*"; - else if (h != NULL) - name = NULL; - else if (sym->_n._n_n._n_zeroes == 0 - && sym->_n._n_n._n_offset != 0) - name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset; - else - { - strncpy (buf, sym->_n._n_name, SYMNMLEN); - buf[SYMNMLEN] = '\0'; - name = buf; - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - } - } - - return TRUE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses sh_relocate_section. */ - -static bfd_byte * -sh_coff_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - struct internal_reloc *internal_relocs = NULL; - struct internal_syment *internal_syms = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || coff_section_data (input_bfd, input_section) == NULL - || coff_section_data (input_bfd, input_section)->contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - memcpy (data, coff_section_data (input_bfd, input_section)->contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - bfd_size_type symesz = bfd_coff_symesz (input_bfd); - bfd_byte *esym, *esymend; - struct internal_syment *isymp; - asection **secpp; - bfd_size_type amt; - - if (! _bfd_coff_get_external_symbols (input_bfd)) - goto error_return; - - internal_relocs = (_bfd_coff_read_internal_relocs - (input_bfd, input_section, FALSE, (bfd_byte *) NULL, - FALSE, (struct internal_reloc *) NULL)); - if (internal_relocs == NULL) - goto error_return; - - amt = obj_raw_syment_count (input_bfd); - amt *= sizeof (struct internal_syment); - internal_syms = (struct internal_syment *) bfd_malloc (amt); - if (internal_syms == NULL) - goto error_return; - - amt = obj_raw_syment_count (input_bfd); - amt *= sizeof (asection *); - sections = (asection **) bfd_malloc (amt); - if (sections == NULL) - goto error_return; - - isymp = internal_syms; - secpp = sections; - esym = (bfd_byte *) obj_coff_external_syms (input_bfd); - esymend = esym + obj_raw_syment_count (input_bfd) * symesz; - while (esym < esymend) - { - bfd_coff_swap_sym_in (input_bfd, esym, isymp); - - if (isymp->n_scnum != 0) - *secpp = coff_section_from_bfd_index (input_bfd, isymp->n_scnum); - else - { - if (isymp->n_value == 0) - *secpp = bfd_und_section_ptr; - else - *secpp = bfd_com_section_ptr; - } - - esym += (isymp->n_numaux + 1) * symesz; - secpp += isymp->n_numaux + 1; - isymp += isymp->n_numaux + 1; - } - - if (! sh_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - internal_syms, sections)) - goto error_return; - - free (sections); - sections = NULL; - free (internal_syms); - internal_syms = NULL; - free (internal_relocs); - internal_relocs = NULL; - } - - return data; - - error_return: - if (internal_relocs != NULL) - free (internal_relocs); - if (internal_syms != NULL) - free (internal_syms); - if (sections != NULL) - free (sections); - return NULL; -} - -/* The target vectors. */ - -#ifndef TARGET_SHL_SYM -CREATE_BIG_COFF_TARGET_VEC (sh_coff_vec, "coff-sh", BFD_IS_RELAXABLE, 0, '_', NULL, COFF_SWAP_TABLE) -#endif - -#ifdef TARGET_SHL_SYM -#define TARGET_SYM TARGET_SHL_SYM -#else -#define TARGET_SYM sh_coff_le_vec -#endif - -#ifndef TARGET_SHL_NAME -#define TARGET_SHL_NAME "coff-shl" -#endif - -#ifdef COFF_WITH_PE -CREATE_LITTLE_COFF_TARGET_VEC (TARGET_SYM, TARGET_SHL_NAME, BFD_IS_RELAXABLE, - SEC_CODE | SEC_DATA, '_', NULL, COFF_SWAP_TABLE); -#else -CREATE_LITTLE_COFF_TARGET_VEC (TARGET_SYM, TARGET_SHL_NAME, BFD_IS_RELAXABLE, - 0, '_', NULL, COFF_SWAP_TABLE) -#endif - -#ifndef TARGET_SHL_SYM - -/* Some people want versions of the SH COFF target which do not align - to 16 byte boundaries. We implement that by adding a couple of new - target vectors. These are just like the ones above, but they - change the default section alignment. To generate them in the - assembler, use -small. To use them in the linker, use -b - coff-sh{l}-small and -oformat coff-sh{l}-small. - - Yes, this is a horrible hack. A general solution for setting - section alignment in COFF is rather complex. ELF handles this - correctly. */ - -/* Only recognize the small versions if the target was not defaulted. - Otherwise we won't recognize the non default endianness. */ - -static const bfd_target * -coff_small_object_p (bfd *abfd) -{ - if (abfd->target_defaulted) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - return coff_object_p (abfd); -} - -/* Set the section alignment for the small versions. */ - -static bfd_boolean -coff_small_new_section_hook (bfd *abfd, asection *section) -{ - if (! coff_new_section_hook (abfd, section)) - return FALSE; - - /* We must align to at least a four byte boundary, because longword - accesses must be on a four byte boundary. */ - if (section->alignment_power == COFF_DEFAULT_SECTION_ALIGNMENT_POWER) - section->alignment_power = 2; - - return TRUE; -} - -/* This is copied from bfd_coff_std_swap_table so that we can change - the default section alignment power. */ - -static bfd_coff_backend_data bfd_coff_small_swap_table = -{ - coff_swap_aux_in, coff_swap_sym_in, coff_swap_lineno_in, - coff_swap_aux_out, coff_swap_sym_out, - coff_swap_lineno_out, coff_swap_reloc_out, - coff_swap_filehdr_out, coff_swap_aouthdr_out, - coff_swap_scnhdr_out, - FILHSZ, AOUTSZ, SCNHSZ, SYMESZ, AUXESZ, RELSZ, LINESZ, FILNMLEN, -#ifdef COFF_LONG_FILENAMES - TRUE, -#else - FALSE, -#endif - COFF_DEFAULT_LONG_SECTION_NAMES, - 2, -#ifdef COFF_FORCE_SYMBOLS_IN_STRINGS - TRUE, -#else - FALSE, -#endif -#ifdef COFF_DEBUG_STRING_WIDE_PREFIX - 4, -#else - 2, -#endif - 32768, - coff_swap_filehdr_in, coff_swap_aouthdr_in, coff_swap_scnhdr_in, - coff_swap_reloc_in, coff_bad_format_hook, coff_set_arch_mach_hook, - coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook, - coff_slurp_symbol_table, symname_in_debug_hook, coff_pointerize_aux_hook, - coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate, - coff_classify_symbol, coff_compute_section_file_positions, - coff_start_final_link, coff_relocate_section, coff_rtype_to_howto, - coff_adjust_symndx, coff_link_add_one_symbol, - coff_link_output_has_begun, coff_final_link_postscript, - bfd_pe_print_pdata -}; - -#define coff_small_close_and_cleanup \ - coff_close_and_cleanup -#define coff_small_bfd_free_cached_info \ - coff_bfd_free_cached_info -#define coff_small_get_section_contents \ - coff_get_section_contents -#define coff_small_get_section_contents_in_window \ - coff_get_section_contents_in_window - -extern const bfd_target sh_coff_small_le_vec; - -const bfd_target sh_coff_small_vec = -{ - "coff-sh-small", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - 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, coff_small_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff_small), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & sh_coff_small_le_vec, - - & bfd_coff_small_swap_table -}; - -const bfd_target sh_coff_small_le_vec = -{ - "coff-shl-small", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little endian too*/ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | BFD_IS_RELAXABLE), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_small_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff_small), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & sh_coff_small_vec, - - & bfd_coff_small_swap_table -}; -#endif diff --git a/sdcc/support/sdbinutils/bfd/coff-sparc.c b/sdcc/support/sdbinutils/bfd/coff-sparc.c deleted file mode 100644 index 7bdb79a51..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-sparc.c +++ /dev/null @@ -1,208 +0,0 @@ -/* BFD back-end for Sparc COFF files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/sparc.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) - -#define BADMAG(x) ((x).f_magic != SPARCMAGIC && (x).f_magic != LYNXCOFFMAGIC) - -/* The page size is a guess based on ELF. */ -#define COFF_PAGE_SIZE 0x10000 - -enum reloc_type - { - R_SPARC_NONE = 0, - R_SPARC_8, R_SPARC_16, R_SPARC_32, - R_SPARC_DISP8, R_SPARC_DISP16, R_SPARC_DISP32, - R_SPARC_WDISP30, R_SPARC_WDISP22, - R_SPARC_HI22, R_SPARC_22, - R_SPARC_13, R_SPARC_LO10, - R_SPARC_GOT10, R_SPARC_GOT13, R_SPARC_GOT22, - R_SPARC_PC10, R_SPARC_PC22, - R_SPARC_WPLT30, - R_SPARC_COPY, - R_SPARC_GLOB_DAT, R_SPARC_JMP_SLOT, - R_SPARC_RELATIVE, - R_SPARC_UA32, - R_SPARC_max - }; - -/* This is stolen pretty directly from elf.c. */ - -static bfd_reloc_status_type -bfd_coff_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 != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - return bfd_reloc_continue; -} - -static reloc_howto_type coff_sparc_howto_table[] = -{ - HOWTO(R_SPARC_NONE, 0,3, 0,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_NONE", FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_8, 0,0, 8,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_8", FALSE,0,0x000000ff,TRUE), - HOWTO(R_SPARC_16, 0,1,16,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_16", FALSE,0,0x0000ffff,TRUE), - HOWTO(R_SPARC_32, 0,2,32,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_32", FALSE,0,0xffffffff,TRUE), - HOWTO(R_SPARC_DISP8, 0,0, 8,TRUE, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_DISP8", FALSE,0,0x000000ff,TRUE), - HOWTO(R_SPARC_DISP16, 0,1,16,TRUE, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_DISP16", FALSE,0,0x0000ffff,TRUE), - HOWTO(R_SPARC_DISP32, 0,2,32,TRUE, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_DISP32", FALSE,0,0x00ffffff,TRUE), - HOWTO(R_SPARC_WDISP30, 2,2,30,TRUE, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_WDISP30", FALSE,0,0x3fffffff,TRUE), - HOWTO(R_SPARC_WDISP22, 2,2,22,TRUE, 0,complain_overflow_signed, bfd_coff_generic_reloc,"R_SPARC_WDISP22", FALSE,0,0x003fffff,TRUE), - HOWTO(R_SPARC_HI22, 10,2,22,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_HI22", FALSE,0,0x003fffff,TRUE), - HOWTO(R_SPARC_22, 0,2,22,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_22", FALSE,0,0x003fffff,TRUE), - HOWTO(R_SPARC_13, 0,2,13,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_13", FALSE,0,0x00001fff,TRUE), - HOWTO(R_SPARC_LO10, 0,2,10,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_LO10", FALSE,0,0x000003ff,TRUE), - HOWTO(R_SPARC_GOT10, 0,2,10,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT10", FALSE,0,0x000003ff,TRUE), - HOWTO(R_SPARC_GOT13, 0,2,13,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT13", FALSE,0,0x00001fff,TRUE), - HOWTO(R_SPARC_GOT22, 10,2,22,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_GOT22", FALSE,0,0x003fffff,TRUE), - HOWTO(R_SPARC_PC10, 0,2,10,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_PC10", FALSE,0,0x000003ff,TRUE), - HOWTO(R_SPARC_PC22, 0,2,22,FALSE,0,complain_overflow_bitfield,bfd_coff_generic_reloc,"R_SPARC_PC22", FALSE,0,0x003fffff,TRUE), - HOWTO(R_SPARC_WPLT30, 0,0,00,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_WPLT30", FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_COPY, 0,0,00,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_COPY", FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_GLOB_DAT,0,0,00,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_GLOB_DAT",FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_JMP_SLOT,0,0,00,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_JMP_SLOT",FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_RELATIVE,0,0,00,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_RELATIVE",FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_UA32, 0,0,00,FALSE,0,complain_overflow_dont, bfd_coff_generic_reloc,"R_SPARC_UA32", FALSE,0,0x00000000,TRUE), -}; - -struct coff_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char coff_reloc_val; -}; - -static const struct coff_reloc_map sparc_reloc_map[] = -{ - { BFD_RELOC_NONE, R_SPARC_NONE, }, - { BFD_RELOC_16, R_SPARC_16, }, - { BFD_RELOC_8, R_SPARC_8 }, - { BFD_RELOC_8_PCREL, R_SPARC_DISP8 }, - { BFD_RELOC_CTOR, R_SPARC_32 }, /* @@ Assumes 32 bits. */ - { BFD_RELOC_32, R_SPARC_32 }, - { BFD_RELOC_32_PCREL, R_SPARC_DISP32 }, - { BFD_RELOC_HI22, R_SPARC_HI22 }, - { BFD_RELOC_LO10, R_SPARC_LO10, }, - { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 }, - { BFD_RELOC_SPARC22, R_SPARC_22 }, - { BFD_RELOC_SPARC13, R_SPARC_13 }, - { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 }, - { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 }, - { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 }, - { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 }, - { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 }, - { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 }, - { BFD_RELOC_SPARC_COPY, R_SPARC_COPY }, - { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT }, - { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT }, - { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE }, - { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 }, - /* { BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, not used?? */ -}; - -static reloc_howto_type * -coff_sparc_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - for (i = 0; i < sizeof (sparc_reloc_map) / sizeof (struct coff_reloc_map); i++) - { - if (sparc_reloc_map[i].bfd_reloc_val == code) - return &coff_sparc_howto_table[(int) sparc_reloc_map[i].coff_reloc_val]; - } - return 0; -} -#define coff_bfd_reloc_type_lookup coff_sparc_reloc_type_lookup - -static reloc_howto_type * -coff_sparc_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (coff_sparc_howto_table) - / sizeof (coff_sparc_howto_table[0])); - i++) - if (coff_sparc_howto_table[i].name != NULL - && strcasecmp (coff_sparc_howto_table[i].name, r_name) == 0) - return &coff_sparc_howto_table[i]; - - return NULL; -} -#define coff_bfd_reloc_name_lookup coff_sparc_reloc_name_lookup - -static void -rtype2howto (arelent *cache_ptr, struct internal_reloc *dst) -{ - BFD_ASSERT (dst->r_type < (unsigned int) R_SPARC_max); - cache_ptr->howto = &coff_sparc_howto_table[dst->r_type]; -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) - -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ - cache_ptr->addend = reloc.r_offset; - -/* Clear the r_spare field in relocs. */ -#define SWAP_OUT_RELOC_EXTRA(abfd,src,dst) \ - do { \ - dst->r_spare[0] = 0; \ - dst->r_spare[1] = 0; \ - } while (0) - -#define __A_MAGIC_SET__ - -/* Enable Sparc-specific hacks in coffcode.h. */ - -#define COFF_SPARC - -#define bfd_pe_print_pdata NULL - -#include "coffcode.h" - -#ifndef TARGET_SYM -#define TARGET_SYM sparc_coff_vec -#endif - -#ifndef TARGET_NAME -#define TARGET_NAME "coff-sparc" -#endif - -CREATE_BIG_COFF_TARGET_VEC (TARGET_SYM, TARGET_NAME, D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-stgo32.c b/sdcc/support/sdbinutils/bfd/coff-stgo32.c deleted file mode 100644 index edb9a28fe..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-stgo32.c +++ /dev/null @@ -1,424 +0,0 @@ -/* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub). - Copyright (C) 1997-2018 Free Software Foundation, Inc. - Written by Robert Hoehne. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* This file handles now also stubbed coff images. The stub is a small - DOS executable program before the coff image to load it in memory - and execute it. This is needed, because DOS cannot run coff files. - - All the functions below are called by the corresponding functions - from coffswap.h. - The only thing what they do is to adjust the information stored in - the COFF file which are offset into the file. - This is needed, because DJGPP uses a very special way to load and run - the coff image. It loads the image in memory and assumes then, that the - image had no stub by using the filepointers as pointers in the coff - image and NOT in the file. - - To be compatible with any existing executables I have fixed this - here and NOT in the DJGPP startup code. */ - -#define TARGET_SYM i386_coff_go32stubbed_vec -#define TARGET_NAME "coff-go32-exe" -#define TARGET_UNDERSCORE '_' -#define COFF_GO32_EXE -#define COFF_LONG_SECTION_NAMES -#define COFF_SUPPORT_GNU_LINKONCE -#define COFF_LONG_FILENAMES - -#define COFF_SECTION_ALIGNMENT_ENTRIES \ -{ COFF_SECTION_NAME_EXACT_MATCH (".data"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_EXACT_MATCH (".text"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \ -{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \ - COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } - -#include "sysdep.h" -#include "bfd.h" - -/* All that ..._PRE and ...POST functions are called from the corresponding - coff_swap... functions. The ...PRE functions are called at the beginning - of the function and the ...POST functions at the end of the swap routines. */ - -static void -adjust_filehdr_in_post (bfd *, void *, void *); -static void -adjust_filehdr_out_pre (bfd *, void *, void *); -static void -adjust_filehdr_out_post (bfd *, void *, void *); -static void -adjust_scnhdr_in_post (bfd *, void *, void *); -static void -adjust_scnhdr_out_pre (bfd *, void *, void *); -static void -adjust_scnhdr_out_post (bfd *, void *, void *); -static void -adjust_aux_in_post (bfd *, void *, int, int, int, int, void *); -static void -adjust_aux_out_pre (bfd *, void *, int, int, int, int, void *); -static void -adjust_aux_out_post (bfd *, void *, int, int, int, int, void *); -static void -create_go32_stub (bfd *); - -#define COFF_ADJUST_FILEHDR_IN_POST adjust_filehdr_in_post -#define COFF_ADJUST_FILEHDR_OUT_PRE adjust_filehdr_out_pre -#define COFF_ADJUST_FILEHDR_OUT_POST adjust_filehdr_out_post - -#define COFF_ADJUST_SCNHDR_IN_POST adjust_scnhdr_in_post -#define COFF_ADJUST_SCNHDR_OUT_PRE adjust_scnhdr_out_pre -#define COFF_ADJUST_SCNHDR_OUT_POST adjust_scnhdr_out_post - -#define COFF_ADJUST_AUX_IN_POST adjust_aux_in_post -#define COFF_ADJUST_AUX_OUT_PRE adjust_aux_out_pre -#define COFF_ADJUST_AUX_OUT_POST adjust_aux_out_post - -static const bfd_target *go32_check_format (bfd *); - -#define COFF_CHECK_FORMAT go32_check_format - -static bfd_boolean - go32_stubbed_coff_bfd_copy_private_bfd_data (bfd *, bfd *); - -#define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data - -#include "coff-i386.c" - -/* This macro is used, because I cannot assume the endianness of the - host system. */ -#define _H(index) (H_GET_16 (abfd, (header + index * 2))) - -/* These bytes are a 2048-byte DOS executable, which loads the COFF - image into memory and then runs it. It is called 'stub'. */ - -static const unsigned char stub_bytes[GO32_STUBSIZE] = -{ -#include "go32stub.h" -}; - -/* - I have not commented each swap function below, because the - technique is in any function the same. For the ...in function, - all the pointers are adjusted by adding GO32_STUBSIZE and for the - ...out function, it is subtracted first and after calling the - standard swap function it is reset to the old value. */ - -/* This macro is used for adjusting the filepointers, which - is done only, if the pointer is nonzero. */ - -#define ADJUST_VAL(val,diff) \ - if (val != 0) val += diff - -static void -adjust_filehdr_in_post (bfd * abfd ATTRIBUTE_UNUSED, - void * src, - void * dst) -{ - FILHDR *filehdr_src = (FILHDR *) src; - struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; - - ADJUST_VAL (filehdr_dst->f_symptr, GO32_STUBSIZE); - - /* Save now the stub to be used later. Put the stub data to FILEHDR_DST - first as coff_data (abfd) still does not exist. It may not even be ever - created as we are just checking the file format of ABFD. */ - memcpy (filehdr_dst->go32stub, filehdr_src->stub, GO32_STUBSIZE); - filehdr_dst->f_flags |= F_GO32STUB; -} - -static void -adjust_filehdr_out_pre (bfd * abfd, void * in, void * out) -{ - struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; - FILHDR *filehdr_out = (FILHDR *) out; - - /* Generate the stub. */ - create_go32_stub (abfd); - - /* Copy the stub to the file header. */ - if (coff_data (abfd)->go32stub != NULL) - memcpy (filehdr_out->stub, coff_data (abfd)->go32stub, GO32_STUBSIZE); - else - /* Use the default. */ - memcpy (filehdr_out->stub, stub_bytes, GO32_STUBSIZE); - - ADJUST_VAL (filehdr_in->f_symptr, -GO32_STUBSIZE); -} - -static void -adjust_filehdr_out_post (bfd * abfd ATTRIBUTE_UNUSED, - void * in, - void * out ATTRIBUTE_UNUSED) -{ - struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; - /* Undo the above change. */ - ADJUST_VAL (filehdr_in->f_symptr, GO32_STUBSIZE); -} - -static void -adjust_scnhdr_in_post (bfd * abfd ATTRIBUTE_UNUSED, - void * ext ATTRIBUTE_UNUSED, - void * in) -{ - struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; - - ADJUST_VAL (scnhdr_int->s_scnptr, GO32_STUBSIZE); - ADJUST_VAL (scnhdr_int->s_relptr, GO32_STUBSIZE); - ADJUST_VAL (scnhdr_int->s_lnnoptr, GO32_STUBSIZE); -} - -static void -adjust_scnhdr_out_pre (bfd * abfd ATTRIBUTE_UNUSED, - void * in, - void * out ATTRIBUTE_UNUSED) -{ - struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; - - ADJUST_VAL (scnhdr_int->s_scnptr, -GO32_STUBSIZE); - ADJUST_VAL (scnhdr_int->s_relptr, -GO32_STUBSIZE); - ADJUST_VAL (scnhdr_int->s_lnnoptr, -GO32_STUBSIZE); -} - -static void -adjust_scnhdr_out_post (bfd * abfd ATTRIBUTE_UNUSED, - void * in, - void * out ATTRIBUTE_UNUSED) -{ - struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; - - ADJUST_VAL (scnhdr_int->s_scnptr, GO32_STUBSIZE); - ADJUST_VAL (scnhdr_int->s_relptr, GO32_STUBSIZE); - ADJUST_VAL (scnhdr_int->s_lnnoptr, GO32_STUBSIZE); -} - -static void -adjust_aux_in_post (bfd * abfd ATTRIBUTE_UNUSED, - void * ext1 ATTRIBUTE_UNUSED, - int type, - int in_class, - int indx ATTRIBUTE_UNUSED, - int numaux ATTRIBUTE_UNUSED, - void * in1) -{ - union internal_auxent *in = (union internal_auxent *) in1; - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, GO32_STUBSIZE); - } -} - -static void -adjust_aux_out_pre (bfd *abfd ATTRIBUTE_UNUSED, - void * inp, - int type, - int in_class, - int indx ATTRIBUTE_UNUSED, - int numaux ATTRIBUTE_UNUSED, - void * extp ATTRIBUTE_UNUSED) -{ - union internal_auxent *in = (union internal_auxent *) inp; - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -GO32_STUBSIZE); - } -} - -static void -adjust_aux_out_post (bfd *abfd ATTRIBUTE_UNUSED, - void * inp, - int type, - int in_class, - int indx ATTRIBUTE_UNUSED, - int numaux ATTRIBUTE_UNUSED, - void * extp ATTRIBUTE_UNUSED) -{ - union internal_auxent *in = (union internal_auxent *) inp; - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, GO32_STUBSIZE); - } -} - -/* That's the function, which creates the stub. There are - different cases from where the stub is taken. - At first the environment variable $(GO32STUB) is checked and then - $(STUB) if it was not set. - If it exists and points to a valid stub the stub is taken from - that file. This file can be also a whole executable file, because - the stub is computed from the exe information at the start of that - file. - - If there was any error, the standard stub (compiled in this file) - is taken. */ - -static void -create_go32_stub (bfd *abfd) -{ - /* Do it only once. */ - if (coff_data (abfd)->go32stub == NULL) - { - char *stub; - struct stat st; - int f; - unsigned char header[10]; - char magic[8]; - unsigned long coff_start; - long exe_start; - - /* Check at first the environment variable $(GO32STUB). */ - stub = getenv ("GO32STUB"); - /* Now check the environment variable $(STUB). */ - if (stub == NULL) - stub = getenv ("STUB"); - if (stub == NULL) - goto stub_end; - if (stat (stub, &st) != 0) - goto stub_end; -#ifdef O_BINARY - f = open (stub, O_RDONLY | O_BINARY); -#else - f = open (stub, O_RDONLY); -#endif - if (f < 0) - goto stub_end; - if (read (f, &header, sizeof (header)) < 0) - { - close (f); - goto stub_end; - } - if (_H (0) != 0x5a4d) /* It is not an exe file. */ - { - close (f); - goto stub_end; - } - /* Compute the size of the stub (it is every thing up - to the beginning of the coff image). */ - coff_start = (long) _H (2) * 512L; - if (_H (1)) - coff_start += (long) _H (1) - 512L; - - /* Currently there is only a fixed stub size of 2048 bytes - supported. */ - if (coff_start != 2048) - { - close (f); - goto stub_end; - } - exe_start = _H (4) * 16; - if ((long) lseek (f, exe_start, SEEK_SET) != exe_start) - { - close (f); - goto stub_end; - } - if (read (f, &magic, 8) != 8) - { - close (f); - goto stub_end; - } - if (! CONST_STRNEQ (magic, "go32stub")) - { - close (f); - goto stub_end; - } - /* Now we found a correct stub (hopefully). */ - coff_data (abfd)->go32stub = bfd_alloc (abfd, (bfd_size_type) coff_start); - if (coff_data (abfd)->go32stub == NULL) - { - close (f); - return; - } - lseek (f, 0L, SEEK_SET); - if ((unsigned long) read (f, coff_data (abfd)->go32stub, coff_start) - != coff_start) - { - bfd_release (abfd, coff_data (abfd)->go32stub); - coff_data (abfd)->go32stub = NULL; - } - close (f); - } -stub_end: - /* There was something wrong above, so use now the standard builtin - stub. */ - if (coff_data (abfd)->go32stub == NULL) - { - coff_data (abfd)->go32stub - = bfd_alloc (abfd, (bfd_size_type) GO32_STUBSIZE); - if (coff_data (abfd)->go32stub == NULL) - return; - memcpy (coff_data (abfd)->go32stub, stub_bytes, GO32_STUBSIZE); - } -} - -/* If ibfd was a stubbed coff image, copy the stub from that bfd - to the new obfd. */ - -static bfd_boolean -go32_stubbed_coff_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - /* Check if both are the same targets. */ - if (ibfd->xvec != obfd->xvec) - return TRUE; - - /* Check if we have a source stub. */ - if (coff_data (ibfd)->go32stub == NULL) - return TRUE; - - /* As adjust_filehdr_out_pre may get called only after this function, - optionally allocate the output stub. */ - if (coff_data (obfd)->go32stub == NULL) - coff_data (obfd)->go32stub = bfd_alloc (obfd, - (bfd_size_type) GO32_STUBSIZE); - - /* Now copy the stub. */ - if (coff_data (obfd)->go32stub != NULL) - memcpy (coff_data (obfd)->go32stub, coff_data (ibfd)->go32stub, - GO32_STUBSIZE); - - return TRUE; -} - -/* coff_object_p only checks 2 bytes F_MAGIC at GO32_STUBSIZE inside the file - which is too fragile. */ - -static const bfd_target * -go32_check_format (bfd *abfd) -{ - char mz[2]; - - if (bfd_bread (mz, 2, abfd) != 2 || mz[0] != 'M' || mz[1] != 'Z') - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - if (bfd_seek (abfd, 0, SEEK_SET) != 0) - return NULL; - - return coff_object_p (abfd); -} diff --git a/sdcc/support/sdbinutils/bfd/coff-svm68k.c b/sdcc/support/sdbinutils/bfd/coff-svm68k.c deleted file mode 100644 index ae12b49a6..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-svm68k.c +++ /dev/null @@ -1,27 +0,0 @@ -/* BFD back-end for Motorola sysv68 - Copyright (C) 1997-2018 Free Software Foundation, Inc. - Written by Philippe De Muyter . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGET_SYM m68k_coff_sysv_vec -#define TARGET_NAME "coff-m68k-sysv" -#define STATIC_RELOCS -#define COFF_COMMON_ADDEND - -#include "coff-m68k.c" diff --git a/sdcc/support/sdbinutils/bfd/coff-tic30.c b/sdcc/support/sdbinutils/bfd/coff-tic30.c deleted file mode 100644 index f597a28b8..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-tic30.c +++ /dev/null @@ -1,222 +0,0 @@ -/* BFD back-end for TMS320C30 coff binaries. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "coff/tic30.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) - -reloc_howto_type tic30_coff_howto_table[] = - { - HOWTO (R_TIC30_ABS16, 2, 1, 16, FALSE, 0, 0, NULL, - "16", FALSE, 0x0000FFFF, 0x0000FFFF, FALSE), - HOWTO (R_TIC30_ABS24, 2, 2, 24, FALSE, 8, complain_overflow_bitfield, NULL, - "24", FALSE, 0xFFFFFF00, 0xFFFFFF00, FALSE), - HOWTO (R_TIC30_LDP, 18, 0, 24, FALSE, 0, complain_overflow_bitfield, NULL, - "LDP", FALSE, 0x00FF0000, 0x000000FF, FALSE), - HOWTO (R_TIC30_ABS32, 2, 2, 32, FALSE, 0, complain_overflow_bitfield, NULL, - "32", FALSE, 0xFFFFFFFF, 0xFFFFFFFF, FALSE), - HOWTO (R_TIC30_PC16, 2, 1, 16, TRUE, 0, complain_overflow_signed, NULL, - "PCREL", FALSE, 0x0000FFFF, 0x0000FFFF, FALSE), - EMPTY_HOWTO (-1) - }; - -#ifndef coff_bfd_reloc_type_lookup -#define coff_bfd_reloc_type_lookup tic30_coff_reloc_type_lookup -#define coff_bfd_reloc_name_lookup tic30_coff_reloc_name_lookup - -/* For the case statement use the code values used in tc_gen_reloc to - map to the howto table entries that match those in both the aout - and coff implementations. */ - -static reloc_howto_type * -tic30_coff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_8: - case BFD_RELOC_TIC30_LDP: - return &tic30_coff_howto_table[2]; - case BFD_RELOC_16: - return &tic30_coff_howto_table[0]; - case BFD_RELOC_24: - return &tic30_coff_howto_table[1]; - case BFD_RELOC_16_PCREL: - return &tic30_coff_howto_table[4]; - case BFD_RELOC_32: - return &tic30_coff_howto_table[3]; - default: - return (reloc_howto_type *) NULL; - } -} - -static reloc_howto_type * -tic30_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (tic30_coff_howto_table) - / sizeof (tic30_coff_howto_table[0])); - i++) - if (tic30_coff_howto_table[i].name != NULL - && strcasecmp (tic30_coff_howto_table[i].name, r_name) == 0) - return &tic30_coff_howto_table[i]; - - return NULL; -} - -#endif - -/* Turn a howto into a reloc number. */ - -static int -coff_tic30_select_reloc (reloc_howto_type *howto) -{ - return howto->type; -} - -#define SELECT_RELOC(x,howto) x.r_type = coff_tic30_select_reloc(howto) - -#define BADMAG(x) TIC30BADMAG(x) -#define TIC30 1 /* Customize coffcode.h */ -#define __A_MAGIC_SET__ - -/* Code to swap in the reloc */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) dst->r_stuff[0] = 'S'; \ -dst->r_stuff[1] = 'C'; - -/* Code to turn a r_type into a howto ptr, uses the above howto table. */ - -static void -rtype2howto (arelent *internal, struct internal_reloc *dst) -{ - switch (dst->r_type) - { - case R_TIC30_ABS16: - internal->howto = &tic30_coff_howto_table[0]; - break; - case R_TIC30_ABS24: - internal->howto = &tic30_coff_howto_table[1]; - break; - case R_TIC30_ABS32: - internal->howto = &tic30_coff_howto_table[3]; - break; - case R_TIC30_LDP: - internal->howto = &tic30_coff_howto_table[2]; - break; - case R_TIC30_PC16: - internal->howto = &tic30_coff_howto_table[4]; - break; - default: - internal->howto = NULL; - break; - } -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry) - -/* Perform any necessary magic to the addend in a reloc entry */ - -#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ - cache_ptr->addend = ext_reloc.r_offset; - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing(relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent *relent, - struct internal_reloc *reloc, - asymbol **symbols, - bfd *abfd, - asection *section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (reloc->r_symndx > 0) - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - else - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - relent->addend = reloc->r_offset; - relent->address -= section->vma; -} - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -const bfd_target tic30_coff_vec = -{ - "coff-tic30", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_LITTLE, /* header byte order is little */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - 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_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - COFF_SWAP_TABLE -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-tic4x.c b/sdcc/support/sdbinutils/bfd/coff-tic4x.c deleted file mode 100644 index 660b51974..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-tic4x.c +++ /dev/null @@ -1,291 +0,0 @@ -/* BFD back-end for TMS320C4X coff binaries. - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "coff/tic4x.h" -#include "coff/internal.h" -#include "libcoff.h" - -#undef F_LSYMS -#define F_LSYMS F_LSYMS_TICOFF - -static reloc_howto_type * -coff_tic4x_rtype_to_howto (bfd *, asection *, struct internal_reloc *, - struct coff_link_hash_entry *, - struct internal_syment *, bfd_vma *); -static void -tic4x_reloc_processing (arelent *, struct internal_reloc *, - asymbol **, bfd *, asection *); - -/* Replace the stock _bfd_coff_is_local_label_name to recognize TI COFF local - labels. */ -static bfd_boolean -ticoff_bfd_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, - const char *name) -{ - if (TICOFF_LOCAL_LABEL_P(name)) - return TRUE; - return FALSE; -} - -#define coff_bfd_is_local_label_name ticoff_bfd_is_local_label_name - -#define RELOC_PROCESSING(RELENT,RELOC,SYMS,ABFD,SECT)\ - tic4x_reloc_processing (RELENT,RELOC,SYMS,ABFD,SECT) - -/* Customize coffcode.h; the default coff_ functions are set up to use - COFF2; coff_bad_format_hook uses BADMAG, so set that for COFF2. - The COFF1 and COFF0 vectors use custom _bad_format_hook procs - instead of setting BADMAG. */ -#define BADMAG(x) COFF2_BADMAG(x) - -#undef coff_rtype_to_howto -#define coff_rtype_to_howto coff_tic4x_rtype_to_howto - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -static bfd_reloc_status_type -tic4x_relocation (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != (bfd *) NULL) - { - /* 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->address += input_section->output_offset; - return bfd_reloc_ok; - } - return bfd_reloc_continue; -} - -reloc_howto_type tic4x_howto_table[] = -{ - HOWTO(R_RELWORD, 0, 2, 16, FALSE, 0, complain_overflow_signed, tic4x_relocation, "RELWORD", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_REL24, 0, 2, 24, FALSE, 0, complain_overflow_bitfield, tic4x_relocation, "REL24", TRUE, 0x00ffffff, 0x00ffffff, FALSE), - HOWTO(R_RELLONG, 0, 2, 32, FALSE, 0, complain_overflow_dont, tic4x_relocation, "RELLONG", TRUE, 0xffffffff, 0xffffffff, FALSE), - HOWTO(R_PCRWORD, 0, 2, 16, TRUE, 0, complain_overflow_signed, tic4x_relocation, "PCRWORD", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_PCR24, 0, 2, 24, TRUE, 0, complain_overflow_signed, tic4x_relocation, "PCR24", TRUE, 0x00ffffff, 0x00ffffff, FALSE), - HOWTO(R_PARTLS16, 0, 2, 16, FALSE, 0, complain_overflow_dont, tic4x_relocation, "PARTLS16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_PARTMS8, 16, 2, 16, FALSE, 0, complain_overflow_dont, tic4x_relocation, "PARTMS8", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_RELWORD, 0, 2, 16, FALSE, 0, complain_overflow_signed, tic4x_relocation, "ARELWORD", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_REL24, 0, 2, 24, FALSE, 0, complain_overflow_signed, tic4x_relocation, "AREL24", TRUE, 0x00ffffff, 0x00ffffff, FALSE), - HOWTO(R_RELLONG, 0, 2, 32, FALSE, 0, complain_overflow_signed, tic4x_relocation, "ARELLONG", TRUE, 0xffffffff, 0xffffffff, FALSE), - HOWTO(R_PCRWORD, 0, 2, 16, TRUE, 0, complain_overflow_signed, tic4x_relocation, "APCRWORD", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_PCR24, 0, 2, 24, TRUE, 0, complain_overflow_signed, tic4x_relocation, "APCR24", TRUE, 0x00ffffff, 0x00ffffff, FALSE), - HOWTO(R_PARTLS16, 0, 2, 16, FALSE, 0, complain_overflow_dont, tic4x_relocation, "APARTLS16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO(R_PARTMS8, 16, 2, 16, FALSE, 0, complain_overflow_dont, tic4x_relocation, "APARTMS8", TRUE, 0x0000ffff, 0x0000ffff, FALSE), -}; -#define HOWTO_SIZE (sizeof(tic4x_howto_table) / sizeof(tic4x_howto_table[0])) - -#undef coff_bfd_reloc_type_lookup -#define coff_bfd_reloc_type_lookup tic4x_coff_reloc_type_lookup -#undef coff_bfd_reloc_name_lookup -#define coff_bfd_reloc_name_lookup tic4x_coff_reloc_name_lookup - -/* For the case statement use the code values used tc_gen_reloc (defined in - bfd/reloc.c) to map to the howto table entries. */ - -static reloc_howto_type * -tic4x_coff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int type; - unsigned int i; - - switch (code) - { - case BFD_RELOC_32: type = R_RELLONG; break; - case BFD_RELOC_24: type = R_REL24; break; - case BFD_RELOC_16: type = R_RELWORD; break; - case BFD_RELOC_24_PCREL: type = R_PCR24; break; - case BFD_RELOC_16_PCREL: type = R_PCRWORD; break; - case BFD_RELOC_HI16: type = R_PARTMS8; break; - case BFD_RELOC_LO16: type = R_PARTLS16; break; - default: - return NULL; - } - - for (i = 0; i < HOWTO_SIZE; i++) - { - if (tic4x_howto_table[i].type == type) - return tic4x_howto_table + i; - } - return NULL; -} - -static reloc_howto_type * -tic4x_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (tic4x_howto_table) / sizeof (tic4x_howto_table[0]); - i++) - if (tic4x_howto_table[i].name != NULL - && strcasecmp (tic4x_howto_table[i].name, r_name) == 0) - return &tic4x_howto_table[i]; - - return NULL; -} - -/* Code to turn a r_type into a howto ptr, uses the above howto table. - Called after some initial checking by the tic4x_rtype_to_howto fn - below. */ -static void -tic4x_lookup_howto (arelent *internal, - struct internal_reloc *dst) -{ - unsigned int i; - int bank = (dst->r_symndx == -1) ? HOWTO_BANK : 0; - - for (i = 0; i < HOWTO_SIZE; i++) - { - if (tic4x_howto_table[i].type == dst->r_type) - { - internal->howto = tic4x_howto_table + i + bank; - return; - } - } - - _bfd_error_handler (_("Unrecognized reloc type 0x%x"), - (unsigned int) dst->r_type); - abort(); -} - -static reloc_howto_type * -coff_tic4x_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - bfd_vma *addendp) -{ - arelent genrel; - - if (rel->r_symndx == -1 && addendp != NULL) - /* This is a TI "internal relocation", which means that the relocation - amount is the amount by which the current section is being relocated - in the output section. */ - *addendp = (sec->output_section->vma + sec->output_offset) - sec->vma; - - tic4x_lookup_howto (&genrel, rel); - - return genrel.howto; -} - - -static void -tic4x_reloc_processing (arelent *relent, - struct internal_reloc *reloc, - asymbol **symbols, - bfd *abfd, - asection *section) -{ - asymbol *ptr; - - relent->address = reloc->r_vaddr; - - if (reloc->r_symndx != -1) - { - if (reloc->r_symndx < 0 || reloc->r_symndx >= obj_conv_table_size (abfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: warning: illegal symbol index %ld in relocs"), - abfd, reloc->r_symndx); - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - ptr = NULL; - } - else - { - relent->sym_ptr_ptr = (symbols - + obj_convert (abfd)[reloc->r_symndx]); - ptr = *(relent->sym_ptr_ptr); - } - } - else - { - relent->sym_ptr_ptr = section->symbol_ptr_ptr; - ptr = *(relent->sym_ptr_ptr); - } - - /* The symbols definitions that we have read in have been relocated - as if their sections started at 0. But the offsets refering to - the symbols in the raw data have not been modified, so we have to - have a negative addend to compensate. - - Note that symbols which used to be common must be left alone. */ - - /* Calculate any reloc addend by looking at the symbol. */ - CALC_ADDEND (abfd, ptr, *reloc, relent); - - relent->address -= section->vma; - /* !! relent->section = (asection *) NULL; */ - - /* Fill in the relent->howto field from reloc->r_type. */ - tic4x_lookup_howto (relent, reloc); -} - - -/* TI COFF v0, DOS tools (little-endian headers). */ -CREATE_LITTLE_COFF_TARGET_VEC(tic4x_coff0_vec, "coff0-tic4x", - 0, SEC_CODE | SEC_READONLY, '_', - NULL, &ticoff0_swap_table); - -/* TI COFF v0, SPARC tools (big-endian headers). */ -CREATE_BIGHDR_COFF_TARGET_VEC(tic4x_coff0_beh_vec, "coff0-beh-tic4x", - 0, SEC_CODE | SEC_READONLY, '_', - &tic4x_coff0_vec, &ticoff0_swap_table); - -/* TI COFF v1, DOS tools (little-endian headers). */ -CREATE_LITTLE_COFF_TARGET_VEC(tic4x_coff1_vec, "coff1-tic4x", - 0, SEC_CODE | SEC_READONLY, '_', - &tic4x_coff0_beh_vec, &ticoff1_swap_table); - -/* TI COFF v1, SPARC tools (big-endian headers). */ -CREATE_BIGHDR_COFF_TARGET_VEC(tic4x_coff1_beh_vec, "coff1-beh-tic4x", - 0, SEC_CODE | SEC_READONLY, '_', - &tic4x_coff1_vec, &ticoff1_swap_table); - -/* TI COFF v2, TI DOS tools output (little-endian headers). */ -CREATE_LITTLE_COFF_TARGET_VEC(tic4x_coff2_vec, "coff2-tic4x", - 0, SEC_CODE | SEC_READONLY, '_', - &tic4x_coff1_beh_vec, COFF_SWAP_TABLE); - -/* TI COFF v2, TI SPARC tools output (big-endian headers). */ -CREATE_BIGHDR_COFF_TARGET_VEC(tic4x_coff2_beh_vec, "coff2-beh-tic4x", - 0, SEC_CODE | SEC_READONLY, '_', - &tic4x_coff2_vec, COFF_SWAP_TABLE); diff --git a/sdcc/support/sdbinutils/bfd/coff-tic54x.c b/sdcc/support/sdbinutils/bfd/coff-tic54x.c deleted file mode 100644 index 0b6848fd3..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-tic54x.c +++ /dev/null @@ -1,673 +0,0 @@ -/* BFD back-end for TMS320C54X coff binaries. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Timothy Wall (twall@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "coff/tic54x.h" -#include "coff/internal.h" -#include "libcoff.h" - -#undef F_LSYMS -#define F_LSYMS F_LSYMS_TICOFF - -static void -tic54x_reloc_processing (arelent *, struct internal_reloc *, - asymbol **, bfd *, asection *); - -/* 32-bit operations - The octet order is screwy. words are LSB first (LS octet, actually), but - longwords are MSW first. For example, 0x12345678 is encoded 0x5678 in the - first word and 0x1234 in the second. When looking at the data as stored in - the COFF file, you would see the octets ordered as 0x78, 0x56, 0x34, 0x12. - Don't bother with 64-bits, as there aren't any. */ - -static bfd_vma -tic54x_getl32 (const void *p) -{ - const bfd_byte *addr = p; - unsigned long v; - - v = (unsigned long) addr[2]; - v |= (unsigned long) addr[3] << 8; - v |= (unsigned long) addr[0] << 16; - v |= (unsigned long) addr[1] << 24; - return v; -} - -static void -tic54x_putl32 (bfd_vma data, void *p) -{ - bfd_byte *addr = p; - addr[2] = data & 0xff; - addr[3] = (data >> 8) & 0xff; - addr[0] = (data >> 16) & 0xff; - addr[1] = (data >> 24) & 0xff; -} - -static bfd_signed_vma -tic54x_getl_signed_32 (const void *p) -{ - const bfd_byte *addr = p; - unsigned long v; - - v = (unsigned long) addr[2]; - v |= (unsigned long) addr[3] << 8; - v |= (unsigned long) addr[0] << 16; - v |= (unsigned long) addr[1] << 24; -#define COERCE32(x) \ - ((bfd_signed_vma) (long) (((unsigned long) (x) ^ 0x80000000) - 0x80000000)) - return COERCE32 (v); -} - -#define coff_get_section_load_page bfd_ticoff_get_section_load_page -#define coff_set_section_load_page bfd_ticoff_set_section_load_page - -void -bfd_ticoff_set_section_load_page (asection *sect, - int page) -{ - sect->lma = (sect->lma & ADDR_MASK) | PG_TO_FLAG(page); -} - -int -bfd_ticoff_get_section_load_page (asection *sect) -{ - int page; - - /* Provide meaningful defaults for predefined sections. */ - if (sect == bfd_com_section_ptr) - page = PG_DATA; - - else if (bfd_is_und_section (sect) - || bfd_is_abs_section (sect) - || bfd_is_ind_section (sect)) - page = PG_PROG; - - else - page = FLAG_TO_PG (sect->lma); - - return page; -} - -/* Set the architecture appropriately. Allow unkown architectures - (e.g. binary). */ - -static bfd_boolean -tic54x_set_arch_mach (bfd *abfd, - enum bfd_architecture arch, - unsigned long machine) -{ - if (arch == bfd_arch_unknown) - arch = bfd_arch_tic54x; - - else if (arch != bfd_arch_tic54x) - return FALSE; - - return bfd_default_set_arch_mach (abfd, arch, machine); -} - -static bfd_reloc_status_type -tic54x_relocation (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != (bfd *) NULL) - { - /* 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->address += input_section->output_offset; - return bfd_reloc_ok; - } - return bfd_reloc_continue; -} - -reloc_howto_type tic54x_howto_table[] = - { - /* type,rightshift,size (0=byte, 1=short, 2=long), - bit size, pc_relative, bitpos, dont complain_on_overflow, - special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset. */ - - /* NORMAL BANK */ - /* 16-bit direct reference to symbol's address. */ - HOWTO (R_RELWORD,0,1,16,FALSE,0,complain_overflow_dont, - tic54x_relocation,"REL16",FALSE,0xFFFF,0xFFFF,FALSE), - - /* 7 LSBs of an address */ - HOWTO (R_PARTLS7,0,1,7,FALSE,0,complain_overflow_dont, - tic54x_relocation,"LS7",FALSE,0x007F,0x007F,FALSE), - - /* 9 MSBs of an address */ - /* TI assembler doesn't shift its encoding, and is thus incompatible */ - HOWTO (R_PARTMS9,7,1,9,FALSE,0,complain_overflow_dont, - tic54x_relocation,"MS9",FALSE,0x01FF,0x01FF,FALSE), - - /* 23-bit relocation */ - HOWTO (R_EXTWORD,0,2,23,FALSE,0,complain_overflow_dont, - tic54x_relocation,"RELEXT",FALSE,0x7FFFFF,0x7FFFFF,FALSE), - - /* 16 bits of 23-bit extended address */ - HOWTO (R_EXTWORD16,0,1,16,FALSE,0,complain_overflow_dont, - tic54x_relocation,"RELEXT16",FALSE,0x7FFFFF,0x7FFFFF,FALSE), - - /* upper 7 bits of 23-bit extended address */ - HOWTO (R_EXTWORDMS7,16,1,7,FALSE,0,complain_overflow_dont, - tic54x_relocation,"RELEXTMS7",FALSE,0x7F,0x7F,FALSE), - - /* ABSOLUTE BANK */ - /* 16-bit direct reference to symbol's address, absolute */ - HOWTO (R_RELWORD,0,1,16,FALSE,0,complain_overflow_dont, - tic54x_relocation,"AREL16",FALSE,0xFFFF,0xFFFF,FALSE), - - /* 7 LSBs of an address, absolute */ - HOWTO (R_PARTLS7,0,1,7,FALSE,0,complain_overflow_dont, - tic54x_relocation,"ALS7",FALSE,0x007F,0x007F,FALSE), - - /* 9 MSBs of an address, absolute */ - /* TI assembler doesn't shift its encoding, and is thus incompatible */ - HOWTO (R_PARTMS9,7,1,9,FALSE,0,complain_overflow_dont, - tic54x_relocation,"AMS9",FALSE,0x01FF,0x01FF,FALSE), - - /* 23-bit direct reference, absolute */ - HOWTO (R_EXTWORD,0,2,23,FALSE,0,complain_overflow_dont, - tic54x_relocation,"ARELEXT",FALSE,0x7FFFFF,0x7FFFFF,FALSE), - - /* 16 bits of 23-bit extended address, absolute */ - HOWTO (R_EXTWORD16,0,1,16,FALSE,0,complain_overflow_dont, - tic54x_relocation,"ARELEXT16",FALSE,0x7FFFFF,0x7FFFFF,FALSE), - - /* upper 7 bits of 23-bit extended address, absolute */ - HOWTO (R_EXTWORDMS7,16,1,7,FALSE,0,complain_overflow_dont, - tic54x_relocation,"ARELEXTMS7",FALSE,0x7F,0x7F,FALSE), - - /* 32-bit relocation exclusively for stabs */ - HOWTO (R_RELLONG,0,2,32,FALSE,0,complain_overflow_dont, - tic54x_relocation,"STAB",FALSE,0xFFFFFFFF,0xFFFFFFFF,FALSE), - }; - -#define coff_bfd_reloc_type_lookup tic54x_coff_reloc_type_lookup -#define coff_bfd_reloc_name_lookup tic54x_coff_reloc_name_lookup - -/* For the case statement use the code values used tc_gen_reloc (defined in - bfd/reloc.c) to map to the howto table entries. */ - -static reloc_howto_type * -tic54x_coff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_16: - return &tic54x_howto_table[0]; - case BFD_RELOC_TIC54X_PARTLS7: - return &tic54x_howto_table[1]; - case BFD_RELOC_TIC54X_PARTMS9: - return &tic54x_howto_table[2]; - case BFD_RELOC_TIC54X_23: - return &tic54x_howto_table[3]; - case BFD_RELOC_TIC54X_16_OF_23: - return &tic54x_howto_table[4]; - case BFD_RELOC_TIC54X_MS7_OF_23: - return &tic54x_howto_table[5]; - case BFD_RELOC_32: - return &tic54x_howto_table[12]; - default: - return (reloc_howto_type *) NULL; - } -} - -static reloc_howto_type * -tic54x_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (tic54x_howto_table) / sizeof (tic54x_howto_table[0]); - i++) - if (tic54x_howto_table[i].name != NULL - && strcasecmp (tic54x_howto_table[i].name, r_name) == 0) - return &tic54x_howto_table[i]; - - return NULL; -} - -/* Code to turn a r_type into a howto ptr, uses the above howto table. - Called after some initial checking by the tic54x_rtype_to_howto fn below. */ - -static void -tic54x_lookup_howto (arelent *internal, - struct internal_reloc *dst) -{ - unsigned i; - int bank = (dst->r_symndx == -1) ? HOWTO_BANK : 0; - - for (i = 0; i < sizeof tic54x_howto_table/sizeof tic54x_howto_table[0]; i++) - { - if (tic54x_howto_table[i].type == dst->r_type) - { - internal->howto = tic54x_howto_table + i + bank; - return; - } - } - - _bfd_error_handler (_("Unrecognized reloc type 0x%x"), - (unsigned int) dst->r_type); - abort (); -} - -#define RELOC_PROCESSING(RELENT,RELOC,SYMS,ABFD,SECT)\ - tic54x_reloc_processing(RELENT,RELOC,SYMS,ABFD,SECT) - -#define coff_rtype_to_howto coff_tic54x_rtype_to_howto - -static reloc_howto_type * -coff_tic54x_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - bfd_vma *addendp) -{ - arelent genrel; - - if (rel->r_symndx == -1 && addendp != NULL) - { - /* This is a TI "internal relocation", which means that the relocation - amount is the amount by which the current section is being relocated - in the output section. */ - *addendp = (sec->output_section->vma + sec->output_offset) - sec->vma; - } - - tic54x_lookup_howto (&genrel, rel); - - return genrel.howto; -} - -/* Replace the stock _bfd_coff_is_local_label_name to recognize TI COFF local - labels. */ - -static bfd_boolean -ticoff_bfd_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, - const char *name) -{ - if (TICOFF_LOCAL_LABEL_P(name)) - return TRUE; - return FALSE; -} - -#define coff_bfd_is_local_label_name ticoff_bfd_is_local_label_name - -/* Customize coffcode.h; the default coff_ functions are set up to use COFF2; - coff_bad_format_hook uses BADMAG, so set that for COFF2. The COFF1 - and COFF0 vectors use custom _bad_format_hook procs instead of setting - BADMAG. */ -#define BADMAG(x) COFF2_BADMAG(x) - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -static bfd_boolean -tic54x_set_section_contents (bfd *abfd, - sec_ptr section, - const void * location, - file_ptr offset, - bfd_size_type bytes_to_do) -{ - return coff_set_section_contents (abfd, section, location, - offset, bytes_to_do); -} - -static void -tic54x_reloc_processing (arelent *relent, - struct internal_reloc *reloc, - asymbol **symbols, - bfd *abfd, - asection *section) -{ - asymbol *ptr; - - relent->address = reloc->r_vaddr; - - if (reloc->r_symndx != -1) - { - if (reloc->r_symndx < 0 || reloc->r_symndx >= obj_conv_table_size (abfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: warning: illegal symbol index %ld in relocs"), - abfd, reloc->r_symndx); - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - ptr = NULL; - } - else - { - relent->sym_ptr_ptr = (symbols - + obj_convert (abfd)[reloc->r_symndx]); - ptr = *(relent->sym_ptr_ptr); - } - } - else - { - relent->sym_ptr_ptr = section->symbol_ptr_ptr; - ptr = *(relent->sym_ptr_ptr); - } - - /* The symbols definitions that we have read in have been - relocated as if their sections started at 0. But the offsets - refering to the symbols in the raw data have not been - modified, so we have to have a negative addend to compensate. - - Note that symbols which used to be common must be left alone. */ - - /* Calculate any reloc addend by looking at the symbol. */ - CALC_ADDEND (abfd, ptr, *reloc, relent); - - relent->address -= section->vma; - /* !! relent->section = (asection *) NULL;*/ - - /* Fill in the relent->howto field from reloc->r_type. */ - tic54x_lookup_howto (relent, reloc); -} - -/* TI COFF v0, DOS tools (little-endian headers). */ -const bfd_target tic54x_coff0_vec = - { - "coff0-c54x", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little (DOS tools) */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - tic54x_getl32, tic54x_getl_signed_32, tic54x_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (tic54x), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - NULL, - - & ticoff0_swap_table - }; - -/* TI COFF v0, SPARC tools (big-endian headers). */ -const bfd_target tic54x_coff0_beh_vec = - { - "coff0-beh-c54x", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - tic54x_getl32, tic54x_getl_signed_32, tic54x_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* 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, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (tic54x), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & tic54x_coff0_vec, - - & ticoff0_swap_table - }; - -/* TI COFF v1, DOS tools (little-endian headers). */ -const bfd_target tic54x_coff1_vec = - { - "coff1-c54x", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little (DOS tools) */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - tic54x_getl32, tic54x_getl_signed_32, tic54x_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (tic54x), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & tic54x_coff0_beh_vec, - - & ticoff1_swap_table -}; - -/* TI COFF v1, SPARC tools (big-endian headers). */ -const bfd_target tic54x_coff1_beh_vec = - { - "coff1-beh-c54x", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - tic54x_getl32, tic54x_getl_signed_32, tic54x_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* 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, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (tic54x), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & tic54x_coff1_vec, - - & ticoff1_swap_table - }; - -/* TI COFF v2, TI DOS tools output (little-endian headers). */ -const bfd_target tic54x_coff2_vec = - { - "coff2-c54x", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_LITTLE, /* header byte order is little (DOS tools) */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - tic54x_getl32, tic54x_getl_signed_32, tic54x_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ - - {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (tic54x), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & tic54x_coff1_beh_vec, - - COFF_SWAP_TABLE - }; - -/* TI COFF v2, TI SPARC tools output (big-endian headers). */ -const bfd_target tic54x_coff2_beh_vec = - { - "coff2-beh-c54x", /* name */ - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* data byte order is little */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | /* object flags */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT ), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ - '_', /* leading symbol underscore */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - tic54x_getl32, tic54x_getl_signed_32, tic54x_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* 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, coff_object_p, /* bfd_check_format */ - bfd_generic_archive_p, _bfd_dummy_target}, - {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */ - bfd_false}, - {bfd_false, coff_write_object_contents, /* bfd_write_contents */ - _bfd_write_archive_contents, bfd_false}, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (tic54x), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - & tic54x_coff2_vec, - - COFF_SWAP_TABLE - }; diff --git a/sdcc/support/sdbinutils/bfd/coff-tic80.c b/sdcc/support/sdbinutils/bfd/coff-tic80.c deleted file mode 100644 index 3496a05b0..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-tic80.c +++ /dev/null @@ -1,711 +0,0 @@ -/* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP). - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - Written by Fred Fish (fnf@cygnus.com) - - There is nothing new under the sun. This file draws a lot on other - coff files. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#ifdef _CONST -/* Newlib-based hosts define _CONST as a STDC-safe alias for const, - but to the tic80 toolchain it means something altogether different. - Since sysdep.h will have pulled in stdio.h and hence _ansi.h which - contains this definition, we must undef it before including the - tic80-specific definition. */ -#undef _CONST -#endif /* _CONST */ -#include "coff/tic80.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) -#define COFF_ALIGN_IN_SECTION_HEADER 1 -#define COFF_ALIGN_IN_SFLAGS 1 -#define COFF_ENCODE_ALIGNMENT(S,X) ((S).s_flags |= (((unsigned)(X) & 0xf) << 8)) -#define COFF_DECODE_ALIGNMENT(X) (((X) >> 8) & 0xf) - -#define GET_SCNHDR_FLAGS H_GET_16 -#define PUT_SCNHDR_FLAGS H_PUT_16 - -static bfd_reloc_status_type ppbase_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type glob15_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type glob16_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type local16_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - - -static reloc_howto_type tic80_howto_table[] = -{ - - HOWTO (R_RELLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - NULL, /* special_function */ - "RELLONG", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MPPCR, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - NULL, /* special_function */ - "MPPCR", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ABS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - NULL, /* special_function */ - "ABS", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPBASE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppbase_reloc, /* special_function */ - "PPBASE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPLBASE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppbase_reloc, /* special_function */ - "PPLBASE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PP15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob15_reloc, /* special_function */ - "PP15", /* name */ - TRUE, /* partial_inplace */ - 0x1ffc0, /* src_mask */ - 0x1ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PP15W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob15_reloc, /* special_function */ - "PP15W", /* name */ - TRUE, /* partial_inplace */ - 0x1ffc0, /* src_mask */ - 0x1ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PP15H, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob15_reloc, /* special_function */ - "PP15H", /* name */ - TRUE, /* partial_inplace */ - 0x1ffc0, /* src_mask */ - 0x1ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PP16B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob16_reloc, /* special_function */ - "PP16B", /* name */ - TRUE, /* partial_inplace */ - 0x3ffc0, /* src_mask */ - 0x3ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPL15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "PPL15", /* name */ - TRUE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPL15W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "PPL15W", /* name */ - TRUE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPL15H, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "PPL15H", /* name */ - TRUE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPL16B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - local16_reloc, /* special_function */ - "PPL16B", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPN15, /* type */ - 0, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob15_reloc, /* special_function */ - "PPN15", /* name */ - TRUE, /* partial_inplace */ - 0x1ffc0, /* src_mask */ - 0x1ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPN15W, /* type */ - 2, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob15_reloc, /* special_function */ - "PPN15W", /* name */ - TRUE, /* partial_inplace */ - 0x1ffc0, /* src_mask */ - 0x1ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPN15H, /* type */ - 1, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob15_reloc, /* special_function */ - "PPN15H", /* name */ - TRUE, /* partial_inplace */ - 0x1ffc0, /* src_mask */ - 0x1ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPN16B, /* type */ - 0, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - glob16_reloc, /* special_function */ - "PPN16B", /* name */ - TRUE, /* partial_inplace */ - 0x3ffc0, /* src_mask */ - 0x3ffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPLN15, /* type */ - 0, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "PPLN15", /* name */ - TRUE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPLN15W, /* type */ - 2, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "PPLN15W", /* name */ - TRUE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPLN15H, /* type */ - 1, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "PPLN15H", /* name */ - TRUE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPLN16B, /* type */ - 0, /* rightshift */ - -2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - local16_reloc, /* special_function */ - "PPLN16B", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -/* Special relocation functions, used when the output file is not - itself a COFF TIc80 file. */ - -/* This special function is used for the base address type - relocations. */ - -static bfd_reloc_status_type -ppbase_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol_in ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - /* FIXME. */ - abort (); -} - -/* This special function is used for the global 15 bit relocations. */ - -static bfd_reloc_status_type -glob15_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol_in ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - /* FIXME. */ - abort (); -} - -/* This special function is used for the global 16 bit relocations. */ - -static bfd_reloc_status_type -glob16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol_in ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - /* FIXME. */ - abort (); -} - -/* This special function is used for the local 16 bit relocations. */ - -static bfd_reloc_status_type -local16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol_in ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - /* FIXME. */ - abort (); -} - -/* Code to turn an external r_type into a pointer to an entry in the howto_table. - If passed an r_type we don't recognize the abort rather than silently failing - to generate an output file. */ - -static void -rtype2howto (arelent *cache_ptr, struct internal_reloc *dst) -{ - unsigned int i; - - for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++) - { - if (tic80_howto_table[i].type == dst->r_type) - { - cache_ptr->howto = tic80_howto_table + i; - return; - } - } - - _bfd_error_handler (_("Unrecognized reloc type 0x%x"), - (unsigned int) dst->r_type); - cache_ptr->howto = tic80_howto_table + 0; -} - -#define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst) -#define coff_rtype_to_howto coff_tic80_rtype_to_howto - -static reloc_howto_type * -coff_tic80_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h ATTRIBUTE_UNUSED, - struct internal_syment *sym ATTRIBUTE_UNUSED, - bfd_vma *addendp) -{ - arelent genrel; - - if (rel -> r_symndx == -1 && addendp != NULL) - { - /* This is a TI "internal relocation", which means that the relocation - amount is the amount by which the current section is being relocated - in the output section. */ - *addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma; - } - RTYPE2HOWTO (&genrel, rel); - return genrel.howto; -} - -#ifndef BADMAG -#define BADMAG(x) TIC80BADMAG(x) -#endif - -#define coff_relocate_section coff_tic80_relocate_section - -/* We need a special relocation routine to handle the PP relocs. Most - of this is a copy of _bfd_coff_generic_relocate_section. */ - -static bfd_boolean -coff_tic80_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct coff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma addend; - bfd_vma val; - reloc_howto_type *howto; - bfd_reloc_status_type rstat; - bfd_vma addr; - - symndx = rel->r_symndx; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else - { - h = obj_coff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - } - - /* COFF treats common symbols in one of two ways. Either the - size of the symbol is included in the section contents, or it - is not. We assume that the size is not included, and force - the rtype_to_howto function to adjust the addend as needed. */ - - if (sym != NULL && sym->n_scnum != 0) - addend = - sym->n_value; - else - addend = 0; - - howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h, - sym, &addend); - if (howto == NULL) - return FALSE; - - val = 0; - - if (h == NULL) - { - asection *sec; - - if (symndx == -1) - { - sec = bfd_abs_section_ptr; - val = 0; - } - else - { - sec = sections[symndx]; - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value); - if (! obj_pe (output_bfd)) - val -= sec->vma; - } - } - else - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *sec; - - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - - else if (! bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - } - - addr = rel->r_vaddr - input_section->vma; - - /* FIXME: This code assumes little endian, but the PP can - apparently be bi-endian. I don't know if the bi-endianness - applies to the instruction set or just to the data. */ - switch (howto->type) - { - default: - case R_ABS: - case R_RELLONGX: - case R_PPL15: - case R_PPL15W: - case R_PPL15H: - case R_PPLN15: - case R_PPLN15W: - case R_PPLN15H: - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, addr, val, addend); - break; - - case R_PP15: - case R_PP15W: - case R_PP15H: - case R_PPN15: - case R_PPN15W: - case R_PPN15H: - /* Offset the address so that we can use 4 byte relocations. */ - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents + 2, addr, val, addend); - break; - - case R_PP16B: - case R_PPN16B: - { - /* The most significant bit is stored in bit 6. */ - bfd_byte hold; - - hold = contents[addr + 4]; - contents[addr + 4] &=~ 0x20; - contents[addr + 4] |= (contents[addr] >> 1) & 0x20; - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents + 2, addr, - val, addend); - contents[addr] &=~ 0x40; - contents[addr] |= (contents[addr + 4] << 1) & 0x40; - contents[addr + 4] &=~ 0x20; - contents[addr + 4] |= hold & 0x20; - break; - } - - case R_PPL16B: - case R_PPLN16B: - { - /* The most significant bit is stored in bit 28. */ - bfd_byte hold; - - hold = contents[addr + 1]; - contents[addr + 1] &=~ 0x80; - contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80; - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, addr, - val, addend); - contents[addr + 3] &= ~0x10; - contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10; - contents[addr + 1] &=~ 0x80; - contents[addr + 1] |= hold & 0x80; - break; - } - - case R_PPBASE: - /* Parameter RAM is from 0x1000000 to 0x1000800. */ - contents[addr] &=~ 0x3; - if (val >= 0x1000000 && val < 0x1000800) - contents[addr] |= 0x3; - else - contents[addr] |= 0x2; - rstat = bfd_reloc_ok; - break; - - case R_PPLBASE: - /* Parameter RAM is from 0x1000000 to 0x1000800. */ - contents[addr + 2] &= ~0xc0; - if (val >= 0x1000000 && val < 0x1000800) - contents[addr + 2] |= 0xc0; - else - contents[addr + 2] |= 0x80; - rstat = bfd_reloc_ok; - break; - } - - switch (rstat) - { - default: - abort (); - case bfd_reloc_ok: - break; - case bfd_reloc_outofrange: - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: bad reloc address %#Lx in section `%A'"), - input_bfd, rel->r_vaddr, input_section); - return FALSE; - case bfd_reloc_overflow: - { - const char *name; - char buf[SYMNMLEN + 1]; - - if (symndx == -1) - name = "*ABS*"; - else if (h != NULL) - name = NULL; - else - { - name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); - if (name == NULL) - return FALSE; - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - } - } - return TRUE; -} - -#define TIC80COFF 1 /* Customize coffcode.h */ -#undef C_AUTOARG /* Clashes with TIc80's C_UEXT */ -#undef C_LASTENT /* Clashes with TIc80's C_STATLAB */ - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -CREATE_LITTLE_COFF_TARGET_VEC (tic80_coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-u68k.c b/sdcc/support/sdbinutils/bfd/coff-u68k.c deleted file mode 100644 index cbdb6aa41..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-u68k.c +++ /dev/null @@ -1,36 +0,0 @@ -/* BFD back-end for Motorola 68000 COFF binaries having underscore with name. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGET_SYM m68k_coff_un_vec -#define TARGET_NAME "coff-m68k-un" - -#define NAMES_HAVE_UNDERSCORE - -/* define this to not have multiple copy of m68k_rtype2howto - in the executable file */ -#define ONLY_DECLARE_RELOCS - -/* This magic number indicates that the names have underscores. - Other 68k magic numbers indicate that the names do not have - underscores. */ -#define BADMAG(x) ((x).f_magic != MC68KBCSMAGIC) - -#include "coff-m68k.c" diff --git a/sdcc/support/sdbinutils/bfd/coff-w65.c b/sdcc/support/sdbinutils/bfd/coff-w65.c deleted file mode 100644 index c9c58f74c..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-w65.c +++ /dev/null @@ -1,375 +0,0 @@ -/* BFD back-end for WDC 65816 COFF binaries. - Copyright (C) 1995-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "coff/w65.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) -static reloc_howto_type howto_table[] = -{ - HOWTO (R_W65_ABS8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "abs8", TRUE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_W65_ABS16, 1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (R_W65_ABS24, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs24", TRUE, 0x00ffffff, 0x00ffffff, FALSE), - HOWTO (R_W65_ABS8S8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, ">abs8", TRUE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_W65_ABS8S16, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "^abs8", TRUE, 0x000000ff, 0x000000ff, FALSE), - HOWTO (R_W65_ABS16S8, 1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, ">abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (R_W65_ABS16S16,1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, "^abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), - HOWTO (R_W65_PCR8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "pcrel8", TRUE, 0x000000ff, 0x000000ff, TRUE), - HOWTO (R_W65_PCR16, 1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, TRUE), - HOWTO (R_W65_DP, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "dp", TRUE, 0x000000ff, 0x000000ff, FALSE), -}; - -#define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0])) - -/* Turn a howto into a reloc number. */ - -#define SELECT_RELOC(x,howto) \ - { x.r_type = select_reloc(howto); } - -#define BADMAG(x) (W65BADMAG(x)) -#define W65 1 /* Customize coffcode.h */ -#define __A_MAGIC_SET__ - -/* Code to swap in the reloc */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ - dst->r_stuff[0] = 'S'; \ - dst->r_stuff[1] = 'C'; - -static int -select_reloc (reloc_howto_type *howto) -{ - return howto->type; -} - -/* Code to turn a r_type into a howto ptr, uses the above howto table. */ - -static void -rtype2howto (arelent *internal, - struct internal_reloc *dst) -{ - if (dst->r_type > 0 && dst->r_type <= NUM_HOWTOS) - internal->howto = howto_table + dst->r_type - 1; - else - internal->howto = NULL; -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) - -/* Perform any necessary magic to the addend in a reloc entry. */ - -#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ - cache_ptr->addend = ext_reloc.r_offset; - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing(relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent * relent, - struct internal_reloc *reloc, - asymbol ** symbols, - bfd * abfd, - asection * section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (((int) reloc->r_symndx) > 0) - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - else - relent->sym_ptr_ptr = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr; - - relent->addend = reloc->r_offset; - - relent->address -= section->vma; - /* relent->section = 0;*/ -} - -static int -w65_reloc16_estimate (bfd *abfd, - asection *input_section, - arelent *reloc, - unsigned int shrink, - struct bfd_link_info *link_info) -{ - bfd_vma value; - bfd_vma dot; - bfd_vma gap; - - /* The address of the thing to be relocated will have moved back by - the size of the shrink - but we don't change reloc->address here, - since we need it to know where the relocation lives in the source - uncooked section. */ - - /* reloc->address -= shrink; conceptual */ - - bfd_vma address = reloc->address - shrink; - - switch (reloc->howto->type) - { - case R_MOV16B2: - case R_JMP2: - shrink+=2; - break; - - /* Thing is a move one byte. */ - case R_MOV16B1: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - if (value >= 0xff00) - { - /* Change the reloc type from 16bit, possible 8 to 8bit - possible 16. */ - reloc->howto = reloc->howto + 1; - /* The place to relc moves back by one. */ - /* This will be two bytes smaller in the long run. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - - break; - /* This is the 24 bit branch which could become an 8 bitter, - the relocation points to the first byte of the insn, not the - actual data. */ - - case R_JMPL1: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - dot = input_section->output_section->vma + - input_section->output_offset + address; - - /* See if the address we're looking at within 127 bytes of where - we are, if so then we can use a small branch rather than the - jump we were going to. */ - gap = value - dot; - - if (-120 < (long) gap && (long) gap < 120) - { - /* Change the reloc type from 24bit, possible 8 to 8bit - possible 32. */ - reloc->howto = reloc->howto + 1; - /* This will be two bytes smaller in the long run. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - break; - - case R_JMP1: - value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); - - dot = input_section->output_section->vma + - input_section->output_offset + address; - - /* See if the address we're looking at within 127 bytes of where - we are, if so then we can use a small branch rather than the - jump we were going to. */ - gap = value - (dot - shrink); - - if (-120 < (long) gap && (long) gap < 120) - { - /* Change the reloc type from 16bit, possible 8 to 8bit - possible 16. */ - reloc->howto = reloc->howto + 1; - /* The place to relc moves back by one. */ - - /* This will be two bytes smaller in the long run. */ - shrink += 2; - bfd_perform_slip (abfd, 2, input_section, address); - } - break; - } - - return shrink; -} - -/* First phase of a relaxing link. */ - -/* Reloc types - large small - R_MOV16B1 R_MOV16B2 mov.b with 16bit or 8 bit address - R_JMP1 R_JMP2 jmp or pcrel branch - R_JMPL1 R_JMPL_B8 24jmp or pcrel branch - R_MOV24B1 R_MOV24B2 24 or 8 bit reloc for mov.b */ - -static void -w65_reloc16_extra_cases (bfd *abfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - arelent *reloc, - bfd_byte *data, - unsigned int *src_ptr, - unsigned int *dst_ptr) -{ - unsigned int src_address = *src_ptr; - unsigned int dst_address = *dst_ptr; - asection *input_section = link_order->u.indirect.section; - - switch (reloc->howto->type) - { - case R_W65_ABS8: - case R_W65_DP: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_put_8 (abfd, gap, data + dst_address); - dst_address += 1; - src_address += 1; - } - break; - - case R_W65_ABS8S8: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - gap >>= 8; - bfd_put_8 (abfd, gap, data + dst_address); - dst_address += 1; - src_address += 1; - } - break; - - case R_W65_ABS8S16: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - gap >>= 16; - bfd_put_8 (abfd, gap, data + dst_address); - dst_address += 1; - src_address += 1; - } - break; - - case R_W65_ABS16: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - - bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); - dst_address += 2; - src_address += 2; - } - break; - case R_W65_ABS16S8: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - gap >>= 8; - bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); - dst_address += 2; - src_address += 2; - } - break; - case R_W65_ABS16S16: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - gap >>= 16; - bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); - dst_address += 2; - src_address += 2; - } - break; - - case R_W65_ABS24: - { - unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); - bfd_put_8 (abfd, gap >> 16, data+dst_address + 2); - dst_address += 3; - src_address += 3; - } - break; - - case R_W65_PCR8: - { - int gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (dst_address - + input_section->output_offset - + input_section->output_section->vma); - - gap -= dot + 1; - if (gap < -128 || gap > 127) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_8 (abfd, gap, data + dst_address); - dst_address += 1; - src_address += 1; - } - break; - - case R_W65_PCR16: - { - bfd_vma gap = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (dst_address - + input_section->output_offset - + input_section->output_section->vma); - - /* This wraps within the page, so ignore the relativeness, look at the - high part. */ - if ((gap & 0xf0000) != (dot & 0xf0000)) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - gap -= dot + 2; - bfd_put_16 (abfd, gap, data + dst_address); - dst_address += 2; - src_address += 2; - } - break; - default: - printf (_("ignoring reloc %s\n"), reloc->howto->name); - break; - - } - *src_ptr = src_address; - *dst_ptr = dst_address; -} - -#define coff_reloc16_extra_cases w65_reloc16_extra_cases -#define coff_reloc16_estimate w65_reloc16_estimate - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#undef coff_bfd_get_relocated_section_contents -#undef coff_bfd_relax_section -#define coff_bfd_get_relocated_section_contents \ - bfd_coff_reloc16_get_relocated_section_contents -#define coff_bfd_relax_section bfd_coff_reloc16_relax_section - -CREATE_LITTLE_COFF_TARGET_VEC (w65_coff_vec, "coff-w65", BFD_IS_RELAXABLE, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-we32k.c b/sdcc/support/sdbinutils/bfd/coff-we32k.c deleted file mode 100644 index a71e0ad4d..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-we32k.c +++ /dev/null @@ -1,78 +0,0 @@ -/* BFD back-end for we32k COFF files. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - Contributed by Brendan Kehoe (brendan@cs.widener.edu). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/we32k.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) - -static reloc_howto_type howto_table[] = -{ - EMPTY_HOWTO (0), - EMPTY_HOWTO (1), - EMPTY_HOWTO (2), - EMPTY_HOWTO (3), - EMPTY_HOWTO (4), - EMPTY_HOWTO (5), - HOWTO(R_DIR32, 0, 2, 32, FALSE, 0,complain_overflow_bitfield, 0, "dir32", TRUE, 0xffffffff,0xffffffff, FALSE), - EMPTY_HOWTO (7), - EMPTY_HOWTO (010), - EMPTY_HOWTO (011), - EMPTY_HOWTO (012), - EMPTY_HOWTO (013), - EMPTY_HOWTO (014), - EMPTY_HOWTO (015), - EMPTY_HOWTO (016), - HOWTO(R_RELBYTE, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO(R_RELWORD, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0, "16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO(R_RELLONG, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "32", TRUE, 0xffffffff,0xffffffff, FALSE), - HOWTO(R_PCRBYTE, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0, "DISP8", TRUE, 0x000000ff,0x000000ff, FALSE), - HOWTO(R_PCRWORD, 0, 1, 16, TRUE, 0, complain_overflow_signed, 0, "DISP16", TRUE, 0x0000ffff,0x0000ffff, FALSE), - HOWTO(R_PCRLONG, 0, 2, 32, TRUE, 0, complain_overflow_signed, 0, "DISP32", TRUE, 0xffffffff,0xffffffff, FALSE), -}; - -#define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0])) - -/* Turn a howto into a reloc nunmber */ - -#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } -#define BADMAG(x) WE32KBADMAG(x) -#define WE32K 1 - -#define RTYPE2HOWTO(cache_ptr, dst) \ - ((cache_ptr)->howto = \ - ((dst)->r_type < NUM_HOWTOS \ - ? howto_table + (dst)->r_type \ - : NULL)) - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#define coff_write_armap bsd_write_armap - -CREATE_BIG_COFF_TARGET_VEC (we32k_coff_vec, "coff-we32k", 0, 0, 0, NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff-x86_64.c b/sdcc/support/sdbinutils/bfd/coff-x86_64.c deleted file mode 100644 index 25e988322..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-x86_64.c +++ /dev/null @@ -1,811 +0,0 @@ -/* BFD back-end for AMD 64 COFF files. - Copyright (C) 2006-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. - - Written by Kai Tietz, OneVision Software GmbH&CoKg. */ - -#ifndef COFF_WITH_pex64 -#define COFF_WITH_pex64 -#endif - -/* Note we have to make sure not to include headers twice. - Not all headers are wrapped in #ifdef guards, so we define - PEI_HEADERS to prevent double including here. */ -#ifndef PEI_HEADERS -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "coff/x86_64.h" -#include "coff/internal.h" -#include "coff/pe.h" -#include "libcoff.h" -#include "libiberty.h" -#endif - -#define BADMAG(x) AMD64BADMAG(x) - -#ifdef COFF_WITH_pex64 -# undef AOUTSZ -# define AOUTSZ PEPAOUTSZ -# define PEAOUTHDR PEPAOUTHDR -#endif - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2) - -/* The page size is a guess based on ELF. */ - -#define COFF_PAGE_SIZE 0x1000 - -/* For some reason when using AMD COFF the value stored in the .text - section for a reference to a common symbol is the value itself plus - any desired offset. Ian Taylor, Cygnus Support. */ - -/* If we are producing relocatable output, we need to do some - adjustments to the object file that are not done by the - bfd_perform_relocation function. This function is called by every - reloc type to make any required adjustments. */ - -static bfd_reloc_status_type -coff_amd64_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - symvalue diff; - -#if !defined(COFF_WITH_PE) - if (output_bfd == NULL) - return bfd_reloc_continue; -#endif - - if (bfd_is_com_section (symbol->section)) - { -#if !defined(COFF_WITH_PE) - /* We are relocating a common symbol. The current value in the - object file is ORIG + OFFSET, where ORIG is the value of the - common symbol as seen by the object file when it was compiled - (this may be zero if the symbol was undefined) and OFFSET is - the offset into the common symbol (normally zero, but may be - non-zero when referring to a field in a common structure). - ORIG is the negative of reloc_entry->addend, which is set by - the CALC_ADDEND macro below. We want to replace the value in - the object file with NEW + OFFSET, where NEW is the value of - the common symbol which we are going to put in the final - object file. NEW is symbol->value. */ - diff = symbol->value + reloc_entry->addend; -#else - /* In PE mode, we do not offset the common symbol. */ - diff = reloc_entry->addend; -#endif - } - else - { - /* For some reason bfd_perform_relocation always effectively - ignores the addend for a COFF target when producing - relocatable output. This seems to be always wrong for 386 - COFF, so we handle the addend here instead. */ -#if defined(COFF_WITH_PE) - if (output_bfd == NULL) - { - reloc_howto_type *howto = reloc_entry->howto; - - /* Although PC relative relocations are very similar between - PE and non-PE formats, but they are off by 1 << howto->size - bytes. For the external relocation, PE is very different - from others. See md_apply_fix3 () in gas/config/tc-amd64.c. - When we link PE and non-PE object files together to - generate a non-PE executable, we have to compensate it - here. */ - if(howto->pc_relative && howto->pcrel_offset) - diff = -(1 << howto->size); - else if(symbol->flags & BSF_WEAK) - diff = reloc_entry->addend - symbol->value; - else - diff = -reloc_entry->addend; - } - else -#endif - diff = reloc_entry->addend; - } - -#if defined(COFF_WITH_PE) - /* FIXME: How should this case be handled? */ - if (reloc_entry->howto->type == R_AMD64_IMAGEBASE - && output_bfd != NULL - && bfd_get_flavour (output_bfd) == bfd_target_coff_flavour) - diff -= pe_data (output_bfd)->pe_opthdr.ImageBase; -#endif - -#define DOIT(x) \ - x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask)) - - if (diff != 0) - { - reloc_howto_type *howto = reloc_entry->howto; - unsigned char *addr = (unsigned char *) data + reloc_entry->address; - - if (! bfd_reloc_offset_in_range (howto, abfd, input_section, - reloc_entry->address - * bfd_octets_per_byte (abfd))) - return bfd_reloc_outofrange; - - switch (howto->size) - { - case 0: - { - char x = bfd_get_8 (abfd, addr); - DOIT (x); - bfd_put_8 (abfd, x, addr); - } - break; - - case 1: - { - short x = bfd_get_16 (abfd, addr); - DOIT (x); - bfd_put_16 (abfd, (bfd_vma) x, addr); - } - break; - - case 2: - { - long x = bfd_get_32 (abfd, addr); - DOIT (x); - bfd_put_32 (abfd, (bfd_vma) x, addr); - } - break; - - case 4: - { - bfd_uint64_t x = bfd_get_64 (abfd, addr); - DOIT (x); - bfd_put_64 (abfd, x, addr); - } - break; - - default: - bfd_set_error (bfd_error_bad_value); - return bfd_reloc_notsupported; - } - } - - /* Now let bfd_perform_relocation finish everything up. */ - return bfd_reloc_continue; -} - -#if defined(COFF_WITH_PE) -/* Return TRUE if this relocation should appear in the output .reloc - section. */ - -static bfd_boolean -in_reloc_p (bfd *abfd ATTRIBUTE_UNUSED, reloc_howto_type *howto) -{ - return ! howto->pc_relative && howto->type != R_AMD64_IMAGEBASE - && howto->type != R_AMD64_SECREL; -} -#endif /* COFF_WITH_PE */ - -#ifndef PCRELOFFSET -#define PCRELOFFSET TRUE -#endif - -static reloc_howto_type howto_table[] = -{ - EMPTY_HOWTO (0), - HOWTO (R_AMD64_DIR64, /* type 1*/ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long, 4 = long long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_64", /* name */ - TRUE, /* partial_inplace */ - 0xffffffffffffffffll, /* src_mask */ - 0xffffffffffffffffll, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_AMD64_DIR32, /* type 2 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - /* PE IMAGE_REL_AMD64_ADDR32NB relocation (3). */ - HOWTO (R_AMD64_IMAGEBASE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "rva32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* 32-bit longword PC relative relocation (4). */ - HOWTO (R_AMD64_PCRLONG, /* type 4 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_PC32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - - HOWTO (R_AMD64_PCRLONG_1, /* type 5 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "DISP32+1", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_AMD64_PCRLONG_2, /* type 6 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "DISP32+2", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_AMD64_PCRLONG_3, /* type 7 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "DISP32+3", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_AMD64_PCRLONG_4, /* type 8 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "DISP32+4", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - HOWTO (R_AMD64_PCRLONG_5, /* type 9 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "DISP32+5", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - EMPTY_HOWTO (10), /* R_AMD64_SECTION 10 */ -#if defined(COFF_WITH_PE) - /* 32-bit longword section relative relocation (11). */ - HOWTO (R_AMD64_SECREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "secrel32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -#else - EMPTY_HOWTO (11), -#endif - EMPTY_HOWTO (12), - EMPTY_HOWTO (13), -#ifndef DONT_EXTEND_AMD64 - HOWTO (R_AMD64_PCRQUAD, - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_PC64", /* name */ - TRUE, /* partial_inplace */ - 0xffffffffffffffffll, /* src_mask */ - 0xffffffffffffffffll, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ -#else - EMPTY_HOWTO (14), -#endif - /* Byte relocation (15). */ - HOWTO (R_RELBYTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 16-bit word relocation (16). */ - HOWTO (R_RELWORD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 32-bit longword relocation (17). */ - HOWTO (R_RELLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_32S", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* Byte PC relative relocation (18). */ - HOWTO (R_PCRBYTE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_PC8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 16-bit word PC relative relocation (19). */ - HOWTO (R_PCRWORD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_PC16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - PCRELOFFSET), /* pcrel_offset */ - /* 32-bit longword PC relative relocation (20). */ - HOWTO (R_PCRLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - coff_amd64_reloc, /* special_function */ - "R_X86_64_PC32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - PCRELOFFSET) /* pcrel_offset */ -}; - -#define NUM_HOWTOS ARRAY_SIZE (howto_table) - -/* Turn a howto into a reloc nunmber */ - -#define SELECT_RELOC(x,howto) { x.r_type = howto->type; } -#define I386 1 /* Customize coffcode.h */ -#define AMD64 1 - -#define RTYPE2HOWTO(cache_ptr, dst) \ - ((cache_ptr)->howto = \ - ((dst)->r_type < NUM_HOWTOS) \ - ? howto_table + (dst)->r_type \ - : NULL) - -/* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared - library. On some other COFF targets STYP_BSS is normally - STYP_NOLOAD. */ -#define BSS_NOLOAD_IS_SHARED_LIBRARY - -/* Compute the addend of a reloc. If the reloc is to a common symbol, - the object file contains the value of the common symbol. By the - time this is called, the linker may be using a different symbol - from a different object file with a different value. Therefore, we - hack wildly to locate the original symbol from this file so that we - can make the correct adjustment. This macro sets coffsym to the - symbol from the original file, and uses it to set the addend value - correctly. If this is not a common symbol, the usual addend - calculation is done, except that an additional tweak is needed for - PC relative relocs. - FIXME: This macro refers to symbols and asect; these are from the - calling function, not the macro arguments. */ - -#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr) \ - { \ - coff_symbol_type *coffsym = NULL; \ - \ - if (ptr && bfd_asymbol_bfd (ptr) != abfd) \ - coffsym = (obj_symbols (abfd) \ - + (cache_ptr->sym_ptr_ptr - symbols)); \ - else if (ptr) \ - coffsym = coff_symbol_from (ptr); \ - \ - if (coffsym != NULL \ - && coffsym->native->u.syment.n_scnum == 0) \ - cache_ptr->addend = - coffsym->native->u.syment.n_value; \ - else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ - && ptr->section != NULL) \ - cache_ptr->addend = - (ptr->section->vma + ptr->value); \ - else \ - cache_ptr->addend = 0; \ - if (ptr && reloc.r_type < NUM_HOWTOS \ - && howto_table[reloc.r_type].pc_relative) \ - cache_ptr->addend += asect->vma; \ - } - -/* We use the special COFF backend linker. For normal AMD64 COFF, we - can use the generic relocate_section routine. For PE, we need our - own routine. */ - -#if !defined(COFF_WITH_PE) - -#define coff_relocate_section _bfd_coff_generic_relocate_section - -#else /* COFF_WITH_PE */ - -/* The PE relocate section routine. The only difference between this - and the regular routine is that we don't want to do anything for a - relocatable link. */ - -static bfd_boolean -coff_pe_amd64_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - if (bfd_link_relocatable (info)) - return TRUE; - - return _bfd_coff_generic_relocate_section (output_bfd, info, input_bfd,input_section, contents,relocs, syms, sections); -} - -#define coff_relocate_section coff_pe_amd64_relocate_section - -#endif /* COFF_WITH_PE */ - -/* Convert an rtype to howto for the COFF backend linker. */ - -static reloc_howto_type * -coff_amd64_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - struct internal_reloc *rel, - struct coff_link_hash_entry *h, - struct internal_syment *sym, - bfd_vma *addendp) -{ - reloc_howto_type *howto; - - if (rel->r_type >= NUM_HOWTOS) - { - bfd_set_error (bfd_error_bad_value); - return NULL; - } - howto = howto_table + rel->r_type; - -#if defined(COFF_WITH_PE) - /* Cancel out code in _bfd_coff_generic_relocate_section. */ - *addendp = 0; - if (rel->r_type >= R_AMD64_PCRLONG_1 && rel->r_type <= R_AMD64_PCRLONG_5) - { - *addendp -= (bfd_vma)(rel->r_type - R_AMD64_PCRLONG); - rel->r_type = R_AMD64_PCRLONG; - } -#endif - - if (howto->pc_relative) - *addendp += sec->vma; - - if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0) - { - /* This is a common symbol. The section contents include the - size (sym->n_value) as an addend. The relocate_section - function will be adding in the final value of the symbol. We - need to subtract out the current size in order to get the - correct result. */ - BFD_ASSERT (h != NULL); - -#if !defined(COFF_WITH_PE) - /* I think we *do* want to bypass this. If we don't, I have - seen some data parameters get the wrong relocation address. - If I link two versions with and without this section bypassed - and then do a binary comparison, the addresses which are - different can be looked up in the map. The case in which - this section has been bypassed has addresses which correspond - to values I can find in the map. */ - *addendp -= sym->n_value; -#endif - } - -#if !defined(COFF_WITH_PE) - /* If the output symbol is common (in which case this must be a - relocatable link), we need to add in the final size of the - common symbol. */ - if (h != NULL && h->root.type == bfd_link_hash_common) - *addendp += h->root.u.c.size; -#endif - -#if defined(COFF_WITH_PE) - if (howto->pc_relative) - { -#ifndef DONT_EXTEND_AMD64 - if (rel->r_type == R_AMD64_PCRQUAD) - *addendp -= 8; - else -#endif - *addendp -= 4; - - /* If the symbol is defined, then the generic code is going to - add back the symbol value in order to cancel out an - adjustment it made to the addend. However, we set the addend - to 0 at the start of this function. We need to adjust here, - to avoid the adjustment the generic code will make. FIXME: - This is getting a bit hackish. */ - if (sym != NULL && sym->n_scnum != 0) - *addendp -= sym->n_value; - } - - if (rel->r_type == R_AMD64_IMAGEBASE - && (bfd_get_flavour (sec->output_section->owner) == bfd_target_coff_flavour)) - *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase; - - if (rel->r_type == R_AMD64_SECREL) - { - bfd_vma osect_vma; - - if (h && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - osect_vma = h->root.u.def.section->output_section->vma; - else - { - asection *s; - int i; - - /* Sigh, the only way to get the section to offset against - is to find it the hard way. */ - for (s = abfd->sections, i = 1; i < sym->n_scnum; i++) - s = s->next; - - osect_vma = s->output_section->vma; - } - - *addendp -= osect_vma; - } -#endif - - return howto; -} - -#define coff_bfd_reloc_type_lookup coff_amd64_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_amd64_reloc_name_lookup - -static reloc_howto_type * -coff_amd64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_RVA: - return howto_table + R_AMD64_IMAGEBASE; - case BFD_RELOC_32: - return howto_table + R_AMD64_DIR32; - case BFD_RELOC_64: - return howto_table + R_AMD64_DIR64; - case BFD_RELOC_64_PCREL: -#ifndef DONT_EXTEND_AMD64 - return howto_table + R_AMD64_PCRQUAD; -#else - /* Fall through. */ -#endif - case BFD_RELOC_32_PCREL: - return howto_table + R_AMD64_PCRLONG; - case BFD_RELOC_X86_64_32S: - return howto_table + R_RELLONG; - case BFD_RELOC_16: - return howto_table + R_RELWORD; - case BFD_RELOC_16_PCREL: - return howto_table + R_PCRWORD; - case BFD_RELOC_8: - return howto_table + R_RELBYTE; - case BFD_RELOC_8_PCREL: - return howto_table + R_PCRBYTE; -#if defined(COFF_WITH_PE) - case BFD_RELOC_32_SECREL: - return howto_table + R_AMD64_SECREL; -#endif - default: - BFD_FAIL (); - return 0; - } -} - -static reloc_howto_type * -coff_amd64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < NUM_HOWTOS; i++) - if (howto_table[i].name != NULL - && strcasecmp (howto_table[i].name, r_name) == 0) - return &howto_table[i]; - - return NULL; -} - -#define coff_rtype_to_howto coff_amd64_rtype_to_howto - -#ifdef TARGET_UNDERSCORE - -/* If amd64 gcc uses underscores for symbol names, then it does not use - a leading dot for local labels, so if TARGET_UNDERSCORE is defined - we treat all symbols starting with L as local. */ - -static bfd_boolean -coff_amd64_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == 'L') - return TRUE; - - return _bfd_coff_is_local_label_name (abfd, name); -} - -#define coff_bfd_is_local_label_name coff_amd64_is_local_label_name - -#endif /* TARGET_UNDERSCORE */ - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#ifdef PE -#define amd64coff_object_p pe_bfd_object_p -#else -#define amd64coff_object_p coff_object_p -#endif - -const bfd_target -#ifdef TARGET_SYM - TARGET_SYM = -#else - x86_64_coff_vec = -#endif -{ -#ifdef TARGET_NAME - TARGET_NAME, -#else - "coff-x86-64", /* Name. */ -#endif - bfd_target_coff_flavour, - BFD_ENDIAN_LITTLE, /* Data byte order is little. */ - BFD_ENDIAN_LITTLE, /* Header byte order is little. */ - - (HAS_RELOC | EXEC_P | /* Object flags. */ - HAS_LINENO | HAS_DEBUG | - HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED | BFD_COMPRESS | BFD_DECOMPRESS), - - (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* Section flags. */ -#if defined(COFF_WITH_PE) - | SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_READONLY | SEC_DEBUGGING -#endif - | SEC_CODE | SEC_DATA | SEC_EXCLUDE ), - -#ifdef TARGET_UNDERSCORE - TARGET_UNDERSCORE, /* Leading underscore. */ -#else - 0, /* Leading underscore. */ -#endif - '/', /* Ar_pad_char. */ - 15, /* Ar_max_namelen. */ - 0, /* match priority. */ - - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */ - bfd_getl64, bfd_getl_signed_64, bfd_putl64, - bfd_getl32, bfd_getl_signed_32, bfd_putl32, - bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs. */ - - /* Note that we allow an object file to be treated as a core file as well. */ - { _bfd_dummy_target, amd64coff_object_p, /* BFD_check_format. */ - bfd_generic_archive_p, amd64coff_object_p }, - { bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format. */ - bfd_false }, - { bfd_false, coff_write_object_contents, /* bfd_write_contents. */ - _bfd_write_archive_contents, bfd_false }, - - BFD_JUMP_TABLE_GENERIC (coff), - BFD_JUMP_TABLE_COPY (coff), - BFD_JUMP_TABLE_CORE (_bfd_nocore), - BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), - BFD_JUMP_TABLE_SYMBOLS (coff), - BFD_JUMP_TABLE_RELOCS (coff), - BFD_JUMP_TABLE_WRITE (coff), - BFD_JUMP_TABLE_LINK (coff), - BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), - - NULL, - - COFF_SWAP_TABLE -}; diff --git a/sdcc/support/sdbinutils/bfd/coff-z80.c b/sdcc/support/sdbinutils/bfd/coff-z80.c deleted file mode 100644 index aaf510924..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-z80.c +++ /dev/null @@ -1,283 +0,0 @@ -/* BFD back-end for Zilog Z80 COFF binaries. - Copyright (C) 2005-2018 Free Software Foundation, Inc. - Contributed by Arnold Metselaar - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "coff/z80.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0 - -static reloc_howto_type r_imm32 = -HOWTO (R_IMM32, 0, 2, 32, FALSE, 0, - complain_overflow_dont, 0, "r_imm32", TRUE, 0xffffffff, 0xffffffff, - FALSE); - -static reloc_howto_type r_imm24 = -HOWTO (R_IMM24, 0, 1, 24, FALSE, 0, - complain_overflow_dont, 0, "r_imm24", TRUE, 0x00ffffff, 0x00ffffff, - FALSE); - -static reloc_howto_type r_imm16 = -HOWTO (R_IMM16, 0, 1, 16, FALSE, 0, - complain_overflow_dont, 0, "r_imm16", TRUE, 0x0000ffff, 0x0000ffff, - FALSE); - -static reloc_howto_type r_imm8 = -HOWTO (R_IMM8, 0, 0, 8, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff, - FALSE); - -static reloc_howto_type r_jr = -HOWTO (R_JR, 0, 0, 8, TRUE, 0, - complain_overflow_signed, 0, "r_jr", FALSE, 0, 0xFF, - FALSE); - -static reloc_howto_type r_off8 = -HOWTO (R_OFF8, 0, 0, 8, FALSE, 0, - complain_overflow_signed, 0,"r_off8", FALSE, 0, 0xff, - FALSE); - - -#define BADMAG(x) Z80BADMAG(x) -#define Z80 1 /* Customize coffcode.h. */ -#define __A_MAGIC_SET__ - -/* Code to swap in the reloc. */ - -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 - -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ - dst->r_stuff[0] = 'S'; \ - dst->r_stuff[1] = 'C'; - -/* Code to turn a r_type into a howto ptr, uses the above howto table. */ - -static void -rtype2howto (arelent *internal, struct internal_reloc *dst) -{ - switch (dst->r_type) - { - default: - internal->howto = NULL; - break; - case R_IMM8: - internal->howto = &r_imm8; - break; - case R_IMM16: - internal->howto = &r_imm16; - break; - case R_IMM24: - internal->howto = &r_imm24; - break; - case R_IMM32: - internal->howto = &r_imm32; - break; - case R_JR: - internal->howto = &r_jr; - break; - case R_OFF8: - internal->howto = &r_off8; - break; - } -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry) - -static reloc_howto_type * -coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_8: return & r_imm8; - case BFD_RELOC_16: return & r_imm16; - case BFD_RELOC_24: return & r_imm24; - case BFD_RELOC_32: return & r_imm32; - case BFD_RELOC_8_PCREL: return & r_jr; - case BFD_RELOC_Z80_DISP8: return & r_off8; - default: BFD_FAIL (); - return NULL; - } -} - -static reloc_howto_type * -coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - if (strcasecmp (r_imm8.name, r_name) == 0) - return &r_imm8; - if (strcasecmp (r_imm16.name, r_name) == 0) - return &r_imm16; - if (strcasecmp (r_imm24.name, r_name) == 0) - return &r_imm24; - if (strcasecmp (r_imm32.name, r_name) == 0) - return &r_imm32; - if (strcasecmp (r_jr.name, r_name) == 0) - return &r_jr; - if (strcasecmp (r_off8.name, r_name) == 0) - return &r_off8; - - return NULL; -} - -/* Perform any necessary magic to the addend in a reloc entry. */ - -#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ - cache_ptr->addend = ext_reloc.r_offset; - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing(relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent *relent, - struct internal_reloc *reloc, - asymbol **symbols, - bfd *abfd, - asection *section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (reloc->r_symndx > 0) - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - else - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - relent->addend = reloc->r_offset; - relent->address -= section->vma; -} - -static void -extra_case (bfd *in_abfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - arelent *reloc, - bfd_byte *data, - unsigned int *src_ptr, - unsigned int *dst_ptr) -{ - asection * input_section = link_order->u.indirect.section; - int val; - - switch (reloc->howto->type) - { - case R_OFF8: - val = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - if (val>127 || val<-128) /* Test for overflow. */ - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_8 (in_abfd, val, data + *dst_ptr); - (*dst_ptr) += 1; - (*src_ptr) += 1; - break; - - case R_IMM8: - val = bfd_get_8 ( in_abfd, data+*src_ptr) - + bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_8 (in_abfd, val, data + *dst_ptr); - (*dst_ptr) += 1; - (*src_ptr) += 1; - break; - - case R_IMM16: - val = bfd_get_16 ( in_abfd, data+*src_ptr) - + bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_16 (in_abfd, val, data + *dst_ptr); - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - - case R_IMM24: - val = bfd_get_16 ( in_abfd, data+*src_ptr) - + (bfd_get_8 ( in_abfd, data+*src_ptr+2) << 16) - + bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_16 (in_abfd, val, data + *dst_ptr); - bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr+2); - (*dst_ptr) += 3; - (*src_ptr) += 3; - break; - - case R_IMM32: - val = bfd_get_32 ( in_abfd, data+*src_ptr) - + bfd_coff_reloc16_get_value (reloc, link_info, input_section); - bfd_put_32 (in_abfd, val, data + *dst_ptr); - (*dst_ptr) += 4; - (*src_ptr) += 4; - break; - - case R_JR: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 1; /* -1, Since the offset is relative - to the value of PC after reading - the offset. */ - - if (gap >= 128 || gap < -128) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_8 (in_abfd, gap, data + *dst_ptr); - (*dst_ptr)++; - (*src_ptr)++; - break; - } - - default: - abort (); - } -} - -#define coff_reloc16_extra_cases extra_case -#define coff_bfd_reloc_type_lookup coff_z80_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#undef coff_bfd_get_relocated_section_contents -#define coff_bfd_get_relocated_section_contents \ - bfd_coff_reloc16_get_relocated_section_contents - -#undef coff_bfd_relax_section -#define coff_bfd_relax_section bfd_coff_reloc16_relax_section - -CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0, - SEC_CODE | SEC_DATA, '\0', NULL, - COFF_SWAP_TABLE) - diff --git a/sdcc/support/sdbinutils/bfd/coff-z8k.c b/sdcc/support/sdbinutils/bfd/coff-z8k.c deleted file mode 100644 index 0adfd7118..000000000 --- a/sdcc/support/sdbinutils/bfd/coff-z8k.c +++ /dev/null @@ -1,375 +0,0 @@ -/* BFD back-end for Zilog Z800n COFF binaries. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - Contributed by Cygnus Support. - 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "coff/z8k.h" -#include "coff/internal.h" -#include "libcoff.h" - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) - -static reloc_howto_type r_imm32 = -HOWTO (R_IMM32, 0, 2, 32, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm32", TRUE, 0xffffffff, - 0xffffffff, FALSE); - -static reloc_howto_type r_imm4l = -HOWTO (R_IMM4L, 0, 0, 4, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm4l", TRUE, 0xf, 0xf, FALSE); - -static reloc_howto_type r_da = -HOWTO (R_IMM16, 0, 1, 16, FALSE, 0, - complain_overflow_bitfield, 0, "r_da", TRUE, 0x0000ffff, 0x0000ffff, - FALSE); - -static reloc_howto_type r_imm8 = -HOWTO (R_IMM8, 0, 0, 8, FALSE, 0, - complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff, - FALSE); - -static reloc_howto_type r_rel16 = -HOWTO (R_REL16, 0, 1, 16, FALSE, 0, - complain_overflow_bitfield, 0, "r_rel16", TRUE, 0x0000ffff, 0x0000ffff, - TRUE); - -static reloc_howto_type r_jr = -HOWTO (R_JR, 1, 0, 8, TRUE, 0, complain_overflow_signed, 0, - "r_jr", TRUE, 0xff, 0xff, TRUE); - -static reloc_howto_type r_disp7 = -HOWTO (R_DISP7, 0, 0, 7, TRUE, 0, complain_overflow_bitfield, 0, - "r_disp7", TRUE, 0x7f, 0x7f, TRUE); - -static reloc_howto_type r_callr = -HOWTO (R_CALLR, 1, 1, 12, TRUE, 0, complain_overflow_signed, 0, - "r_callr", TRUE, 0xfff, 0xfff, TRUE); - -#define BADMAG(x) Z8KBADMAG(x) -#define Z8K 1 /* Customize coffcode.h. */ -#define __A_MAGIC_SET__ - -/* Code to swap in the reloc. */ -#define SWAP_IN_RELOC_OFFSET H_GET_32 -#define SWAP_OUT_RELOC_OFFSET H_PUT_32 -#define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ - dst->r_stuff[0] = 'S'; \ - dst->r_stuff[1] = 'C'; - -/* Code to turn a r_type into a howto ptr, uses the above howto table. */ - -static void -rtype2howto (arelent *internal, struct internal_reloc *dst) -{ - switch (dst->r_type) - { - default: - internal->howto = NULL; - break; - case R_IMM8: - internal->howto = &r_imm8; - break; - case R_IMM16: - internal->howto = &r_da; - break; - case R_JR: - internal->howto = &r_jr; - break; - case R_DISP7: - internal->howto = &r_disp7; - break; - case R_CALLR: - internal->howto = &r_callr; - break; - case R_REL16: - internal->howto = &r_rel16; - break; - case R_IMM32: - internal->howto = &r_imm32; - break; - case R_IMM4L: - internal->howto = &r_imm4l; - break; - } -} - -#define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry) - -static reloc_howto_type * -coff_z8k_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_8: return & r_imm8; - case BFD_RELOC_16: return & r_da; - case BFD_RELOC_32: return & r_imm32; - case BFD_RELOC_8_PCREL: return & r_jr; - case BFD_RELOC_16_PCREL: return & r_rel16; - case BFD_RELOC_Z8K_DISP7: return & r_disp7; - case BFD_RELOC_Z8K_CALLR: return & r_callr; - case BFD_RELOC_Z8K_IMM4L: return & r_imm4l; - default: BFD_FAIL (); - return 0; - } -} - -static reloc_howto_type * -coff_z8k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - if (strcasecmp (r_imm8.name, r_name) == 0) - return &r_imm8; - if (strcasecmp (r_da.name, r_name) == 0) - return &r_da; - if (strcasecmp (r_imm32.name, r_name) == 0) - return &r_imm32; - if (strcasecmp (r_jr.name, r_name) == 0) - return &r_jr; - if (strcasecmp (r_rel16.name, r_name) == 0) - return &r_rel16; - if (strcasecmp (r_disp7.name, r_name) == 0) - return &r_disp7; - if (strcasecmp (r_callr.name, r_name) == 0) - return &r_callr; - if (strcasecmp (r_imm4l.name, r_name) == 0) - return &r_imm4l; - - return NULL; -} - -/* Perform any necessary magic to the addend in a reloc entry. */ - -#define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ - cache_ptr->addend = ext_reloc.r_offset; - -#define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ - reloc_processing(relent, reloc, symbols, abfd, section) - -static void -reloc_processing (arelent *relent, - struct internal_reloc *reloc, - asymbol **symbols, - bfd *abfd, - asection *section) -{ - relent->address = reloc->r_vaddr; - rtype2howto (relent, reloc); - - if (reloc->r_symndx > 0) - relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; - else - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - relent->addend = reloc->r_offset; - relent->address -= section->vma; -} - -static void -extra_case (bfd *in_abfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - arelent *reloc, - bfd_byte *data, - unsigned int *src_ptr, - unsigned int *dst_ptr) -{ - asection * input_section = link_order->u.indirect.section; - - switch (reloc->howto->type) - { - case R_IMM8: - bfd_put_8 (in_abfd, - bfd_coff_reloc16_get_value (reloc, link_info, input_section), - data + *dst_ptr); - (*dst_ptr) += 1; - (*src_ptr) += 1; - break; - - case R_IMM32: - /* If no flags are set, assume immediate value. */ - if (! (*reloc->sym_ptr_ptr)->section->flags) - { - bfd_put_32 (in_abfd, - bfd_coff_reloc16_get_value (reloc, link_info, - input_section), - data + *dst_ptr); - } - else - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - /* Addresses are 23 bit, and the layout of those in a 32-bit - value is as follows: - 1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA - (A - address bits, x - ignore). */ - dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000; - bfd_put_32 (in_abfd, dst, data + *dst_ptr); - } - (*dst_ptr) += 4; - (*src_ptr) += 4; - break; - - case R_IMM4L: - bfd_put_8 (in_abfd, - ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0) - | (0x0f - & bfd_coff_reloc16_get_value (reloc, link_info, - input_section))), - data + *dst_ptr); - (*dst_ptr) += 1; - (*src_ptr) += 1; - break; - - case R_IMM16: - bfd_put_16 (in_abfd, - bfd_coff_reloc16_get_value (reloc, link_info, input_section), - data + *dst_ptr); - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - - case R_JR: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 1; /* -1, since we're in the odd byte of the - word and the pc's been incremented. */ - - if (gap & 1) - abort (); - gap /= 2; - if (gap > 127 || gap < -128) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_8 (in_abfd, gap, data + *dst_ptr); - (*dst_ptr)++; - (*src_ptr)++; - break; - } - - case R_DISP7: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 1; /* -1, since we're in the odd byte of the - word and the pc's been incremented. */ - - if (gap & 1) - abort (); - gap /= 2; - - if (gap > 0 || gap < -127) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_8 (in_abfd, - (bfd_get_8 ( in_abfd, data + *dst_ptr) & 0x80) + (-gap & 0x7f), - data + *dst_ptr); - (*dst_ptr)++; - (*src_ptr)++; - break; - } - - case R_CALLR: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 2; - - if (gap & 1) - abort (); - if (gap > 4096 || gap < -4095) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - gap /= 2; - bfd_put_16 (in_abfd, - (bfd_get_16 ( in_abfd, data + *dst_ptr) & 0xf000) | (-gap & 0x0fff), - data + *dst_ptr); - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - } - - case R_REL16: - { - bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, - input_section); - bfd_vma dot = (*dst_ptr - + input_section->output_offset - + input_section->output_section->vma); - int gap = dst - dot - 2; - - if (gap > 32767 || gap < -32768) - (*link_info->callbacks->reloc_overflow) - (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), - reloc->howto->name, reloc->addend, input_section->owner, - input_section, reloc->address); - - bfd_put_16 (in_abfd, (bfd_vma) gap, data + *dst_ptr); - (*dst_ptr) += 2; - (*src_ptr) += 2; - break; - } - - default: - abort (); - } -} - -#define coff_reloc16_extra_cases extra_case -#define coff_bfd_reloc_type_lookup coff_z8k_reloc_type_lookup -#define coff_bfd_reloc_name_lookup coff_z8k_reloc_name_lookup - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include "coffcode.h" - -#undef coff_bfd_get_relocated_section_contents -#define coff_bfd_get_relocated_section_contents \ - bfd_coff_reloc16_get_relocated_section_contents - -#undef coff_bfd_relax_section -#define coff_bfd_relax_section bfd_coff_reloc16_relax_section - -CREATE_BIG_COFF_TARGET_VEC (z8k_coff_vec, "coff-z8k", 0, 0, '_', NULL, COFF_SWAP_TABLE) diff --git a/sdcc/support/sdbinutils/bfd/coff64-rs6000.c b/sdcc/support/sdbinutils/bfd/coff64-rs6000.c deleted file mode 100644 index 884d82a12..000000000 --- a/sdcc/support/sdbinutils/bfd/coff64-rs6000.c +++ /dev/null @@ -1,3063 +0,0 @@ -/* BFD back-end for IBM RS/6000 "XCOFF64" files. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Written Clinton Popetz. - 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "coff/internal.h" -#include "coff/xcoff.h" -#include "coff/rs6k64.h" -#include "libcoff.h" -#include "libxcoff.h" - -#define GET_FILEHDR_SYMPTR H_GET_64 -#define PUT_FILEHDR_SYMPTR H_PUT_64 -#define GET_AOUTHDR_DATA_START H_GET_64 -#define PUT_AOUTHDR_DATA_START H_PUT_64 -#define GET_AOUTHDR_TEXT_START H_GET_64 -#define PUT_AOUTHDR_TEXT_START H_PUT_64 -#define GET_AOUTHDR_TSIZE H_GET_64 -#define PUT_AOUTHDR_TSIZE H_PUT_64 -#define GET_AOUTHDR_DSIZE H_GET_64 -#define PUT_AOUTHDR_DSIZE H_PUT_64 -#define GET_AOUTHDR_BSIZE H_GET_64 -#define PUT_AOUTHDR_BSIZE H_PUT_64 -#define GET_AOUTHDR_ENTRY H_GET_64 -#define PUT_AOUTHDR_ENTRY H_PUT_64 -#define GET_SCNHDR_PADDR H_GET_64 -#define PUT_SCNHDR_PADDR H_PUT_64 -#define GET_SCNHDR_VADDR H_GET_64 -#define PUT_SCNHDR_VADDR H_PUT_64 -#define GET_SCNHDR_SIZE H_GET_64 -#define PUT_SCNHDR_SIZE H_PUT_64 -#define GET_SCNHDR_SCNPTR H_GET_64 -#define PUT_SCNHDR_SCNPTR H_PUT_64 -#define GET_SCNHDR_RELPTR H_GET_64 -#define PUT_SCNHDR_RELPTR H_PUT_64 -#define GET_SCNHDR_LNNOPTR H_GET_64 -#define PUT_SCNHDR_LNNOPTR H_PUT_64 -#define GET_SCNHDR_NRELOC H_GET_32 -#define MAX_SCNHDR_NRELOC 0xffffffff -#define PUT_SCNHDR_NRELOC H_PUT_32 -#define GET_SCNHDR_NLNNO H_GET_32 -#define MAX_SCNHDR_NLNNO 0xffffffff -#define PUT_SCNHDR_NLNNO H_PUT_32 -#define GET_RELOC_VADDR H_GET_64 -#define PUT_RELOC_VADDR H_PUT_64 - -#define COFF_FORCE_SYMBOLS_IN_STRINGS -#define COFF_DEBUG_STRING_WIDE_PREFIX - - -#define COFF_ADJUST_SCNHDR_OUT_POST(ABFD, INT, EXT) \ - do \ - { \ - memset (((SCNHDR *) EXT)->s_pad, 0, \ - sizeof (((SCNHDR *) EXT)->s_pad)); \ - } \ - while (0) - -#define NO_COFF_LINENOS - -#define coff_SWAP_lineno_in _bfd_xcoff64_swap_lineno_in -#define coff_SWAP_lineno_out _bfd_xcoff64_swap_lineno_out - -static void _bfd_xcoff64_swap_lineno_in - (bfd *, void *, void *); -static unsigned int _bfd_xcoff64_swap_lineno_out - (bfd *, void *, void *); -static bfd_boolean _bfd_xcoff64_put_symbol_name - (struct bfd_link_info *, struct bfd_strtab_hash *, - struct internal_syment *, const char *); -static bfd_boolean _bfd_xcoff64_put_ldsymbol_name - (bfd *, struct xcoff_loader_info *, struct internal_ldsym *, const char *); -static void _bfd_xcoff64_swap_sym_in - (bfd *, void *, void *); -static unsigned int _bfd_xcoff64_swap_sym_out - (bfd *, void *, void *); -static void _bfd_xcoff64_swap_aux_in - (bfd *, void *, int, int, int, int, void *); -static unsigned int _bfd_xcoff64_swap_aux_out - (bfd *, void *, int, int, int, int, void *); -static void xcoff64_swap_reloc_in - (bfd *, void *, void *); -static unsigned int xcoff64_swap_reloc_out - (bfd *, void *, void *); -extern bfd_boolean _bfd_xcoff_mkobject - (bfd *); -extern bfd_boolean _bfd_xcoff_copy_private_bfd_data - (bfd *, bfd *); -extern bfd_boolean _bfd_xcoff_is_local_label_name - (bfd *, const char *); -extern void xcoff64_rtype2howto - (arelent *, struct internal_reloc *); -extern reloc_howto_type * xcoff64_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -extern bfd_boolean _bfd_xcoff_slurp_armap - (bfd *); -extern void *_bfd_xcoff_read_ar_hdr - (bfd *); -extern bfd *_bfd_xcoff_openr_next_archived_file - (bfd *, bfd *); -extern int _bfd_xcoff_stat_arch_elt - (bfd *, struct stat *); -extern bfd_boolean _bfd_xcoff_write_armap - (bfd *, unsigned int, struct orl *, unsigned int, int); -extern bfd_boolean _bfd_xcoff_write_archive_contents - (bfd *); -extern int _bfd_xcoff_sizeof_headers - (bfd *, struct bfd_link_info *); -extern void _bfd_xcoff_swap_sym_in - (bfd *, void *, void *); -extern unsigned int _bfd_xcoff_swap_sym_out - (bfd *, void *, void *); -extern void _bfd_xcoff_swap_aux_in - (bfd *, void *, int, int, int, int, void *); -extern unsigned int _bfd_xcoff_swap_aux_out - (bfd *, void *, int, int, int, int, void *); -static void xcoff64_swap_ldhdr_in - (bfd *, const void *, struct internal_ldhdr *); -static void xcoff64_swap_ldhdr_out - (bfd *, const struct internal_ldhdr *, void *d); -static void xcoff64_swap_ldsym_in - (bfd *, const void *, struct internal_ldsym *); -static void xcoff64_swap_ldsym_out - (bfd *, const struct internal_ldsym *, void *d); -static void xcoff64_swap_ldrel_in - (bfd *, const void *, struct internal_ldrel *); -static void xcoff64_swap_ldrel_out - (bfd *, const struct internal_ldrel *, void *d); -static bfd_boolean xcoff64_write_object_contents - (bfd *); -static bfd_boolean xcoff64_ppc_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, - struct internal_reloc *, struct internal_syment *, - asection **); -static bfd_boolean xcoff64_slurp_armap - (bfd *); -static const bfd_target *xcoff64_archive_p - (bfd *); -static bfd *xcoff64_openr_next_archived_file - (bfd *, bfd *); -static int xcoff64_sizeof_headers - (bfd *, struct bfd_link_info *); -static asection *xcoff64_create_csect_from_smclas - (bfd *, union internal_auxent *, const char *); -static bfd_boolean xcoff64_is_lineno_count_overflow - (bfd *, bfd_vma); -static bfd_boolean xcoff64_is_reloc_count_overflow - (bfd *, bfd_vma); -static bfd_vma xcoff64_loader_symbol_offset - (bfd *, struct internal_ldhdr *); -static bfd_vma xcoff64_loader_reloc_offset - (bfd *, struct internal_ldhdr *); -static bfd_boolean xcoff64_generate_rtinit - (bfd *, const char *, const char *, bfd_boolean); -static bfd_boolean xcoff64_bad_format_hook - (bfd *, void *); - -/* Relocation functions */ -static bfd_boolean xcoff64_reloc_type_br - (XCOFF_RELOC_FUNCTION_ARGS); - -bfd_boolean (*xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION]) - (XCOFF_RELOC_FUNCTION_ARGS) = -{ - xcoff_reloc_type_pos, /* R_POS (0x00) */ - xcoff_reloc_type_neg, /* R_NEG (0x01) */ - xcoff_reloc_type_rel, /* R_REL (0x02) */ - xcoff_reloc_type_toc, /* R_TOC (0x03) */ - xcoff_reloc_type_fail, /* R_RTB (0x04) */ - xcoff_reloc_type_toc, /* R_GL (0x05) */ - xcoff_reloc_type_toc, /* R_TCL (0x06) */ - xcoff_reloc_type_fail, /* (0x07) */ - xcoff_reloc_type_ba, /* R_BA (0x08) */ - xcoff_reloc_type_fail, /* (0x09) */ - xcoff64_reloc_type_br, /* R_BR (0x0a) */ - xcoff_reloc_type_fail, /* (0x0b) */ - xcoff_reloc_type_pos, /* R_RL (0x0c) */ - xcoff_reloc_type_pos, /* R_RLA (0x0d) */ - xcoff_reloc_type_fail, /* (0x0e) */ - xcoff_reloc_type_noop, /* R_REF (0x0f) */ - xcoff_reloc_type_fail, /* (0x10) */ - xcoff_reloc_type_fail, /* (0x11) */ - xcoff_reloc_type_toc, /* R_TRL (0x12) */ - xcoff_reloc_type_toc, /* R_TRLA (0x13) */ - xcoff_reloc_type_fail, /* R_RRTBI (0x14) */ - xcoff_reloc_type_fail, /* R_RRTBA (0x15) */ - xcoff_reloc_type_ba, /* R_CAI (0x16) */ - xcoff_reloc_type_crel, /* R_CREL (0x17) */ - xcoff_reloc_type_ba, /* R_RBA (0x18) */ - xcoff_reloc_type_ba, /* R_RBAC (0x19) */ - xcoff64_reloc_type_br, /* R_RBR (0x1a) */ - xcoff_reloc_type_ba, /* R_RBRC (0x1b) */ -}; - -/* coffcode.h needs these to be defined. */ -/* Internalcoff.h and coffcode.h modify themselves based on these flags. */ -#define XCOFF64 -#define RS6000COFF_C 1 - -#define SELECT_RELOC(internal, howto) \ - { \ - internal.r_type = howto->type; \ - internal.r_size = \ - ((howto->complain_on_overflow == complain_overflow_signed \ - ? 0x80 \ - : 0) \ - | (howto->bitsize - 1)); \ - } - -#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3) -#define COFF_LONG_FILENAMES -#define NO_COFF_SYMBOLS -#define RTYPE2HOWTO(cache_ptr, dst) xcoff64_rtype2howto (cache_ptr, dst) -#define coff_mkobject _bfd_xcoff_mkobject -#define coff_bfd_copy_private_bfd_data _bfd_xcoff_copy_private_bfd_data -#define coff_bfd_is_local_label_name _bfd_xcoff_is_local_label_name -#define coff_bfd_reloc_type_lookup xcoff64_reloc_type_lookup -#define coff_bfd_reloc_name_lookup xcoff64_reloc_name_lookup -#ifdef AIX_CORE -extern const bfd_target * rs6000coff_core_p - (bfd *abfd); -extern bfd_boolean rs6000coff_core_file_matches_executable_p - (bfd *cbfd, bfd *ebfd); -extern char *rs6000coff_core_file_failing_command - (bfd *abfd); -extern int rs6000coff_core_file_failing_signal - (bfd *abfd); -#define CORE_FILE_P rs6000coff_core_p -#define coff_core_file_failing_command \ - rs6000coff_core_file_failing_command -#define coff_core_file_failing_signal \ - rs6000coff_core_file_failing_signal -#define coff_core_file_matches_executable_p \ - rs6000coff_core_file_matches_executable_p -#define coff_core_file_pid \ - _bfd_nocore_core_file_pid -#else -#define CORE_FILE_P _bfd_dummy_target -#define coff_core_file_failing_command \ - _bfd_nocore_core_file_failing_command -#define coff_core_file_failing_signal \ - _bfd_nocore_core_file_failing_signal -#define coff_core_file_matches_executable_p \ - _bfd_nocore_core_file_matches_executable_p -#define coff_core_file_pid \ - _bfd_nocore_core_file_pid -#endif -#define coff_SWAP_sym_in _bfd_xcoff64_swap_sym_in -#define coff_SWAP_sym_out _bfd_xcoff64_swap_sym_out -#define coff_SWAP_aux_in _bfd_xcoff64_swap_aux_in -#define coff_SWAP_aux_out _bfd_xcoff64_swap_aux_out -#define coff_swap_reloc_in xcoff64_swap_reloc_in -#define coff_swap_reloc_out xcoff64_swap_reloc_out -#define NO_COFF_RELOCS - -#ifndef bfd_pe_print_pdata -#define bfd_pe_print_pdata NULL -#endif - -#include -#include "coffcode.h" - -/* For XCOFF64, the effective width of symndx changes depending on - whether we are the first entry. Sigh. */ -static void -_bfd_xcoff64_swap_lineno_in (bfd *abfd, void *ext1, void *in1) -{ - LINENO *ext = (LINENO *) ext1; - struct internal_lineno *in = (struct internal_lineno *) in1; - - in->l_lnno = H_GET_32 (abfd, (ext->l_lnno)); - if (in->l_lnno == 0) - in->l_addr.l_symndx = H_GET_32 (abfd, ext->l_addr.l_symndx); - else - in->l_addr.l_paddr = H_GET_64 (abfd, ext->l_addr.l_paddr); -} - -static unsigned int -_bfd_xcoff64_swap_lineno_out (bfd *abfd, void *inp, void *outp) -{ - struct internal_lineno *in = (struct internal_lineno *) inp; - struct external_lineno *ext = (struct external_lineno *) outp; - - H_PUT_32 (abfd, in->l_addr.l_symndx, ext->l_addr.l_symndx); - H_PUT_32 (abfd, in->l_lnno, (ext->l_lnno)); - - if (in->l_lnno == 0) - H_PUT_32 (abfd, in->l_addr.l_symndx, ext->l_addr.l_symndx); - else - H_PUT_64 (abfd, in->l_addr.l_paddr, ext->l_addr.l_paddr); - - return bfd_coff_linesz (abfd); -} - -static void -_bfd_xcoff64_swap_sym_in (bfd *abfd, void *ext1, void *in1) -{ - struct external_syment *ext = (struct external_syment *) ext1; - struct internal_syment *in = (struct internal_syment *) in1; - - in->_n._n_n._n_zeroes = 0; - in->_n._n_n._n_offset = H_GET_32 (abfd, ext->e_offset); - in->n_value = H_GET_64 (abfd, ext->e_value); - in->n_scnum = (short) H_GET_16 (abfd, ext->e_scnum); - in->n_type = H_GET_16 (abfd, ext->e_type); - in->n_sclass = H_GET_8 (abfd, ext->e_sclass); - in->n_numaux = H_GET_8 (abfd, ext->e_numaux); -} - -static unsigned int -_bfd_xcoff64_swap_sym_out (bfd *abfd, void *inp, void *extp) -{ - struct internal_syment *in = (struct internal_syment *) inp; - struct external_syment *ext = (struct external_syment *) extp; - - H_PUT_32 (abfd, in->_n._n_n._n_offset, ext->e_offset); - H_PUT_64 (abfd, in->n_value, ext->e_value); - H_PUT_16 (abfd, in->n_scnum, ext->e_scnum); - H_PUT_16 (abfd, in->n_type, ext->e_type); - H_PUT_8 (abfd, in->n_sclass, ext->e_sclass); - H_PUT_8 (abfd, in->n_numaux, ext->e_numaux); - return bfd_coff_symesz (abfd); -} - -static void -_bfd_xcoff64_swap_aux_in (bfd *abfd, void *ext1, int type, int in_class, - int indx, int numaux, void *in1) -{ - union external_auxent *ext = (union external_auxent *) ext1; - union internal_auxent *in = (union internal_auxent *) in1; - - switch (in_class) - { - case C_FILE: - if (ext->x_file.x_n.x_n.x_zeroes[0] == 0) - { - in->x_file.x_n.x_zeroes = 0; - in->x_file.x_n.x_offset = - H_GET_32 (abfd, ext->x_file.x_n.x_n.x_offset); - } - else - { - memcpy (in->x_file.x_fname, ext->x_file.x_n.x_fname, FILNMLEN); - } - goto end; - - /* RS/6000 "csect" auxents */ - case C_EXT: - case C_AIX_WEAKEXT: - case C_HIDEXT: - if (indx + 1 == numaux) - { - bfd_signed_vma h = 0; - bfd_vma l = 0; - - h = H_GET_S32 (abfd, ext->x_csect.x_scnlen_hi); - l = H_GET_32 (abfd, ext->x_csect.x_scnlen_lo); - - in->x_csect.x_scnlen.l = h << 32 | (l & 0xffffffff); - - in->x_csect.x_parmhash = H_GET_32 (abfd, ext->x_csect.x_parmhash); - in->x_csect.x_snhash = H_GET_16 (abfd, ext->x_csect.x_snhash); - /* We don't have to hack bitfields in x_smtyp because it's - defined by shifts-and-ands, which are equivalent on all - byte orders. */ - in->x_csect.x_smtyp = H_GET_8 (abfd, ext->x_csect.x_smtyp); - in->x_csect.x_smclas = H_GET_8 (abfd, ext->x_csect.x_smclas); - goto end; - } - break; - - case C_STAT: - case C_LEAFSTAT: - case C_HIDDEN: - if (type == T_NULL) - { - /* PE defines some extra fields; we zero them out for - safety. */ - in->x_scn.x_checksum = 0; - in->x_scn.x_associated = 0; - in->x_scn.x_comdat = 0; - - goto end; - } - break; - } - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - in->x_sym.x_fcnary.x_fcn.x_lnnoptr - = H_GET_64 (abfd, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr); - in->x_sym.x_fcnary.x_fcn.x_endndx.l - = H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_endndx); - } - if (ISFCN (type)) - { - in->x_sym.x_misc.x_fsize - = H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_fsize); - } - else - { - in->x_sym.x_misc.x_lnsz.x_lnno - = H_GET_32 (abfd, ext->x_sym.x_fcnary.x_lnsz.x_lnno); - in->x_sym.x_misc.x_lnsz.x_size - = H_GET_16 (abfd, ext->x_sym.x_fcnary.x_lnsz.x_size); - } - - end: ; -} - -static unsigned int -_bfd_xcoff64_swap_aux_out (bfd *abfd, void *inp, int type, int in_class, - int indx ATTRIBUTE_UNUSED, - int numaux ATTRIBUTE_UNUSED, - void *extp) -{ - union internal_auxent *in = (union internal_auxent *) inp; - union external_auxent *ext = (union external_auxent *) extp; - - memset (ext, 0, bfd_coff_auxesz (abfd)); - switch (in_class) - { - case C_FILE: - if (in->x_file.x_n.x_zeroes == 0) - { - H_PUT_32 (abfd, 0, ext->x_file.x_n.x_n.x_zeroes); - H_PUT_32 (abfd, in->x_file.x_n.x_offset, - ext->x_file.x_n.x_n.x_offset); - } - else - { - memcpy (ext->x_file.x_n.x_fname, in->x_file.x_fname, FILNMLEN); - } - H_PUT_8 (abfd, _AUX_FILE, ext->x_auxtype.x_auxtype); - goto end; - - /* RS/6000 "csect" auxents */ - case C_EXT: - case C_AIX_WEAKEXT: - case C_HIDEXT: - if (indx + 1 == numaux) - { - bfd_vma temp; - - temp = in->x_csect.x_scnlen.l & 0xffffffff; - H_PUT_32 (abfd, temp, ext->x_csect.x_scnlen_lo); - temp = in->x_csect.x_scnlen.l >> 32; - H_PUT_32 (abfd, temp, ext->x_csect.x_scnlen_hi); - H_PUT_32 (abfd, in->x_csect.x_parmhash, ext->x_csect.x_parmhash); - H_PUT_16 (abfd, in->x_csect.x_snhash, ext->x_csect.x_snhash); - /* We don't have to hack bitfields in x_smtyp because it's - defined by shifts-and-ands, which are equivalent on all - byte orders. */ - H_PUT_8 (abfd, in->x_csect.x_smtyp, ext->x_csect.x_smtyp); - H_PUT_8 (abfd, in->x_csect.x_smclas, ext->x_csect.x_smclas); - H_PUT_8 (abfd, _AUX_CSECT, ext->x_auxtype.x_auxtype); - goto end; - } - break; - - case C_STAT: - case C_LEAFSTAT: - case C_HIDDEN: - if (type == T_NULL) - { - goto end; - } - break; - } - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - H_PUT_64 (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, - ext->x_sym.x_fcnary.x_fcn.x_lnnoptr); - H_PUT_8 (abfd, _AUX_FCN, - ext->x_auxtype.x_auxtype); - H_PUT_32 (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, - ext->x_sym.x_fcnary.x_fcn.x_endndx); - } - if (ISFCN (type)) - { - H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, - ext->x_sym.x_fcnary.x_fcn.x_fsize); - } - else - { - H_PUT_32 (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, - ext->x_sym.x_fcnary.x_lnsz.x_lnno); - H_PUT_16 (abfd, in->x_sym.x_misc.x_lnsz.x_size, - ext->x_sym.x_fcnary.x_lnsz.x_size); - } - - end: - - return bfd_coff_auxesz (abfd); -} - -static bfd_boolean -_bfd_xcoff64_put_symbol_name (struct bfd_link_info *info, - struct bfd_strtab_hash *strtab, - struct internal_syment *sym, - const char *name) -{ - bfd_boolean hash; - bfd_size_type indx; - - hash = !info->traditional_format; - indx = _bfd_stringtab_add (strtab, name, hash, FALSE); - - if (indx == (bfd_size_type) -1) - return FALSE; - - sym->_n._n_n._n_zeroes = 0; - sym->_n._n_n._n_offset = STRING_SIZE_SIZE + indx; - - return TRUE; -} - -static bfd_boolean -_bfd_xcoff64_put_ldsymbol_name (bfd *abfd ATTRIBUTE_UNUSED, - struct xcoff_loader_info *ldinfo, - struct internal_ldsym *ldsym, - const char *name) -{ - size_t len; - len = strlen (name); - - if (ldinfo->string_size + len + 3 > ldinfo->string_alc) - { - bfd_size_type newalc; - char *newstrings; - - newalc = ldinfo->string_alc * 2; - if (newalc == 0) - newalc = 32; - while (ldinfo->string_size + len + 3 > newalc) - newalc *= 2; - - newstrings = bfd_realloc (ldinfo->strings, newalc); - if (newstrings == NULL) - { - ldinfo->failed = TRUE; - return FALSE; - } - ldinfo->string_alc = newalc; - ldinfo->strings = newstrings; - } - - bfd_put_16 (ldinfo->output_bfd, (bfd_vma) (len + 1), - ldinfo->strings + ldinfo->string_size); - strcpy (ldinfo->strings + ldinfo->string_size + 2, name); - ldsym->_l._l_l._l_zeroes = 0; - ldsym->_l._l_l._l_offset = ldinfo->string_size + 2; - ldinfo->string_size += len + 3; - - return TRUE; -} - -/* Routines to swap information in the XCOFF .loader section. If we - ever need to write an XCOFF loader, this stuff will need to be - moved to another file shared by the linker (which XCOFF calls the - ``binder'') and the loader. */ - -/* Swap in the ldhdr structure. */ - -static void -xcoff64_swap_ldhdr_in (bfd *abfd, - const void *s, - struct internal_ldhdr *dst) -{ - const struct external_ldhdr *src = (const struct external_ldhdr *) s; - - dst->l_version = bfd_get_32 (abfd, src->l_version); - dst->l_nsyms = bfd_get_32 (abfd, src->l_nsyms); - dst->l_nreloc = bfd_get_32 (abfd, src->l_nreloc); - dst->l_istlen = bfd_get_32 (abfd, src->l_istlen); - dst->l_nimpid = bfd_get_32 (abfd, src->l_nimpid); - dst->l_stlen = bfd_get_32 (abfd, src->l_stlen); - dst->l_impoff = bfd_get_64 (abfd, src->l_impoff); - dst->l_stoff = bfd_get_64 (abfd, src->l_stoff); - dst->l_symoff = bfd_get_64 (abfd, src->l_symoff); - dst->l_rldoff = bfd_get_64 (abfd, src->l_rldoff); -} - -/* Swap out the ldhdr structure. */ - -static void -xcoff64_swap_ldhdr_out (bfd *abfd, const struct internal_ldhdr *src, void *d) -{ - struct external_ldhdr *dst = (struct external_ldhdr *) d; - - bfd_put_32 (abfd, (bfd_vma) src->l_version, dst->l_version); - bfd_put_32 (abfd, src->l_nsyms, dst->l_nsyms); - bfd_put_32 (abfd, src->l_nreloc, dst->l_nreloc); - bfd_put_32 (abfd, src->l_istlen, dst->l_istlen); - bfd_put_32 (abfd, src->l_nimpid, dst->l_nimpid); - bfd_put_32 (abfd, src->l_stlen, dst->l_stlen); - bfd_put_64 (abfd, src->l_impoff, dst->l_impoff); - bfd_put_64 (abfd, src->l_stoff, dst->l_stoff); - bfd_put_64 (abfd, src->l_symoff, dst->l_symoff); - bfd_put_64 (abfd, src->l_rldoff, dst->l_rldoff); -} - -/* Swap in the ldsym structure. */ - -static void -xcoff64_swap_ldsym_in (bfd *abfd, const void *s, struct internal_ldsym *dst) -{ - const struct external_ldsym *src = (const struct external_ldsym *) s; - /* XCOFF64 does not use l_zeroes like XCOFF32 - Set the internal l_zeroes to 0 so the common 32/64 code uses l_value - as an offset into the loader symbol table. */ - dst->_l._l_l._l_zeroes = 0; - dst->_l._l_l._l_offset = bfd_get_32 (abfd, src->l_offset); - dst->l_value = bfd_get_64 (abfd, src->l_value); - dst->l_scnum = bfd_get_16 (abfd, src->l_scnum); - dst->l_smtype = bfd_get_8 (abfd, src->l_smtype); - dst->l_smclas = bfd_get_8 (abfd, src->l_smclas); - dst->l_ifile = bfd_get_32 (abfd, src->l_ifile); - dst->l_parm = bfd_get_32 (abfd, src->l_parm); -} - -/* Swap out the ldsym structure. */ - -static void -xcoff64_swap_ldsym_out (bfd *abfd, const struct internal_ldsym *src, void *d) -{ - struct external_ldsym *dst = (struct external_ldsym *) d; - - bfd_put_64 (abfd, src->l_value, dst->l_value); - bfd_put_32 (abfd, (bfd_vma) src->_l._l_l._l_offset, dst->l_offset); - bfd_put_16 (abfd, (bfd_vma) src->l_scnum, dst->l_scnum); - bfd_put_8 (abfd, src->l_smtype, dst->l_smtype); - bfd_put_8 (abfd, src->l_smclas, dst->l_smclas); - bfd_put_32 (abfd, src->l_ifile, dst->l_ifile); - bfd_put_32 (abfd, src->l_parm, dst->l_parm); -} - -static void -xcoff64_swap_reloc_in (bfd *abfd, void *s, void *d) -{ - struct external_reloc *src = (struct external_reloc *) s; - struct internal_reloc *dst = (struct internal_reloc *) d; - - memset (dst, 0, sizeof (struct internal_reloc)); - - dst->r_vaddr = bfd_get_64 (abfd, src->r_vaddr); - dst->r_symndx = bfd_get_32 (abfd, src->r_symndx); - dst->r_size = bfd_get_8 (abfd, src->r_size); - dst->r_type = bfd_get_8 (abfd, src->r_type); -} - -static unsigned int -xcoff64_swap_reloc_out (bfd *abfd, void *s, void *d) -{ - struct internal_reloc *src = (struct internal_reloc *) s; - struct external_reloc *dst = (struct external_reloc *) d; - - bfd_put_64 (abfd, src->r_vaddr, dst->r_vaddr); - bfd_put_32 (abfd, src->r_symndx, dst->r_symndx); - bfd_put_8 (abfd, src->r_type, dst->r_type); - bfd_put_8 (abfd, src->r_size, dst->r_size); - - return bfd_coff_relsz (abfd); -} - -/* Swap in the ldrel structure. */ - -static void -xcoff64_swap_ldrel_in (bfd *abfd, const void *s, struct internal_ldrel *dst) -{ - const struct external_ldrel *src = (const struct external_ldrel *) s; - - dst->l_vaddr = bfd_get_64 (abfd, src->l_vaddr); - dst->l_symndx = bfd_get_32 (abfd, src->l_symndx); - dst->l_rtype = bfd_get_16 (abfd, src->l_rtype); - dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm); -} - -/* Swap out the ldrel structure. */ - -static void -xcoff64_swap_ldrel_out (bfd *abfd, const struct internal_ldrel *src, void *d) -{ - struct external_ldrel *dst = (struct external_ldrel *) d; - - bfd_put_64 (abfd, src->l_vaddr, dst->l_vaddr); - bfd_put_16 (abfd, (bfd_vma) src->l_rtype, dst->l_rtype); - bfd_put_16 (abfd, (bfd_vma) src->l_rsecnm, dst->l_rsecnm); - bfd_put_32 (abfd, src->l_symndx, dst->l_symndx); -} - -static bfd_boolean -xcoff64_write_object_contents (bfd *abfd) -{ - asection *current; - bfd_boolean hasrelocs = FALSE; - bfd_boolean haslinno = FALSE; - file_ptr scn_base; - file_ptr reloc_base; - file_ptr lineno_base; - file_ptr sym_base; - unsigned long reloc_size = 0; - unsigned long lnno_size = 0; - asection *text_sec = NULL; - asection *data_sec = NULL; - asection *bss_sec = NULL; - struct internal_filehdr internal_f; - struct internal_aouthdr internal_a; - - bfd_set_error (bfd_error_system_call); - - if (! abfd->output_has_begun) - { - if (! bfd_coff_compute_section_file_positions (abfd)) - return FALSE; - } - - /* Work out the size of the reloc and linno areas. */ - reloc_base = obj_relocbase (abfd); - - for (current = abfd->sections; current != NULL; current = current->next) - reloc_size += current->reloc_count * bfd_coff_relsz (abfd); - - lineno_base = reloc_base + reloc_size; - - /* Make a pass through the symbol table to count line number entries and - put them into the correct asections. */ - lnno_size = coff_count_linenumbers (abfd) * bfd_coff_linesz (abfd); - - sym_base = lineno_base + lnno_size; - - /* Indicate in each section->line_filepos its actual file address. */ - for (current = abfd->sections; current != NULL; current = current->next) - { - if (current->lineno_count) - { - current->line_filepos = lineno_base; - current->moving_line_filepos = lineno_base; - lineno_base += current->lineno_count * bfd_coff_linesz (abfd); - } - else - { - current->line_filepos = 0; - } - - if (current->reloc_count) - { - current->rel_filepos = reloc_base; - reloc_base += current->reloc_count * bfd_coff_relsz (abfd); - } - else - { - current->rel_filepos = 0; - } - } - - if ((abfd->flags & EXEC_P) != 0) - { - scn_base = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); - internal_f.f_opthdr = bfd_coff_aoutsz (abfd); - } - else - { - scn_base = bfd_coff_filhsz (abfd); - internal_f.f_opthdr = 0; - } - - internal_f.f_nscns = 0; - - if (bfd_seek (abfd, scn_base, SEEK_SET) != 0) - return FALSE; - - for (current = abfd->sections; current != NULL; current = current->next) - { - struct internal_scnhdr section; - struct external_scnhdr buff; - bfd_size_type amount; - - internal_f.f_nscns++; - - strncpy (section.s_name, current->name, SCNNMLEN); - - section.s_vaddr = current->vma; - section.s_paddr = current->lma; - section.s_size = current->size; - - /* If this section has no size or is unloadable then the scnptr - will be 0 too. */ - if (current->size == 0 - || (current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) - { - section.s_scnptr = 0; - } - else - { - section.s_scnptr = current->filepos; - } - - section.s_relptr = current->rel_filepos; - section.s_lnnoptr = current->line_filepos; - section.s_nreloc = current->reloc_count; - - section.s_nlnno = current->lineno_count; - if (current->reloc_count != 0) - hasrelocs = TRUE; - if (current->lineno_count != 0) - haslinno = TRUE; - - section.s_flags = sec_to_styp_flags (current->name, current->flags); - - if (!strcmp (current->name, _TEXT)) - { - text_sec = current; - } - else if (!strcmp (current->name, _DATA)) - { - data_sec = current; - } - else if (!strcmp (current->name, _BSS)) - { - bss_sec = current; - } - - amount = bfd_coff_scnhsz (abfd); - if (bfd_coff_swap_scnhdr_out (abfd, §ion, &buff) == 0 - || bfd_bwrite (&buff, amount, abfd) != amount) - return FALSE; - } - - internal_f.f_timdat = 0; - - internal_f.f_flags = 0; - - if (!hasrelocs) - internal_f.f_flags |= F_RELFLG; - if (!haslinno) - internal_f.f_flags |= F_LNNO; - if (abfd->flags & EXEC_P) - internal_f.f_flags |= F_EXEC; - - /* FIXME: this is wrong for PPC_PE! */ - if (bfd_little_endian (abfd)) - internal_f.f_flags |= F_AR32WR; - else - internal_f.f_flags |= F_AR32W; - - if ((abfd->flags & DYNAMIC) != 0) - internal_f.f_flags |= F_SHROBJ; - if (bfd_get_section_by_name (abfd, _LOADER) != NULL) - internal_f.f_flags |= F_DYNLOAD; - - memset (&internal_a, 0, sizeof internal_a); - - internal_f.f_magic = bfd_xcoff_magic_number (abfd); - internal_a.magic = (abfd->flags & D_PAGED - ? RS6K_AOUTHDR_ZMAGIC - : (abfd->flags & WP_TEXT - ? RS6K_AOUTHDR_NMAGIC - : RS6K_AOUTHDR_OMAGIC)); - - /* FIXME: Does anybody ever set this to another value? */ - internal_a.vstamp = 0; - - /* Now should write relocs, strings, syms. */ - obj_sym_filepos (abfd) = sym_base; - - internal_f.f_symptr = 0; - internal_f.f_nsyms = 0; - - /* If bfd_get_symcount (abfd) != 0, then we are not using the COFF - backend linker, and obj_raw_syment_count is not valid until after - coff_write_symbols is called. */ - if (bfd_get_symcount (abfd) != 0) - { - int firstundef; - - if (!coff_renumber_symbols (abfd, &firstundef)) - return FALSE; - coff_mangle_symbols (abfd); - if (! coff_write_symbols (abfd)) - return FALSE; - if (! coff_write_linenumbers (abfd)) - return FALSE; - if (! coff_write_relocs (abfd, firstundef)) - return FALSE; - - internal_f.f_symptr = sym_base; - internal_f.f_nsyms = bfd_get_symcount (abfd); - } - else if (obj_raw_syment_count (abfd) != 0) - { - internal_f.f_symptr = sym_base; - - /* AIX appears to require that F_RELFLG not be set if there are - local symbols but no relocations. */ - internal_f.f_flags &=~ F_RELFLG; - } - else - { - internal_f.f_flags |= F_LSYMS; - } - - if (text_sec) - { - internal_a.tsize = text_sec->size; - internal_a.text_start = internal_a.tsize ? text_sec->vma : 0; - } - - if (data_sec) - { - internal_a.dsize = data_sec->size; - internal_a.data_start = internal_a.dsize ? data_sec->vma : 0; - } - - if (bss_sec) - { - internal_a.bsize = bss_sec->size; - if (internal_a.bsize && bss_sec->vma < internal_a.data_start) - internal_a.data_start = bss_sec->vma; - } - - internal_a.entry = bfd_get_start_address (abfd); - internal_f.f_nsyms = obj_raw_syment_count (abfd); - - if (xcoff_data (abfd)->full_aouthdr) - { - bfd_vma toc; - asection *loader_sec; - - internal_a.vstamp = 1; - - internal_a.o_snentry = xcoff_data (abfd)->snentry; - if (internal_a.o_snentry == 0) - internal_a.entry = (bfd_vma) -1; - - if (text_sec != NULL) - { - internal_a.o_sntext = text_sec->target_index; - internal_a.o_algntext = bfd_get_section_alignment (abfd, text_sec); - } - else - { - internal_a.o_sntext = 0; - internal_a.o_algntext = 0; - } - - if (data_sec != NULL) - { - internal_a.o_sndata = data_sec->target_index; - internal_a.o_algndata = bfd_get_section_alignment (abfd, data_sec); - } - else - { - internal_a.o_sndata = 0; - internal_a.o_algndata = 0; - } - - loader_sec = bfd_get_section_by_name (abfd, ".loader"); - if (loader_sec != NULL) - internal_a.o_snloader = loader_sec->target_index; - else - internal_a.o_snloader = 0; - if (bss_sec != NULL) - internal_a.o_snbss = bss_sec->target_index; - else - internal_a.o_snbss = 0; - - toc = xcoff_data (abfd)->toc; - internal_a.o_toc = toc; - internal_a.o_sntoc = xcoff_data (abfd)->sntoc; - - internal_a.o_modtype = xcoff_data (abfd)->modtype; - if (xcoff_data (abfd)->cputype != -1) - internal_a.o_cputype = xcoff_data (abfd)->cputype; - else - { - switch (bfd_get_arch (abfd)) - { - case bfd_arch_rs6000: - internal_a.o_cputype = 4; - break; - case bfd_arch_powerpc: - if (bfd_get_mach (abfd) == bfd_mach_ppc) - internal_a.o_cputype = 3; - else if (bfd_get_mach (abfd) == bfd_mach_ppc_620) - internal_a.o_cputype = 2; - else - internal_a.o_cputype = 1; - break; - default: - abort (); - } - } - internal_a.o_maxstack = xcoff_data (abfd)->maxstack; - internal_a.o_maxdata = xcoff_data (abfd)->maxdata; - } - - if (bfd_seek (abfd, (file_ptr) 0, 0) != 0) - return FALSE; - - { - char * buff; - bfd_size_type amount = bfd_coff_filhsz (abfd); - - buff = bfd_malloc (amount); - if (buff == NULL) - return FALSE; - - bfd_coff_swap_filehdr_out (abfd, &internal_f, buff); - amount = bfd_bwrite (buff, amount, abfd); - - free (buff); - - if (amount != bfd_coff_filhsz (abfd)) - return FALSE; - } - - if (abfd->flags & EXEC_P) - { - char * buff; - bfd_size_type amount = bfd_coff_aoutsz (abfd); - - buff = bfd_malloc (amount); - if (buff == NULL) - return FALSE; - - bfd_coff_swap_aouthdr_out (abfd, &internal_a, buff); - amount = bfd_bwrite (buff, amount, abfd); - - free (buff); - - if (amount != bfd_coff_aoutsz (abfd)) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -xcoff64_reloc_type_br (bfd *input_bfd, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct internal_reloc *rel, - struct internal_syment *sym ATTRIBUTE_UNUSED, - struct reloc_howto_struct *howto, - bfd_vma val, - bfd_vma addend, - bfd_vma *relocation, - bfd_byte *contents) -{ - struct xcoff_link_hash_entry *h; - bfd_vma section_offset; - - if (0 > rel->r_symndx) - return FALSE; - - h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx]; - section_offset = rel->r_vaddr - input_section->vma; - - /* If we see an R_BR or R_RBR reloc which is jumping to global - linkage code, and it is followed by an appropriate cror nop - instruction, we replace the cror with ld r2,40(r1). This - restores the TOC after the glink code. Contrariwise, if the - call is followed by a ld r2,40(r1), but the call is not - going to global linkage code, we can replace the load with a - cror. */ - if (NULL != h - && (bfd_link_hash_defined == h->root.type - || bfd_link_hash_defweak == h->root.type) - && section_offset + 8 <= input_section->size) - { - bfd_byte *pnext; - unsigned long next; - - pnext = contents + section_offset + 4; - next = bfd_get_32 (input_bfd, pnext); - - /* The _ptrgl function is magic. It is used by the AIX compiler to call - a function through a pointer. */ - if (h->smclas == XMC_GL || strcmp (h->root.root.string, "._ptrgl") == 0) - { - if (next == 0x4def7b82 /* cror 15,15,15 */ - || next == 0x4ffffb82 /* cror 31,31,31 */ - || next == 0x60000000) /* ori r0,r0,0 */ - bfd_put_32 (input_bfd, 0xe8410028, pnext); /* ld r2,40(r1) */ - } - else - { - if (next == 0xe8410028) /* ld r2,40(r1) */ - bfd_put_32 (input_bfd, 0x60000000, pnext); /* ori r0,r0,0 */ - } - } - else if (NULL != h && bfd_link_hash_undefined == h->root.type) - { - /* Normally, this relocation is against a defined symbol. In the - case where this is a partial link and the output section offset - is greater than 2^25, the linker will return an invalid error - message that the relocation has been truncated. Yes it has been - truncated but no it not important. For this case, disable the - overflow checking. */ - howto->complain_on_overflow = complain_overflow_dont; - } - - /* The original PC-relative relocation is biased by -r_vaddr, so adding - the value below will give the absolute target address. */ - *relocation = val + addend + rel->r_vaddr; - - howto->src_mask &= ~3; - howto->dst_mask = howto->src_mask; - - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && bfd_is_abs_section (h->root.u.def.section) - && section_offset + 4 <= input_section->size) - { - bfd_byte *ptr; - bfd_vma insn; - - /* Turn the relative branch into an absolute one by setting the - AA bit. */ - ptr = contents + section_offset; - insn = bfd_get_32 (input_bfd, ptr); - insn |= 2; - bfd_put_32 (input_bfd, insn, ptr); - - /* Make the howto absolute too. */ - howto->pc_relative = FALSE; - howto->complain_on_overflow = complain_overflow_bitfield; - } - else - { - /* Use a PC-relative howto and subtract the instruction's address - from the target address we calculated above. */ - howto->pc_relative = TRUE; - *relocation -= (input_section->output_section->vma - + input_section->output_offset - + section_offset); - } - return TRUE; -} - -/* This is the relocation function for the PowerPC64. - See xcoff_ppc_relocation_section for more information. */ - -bfd_boolean -xcoff64_ppc_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct xcoff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma addend; - bfd_vma val; - struct reloc_howto_struct howto; - bfd_vma relocation; - bfd_vma value_to_relocate; - bfd_vma address; - bfd_byte *location; - - /* Relocation type R_REF is a special relocation type which is - merely used to prevent garbage collection from occurring for - the csect including the symbol which it references. */ - if (rel->r_type == R_REF) - continue; - - /* howto */ - howto.type = rel->r_type; - howto.rightshift = 0; - howto.bitsize = (rel->r_size & 0x3f) + 1; - howto.size = howto.bitsize > 16 ? (howto.bitsize > 32 ? 4 : 2) : 1; - howto.pc_relative = FALSE; - howto.bitpos = 0; - howto.complain_on_overflow = (rel->r_size & 0x80 - ? complain_overflow_signed - : complain_overflow_bitfield); - howto.special_function = NULL; - howto.name = "internal"; - howto.partial_inplace = TRUE; - howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize); - howto.pcrel_offset = FALSE; - - /* symbol */ - val = 0; - addend = 0; - h = NULL; - sym = NULL; - symndx = rel->r_symndx; - - if (-1 != symndx) - { - asection *sec; - - h = obj_xcoff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - addend = - sym->n_value; - - if (NULL == h) - { - sec = sections[symndx]; - /* Hack to make sure we use the right TOC anchor value - if this reloc is against the TOC anchor. */ - if (sec->name[3] == '0' - && strcmp (sec->name, ".tc0") == 0) - val = xcoff_data (output_bfd)->toc; - else - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value - - sec->vma); - } - else - { - if (info->unresolved_syms_in_objects != RM_IGNORE - && (h->flags & XCOFF_WAS_UNDEFINED) != 0) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, - info->unresolved_syms_in_objects == RM_GENERATE_ERROR); - - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else if (h->root.type == bfd_link_hash_common) - { - sec = h->root.u.c.p->section; - val = (sec->output_section->vma - + sec->output_offset); - } - else - { - BFD_ASSERT (bfd_link_relocatable (info) - || (h->flags & XCOFF_DEF_DYNAMIC) != 0 - || (h->flags & XCOFF_IMPORT) != 0); - } - } - } - - if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION - || !((*xcoff64_calculate_relocation[rel->r_type]) - (input_bfd, input_section, output_bfd, rel, sym, &howto, val, - addend, &relocation, contents))) - return FALSE; - - /* address */ - address = rel->r_vaddr - input_section->vma; - location = contents + address; - - if (address > input_section->size) - abort (); - - /* Get the value we are going to relocate. */ - if (1 == howto.size) - value_to_relocate = bfd_get_16 (input_bfd, location); - else if (2 == howto.size) - value_to_relocate = bfd_get_32 (input_bfd, location); - else - value_to_relocate = bfd_get_64 (input_bfd, location); - - /* 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. */ - - if ((unsigned int) howto.complain_on_overflow - >= XCOFF_MAX_COMPLAIN_OVERFLOW) - abort (); - - if (((*xcoff_complain_overflow[howto.complain_on_overflow]) - (input_bfd, value_to_relocate, relocation, &howto))) - { - const char *name; - char buf[SYMNMLEN + 1]; - char reloc_type_name[10]; - - if (symndx == -1) - { - name = "*ABS*"; - } - else if (h != NULL) - { - name = NULL; - } - else - { - name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); - if (name == NULL) - name = "UNKNOWN"; - } - sprintf (reloc_type_name, "0x%02x", rel->r_type); - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, reloc_type_name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - - /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE. */ - value_to_relocate = ((value_to_relocate & ~howto.dst_mask) - | (((value_to_relocate & howto.src_mask) - + relocation) & howto.dst_mask)); - - /* Put the value back in the object file. */ - if (1 == howto.size) - bfd_put_16 (input_bfd, value_to_relocate, location); - else if (2 == howto.size) - bfd_put_32 (input_bfd, value_to_relocate, location); - else - bfd_put_64 (input_bfd, value_to_relocate, location); - - } - return TRUE; -} - - -/* The XCOFF reloc table. Actually, XCOFF relocations specify the - bitsize and whether they are signed or not, along with a - conventional type. This table is for the types, which are used for - different algorithms for putting in the reloc. Many of these - relocs need special_function entries, which I have not written. */ - -reloc_howto_type xcoff64_howto_table[] = -{ - /* 0x00: Standard 64 bit relocation. */ - HOWTO (R_POS, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_POS_64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x01: 64 bit relocation, but store negative value. */ - HOWTO (R_NEG, /* type */ - 0, /* rightshift */ - -4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_NEG", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x02: 32 bit PC relative relocation. */ - HOWTO (R_REL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_REL", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x03: 16 bit TOC relative relocation. */ - HOWTO (R_TOC, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TOC", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x04: I don't really know what this is. */ - HOWTO (R_RTB, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RTB", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x05: External TOC relative symbol. */ - HOWTO (R_GL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_GL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x06: Local TOC relative symbol. */ - HOWTO (R_TCL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TCL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (7), - - /* 0x08: Non modifiable absolute branch. */ - HOWTO (R_BA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_BA_26", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (9), - - /* 0x0a: Non modifiable relative branch. */ - HOWTO (R_BR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_BR", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0xb), - - /* 0x0c: Indirect load. */ - HOWTO (R_RL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x0d: Load address. */ - HOWTO (R_RLA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RLA", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0xe), - - /* 0x0f: Non-relocating reference. Bitsize is 1 so that r_rsize is 0. */ - HOWTO (R_REF, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 1, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - 0, /* special_function */ - "R_REF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0x10), - EMPTY_HOWTO (0x11), - - /* 0x12: TOC relative indirect load. */ - HOWTO (R_TRL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TRL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x13: TOC relative load address. */ - HOWTO (R_TRLA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_TRLA", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x14: Modifiable relative branch. */ - HOWTO (R_RRTBI, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RRTBI", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x15: Modifiable absolute branch. */ - HOWTO (R_RRTBA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RRTBA", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x16: Modifiable call absolute indirect. */ - HOWTO (R_CAI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_CAI", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x17: Modifiable call relative. */ - HOWTO (R_CREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_CREL", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x18: Modifiable branch absolute. */ - HOWTO (R_RBA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBA", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x19: Modifiable branch absolute. */ - HOWTO (R_RBAC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBAC", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1a: Modifiable branch relative. */ - HOWTO (R_RBR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBR_26", /* name */ - TRUE, /* partial_inplace */ - 0x03fffffc, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1b: Modifiable branch absolute. */ - HOWTO (R_RBRC, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBRC", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1c: Standard 32 bit relocation. */ - HOWTO (R_POS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_POS_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1d: 16 bit Non modifiable absolute branch. */ - HOWTO (R_BA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_BA_16", /* name */ - TRUE, /* partial_inplace */ - 0xfffc, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1e: Modifiable branch relative. */ - HOWTO (R_RBR, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBR_16", /* name */ - TRUE, /* partial_inplace */ - 0xfffc, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 0x1f: Modifiable branch absolute. */ - HOWTO (R_RBA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_RBA_16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -void -xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal) -{ - if (internal->r_type > R_RBRC) - abort (); - - /* Default howto layout works most of the time */ - relent->howto = &xcoff64_howto_table[internal->r_type]; - - /* Special case some 16 bit reloc */ - if (15 == (internal->r_size & 0x3f)) - { - if (R_BA == internal->r_type) - relent->howto = &xcoff64_howto_table[0x1d]; - else if (R_RBR == internal->r_type) - relent->howto = &xcoff64_howto_table[0x1e]; - else if (R_RBA == internal->r_type) - relent->howto = &xcoff64_howto_table[0x1f]; - } - /* Special case 32 bit */ - else if (31 == (internal->r_size & 0x3f)) - { - if (R_POS == internal->r_type) - relent->howto = &xcoff64_howto_table[0x1c]; - } - - /* The r_size field of an XCOFF reloc encodes the bitsize of the - relocation, as well as indicating whether it is signed or not. - Doublecheck that the relocation information gathered from the - type matches this information. The bitsize is not significant - for R_REF relocs. */ - if (relent->howto->dst_mask != 0 - && (relent->howto->bitsize - != ((unsigned int) internal->r_size & 0x3f) + 1)) - abort (); -} - -reloc_howto_type * -xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_PPC_B26: - return &xcoff64_howto_table[0xa]; - case BFD_RELOC_PPC_BA16: - return &xcoff64_howto_table[0x1d]; - case BFD_RELOC_PPC_BA26: - return &xcoff64_howto_table[8]; - case BFD_RELOC_PPC_TOC16: - return &xcoff64_howto_table[3]; - case BFD_RELOC_16: - /* Note that this relocation is only internally used by gas. */ - return &xcoff64_howto_table[0xc]; - case BFD_RELOC_PPC_B16: - return &xcoff64_howto_table[0x1e]; - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - return &xcoff64_howto_table[0x1c]; - case BFD_RELOC_64: - return &xcoff64_howto_table[0]; - case BFD_RELOC_NONE: - return &xcoff64_howto_table[0xf]; - default: - return NULL; - } -} - -static reloc_howto_type * -xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]); - i++) - if (xcoff64_howto_table[i].name != NULL - && strcasecmp (xcoff64_howto_table[i].name, r_name) == 0) - return &xcoff64_howto_table[i]; - - return NULL; -} - -/* PR 21786: The PE/COFF standard does not require NUL termination for any of - the ASCII fields in the archive headers. So in order to be able to extract - numerical values we provide our own versions of strtol and strtoll which - take a maximum length as an additional parameter. Also - just to save space, - we omit the endptr return parameter, since we know that it is never used. */ - -static long -_bfd_strntol (const char * nptr, int base, unsigned int maxlen) -{ - char buf[24]; /* Should be enough. */ - - BFD_ASSERT (maxlen < (sizeof (buf) - 1)); - - memcpy (buf, nptr, maxlen); - buf[maxlen] = 0; - return strtol (buf, NULL, base); -} - -static long long -_bfd_strntoll (const char * nptr, int base, unsigned int maxlen) -{ - char buf[32]; /* Should be enough. */ - - BFD_ASSERT (maxlen < (sizeof (buf) - 1)); - - memcpy (buf, nptr, maxlen); - buf[maxlen] = 0; - return strtoll (buf, NULL, base); -} - -/* Macro to read an ASCII value stored in an archive header field. */ -#define GET_VALUE_IN_FIELD(VAR, FIELD) \ - do \ - { \ - (VAR) = sizeof (VAR) > sizeof (long) \ - ? _bfd_strntoll (FIELD, 10, sizeof FIELD) \ - : _bfd_strntol (FIELD, 10, sizeof FIELD); \ - } \ - while (0) - -/* Read in the armap of an XCOFF archive. */ - -static bfd_boolean -xcoff64_slurp_armap (bfd *abfd) -{ - file_ptr off; - size_t namlen; - bfd_size_type sz, amt; - bfd_byte *contents, *cend; - bfd_vma c, i; - carsym *arsym; - bfd_byte *p; - file_ptr pos; - - /* This is for the new format. */ - struct xcoff_ar_hdr_big hdr; - - if (xcoff_ardata (abfd) == NULL) - { - bfd_has_map (abfd) = FALSE; - return TRUE; - } - - off = bfd_scan_vma (xcoff_ardata_big (abfd)->symoff64, - (const char **) NULL, 10); - if (off == 0) - { - bfd_has_map (abfd) = FALSE; - return TRUE; - } - - if (bfd_seek (abfd, off, SEEK_SET) != 0) - return FALSE; - - /* The symbol table starts with a normal archive header. */ - if (bfd_bread (&hdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd) - != SIZEOF_AR_HDR_BIG) - return FALSE; - - /* Skip the name (normally empty). */ - GET_VALUE_IN_FIELD (namlen, hdr.namlen); - pos = ((namlen + 1) & ~(size_t) 1) + SXCOFFARFMAG; - if (bfd_seek (abfd, pos, SEEK_CUR) != 0) - return FALSE; - - sz = bfd_scan_vma (hdr.size, (const char **) NULL, 10); - - /* Read in the entire symbol table. */ - contents = (bfd_byte *) bfd_alloc (abfd, sz); - if (contents == NULL) - return FALSE; - if (bfd_bread (contents, sz, abfd) != sz) - return FALSE; - - /* The symbol table starts with an eight byte count. */ - c = H_GET_64 (abfd, contents); - - if (c * 8 >= sz) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - amt = c; - amt *= sizeof (carsym); - bfd_ardata (abfd)->symdefs = (carsym *) bfd_alloc (abfd, amt); - if (bfd_ardata (abfd)->symdefs == NULL) - return FALSE; - - /* After the count comes a list of eight byte file offsets. */ - for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 8; - i < c; - ++i, ++arsym, p += 8) - arsym->file_offset = H_GET_64 (abfd, p); - - /* After the file offsets come null terminated symbol names. */ - cend = contents + sz; - for (i = 0, arsym = bfd_ardata (abfd)->symdefs; - i < c; - ++i, ++arsym, p += strlen ((char *) p) + 1) - { - if (p >= cend) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - arsym->name = (char *) p; - } - - bfd_ardata (abfd)->symdef_count = c; - bfd_has_map (abfd) = TRUE; - - return TRUE; -} - - -/* See if this is an NEW XCOFF archive. */ - -static const bfd_target * -xcoff64_archive_p (bfd *abfd) -{ - struct artdata *tdata_hold; - char magic[SXCOFFARMAG]; - /* This is the new format. */ - struct xcoff_ar_file_hdr_big hdr; - bfd_size_type amt = SXCOFFARMAG; - - if (bfd_bread (magic, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - if (strncmp (magic, XCOFFARMAGBIG, SXCOFFARMAG) != 0) - { - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - /* Copy over the magic string. */ - memcpy (hdr.magic, magic, SXCOFFARMAG); - - /* Now read the rest of the file header. */ - amt = SIZEOF_AR_FILE_HDR_BIG - SXCOFFARMAG; - if (bfd_bread (&hdr.memoff, amt, abfd) != amt) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_wrong_format); - return NULL; - } - - tdata_hold = bfd_ardata (abfd); - - amt = sizeof (struct artdata); - bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt); - if (bfd_ardata (abfd) == (struct artdata *) NULL) - goto error_ret_restore; - - /* 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)->first_file_filepos = bfd_scan_vma (hdr.firstmemoff, - (const char **) NULL, - 10); - - amt = SIZEOF_AR_FILE_HDR_BIG; - bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, amt); - if (bfd_ardata (abfd)->tdata == NULL) - goto error_ret; - - memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR_BIG); - - if (! xcoff64_slurp_armap (abfd)) - { - error_ret: - bfd_release (abfd, bfd_ardata (abfd)); - error_ret_restore: - bfd_ardata (abfd) = tdata_hold; - return NULL; - } - - return abfd->xvec; -} - - -/* Open the next element in an XCOFF archive. */ - -static bfd * -xcoff64_openr_next_archived_file (bfd *archive, bfd *last_file) -{ - bfd_vma filestart; - - if ((xcoff_ardata (archive) == NULL) - || ! xcoff_big_format_p (archive)) - { - bfd_set_error (bfd_error_invalid_operation); - return NULL; - } - - if (last_file == NULL) - { - filestart = bfd_ardata (archive)->first_file_filepos; - } - else - { - filestart = bfd_scan_vma (arch_xhdr_big (last_file)->nextoff, - (const char **) NULL, 10); - } - - if (filestart == 0 - || filestart == bfd_scan_vma (xcoff_ardata_big (archive)->memoff, - (const char **) NULL, 10) - || filestart == bfd_scan_vma (xcoff_ardata_big (archive)->symoff, - (const char **) NULL, 10)) - { - bfd_set_error (bfd_error_no_more_archived_files); - return NULL; - } - - return _bfd_get_elt_at_filepos (archive, (file_ptr) filestart); -} - -/* We can't use the usual coff_sizeof_headers routine, because AIX - always uses an a.out header. */ - -static int -xcoff64_sizeof_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - int size; - - size = bfd_coff_filhsz (abfd); - - /* Don't think the small aout header can be used since some of the - old elements have been reordered past the end of the old coff - small aout size. */ - - if (xcoff_data (abfd)->full_aouthdr) - size += bfd_coff_aoutsz (abfd); - - size += abfd->section_count * bfd_coff_scnhsz (abfd); - return size; -} - -static asection * -xcoff64_create_csect_from_smclas (bfd *abfd, union internal_auxent *aux, - const char *symbol_name) -{ - asection *return_value = NULL; - - /* Changes from 32 : - .sv == 8, is only for 32 bit programs - .ti == 12 and .tb == 13 are now reserved. */ - static const char *names[19] = - { - ".pr", ".ro", ".db", ".tc", ".ua", ".rw", ".gl", ".xo", - NULL, ".bs", ".ds", ".uc", NULL, NULL, NULL, ".tc0", - ".td", ".sv64", ".sv3264" - }; - - if ((19 >= aux->x_csect.x_smclas) - && (NULL != names[aux->x_csect.x_smclas])) - { - - return_value = bfd_make_section_anyway - (abfd, names[aux->x_csect.x_smclas]); - - } - else - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: symbol `%s' has unrecognized smclas %d"), - abfd, symbol_name, aux->x_csect.x_smclas); - bfd_set_error (bfd_error_bad_value); - } - - return return_value; -} - -static bfd_boolean -xcoff64_is_lineno_count_overflow (bfd *abfd ATTRIBUTE_UNUSED, - bfd_vma value ATTRIBUTE_UNUSED) -{ - return FALSE; -} - -static bfd_boolean -xcoff64_is_reloc_count_overflow (bfd *abfd ATTRIBUTE_UNUSED, - bfd_vma value ATTRIBUTE_UNUSED) -{ - return FALSE; -} - -static bfd_vma -xcoff64_loader_symbol_offset (bfd *abfd ATTRIBUTE_UNUSED, - struct internal_ldhdr *ldhdr) -{ - return (ldhdr->l_symoff); -} - -static bfd_vma -xcoff64_loader_reloc_offset (bfd *abfd ATTRIBUTE_UNUSED, - struct internal_ldhdr *ldhdr) -{ - return (ldhdr->l_rldoff); -} - -static bfd_boolean -xcoff64_bad_format_hook (bfd * abfd, void *filehdr) -{ - struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; - - /* Check flavor first. */ - if (bfd_get_flavour (abfd) != bfd_target_xcoff_flavour) - return FALSE; - - if (bfd_xcoff_magic_number (abfd) != internal_f->f_magic) - return FALSE; - - return TRUE; -} - -static bfd_boolean -xcoff64_generate_rtinit (bfd *abfd, const char *init, const char *fini, - bfd_boolean rtld) -{ - bfd_byte filehdr_ext[FILHSZ]; - bfd_byte scnhdr_ext[SCNHSZ * 3]; - bfd_byte syment_ext[SYMESZ * 10]; - bfd_byte reloc_ext[RELSZ * 3]; - bfd_byte *data_buffer; - bfd_size_type data_buffer_size; - bfd_byte *string_table, *st_tmp; - bfd_size_type string_table_size; - bfd_vma val; - size_t initsz, finisz; - struct internal_filehdr filehdr; - struct internal_scnhdr text_scnhdr; - struct internal_scnhdr data_scnhdr; - struct internal_scnhdr bss_scnhdr; - struct internal_syment syment; - union internal_auxent auxent; - struct internal_reloc reloc; - - char *text_name = ".text"; - char *data_name = ".data"; - char *bss_name = ".bss"; - char *rtinit_name = "__rtinit"; - char *rtld_name = "__rtld"; - - if (! bfd_xcoff_rtinit_size (abfd)) - return FALSE; - - initsz = (init == NULL ? 0 : 1 + strlen (init)); - finisz = (fini == NULL ? 0 : 1 + strlen (fini)); - - /* File header. */ - memset (filehdr_ext, 0, FILHSZ); - memset (&filehdr, 0, sizeof (struct internal_filehdr)); - filehdr.f_magic = bfd_xcoff_magic_number (abfd); - filehdr.f_nscns = 3; - filehdr.f_timdat = 0; - filehdr.f_nsyms = 0; /* at least 6, no more than 8 */ - filehdr.f_symptr = 0; /* set below */ - filehdr.f_opthdr = 0; - filehdr.f_flags = 0; - - /* Section headers. */ - memset (scnhdr_ext, 0, 3 * SCNHSZ); - - /* Text. */ - memset (&text_scnhdr, 0, sizeof (struct internal_scnhdr)); - memcpy (text_scnhdr.s_name, text_name, strlen (text_name)); - text_scnhdr.s_paddr = 0; - text_scnhdr.s_vaddr = 0; - text_scnhdr.s_size = 0; - text_scnhdr.s_scnptr = 0; - text_scnhdr.s_relptr = 0; - text_scnhdr.s_lnnoptr = 0; - text_scnhdr.s_nreloc = 0; - text_scnhdr.s_nlnno = 0; - text_scnhdr.s_flags = STYP_TEXT; - - /* Data. */ - memset (&data_scnhdr, 0, sizeof (struct internal_scnhdr)); - memcpy (data_scnhdr.s_name, data_name, strlen (data_name)); - data_scnhdr.s_paddr = 0; - data_scnhdr.s_vaddr = 0; - data_scnhdr.s_size = 0; /* set below */ - data_scnhdr.s_scnptr = FILHSZ + 3 * SCNHSZ; - data_scnhdr.s_relptr = 0; /* set below */ - data_scnhdr.s_lnnoptr = 0; - data_scnhdr.s_nreloc = 0; /* either 1 or 2 */ - data_scnhdr.s_nlnno = 0; - data_scnhdr.s_flags = STYP_DATA; - - /* Bss. */ - memset (&bss_scnhdr, 0, sizeof (struct internal_scnhdr)); - memcpy (bss_scnhdr.s_name, bss_name, strlen (bss_name)); - bss_scnhdr.s_paddr = 0; /* set below */ - bss_scnhdr.s_vaddr = 0; /* set below */ - bss_scnhdr.s_size = 0; /* set below */ - bss_scnhdr.s_scnptr = 0; - bss_scnhdr.s_relptr = 0; - bss_scnhdr.s_lnnoptr = 0; - bss_scnhdr.s_nreloc = 0; - bss_scnhdr.s_nlnno = 0; - bss_scnhdr.s_flags = STYP_BSS; - - /* .data - 0x0000 0x00000000 : rtl - 0x0004 0x00000000 : - 0x0008 0x00000018 : offset to init, or 0 - 0x000C 0x00000038 : offset to fini, or 0 - 0x0010 0x00000010 : size of descriptor - 0x0014 0x00000000 : pad - 0x0018 0x00000000 : init, needs a reloc - 0x001C 0x00000000 : - 0x0020 0x00000058 : offset to init name - 0x0024 0x00000000 : flags, padded to a word - 0x0028 0x00000000 : empty init - 0x002C 0x00000000 : - 0x0030 0x00000000 : - 0x0034 0x00000000 : - 0x0038 0x00000000 : fini, needs a reloc - 0x003C 0x00000000 : - 0x0040 0x00000??? : offset to fini name - 0x0044 0x00000000 : flags, padded to a word - 0x0048 0x00000000 : empty fini - 0x004C 0x00000000 : - 0x0050 0x00000000 : - 0x0054 0x00000000 : - 0x0058 init name - 0x0058 + initsz fini name */ - - data_buffer_size = 0x0058 + initsz + finisz; - data_buffer_size = (data_buffer_size + 7) &~ (bfd_size_type) 7; - data_buffer = NULL; - data_buffer = (bfd_byte *) bfd_zmalloc (data_buffer_size); - if (data_buffer == NULL) - return FALSE; - - if (initsz) - { - val = 0x18; - bfd_put_32 (abfd, val, &data_buffer[0x08]); - val = 0x58; - bfd_put_32 (abfd, val, &data_buffer[0x20]); - memcpy (&data_buffer[val], init, initsz); - } - - if (finisz) - { - val = 0x38; - bfd_put_32 (abfd, val, &data_buffer[0x0C]); - val = 0x58 + initsz; - bfd_put_32 (abfd, val, &data_buffer[0x40]); - memcpy (&data_buffer[val], fini, finisz); - } - - val = 0x10; - bfd_put_32 (abfd, val, &data_buffer[0x10]); - data_scnhdr.s_size = data_buffer_size; - bss_scnhdr.s_paddr = bss_scnhdr.s_vaddr = data_scnhdr.s_size; - - /* String table. */ - string_table_size = 4; - string_table_size += strlen (data_name) + 1; - string_table_size += strlen (rtinit_name) + 1; - string_table_size += initsz; - string_table_size += finisz; - if (rtld) - string_table_size += strlen (rtld_name) + 1; - - string_table = (bfd_byte *) bfd_zmalloc (string_table_size); - if (string_table == NULL) - return FALSE; - - val = string_table_size; - bfd_put_32 (abfd, val, &string_table[0]); - st_tmp = string_table + 4; - - /* symbols - 0. .data csect - 2. __rtinit - 4. init function - 6. fini function - 8. __rtld */ - memset (syment_ext, 0, 10 * SYMESZ); - memset (reloc_ext, 0, 3 * RELSZ); - - /* .data csect */ - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, data_name, strlen (data_name)); - st_tmp += strlen (data_name) + 1; - - syment.n_scnum = 2; - syment.n_sclass = C_HIDEXT; - syment.n_numaux = 1; - auxent.x_csect.x_scnlen.l = data_buffer_size; - auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD; - auxent.x_csect.x_smclas = XMC_RW; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - filehdr.f_nsyms += 2; - - /* __rtinit */ - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, rtinit_name, strlen (rtinit_name)); - st_tmp += strlen (rtinit_name) + 1; - - syment.n_scnum = 2; - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - auxent.x_csect.x_smtyp = XTY_LD; - auxent.x_csect.x_smclas = XMC_RW; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - filehdr.f_nsyms += 2; - - /* Init. */ - if (initsz) - { - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, init, initsz); - st_tmp += initsz; - - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - /* Reloc. */ - memset (&reloc, 0, sizeof (struct internal_reloc)); - reloc.r_vaddr = 0x0018; - reloc.r_symndx = filehdr.f_nsyms; - reloc.r_type = R_POS; - reloc.r_size = 63; - bfd_coff_swap_reloc_out (abfd, &reloc, &reloc_ext[0]); - - filehdr.f_nsyms += 2; - data_scnhdr.s_nreloc += 1; - } - - /* Finit. */ - if (finisz) - { - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, fini, finisz); - st_tmp += finisz; - - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - - /* Reloc. */ - memset (&reloc, 0, sizeof (struct internal_reloc)); - reloc.r_vaddr = 0x0038; - reloc.r_symndx = filehdr.f_nsyms; - reloc.r_type = R_POS; - reloc.r_size = 63; - bfd_coff_swap_reloc_out (abfd, &reloc, - &reloc_ext[data_scnhdr.s_nreloc * RELSZ]); - - filehdr.f_nsyms += 2; - data_scnhdr.s_nreloc += 1; - } - - if (rtld) - { - memset (&syment, 0, sizeof (struct internal_syment)); - memset (&auxent, 0, sizeof (union internal_auxent)); - - syment._n._n_n._n_offset = st_tmp - string_table; - memcpy (st_tmp, rtld_name, strlen (rtld_name)); - st_tmp += strlen (rtld_name) + 1; - - syment.n_sclass = C_EXT; - syment.n_numaux = 1; - bfd_coff_swap_sym_out (abfd, &syment, - &syment_ext[filehdr.f_nsyms * SYMESZ]); - bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, - syment.n_numaux, - &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); - - /* Reloc. */ - memset (&reloc, 0, sizeof (struct internal_reloc)); - reloc.r_vaddr = 0x0000; - reloc.r_symndx = filehdr.f_nsyms; - reloc.r_type = R_POS; - reloc.r_size = 63; - bfd_coff_swap_reloc_out (abfd, &reloc, - &reloc_ext[data_scnhdr.s_nreloc * RELSZ]); - - filehdr.f_nsyms += 2; - data_scnhdr.s_nreloc += 1; - - bss_scnhdr.s_size = 0; - } - - data_scnhdr.s_relptr = data_scnhdr.s_scnptr + data_buffer_size; - filehdr.f_symptr = data_scnhdr.s_relptr + data_scnhdr.s_nreloc * RELSZ; - - bfd_coff_swap_filehdr_out (abfd, &filehdr, filehdr_ext); - bfd_bwrite (filehdr_ext, FILHSZ, abfd); - bfd_coff_swap_scnhdr_out (abfd, &text_scnhdr, &scnhdr_ext[SCNHSZ * 0]); - bfd_coff_swap_scnhdr_out (abfd, &data_scnhdr, &scnhdr_ext[SCNHSZ * 1]); - bfd_coff_swap_scnhdr_out (abfd, &bss_scnhdr, &scnhdr_ext[SCNHSZ * 2]); - bfd_bwrite (scnhdr_ext, 3 * SCNHSZ, abfd); - bfd_bwrite (data_buffer, data_buffer_size, abfd); - bfd_bwrite (reloc_ext, data_scnhdr.s_nreloc * RELSZ, abfd); - bfd_bwrite (syment_ext, filehdr.f_nsyms * SYMESZ, abfd); - bfd_bwrite (string_table, string_table_size, abfd); - - free (data_buffer); - data_buffer = NULL; - - return TRUE; -} - -/* The typical dynamic reloc. */ - -static reloc_howto_type xcoff64_dynamic_reloc = -HOWTO (0, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - 0, /* special_function */ - "R_POS", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE); /* pcrel_offset */ - -static unsigned long xcoff64_glink_code[10] = -{ - 0xe9820000, /* ld r12,0(r2) */ - 0xf8410028, /* std r2,40(r1) */ - 0xe80c0000, /* ld r0,0(r12) */ - 0xe84c0008, /* ld r0,8(r12) */ - 0x7c0903a6, /* mtctr r0 */ - 0x4e800420, /* bctr */ - 0x00000000, /* start of traceback table */ - 0x000ca000, /* traceback table */ - 0x00000000, /* traceback table */ - 0x00000018, /* ??? */ -}; - -static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = - { - { /* COFF backend, defined in libcoff.h. */ - _bfd_xcoff64_swap_aux_in, - _bfd_xcoff64_swap_sym_in, - _bfd_xcoff64_swap_lineno_in, - _bfd_xcoff64_swap_aux_out, - _bfd_xcoff64_swap_sym_out, - _bfd_xcoff64_swap_lineno_out, - xcoff64_swap_reloc_out, - coff_swap_filehdr_out, - coff_swap_aouthdr_out, - coff_swap_scnhdr_out, - FILHSZ, - AOUTSZ, - SCNHSZ, - SYMESZ, - AUXESZ, - RELSZ, - LINESZ, - FILNMLEN, - TRUE, /* _bfd_coff_long_filenames */ - XCOFF_NO_LONG_SECTION_NAMES, /* _bfd_coff_long_section_names */ - 3, /* _bfd_coff_default_section_alignment_power */ - TRUE, /* _bfd_coff_force_symnames_in_strings */ - 4, /* _bfd_coff_debug_string_prefix_length */ - 32768, /* _bfd_coff_max_nscns */ - coff_swap_filehdr_in, - coff_swap_aouthdr_in, - coff_swap_scnhdr_in, - xcoff64_swap_reloc_in, - xcoff64_bad_format_hook, - coff_set_arch_mach_hook, - coff_mkobject_hook, - styp_to_sec_flags, - coff_set_alignment_hook, - coff_slurp_symbol_table, - symname_in_debug_hook, - coff_pointerize_aux_hook, - coff_print_aux, - dummy_reloc16_extra_cases, - dummy_reloc16_estimate, - NULL, /* bfd_coff_symbol_classification */ - coff_compute_section_file_positions, - NULL, /* _bfd_coff_start_final_link */ - xcoff64_ppc_relocate_section, - coff_rtype_to_howto, - NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, - coff_link_output_has_begun, - coff_final_link_postscript, - NULL /* print_pdata. */ - }, - - 0x01EF, /* magic number */ - bfd_arch_powerpc, - bfd_mach_ppc_620, - - /* Function pointers to xcoff specific swap routines. */ - xcoff64_swap_ldhdr_in, - xcoff64_swap_ldhdr_out, - xcoff64_swap_ldsym_in, - xcoff64_swap_ldsym_out, - xcoff64_swap_ldrel_in, - xcoff64_swap_ldrel_out, - - /* Sizes. */ - LDHDRSZ, - LDSYMSZ, - LDRELSZ, - 24, /* _xcoff_function_descriptor_size */ - 0, /* _xcoff_small_aout_header_size */ - - /* Versions. */ - 2, /* _xcoff_ldhdr_version */ - - _bfd_xcoff64_put_symbol_name, - _bfd_xcoff64_put_ldsymbol_name, - &xcoff64_dynamic_reloc, - xcoff64_create_csect_from_smclas, - - /* Lineno and reloc count overflow. */ - xcoff64_is_lineno_count_overflow, - xcoff64_is_reloc_count_overflow, - - xcoff64_loader_symbol_offset, - xcoff64_loader_reloc_offset, - - /* glink. */ - &xcoff64_glink_code[0], - 40, /* _xcoff_glink_size */ - - /* rtinit. */ - 88, /* _xcoff_rtinit_size */ - xcoff64_generate_rtinit, - }; - -/* The transfer vector that leads the outside world to all of the above. */ -const bfd_target rs6000_xcoff64_vec = - { - "aixcoff64-rs6000", - bfd_target_xcoff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC - | HAS_SYMS | HAS_LOCALS | WP_TEXT), - - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, - 0, /* leading char */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - /* 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_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 */ - _bfd_dummy_target, - coff_object_p, - xcoff64_archive_p, - CORE_FILE_P - }, - - { /* bfd_set_format */ - bfd_false, - coff_mkobject, - _bfd_generic_mkarchive, - bfd_false - }, - - {/* bfd_write_contents */ - bfd_false, - xcoff64_write_object_contents, - _bfd_xcoff_write_archive_contents, - bfd_false - }, - - /* Generic */ - _bfd_archive_close_and_cleanup, - bfd_true, - coff_new_section_hook, - _bfd_generic_get_section_contents, - _bfd_generic_get_section_contents_in_window, - - /* Copy */ - _bfd_xcoff_copy_private_bfd_data, - _bfd_generic_bfd_merge_private_bfd_data, - _bfd_generic_init_private_section_data, - _bfd_generic_bfd_copy_private_section_data, - _bfd_generic_bfd_copy_private_symbol_data, - _bfd_generic_bfd_copy_private_header_data, - _bfd_generic_bfd_set_private_flags, - _bfd_generic_bfd_print_private_bfd_data, - - /* Core */ - BFD_JUMP_TABLE_CORE (coff), - - /* Archive */ - xcoff64_slurp_armap, - _bfd_noarchive_slurp_extended_name_table, - _bfd_noarchive_construct_extended_name_table, - bfd_dont_truncate_arname, - _bfd_xcoff_write_armap, - _bfd_xcoff_read_ar_hdr, - _bfd_generic_write_ar_hdr, - xcoff64_openr_next_archived_file, - _bfd_generic_get_elt_at_index, - _bfd_xcoff_stat_arch_elt, - bfd_true, - - /* Symbols */ - coff_get_symtab_upper_bound, - coff_canonicalize_symtab, - coff_make_empty_symbol, - coff_print_symbol, - coff_get_symbol_info, - coff_get_symbol_version_string, - _bfd_xcoff_is_local_label_name, - coff_bfd_is_target_special_symbol, - coff_get_lineno, - coff_find_nearest_line, - coff_find_line, - coff_find_inliner_info, - coff_bfd_make_debug_symbol, - _bfd_generic_read_minisymbols, - _bfd_generic_minisymbol_to_symbol, - - /* Reloc */ - coff_get_reloc_upper_bound, - coff_canonicalize_reloc, - _bfd_generic_set_reloc, - xcoff64_reloc_type_lookup, - xcoff64_reloc_name_lookup, - - /* Write */ - coff_set_arch_mach, - coff_set_section_contents, - - /* Link */ - xcoff64_sizeof_headers, - bfd_generic_get_relocated_section_contents, - bfd_generic_relax_section, - _bfd_xcoff_bfd_link_hash_table_create, - _bfd_xcoff_bfd_link_add_symbols, - _bfd_generic_link_just_syms, - _bfd_generic_copy_link_hash_symbol_type, - _bfd_xcoff_bfd_final_link, - _bfd_generic_link_split_section, - _bfd_generic_link_check_relocs, - bfd_generic_gc_sections, - bfd_generic_lookup_section_flags, - bfd_generic_merge_sections, - bfd_generic_is_group_section, - bfd_generic_discard_group, - _bfd_generic_section_already_linked, - _bfd_xcoff_define_common_symbol, - bfd_generic_define_start_stop, - - /* Dynamic */ - _bfd_xcoff_get_dynamic_symtab_upper_bound, - _bfd_xcoff_canonicalize_dynamic_symtab, - _bfd_nodynamic_get_synthetic_symtab, - _bfd_xcoff_get_dynamic_reloc_upper_bound, - _bfd_xcoff_canonicalize_dynamic_reloc, - - /* Opposite endian version, none exists */ - NULL, - - &bfd_xcoff_backend_data, - }; - -extern const bfd_target *xcoff64_core_p - (bfd *); -extern bfd_boolean xcoff64_core_file_matches_executable_p - (bfd *, bfd *); -extern char *xcoff64_core_file_failing_command - (bfd *); -extern int xcoff64_core_file_failing_signal - (bfd *); -#define xcoff64_core_file_pid _bfd_nocore_core_file_pid - -/* AIX 5 */ -static const struct xcoff_backend_data_rec bfd_xcoff_aix5_backend_data = - { - { /* COFF backend, defined in libcoff.h. */ - _bfd_xcoff64_swap_aux_in, - _bfd_xcoff64_swap_sym_in, - _bfd_xcoff64_swap_lineno_in, - _bfd_xcoff64_swap_aux_out, - _bfd_xcoff64_swap_sym_out, - _bfd_xcoff64_swap_lineno_out, - xcoff64_swap_reloc_out, - coff_swap_filehdr_out, - coff_swap_aouthdr_out, - coff_swap_scnhdr_out, - FILHSZ, - AOUTSZ, - SCNHSZ, - SYMESZ, - AUXESZ, - RELSZ, - LINESZ, - FILNMLEN, - TRUE, /* _bfd_coff_long_filenames */ - XCOFF_NO_LONG_SECTION_NAMES, /* _bfd_coff_long_section_names */ - 3, /* _bfd_coff_default_section_alignment_power */ - TRUE, /* _bfd_coff_force_symnames_in_strings */ - 4, /* _bfd_coff_debug_string_prefix_length */ - 32768, /* _bfd_coff_max_nscns */ - coff_swap_filehdr_in, - coff_swap_aouthdr_in, - coff_swap_scnhdr_in, - xcoff64_swap_reloc_in, - xcoff64_bad_format_hook, - coff_set_arch_mach_hook, - coff_mkobject_hook, - styp_to_sec_flags, - coff_set_alignment_hook, - coff_slurp_symbol_table, - symname_in_debug_hook, - coff_pointerize_aux_hook, - coff_print_aux, - dummy_reloc16_extra_cases, - dummy_reloc16_estimate, - NULL, /* bfd_coff_sym_is_global */ - coff_compute_section_file_positions, - NULL, /* _bfd_coff_start_final_link */ - xcoff64_ppc_relocate_section, - coff_rtype_to_howto, - NULL, /* _bfd_coff_adjust_symndx */ - _bfd_generic_link_add_one_symbol, - coff_link_output_has_begun, - coff_final_link_postscript, - NULL /* print_pdata. */ - }, - - U64_TOCMAGIC, /* magic number */ - bfd_arch_powerpc, - bfd_mach_ppc_620, - - /* Function pointers to xcoff specific swap routines. */ - xcoff64_swap_ldhdr_in, - xcoff64_swap_ldhdr_out, - xcoff64_swap_ldsym_in, - xcoff64_swap_ldsym_out, - xcoff64_swap_ldrel_in, - xcoff64_swap_ldrel_out, - - /* Sizes. */ - LDHDRSZ, - LDSYMSZ, - LDRELSZ, - 24, /* _xcoff_function_descriptor_size */ - 0, /* _xcoff_small_aout_header_size */ - /* Versions. */ - 2, /* _xcoff_ldhdr_version */ - - _bfd_xcoff64_put_symbol_name, - _bfd_xcoff64_put_ldsymbol_name, - &xcoff64_dynamic_reloc, - xcoff64_create_csect_from_smclas, - - /* Lineno and reloc count overflow. */ - xcoff64_is_lineno_count_overflow, - xcoff64_is_reloc_count_overflow, - - xcoff64_loader_symbol_offset, - xcoff64_loader_reloc_offset, - - /* glink. */ - &xcoff64_glink_code[0], - 40, /* _xcoff_glink_size */ - - /* rtinit. */ - 88, /* _xcoff_rtinit_size */ - xcoff64_generate_rtinit, - }; - -/* The transfer vector that leads the outside world to all of the above. */ -const bfd_target rs6000_xcoff64_aix_vec = - { - "aix5coff64-rs6000", - bfd_target_xcoff_flavour, - BFD_ENDIAN_BIG, /* data byte order is big */ - BFD_ENDIAN_BIG, /* header byte order is big */ - - (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | DYNAMIC - | HAS_SYMS | HAS_LOCALS | WP_TEXT), - - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA, - 0, /* leading char */ - '/', /* ar_pad_char */ - 15, /* ar_max_namelen */ - 0, /* match priority. */ - - /* 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_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 */ - _bfd_dummy_target, - coff_object_p, - xcoff64_archive_p, - xcoff64_core_p - }, - - { /* bfd_set_format */ - bfd_false, - coff_mkobject, - _bfd_generic_mkarchive, - bfd_false - }, - - {/* bfd_write_contents */ - bfd_false, - xcoff64_write_object_contents, - _bfd_xcoff_write_archive_contents, - bfd_false - }, - - /* Generic */ - _bfd_archive_close_and_cleanup, - bfd_true, - coff_new_section_hook, - _bfd_generic_get_section_contents, - _bfd_generic_get_section_contents_in_window, - - /* Copy */ - _bfd_xcoff_copy_private_bfd_data, - _bfd_generic_bfd_merge_private_bfd_data, - _bfd_generic_init_private_section_data, - _bfd_generic_bfd_copy_private_section_data, - _bfd_generic_bfd_copy_private_symbol_data, - _bfd_generic_bfd_copy_private_header_data, - _bfd_generic_bfd_set_private_flags, - _bfd_generic_bfd_print_private_bfd_data, - - /* Core */ - BFD_JUMP_TABLE_CORE (xcoff64), - - /* Archive */ - xcoff64_slurp_armap, - _bfd_noarchive_slurp_extended_name_table, - _bfd_noarchive_construct_extended_name_table, - bfd_dont_truncate_arname, - _bfd_xcoff_write_armap, - _bfd_xcoff_read_ar_hdr, - _bfd_generic_write_ar_hdr, - xcoff64_openr_next_archived_file, - _bfd_generic_get_elt_at_index, - _bfd_xcoff_stat_arch_elt, - bfd_true, - - /* Symbols */ - coff_get_symtab_upper_bound, - coff_canonicalize_symtab, - coff_make_empty_symbol, - coff_print_symbol, - coff_get_symbol_info, - coff_get_symbol_version_string, - _bfd_xcoff_is_local_label_name, - coff_bfd_is_target_special_symbol, - coff_get_lineno, - coff_find_nearest_line, - coff_find_line, - coff_find_inliner_info, - coff_bfd_make_debug_symbol, - _bfd_generic_read_minisymbols, - _bfd_generic_minisymbol_to_symbol, - - /* Reloc */ - coff_get_reloc_upper_bound, - coff_canonicalize_reloc, - _bfd_generic_set_reloc, - xcoff64_reloc_type_lookup, - xcoff64_reloc_name_lookup, - - /* Write */ - coff_set_arch_mach, - coff_set_section_contents, - - /* Link */ - xcoff64_sizeof_headers, - bfd_generic_get_relocated_section_contents, - bfd_generic_relax_section, - _bfd_xcoff_bfd_link_hash_table_create, - _bfd_xcoff_bfd_link_add_symbols, - _bfd_generic_link_just_syms, - _bfd_generic_copy_link_hash_symbol_type, - _bfd_xcoff_bfd_final_link, - _bfd_generic_link_split_section, - _bfd_generic_link_check_relocs, - bfd_generic_gc_sections, - bfd_generic_lookup_section_flags, - bfd_generic_merge_sections, - bfd_generic_is_group_section, - bfd_generic_discard_group, - _bfd_generic_section_already_linked, - _bfd_xcoff_define_common_symbol, - bfd_generic_define_start_stop, - - /* Dynamic */ - _bfd_xcoff_get_dynamic_symtab_upper_bound, - _bfd_xcoff_canonicalize_dynamic_symtab, - _bfd_nodynamic_get_synthetic_symtab, - _bfd_xcoff_get_dynamic_reloc_upper_bound, - _bfd_xcoff_canonicalize_dynamic_reloc, - - /* Opposite endian version, none exists. */ - NULL, - - & bfd_xcoff_aix5_backend_data, - }; diff --git a/sdcc/support/sdbinutils/bfd/coffgen.c b/sdcc/support/sdbinutils/bfd/coffgen.c deleted file mode 100644 index b2410873d..000000000 --- a/sdcc/support/sdbinutils/bfd/coffgen.c +++ /dev/null @@ -1,3135 +0,0 @@ -/* Support for the generic parts of COFF, for BFD. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* 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 "sysdep.h" -#include "bfd.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. On reading, we want to - accept long names if the format permits them at all, regardless - of the current state of the flag that dictates if we would generate - them in outputs; this construct checks if that is the case by - attempting to set the flag, without changing its state; the call - will fail for formats that do not support long names at all. */ - if (bfd_coff_set_long_section_names (abfd, bfd_coff_long_section_names (abfd)) - && hdr->s_name[0] == '/') - { - char buf[SCNNMLEN]; - long strindex; - char *p; - const char *strings; - - /* Flag that this BFD uses long names, even though the format might - expect them to be off by default. This won't directly affect the - format of any output BFD created from this one, but the information - can be used to decide what to do. */ - bfd_coff_set_long_section_names (abfd, TRUE); - 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; - if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) - return FALSE; - strings += strindex; - name = (char *) bfd_alloc (abfd, - (bfd_size_type) strlen (strings) + 1 + 1); - if (name == NULL) - return FALSE; - strcpy (name, strings); - } - } - - if (name == NULL) - { - /* Assorted wastage to null-terminate the name, thanks AT&T! */ - name = (char *) bfd_alloc (abfd, - (bfd_size_type) sizeof (hdr->s_name) + 1 + 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; - - /* Compress/decompress DWARF debug sections with names: .debug_* and - .zdebug_*, after the section flags is set. */ - if ((flags & SEC_DEBUGGING) - && strlen (name) > 7 - && ((name[1] == 'd' && name[6] == '_') - || (strlen (name) > 8 && name[1] == 'z' && name[7] == '_'))) - { - enum { nothing, compress, decompress } action = nothing; - char *new_name = NULL; - - if (bfd_is_section_compressed (abfd, return_section)) - { - /* Compressed section. Check if we should decompress. */ - if ((abfd->flags & BFD_DECOMPRESS)) - action = decompress; - } - else if (!bfd_is_section_compressed (abfd, return_section)) - { - /* Normal section. Check if we should compress. */ - if ((abfd->flags & BFD_COMPRESS) && return_section->size != 0) - action = compress; - } - - switch (action) - { - case nothing: - break; - case compress: - if (!bfd_init_section_compress_status (abfd, return_section)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: unable to initialize compress status for section %s"), - abfd, name); - return FALSE; - } - if (return_section->compress_status == COMPRESS_SECTION_DONE) - { - if (name[1] != 'z') - { - unsigned int len = strlen (name); - - new_name = bfd_alloc (abfd, len + 2); - if (new_name == NULL) - return FALSE; - new_name[0] = '.'; - new_name[1] = 'z'; - memcpy (new_name + 2, name + 1, len); - } - } - break; - case decompress: - if (!bfd_init_section_decompress_status (abfd, return_section)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: unable to initialize decompress status for section %s"), - abfd, name); - return FALSE; - } - if (name[1] == 'z') - { - unsigned int len = strlen (name); - - new_name = bfd_alloc (abfd, len); - if (new_name == NULL) - return FALSE; - new_name[0] = '.'; - memcpy (new_name + 1, name + 2, len - 1); - } - break; - } - if (new_name != NULL) - bfd_rename_section (abfd, return_section, new_name); - } - - return result; -} - -/* Read in a COFF object and make it into a BFD. This is used by - ECOFF as well. */ -const bfd_target * -coff_real_object_p (bfd *, - unsigned, - struct internal_filehdr *, - struct internal_aouthdr *); -const bfd_target * -coff_real_object_p (bfd *abfd, - unsigned nscns, - struct internal_filehdr *internal_f, - 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 = (char *) 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; - } - /* PR 17512: file: 11056-1136-0.004. */ - if (internal_f.f_opthdr < aoutsz) - memset (((char *) opthdr) + internal_f.f_opthdr, 0, aoutsz - internal_f.f_opthdr); - - bfd_coff_swap_aouthdr_in (abfd, opthdr, (void *) &internal_a); - bfd_release (abfd, opthdr); - } - - 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 section_index) -{ - struct bfd_section *answer = abfd->sections; - - if (section_index == N_ABS) - return bfd_abs_section_ptr; - if (section_index == N_UNDEF) - return bfd_und_section_ptr; - if (section_index == N_DEBUG) - return bfd_abs_section_ptr; - - while (answer) - { - if (answer->target_index == section_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; - } - /* PR 17910: Only check for string overflow if the length has been set. - Some DLLs, eg those produced by Visual Studio, may not set the length field. */ - if (obj_coff_strings_len (abfd) > 0 - && sym->_n._n_n._n_offset >= obj_coff_strings_len (abfd)) - return NULL; - return strings + sym->_n._n_n._n_offset; - } -} - -/* 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 (sec->reloc_count == 0) - return internal_relocs; /* Nothing to do. */ - - if (coff_section_data (abfd, sec) != NULL - && coff_section_data (abfd, sec)->relocs != NULL) - { - if (! require_internal) - return coff_section_data (abfd, sec)->relocs; - memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs, - sec->reloc_count * sizeof (struct internal_reloc)); - return internal_relocs; - } - - relsz = bfd_coff_relsz (abfd); - - amt = sec->reloc_count * relsz; - if (external_relocs == NULL) - { - free_external = (bfd_byte *) bfd_malloc (amt); - if (free_external == NULL) - goto error_return; - external_relocs = free_external; - } - - if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 - || bfd_bread (external_relocs, amt, abfd) != amt) - goto error_return; - - if (internal_relocs == NULL) - { - amt = sec->reloc_count; - amt *= sizeof (struct internal_reloc); - free_internal = (struct internal_reloc *) bfd_malloc (amt); - if (free_internal == NULL) - 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; -} - -static void -fixup_symbol_value (bfd *abfd, - coff_symbol_type *coff_symbol_ptr, - struct internal_syment *syment) -{ - /* Normalize the symbol flags. */ - if (coff_symbol_ptr->symbol.section - && 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 = (asymbol **) bfd_alloc (bfd_ptr, amt); - if (!newsyms) - return FALSE; - bfd_ptr->outsymbols = newsyms; - for (i = 0; i < symbol_count; i++) - if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0 - || (!bfd_is_und_section (symbol_ptr_ptr[i]->section) - && !bfd_is_com_section (symbol_ptr_ptr[i]->section) - && ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) != 0 - || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK)) - == 0)))) - *newsyms++ = symbol_ptr_ptr[i]; - - for (i = 0; i < symbol_count; i++) - if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 - && !bfd_is_und_section (symbol_ptr_ptr[i]->section) - && (bfd_is_com_section (symbol_ptr_ptr[i]->section) - || ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) == 0 - && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK)) - != 0)))) - *newsyms++ = symbol_ptr_ptr[i]; - - *first_undef = newsyms - bfd_ptr->outsymbols; - - for (i = 0; i < symbol_count; i++) - if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 - && bfd_is_und_section (symbol_ptr_ptr[i]->section)) - *newsyms++ = symbol_ptr_ptr[i]; - *newsyms = (asymbol *) NULL; - symbol_ptr_ptr = bfd_ptr->outsymbols; - } - - for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) - { - coff_symbol_type *coff_symbol_ptr; - - coff_symbol_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); - symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; - if (coff_symbol_ptr && coff_symbol_ptr->native) - { - combined_entry_type *s = coff_symbol_ptr->native; - int i; - - BFD_ASSERT (s->is_sym); - if (s->u.syment.n_sclass == C_FILE) - { - if (last_file != NULL) - 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_ptr = coff_symbol_from (symbol_ptr_ptr[symbol_index]); - if (coff_symbol_ptr && coff_symbol_ptr->native) - { - int i; - combined_entry_type *s = coff_symbol_ptr->native; - - BFD_ASSERT (s->is_sym); - if (s->fix_value) - { - /* FIXME: We should use a union here. */ - s->u.syment.n_value = - (bfd_hostptr_t) ((combined_entry_type *) - ((bfd_hostptr_t) 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; - - BFD_ASSERT (! a->is_sym); - 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); - - BFD_ASSERT (native->is_sym); - 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); - - BFD_ASSERT (! (native + 1)->is_sym); - 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 n_sclass = (int) native->u.syment.n_sclass; - asection *output_section = symbol->section->output_section - ? symbol->section->output_section - : symbol->section; - void * buf; - bfd_size_type symesz; - - BFD_ASSERT (native->is_sym); - - 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 = - 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_ASSERT (! (native + j + 1)->is_sym); - bfd_coff_swap_aux_out (abfd, - &((native + j + 1)->u.auxent), - type, n_sclass, (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. */ - -bfd_boolean -coff_write_alien_symbol (bfd *abfd, - asymbol *symbol, - struct internal_syment *isym, - union internal_auxent *iaux, - 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[2]; - asection *output_section = symbol->section->output_section - ? symbol->section->output_section - : symbol->section; - struct bfd_link_info *link_info = coff_data (abfd)->link_info; - bfd_boolean ret; - - if ((!link_info || link_info->strip_discarded) - && !bfd_is_abs_section (symbol->section) - && symbol->section->output_section == bfd_abs_section_ptr) - { - symbol->name = ""; - if (isym != NULL) - memset (isym, 0, sizeof (*isym)); - return TRUE; - } - native = dummy; - native->is_sym = TRUE; - native[1].is_sym = FALSE; - native->u.syment.n_type = T_NULL; - native->u.syment.n_flags = 0; - native->u.syment.n_numaux = 0; - 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_FILE) - { - native->u.syment.n_scnum = N_DEBUG; - native->u.syment.n_numaux = 1; - } - 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 = ""; - if (isym != NULL) - memset (isym, 0, sizeof (*isym)); - return TRUE; - } - else - { - native->u.syment.n_scnum = output_section->target_index; - native->u.syment.n_value = (symbol->value - + symbol->section->output_offset); - if (! obj_pe (abfd)) - native->u.syment.n_value += output_section->vma; - - /* Copy the any flags from the file header into the symbol. - FIXME: Why? */ - { - coff_symbol_type *c = coff_symbol_from (symbol); - if (c != (coff_symbol_type *) NULL) - native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; - } - } - - native->u.syment.n_type = 0; - if (symbol->flags & BSF_FILE) - native->u.syment.n_sclass = C_FILE; - else 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; - - ret = coff_write_symbol (abfd, symbol, native, written, string_size_p, - debug_string_section_p, debug_string_size_p); - if (isym != NULL) - *isym = native->u.syment; - if (iaux != NULL && native->u.syment.n_numaux) - *iaux = native[1].u.auxent; - return ret; -} - -/* 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; - struct bfd_link_info *link_info = coff_data (abfd)->link_info; - - if ((!link_info || link_info->strip_discarded) - && !bfd_is_abs_section (symbol->symbol.section) - && symbol->symbol.section->output_section == bfd_abs_section_ptr) - { - symbol->symbol.name = ""; - return TRUE; - } - - BFD_ASSERT (native->is_sym); - /* If this symbol has an associated line number, we must store the - symbol index in the line number field. We also tag the auxent to - point to the right place in the lineno table. */ - 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); -} - -static void -null_error_handler (const char *fmt ATTRIBUTE_UNUSED, - va_list ap ATTRIBUTE_UNUSED) -{ -} - -/* 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 (symbol); - - if (c_symbol == (coff_symbol_type *) NULL - || c_symbol->native == (combined_entry_type *) NULL) - { - if (!coff_write_alien_symbol (abfd, symbol, NULL, NULL, &written, - &string_size, &debug_string_section, - &debug_string_size)) - return FALSE; - } - else - { - if (coff_backend_info (abfd)->_bfd_coff_classify_symbol != NULL) - { - bfd_error_handler_type current_error_handler; - enum coff_symbol_classification sym_class; - unsigned char *n_sclass; - - /* Suppress error reporting by bfd_coff_classify_symbol. - Error messages can be generated when we are processing a local - symbol which has no associated section and we do not have to - worry about this, all we need to know is that it is local. */ - current_error_handler = bfd_set_error_handler (null_error_handler); - BFD_ASSERT (c_symbol->native->is_sym); - sym_class = bfd_coff_classify_symbol (abfd, - &c_symbol->native->u.syment); - (void) bfd_set_error_handler (current_error_handler); - - n_sclass = &c_symbol->native->u.syment.n_sclass; - - /* If the symbol class has been changed (eg objcopy/ld script/etc) - we cannot retain the existing sclass from the original symbol. - Weak symbols only have one valid sclass, so just set it always. - If it is not local class and should be, set it C_STAT. - If it is global and not classified as global, or if it is - weak (which is also classified as global), set it C_EXT. */ - - if (symbol->flags & BSF_WEAK) - *n_sclass = obj_pe (abfd) ? C_NT_WEAK : C_WEAKEXT; - else if (symbol->flags & BSF_LOCAL && sym_class != COFF_SYMBOL_LOCAL) - *n_sclass = C_STAT; - else if (symbol->flags & BSF_GLOBAL - && (sym_class != COFF_SYMBOL_GLOBAL -#ifdef COFF_WITH_PE - || *n_sclass == C_NT_WEAK -#endif - || *n_sclass == C_WEAKEXT)) - c_symbol->native->u.syment.n_sclass = C_EXT; - } - - 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 (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 (! c_symbol->native->is_sym) - maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; - - else if (bfd_coff_symname_in_debug (abfd, - &c_symbol->native->u.syment)) - /* This symbol name is in the XCOFF .debug section. - 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 n_sclass = symbol->u.syment.n_sclass; - - BFD_ASSERT (symbol->is_sym); - if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) - { - if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) - (abfd, table_base, symbol, indaux, auxent)) - return; - } - - /* Don't bother if this is a file or a section. */ - if (n_sclass == C_STAT && type == T_NULL) - return; - if (n_sclass == C_FILE) - return; - - BFD_ASSERT (! auxent->is_sym); - /* Otherwise patch up. */ -#define N_TMASK coff_data (abfd)->local_n_tmask -#define N_BTSHFT coff_data (abfd)->local_n_btshft - - if ((ISFCN (type) || ISTAG (n_sclass) || n_sclass == C_BLOCK - || n_sclass == 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, asection ** sect_return) -{ - 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 = (char *) 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; - - * sect_return = sect; - 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 = (char *) 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; - if (size == 0) - return TRUE; - /* Check for integer overflow and for unreasonable symbol counts. */ - if (size < obj_raw_syment_count (abfd) - || (bfd_get_file_size (abfd) > 0 - && size > bfd_get_file_size (abfd))) - - { - _bfd_error_handler (_("%B: corrupt symbol count: %#Lx"), - abfd, obj_raw_syment_count (abfd)); - return FALSE; - } - - syms = bfd_malloc (size); - if (syms == NULL) - { - /* PR 21013: Provide an error message when the alloc fails. */ - _bfd_error_handler (_("%B: not enough memory to allocate space for %#Lx symbols of size %#Lx"), - abfd, obj_raw_syment_count (abfd), symesz); - 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. If the strings - are loaded then the STRINGS and STRINGS_LEN fields in the - coff_tdata structure will be set. */ - -const char * -_bfd_coff_read_string_table (bfd *abfd) -{ - 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 || strsize > bfd_get_file_size (abfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: bad string table size %Lu"), abfd, strsize); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - strings = (char *) bfd_malloc (strsize + 1); - if (strings == NULL) - return NULL; - - /* PR 17521 file: 079-54929-0.004. - A corrupt file could contain an index that points into the first - STRING_SIZE_SIZE bytes of the string table, so make sure that - they are zero. */ - memset (strings, 0, STRING_SIZE_SIZE); - - if (bfd_bread (strings + STRING_SIZE_SIZE, strsize - STRING_SIZE_SIZE, abfd) - != strsize - STRING_SIZE_SIZE) - { - free (strings); - return NULL; - } - - obj_coff_strings (abfd) = strings; - obj_coff_strings_len (abfd) = strsize; - /* Terminate the string table, just in case. */ - strings[strsize] = 0; - return strings; -} - -/* Free up the external symbols and strings read from a COFF file. */ - -bfd_boolean -_bfd_coff_free_symbols (bfd *abfd) -{ - if (! bfd_family_coff (abfd)) - return FALSE; - - 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; - obj_coff_strings_len (abfd) = 0; - } - - 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; - asection * debug_sec = NULL; - char *debug_sec_data = NULL; - bfd_size_type size; - - if (obj_raw_syments (abfd) != NULL) - return obj_raw_syments (abfd); - - if (! _bfd_coff_get_external_symbols (abfd)) - return NULL; - - size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); - /* Check for integer overflow. */ - if (size < obj_raw_syment_count (abfd)) - return NULL; - internal = (combined_entry_type *) bfd_zalloc (abfd, size); - if (internal == NULL && size != 0) - return NULL; - internal_end = internal + obj_raw_syment_count (abfd); - - 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; - internal_ptr->is_sym = TRUE; - - /* PR 17512: file: 1353-1166-0.004. */ - if (symbol_ptr->u.syment.n_sclass == C_FILE - && symbol_ptr->u.syment.n_numaux > 0 - && raw_src + symesz + symbol_ptr->u.syment.n_numaux - * symesz > raw_end) - { - bfd_release (abfd, internal); - return NULL; - } - - for (i = 0; - i < symbol_ptr->u.syment.n_numaux; - i++) - { - internal_ptr++; - /* PR 17512: Prevent buffer overrun. */ - if (internal_ptr >= internal_end) - { - bfd_release (abfd, internal); - return NULL; - } - - raw_src += symesz; - bfd_coff_swap_aux_in (abfd, (void *) raw_src, - symbol_ptr->u.syment.n_type, - symbol_ptr->u.syment.n_sclass, - (int) i, symbol_ptr->u.syment.n_numaux, - &(internal_ptr->u.auxent)); - - internal_ptr->is_sym = FALSE; - coff_pointerize_aux (abfd, internal, symbol_ptr, i, - internal_ptr); - } - } - - /* 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++) - { - BFD_ASSERT (internal_ptr->is_sym); - - if (internal_ptr->u.syment.n_sclass == C_FILE - && internal_ptr->u.syment.n_numaux > 0) - { - combined_entry_type * aux = internal_ptr + 1; - - /* Make a file symbol point to the name in the auxent, since - the text ".file" is redundant. */ - BFD_ASSERT (! aux->is_sym); - - if (aux->u.auxent.x_file.x_n.x_zeroes == 0) - { - /* The filename is a long one, point into the string table. */ - if (string_table == NULL) - { - string_table = _bfd_coff_read_string_table (abfd); - if (string_table == NULL) - return NULL; - } - - if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_offset) - >= obj_coff_strings_len (abfd)) - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); - else - internal_ptr->u.syment._n._n_n._n_offset = - (bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_offset)); - } - else - { - /* 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 = - (bfd_hostptr_t) - copy_name (abfd, - aux->u.auxent.x_file.x_fname, - internal_ptr->u.syment.n_numaux * symesz); - else - internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - copy_name (abfd, - aux->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 = (char *) 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 = (bfd_hostptr_t) 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 = (bfd_hostptr_t) ""; - 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; - } - if (internal_ptr->u.syment._n._n_n._n_offset >= obj_coff_strings_len (abfd) - || string_table + internal_ptr->u.syment._n._n_n._n_offset < string_table) - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); - else - internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - (string_table - + internal_ptr->u.syment._n._n_n._n_offset)); - } - else - { - /* Long name in debug section. Very similar. */ - if (debug_sec_data == NULL) - debug_sec_data = build_debug_section (abfd, & debug_sec); - if (debug_sec_data != NULL) - { - BFD_ASSERT (debug_sec != NULL); - /* PR binutils/17512: Catch out of range offsets into the debug data. */ - if (internal_ptr->u.syment._n._n_n._n_offset > debug_sec->size - || debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset < debug_sec_data) - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _(""); - else - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) - (debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset); - } - else - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) ""; - } - } - internal_ptr += internal_ptr->u.syment.n_numaux; - } - - 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_symbol = (coff_symbol_type *) bfd_zalloc (abfd, amt); - - if (new_symbol == NULL) - return NULL; - new_symbol->symbol.section = 0; - new_symbol->native = NULL; - new_symbol->lineno = NULL; - new_symbol->done_lineno = FALSE; - new_symbol->symbol.the_bfd = abfd; - - return & new_symbol->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_symbol = (coff_symbol_type *) bfd_alloc (abfd, amt); - - if (new_symbol == 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_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt); - if (!new_symbol->native) - return NULL; - new_symbol->native->is_sym = TRUE; - new_symbol->symbol.section = bfd_abs_section_ptr; - new_symbol->symbol.flags = BSF_DEBUGGING; - new_symbol->lineno = NULL; - new_symbol->done_lineno = FALSE; - new_symbol->symbol.the_bfd = abfd; - - return & new_symbol->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 - && coffsymbol (symbol)->native->is_sym) - ret->value = coffsymbol (symbol)->native->u.syment.n_value - - (bfd_hostptr_t) obj_raw_syments (abfd); -} - -/* 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)); - - /* PR 17512: file: 079-33786-0.001:0.1. */ - if (combined < obj_raw_syments (abfd) - || combined >= obj_raw_syments (abfd) + obj_raw_syment_count (abfd)) - { - fprintf (file, _(" %s"), symbol->name); - break; - } - - BFD_ASSERT (combined->is_sym); - if (! combined->fix_value) - val = (bfd_vma) combined->u.syment.n_value; - else - val = combined->u.syment.n_value - (bfd_hostptr_t) 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); - bfd_fprintf_vma (abfd, 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; - - BFD_ASSERT (! auxp->is_sym); - 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", - (unsigned 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; - } - /* Fall through. */ - case C_EXT: - case C_AIX_WEAKEXT: - 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, - (unsigned long) auxp->u.auxent.x_sym.x_misc.x_fsize, - llnos, next); - break; - } - /* 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) - { - if (l->line_number > 0) - { - fprintf (file, "\n%4d : ", l->line_number); - bfd_fprintf_vma (abfd, 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_with_names (bfd *abfd, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - const struct dwarf_debug_section *debug_sections) -{ - 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, symbols, NULL, section, offset, - filename_ptr, functionname_ptr, - line_ptr, NULL, debug_sections, 0, - &coff_data(abfd)->dwarf2_find_line_info)) - return TRUE; - - sec_data = coff_section_data (abfd, section); - - /* If the DWARF lookup failed, but there is DWARF information available - then the problem might be that the file has been rebased. This tool - changes the VMAs of all the sections, but it does not update the DWARF - information. So try again, using a bias against the address sought. */ - if (coff_data (abfd)->dwarf2_find_line_info != NULL) - { - bfd_signed_vma bias; - - /* Create a cache of the result 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->saved_bias) - bias = sec_data->saved_bias; - else - { - bias = _bfd_dwarf2_find_symbol_bias (symbols, - & coff_data (abfd)->dwarf2_find_line_info); - if (sec_data) - { - sec_data->saved_bias = TRUE; - sec_data->bias = bias; - } - } - - if (bias - && _bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, - offset + bias, - filename_ptr, functionname_ptr, - line_ptr, NULL, debug_sections, 0, - &coff_data(abfd)->dwarf2_find_line_info)) - return TRUE; - } - - *filename_ptr = 0; - *functionname_ptr = 0; - *line_ptr = 0; - - /* 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) - { - BFD_ASSERT (p->is_sym); - 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) - { - bfd_vma file_addr; - combined_entry_type *p2; - - for (p2 = p + 1 + p->u.syment.n_numaux; - p2 < pend; - p2 += 1 + p2->u.syment.n_numaux) - { - BFD_ASSERT (p2->is_sym); - if (p2->u.syment.n_scnum > 0 - && (section - == coff_section_from_bfd_index (abfd, - p2->u.syment.n_scnum))) - break; - if (p2->u.syment.n_sclass == C_FILE) - { - p2 = pend; - break; - } - } - if (p2 >= pend) - break; - - file_addr = (bfd_vma) p2->u.syment.n_value; - /* PR 11512: Include the section address of the function name symbol. */ - if (p2->u.syment.n_scnum > 0) - file_addr += coff_section_from_bfd_index (abfd, - p2->u.syment.n_scnum)->vma; - /* 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 >= file_addr - && offset + sec_vma - file_addr <= 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; - } - } - - if (section->lineno_count == 0) - { - *functionname_ptr = NULL; - *line_ptr = 0; - return TRUE; - } - - /* Now wander though the raw linenumbers of the section. - If we have been called on this section before, and the offset - we want is further down then we can prime the lookup loop. */ - 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; - - BFD_ASSERT (s->is_sym); - 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 - 1; - sec_data->function = *functionname_ptr; - sec_data->line_base = line_base; - } - - return TRUE; -} - -bfd_boolean -coff_find_nearest_line (bfd *abfd, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - unsigned int *discriminator_ptr) -{ - if (discriminator_ptr) - *discriminator_ptr = 0; - return coff_find_nearest_line_with_names (abfd, symbols, section, offset, - filename_ptr, functionname_ptr, - line_ptr, dwarf_debug_sections); -} - -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, struct bfd_link_info *info) -{ - size_t size; - - if (!bfd_link_relocatable (info)) - 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 symbol_class) -{ - coff_symbol_type * csym; - - csym = coff_symbol_from (symbol); - if (csym == NULL) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - else if (csym->native == NULL) - { - /* This is an alien symbol which no native coff backend data. - We cheat here by creating a fake native entry for it and - then filling in the class. This code is based on that in - coff_write_alien_symbol(). */ - - combined_entry_type * native; - bfd_size_type amt = sizeof (* native); - - native = (combined_entry_type *) bfd_zalloc (abfd, amt); - if (native == NULL) - return FALSE; - - native->is_sym = TRUE; - native->u.syment.n_type = T_NULL; - native->u.syment.n_sclass = symbol_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 = symbol_class; - - return TRUE; -} - -bfd_boolean -_bfd_coff_section_already_linked (bfd *abfd, - asection *sec, - struct bfd_link_info *info) -{ - flagword flags; - const char *name, *key; - struct bfd_section_already_linked *l; - struct bfd_section_already_linked_hash_entry *already_linked_list; - struct coff_comdat_info *s_comdat; - - flags = sec->flags; - if ((flags & SEC_LINK_ONCE) == 0) - return FALSE; - - /* The COFF backend linker doesn't support group sections. */ - if ((flags & SEC_GROUP) != 0) - return FALSE; - - name = bfd_get_section_name (abfd, sec); - s_comdat = bfd_coff_get_comdat_section (abfd, sec); - - if (s_comdat != NULL) - key = s_comdat->name; - else - { - if (CONST_STRNEQ (name, ".gnu.linkonce.") - && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) - key++; - else - /* FIXME: gcc as of 2011-09 emits sections like .text$, - .xdata$ and .pdata$ only the first of which has a - comdat key. Should these all match the LTO IR key? */ - key = name; - } - - already_linked_list = bfd_section_already_linked_table_lookup (key); - - for (l = already_linked_list->entry; l != NULL; l = l->next) - { - struct coff_comdat_info *l_comdat; - - l_comdat = bfd_coff_get_comdat_section (l->sec->owner, l->sec); - - /* The section names must match, and both sections must be - comdat and have the same comdat name, or both sections must - be non-comdat. LTO IR plugin sections are an exception. They - are always named .gnu.linkonce.t. ( is some string) - and match any comdat section with comdat name of , and - any linkonce section with the same suffix, ie. - .gnu.linkonce.*.. */ - if (((s_comdat != NULL) == (l_comdat != NULL) - && strcmp (name, l->sec->name) == 0) - || (l->sec->owner->flags & BFD_PLUGIN) != 0) - { - /* The section has already been linked. See if we should - issue a warning. */ - return _bfd_handle_already_linked (sec, l, info); - } - } - - /* This is the first section with this name. Record it. */ - if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) - info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); - return FALSE; -} - -/* Initialize COOKIE for input bfd ABFD. */ - -static bfd_boolean -init_reloc_cookie (struct coff_reloc_cookie *cookie, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *abfd) -{ - /* Sometimes the symbol table does not yet have been loaded here. */ - bfd_coff_slurp_symbol_table (abfd); - - cookie->abfd = abfd; - cookie->sym_hashes = obj_coff_sym_hashes (abfd); - - cookie->symbols = obj_symbols (abfd); - - return TRUE; -} - -/* Free the memory allocated by init_reloc_cookie, if appropriate. */ - -static void -fini_reloc_cookie (struct coff_reloc_cookie *cookie ATTRIBUTE_UNUSED, - bfd *abfd ATTRIBUTE_UNUSED) -{ - /* Nothing to do. */ -} - -/* Initialize the relocation information in COOKIE for input section SEC - of input bfd ABFD. */ - -static bfd_boolean -init_reloc_cookie_rels (struct coff_reloc_cookie *cookie, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *abfd, - asection *sec) -{ - if (sec->reloc_count == 0) - { - cookie->rels = NULL; - cookie->relend = NULL; - cookie->rel = NULL; - return TRUE; - } - - cookie->rels = _bfd_coff_read_internal_relocs (abfd, sec, FALSE, NULL, 0, NULL); - - if (cookie->rels == NULL) - return FALSE; - - cookie->rel = cookie->rels; - cookie->relend = (cookie->rels + sec->reloc_count); - return TRUE; -} - -/* Free the memory allocated by init_reloc_cookie_rels, - if appropriate. */ - -static void -fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie, - asection *sec) -{ - if (cookie->rels - /* PR 20401. The relocs may not have been cached, so check first. - If the relocs were loaded by init_reloc_cookie_rels() then this - will be the case. FIXME: Would performance be improved if the - relocs *were* cached ? */ - && coff_section_data (NULL, sec) - && coff_section_data (NULL, sec)->relocs != cookie->rels) - free (cookie->rels); -} - -/* Initialize the whole of COOKIE for input section SEC. */ - -static bfd_boolean -init_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, - struct bfd_link_info *info, - asection *sec) -{ - if (!init_reloc_cookie (cookie, info, sec->owner)) - return FALSE; - - if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) - { - fini_reloc_cookie (cookie, sec->owner); - return FALSE; - } - return TRUE; -} - -/* Free the memory allocated by init_reloc_cookie_for_section, - if appropriate. */ - -static void -fini_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, - asection *sec) -{ - fini_reloc_cookie_rels (cookie, sec); - fini_reloc_cookie (cookie, sec->owner); -} - -static asection * -_bfd_coff_gc_mark_hook (asection *sec, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct internal_reloc *rel ATTRIBUTE_UNUSED, - struct coff_link_hash_entry *h, - struct internal_syment *sym) -{ - if (h != NULL) - { - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - return h->root.u.def.section; - - case bfd_link_hash_common: - return h->root.u.c.p->section; - - case bfd_link_hash_undefweak: - if (h->symbol_class == C_NT_WEAK && h->numaux == 1) - { - /* PE weak externals. A weak symbol may include an auxiliary - record indicating that if the weak symbol is not resolved, - another external symbol is used instead. */ - struct coff_link_hash_entry *h2 = - h->auxbfd->tdata.coff_obj_data->sym_hashes[ - h->aux->x_sym.x_tagndx.l]; - - if (h2 && h2->root.type != bfd_link_hash_undefined) - return h2->root.u.def.section; - } - break; - - case bfd_link_hash_undefined: - default: - break; - } - return NULL; - } - - return coff_section_from_bfd_index (sec->owner, sym->n_scnum); -} - -/* COOKIE->rel describes a relocation against section SEC, which is - a section we've decided to keep. Return the section that contains - the relocation symbol, or NULL if no section contains it. */ - -static asection * -_bfd_coff_gc_mark_rsec (struct bfd_link_info *info, asection *sec, - coff_gc_mark_hook_fn gc_mark_hook, - struct coff_reloc_cookie *cookie) -{ - struct coff_link_hash_entry *h; - - h = cookie->sym_hashes[cookie->rel->r_symndx]; - if (h != NULL) - { - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct coff_link_hash_entry *) h->root.u.i.link; - - return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); - } - - return (*gc_mark_hook) (sec, info, cookie->rel, NULL, - &(cookie->symbols - + obj_convert (sec->owner)[cookie->rel->r_symndx])->native->u.syment); -} - -static bfd_boolean _bfd_coff_gc_mark - (struct bfd_link_info *, asection *, coff_gc_mark_hook_fn); - -/* COOKIE->rel describes a relocation against section SEC, which is - a section we've decided to keep. Mark the section that contains - the relocation symbol. */ - -static bfd_boolean -_bfd_coff_gc_mark_reloc (struct bfd_link_info *info, - asection *sec, - coff_gc_mark_hook_fn gc_mark_hook, - struct coff_reloc_cookie *cookie) -{ - asection *rsec; - - rsec = _bfd_coff_gc_mark_rsec (info, sec, gc_mark_hook, cookie); - if (rsec && !rsec->gc_mark) - { - if (bfd_get_flavour (rsec->owner) != bfd_target_coff_flavour) - rsec->gc_mark = 1; - else if (!_bfd_coff_gc_mark (info, rsec, gc_mark_hook)) - return FALSE; - } - return TRUE; -} - -/* The mark phase of garbage collection. For a given section, mark - it and any sections in this section's group, and all the sections - which define symbols to which it refers. */ - -static bfd_boolean -_bfd_coff_gc_mark (struct bfd_link_info *info, - asection *sec, - coff_gc_mark_hook_fn gc_mark_hook) -{ - bfd_boolean ret = TRUE; - - sec->gc_mark = 1; - - /* Look through the section relocs. */ - if ((sec->flags & SEC_RELOC) != 0 - && sec->reloc_count > 0) - { - struct coff_reloc_cookie cookie; - - if (!init_reloc_cookie_for_section (&cookie, info, sec)) - ret = FALSE; - else - { - for (; cookie.rel < cookie.relend; cookie.rel++) - { - if (!_bfd_coff_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) - { - ret = FALSE; - break; - } - } - fini_reloc_cookie_for_section (&cookie, sec); - } - } - - return ret; -} - -static bfd_boolean -_bfd_coff_gc_mark_extra_sections (struct bfd_link_info *info, - coff_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED) -{ - bfd *ibfd; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *isec; - bfd_boolean some_kept; - - if (bfd_get_flavour (ibfd) != bfd_target_coff_flavour) - continue; - - /* Ensure all linker created sections are kept, and see whether - any other section is already marked. */ - some_kept = FALSE; - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - { - if ((isec->flags & SEC_LINKER_CREATED) != 0) - isec->gc_mark = 1; - else if (isec->gc_mark) - some_kept = TRUE; - } - - /* If no section in this file will be kept, then we can - toss out debug sections. */ - if (!some_kept) - continue; - - /* Keep debug and special sections like .comment when they are - not part of a group, or when we have single-member groups. */ - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - if ((isec->flags & SEC_DEBUGGING) != 0 - || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) - isec->gc_mark = 1; - } - return TRUE; -} - -/* Sweep symbols in swept sections. Called via coff_link_hash_traverse. */ - -static bfd_boolean -coff_gc_sweep_symbol (struct coff_link_hash_entry *h, - void *data ATTRIBUTE_UNUSED) -{ - if (h->root.type == bfd_link_hash_warning) - h = (struct coff_link_hash_entry *) h->root.u.i.link; - - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !h->root.u.def.section->gc_mark - && !(h->root.u.def.section->owner->flags & DYNAMIC)) - { - /* Do our best to hide the symbol. */ - h->root.u.def.section = bfd_und_section_ptr; - h->symbol_class = C_HIDDEN; - } - - return TRUE; -} - -/* The sweep phase of garbage collection. Remove all garbage sections. */ - -typedef bfd_boolean (*gc_sweep_hook_fn) - (bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); - -static bfd_boolean -coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) -{ - bfd *sub; - - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - asection *o; - - if (bfd_get_flavour (sub) != bfd_target_coff_flavour) - continue; - - for (o = sub->sections; o != NULL; o = o->next) - { - /* Keep debug and special sections. */ - if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0 - || (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) - o->gc_mark = 1; - else if (CONST_STRNEQ (o->name, ".idata") - || CONST_STRNEQ (o->name, ".pdata") - || CONST_STRNEQ (o->name, ".xdata") - || CONST_STRNEQ (o->name, ".rsrc")) - o->gc_mark = 1; - - if (o->gc_mark) - continue; - - /* Skip sweeping sections already excluded. */ - if (o->flags & SEC_EXCLUDE) - continue; - - /* Since this is early in the link process, it is simple - to remove a section from the output. */ - o->flags |= SEC_EXCLUDE; - - if (info->print_gc_sections && o->size != 0) - /* xgettext: c-format */ - _bfd_error_handler (_("Removing unused section '%A' in file '%B'"), - o, sub); - -#if 0 - /* But we also have to update some of the relocation - info we collected before. */ - if (gc_sweep_hook - && (o->flags & SEC_RELOC) != 0 - && o->reloc_count > 0 - && !bfd_is_abs_section (o->output_section)) - { - struct internal_reloc *internal_relocs; - bfd_boolean r; - - internal_relocs - = _bfd_coff_link_read_relocs (o->owner, o, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - return FALSE; - - r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs); - - if (coff_section_data (o)->relocs != internal_relocs) - free (internal_relocs); - - if (!r) - return FALSE; - } -#endif - } - } - - /* Remove the symbols that were in the swept sections from the dynamic - symbol table. */ - coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol, - NULL); - - return TRUE; -} - -/* Keep all sections containing symbols undefined on the command-line, - and the section containing the entry symbol. */ - -static void -_bfd_coff_gc_keep (struct bfd_link_info *info) -{ - struct bfd_sym_chain *sym; - - for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) - { - struct coff_link_hash_entry *h; - - h = coff_link_hash_lookup (coff_hash_table (info), sym->name, - FALSE, FALSE, FALSE); - - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !bfd_is_abs_section (h->root.u.def.section)) - h->root.u.def.section->flags |= SEC_KEEP; - } -} - -/* Do mark and sweep of unused sections. */ - -bfd_boolean -bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) -{ - bfd *sub; - - /* FIXME: Should we implement this? */ -#if 0 - const bfd_coff_backend_data *bed = coff_backend_info (abfd); - - if (!bed->can_gc_sections - || !is_coff_hash_table (info->hash)) - { - _bfd_error_handler(_("Warning: gc-sections option ignored")); - return TRUE; - } -#endif - - _bfd_coff_gc_keep (info); - - /* Grovel through relocs to find out who stays ... */ - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - asection *o; - - if (bfd_get_flavour (sub) != bfd_target_coff_flavour) - continue; - - for (o = sub->sections; o != NULL; o = o->next) - { - if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP - || CONST_STRNEQ (o->name, ".vectors") - || CONST_STRNEQ (o->name, ".ctors") - || CONST_STRNEQ (o->name, ".dtors")) - && !o->gc_mark) - { - if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook)) - return FALSE; - } - } - } - - /* Allow the backend to mark additional target specific sections. */ - _bfd_coff_gc_mark_extra_sections (info, _bfd_coff_gc_mark_hook); - - /* ... and mark SEC_EXCLUDE for those that go. */ - return coff_gc_sweep (abfd, info); -} diff --git a/sdcc/support/sdbinutils/bfd/cofflink.c b/sdcc/support/sdbinutils/bfd/cofflink.c deleted file mode 100644 index beff5cd3c..000000000 --- a/sdcc/support/sdbinutils/bfd/cofflink.c +++ /dev/null @@ -1,3154 +0,0 @@ -/* COFF specific linker code. - Copyright (C) 1994-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 the COFF backend linker code. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "coff/internal.h" -#include "libcoff.h" -#include "safe-ctype.h" - -static bfd_boolean coff_link_add_object_symbols (bfd *, struct bfd_link_info *); -static bfd_boolean coff_link_check_archive_element - (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *, - bfd_boolean *); -static bfd_boolean coff_link_add_symbols (bfd *, struct bfd_link_info *); - -/* Return TRUE if SYM is a weak, external symbol. */ -#define IS_WEAK_EXTERNAL(abfd, sym) \ - ((sym).n_sclass == C_WEAKEXT \ - || (obj_pe (abfd) && (sym).n_sclass == C_NT_WEAK)) - -/* Return TRUE if SYM is an external symbol. */ -#define IS_EXTERNAL(abfd, sym) \ - ((sym).n_sclass == C_EXT || IS_WEAK_EXTERNAL (abfd, sym)) - -/* Define macros so that the ISFCN, et. al., macros work correctly. - These macros are defined in include/coff/internal.h in terms of - N_TMASK, etc. These definitions require a user to define local - variables with the appropriate names, and with values from the - coff_data (abfd) structure. */ - -#define N_TMASK n_tmask -#define N_BTSHFT n_btshft -#define N_BTMASK n_btmask - -/* Create an entry in a COFF linker hash table. */ - -struct bfd_hash_entry * -_bfd_coff_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct coff_link_hash_entry *ret = (struct coff_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct coff_link_hash_entry *) NULL) - ret = ((struct coff_link_hash_entry *) - bfd_hash_allocate (table, sizeof (struct coff_link_hash_entry))); - if (ret == (struct coff_link_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct coff_link_hash_entry *) - _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != (struct coff_link_hash_entry *) NULL) - { - /* Set local fields. */ - ret->indx = -1; - ret->type = T_NULL; - ret->symbol_class = C_NULL; - ret->numaux = 0; - ret->auxbfd = NULL; - ret->aux = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Initialize a COFF linker hash table. */ - -bfd_boolean -_bfd_coff_link_hash_table_init (struct coff_link_hash_table *table, - bfd *abfd, - struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, - struct bfd_hash_table *, - const char *), - unsigned int entsize) -{ - memset (&table->stab_info, 0, sizeof (table->stab_info)); - return _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); -} - -/* Create a COFF linker hash table. */ - -struct bfd_link_hash_table * -_bfd_coff_link_hash_table_create (bfd *abfd) -{ - struct coff_link_hash_table *ret; - bfd_size_type amt = sizeof (struct coff_link_hash_table); - - ret = (struct coff_link_hash_table *) bfd_malloc (amt); - if (ret == NULL) - return NULL; - - if (! _bfd_coff_link_hash_table_init (ret, abfd, - _bfd_coff_link_hash_newfunc, - sizeof (struct coff_link_hash_entry))) - { - free (ret); - return (struct bfd_link_hash_table *) NULL; - } - return &ret->root; -} - -/* Create an entry in a COFF debug merge hash table. */ - -struct bfd_hash_entry * -_bfd_coff_debug_merge_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct coff_debug_merge_hash_entry *ret = - (struct coff_debug_merge_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct coff_debug_merge_hash_entry *) NULL) - ret = ((struct coff_debug_merge_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct coff_debug_merge_hash_entry))); - if (ret == (struct coff_debug_merge_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct coff_debug_merge_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - if (ret != (struct coff_debug_merge_hash_entry *) NULL) - { - /* Set local fields. */ - ret->types = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Given a COFF BFD, add symbols to the global hash table as - appropriate. */ - -bfd_boolean -_bfd_coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) -{ - switch (bfd_get_format (abfd)) - { - case bfd_object: - return coff_link_add_object_symbols (abfd, info); - case bfd_archive: - return _bfd_generic_link_add_archive_symbols - (abfd, info, coff_link_check_archive_element); - default: - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } -} - -/* Add symbols from a COFF object file. */ - -static bfd_boolean -coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) -{ - if (! _bfd_coff_get_external_symbols (abfd)) - return FALSE; - if (! coff_link_add_symbols (abfd, info)) - return FALSE; - - if (! info->keep_memory - && ! _bfd_coff_free_symbols (abfd)) - return FALSE; - - return TRUE; -} - -/* Check a single archive element to see if we need to include it in - the link. *PNEEDED is set according to whether this element is - needed in the link or not. This is called via - _bfd_generic_link_add_archive_symbols. */ - -static bfd_boolean -coff_link_check_archive_element (bfd *abfd, - struct bfd_link_info *info, - struct bfd_link_hash_entry *h, - const char *name, - bfd_boolean *pneeded) -{ - *pneeded = FALSE; - - /* We are only interested in symbols that are currently undefined. - If a symbol is currently known to be common, COFF linkers do not - bring in an object file which defines it. */ - if (h->type != bfd_link_hash_undefined) - return TRUE; - - /* PR 22369 - Skip non COFF objects in the archive. */ - if (! bfd_family_coff (abfd)) - return TRUE; - - /* Include this element? */ - if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd)) - return TRUE; - *pneeded = TRUE; - - return coff_link_add_object_symbols (abfd, info); -} - -/* Add all the symbols from an object file to the hash table. */ - -static bfd_boolean -coff_link_add_symbols (bfd *abfd, - struct bfd_link_info *info) -{ - unsigned int n_tmask = coff_data (abfd)->local_n_tmask; - unsigned int n_btshft = coff_data (abfd)->local_n_btshft; - unsigned int n_btmask = coff_data (abfd)->local_n_btmask; - bfd_boolean keep_syms; - bfd_boolean default_copy; - bfd_size_type symcount; - struct coff_link_hash_entry **sym_hash; - bfd_size_type symesz; - bfd_byte *esym; - bfd_byte *esym_end; - bfd_size_type amt; - - symcount = obj_raw_syment_count (abfd); - - if (symcount == 0) - return TRUE; /* Nothing to do. */ - - /* Keep the symbols during this function, in case the linker needs - to read the generic symbols in order to report an error message. */ - keep_syms = obj_coff_keep_syms (abfd); - obj_coff_keep_syms (abfd) = TRUE; - - if (info->keep_memory) - default_copy = FALSE; - else - default_copy = TRUE; - - /* We keep a list of the linker hash table entries that correspond - to particular symbols. */ - amt = symcount * sizeof (struct coff_link_hash_entry *); - sym_hash = (struct coff_link_hash_entry **) bfd_zalloc (abfd, amt); - if (sym_hash == NULL) - goto error_return; - obj_coff_sym_hashes (abfd) = sym_hash; - - symesz = bfd_coff_symesz (abfd); - BFD_ASSERT (symesz == bfd_coff_auxesz (abfd)); - esym = (bfd_byte *) obj_coff_external_syms (abfd); - esym_end = esym + symcount * symesz; - while (esym < esym_end) - { - struct internal_syment sym; - enum coff_symbol_classification classification; - bfd_boolean copy; - - bfd_coff_swap_sym_in (abfd, esym, &sym); - - classification = bfd_coff_classify_symbol (abfd, &sym); - if (classification != COFF_SYMBOL_LOCAL) - { - const char *name; - char buf[SYMNMLEN + 1]; - flagword flags; - asection *section; - bfd_vma value; - bfd_boolean addit; - - /* This symbol is externally visible. */ - - name = _bfd_coff_internal_syment_name (abfd, &sym, buf); - if (name == NULL) - goto error_return; - - /* We must copy the name into memory if we got it from the - syment itself, rather than the string table. */ - copy = default_copy; - if (sym._n._n_n._n_zeroes != 0 - || sym._n._n_n._n_offset == 0) - copy = TRUE; - - value = sym.n_value; - - switch (classification) - { - default: - abort (); - - case COFF_SYMBOL_GLOBAL: - flags = BSF_EXPORT | BSF_GLOBAL; - section = coff_section_from_bfd_index (abfd, sym.n_scnum); - if (! obj_pe (abfd)) - value -= section->vma; - break; - - case COFF_SYMBOL_UNDEFINED: - flags = 0; - section = bfd_und_section_ptr; - break; - - case COFF_SYMBOL_COMMON: - flags = BSF_GLOBAL; - section = bfd_com_section_ptr; - break; - - case COFF_SYMBOL_PE_SECTION: - flags = BSF_SECTION_SYM | BSF_GLOBAL; - section = coff_section_from_bfd_index (abfd, sym.n_scnum); - break; - } - - if (IS_WEAK_EXTERNAL (abfd, sym)) - flags = BSF_WEAK; - - addit = TRUE; - - /* In the PE format, section symbols actually refer to the - start of the output section. We handle them specially - here. */ - if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) - { - *sym_hash = coff_link_hash_lookup (coff_hash_table (info), - name, FALSE, copy, FALSE); - if (*sym_hash != NULL) - { - if (((*sym_hash)->coff_link_hash_flags - & COFF_LINK_HASH_PE_SECTION_SYMBOL) == 0 - && (*sym_hash)->root.type != bfd_link_hash_undefined - && (*sym_hash)->root.type != bfd_link_hash_undefweak) - _bfd_error_handler - (_("Warning: symbol `%s' is both section and non-section"), - name); - - addit = FALSE; - } - } - - /* The Microsoft Visual C compiler does string pooling by - hashing the constants to an internal symbol name, and - relying on the linker comdat support to discard - duplicate names. However, if one string is a literal and - one is a data initializer, one will end up in the .data - section and one will end up in the .rdata section. The - Microsoft linker will combine them into the .data - section, which seems to be wrong since it might cause the - literal to change. - - As long as there are no external references to the - symbols, which there shouldn't be, we can treat the .data - and .rdata instances as separate symbols. The comdat - code in the linker will do the appropriate merging. Here - we avoid getting a multiple definition error for one of - these special symbols. - - FIXME: I don't think this will work in the case where - there are two object files which use the constants as a - literal and two object files which use it as a data - initializer. One or the other of the second object files - is going to wind up with an inappropriate reference. */ - if (obj_pe (abfd) - && (classification == COFF_SYMBOL_GLOBAL - || classification == COFF_SYMBOL_PE_SECTION) - && coff_section_data (abfd, section) != NULL - && coff_section_data (abfd, section)->comdat != NULL - && CONST_STRNEQ (name, "??_") - && strcmp (name, coff_section_data (abfd, section)->comdat->name) == 0) - { - if (*sym_hash == NULL) - *sym_hash = coff_link_hash_lookup (coff_hash_table (info), - name, FALSE, copy, FALSE); - if (*sym_hash != NULL - && (*sym_hash)->root.type == bfd_link_hash_defined - && coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat != NULL - && strcmp (coff_section_data (abfd, (*sym_hash)->root.u.def.section)->comdat->name, - coff_section_data (abfd, section)->comdat->name) == 0) - addit = FALSE; - } - - if (addit) - { - if (! (bfd_coff_link_add_one_symbol - (info, abfd, name, flags, section, value, - (const char *) NULL, copy, FALSE, - (struct bfd_link_hash_entry **) sym_hash))) - goto error_return; - } - - if (obj_pe (abfd) && (flags & BSF_SECTION_SYM) != 0) - (*sym_hash)->coff_link_hash_flags |= - COFF_LINK_HASH_PE_SECTION_SYMBOL; - - /* Limit the alignment of a common symbol to the possible - alignment of a section. There is no point to permitting - a higher alignment for a common symbol: we can not - guarantee it, and it may cause us to allocate extra space - in the common section. */ - if (section == bfd_com_section_ptr - && (*sym_hash)->root.type == bfd_link_hash_common - && ((*sym_hash)->root.u.c.p->alignment_power - > bfd_coff_default_section_alignment_power (abfd))) - (*sym_hash)->root.u.c.p->alignment_power - = bfd_coff_default_section_alignment_power (abfd); - - if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)) - { - /* If we don't have any symbol information currently in - the hash table, or if we are looking at a symbol - definition, then update the symbol class and type in - the hash table. */ - if (((*sym_hash)->symbol_class == C_NULL - && (*sym_hash)->type == T_NULL) - || sym.n_scnum != 0 - || (sym.n_value != 0 - && (*sym_hash)->root.type != bfd_link_hash_defined - && (*sym_hash)->root.type != bfd_link_hash_defweak)) - { - (*sym_hash)->symbol_class = sym.n_sclass; - if (sym.n_type != T_NULL) - { - /* We want to warn if the type changed, but not - if it changed from an unspecified type. - Testing the whole type byte may work, but the - change from (e.g.) a function of unspecified - type to function of known type also wants to - skip the warning. */ - if ((*sym_hash)->type != T_NULL - && (*sym_hash)->type != sym.n_type - && !(DTYPE ((*sym_hash)->type) == DTYPE (sym.n_type) - && (BTYPE ((*sym_hash)->type) == T_NULL - || BTYPE (sym.n_type) == T_NULL))) - _bfd_error_handler - /* xgettext: c-format */ - (_("Warning: type of symbol `%s' changed" - " from %d to %d in %B"), - name, (*sym_hash)->type, sym.n_type, abfd); - - /* We don't want to change from a meaningful - base type to a null one, but if we know - nothing, take what little we might now know. */ - if (BTYPE (sym.n_type) != T_NULL - || (*sym_hash)->type == T_NULL) - (*sym_hash)->type = sym.n_type; - } - (*sym_hash)->auxbfd = abfd; - if (sym.n_numaux != 0) - { - union internal_auxent *alloc; - unsigned int i; - bfd_byte *eaux; - union internal_auxent *iaux; - - (*sym_hash)->numaux = sym.n_numaux; - alloc = ((union internal_auxent *) - bfd_hash_allocate (&info->hash->table, - (sym.n_numaux - * sizeof (*alloc)))); - if (alloc == NULL) - goto error_return; - for (i = 0, eaux = esym + symesz, iaux = alloc; - i < sym.n_numaux; - i++, eaux += symesz, iaux++) - bfd_coff_swap_aux_in (abfd, eaux, sym.n_type, - sym.n_sclass, (int) i, - sym.n_numaux, iaux); - (*sym_hash)->aux = alloc; - } - } - } - - if (classification == COFF_SYMBOL_PE_SECTION - && (*sym_hash)->numaux != 0) - { - /* Some PE sections (such as .bss) have a zero size in - the section header, but a non-zero size in the AUX - record. Correct that here. - - FIXME: This is not at all the right place to do this. - For example, it won't help objdump. This needs to be - done when we swap in the section header. */ - BFD_ASSERT ((*sym_hash)->numaux == 1); - if (section->size == 0) - section->size = (*sym_hash)->aux[0].x_scn.x_scnlen; - - /* FIXME: We could test whether the section sizes - matches the size in the aux entry, but apparently - that sometimes fails unexpectedly. */ - } - } - - esym += (sym.n_numaux + 1) * symesz; - sym_hash += sym.n_numaux + 1; - } - - /* If this is a non-traditional, non-relocatable link, try to - optimize the handling of any .stab/.stabstr sections. */ - if (! bfd_link_relocatable (info) - && ! info->traditional_format - && bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd) - && (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 (CONST_STRNEQ (stab->name, ".stab") - && (!stab->name[5] - || (stab->name[5] == '.' && ISDIGIT (stab->name[6])))) - { - struct coff_link_hash_table *table; - struct coff_section_tdata *secdata - = coff_section_data (abfd, stab); - - if (secdata == NULL) - { - amt = sizeof (struct coff_section_tdata); - stab->used_by_bfd = bfd_zalloc (abfd, amt); - if (stab->used_by_bfd == NULL) - goto error_return; - secdata = coff_section_data (abfd, stab); - } - - table = coff_hash_table (info); - - if (! _bfd_link_section_stabs (abfd, &table->stab_info, - stab, stabstr, - &secdata->stab_info, - &string_offset)) - goto error_return; - } - } - } - - obj_coff_keep_syms (abfd) = keep_syms; - - return TRUE; - - error_return: - obj_coff_keep_syms (abfd) = keep_syms; - return FALSE; -} - -/* Do the final link step. */ - -bfd_boolean -_bfd_coff_final_link (bfd *abfd, - struct bfd_link_info *info) -{ - bfd_size_type symesz; - struct coff_final_link_info flaginfo; - bfd_boolean debug_merge_allocated; - bfd_boolean long_section_names; - asection *o; - struct bfd_link_order *p; - bfd_size_type max_sym_count; - bfd_size_type max_lineno_count; - bfd_size_type max_reloc_count; - bfd_size_type max_output_reloc_count; - bfd_size_type max_contents_size; - file_ptr rel_filepos; - unsigned int relsz; - file_ptr line_filepos; - unsigned int linesz; - bfd *sub; - bfd_byte *external_relocs = NULL; - char strbuf[STRING_SIZE_SIZE]; - bfd_size_type amt; - - symesz = bfd_coff_symesz (abfd); - - flaginfo.info = info; - flaginfo.output_bfd = abfd; - flaginfo.strtab = NULL; - flaginfo.section_info = NULL; - flaginfo.last_file_index = -1; - flaginfo.last_bf_index = -1; - flaginfo.internal_syms = NULL; - flaginfo.sec_ptrs = NULL; - flaginfo.sym_indices = NULL; - flaginfo.outsyms = NULL; - flaginfo.linenos = NULL; - flaginfo.contents = NULL; - flaginfo.external_relocs = NULL; - flaginfo.internal_relocs = NULL; - flaginfo.global_to_static = FALSE; - debug_merge_allocated = FALSE; - - coff_data (abfd)->link_info = info; - - flaginfo.strtab = _bfd_stringtab_init (); - if (flaginfo.strtab == NULL) - goto error_return; - - if (! coff_debug_merge_hash_table_init (&flaginfo.debug_merge)) - goto error_return; - debug_merge_allocated = TRUE; - - /* Compute the file positions for all the sections. */ - if (! abfd->output_has_begun) - { - if (! bfd_coff_compute_section_file_positions (abfd)) - goto error_return; - } - - /* Count the line numbers and relocation entries required for the - output file. Set the file positions for the relocs. */ - rel_filepos = obj_relocbase (abfd); - relsz = bfd_coff_relsz (abfd); - max_contents_size = 0; - max_lineno_count = 0; - max_reloc_count = 0; - - long_section_names = FALSE; - for (o = abfd->sections; o != NULL; o = o->next) - { - o->reloc_count = 0; - o->lineno_count = 0; - for (p = o->map_head.link_order; p != NULL; p = p->next) - { - if (p->type == bfd_indirect_link_order) - { - asection *sec; - - sec = p->u.indirect.section; - - /* 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 (info->strip == strip_none - || info->strip == strip_some) - o->lineno_count += sec->lineno_count; - - if (bfd_link_relocatable (info)) - o->reloc_count += sec->reloc_count; - - if (sec->rawsize > max_contents_size) - max_contents_size = sec->rawsize; - if (sec->size > max_contents_size) - max_contents_size = sec->size; - if (sec->lineno_count > max_lineno_count) - max_lineno_count = sec->lineno_count; - if (sec->reloc_count > max_reloc_count) - max_reloc_count = sec->reloc_count; - } - else if (bfd_link_relocatable (info) - && (p->type == bfd_section_reloc_link_order - || p->type == bfd_symbol_reloc_link_order)) - ++o->reloc_count; - } - if (o->reloc_count == 0) - o->rel_filepos = 0; - else - { - o->flags |= SEC_RELOC; - o->rel_filepos = rel_filepos; - rel_filepos += o->reloc_count * relsz; - /* In PE COFF, if there are at least 0xffff relocations an - extra relocation will be written out to encode the count. */ - if (obj_pe (abfd) && o->reloc_count >= 0xffff) - rel_filepos += relsz; - } - - if (bfd_coff_long_section_names (abfd) - && strlen (o->name) > SCNNMLEN) - { - /* This section has a long name which must go in the string - table. This must correspond to the code in - coff_write_object_contents which puts the string index - into the s_name field of the section header. That is why - we pass hash as FALSE. */ - if (_bfd_stringtab_add (flaginfo.strtab, o->name, FALSE, FALSE) - == (bfd_size_type) -1) - goto error_return; - long_section_names = TRUE; - } - } - - /* If doing a relocatable link, allocate space for the pointers we - need to keep. */ - if (bfd_link_relocatable (info)) - { - unsigned int i; - - /* We use section_count + 1, rather than section_count, because - the target_index fields are 1 based. */ - amt = abfd->section_count + 1; - amt *= sizeof (struct coff_link_section_info); - flaginfo.section_info = (struct coff_link_section_info *) bfd_malloc (amt); - if (flaginfo.section_info == NULL) - goto error_return; - for (i = 0; i <= abfd->section_count; i++) - { - flaginfo.section_info[i].relocs = NULL; - flaginfo.section_info[i].rel_hashes = NULL; - } - } - - /* We now know the size of the relocs, so we can determine the file - positions of the line numbers. */ - line_filepos = rel_filepos; - linesz = bfd_coff_linesz (abfd); - max_output_reloc_count = 0; - for (o = abfd->sections; o != NULL; o = o->next) - { - if (o->lineno_count == 0) - o->line_filepos = 0; - else - { - o->line_filepos = line_filepos; - line_filepos += o->lineno_count * linesz; - } - - if (o->reloc_count != 0) - { - /* We don't know the indices of global symbols until we have - written out all the local symbols. For each section in - the output file, we keep an array of pointers to hash - table entries. Each entry in the array corresponds to a - reloc. When we find a reloc against a global symbol, we - set the corresponding entry in this array so that we can - fix up the symbol index after we have written out all the - local symbols. - - Because of this problem, we also keep the relocs in - memory until the end of the link. This wastes memory, - but only when doing a relocatable link, which is not the - common case. */ - BFD_ASSERT (bfd_link_relocatable (info)); - amt = o->reloc_count; - amt *= sizeof (struct internal_reloc); - flaginfo.section_info[o->target_index].relocs = - (struct internal_reloc *) bfd_malloc (amt); - amt = o->reloc_count; - amt *= sizeof (struct coff_link_hash_entry *); - flaginfo.section_info[o->target_index].rel_hashes = - (struct coff_link_hash_entry **) bfd_malloc (amt); - if (flaginfo.section_info[o->target_index].relocs == NULL - || flaginfo.section_info[o->target_index].rel_hashes == NULL) - goto error_return; - - if (o->reloc_count > max_output_reloc_count) - max_output_reloc_count = o->reloc_count; - } - - /* Reset the reloc and lineno counts, so that we can use them to - count the number of entries we have output so far. */ - o->reloc_count = 0; - o->lineno_count = 0; - } - - obj_sym_filepos (abfd) = line_filepos; - - /* Figure out the largest number of symbols in an input BFD. Take - the opportunity to clear the output_has_begun fields of all the - input BFD's. */ - max_sym_count = 0; - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - size_t sz; - - sub->output_has_begun = FALSE; - sz = bfd_family_coff (sub) ? obj_raw_syment_count (sub) : 2; - if (sz > max_sym_count) - max_sym_count = sz; - } - - /* Allocate some buffers used while linking. */ - amt = max_sym_count * sizeof (struct internal_syment); - flaginfo.internal_syms = (struct internal_syment *) bfd_malloc (amt); - amt = max_sym_count * sizeof (asection *); - flaginfo.sec_ptrs = (asection **) bfd_malloc (amt); - amt = max_sym_count * sizeof (long); - flaginfo.sym_indices = (long int *) bfd_malloc (amt); - flaginfo.outsyms = (bfd_byte *) bfd_malloc ((max_sym_count + 1) * symesz); - amt = max_lineno_count * bfd_coff_linesz (abfd); - flaginfo.linenos = (bfd_byte *) bfd_malloc (amt); - flaginfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); - amt = max_reloc_count * relsz; - flaginfo.external_relocs = (bfd_byte *) bfd_malloc (amt); - if (! bfd_link_relocatable (info)) - { - amt = max_reloc_count * sizeof (struct internal_reloc); - flaginfo.internal_relocs = (struct internal_reloc *) bfd_malloc (amt); - } - if ((flaginfo.internal_syms == NULL && max_sym_count > 0) - || (flaginfo.sec_ptrs == NULL && max_sym_count > 0) - || (flaginfo.sym_indices == NULL && max_sym_count > 0) - || flaginfo.outsyms == NULL - || (flaginfo.linenos == NULL && max_lineno_count > 0) - || (flaginfo.contents == NULL && max_contents_size > 0) - || (flaginfo.external_relocs == NULL && max_reloc_count > 0) - || (! bfd_link_relocatable (info) - && flaginfo.internal_relocs == NULL - && max_reloc_count > 0)) - goto error_return; - - /* We now know the position of everything in the file, except that - we don't know the size of the symbol table and therefore we don't - know where the string table starts. We just build the string - table in memory as we go along. We process all the relocations - for a single input file at once. */ - obj_raw_syment_count (abfd) = 0; - - if (coff_backend_info (abfd)->_bfd_coff_start_final_link) - { - if (! bfd_coff_start_final_link (abfd, info)) - goto error_return; - } - - 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_family_coff (p->u.indirect.section->owner)) - { - sub = p->u.indirect.section->owner; - if (! bfd_coff_link_output_has_begun (sub, & flaginfo)) - { - if (! _bfd_coff_link_input_bfd (&flaginfo, 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 (! _bfd_coff_reloc_link_order (abfd, &flaginfo, o, p)) - goto error_return; - } - else - { - if (! _bfd_default_link_order (abfd, info, o, p)) - goto error_return; - } - } - } - - if (flaginfo.info->strip != strip_all && flaginfo.info->discard != discard_all) - { - /* Add local symbols from foreign inputs. */ - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - unsigned int i; - - if (bfd_family_coff (sub) || ! bfd_get_outsymbols (sub)) - continue; - for (i = 0; i < bfd_get_symcount (sub); ++i) - { - asymbol *sym = bfd_get_outsymbols (sub) [i]; - file_ptr pos; - struct internal_syment isym; - union internal_auxent iaux; - bfd_size_type string_size = 0, indx; - bfd_vma written = 0; - bfd_boolean rewrite = FALSE, hash; - - if (! (sym->flags & BSF_LOCAL) - || (sym->flags & (BSF_SECTION_SYM | BSF_DEBUGGING_RELOC - | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC - | BSF_SYNTHETIC)) - || ((sym->flags & BSF_DEBUGGING) - && ! (sym->flags & BSF_FILE))) - continue; - - /* See if we are discarding symbols with this name. */ - if ((flaginfo.info->strip == strip_some - && (bfd_hash_lookup (flaginfo.info->keep_hash, - bfd_asymbol_name(sym), FALSE, FALSE) - == NULL)) - || (((flaginfo.info->discard == discard_sec_merge - && (bfd_get_section (sym)->flags & SEC_MERGE) - && ! bfd_link_relocatable (flaginfo.info)) - || flaginfo.info->discard == discard_l) - && bfd_is_local_label_name (sub, bfd_asymbol_name(sym)))) - continue; - - pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) - * symesz; - if (bfd_seek (abfd, pos, SEEK_SET) != 0) - goto error_return; - if (! coff_write_alien_symbol(abfd, sym, &isym, &iaux, &written, - &string_size, NULL, NULL)) - goto error_return; - - hash = !flaginfo.info->traditional_format; - - if (string_size >= 6 && isym.n_sclass == C_FILE - && ! isym._n._n_n._n_zeroes && isym.n_numaux) - { - indx = _bfd_stringtab_add (flaginfo.strtab, ".file", hash, - FALSE); - if (indx == (bfd_size_type) -1) - goto error_return; - isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; - bfd_coff_swap_sym_out (abfd, &isym, flaginfo.outsyms); - if (bfd_seek (abfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo.outsyms, symesz, - abfd) != symesz) - goto error_return; - string_size -= 6; - } - - if (string_size) - { - indx = _bfd_stringtab_add (flaginfo.strtab, - bfd_asymbol_name (sym), hash, - FALSE); - if (indx == (bfd_size_type) -1) - goto error_return; - if (isym.n_sclass != C_FILE) - { - isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; - bfd_coff_swap_sym_out (abfd, &isym, flaginfo.outsyms); - rewrite = TRUE; - } - else - { - BFD_ASSERT (isym.n_numaux == 1); - iaux.x_file.x_n.x_offset = STRING_SIZE_SIZE + indx; - bfd_coff_swap_aux_out (abfd, &iaux, isym.n_type, C_FILE, - 0, 1, flaginfo.outsyms + symesz); - if (bfd_seek (abfd, pos + symesz, SEEK_SET) != 0 - || bfd_bwrite (flaginfo.outsyms + symesz, symesz, - abfd) != symesz) - goto error_return; - } - } - - if (isym.n_sclass == C_FILE) - { - if (flaginfo.last_file_index != -1) - { - flaginfo.last_file.n_value = obj_raw_syment_count (abfd); - bfd_coff_swap_sym_out (abfd, &flaginfo.last_file, - flaginfo.outsyms); - pos = obj_sym_filepos (abfd) + flaginfo.last_file_index - * symesz; - rewrite = TRUE; - } - flaginfo.last_file_index = obj_raw_syment_count (abfd); - flaginfo.last_file = isym; - } - - if (rewrite - && (bfd_seek (abfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz)) - goto error_return; - - obj_raw_syment_count (abfd) += written; - } - } - } - - if (! bfd_coff_final_link_postscript (abfd, & flaginfo)) - goto error_return; - - /* Free up the buffers used by _bfd_coff_link_input_bfd. */ - - coff_debug_merge_hash_table_free (&flaginfo.debug_merge); - debug_merge_allocated = FALSE; - - if (flaginfo.internal_syms != NULL) - { - free (flaginfo.internal_syms); - flaginfo.internal_syms = NULL; - } - if (flaginfo.sec_ptrs != NULL) - { - free (flaginfo.sec_ptrs); - flaginfo.sec_ptrs = NULL; - } - if (flaginfo.sym_indices != NULL) - { - free (flaginfo.sym_indices); - flaginfo.sym_indices = NULL; - } - if (flaginfo.linenos != NULL) - { - free (flaginfo.linenos); - flaginfo.linenos = NULL; - } - if (flaginfo.contents != NULL) - { - free (flaginfo.contents); - flaginfo.contents = NULL; - } - if (flaginfo.external_relocs != NULL) - { - free (flaginfo.external_relocs); - flaginfo.external_relocs = NULL; - } - if (flaginfo.internal_relocs != NULL) - { - free (flaginfo.internal_relocs); - flaginfo.internal_relocs = NULL; - } - - /* The value of the last C_FILE symbol is supposed to be the symbol - index of the first external symbol. Write it out again if - necessary. */ - if (flaginfo.last_file_index != -1 - && (unsigned int) flaginfo.last_file.n_value != obj_raw_syment_count (abfd)) - { - file_ptr pos; - - flaginfo.last_file.n_value = obj_raw_syment_count (abfd); - bfd_coff_swap_sym_out (abfd, &flaginfo.last_file, - flaginfo.outsyms); - - pos = obj_sym_filepos (abfd) + flaginfo.last_file_index * symesz; - if (bfd_seek (abfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo.outsyms, symesz, abfd) != symesz) - return FALSE; - } - - /* If doing task linking (ld --task-link) then make a pass through the - global symbols, writing out any that are defined, and making them - static. */ - if (info->task_link) - { - flaginfo.failed = FALSE; - coff_link_hash_traverse (coff_hash_table (info), - _bfd_coff_write_task_globals, &flaginfo); - if (flaginfo.failed) - goto error_return; - } - - /* Write out the global symbols. */ - flaginfo.failed = FALSE; - bfd_hash_traverse (&info->hash->table, _bfd_coff_write_global_sym, &flaginfo); - if (flaginfo.failed) - goto error_return; - - /* The outsyms buffer is used by _bfd_coff_write_global_sym. */ - if (flaginfo.outsyms != NULL) - { - free (flaginfo.outsyms); - flaginfo.outsyms = NULL; - } - - if (bfd_link_relocatable (info) && max_output_reloc_count > 0) - { - /* Now that we have written out all the global symbols, we know - the symbol indices to use for relocs against them, and we can - finally write out the relocs. */ - amt = max_output_reloc_count * relsz; - external_relocs = (bfd_byte *) bfd_malloc (amt); - if (external_relocs == NULL) - goto error_return; - - for (o = abfd->sections; o != NULL; o = o->next) - { - struct internal_reloc *irel; - struct internal_reloc *irelend; - struct coff_link_hash_entry **rel_hash; - bfd_byte *erel; - - if (o->reloc_count == 0) - continue; - - irel = flaginfo.section_info[o->target_index].relocs; - irelend = irel + o->reloc_count; - rel_hash = flaginfo.section_info[o->target_index].rel_hashes; - erel = external_relocs; - for (; irel < irelend; irel++, rel_hash++, erel += relsz) - { - if (*rel_hash != NULL) - { - BFD_ASSERT ((*rel_hash)->indx >= 0); - irel->r_symndx = (*rel_hash)->indx; - } - bfd_coff_swap_reloc_out (abfd, irel, erel); - } - - if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0) - goto error_return; - if (obj_pe (abfd) && o->reloc_count >= 0xffff) - { - /* In PE COFF, write the count of relocs as the first - reloc. The header overflow bit will be set - elsewhere. */ - struct internal_reloc incount; - bfd_byte *excount = (bfd_byte *)bfd_malloc (relsz); - - memset (&incount, 0, sizeof (incount)); - incount.r_vaddr = o->reloc_count + 1; - bfd_coff_swap_reloc_out (abfd, &incount, excount); - if (bfd_bwrite (excount, relsz, abfd) != relsz) - /* We'll leak, but it's an error anyway. */ - goto error_return; - free (excount); - } - if (bfd_bwrite (external_relocs, - (bfd_size_type) relsz * o->reloc_count, abfd) - != (bfd_size_type) relsz * o->reloc_count) - goto error_return; - } - - free (external_relocs); - external_relocs = NULL; - } - - /* Free up the section information. */ - if (flaginfo.section_info != NULL) - { - unsigned int i; - - for (i = 0; i < abfd->section_count; i++) - { - if (flaginfo.section_info[i].relocs != NULL) - free (flaginfo.section_info[i].relocs); - if (flaginfo.section_info[i].rel_hashes != NULL) - free (flaginfo.section_info[i].rel_hashes); - } - free (flaginfo.section_info); - flaginfo.section_info = NULL; - } - - /* If we have optimized stabs strings, output them. */ - if (coff_hash_table (info)->stab_info.stabstr != NULL) - { - if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info)) - return FALSE; - } - - /* Write out the string table. */ - if (obj_raw_syment_count (abfd) != 0 || long_section_names) - { - file_ptr pos; - - pos = obj_sym_filepos (abfd) + obj_raw_syment_count (abfd) * symesz; - if (bfd_seek (abfd, pos, SEEK_SET) != 0) - return FALSE; - -#if STRING_SIZE_SIZE == 4 - H_PUT_32 (abfd, - _bfd_stringtab_size (flaginfo.strtab) + STRING_SIZE_SIZE, - strbuf); -#else - #error Change H_PUT_32 above -#endif - - if (bfd_bwrite (strbuf, (bfd_size_type) STRING_SIZE_SIZE, abfd) - != STRING_SIZE_SIZE) - return FALSE; - - if (! _bfd_stringtab_emit (abfd, flaginfo.strtab)) - return FALSE; - - obj_coff_strings_written (abfd) = TRUE; - } - - _bfd_stringtab_free (flaginfo.strtab); - - /* Setting bfd_get_symcount to 0 will cause write_object_contents to - not try to write out the symbols. */ - bfd_get_symcount (abfd) = 0; - - return TRUE; - - error_return: - if (debug_merge_allocated) - coff_debug_merge_hash_table_free (&flaginfo.debug_merge); - if (flaginfo.strtab != NULL) - _bfd_stringtab_free (flaginfo.strtab); - if (flaginfo.section_info != NULL) - { - unsigned int i; - - for (i = 0; i < abfd->section_count; i++) - { - if (flaginfo.section_info[i].relocs != NULL) - free (flaginfo.section_info[i].relocs); - if (flaginfo.section_info[i].rel_hashes != NULL) - free (flaginfo.section_info[i].rel_hashes); - } - free (flaginfo.section_info); - } - if (flaginfo.internal_syms != NULL) - free (flaginfo.internal_syms); - if (flaginfo.sec_ptrs != NULL) - free (flaginfo.sec_ptrs); - if (flaginfo.sym_indices != NULL) - free (flaginfo.sym_indices); - if (flaginfo.outsyms != NULL) - free (flaginfo.outsyms); - if (flaginfo.linenos != NULL) - free (flaginfo.linenos); - if (flaginfo.contents != NULL) - free (flaginfo.contents); - if (flaginfo.external_relocs != NULL) - free (flaginfo.external_relocs); - if (flaginfo.internal_relocs != NULL) - free (flaginfo.internal_relocs); - if (external_relocs != NULL) - free (external_relocs); - return FALSE; -} - -/* Parse out a -heap , line. */ - -static char * -dores_com (char *ptr, bfd *output_bfd, int heap) -{ - if (coff_data(output_bfd)->pe) - { - int val = strtoul (ptr, &ptr, 0); - - if (heap) - pe_data(output_bfd)->pe_opthdr.SizeOfHeapReserve = val; - else - pe_data(output_bfd)->pe_opthdr.SizeOfStackReserve = val; - - if (ptr[0] == ',') - { - val = strtoul (ptr+1, &ptr, 0); - if (heap) - pe_data(output_bfd)->pe_opthdr.SizeOfHeapCommit = val; - else - pe_data(output_bfd)->pe_opthdr.SizeOfStackCommit = val; - } - } - return ptr; -} - -static char * -get_name (char *ptr, char **dst) -{ - while (*ptr == ' ') - ptr++; - *dst = ptr; - while (*ptr && *ptr != ' ') - ptr++; - *ptr = 0; - return ptr+1; -} - -/* Process any magic embedded commands in a section called .drectve. */ - -static int -process_embedded_commands (bfd *output_bfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *abfd) -{ - asection *sec = bfd_get_section_by_name (abfd, ".drectve"); - char *s; - char *e; - bfd_byte *copy; - - if (!sec) - return 1; - - if (!bfd_malloc_and_get_section (abfd, sec, ©)) - { - if (copy != NULL) - free (copy); - return 0; - } - e = (char *) copy + sec->size; - - for (s = (char *) copy; s < e ; ) - { - if (s[0] != '-') - { - s++; - continue; - } - if (CONST_STRNEQ (s, "-attr")) - { - char *name; - char *attribs; - asection *asec; - int loop = 1; - int had_write = 0; - int had_exec= 0; - - s += 5; - s = get_name (s, &name); - s = get_name (s, &attribs); - - while (loop) - { - switch (*attribs++) - { - case 'W': - had_write = 1; - break; - case 'R': - break; - case 'S': - break; - case 'X': - had_exec = 1; - break; - default: - loop = 0; - } - } - asec = bfd_get_section_by_name (abfd, name); - if (asec) - { - if (had_exec) - asec->flags |= SEC_CODE; - if (!had_write) - asec->flags |= SEC_READONLY; - } - } - else if (CONST_STRNEQ (s, "-heap")) - s = dores_com (s + 5, output_bfd, 1); - - else if (CONST_STRNEQ (s, "-stack")) - s = dores_com (s + 6, output_bfd, 0); - - /* GNU extension for aligned commons. */ - else if (CONST_STRNEQ (s, "-aligncomm:")) - { - /* Common symbols must be aligned on reading, as it - is too late to do anything here, after they have - already been allocated, so just skip the directive. */ - s += 11; - } - - else - s++; - } - free (copy); - return 1; -} - -/* Place a marker against all symbols which are used by relocations. - This marker can be picked up by the 'do we skip this symbol ?' - loop in _bfd_coff_link_input_bfd() and used to prevent skipping - that symbol. */ - -static void -mark_relocs (struct coff_final_link_info *flaginfo, bfd *input_bfd) -{ - asection * a; - - if ((bfd_get_file_flags (input_bfd) & HAS_SYMS) == 0) - return; - - for (a = input_bfd->sections; a != (asection *) NULL; a = a->next) - { - struct internal_reloc * internal_relocs; - struct internal_reloc * irel; - struct internal_reloc * irelend; - - if ((a->flags & SEC_RELOC) == 0 || a->reloc_count < 1 - || a->linker_mark == 0) - continue; - /* Don't mark relocs in excluded sections. */ - if (a->output_section == bfd_abs_section_ptr) - continue; - - /* Read in the relocs. */ - internal_relocs = _bfd_coff_read_internal_relocs - (input_bfd, a, FALSE, - flaginfo->external_relocs, - bfd_link_relocatable (flaginfo->info), - (bfd_link_relocatable (flaginfo->info) - ? (flaginfo->section_info[ a->output_section->target_index ].relocs + a->output_section->reloc_count) - : flaginfo->internal_relocs) - ); - - if (internal_relocs == NULL) - continue; - - irel = internal_relocs; - irelend = irel + a->reloc_count; - - /* Place a mark in the sym_indices array (whose entries have - been initialised to 0) for all of the symbols that are used - in the relocation table. This will then be picked up in the - skip/don't-skip pass. */ - for (; irel < irelend; irel++) - if ((unsigned long) irel->r_symndx < obj_raw_syment_count (input_bfd)) - flaginfo->sym_indices[irel->r_symndx] = -1; - } -} - -/* Link an input file into the linker output file. This function - handles all the sections and relocations of the input file at once. */ - -bfd_boolean -_bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd) -{ - unsigned int n_tmask = coff_data (input_bfd)->local_n_tmask; - unsigned int n_btshft = coff_data (input_bfd)->local_n_btshft; - bfd_boolean (*adjust_symndx) - (bfd *, struct bfd_link_info *, bfd *, asection *, - struct internal_reloc *, bfd_boolean *); - bfd *output_bfd; - const char *strings; - bfd_size_type syment_base; - bfd_boolean copy, hash; - bfd_size_type isymesz; - bfd_size_type osymesz; - bfd_size_type linesz; - bfd_byte *esym; - bfd_byte *esym_end; - struct internal_syment *isymp; - asection **secpp; - long *indexp; - unsigned long output_index; - bfd_byte *outsym; - struct coff_link_hash_entry **sym_hash; - asection *o; - - /* Move all the symbols to the output file. */ - - output_bfd = flaginfo->output_bfd; - strings = NULL; - syment_base = obj_raw_syment_count (output_bfd); - isymesz = bfd_coff_symesz (input_bfd); - osymesz = bfd_coff_symesz (output_bfd); - linesz = bfd_coff_linesz (input_bfd); - BFD_ASSERT (linesz == bfd_coff_linesz (output_bfd)); - - copy = FALSE; - if (! flaginfo->info->keep_memory) - copy = TRUE; - hash = TRUE; - if (flaginfo->info->traditional_format) - hash = FALSE; - - if (! _bfd_coff_get_external_symbols (input_bfd)) - return FALSE; - - esym = (bfd_byte *) obj_coff_external_syms (input_bfd); - esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; - isymp = flaginfo->internal_syms; - secpp = flaginfo->sec_ptrs; - indexp = flaginfo->sym_indices; - output_index = syment_base; - outsym = flaginfo->outsyms; - - if (coff_data (output_bfd)->pe - && ! process_embedded_commands (output_bfd, flaginfo->info, input_bfd)) - return FALSE; - - /* If we are going to perform relocations and also strip/discard some - symbols then we must make sure that we do not strip/discard those - symbols that are going to be involved in the relocations. */ - if (( flaginfo->info->strip != strip_none - || flaginfo->info->discard != discard_none) - && bfd_link_relocatable (flaginfo->info)) - { - /* Mark the symbol array as 'not-used'. */ - memset (indexp, 0, obj_raw_syment_count (input_bfd) * sizeof * indexp); - - mark_relocs (flaginfo, input_bfd); - } - - while (esym < esym_end) - { - struct internal_syment isym; - enum coff_symbol_classification classification; - bfd_boolean skip; - bfd_boolean global; - bfd_boolean dont_skip_symbol; - int add; - - bfd_coff_swap_sym_in (input_bfd, esym, isymp); - - /* Make a copy of *isymp so that the relocate_section function - always sees the original values. This is more reliable than - always recomputing the symbol value even if we are stripping - the symbol. */ - isym = *isymp; - - classification = bfd_coff_classify_symbol (input_bfd, &isym); - switch (classification) - { - default: - abort (); - case COFF_SYMBOL_GLOBAL: - case COFF_SYMBOL_PE_SECTION: - case COFF_SYMBOL_LOCAL: - *secpp = coff_section_from_bfd_index (input_bfd, isym.n_scnum); - break; - case COFF_SYMBOL_COMMON: - *secpp = bfd_com_section_ptr; - break; - case COFF_SYMBOL_UNDEFINED: - *secpp = bfd_und_section_ptr; - break; - } - - /* Extract the flag indicating if this symbol is used by a - relocation. */ - if ((flaginfo->info->strip != strip_none - || flaginfo->info->discard != discard_none) - && bfd_link_relocatable (flaginfo->info)) - dont_skip_symbol = *indexp; - else - dont_skip_symbol = FALSE; - - *indexp = -1; - - skip = FALSE; - global = FALSE; - add = 1 + isym.n_numaux; - - /* If we are stripping all symbols, we want to skip this one. */ - if (flaginfo->info->strip == strip_all && ! dont_skip_symbol) - skip = TRUE; - - if (! skip) - { - switch (classification) - { - default: - abort (); - case COFF_SYMBOL_GLOBAL: - case COFF_SYMBOL_COMMON: - case COFF_SYMBOL_PE_SECTION: - /* This is a global symbol. Global symbols come at the - end of the symbol table, so skip them for now. - Locally defined function symbols, however, are an - exception, and are not moved to the end. */ - global = TRUE; - if (! ISFCN (isym.n_type)) - skip = TRUE; - break; - - case COFF_SYMBOL_UNDEFINED: - /* Undefined symbols are left for the end. */ - global = TRUE; - skip = TRUE; - break; - - case COFF_SYMBOL_LOCAL: - /* This is a local symbol. Skip it if we are discarding - local symbols. */ - if (flaginfo->info->discard == discard_all && ! dont_skip_symbol) - skip = TRUE; - break; - } - } - -#ifndef COFF_WITH_PE - /* Skip section symbols for sections which are not going to be - emitted. */ - if (!skip - && !dont_skip_symbol - && isym.n_sclass == C_STAT - && isym.n_type == T_NULL - && isym.n_numaux > 0 - && ((*secpp)->output_section == bfd_abs_section_ptr - || bfd_section_removed_from_list (output_bfd, - (*secpp)->output_section))) - skip = TRUE; -#endif - - /* If we stripping debugging symbols, and this is a debugging - symbol, then skip it. FIXME: gas sets the section to N_ABS - for some types of debugging symbols; I don't know if this is - a bug or not. In any case, we handle it here. */ - if (! skip - && flaginfo->info->strip == strip_debugger - && ! dont_skip_symbol - && (isym.n_scnum == N_DEBUG - || (isym.n_scnum == N_ABS - && (isym.n_sclass == C_AUTO - || isym.n_sclass == C_REG - || isym.n_sclass == C_MOS - || isym.n_sclass == C_MOE - || isym.n_sclass == C_MOU - || isym.n_sclass == C_ARG - || isym.n_sclass == C_REGPARM - || isym.n_sclass == C_FIELD - || isym.n_sclass == C_EOS)))) - skip = TRUE; - - /* If some symbols are stripped based on the name, work out the - name and decide whether to skip this symbol. */ - if (! skip - && (flaginfo->info->strip == strip_some - || flaginfo->info->discard == discard_l)) - { - const char *name; - char buf[SYMNMLEN + 1]; - - name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); - if (name == NULL) - return FALSE; - - if (! dont_skip_symbol - && ((flaginfo->info->strip == strip_some - && (bfd_hash_lookup (flaginfo->info->keep_hash, name, FALSE, - FALSE) == NULL)) - || (! global - && flaginfo->info->discard == discard_l - && bfd_is_local_label_name (input_bfd, name)))) - skip = TRUE; - } - - /* If this is an enum, struct, or union tag, see if we have - already output an identical type. */ - if (! skip - && !flaginfo->info->traditional_format - && (isym.n_sclass == C_ENTAG - || isym.n_sclass == C_STRTAG - || isym.n_sclass == C_UNTAG) - && isym.n_numaux == 1) - { - const char *name; - char buf[SYMNMLEN + 1]; - struct coff_debug_merge_hash_entry *mh; - struct coff_debug_merge_type *mt; - union internal_auxent aux; - struct coff_debug_merge_element **epp; - bfd_byte *esl, *eslend; - struct internal_syment *islp; - bfd_size_type amt; - - name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf); - if (name == NULL) - return FALSE; - - /* Ignore fake names invented by compiler; treat them all as - the same name. */ - if (*name == '~' || *name == '.' || *name == '$' - || (*name == bfd_get_symbol_leading_char (input_bfd) - && (name[1] == '~' || name[1] == '.' || name[1] == '$'))) - name = ""; - - mh = coff_debug_merge_hash_lookup (&flaginfo->debug_merge, name, - TRUE, TRUE); - if (mh == NULL) - return FALSE; - - /* Allocate memory to hold type information. If this turns - out to be a duplicate, we pass this address to - bfd_release. */ - amt = sizeof (struct coff_debug_merge_type); - mt = (struct coff_debug_merge_type *) bfd_alloc (input_bfd, amt); - if (mt == NULL) - return FALSE; - mt->type_class = isym.n_sclass; - - /* Pick up the aux entry, which points to the end of the tag - entries. */ - bfd_coff_swap_aux_in (input_bfd, (esym + isymesz), - isym.n_type, isym.n_sclass, 0, isym.n_numaux, - &aux); - - /* Gather the elements. */ - epp = &mt->elements; - mt->elements = NULL; - islp = isymp + 2; - esl = esym + 2 * isymesz; - eslend = ((bfd_byte *) obj_coff_external_syms (input_bfd) - + aux.x_sym.x_fcnary.x_fcn.x_endndx.l * isymesz); - while (esl < eslend) - { - const char *elename; - char elebuf[SYMNMLEN + 1]; - char *name_copy; - - bfd_coff_swap_sym_in (input_bfd, esl, islp); - - amt = sizeof (struct coff_debug_merge_element); - *epp = (struct coff_debug_merge_element *) - bfd_alloc (input_bfd, amt); - if (*epp == NULL) - return FALSE; - - elename = _bfd_coff_internal_syment_name (input_bfd, islp, - elebuf); - if (elename == NULL) - return FALSE; - - amt = strlen (elename) + 1; - name_copy = (char *) bfd_alloc (input_bfd, amt); - if (name_copy == NULL) - return FALSE; - strcpy (name_copy, elename); - - (*epp)->name = name_copy; - (*epp)->type = islp->n_type; - (*epp)->tagndx = 0; - if (islp->n_numaux >= 1 - && islp->n_type != T_NULL - && islp->n_sclass != C_EOS) - { - union internal_auxent eleaux; - long indx; - - bfd_coff_swap_aux_in (input_bfd, (esl + isymesz), - islp->n_type, islp->n_sclass, 0, - islp->n_numaux, &eleaux); - indx = eleaux.x_sym.x_tagndx.l; - - /* FIXME: If this tagndx entry refers to a symbol - defined later in this file, we just ignore it. - Handling this correctly would be tedious, and may - not be required. */ - if (indx > 0 - && (indx - < ((esym - - (bfd_byte *) obj_coff_external_syms (input_bfd)) - / (long) isymesz))) - { - (*epp)->tagndx = flaginfo->sym_indices[indx]; - if ((*epp)->tagndx < 0) - (*epp)->tagndx = 0; - } - } - epp = &(*epp)->next; - *epp = NULL; - - esl += (islp->n_numaux + 1) * isymesz; - islp += islp->n_numaux + 1; - } - - /* See if we already have a definition which matches this - type. We always output the type if it has no elements, - for simplicity. */ - if (mt->elements == NULL) - bfd_release (input_bfd, mt); - else - { - struct coff_debug_merge_type *mtl; - - for (mtl = mh->types; mtl != NULL; mtl = mtl->next) - { - struct coff_debug_merge_element *me, *mel; - - if (mtl->type_class != mt->type_class) - continue; - - for (me = mt->elements, mel = mtl->elements; - me != NULL && mel != NULL; - me = me->next, mel = mel->next) - { - if (strcmp (me->name, mel->name) != 0 - || me->type != mel->type - || me->tagndx != mel->tagndx) - break; - } - - if (me == NULL && mel == NULL) - break; - } - - if (mtl == NULL || (bfd_size_type) mtl->indx >= syment_base) - { - /* This is the first definition of this type. */ - mt->indx = output_index; - mt->next = mh->types; - mh->types = mt; - } - else - { - /* This is a redefinition which can be merged. */ - bfd_release (input_bfd, mt); - *indexp = mtl->indx; - add = (eslend - esym) / isymesz; - skip = TRUE; - } - } - } - - /* We now know whether we are to skip this symbol or not. */ - if (! skip) - { - /* Adjust the symbol in order to output it. */ - - if (isym._n._n_n._n_zeroes == 0 - && isym._n._n_n._n_offset != 0) - { - const char *name; - bfd_size_type indx; - - /* This symbol has a long name. Enter it in the string - table we are building. Note that we do not check - bfd_coff_symname_in_debug. That is only true for - XCOFF, and XCOFF requires different linking code - anyhow. */ - name = _bfd_coff_internal_syment_name (input_bfd, &isym, NULL); - if (name == NULL) - return FALSE; - indx = _bfd_stringtab_add (flaginfo->strtab, name, hash, copy); - if (indx == (bfd_size_type) -1) - return FALSE; - isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; - } - - switch (isym.n_sclass) - { - case C_AUTO: - case C_MOS: - case C_EOS: - case C_MOE: - case C_MOU: - case C_UNTAG: - case C_STRTAG: - case C_ENTAG: - case C_TPDEF: - case C_ARG: - case C_USTATIC: - case C_REG: - case C_REGPARM: - case C_FIELD: - /* The symbol value should not be modified. */ - break; - - case C_FCN: - if (obj_pe (input_bfd) - && strcmp (isym.n_name, ".bf") != 0 - && isym.n_scnum > 0) - { - /* For PE, .lf and .ef get their value left alone, - while .bf gets relocated. However, they all have - "real" section numbers, and need to be moved into - the new section. */ - isym.n_scnum = (*secpp)->output_section->target_index; - break; - } - /* Fall through. */ - default: - case C_LABEL: /* Not completely sure about these 2 */ - case C_EXTDEF: - case C_BLOCK: - case C_EFCN: - case C_NULL: - case C_EXT: - case C_STAT: - case C_SECTION: - case C_NT_WEAK: - /* Compute new symbol location. */ - if (isym.n_scnum > 0) - { - isym.n_scnum = (*secpp)->output_section->target_index; - isym.n_value += (*secpp)->output_offset; - if (! obj_pe (input_bfd)) - isym.n_value -= (*secpp)->vma; - if (! obj_pe (flaginfo->output_bfd)) - isym.n_value += (*secpp)->output_section->vma; - } - break; - - case C_FILE: - /* The value of a C_FILE symbol is the symbol index of - the next C_FILE symbol. The value of the last C_FILE - symbol is the symbol index to the first external - symbol (actually, coff_renumber_symbols does not get - this right--it just sets the value of the last C_FILE - symbol to zero--and nobody has ever complained about - it). We try to get this right, below, just before we - write the symbols out, but in the general case we may - have to write the symbol out twice. */ - if (flaginfo->last_file_index != -1 - && flaginfo->last_file.n_value != (bfd_vma) output_index) - { - /* We must correct the value of the last C_FILE - entry. */ - flaginfo->last_file.n_value = output_index; - if ((bfd_size_type) flaginfo->last_file_index >= syment_base) - { - /* The last C_FILE symbol is in this input file. */ - bfd_coff_swap_sym_out (output_bfd, - &flaginfo->last_file, - (flaginfo->outsyms - + ((flaginfo->last_file_index - - syment_base) - * osymesz))); - } - else - { - file_ptr pos; - - /* We have already written out the last C_FILE - symbol. We need to write it out again. We - borrow *outsym temporarily. */ - bfd_coff_swap_sym_out (output_bfd, - &flaginfo->last_file, outsym); - pos = obj_sym_filepos (output_bfd); - pos += flaginfo->last_file_index * osymesz; - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 - || bfd_bwrite (outsym, osymesz, output_bfd) != osymesz) - return FALSE; - } - } - - flaginfo->last_file_index = output_index; - flaginfo->last_file = isym; - break; - } - - /* If doing task linking, convert normal global function symbols to - static functions. */ - if (flaginfo->info->task_link && IS_EXTERNAL (input_bfd, isym)) - isym.n_sclass = C_STAT; - - /* Output the symbol. */ - bfd_coff_swap_sym_out (output_bfd, &isym, outsym); - - *indexp = output_index; - - if (global) - { - long indx; - struct coff_link_hash_entry *h; - - indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd)) - / isymesz); - h = obj_coff_sym_hashes (input_bfd)[indx]; - if (h == NULL) - { - /* This can happen if there were errors earlier in - the link. */ - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - h->indx = output_index; - } - - output_index += add; - outsym += add * osymesz; - } - - esym += add * isymesz; - isymp += add; - ++secpp; - ++indexp; - for (--add; add > 0; --add) - { - *secpp++ = NULL; - *indexp++ = -1; - } - } - - /* Fix up the aux entries. This must be done in a separate pass, - because we don't know the correct symbol indices until we have - already decided which symbols we are going to keep. */ - esym = (bfd_byte *) obj_coff_external_syms (input_bfd); - esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; - isymp = flaginfo->internal_syms; - indexp = flaginfo->sym_indices; - sym_hash = obj_coff_sym_hashes (input_bfd); - outsym = flaginfo->outsyms; - - while (esym < esym_end) - { - int add; - - add = 1 + isymp->n_numaux; - - if ((*indexp < 0 - || (bfd_size_type) *indexp < syment_base) - && (*sym_hash == NULL - || (*sym_hash)->auxbfd != input_bfd)) - esym += add * isymesz; - else - { - struct coff_link_hash_entry *h; - int i; - - h = NULL; - if (*indexp < 0) - { - h = *sym_hash; - - /* The m68k-motorola-sysv assembler will sometimes - generate two symbols with the same name, but only one - will have aux entries. */ - BFD_ASSERT (isymp->n_numaux == 0 - || h->numaux == 0 - || h->numaux == isymp->n_numaux); - } - - esym += isymesz; - - if (h == NULL) - outsym += osymesz; - - /* Handle the aux entries. This handling is based on - coff_pointerize_aux. I don't know if it always correct. */ - for (i = 0; i < isymp->n_numaux && esym < esym_end; i++) - { - union internal_auxent aux; - union internal_auxent *auxp; - - if (h != NULL && h->aux != NULL && (h->numaux > i)) - auxp = h->aux + i; - else - { - bfd_coff_swap_aux_in (input_bfd, esym, isymp->n_type, - isymp->n_sclass, i, isymp->n_numaux, &aux); - auxp = &aux; - } - - if (isymp->n_sclass == C_FILE) - { - /* If this is a long filename, we must put it in the - string table. */ - if (auxp->x_file.x_n.x_zeroes == 0 - && auxp->x_file.x_n.x_offset != 0) - { - const char *filename; - bfd_size_type indx; - - BFD_ASSERT (auxp->x_file.x_n.x_offset - >= STRING_SIZE_SIZE); - if (strings == NULL) - { - strings = _bfd_coff_read_string_table (input_bfd); - if (strings == NULL) - return FALSE; - } - if ((bfd_size_type) auxp->x_file.x_n.x_offset >= obj_coff_strings_len (input_bfd)) - filename = _(""); - else - filename = strings + auxp->x_file.x_n.x_offset; - indx = _bfd_stringtab_add (flaginfo->strtab, filename, - hash, copy); - if (indx == (bfd_size_type) -1) - return FALSE; - auxp->x_file.x_n.x_offset = STRING_SIZE_SIZE + indx; - } - } - else if ((isymp->n_sclass != C_STAT || isymp->n_type != T_NULL) - && isymp->n_sclass != C_NT_WEAK) - { - unsigned long indx; - - if (ISFCN (isymp->n_type) - || ISTAG (isymp->n_sclass) - || isymp->n_sclass == C_BLOCK - || isymp->n_sclass == C_FCN) - { - indx = auxp->x_sym.x_fcnary.x_fcn.x_endndx.l; - if (indx > 0 - && indx < obj_raw_syment_count (input_bfd)) - { - /* We look forward through the symbol for - the index of the next symbol we are going - to include. I don't know if this is - entirely right. */ - while ((flaginfo->sym_indices[indx] < 0 - || ((bfd_size_type) flaginfo->sym_indices[indx] - < syment_base)) - && indx < obj_raw_syment_count (input_bfd)) - ++indx; - if (indx >= obj_raw_syment_count (input_bfd)) - indx = output_index; - else - indx = flaginfo->sym_indices[indx]; - auxp->x_sym.x_fcnary.x_fcn.x_endndx.l = indx; - } - } - - indx = auxp->x_sym.x_tagndx.l; - if (indx > 0 && indx < obj_raw_syment_count (input_bfd)) - { - long symindx; - - symindx = flaginfo->sym_indices[indx]; - if (symindx < 0) - auxp->x_sym.x_tagndx.l = 0; - else - auxp->x_sym.x_tagndx.l = symindx; - } - - /* The .bf symbols are supposed to be linked through - the endndx field. We need to carry this list - across object files. */ - if (i == 0 - && h == NULL - && isymp->n_sclass == C_FCN - && (isymp->_n._n_n._n_zeroes != 0 - || isymp->_n._n_n._n_offset == 0) - && isymp->_n._n_name[0] == '.' - && isymp->_n._n_name[1] == 'b' - && isymp->_n._n_name[2] == 'f' - && isymp->_n._n_name[3] == '\0') - { - if (flaginfo->last_bf_index != -1) - { - flaginfo->last_bf.x_sym.x_fcnary.x_fcn.x_endndx.l = - *indexp; - - if ((bfd_size_type) flaginfo->last_bf_index - >= syment_base) - { - void *auxout; - - /* The last .bf symbol is in this input - file. This will only happen if the - assembler did not set up the .bf - endndx symbols correctly. */ - auxout = (flaginfo->outsyms - + ((flaginfo->last_bf_index - - syment_base) - * osymesz)); - - bfd_coff_swap_aux_out (output_bfd, - &flaginfo->last_bf, - isymp->n_type, - isymp->n_sclass, - 0, isymp->n_numaux, - auxout); - } - else - { - file_ptr pos; - - /* We have already written out the last - .bf aux entry. We need to write it - out again. We borrow *outsym - temporarily. FIXME: This case should - be made faster. */ - bfd_coff_swap_aux_out (output_bfd, - &flaginfo->last_bf, - isymp->n_type, - isymp->n_sclass, - 0, isymp->n_numaux, - outsym); - pos = obj_sym_filepos (output_bfd); - pos += flaginfo->last_bf_index * osymesz; - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 - || (bfd_bwrite (outsym, osymesz, output_bfd) - != osymesz)) - return FALSE; - } - } - - if (auxp->x_sym.x_fcnary.x_fcn.x_endndx.l != 0) - flaginfo->last_bf_index = -1; - else - { - /* The endndx field of this aux entry must - be updated with the symbol number of the - next .bf symbol. */ - flaginfo->last_bf = *auxp; - flaginfo->last_bf_index = (((outsym - flaginfo->outsyms) - / osymesz) - + syment_base); - } - } - } - - if (h == NULL) - { - bfd_coff_swap_aux_out (output_bfd, auxp, isymp->n_type, - isymp->n_sclass, i, isymp->n_numaux, - outsym); - outsym += osymesz; - } - - esym += isymesz; - } - } - - indexp += add; - isymp += add; - sym_hash += add; - } - - /* Relocate the line numbers, unless we are stripping them. */ - if (flaginfo->info->strip == strip_none - || flaginfo->info->strip == strip_some) - { - for (o = input_bfd->sections; o != NULL; o = o->next) - { - bfd_vma offset; - bfd_byte *eline; - bfd_byte *elineend; - bfd_byte *oeline; - bfd_boolean skipping; - file_ptr pos; - bfd_size_type amt; - - /* FIXME: If SEC_HAS_CONTENTS is not for the section, then - build_link_order in ldwrite.c will not have created a - link order, which means that we will not have seen this - input section in _bfd_coff_final_link, which means that - we will not have allocated space for the line numbers of - this section. I don't think line numbers can be - meaningful for a section which does not have - SEC_HAS_CONTENTS set, but, if they do, this must be - changed. */ - if (o->lineno_count == 0 - || (o->output_section->flags & SEC_HAS_CONTENTS) == 0) - continue; - - if (bfd_seek (input_bfd, o->line_filepos, SEEK_SET) != 0 - || bfd_bread (flaginfo->linenos, linesz * o->lineno_count, - input_bfd) != linesz * o->lineno_count) - return FALSE; - - offset = o->output_section->vma + o->output_offset - o->vma; - eline = flaginfo->linenos; - oeline = flaginfo->linenos; - elineend = eline + linesz * o->lineno_count; - skipping = FALSE; - for (; eline < elineend; eline += linesz) - { - struct internal_lineno iline; - - bfd_coff_swap_lineno_in (input_bfd, eline, &iline); - - if (iline.l_lnno != 0) - iline.l_addr.l_paddr += offset; - else if (iline.l_addr.l_symndx >= 0 - && ((unsigned long) iline.l_addr.l_symndx - < obj_raw_syment_count (input_bfd))) - { - long indx; - - indx = flaginfo->sym_indices[iline.l_addr.l_symndx]; - - if (indx < 0) - { - /* These line numbers are attached to a symbol - which we are stripping. We must discard the - line numbers because reading them back with - no associated symbol (or associating them all - with symbol #0) will fail. We can't regain - the space in the output file, but at least - they're dense. */ - skipping = TRUE; - } - else - { - struct internal_syment is; - union internal_auxent ia; - - /* Fix up the lnnoptr field in the aux entry of - the symbol. It turns out that we can't do - this when we modify the symbol aux entries, - because gas sometimes screws up the lnnoptr - field and makes it an offset from the start - of the line numbers rather than an absolute - file index. */ - bfd_coff_swap_sym_in (output_bfd, - (flaginfo->outsyms - + ((indx - syment_base) - * osymesz)), &is); - if ((ISFCN (is.n_type) - || is.n_sclass == C_BLOCK) - && is.n_numaux >= 1) - { - void *auxptr; - - auxptr = (flaginfo->outsyms - + ((indx - syment_base + 1) - * osymesz)); - bfd_coff_swap_aux_in (output_bfd, auxptr, - is.n_type, is.n_sclass, - 0, is.n_numaux, &ia); - ia.x_sym.x_fcnary.x_fcn.x_lnnoptr = - (o->output_section->line_filepos - + o->output_section->lineno_count * linesz - + eline - flaginfo->linenos); - bfd_coff_swap_aux_out (output_bfd, &ia, - is.n_type, is.n_sclass, 0, - is.n_numaux, auxptr); - } - - skipping = FALSE; - } - - iline.l_addr.l_symndx = indx; - } - - if (!skipping) - { - bfd_coff_swap_lineno_out (output_bfd, &iline, oeline); - oeline += linesz; - } - } - - pos = o->output_section->line_filepos; - pos += o->output_section->lineno_count * linesz; - amt = oeline - flaginfo->linenos; - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo->linenos, amt, output_bfd) != amt) - return FALSE; - - o->output_section->lineno_count += amt / linesz; - } - } - - /* If we swapped out a C_FILE symbol, guess that the next C_FILE - symbol will be the first symbol in the next input file. In the - normal case, this will save us from writing out the C_FILE symbol - again. */ - if (flaginfo->last_file_index != -1 - && (bfd_size_type) flaginfo->last_file_index >= syment_base) - { - flaginfo->last_file.n_value = output_index; - bfd_coff_swap_sym_out (output_bfd, &flaginfo->last_file, - (flaginfo->outsyms - + ((flaginfo->last_file_index - syment_base) - * osymesz))); - } - - /* Write the modified symbols to the output file. */ - if (outsym > flaginfo->outsyms) - { - file_ptr pos; - bfd_size_type amt; - - pos = obj_sym_filepos (output_bfd) + syment_base * osymesz; - amt = outsym - flaginfo->outsyms; - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo->outsyms, amt, output_bfd) != amt) - return FALSE; - - BFD_ASSERT ((obj_raw_syment_count (output_bfd) - + (outsym - flaginfo->outsyms) / osymesz) - == output_index); - - obj_raw_syment_count (output_bfd) = output_index; - } - - /* Relocate the contents of each section. */ - adjust_symndx = coff_backend_info (input_bfd)->_bfd_coff_adjust_symndx; - for (o = input_bfd->sections; o != NULL; o = o->next) - { - bfd_byte *contents; - struct coff_section_tdata *secdata; - - if (! o->linker_mark) - /* This section was omitted from the link. */ - continue; - - if ((o->flags & SEC_LINKER_CREATED) != 0) - continue; - - if ((o->flags & SEC_HAS_CONTENTS) == 0 - || (o->size == 0 && (o->flags & SEC_RELOC) == 0)) - { - if ((o->flags & SEC_RELOC) != 0 - && o->reloc_count != 0) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: relocs in section `%A', but it has no contents"), - input_bfd, o); - bfd_set_error (bfd_error_no_contents); - return FALSE; - } - - continue; - } - - secdata = coff_section_data (input_bfd, o); - if (secdata != NULL && secdata->contents != NULL) - contents = secdata->contents; - else - { - contents = flaginfo->contents; - if (! bfd_get_full_section_contents (input_bfd, o, &contents)) - return FALSE; - } - - if ((o->flags & SEC_RELOC) != 0) - { - int target_index; - struct internal_reloc *internal_relocs; - struct internal_reloc *irel; - - /* Read in the relocs. */ - target_index = o->output_section->target_index; - internal_relocs = (_bfd_coff_read_internal_relocs - (input_bfd, o, FALSE, flaginfo->external_relocs, - bfd_link_relocatable (flaginfo->info), - (bfd_link_relocatable (flaginfo->info) - ? (flaginfo->section_info[target_index].relocs - + o->output_section->reloc_count) - : flaginfo->internal_relocs))); - if (internal_relocs == NULL - && o->reloc_count > 0) - return FALSE; - - /* Run through the relocs looking for relocs against symbols - coming from discarded sections and complain about them. */ - irel = internal_relocs; - for (; irel < &internal_relocs[o->reloc_count]; irel++) - { - struct coff_link_hash_entry *h; - asection *ps = NULL; - long symndx = irel->r_symndx; - if (symndx < 0) - continue; - h = obj_coff_sym_hashes (input_bfd)[symndx]; - if (h == NULL) - continue; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct coff_link_hash_entry *) h->root.u.i.link; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - ps = h->root.u.def.section; - if (ps == NULL) - continue; - /* Complain if definition comes from an excluded section. */ - if (ps->flags & SEC_EXCLUDE) - (*flaginfo->info->callbacks->einfo) - /* xgettext: c-format */ - (_("%X`%s' referenced in section `%A' of %B: " - "defined in discarded section `%A' of %B\n"), - h->root.root.string, o, input_bfd, ps, ps->owner); - } - - /* Call processor specific code to relocate the section - contents. */ - if (! bfd_coff_relocate_section (output_bfd, flaginfo->info, - input_bfd, o, - contents, - internal_relocs, - flaginfo->internal_syms, - flaginfo->sec_ptrs)) - return FALSE; - - if (bfd_link_relocatable (flaginfo->info)) - { - bfd_vma offset; - struct internal_reloc *irelend; - struct coff_link_hash_entry **rel_hash; - - offset = o->output_section->vma + o->output_offset - o->vma; - irel = internal_relocs; - irelend = irel + o->reloc_count; - rel_hash = (flaginfo->section_info[target_index].rel_hashes - + o->output_section->reloc_count); - for (; irel < irelend; irel++, rel_hash++) - { - struct coff_link_hash_entry *h; - bfd_boolean adjusted; - - *rel_hash = NULL; - - /* Adjust the reloc address and symbol index. */ - irel->r_vaddr += offset; - - if (irel->r_symndx == -1) - continue; - - if (adjust_symndx) - { - if (! (*adjust_symndx) (output_bfd, flaginfo->info, - input_bfd, o, irel, - &adjusted)) - return FALSE; - if (adjusted) - continue; - } - - h = obj_coff_sym_hashes (input_bfd)[irel->r_symndx]; - if (h != NULL) - { - /* This is a global symbol. */ - if (h->indx >= 0) - irel->r_symndx = h->indx; - else - { - /* This symbol is being written at the end - of the file, and we do not yet know the - symbol index. We save the pointer to the - hash table entry in the rel_hash list. - We set the indx field to -2 to indicate - that this symbol must not be stripped. */ - *rel_hash = h; - h->indx = -2; - } - } - else - { - long indx; - - indx = flaginfo->sym_indices[irel->r_symndx]; - if (indx != -1) - irel->r_symndx = indx; - else - { - struct internal_syment *is; - const char *name; - char buf[SYMNMLEN + 1]; - - /* This reloc is against a symbol we are - stripping. This should have been handled - by the 'dont_skip_symbol' code in the while - loop at the top of this function. */ - is = flaginfo->internal_syms + irel->r_symndx; - - name = (_bfd_coff_internal_syment_name - (input_bfd, is, buf)); - if (name == NULL) - return FALSE; - - (*flaginfo->info->callbacks->unattached_reloc) - (flaginfo->info, name, input_bfd, o, irel->r_vaddr); - } - } - } - - o->output_section->reloc_count += o->reloc_count; - } - } - - /* Write out the modified section contents. */ - if (secdata == NULL || secdata->stab_info == NULL) - { - file_ptr loc = o->output_offset * bfd_octets_per_byte (output_bfd); - if (! bfd_set_section_contents (output_bfd, o->output_section, - contents, loc, o->size)) - return FALSE; - } - else - { - if (! (_bfd_write_section_stabs - (output_bfd, &coff_hash_table (flaginfo->info)->stab_info, - o, &secdata->stab_info, contents))) - return FALSE; - } - } - - if (! flaginfo->info->keep_memory - && ! _bfd_coff_free_symbols (input_bfd)) - return FALSE; - - return TRUE; -} - -/* Write out a global symbol. Called via bfd_hash_traverse. */ - -bfd_boolean -_bfd_coff_write_global_sym (struct bfd_hash_entry *bh, void *data) -{ - struct coff_link_hash_entry *h = (struct coff_link_hash_entry *) bh; - struct coff_final_link_info *flaginfo = (struct coff_final_link_info *) data; - bfd *output_bfd; - struct internal_syment isym; - bfd_size_type symesz; - unsigned int i; - file_ptr pos; - - output_bfd = flaginfo->output_bfd; - - if (h->root.type == bfd_link_hash_warning) - { - h = (struct coff_link_hash_entry *) h->root.u.i.link; - if (h->root.type == bfd_link_hash_new) - return TRUE; - } - - if (h->indx >= 0) - return TRUE; - - if (h->indx != -2 - && (flaginfo->info->strip == strip_all - || (flaginfo->info->strip == strip_some - && (bfd_hash_lookup (flaginfo->info->keep_hash, - h->root.root.string, FALSE, FALSE) - == NULL)))) - return TRUE; - - 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: - isym.n_scnum = N_UNDEF; - isym.n_value = 0; - break; - - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - { - asection *sec; - - sec = h->root.u.def.section->output_section; - if (bfd_is_abs_section (sec)) - isym.n_scnum = N_ABS; - else - isym.n_scnum = sec->target_index; - isym.n_value = (h->root.u.def.value - + h->root.u.def.section->output_offset); - if (! obj_pe (flaginfo->output_bfd)) - isym.n_value += sec->vma; - } - break; - - case bfd_link_hash_common: - isym.n_scnum = N_UNDEF; - isym.n_value = h->root.u.c.size; - break; - - case bfd_link_hash_indirect: - /* Just ignore these. They can't be handled anyhow. */ - return TRUE; - } - - if (strlen (h->root.root.string) <= SYMNMLEN) - strncpy (isym._n._n_name, h->root.root.string, SYMNMLEN); - else - { - bfd_boolean hash; - bfd_size_type indx; - - hash = TRUE; - if (flaginfo->info->traditional_format) - hash = FALSE; - indx = _bfd_stringtab_add (flaginfo->strtab, h->root.root.string, hash, - FALSE); - if (indx == (bfd_size_type) -1) - { - flaginfo->failed = TRUE; - return FALSE; - } - isym._n._n_n._n_zeroes = 0; - isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx; - } - - isym.n_sclass = h->symbol_class; - isym.n_type = h->type; - - if (isym.n_sclass == C_NULL) - isym.n_sclass = C_EXT; - - /* If doing task linking and this is the pass where we convert - defined globals to statics, then do that conversion now. If the - symbol is not being converted, just ignore it and it will be - output during a later pass. */ - if (flaginfo->global_to_static) - { - if (! IS_EXTERNAL (output_bfd, isym)) - return TRUE; - - isym.n_sclass = C_STAT; - } - - /* When a weak symbol is not overridden by a strong one, - turn it into an external symbol when not building a - shared or relocatable object. */ - if (! bfd_link_pic (flaginfo->info) - && ! bfd_link_relocatable (flaginfo->info) - && IS_WEAK_EXTERNAL (flaginfo->output_bfd, isym)) - isym.n_sclass = C_EXT; - - isym.n_numaux = h->numaux; - - bfd_coff_swap_sym_out (output_bfd, &isym, flaginfo->outsyms); - - symesz = bfd_coff_symesz (output_bfd); - - pos = obj_sym_filepos (output_bfd); - pos += obj_raw_syment_count (output_bfd) * symesz; - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 - || bfd_bwrite (flaginfo->outsyms, symesz, output_bfd) != symesz) - { - flaginfo->failed = TRUE; - return FALSE; - } - - h->indx = obj_raw_syment_count (output_bfd); - - ++obj_raw_syment_count (output_bfd); - - /* Write out any associated aux entries. Most of the aux entries - will have been modified in _bfd_coff_link_input_bfd. We have to - handle section aux entries here, now that we have the final - relocation and line number counts. */ - for (i = 0; i < isym.n_numaux; i++) - { - union internal_auxent *auxp; - - auxp = h->aux + i; - - /* Look for a section aux entry here using the same tests that - coff_swap_aux_out uses. */ - if (i == 0 - && (isym.n_sclass == C_STAT - || isym.n_sclass == C_HIDDEN) - && isym.n_type == T_NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - asection *sec; - - sec = h->root.u.def.section->output_section; - if (sec != NULL) - { - auxp->x_scn.x_scnlen = sec->size; - - /* For PE, an overflow on the final link reportedly does - not matter. FIXME: Why not? */ - if (sec->reloc_count > 0xffff - && (! obj_pe (output_bfd) - || bfd_link_relocatable (flaginfo->info))) - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: %A: reloc overflow: %#x > 0xffff"), - output_bfd, sec, sec->reloc_count); - - if (sec->lineno_count > 0xffff - && (! obj_pe (output_bfd) - || bfd_link_relocatable (flaginfo->info))) - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: warning: %A: line number overflow: %#x > 0xffff"), - output_bfd, sec, sec->lineno_count); - - auxp->x_scn.x_nreloc = sec->reloc_count; - auxp->x_scn.x_nlinno = sec->lineno_count; - auxp->x_scn.x_checksum = 0; - auxp->x_scn.x_associated = 0; - auxp->x_scn.x_comdat = 0; - } - } - - bfd_coff_swap_aux_out (output_bfd, auxp, isym.n_type, - isym.n_sclass, (int) i, isym.n_numaux, - flaginfo->outsyms); - if (bfd_bwrite (flaginfo->outsyms, symesz, output_bfd) != symesz) - { - flaginfo->failed = TRUE; - return FALSE; - } - ++obj_raw_syment_count (output_bfd); - } - - return TRUE; -} - -/* Write out task global symbols, converting them to statics. Called - via coff_link_hash_traverse. Calls bfd_coff_write_global_sym to do - the dirty work, if the symbol we are processing needs conversion. */ - -bfd_boolean -_bfd_coff_write_task_globals (struct coff_link_hash_entry *h, void *data) -{ - struct coff_final_link_info *flaginfo = (struct coff_final_link_info *) data; - bfd_boolean rtnval = TRUE; - bfd_boolean save_global_to_static; - - if (h->root.type == bfd_link_hash_warning) - h = (struct coff_link_hash_entry *) h->root.u.i.link; - - if (h->indx < 0) - { - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - save_global_to_static = flaginfo->global_to_static; - flaginfo->global_to_static = TRUE; - rtnval = _bfd_coff_write_global_sym (&h->root.root, data); - flaginfo->global_to_static = save_global_to_static; - break; - default: - break; - } - } - return (rtnval); -} - -/* Handle a link order which is supposed to generate a reloc. */ - -bfd_boolean -_bfd_coff_reloc_link_order (bfd *output_bfd, - struct coff_final_link_info *flaginfo, - asection *output_section, - struct bfd_link_order *link_order) -{ - reloc_howto_type *howto; - struct internal_reloc *irel; - struct coff_link_hash_entry **rel_hash_ptr; - - 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; - } - - if (link_order->u.reloc.p->addend != 0) - { - bfd_size_type size; - bfd_byte *buf; - bfd_reloc_status_type rstat; - bfd_boolean ok; - file_ptr loc; - - size = bfd_get_reloc_size (howto); - buf = (bfd_byte *) bfd_zmalloc (size); - if (buf == NULL && size != 0) - return FALSE; - - rstat = _bfd_relocate_contents (howto, output_bfd, - (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: - (*flaginfo->info->callbacks->reloc_overflow) - (flaginfo->info, NULL, - (link_order->type == bfd_section_reloc_link_order - ? bfd_section_name (output_bfd, - link_order->u.reloc.p->u.section) - : link_order->u.reloc.p->u.name), - howto->name, link_order->u.reloc.p->addend, - (bfd *) NULL, (asection *) NULL, (bfd_vma) 0); - break; - } - loc = link_order->offset * bfd_octets_per_byte (output_bfd); - ok = bfd_set_section_contents (output_bfd, output_section, buf, - loc, size); - free (buf); - if (! ok) - return FALSE; - } - - /* Store the reloc information in the right place. It will get - swapped and written out at the end of the final_link routine. */ - irel = (flaginfo->section_info[output_section->target_index].relocs - + output_section->reloc_count); - rel_hash_ptr = (flaginfo->section_info[output_section->target_index].rel_hashes - + output_section->reloc_count); - - memset (irel, 0, sizeof (struct internal_reloc)); - *rel_hash_ptr = NULL; - - irel->r_vaddr = output_section->vma + link_order->offset; - - if (link_order->type == bfd_section_reloc_link_order) - { - /* We need to somehow locate a symbol in the right section. The - symbol must either have a value of zero, or we must adjust - the addend by the value of the symbol. FIXME: Write this - when we need it. The old linker couldn't handle this anyhow. */ - abort (); - *rel_hash_ptr = NULL; - irel->r_symndx = 0; - } - else - { - struct coff_link_hash_entry *h; - - h = ((struct coff_link_hash_entry *) - bfd_wrapped_link_hash_lookup (output_bfd, flaginfo->info, - link_order->u.reloc.p->u.name, - FALSE, FALSE, TRUE)); - if (h != NULL) - { - if (h->indx >= 0) - irel->r_symndx = h->indx; - else - { - /* Set the index to -2 to force this symbol to get - written out. */ - h->indx = -2; - *rel_hash_ptr = h; - irel->r_symndx = 0; - } - } - else - { - (*flaginfo->info->callbacks->unattached_reloc) - (flaginfo->info, link_order->u.reloc.p->u.name, - (bfd *) NULL, (asection *) NULL, (bfd_vma) 0); - irel->r_symndx = 0; - } - } - - /* FIXME: Is this always right? */ - irel->r_type = howto->type; - - /* r_size is only used on the RS/6000, which needs its own linker - routines anyhow. r_extern is only used for ECOFF. */ - - /* FIXME: What is the right value for r_offset? Is zero OK? */ - ++output_section->reloc_count; - - return TRUE; -} - -/* A basic reloc handling routine which may be used by processors with - simple relocs. */ - -bfd_boolean -_bfd_coff_generic_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - struct internal_reloc *relocs, - struct internal_syment *syms, - asection **sections) -{ - struct internal_reloc *rel; - struct internal_reloc *relend; - - rel = relocs; - relend = rel + input_section->reloc_count; - for (; rel < relend; rel++) - { - long symndx; - struct coff_link_hash_entry *h; - struct internal_syment *sym; - bfd_vma addend; - bfd_vma val; - asection *sec; - reloc_howto_type *howto; - bfd_reloc_status_type rstat; - - symndx = rel->r_symndx; - - if (symndx == -1) - { - h = NULL; - sym = NULL; - } - else if (symndx < 0 - || (unsigned long) symndx >= obj_raw_syment_count (input_bfd)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: illegal symbol index %ld in relocs"), input_bfd, symndx); - return FALSE; - } - else - { - h = obj_coff_sym_hashes (input_bfd)[symndx]; - sym = syms + symndx; - } - - /* COFF treats common symbols in one of two ways. Either the - size of the symbol is included in the section contents, or it - is not. We assume that the size is not included, and force - the rtype_to_howto function to adjust the addend as needed. */ - if (sym != NULL && sym->n_scnum != 0) - addend = - sym->n_value; - else - addend = 0; - - howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h, - sym, &addend); - if (howto == NULL) - return FALSE; - - /* If we are doing a relocatable link, then we can just ignore - a PC relative reloc that is pcrel_offset. It will already - have the correct value. If this is not a relocatable link, - then we should ignore the symbol value. */ - if (howto->pc_relative && howto->pcrel_offset) - { - if (bfd_link_relocatable (info)) - continue; - if (sym != NULL && sym->n_scnum != 0) - addend += sym->n_value; - } - - val = 0; - sec = NULL; - if (h == NULL) - { - if (symndx == -1) - { - sec = bfd_abs_section_ptr; - val = 0; - } - else - { - sec = sections[symndx]; - - /* PR 19623: Relocations against symbols in - the absolute sections should ignored. */ - if (bfd_is_abs_section (sec)) - continue; - - val = (sec->output_section->vma - + sec->output_offset - + sym->n_value); - if (! obj_pe (input_bfd)) - val -= sec->vma; - } - } - else - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - /* Defined weak symbols are a GNU extension. */ - sec = h->root.u.def.section; - val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - - else if (h->root.type == bfd_link_hash_undefweak) - { - if (h->symbol_class == C_NT_WEAK && h->numaux == 1) - { - /* See _Microsoft Portable Executable and Common Object - File Format Specification_, section 5.5.3. - Note that weak symbols without aux records are a GNU - extension. - FIXME: All weak externals are treated as having - characteristic IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY (1). - These behave as per SVR4 ABI: A library member - will resolve a weak external only if a normal - external causes the library member to be linked. - See also linker.c: generic_link_check_archive_element. */ - struct coff_link_hash_entry *h2 = - h->auxbfd->tdata.coff_obj_data->sym_hashes[ - h->aux->x_sym.x_tagndx.l]; - - if (!h2 || h2->root.type == bfd_link_hash_undefined) - { - sec = bfd_abs_section_ptr; - val = 0; - } - else - { - sec = h2->root.u.def.section; - val = h2->root.u.def.value - + sec->output_section->vma + sec->output_offset; - } - } - else - /* This is a GNU extension. */ - val = 0; - } - - else if (! bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_vaddr - input_section->vma, TRUE); - } - - /* If the input section defining the symbol has been discarded - then zero this reloc field. */ - if (sec != NULL && discarded_section (sec)) - { - _bfd_clear_contents (howto, input_bfd, input_section, - contents + (rel->r_vaddr - input_section->vma)); - continue; - } - - if (info->base_file) - { - /* Emit a reloc if the backend thinks it needs it. */ - if (sym && pe_data (output_bfd)->in_reloc_p (output_bfd, howto)) - { - /* Relocation to a symbol in a section which isn't - absolute. We output the address here to a file. - This file is then read by dlltool when generating the - reloc section. Note that the base file is not - portable between systems. We write out a bfd_vma here, - and dlltool reads in a bfd_vma. */ - bfd_vma addr = (rel->r_vaddr - - input_section->vma - + input_section->output_offset - + input_section->output_section->vma); - if (coff_data (output_bfd)->pe) - addr -= pe_data(output_bfd)->pe_opthdr.ImageBase; - if (fwrite (&addr, 1, sizeof (bfd_vma), (FILE *) info->base_file) - != sizeof (bfd_vma)) - { - bfd_set_error (bfd_error_system_call); - return FALSE; - } - } - } - - rstat = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, - rel->r_vaddr - input_section->vma, - val, addend); - - switch (rstat) - { - default: - abort (); - case bfd_reloc_ok: - break; - case bfd_reloc_outofrange: - _bfd_error_handler - /* xgettext: c-format */ - (_("%B: bad reloc address %#Lx in section `%A'"), - input_bfd, rel->r_vaddr, input_section); - return FALSE; - case bfd_reloc_overflow: - { - const char *name; - char buf[SYMNMLEN + 1]; - - if (symndx == -1) - name = "*ABS*"; - else if (h != NULL) - name = NULL; - else - { - name = _bfd_coff_internal_syment_name (input_bfd, sym, buf); - if (name == NULL) - return FALSE; - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_vaddr - input_section->vma); - } - } - } - return TRUE; -} diff --git a/sdcc/support/sdbinutils/bfd/coffswap.h b/sdcc/support/sdbinutils/bfd/coffswap.h deleted file mode 100644 index 8375af5c4..000000000 --- a/sdcc/support/sdbinutils/bfd/coffswap.h +++ /dev/null @@ -1,840 +0,0 @@ -/* Generic COFF swapping routines, for BFD. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* This file contains routines used to swap COFF data. It is a header - file because the details of swapping depend on the details of the - structures used by each COFF implementation. This is included by - coffcode.h, as well as by the ECOFF backend. - - Any file which uses this must first include "coff/internal.h" and - "coff/CPU.h". The functions will then be correct for that CPU. */ - -#ifndef GET_FCN_LNNOPTR -#define GET_FCN_LNNOPTR(abfd, ext) \ - H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) -#endif - -#ifndef GET_FCN_ENDNDX -#define GET_FCN_ENDNDX(abfd, ext) \ - H_GET_32 (abfd, ext->x_sym.x_fcnary.x_fcn.x_endndx) -#endif - -#ifndef PUT_FCN_LNNOPTR -#define PUT_FCN_LNNOPTR(abfd, in, ext) \ - H_PUT_32 (abfd, in, ext->x_sym.x_fcnary.x_fcn.x_lnnoptr) -#endif -#ifndef PUT_FCN_ENDNDX -#define PUT_FCN_ENDNDX(abfd, in, ext) \ - H_PUT_32 (abfd, in, ext->x_sym.x_fcnary.x_fcn.x_endndx) -#endif -#ifndef GET_LNSZ_LNNO -#define GET_LNSZ_LNNO(abfd, ext) \ - H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_lnno) -#endif -#ifndef GET_LNSZ_SIZE -#define GET_LNSZ_SIZE(abfd, ext) \ - H_GET_16 (abfd, ext->x_sym.x_misc.x_lnsz.x_size) -#endif -#ifndef PUT_LNSZ_LNNO -#define PUT_LNSZ_LNNO(abfd, in, ext) \ - H_PUT_16 (abfd, in, ext->x_sym.x_misc.x_lnsz.x_lnno) -#endif -#ifndef PUT_LNSZ_SIZE -#define PUT_LNSZ_SIZE(abfd, in, ext) \ - H_PUT_16 (abfd, in, ext->x_sym.x_misc.x_lnsz.x_size) -#endif -#ifndef GET_SCN_SCNLEN -#define GET_SCN_SCNLEN(abfd, ext) \ - H_GET_32 (abfd, ext->x_scn.x_scnlen) -#endif -#ifndef GET_SCN_NRELOC -#define GET_SCN_NRELOC(abfd, ext) \ - H_GET_16 (abfd, ext->x_scn.x_nreloc) -#endif -#ifndef GET_SCN_NLINNO -#define GET_SCN_NLINNO(abfd, ext) \ - H_GET_16 (abfd, ext->x_scn.x_nlinno) -#endif -#ifndef PUT_SCN_SCNLEN -#define PUT_SCN_SCNLEN(abfd, in, ext) \ - H_PUT_32 (abfd, in, ext->x_scn.x_scnlen) -#endif -#ifndef PUT_SCN_NRELOC -#define PUT_SCN_NRELOC(abfd, in, ext) \ - H_PUT_16 (abfd, in, ext->x_scn.x_nreloc) -#endif -#ifndef PUT_SCN_NLINNO -#define PUT_SCN_NLINNO(abfd, in, ext) \ - H_PUT_16 (abfd, in, ext->x_scn.x_nlinno) -#endif -#ifndef GET_LINENO_LNNO -#define GET_LINENO_LNNO(abfd, ext) \ - H_GET_16 (abfd, ext->l_lnno); -#endif -#ifndef PUT_LINENO_LNNO -#define PUT_LINENO_LNNO(abfd, val, ext) \ - H_PUT_16 (abfd, val, ext->l_lnno); -#endif - -/* The f_symptr field in the filehdr is sometimes 64 bits. */ -#ifndef GET_FILEHDR_SYMPTR -#define GET_FILEHDR_SYMPTR H_GET_32 -#endif -#ifndef PUT_FILEHDR_SYMPTR -#define PUT_FILEHDR_SYMPTR H_PUT_32 -#endif - -/* Some fields in the aouthdr are sometimes 64 bits. */ -#ifndef GET_AOUTHDR_TSIZE -#define GET_AOUTHDR_TSIZE H_GET_32 -#endif -#ifndef PUT_AOUTHDR_TSIZE -#define PUT_AOUTHDR_TSIZE H_PUT_32 -#endif -#ifndef GET_AOUTHDR_DSIZE -#define GET_AOUTHDR_DSIZE H_GET_32 -#endif -#ifndef PUT_AOUTHDR_DSIZE -#define PUT_AOUTHDR_DSIZE H_PUT_32 -#endif -#ifndef GET_AOUTHDR_BSIZE -#define GET_AOUTHDR_BSIZE H_GET_32 -#endif -#ifndef PUT_AOUTHDR_BSIZE -#define PUT_AOUTHDR_BSIZE H_PUT_32 -#endif -#ifndef GET_AOUTHDR_ENTRY -#define GET_AOUTHDR_ENTRY H_GET_32 -#endif -#ifndef PUT_AOUTHDR_ENTRY -#define PUT_AOUTHDR_ENTRY H_PUT_32 -#endif -#ifndef GET_AOUTHDR_TEXT_START -#define GET_AOUTHDR_TEXT_START H_GET_32 -#endif -#ifndef PUT_AOUTHDR_TEXT_START -#define PUT_AOUTHDR_TEXT_START H_PUT_32 -#endif -#ifndef GET_AOUTHDR_DATA_START -#define GET_AOUTHDR_DATA_START H_GET_32 -#endif -#ifndef PUT_AOUTHDR_DATA_START -#define PUT_AOUTHDR_DATA_START H_PUT_32 -#endif - -/* Some fields in the scnhdr are sometimes 64 bits. */ -#ifndef GET_SCNHDR_PADDR -#define GET_SCNHDR_PADDR H_GET_32 -#endif -#ifndef PUT_SCNHDR_PADDR -#define PUT_SCNHDR_PADDR H_PUT_32 -#endif -#ifndef GET_SCNHDR_VADDR -#define GET_SCNHDR_VADDR H_GET_32 -#endif -#ifndef PUT_SCNHDR_VADDR -#define PUT_SCNHDR_VADDR H_PUT_32 -#endif -#ifndef GET_SCNHDR_SIZE -#define GET_SCNHDR_SIZE H_GET_32 -#endif -#ifndef PUT_SCNHDR_SIZE -#define PUT_SCNHDR_SIZE H_PUT_32 -#endif -#ifndef GET_SCNHDR_SCNPTR -#define GET_SCNHDR_SCNPTR H_GET_32 -#endif -#ifndef PUT_SCNHDR_SCNPTR -#define PUT_SCNHDR_SCNPTR H_PUT_32 -#endif -#ifndef GET_SCNHDR_RELPTR -#define GET_SCNHDR_RELPTR H_GET_32 -#endif -#ifndef PUT_SCNHDR_RELPTR -#define PUT_SCNHDR_RELPTR H_PUT_32 -#endif -#ifndef GET_SCNHDR_LNNOPTR -#define GET_SCNHDR_LNNOPTR H_GET_32 -#endif -#ifndef PUT_SCNHDR_LNNOPTR -#define PUT_SCNHDR_LNNOPTR H_PUT_32 -#endif -#ifndef GET_SCNHDR_NRELOC -#define GET_SCNHDR_NRELOC H_GET_16 -#endif -#ifndef MAX_SCNHDR_NRELOC -#define MAX_SCNHDR_NRELOC 0xffff -#endif -#ifndef PUT_SCNHDR_NRELOC -#define PUT_SCNHDR_NRELOC H_PUT_16 -#endif -#ifndef GET_SCNHDR_NLNNO -#define GET_SCNHDR_NLNNO H_GET_16 -#endif -#ifndef MAX_SCNHDR_NLNNO -#define MAX_SCNHDR_NLNNO 0xffff -#endif -#ifndef PUT_SCNHDR_NLNNO -#define PUT_SCNHDR_NLNNO H_PUT_16 -#endif -#ifndef GET_SCNHDR_FLAGS -#define GET_SCNHDR_FLAGS H_GET_32 -#endif -#ifndef PUT_SCNHDR_FLAGS -#define PUT_SCNHDR_FLAGS H_PUT_32 -#endif - -#ifndef GET_RELOC_VADDR -#define GET_RELOC_VADDR H_GET_32 -#endif -#ifndef PUT_RELOC_VADDR -#define PUT_RELOC_VADDR H_PUT_32 -#endif - -#ifndef NO_COFF_RELOCS - -static void -coff_swap_reloc_in (bfd * abfd, void * src, void * dst) -{ - RELOC *reloc_src = (RELOC *) src; - struct internal_reloc *reloc_dst = (struct internal_reloc *) dst; - - reloc_dst->r_vaddr = GET_RELOC_VADDR (abfd, reloc_src->r_vaddr); - reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx); - reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type); - -#ifdef SWAP_IN_RELOC_OFFSET - reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET (abfd, reloc_src->r_offset); -#endif -} - -static unsigned int -coff_swap_reloc_out (bfd * abfd, void * src, void * dst) -{ - struct internal_reloc *reloc_src = (struct internal_reloc *) src; - struct external_reloc *reloc_dst = (struct external_reloc *) dst; - - PUT_RELOC_VADDR (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr); - H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx); - H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type); - -#ifdef SWAP_OUT_RELOC_OFFSET - SWAP_OUT_RELOC_OFFSET (abfd, reloc_src->r_offset, reloc_dst->r_offset); -#endif -#ifdef SWAP_OUT_RELOC_EXTRA - SWAP_OUT_RELOC_EXTRA (abfd, reloc_src, reloc_dst); -#endif - - return bfd_coff_relsz (abfd); -} - -#endif /* NO_COFF_RELOCS */ - -static void -coff_swap_filehdr_in (bfd * abfd, void * src, void * dst) -{ - FILHDR *filehdr_src = (FILHDR *) src; - struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; - -#ifdef COFF_ADJUST_FILEHDR_IN_PRE - COFF_ADJUST_FILEHDR_IN_PRE (abfd, src, dst); -#endif - filehdr_dst->f_magic = H_GET_16 (abfd, filehdr_src->f_magic); - filehdr_dst->f_nscns = H_GET_16 (abfd, filehdr_src->f_nscns); - filehdr_dst->f_timdat = H_GET_32 (abfd, filehdr_src->f_timdat); - filehdr_dst->f_symptr = GET_FILEHDR_SYMPTR (abfd, filehdr_src->f_symptr); - filehdr_dst->f_nsyms = H_GET_32 (abfd, filehdr_src->f_nsyms); - filehdr_dst->f_opthdr = H_GET_16 (abfd, filehdr_src->f_opthdr); - filehdr_dst->f_flags = H_GET_16 (abfd, filehdr_src->f_flags); -#ifdef TIC80_TARGET_ID - filehdr_dst->f_target_id = H_GET_16 (abfd, filehdr_src->f_target_id); -#endif - -#ifdef COFF_ADJUST_FILEHDR_IN_POST - COFF_ADJUST_FILEHDR_IN_POST (abfd, src, dst); -#endif -} - -static unsigned int -coff_swap_filehdr_out (bfd *abfd, void * in, void * out) -{ - struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; - FILHDR *filehdr_out = (FILHDR *) out; - -#ifdef COFF_ADJUST_FILEHDR_OUT_PRE - COFF_ADJUST_FILEHDR_OUT_PRE (abfd, in, out); -#endif - H_PUT_16 (abfd, filehdr_in->f_magic, filehdr_out->f_magic); - H_PUT_16 (abfd, filehdr_in->f_nscns, filehdr_out->f_nscns); - H_PUT_32 (abfd, filehdr_in->f_timdat, filehdr_out->f_timdat); - PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr, filehdr_out->f_symptr); - H_PUT_32 (abfd, filehdr_in->f_nsyms, filehdr_out->f_nsyms); - H_PUT_16 (abfd, filehdr_in->f_opthdr, filehdr_out->f_opthdr); - H_PUT_16 (abfd, filehdr_in->f_flags, filehdr_out->f_flags); -#ifdef TIC80_TARGET_ID - H_PUT_16 (abfd, filehdr_in->f_target_id, filehdr_out->f_target_id); -#endif - -#ifdef COFF_ADJUST_FILEHDR_OUT_POST - COFF_ADJUST_FILEHDR_OUT_POST (abfd, in, out); -#endif - return bfd_coff_filhsz (abfd); -} - -#ifndef NO_COFF_SYMBOLS - -static void -coff_swap_sym_in (bfd * abfd, void * ext1, void * in1) -{ - SYMENT *ext = (SYMENT *) ext1; - struct internal_syment *in = (struct internal_syment *) in1; - - if (ext->e.e_name[0] == 0) - { - in->_n._n_n._n_zeroes = 0; - in->_n._n_n._n_offset = H_GET_32 (abfd, ext->e.e.e_offset); - } - else - { -#if SYMNMLEN != E_SYMNMLEN -#error we need to cope with truncating or extending SYMNMLEN -#else - memcpy (in->_n._n_name, ext->e.e_name, SYMNMLEN); -#endif - } - - in->n_value = H_GET_32 (abfd, ext->e_value); - in->n_scnum = (short) H_GET_16 (abfd, ext->e_scnum); - if (sizeof (ext->e_type) == 2) - in->n_type = H_GET_16 (abfd, ext->e_type); - else - in->n_type = H_GET_32 (abfd, ext->e_type); - in->n_sclass = H_GET_8 (abfd, ext->e_sclass); - in->n_numaux = H_GET_8 (abfd, ext->e_numaux); -#ifdef COFF_ADJUST_SYM_IN_POST - COFF_ADJUST_SYM_IN_POST (abfd, ext1, in1); -#endif -} - -static unsigned int -coff_swap_sym_out (bfd * abfd, void * inp, void * extp) -{ - struct internal_syment *in = (struct internal_syment *) inp; - SYMENT *ext =(SYMENT *) extp; - -#ifdef COFF_ADJUST_SYM_OUT_PRE - COFF_ADJUST_SYM_OUT_PRE (abfd, inp, extp); -#endif - - if (in->_n._n_name[0] == 0) - { - H_PUT_32 (abfd, 0, ext->e.e.e_zeroes); - H_PUT_32 (abfd, in->_n._n_n._n_offset, ext->e.e.e_offset); - } - else - { -#if SYMNMLEN != E_SYMNMLEN -#error we need to cope with truncating or extending SYMNMLEN -#else - memcpy (ext->e.e_name, in->_n._n_name, SYMNMLEN); -#endif - } - - H_PUT_32 (abfd, in->n_value, ext->e_value); - H_PUT_16 (abfd, in->n_scnum, ext->e_scnum); - - if (sizeof (ext->e_type) == 2) - H_PUT_16 (abfd, in->n_type, ext->e_type); - else - H_PUT_32 (abfd, in->n_type, ext->e_type); - - H_PUT_8 (abfd, in->n_sclass, ext->e_sclass); - H_PUT_8 (abfd, in->n_numaux, ext->e_numaux); - -#ifdef COFF_ADJUST_SYM_OUT_POST - COFF_ADJUST_SYM_OUT_POST (abfd, inp, extp); -#endif - - return SYMESZ; -} - -static void -coff_swap_aux_in (bfd *abfd, - void * ext1, - int type, - int in_class, - int indx, - int numaux, - void * in1) -{ - AUXENT *ext = (AUXENT *) ext1; - union internal_auxent *in = (union internal_auxent *) in1; - -#ifdef COFF_ADJUST_AUX_IN_PRE - COFF_ADJUST_AUX_IN_PRE (abfd, ext1, type, in_class, indx, numaux, in1); -#endif - - switch (in_class) - { - case C_FILE: - if (ext->x_file.x_fname[0] == 0) - { - in->x_file.x_n.x_zeroes = 0; - in->x_file.x_n.x_offset = H_GET_32 (abfd, ext->x_file.x_n.x_offset); - } - else - { -#if FILNMLEN != E_FILNMLEN -#error we need to cope with truncating or extending FILNMLEN -#else - if (numaux > 1) - { - if (indx == 0) - memcpy (in->x_file.x_fname, ext->x_file.x_fname, - numaux * sizeof (AUXENT)); - } - else - memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN); -#endif - } - goto end; - - case C_STAT: -#ifdef C_LEAFSTAT - case C_LEAFSTAT: -#endif - case C_HIDDEN: - if (type == T_NULL) - { - in->x_scn.x_scnlen = GET_SCN_SCNLEN (abfd, ext); - in->x_scn.x_nreloc = GET_SCN_NRELOC (abfd, ext); - in->x_scn.x_nlinno = GET_SCN_NLINNO (abfd, ext); - - /* PE defines some extra fields; we zero them out for - safety. */ - in->x_scn.x_checksum = 0; - in->x_scn.x_associated = 0; - in->x_scn.x_comdat = 0; - - goto end; - } - break; - } - - in->x_sym.x_tagndx.l = H_GET_32 (abfd, ext->x_sym.x_tagndx); -#ifndef NO_TVNDX - in->x_sym.x_tvndx = H_GET_16 (abfd, ext->x_sym.x_tvndx); -#endif - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - in->x_sym.x_fcnary.x_fcn.x_lnnoptr = GET_FCN_LNNOPTR (abfd, ext); - in->x_sym.x_fcnary.x_fcn.x_endndx.l = GET_FCN_ENDNDX (abfd, ext); - } - else - { -#if DIMNUM != E_DIMNUM -#error we need to cope with truncating or extending DIMNUM -#endif - in->x_sym.x_fcnary.x_ary.x_dimen[0] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[0]); - in->x_sym.x_fcnary.x_ary.x_dimen[1] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[1]); - in->x_sym.x_fcnary.x_ary.x_dimen[2] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[2]); - in->x_sym.x_fcnary.x_ary.x_dimen[3] = - H_GET_16 (abfd, ext->x_sym.x_fcnary.x_ary.x_dimen[3]); - } - - if (ISFCN (type)) - in->x_sym.x_misc.x_fsize = H_GET_32 (abfd, ext->x_sym.x_misc.x_fsize); - else - { - in->x_sym.x_misc.x_lnsz.x_lnno = GET_LNSZ_LNNO (abfd, ext); - in->x_sym.x_misc.x_lnsz.x_size = GET_LNSZ_SIZE (abfd, ext); - } - - end: ; - -#ifdef COFF_ADJUST_AUX_IN_POST - COFF_ADJUST_AUX_IN_POST (abfd, ext1, type, in_class, indx, numaux, in1); -#endif -} - -static unsigned int -coff_swap_aux_out (bfd * abfd, - void * inp, - int type, - int in_class, - int indx ATTRIBUTE_UNUSED, - int numaux ATTRIBUTE_UNUSED, - void * extp) -{ - union internal_auxent * in = (union internal_auxent *) inp; - AUXENT *ext = (AUXENT *) extp; - -#ifdef COFF_ADJUST_AUX_OUT_PRE - COFF_ADJUST_AUX_OUT_PRE (abfd, inp, type, in_class, indx, numaux, extp); -#endif - - memset (ext, 0, AUXESZ); - - switch (in_class) - { - case C_FILE: - if (in->x_file.x_fname[0] == 0) - { - H_PUT_32 (abfd, 0, ext->x_file.x_n.x_zeroes); - H_PUT_32 (abfd, in->x_file.x_n.x_offset, ext->x_file.x_n.x_offset); - } - else - { -#if FILNMLEN != E_FILNMLEN -#error we need to cope with truncating or extending FILNMLEN -#else - memcpy (ext->x_file.x_fname, in->x_file.x_fname, FILNMLEN); -#endif - } - goto end; - - case C_STAT: -#ifdef C_LEAFSTAT - case C_LEAFSTAT: -#endif - case C_HIDDEN: - if (type == T_NULL) - { - PUT_SCN_SCNLEN (abfd, in->x_scn.x_scnlen, ext); - PUT_SCN_NRELOC (abfd, in->x_scn.x_nreloc, ext); - PUT_SCN_NLINNO (abfd, in->x_scn.x_nlinno, ext); - goto end; - } - break; - } - - H_PUT_32 (abfd, in->x_sym.x_tagndx.l, ext->x_sym.x_tagndx); -#ifndef NO_TVNDX - H_PUT_16 (abfd, in->x_sym.x_tvndx, ext->x_sym.x_tvndx); -#endif - - if (in_class == C_BLOCK || in_class == C_FCN || ISFCN (type) - || ISTAG (in_class)) - { - PUT_FCN_LNNOPTR (abfd, in->x_sym.x_fcnary.x_fcn.x_lnnoptr, ext); - PUT_FCN_ENDNDX (abfd, in->x_sym.x_fcnary.x_fcn.x_endndx.l, ext); - } - else - { -#if DIMNUM != E_DIMNUM -#error we need to cope with truncating or extending DIMNUM -#endif - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[0], - ext->x_sym.x_fcnary.x_ary.x_dimen[0]); - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[1], - ext->x_sym.x_fcnary.x_ary.x_dimen[1]); - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[2], - ext->x_sym.x_fcnary.x_ary.x_dimen[2]); - H_PUT_16 (abfd, in->x_sym.x_fcnary.x_ary.x_dimen[3], - ext->x_sym.x_fcnary.x_ary.x_dimen[3]); - } - - if (ISFCN (type)) - H_PUT_32 (abfd, in->x_sym.x_misc.x_fsize, ext->x_sym.x_misc.x_fsize); - else - { - PUT_LNSZ_LNNO (abfd, in->x_sym.x_misc.x_lnsz.x_lnno, ext); - PUT_LNSZ_SIZE (abfd, in->x_sym.x_misc.x_lnsz.x_size, ext); - } - - end: -#ifdef COFF_ADJUST_AUX_OUT_POST - COFF_ADJUST_AUX_OUT_POST (abfd, inp, type, in_class, indx, numaux, extp); -#endif - return AUXESZ; -} - -#endif /* NO_COFF_SYMBOLS */ - -#ifndef NO_COFF_LINENOS - -static void -coff_swap_lineno_in (bfd * abfd, void * ext1, void * in1) -{ - LINENO *ext = (LINENO *) ext1; - struct internal_lineno *in = (struct internal_lineno *) in1; - - in->l_addr.l_symndx = H_GET_32 (abfd, ext->l_addr.l_symndx); - in->l_lnno = GET_LINENO_LNNO (abfd, ext); -} - -static unsigned int -coff_swap_lineno_out (bfd * abfd, void * inp, void * outp) -{ - struct internal_lineno *in = (struct internal_lineno *) inp; - struct external_lineno *ext = (struct external_lineno *) outp; - H_PUT_32 (abfd, in->l_addr.l_symndx, ext->l_addr.l_symndx); - - PUT_LINENO_LNNO (abfd, in->l_lnno, ext); - return LINESZ; -} - -#endif /* NO_COFF_LINENOS */ - -static void -coff_swap_aouthdr_in (bfd * abfd, void * aouthdr_ext1, void * aouthdr_int1) -{ - AOUTHDR *aouthdr_ext; - struct internal_aouthdr *aouthdr_int; - - aouthdr_ext = (AOUTHDR *) aouthdr_ext1; - aouthdr_int = (struct internal_aouthdr *) aouthdr_int1; - aouthdr_int->magic = H_GET_16 (abfd, aouthdr_ext->magic); - aouthdr_int->vstamp = H_GET_16 (abfd, aouthdr_ext->vstamp); - aouthdr_int->tsize = GET_AOUTHDR_TSIZE (abfd, aouthdr_ext->tsize); - aouthdr_int->dsize = GET_AOUTHDR_DSIZE (abfd, aouthdr_ext->dsize); - aouthdr_int->bsize = GET_AOUTHDR_BSIZE (abfd, aouthdr_ext->bsize); - aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry); - aouthdr_int->text_start = - GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start); - aouthdr_int->data_start = - GET_AOUTHDR_DATA_START (abfd, aouthdr_ext->data_start); - -#ifdef I960 - aouthdr_int->tagentries = H_GET_32 (abfd, aouthdr_ext->tagentries); -#endif - -#ifdef APOLLO_M68 - H_PUT_32 (abfd, aouthdr_int->o_inlib, aouthdr_ext->o_inlib); - H_PUT_32 (abfd, aouthdr_int->o_sri, aouthdr_ext->o_sri); - H_PUT_32 (abfd, aouthdr_int->vid[0], aouthdr_ext->vid); - H_PUT_32 (abfd, aouthdr_int->vid[1], aouthdr_ext->vid + 4); -#endif - -#ifdef RS6000COFF_C -#ifdef XCOFF64 - aouthdr_int->o_toc = H_GET_64 (abfd, aouthdr_ext->o_toc); -#else - aouthdr_int->o_toc = H_GET_32 (abfd, aouthdr_ext->o_toc); -#endif - aouthdr_int->o_snentry = H_GET_16 (abfd, aouthdr_ext->o_snentry); - aouthdr_int->o_sntext = H_GET_16 (abfd, aouthdr_ext->o_sntext); - aouthdr_int->o_sndata = H_GET_16 (abfd, aouthdr_ext->o_sndata); - aouthdr_int->o_sntoc = H_GET_16 (abfd, aouthdr_ext->o_sntoc); - aouthdr_int->o_snloader = H_GET_16 (abfd, aouthdr_ext->o_snloader); - aouthdr_int->o_snbss = H_GET_16 (abfd, aouthdr_ext->o_snbss); - aouthdr_int->o_algntext = H_GET_16 (abfd, aouthdr_ext->o_algntext); - aouthdr_int->o_algndata = H_GET_16 (abfd, aouthdr_ext->o_algndata); - aouthdr_int->o_modtype = H_GET_16 (abfd, aouthdr_ext->o_modtype); - aouthdr_int->o_cputype = H_GET_16 (abfd, aouthdr_ext->o_cputype); -#ifdef XCOFF64 - aouthdr_int->o_maxstack = H_GET_64 (abfd, aouthdr_ext->o_maxstack); - aouthdr_int->o_maxdata = H_GET_64 (abfd, aouthdr_ext->o_maxdata); -#else - aouthdr_int->o_maxstack = H_GET_32 (abfd, aouthdr_ext->o_maxstack); - aouthdr_int->o_maxdata = H_GET_32 (abfd, aouthdr_ext->o_maxdata); -#endif -#endif - -#ifdef MIPSECOFF - aouthdr_int->bss_start = H_GET_32 (abfd, aouthdr_ext->bss_start); - aouthdr_int->gp_value = H_GET_32 (abfd, aouthdr_ext->gp_value); - aouthdr_int->gprmask = H_GET_32 (abfd, aouthdr_ext->gprmask); - aouthdr_int->cprmask[0] = H_GET_32 (abfd, aouthdr_ext->cprmask[0]); - aouthdr_int->cprmask[1] = H_GET_32 (abfd, aouthdr_ext->cprmask[1]); - aouthdr_int->cprmask[2] = H_GET_32 (abfd, aouthdr_ext->cprmask[2]); - aouthdr_int->cprmask[3] = H_GET_32 (abfd, aouthdr_ext->cprmask[3]); -#endif - -#ifdef ALPHAECOFF - aouthdr_int->bss_start = H_GET_64 (abfd, aouthdr_ext->bss_start); - aouthdr_int->gp_value = H_GET_64 (abfd, aouthdr_ext->gp_value); - aouthdr_int->gprmask = H_GET_32 (abfd, aouthdr_ext->gprmask); - aouthdr_int->fprmask = H_GET_32 (abfd, aouthdr_ext->fprmask); -#endif -} - -static unsigned int -coff_swap_aouthdr_out (bfd * abfd, void * in, void * out) -{ - struct internal_aouthdr *aouthdr_in = (struct internal_aouthdr *) in; - AOUTHDR *aouthdr_out = (AOUTHDR *) out; - - H_PUT_16 (abfd, aouthdr_in->magic, aouthdr_out->magic); - H_PUT_16 (abfd, aouthdr_in->vstamp, aouthdr_out->vstamp); - PUT_AOUTHDR_TSIZE (abfd, aouthdr_in->tsize, aouthdr_out->tsize); - PUT_AOUTHDR_DSIZE (abfd, aouthdr_in->dsize, aouthdr_out->dsize); - PUT_AOUTHDR_BSIZE (abfd, aouthdr_in->bsize, aouthdr_out->bsize); - PUT_AOUTHDR_ENTRY (abfd, aouthdr_in->entry, aouthdr_out->entry); - PUT_AOUTHDR_TEXT_START (abfd, aouthdr_in->text_start, - aouthdr_out->text_start); - PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, - aouthdr_out->data_start); - -#ifdef I960 - H_PUT_32 (abfd, aouthdr_in->tagentries, aouthdr_out->tagentries); -#endif - -#ifdef RS6000COFF_C -#ifdef XCOFF64 - H_PUT_64 (abfd, aouthdr_in->o_toc, aouthdr_out->o_toc); -#else - H_PUT_32 (abfd, aouthdr_in->o_toc, aouthdr_out->o_toc); -#endif - H_PUT_16 (abfd, aouthdr_in->o_snentry, aouthdr_out->o_snentry); - H_PUT_16 (abfd, aouthdr_in->o_sntext, aouthdr_out->o_sntext); - H_PUT_16 (abfd, aouthdr_in->o_sndata, aouthdr_out->o_sndata); - H_PUT_16 (abfd, aouthdr_in->o_sntoc, aouthdr_out->o_sntoc); - H_PUT_16 (abfd, aouthdr_in->o_snloader, aouthdr_out->o_snloader); - H_PUT_16 (abfd, aouthdr_in->o_snbss, aouthdr_out->o_snbss); - H_PUT_16 (abfd, aouthdr_in->o_algntext, aouthdr_out->o_algntext); - H_PUT_16 (abfd, aouthdr_in->o_algndata, aouthdr_out->o_algndata); - H_PUT_16 (abfd, aouthdr_in->o_modtype, aouthdr_out->o_modtype); - H_PUT_16 (abfd, aouthdr_in->o_cputype, aouthdr_out->o_cputype); -#ifdef XCOFF64 - H_PUT_64 (abfd, aouthdr_in->o_maxstack, aouthdr_out->o_maxstack); - H_PUT_64 (abfd, aouthdr_in->o_maxdata, aouthdr_out->o_maxdata); -#else - H_PUT_32 (abfd, aouthdr_in->o_maxstack, aouthdr_out->o_maxstack); - H_PUT_32 (abfd, aouthdr_in->o_maxdata, aouthdr_out->o_maxdata); -#endif - memset (aouthdr_out->o_resv2, 0, sizeof aouthdr_out->o_resv2); -#ifdef XCOFF64 - memset (aouthdr_out->o_debugger, 0, sizeof aouthdr_out->o_debugger); - memset (aouthdr_out->o_resv3, 0, sizeof aouthdr_out->o_resv3); -#endif -#endif - -#ifdef MIPSECOFF - H_PUT_32 (abfd, aouthdr_in->bss_start, aouthdr_out->bss_start); - H_PUT_32 (abfd, aouthdr_in->gp_value, aouthdr_out->gp_value); - H_PUT_32 (abfd, aouthdr_in->gprmask, aouthdr_out->gprmask); - H_PUT_32 (abfd, aouthdr_in->cprmask[0], aouthdr_out->cprmask[0]); - H_PUT_32 (abfd, aouthdr_in->cprmask[1], aouthdr_out->cprmask[1]); - H_PUT_32 (abfd, aouthdr_in->cprmask[2], aouthdr_out->cprmask[2]); - H_PUT_32 (abfd, aouthdr_in->cprmask[3], aouthdr_out->cprmask[3]); -#endif - -#ifdef ALPHAECOFF - /* FIXME: What does bldrev mean? */ - H_PUT_16 (abfd, 2, aouthdr_out->bldrev); - H_PUT_16 (abfd, 0, aouthdr_out->padding); - H_PUT_64 (abfd, aouthdr_in->bss_start, aouthdr_out->bss_start); - H_PUT_64 (abfd, aouthdr_in->gp_value, aouthdr_out->gp_value); - H_PUT_32 (abfd, aouthdr_in->gprmask, aouthdr_out->gprmask); - H_PUT_32 (abfd, aouthdr_in->fprmask, aouthdr_out->fprmask); -#endif - - return AOUTSZ; -} - -static void -coff_swap_scnhdr_in (bfd * abfd, void * ext, void * in) -{ - SCNHDR *scnhdr_ext = (SCNHDR *) ext; - struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; - -#ifdef COFF_ADJUST_SCNHDR_IN_PRE - COFF_ADJUST_SCNHDR_IN_PRE (abfd, ext, in); -#endif - memcpy (scnhdr_int->s_name, scnhdr_ext->s_name, sizeof (scnhdr_int->s_name)); - - scnhdr_int->s_vaddr = GET_SCNHDR_VADDR (abfd, scnhdr_ext->s_vaddr); - scnhdr_int->s_paddr = GET_SCNHDR_PADDR (abfd, scnhdr_ext->s_paddr); - scnhdr_int->s_size = GET_SCNHDR_SIZE (abfd, scnhdr_ext->s_size); - - scnhdr_int->s_scnptr = GET_SCNHDR_SCNPTR (abfd, scnhdr_ext->s_scnptr); - scnhdr_int->s_relptr = GET_SCNHDR_RELPTR (abfd, scnhdr_ext->s_relptr); - scnhdr_int->s_lnnoptr = GET_SCNHDR_LNNOPTR (abfd, scnhdr_ext->s_lnnoptr); - scnhdr_int->s_flags = GET_SCNHDR_FLAGS (abfd, scnhdr_ext->s_flags); - scnhdr_int->s_nreloc = GET_SCNHDR_NRELOC (abfd, scnhdr_ext->s_nreloc); - scnhdr_int->s_nlnno = GET_SCNHDR_NLNNO (abfd, scnhdr_ext->s_nlnno); -#ifdef I960 - scnhdr_int->s_align = GET_SCNHDR_ALIGN (abfd, scnhdr_ext->s_align); -#endif -#ifdef COFF_ADJUST_SCNHDR_IN_POST - COFF_ADJUST_SCNHDR_IN_POST (abfd, ext, in); -#endif -} - -static unsigned int -coff_swap_scnhdr_out (bfd * abfd, void * in, void * out) -{ - struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; - SCNHDR *scnhdr_ext = (SCNHDR *) out; - unsigned int ret = bfd_coff_scnhsz (abfd); - -#ifdef COFF_ADJUST_SCNHDR_OUT_PRE - COFF_ADJUST_SCNHDR_OUT_PRE (abfd, in, out); -#endif - memcpy (scnhdr_ext->s_name, scnhdr_int->s_name, sizeof (scnhdr_int->s_name)); - - PUT_SCNHDR_VADDR (abfd, scnhdr_int->s_vaddr, scnhdr_ext->s_vaddr); - PUT_SCNHDR_PADDR (abfd, scnhdr_int->s_paddr, scnhdr_ext->s_paddr); - PUT_SCNHDR_SIZE (abfd, scnhdr_int->s_size, scnhdr_ext->s_size); - PUT_SCNHDR_SCNPTR (abfd, scnhdr_int->s_scnptr, scnhdr_ext->s_scnptr); - PUT_SCNHDR_RELPTR (abfd, scnhdr_int->s_relptr, scnhdr_ext->s_relptr); - PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, scnhdr_ext->s_lnnoptr); - PUT_SCNHDR_FLAGS (abfd, scnhdr_int->s_flags, scnhdr_ext->s_flags); -#if defined(M88) - H_PUT_32 (abfd, scnhdr_int->s_nlnno, scnhdr_ext->s_nlnno); - H_PUT_32 (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc); -#else - if (scnhdr_int->s_nlnno <= MAX_SCNHDR_NLNNO) - PUT_SCNHDR_NLNNO (abfd, scnhdr_int->s_nlnno, scnhdr_ext->s_nlnno); - else - { - char buf[sizeof (scnhdr_int->s_name) + 1]; - - memcpy (buf, scnhdr_int->s_name, sizeof (scnhdr_int->s_name)); - buf[sizeof (scnhdr_int->s_name)] = '\0'; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: %s: line number overflow: 0x%lx > 0xffff"), - abfd, buf, scnhdr_int->s_nlnno); - PUT_SCNHDR_NLNNO (abfd, 0xffff, scnhdr_ext->s_nlnno); - } - - if (scnhdr_int->s_nreloc <= MAX_SCNHDR_NRELOC) - PUT_SCNHDR_NRELOC (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc); - else - { - char buf[sizeof (scnhdr_int->s_name) + 1]; - - memcpy (buf, scnhdr_int->s_name, sizeof (scnhdr_int->s_name)); - buf[sizeof (scnhdr_int->s_name)] = '\0'; - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %s: reloc overflow: 0x%lx > 0xffff"), - abfd, buf, scnhdr_int->s_nreloc); - bfd_set_error (bfd_error_file_truncated); - PUT_SCNHDR_NRELOC (abfd, 0xffff, scnhdr_ext->s_nreloc); - ret = 0; - } -#endif - -#ifdef I960 - PUT_SCNHDR_ALIGN (abfd, scnhdr_int->s_align, scnhdr_ext->s_align); -#endif -#ifdef COFF_ADJUST_SCNHDR_OUT_POST - COFF_ADJUST_SCNHDR_OUT_POST (abfd, in, out); -#endif - return ret; -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-aarch64.c b/sdcc/support/sdbinutils/bfd/cpu-aarch64.c deleted file mode 100644 index 44cee6c98..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-aarch64.c +++ /dev/null @@ -1,127 +0,0 @@ -/* BFD support for AArch64. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Contributed by ARM Ltd. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING3. If not, - see . */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" - -/* This routine is provided two arch_infos and works out which Aarch64 - machine which would be compatible with both and returns a pointer - to its info structure. */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type * a, const bfd_arch_info_type * b) -{ - /* If a & b are for different architecture we can do nothing. */ - if (a->arch != b->arch) - return NULL; - - /* If a & b are for the same machine then all is well. */ - if (a->mach == b->mach) - return a; - - /* Don't allow mixing ilp32 with lp64. */ - if ((a->mach & bfd_mach_aarch64_ilp32) != (b->mach & bfd_mach_aarch64_ilp32)) - return NULL; - - /* Otherwise if either a or b is the 'default' machine - then it can be polymorphed into the other. */ - if (a->the_default) - return b; - - if (b->the_default) - return a; - - /* So far all newer cores are - supersets of previous cores. */ - if (a->mach < b->mach) - return b; - else if (a->mach > b->mach) - return a; - - /* Never reached! */ - return NULL; -} - -static struct -{ - unsigned int mach; - char *name; -} -processors[] = -{ - /* These two are example CPUs supported in GCC, once we have real - CPUs they will be removed. */ - { bfd_mach_aarch64, "example-1" }, - { bfd_mach_aarch64, "example-2" } -}; - -static bfd_boolean -scan (const struct bfd_arch_info *info, const char *string) -{ - int i; - - /* First test for an exact match. */ - if (strcasecmp (string, info->printable_name) == 0) - return TRUE; - - /* Next check for a processor name instead of an Architecture name. */ - for (i = sizeof (processors) / sizeof (processors[0]); i--;) - { - if (strcasecmp (string, processors[i].name) == 0) - break; - } - - if (i != -1 && info->mach == processors[i].mach) - return TRUE; - - /* Finally check for the default architecture. */ - if (strcasecmp (string, "aarch64") == 0) - return info->the_default; - - return FALSE; -} - -#define N(NUMBER, PRINT, WORDSIZE, DEFAULT, NEXT) \ - { WORDSIZE, WORDSIZE, 8, bfd_arch_aarch64, NUMBER, \ - "aarch64", PRINT, 4, DEFAULT, compatible, scan, \ - bfd_arch_default_fill, NEXT } - -static const bfd_arch_info_type bfd_aarch64_arch_ilp32 = - N (bfd_mach_aarch64_ilp32, "aarch64:ilp32", 32, FALSE, NULL); - -const bfd_arch_info_type bfd_aarch64_arch = - N (0, "aarch64", 64, TRUE, &bfd_aarch64_arch_ilp32); - -bfd_boolean -bfd_is_aarch64_special_symbol_name (const char *name, int type) -{ - if (!name || name[0] != '$') - return FALSE; - if (name[1] == 'x' || name[1] == 'd') - type &= BFD_AARCH64_SPECIAL_SYM_TYPE_MAP; - else if (name[1] == 'm' || name[1] == 'f' || name[1] == 'p') - type &= BFD_AARCH64_SPECIAL_SYM_TYPE_TAG; - else - return FALSE; - - return (type != 0 && (name[2] == 0 || name[2] == '.')); -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-alpha.c b/sdcc/support/sdbinutils/bfd/cpu-alpha.c deleted file mode 100644 index b0eb7ece5..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-alpha.c +++ /dev/null @@ -1,53 +0,0 @@ -/* BFD support for the Alpha architecture. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ - { \ - BITS_WORD, /* bits in a word */ \ - BITS_ADDR, /* bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_alpha, \ - NUMBER, \ - "alpha", \ - PRINT, \ - 3, \ - DEFAULT, \ - bfd_default_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - NEXT, \ - } - -#define NN(index) (&arch_info_struct[index]) - -/* These exist only so that we can reasonably disassemble PALcode. */ -static const bfd_arch_info_type arch_info_struct[] = -{ - N (64, 64, bfd_mach_alpha_ev4, "alpha:ev4", FALSE, NN(1)), - N (64, 64, bfd_mach_alpha_ev5, "alpha:ev5", FALSE, NN(2)), - N (64, 64, bfd_mach_alpha_ev6, "alpha:ev6", FALSE, 0), -}; - -const bfd_arch_info_type bfd_alpha_arch = - N (64, 64, 0, "alpha", TRUE, NN(0)); diff --git a/sdcc/support/sdbinutils/bfd/cpu-arc.c b/sdcc/support/sdbinutils/bfd/cpu-arc.c deleted file mode 100644 index 7a7b6f6ab..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-arc.c +++ /dev/null @@ -1,100 +0,0 @@ -/* BFD support for the ARC processor - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed by Doug Evans (dje@cygnus.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -static const bfd_arch_info_type * -arc_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b); - -#define ARC(mach, print_name, default_p, next) \ -{ \ - 32, /* 32 bits in a word */ \ - 32, /* 32 bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_arc, \ - mach, \ - "arc", \ - print_name, \ - 4, /* section alignment power */ \ - default_p, \ - arc_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - next, \ - } - -static const bfd_arch_info_type arch_info_struct[] = -{ - ARC (bfd_mach_arc_arc600, "A6" , FALSE, &arch_info_struct[1]), - ARC (bfd_mach_arc_arc601, "ARC601", FALSE, &arch_info_struct[2]), - ARC (bfd_mach_arc_arc700, "ARC700", FALSE, &arch_info_struct[3]), - ARC (bfd_mach_arc_arc700, "A7", FALSE, &arch_info_struct[4]), - ARC (bfd_mach_arc_arcv2, "ARCv2", FALSE, &arch_info_struct[5]), - ARC (bfd_mach_arc_arcv2, "EM", FALSE, &arch_info_struct[6]), - ARC (bfd_mach_arc_arcv2, "HS", FALSE, NULL), -}; - -const bfd_arch_info_type bfd_arc_arch = - ARC (bfd_mach_arc_arc600, "ARC600", TRUE, &arch_info_struct[0]); - -/* ARC-specific "compatible" function. The general rule is that if A and B are - compatible, then this function should return architecture that is more - "feature-rich", that is, can run both A and B. ARCv2, EM and HS all has - same mach number, so bfd_default_compatible assumes they are the same, and - returns an A. That causes issues with GDB, because GDB assumes that if - machines are compatible, then "compatible ()" always returns same machine - regardless of argument order. As a result GDB gets confused because, for - example, compatible (ARCv2, EM) returns ARCv2, but compatible (EM, ARCv2) - returns EM, hence GDB is not sure if they are compatible and prints a - warning. */ - -static const bfd_arch_info_type * -arc_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) -{ - const bfd_arch_info_type * const em = &arch_info_struct[5]; - const bfd_arch_info_type * const hs = &arch_info_struct[6]; - - /* Trivial case where a and b is the same instance. Some callers already - check this condition but some do not and get an invalid result. */ - if (a == b) - return a; - - /* If a & b are for different architecture we can do nothing. */ - if (a->arch != b->arch) - return NULL; - - if (a->bits_per_word != b->bits_per_word) - return NULL; - - /* ARCv2|EM and EM. */ - if ((a->mach == bfd_mach_arc_arcv2 && b == em) - || (b->mach == bfd_mach_arc_arcv2 && a == em)) - return em; - - /* ARCv2|HS and HS. */ - if ((a->mach == bfd_mach_arc_arcv2 && b == hs) - || (b->mach == bfd_mach_arc_arcv2 && a == hs)) - return hs; - - return bfd_default_compatible (a, b); -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-arm.c b/sdcc/support/sdbinutils/bfd/cpu-arm.c deleted file mode 100644 index 151f27367..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-arm.c +++ /dev/null @@ -1,439 +0,0 @@ -/* BFD support for the ARM processor - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" - -/* This routine is provided two arch_infos and works out which ARM - machine which would be compatible with both and returns a pointer - to its info structure. */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) -{ - /* If a & b are for different architecture we can do nothing. */ - if (a->arch != b->arch) - return NULL; - - /* If a & b are for the same machine then all is well. */ - if (a->mach == b->mach) - return a; - - /* Otherwise if either a or b is the 'default' machine - then it can be polymorphed into the other. */ - if (a->the_default) - return b; - - if (b->the_default) - return a; - - /* So far all newer ARM architecture cores are - supersets of previous cores. */ - if (a->mach < b->mach) - return b; - else if (a->mach > b->mach) - return a; - - /* Never reached! */ - return NULL; -} - -static struct -{ - unsigned int mach; - char * name; -} -processors[] = -{ - { bfd_mach_arm_2, "arm2" }, - { bfd_mach_arm_2a, "arm250" }, - { bfd_mach_arm_2a, "arm3" }, - { bfd_mach_arm_3, "arm6" }, - { bfd_mach_arm_3, "arm60" }, - { bfd_mach_arm_3, "arm600" }, - { bfd_mach_arm_3, "arm610" }, - { bfd_mach_arm_3, "arm7" }, - { bfd_mach_arm_3, "arm710" }, - { bfd_mach_arm_3, "arm7500" }, - { bfd_mach_arm_3, "arm7d" }, - { bfd_mach_arm_3, "arm7di" }, - { bfd_mach_arm_3M, "arm7dm" }, - { bfd_mach_arm_3M, "arm7dmi" }, - { bfd_mach_arm_4T, "arm7tdmi" }, - { bfd_mach_arm_4, "arm8" }, - { bfd_mach_arm_4, "arm810" }, - { bfd_mach_arm_4, "arm9" }, - { bfd_mach_arm_4, "arm920" }, - { bfd_mach_arm_4T, "arm920t" }, - { bfd_mach_arm_4T, "arm9tdmi" }, - { bfd_mach_arm_4, "sa1" }, - { bfd_mach_arm_4, "strongarm"}, - { bfd_mach_arm_4, "strongarm110" }, - { bfd_mach_arm_4, "strongarm1100" }, - { bfd_mach_arm_XScale, "xscale" }, - { bfd_mach_arm_ep9312, "ep9312" }, - { bfd_mach_arm_iWMMXt, "iwmmxt" }, - { bfd_mach_arm_iWMMXt2, "iwmmxt2" }, - { bfd_mach_arm_unknown, "arm_any" } -}; - -static bfd_boolean -scan (const struct bfd_arch_info *info, const char *string) -{ - int i; - - /* First test for an exact match. */ - if (strcasecmp (string, info->printable_name) == 0) - return TRUE; - - /* Next check for a processor name instead of an Architecture name. */ - for (i = sizeof (processors) / sizeof (processors[0]); i--;) - { - if (strcasecmp (string, processors [i].name) == 0) - break; - } - - if (i != -1 && info->mach == processors [i].mach) - return TRUE; - - /* Finally check for the default architecture. */ - if (strcasecmp (string, "arm") == 0) - return info->the_default; - - return FALSE; -} - -#define N(number, print, default, next) \ -{ 32, 32, 8, bfd_arch_arm, number, "arm", print, 4, default, compatible, \ - scan, bfd_arch_default_fill, next } - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (bfd_mach_arm_2, "armv2", FALSE, & arch_info_struct[1]), - N (bfd_mach_arm_2a, "armv2a", FALSE, & arch_info_struct[2]), - N (bfd_mach_arm_3, "armv3", FALSE, & arch_info_struct[3]), - N (bfd_mach_arm_3M, "armv3m", FALSE, & arch_info_struct[4]), - N (bfd_mach_arm_4, "armv4", FALSE, & arch_info_struct[5]), - N (bfd_mach_arm_4T, "armv4t", FALSE, & arch_info_struct[6]), - N (bfd_mach_arm_5, "armv5", FALSE, & arch_info_struct[7]), - N (bfd_mach_arm_5T, "armv5t", FALSE, & arch_info_struct[8]), - N (bfd_mach_arm_5TE, "armv5te", FALSE, & arch_info_struct[9]), - N (bfd_mach_arm_XScale, "xscale", FALSE, & arch_info_struct[10]), - N (bfd_mach_arm_ep9312, "ep9312", FALSE, & arch_info_struct[11]), - N (bfd_mach_arm_iWMMXt, "iwmmxt", FALSE, & arch_info_struct[12]), - N (bfd_mach_arm_iWMMXt2, "iwmmxt2", FALSE, & arch_info_struct[13]), - N (bfd_mach_arm_unknown, "arm_any", FALSE, NULL) -}; - -const bfd_arch_info_type bfd_arm_arch = - N (0, "arm", TRUE, & arch_info_struct[0]); - -/* Support functions used by both the COFF and ELF versions of the ARM port. */ - -/* Handle the merging of the 'machine' settings of input file IBFD - and an output file OBFD. These values actually represent the - different possible ARM architecture variants. - Returns TRUE if they were merged successfully or FALSE otherwise. */ - -bfd_boolean -bfd_arm_merge_machines (bfd *ibfd, bfd *obfd) -{ - unsigned int in = bfd_get_mach (ibfd); - unsigned int out = bfd_get_mach (obfd); - - /* If the output architecture is unknown, we now have a value to set. */ - if (out == bfd_mach_arm_unknown) - bfd_set_arch_mach (obfd, bfd_arch_arm, in); - - /* If the input architecture is unknown, - then so must be the output architecture. */ - else if (in == bfd_mach_arm_unknown) - /* FIXME: We ought to have some way to - override this on the command line. */ - bfd_set_arch_mach (obfd, bfd_arch_arm, bfd_mach_arm_unknown); - - /* If they are the same then nothing needs to be done. */ - else if (out == in) - ; - - /* Otherwise the general principle that a earlier architecture can be - linked with a later architecture to produce a binary that will execute - on the later architecture. - - We fail however if we attempt to link a Cirrus EP9312 binary with an - Intel XScale binary, since these architecture have co-processors which - will not both be present on the same physical hardware. */ - else if (in == bfd_mach_arm_ep9312 - && (out == bfd_mach_arm_XScale - || out == bfd_mach_arm_iWMMXt - || out == bfd_mach_arm_iWMMXt2)) - { - /* xgettext: c-format */ - _bfd_error_handler (_("\ -error: %B is compiled for the EP9312, whereas %B is compiled for XScale"), - ibfd, obfd); - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - else if (out == bfd_mach_arm_ep9312 - && (in == bfd_mach_arm_XScale - || in == bfd_mach_arm_iWMMXt - || in == bfd_mach_arm_iWMMXt2)) - { - /* xgettext: c-format */ - _bfd_error_handler (_("\ -error: %B is compiled for the EP9312, whereas %B is compiled for XScale"), - obfd, ibfd); - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - else if (in > out) - bfd_set_arch_mach (obfd, bfd_arch_arm, in); - /* else - Nothing to do. */ - - return TRUE; -} - -typedef struct -{ - unsigned char namesz[4]; /* Size of entry's owner string. */ - unsigned char descsz[4]; /* Size of the note descriptor. */ - unsigned char type[4]; /* Interpretation of the descriptor. */ - char name[1]; /* Start of the name+desc data. */ -} arm_Note; - -static bfd_boolean -arm_check_note (bfd *abfd, - bfd_byte *buffer, - bfd_size_type buffer_size, - const char *expected_name, - char **description_return) -{ - unsigned long namesz; - unsigned long descsz; - unsigned long type; - char * descr; - - if (buffer_size < offsetof (arm_Note, name)) - return FALSE; - - /* We have to extract the values this way to allow for a - host whose endian-ness is different from the target. */ - namesz = bfd_get_32 (abfd, buffer); - descsz = bfd_get_32 (abfd, buffer + offsetof (arm_Note, descsz)); - type = bfd_get_32 (abfd, buffer + offsetof (arm_Note, type)); - descr = (char *) buffer + offsetof (arm_Note, name); - - /* Check for buffer overflow. */ - if (namesz + descsz + offsetof (arm_Note, name) > buffer_size) - return FALSE; - - if (expected_name == NULL) - { - if (namesz != 0) - return FALSE; - } - else - { - if (namesz != ((strlen (expected_name) + 1 + 3) & ~3)) - return FALSE; - - if (strcmp (descr, expected_name) != 0) - return FALSE; - - descr += (namesz + 3) & ~3; - } - - /* FIXME: We should probably check the type as well. */ - (void) type; - - if (description_return != NULL) - * description_return = descr; - - return TRUE; -} - -#define NOTE_ARCH_STRING "arch: " - -bfd_boolean -bfd_arm_update_notes (bfd *abfd, const char *note_section) -{ - asection * arm_arch_section; - bfd_size_type buffer_size; - bfd_byte * buffer; - char * arch_string; - char * expected; - - /* Look for a note section. If one is present check the architecture - string encoded in it, and set it to the current architecture if it is - different. */ - arm_arch_section = bfd_get_section_by_name (abfd, note_section); - - if (arm_arch_section == NULL) - return TRUE; - - buffer_size = arm_arch_section->size; - if (buffer_size == 0) - return FALSE; - - if (!bfd_malloc_and_get_section (abfd, arm_arch_section, &buffer)) - goto FAIL; - - /* Parse the note. */ - if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string)) - goto FAIL; - - /* Check the architecture in the note against the architecture of the bfd. */ - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_arm_unknown: expected = "unknown"; break; - case bfd_mach_arm_2: expected = "armv2"; break; - case bfd_mach_arm_2a: expected = "armv2a"; break; - case bfd_mach_arm_3: expected = "armv3"; break; - case bfd_mach_arm_3M: expected = "armv3M"; break; - case bfd_mach_arm_4: expected = "armv4"; break; - case bfd_mach_arm_4T: expected = "armv4t"; break; - case bfd_mach_arm_5: expected = "armv5"; break; - case bfd_mach_arm_5T: expected = "armv5t"; break; - case bfd_mach_arm_5TE: expected = "armv5te"; break; - case bfd_mach_arm_XScale: expected = "XScale"; break; - case bfd_mach_arm_ep9312: expected = "ep9312"; break; - case bfd_mach_arm_iWMMXt: expected = "iWMMXt"; break; - case bfd_mach_arm_iWMMXt2: expected = "iWMMXt2"; break; - } - - if (strcmp (arch_string, expected) != 0) - { - strcpy ((char *) buffer + (offsetof (arm_Note, name) - + ((strlen (NOTE_ARCH_STRING) + 3) & ~3)), - expected); - - if (! bfd_set_section_contents (abfd, arm_arch_section, buffer, - (file_ptr) 0, buffer_size)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("warning: unable to update contents of %s section in %B"), - note_section, abfd); - goto FAIL; - } - } - - free (buffer); - return TRUE; - - FAIL: - if (buffer != NULL) - free (buffer); - return FALSE; -} - - -static struct -{ - const char * string; - unsigned int mach; -} -architectures[] = -{ - { "armv2", bfd_mach_arm_2 }, - { "armv2a", bfd_mach_arm_2a }, - { "armv3", bfd_mach_arm_3 }, - { "armv3M", bfd_mach_arm_3M }, - { "armv4", bfd_mach_arm_4 }, - { "armv4t", bfd_mach_arm_4T }, - { "armv5", bfd_mach_arm_5 }, - { "armv5t", bfd_mach_arm_5T }, - { "armv5te", bfd_mach_arm_5TE }, - { "XScale", bfd_mach_arm_XScale }, - { "ep9312", bfd_mach_arm_ep9312 }, - { "iWMMXt", bfd_mach_arm_iWMMXt }, - { "iWMMXt2", bfd_mach_arm_iWMMXt2 }, - { "arm_any", bfd_mach_arm_unknown } -}; - -/* Extract the machine number stored in a note section. */ -unsigned int -bfd_arm_get_mach_from_notes (bfd *abfd, const char *note_section) -{ - asection * arm_arch_section; - bfd_size_type buffer_size; - bfd_byte * buffer; - char * arch_string; - int i; - - /* Look for a note section. If one is present check the architecture - string encoded in it, and set it to the current architecture if it is - different. */ - arm_arch_section = bfd_get_section_by_name (abfd, note_section); - - if (arm_arch_section == NULL) - return bfd_mach_arm_unknown; - - buffer_size = arm_arch_section->size; - if (buffer_size == 0) - return bfd_mach_arm_unknown; - - if (!bfd_malloc_and_get_section (abfd, arm_arch_section, &buffer)) - goto FAIL; - - /* Parse the note. */ - if (! arm_check_note (abfd, buffer, buffer_size, NOTE_ARCH_STRING, & arch_string)) - goto FAIL; - - /* Interpret the architecture string. */ - for (i = ARRAY_SIZE (architectures); i--;) - if (strcmp (arch_string, architectures[i].string) == 0) - { - free (buffer); - return architectures[i].mach; - } - - FAIL: - if (buffer != NULL) - free (buffer); - return bfd_mach_arm_unknown; -} - -bfd_boolean -bfd_is_arm_special_symbol_name (const char * name, int type) -{ - /* The ARM compiler outputs several obsolete forms. Recognize them - in addition to the standard $a, $t and $d. We are somewhat loose - in what we accept here, since the full set is not documented. */ - if (!name || name[0] != '$') - return FALSE; - if (name[1] == 'a' || name[1] == 't' || name[1] == 'd') - type &= BFD_ARM_SPECIAL_SYM_TYPE_MAP; - else if (name[1] == 'm' || name[1] == 'f' || name[1] == 'p') - type &= BFD_ARM_SPECIAL_SYM_TYPE_TAG; - else if (name[1] >= 'a' && name[1] <= 'z') - type &= BFD_ARM_SPECIAL_SYM_TYPE_OTHER; - else - return FALSE; - - return (type != 0 && (name[2] == 0 || name[2] == '.')); -} - diff --git a/sdcc/support/sdbinutils/bfd/cpu-avr.c b/sdcc/support/sdbinutils/bfd/cpu-avr.c deleted file mode 100644 index 16602825e..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-avr.c +++ /dev/null @@ -1,163 +0,0 @@ -/* BFD library support routines for the AVR architecture. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Denis Chertykov - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* This routine is provided two arch_infos and works out which AVR - machine which would be compatible with both and returns a pointer - to its info structure. */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type * a, - const bfd_arch_info_type * b) -{ - /* If a & b are for different architectures we can do nothing. */ - if (a->arch != b->arch) - return NULL; - - if (a->mach == b->mach) - return a; - - /* avr-6 is compatible only with itself as its call convention is not - compatible with other avr (the mcu saves the return address on 3 bytes - instead of 2). */ - if (a->mach == bfd_mach_avr6 || b->mach == bfd_mach_avr6) - return NULL; - - if (a->mach < bfd_mach_avr6 && b->mach < bfd_mach_avr6) - { - /* Special case for ATmega[16]03 (avr:3) and ATmega83 (avr:4). */ - if ((a->mach == bfd_mach_avr3 && b->mach == bfd_mach_avr4) - || (a->mach == bfd_mach_avr4 && b->mach == bfd_mach_avr3)) - return NULL; - - if (a->mach <= b->mach) - return b; - - if (a->mach >= b->mach) - return a; - } - - if (a->mach == bfd_mach_avr2 && b->mach == bfd_mach_avr25) - return a; - if (a->mach == bfd_mach_avr25 && b->mach == bfd_mach_avr2) - return b; - - if (a->mach == bfd_mach_avr3 && b->mach == bfd_mach_avr31) - return a; - if (a->mach == bfd_mach_avr31 && b->mach == bfd_mach_avr3) - return b; - if (a->mach == bfd_mach_avr3 && b->mach == bfd_mach_avr35) - return a; - if (a->mach == bfd_mach_avr35 && b->mach == bfd_mach_avr3) - return b; - - if (a->mach == bfd_mach_avr5 && b->mach == bfd_mach_avr51) - return a; - if (a->mach == bfd_mach_avr51 && b->mach == bfd_mach_avr5) - return b; - - return NULL; -} - -#define N(addr_bits, machine, print, default, next) \ -{ \ - 8, /* 8 bits in a word. */ \ - addr_bits, /* bits in an address. */ \ - 8, /* 8 bits in a byte. */ \ - bfd_arch_avr, \ - machine, /* Machine number. */ \ - "avr", /* Architecture name. */ \ - print, /* Printable name. */ \ - 1, /* Section align power. */ \ - default, /* Is this the default ? */ \ - compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - next \ -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - /* Assembler only. */ - N (16, bfd_mach_avr1, "avr:1", FALSE, & arch_info_struct[1]), - - /* Classic, <= 8K. */ - N (16, bfd_mach_avr2, "avr:2", FALSE, & arch_info_struct[2]), - - /* Classic + MOVW, <= 8K. */ - N (16, bfd_mach_avr25, "avr:25", FALSE, & arch_info_struct[3]), - - /* Classic, > 8K, <= 64K. */ - /* TODO: addr_bits should be 16, but set to 22 for some following - version of GCC (from 4.3) for backward compatibility. */ - N (22, bfd_mach_avr3, "avr:3", FALSE, & arch_info_struct[4]), - - /* Classic, == 128K. */ - N (22, bfd_mach_avr31, "avr:31", FALSE, & arch_info_struct[5]), - - /* Classic + MOVW + JMP/CALL, > 8K, <= 64K. */ - N (16, bfd_mach_avr35, "avr:35", FALSE, & arch_info_struct[6]), - - /* Enhanced, <= 8K. */ - N (16, bfd_mach_avr4, "avr:4", FALSE, & arch_info_struct[7]), - - /* Enhanced, > 8K, <= 64K. */ - /* TODO: addr_bits should be 16, but set to 22 for some following - version of GCC (from 4.3) for backward compatibility. */ - N (22, bfd_mach_avr5, "avr:5", FALSE, & arch_info_struct[8]), - - /* Enhanced, == 128K. */ - N (22, bfd_mach_avr51, "avr:51", FALSE, & arch_info_struct[9]), - - /* 3-Byte PC. */ - N (22, bfd_mach_avr6, "avr:6", FALSE, & arch_info_struct[10]), - - /* Tiny core (AVR Tiny). */ - N (16, bfd_mach_avrtiny, "avr:100", FALSE, & arch_info_struct[11]), - - /* Xmega 1. */ - N (24, bfd_mach_avrxmega1, "avr:101", FALSE, & arch_info_struct[12]), - - /* Xmega 2. */ - N (24, bfd_mach_avrxmega2, "avr:102", FALSE, & arch_info_struct[13]), - - /* Xmega 3. */ - N (24, bfd_mach_avrxmega3, "avr:103", FALSE, & arch_info_struct[14]), - - /* Xmega 4. */ - N (24, bfd_mach_avrxmega4, "avr:104", FALSE, & arch_info_struct[15]), - - /* Xmega 5. */ - N (24, bfd_mach_avrxmega5, "avr:105", FALSE, & arch_info_struct[16]), - - /* Xmega 6. */ - N (24, bfd_mach_avrxmega6, "avr:106", FALSE, & arch_info_struct[17]), - - /* Xmega 7. */ - N (24, bfd_mach_avrxmega7, "avr:107", FALSE, NULL) - -}; - -const bfd_arch_info_type bfd_avr_arch = - N (16, bfd_mach_avr2, "avr", TRUE, & arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-bfin.c b/sdcc/support/sdbinutils/bfd/cpu-bfin.c deleted file mode 100644 index ae4ab28a2..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-bfin.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD Support for the ADI Blackfin processor. - - Copyright (C) 2005-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_bfin_arch = - { - 16, /* Bits in a word. */ - 32, /* Bits in an address. */ - 8, /* Bits in a byte. */ - bfd_arch_bfin, - 0, /* Only one machine. */ - "bfin", /* Arch name. */ - "bfin", /* Arch printable name. */ - 4, /* Section align power. */ - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-cr16.c b/sdcc/support/sdbinutils/bfd/cpu-cr16.c deleted file mode 100644 index 7bf76643a..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-cr16.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the CR16 processor. - Copyright (C) 2007-2018 Free Software Foundation, Inc. - Written by M R Swami Reddy - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - - -const bfd_arch_info_type bfd_cr16_arch = - { - 16, /* 16 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_cr16, /* enum bfd_architecture arch. */ - bfd_mach_cr16, - "cr16", /* Arch name. */ - "cr16", /* Printable name. */ - 1, /* Unsigned int section alignment power. */ - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-cr16c.c b/sdcc/support/sdbinutils/bfd/cpu-cr16c.c deleted file mode 100644 index 757b05308..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-cr16c.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the CR16C processor. - Copyright (C) 2004-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_cr16c_arch = - { - 16, /* 16 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_cr16c, - bfd_mach_cr16c, - "cr16c", - "cr16c", - 1, - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-cris.c b/sdcc/support/sdbinutils/bfd/cpu-cris.c deleted file mode 100644 index 591f33586..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-cris.c +++ /dev/null @@ -1,109 +0,0 @@ -/* BFD support for the Axis CRIS architecture. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Axis Communications AB. - Written by Hans-Peter Nilsson. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* This routine is provided two arch_infos and returns the lowest common - denominator. CRIS v0..v10 vs. v32 are not compatible in general, but - there's a compatible subset for which we provide an arch_info. */ - -static const bfd_arch_info_type * get_compatible - (const bfd_arch_info_type *, const bfd_arch_info_type *); - -static const bfd_arch_info_type * -get_compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b) -{ - /* Arches must match. */ - if (a->arch != b->arch) - return NULL; - - /* If either is the compatible mach, return the other. */ - if (a->mach == bfd_mach_cris_v10_v32) - return b; - if (b->mach == bfd_mach_cris_v10_v32) - return a; - -#if 0 - /* The code below is disabled but kept as a warning. - See ldlang.c:lang_check. Quite illogically, incompatible arches - (as signalled by this function) are only *warned* about, while with - this function signalling compatible ones, we can have the - cris_elf_merge_private_bfd_data function return an error. This is - undoubtedly a FIXME: in general. Also, the - command_line.warn_mismatch flag and the --no-warn-mismatch option - are misnamed for the multitude of ports that signal compatibility: - it is there an error, not a warning. We work around it by - pretending matching machs here. */ - - /* Except for the compatible mach, machs must match. */ - if (a->mach != b->mach) - return NULL; -#endif - - return a; -} - -#define N(NUMBER, PRINT, NEXT) \ - { 32, 32, 8, bfd_arch_cris, NUMBER, "cris", PRINT, 1, FALSE, \ - get_compatible, bfd_default_scan, bfd_arch_default_fill, NEXT } - -static const bfd_arch_info_type bfd_cris_arch_compat_v10_v32 = - N (bfd_mach_cris_v10_v32, "cris:common_v10_v32", NULL); - -static const bfd_arch_info_type bfd_cris_arch_v32 = - N (bfd_mach_cris_v32, "crisv32", &bfd_cris_arch_compat_v10_v32); - -const bfd_arch_info_type bfd_cris_arch = -{ - 32, /* There's 32 bits_per_word. */ - 32, /* There's 32 bits_per_address. */ - 8, /* There's 8 bits_per_byte. */ - bfd_arch_cris, /* One of enum bfd_architecture, defined - in archures.c and provided in - generated header files. */ - bfd_mach_cris_v0_v10, /* Random BFD-internal number for this - machine, similarly listed in - archures.c. Not emitted in output. */ - "cris", /* The arch_name. */ - "cris", /* The printable name is the same. */ - 1, /* Section alignment power; each section - is aligned to (only) 2^1 bytes. */ - TRUE, /* This is the default "machine". */ - get_compatible, /* A function for testing - "machine" compatibility of two - bfd_arch_info_type. */ - bfd_default_scan, /* Check if a bfd_arch_info_type is a - match. */ - bfd_arch_default_fill, /* Default fill. */ - &bfd_cris_arch_v32 /* Pointer to next bfd_arch_info_type in - the same family. */ -}; - -/* - * Local variables: - * eval: (c-set-style "gnu") - * indent-tabs-mode: t - * End: - */ diff --git a/sdcc/support/sdbinutils/bfd/cpu-crx.c b/sdcc/support/sdbinutils/bfd/cpu-crx.c deleted file mode 100644 index eb07c457f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-crx.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the CRX processor. - Copyright (C) 2004-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - - -const bfd_arch_info_type bfd_crx_arch = - { - 16, /* 16 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_crx, /* enum bfd_architecture arch. */ - bfd_mach_crx, - "crx", /* Arch name. */ - "crx", /* Printable name. */ - 1, /* Unsigned int section alignment power. */ - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-d10v.c b/sdcc/support/sdbinutils/bfd/cpu-d10v.c deleted file mode 100644 index 7331a0b11..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-d10v.c +++ /dev/null @@ -1,75 +0,0 @@ -/* BFD support for the D10V processor - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Contributed by Martin Hunt (hunt@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -static const bfd_arch_info_type d10v_ts3_info = -{ - 16, /* 16 bits in a word. */ - 18, /* really 16 bits in an address, but code has 18 bit range. */ - 8, /* 8 bits in a byte. */ - bfd_arch_d10v, - bfd_mach_d10v_ts3, - "d10v", - "d10v:ts3", - 4, /* Section alignment power. */ - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; - -static const bfd_arch_info_type d10v_ts2_info = -{ - 16, - 18, - 8, - bfd_arch_d10v, - bfd_mach_d10v_ts2, - "d10v", - "d10v:ts2", - 4, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - & d10v_ts3_info, -}; - -const bfd_arch_info_type bfd_d10v_arch = -{ - 16, - 18, - 8, - bfd_arch_d10v, - bfd_mach_d10v, - "d10v", - "d10v", - 4, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - & d10v_ts2_info, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-d30v.c b/sdcc/support/sdbinutils/bfd/cpu-d30v.c deleted file mode 100644 index f48a1b4bb..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-d30v.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the Mitsubishi D30V processor - Copyright (C) 1997-2018 Free Software Foundation, Inc. - Contributed by Martin Hunt (hunt@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_d30v_arch = -{ - 32, /* Bits in a word. */ - 32, /* Bits in an address. */ - 8, /* Bits in a byte. */ - bfd_arch_d30v, - 0, - "d30v", - "d30v", - 4, /* Section alignment power. */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-dlx.c b/sdcc/support/sdbinutils/bfd/cpu-dlx.c deleted file mode 100644 index 1cb164d46..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-dlx.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the DLX Microprocessor architecture. - Copyright (C) 2002-2018 Free Software Foundation, Inc. - Hacked by Kuang Hwa Lin - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_dlx_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_dlx, - 0, /* Only 1 machine. */ - "dlx", - "dlx", - 4, - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-epiphany.c b/sdcc/support/sdbinutils/bfd/cpu-epiphany.c deleted file mode 100644 index 47cce252f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-epiphany.c +++ /dev/null @@ -1,58 +0,0 @@ -/* BFD support for the Adapteva EPIPHANY processor. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Contributed by Embecosm on behalf of Adapteva, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_epiphany16_arch = -{ - 32, /* Bits per word */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_epiphany, /* Architecture. */ - bfd_mach_epiphany16, /* Machine. */ - "epiphany", /* Architecture name. */ - "epiphany16", /* Machine name. */ - 1, /* Section align power. */ - FALSE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; - -const bfd_arch_info_type bfd_epiphany_arch = -{ - 32, /* Bits per word - not really true. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_epiphany, /* Architecture. */ - bfd_mach_epiphany32, /* Machine. */ - "epiphany", /* Architecture name. */ - "epiphany32", /* Machine name. */ - 2, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - & bfd_epiphany16_arch /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-fr30.c b/sdcc/support/sdbinutils/bfd/cpu-fr30.c deleted file mode 100644 index ffc9847c2..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-fr30.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the FR30 processor. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_fr30_arch = -{ - 32, /* bits per word */ - 32, /* bits per address */ - 8, /* bits per byte */ - bfd_arch_fr30, /* architecture */ - bfd_mach_fr30, /* machine */ - "fr30", /* architecture name */ - "fr30", /* printable name */ - 4, /* section align power */ - TRUE, /* the default ? */ - bfd_default_compatible, /* architecture comparison fn */ - bfd_default_scan, /* string to architecture convert fn */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* next in list */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-frv.c b/sdcc/support/sdbinutils/bfd/cpu-frv.c deleted file mode 100644 index 84313964a..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-frv.c +++ /dev/null @@ -1,65 +0,0 @@ -/* BFD support for the FRV processor. - Copyright (C) 2002-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#define FRV_ARCH(MACHINE, NAME, DEFAULT, NEXT) \ -{ \ - 32, /* 32 bits in a word */ \ - 32, /* 32 bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_frv, /* architecture */ \ - MACHINE, /* which machine */ \ - "frv", /* architecture name */ \ - NAME, /* machine name */ \ - 4, /* default alignment */ \ - DEFAULT, /* is this the default? */ \ - bfd_default_compatible, /* architecture comparison fn */ \ - bfd_default_scan, /* string to architecture convert fn */ \ - bfd_arch_default_fill, /* Default fill. */ \ - NEXT /* next in list */ \ -} - -static const bfd_arch_info_type arch_info_300 - = FRV_ARCH (bfd_mach_fr300, "fr300", FALSE, (bfd_arch_info_type *)0); - -static const bfd_arch_info_type arch_info_400 - = FRV_ARCH (bfd_mach_fr400, "fr400", FALSE, &arch_info_300); - -static const bfd_arch_info_type arch_info_450 - = FRV_ARCH (bfd_mach_fr450, "fr450", FALSE, &arch_info_400); - -static const bfd_arch_info_type arch_info_500 - = FRV_ARCH (bfd_mach_fr500, "fr500", FALSE, &arch_info_450); - -static const bfd_arch_info_type arch_info_550 - = FRV_ARCH (bfd_mach_fr550, "fr550", FALSE, &arch_info_500); - -static const bfd_arch_info_type arch_info_simple - = FRV_ARCH (bfd_mach_frvsimple, "simple", FALSE, &arch_info_550); - -static const bfd_arch_info_type arch_info_tomcat - = FRV_ARCH (bfd_mach_frvtomcat, "tomcat", FALSE, &arch_info_simple); - -const bfd_arch_info_type bfd_frv_arch - = FRV_ARCH (bfd_mach_frv, "frv", TRUE, &arch_info_tomcat); - diff --git a/sdcc/support/sdbinutils/bfd/cpu-ft32.c b/sdcc/support/sdbinutils/bfd/cpu-ft32.c deleted file mode 100644 index 1a58dbdc2..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-ft32.c +++ /dev/null @@ -1,75 +0,0 @@ -/* BFD support for the ft32 processor. - Copyright (C) 2013-2018 Free Software Foundation, Inc. - Written by FTDI (support@ftdichip.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - - -static const bfd_arch_info_type arch_info_struct[] = - { - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_ft32, /* enum bfd_architecture arch. */ - bfd_mach_ft32, - "ft32", /* Arch name. */ - "ft32", /* Printable name. */ - 2, /* Unsigned int section alignment power. */ - FALSE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[1], - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_ft32, /* enum bfd_architecture arch. */ - bfd_mach_ft32b, - "ft32b", /* Arch name. */ - "ft32b", /* Printable name. */ - 2, /* Unsigned int section alignment power. */ - FALSE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }, - }; - -const bfd_arch_info_type bfd_ft32_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_ft32, /* enum bfd_architecture arch. */ - bfd_mach_ft32, - "ft32", /* Arch name. */ - "ft32", /* Printable name. */ - 2, /* Unsigned int section alignment power. */ - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - arch_info_struct, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-h8300.c b/sdcc/support/sdbinutils/bfd/cpu-h8300.c deleted file mode 100644 index a480575fd..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-h8300.c +++ /dev/null @@ -1,268 +0,0 @@ -/* BFD library support routines for the Renesas H8/300 architecture. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -static bfd_boolean -h8300_scan (const struct bfd_arch_info *info, const char *string) -{ - if (*string != 'h' && *string != 'H') - return FALSE; - - string++; - if (*string != '8') - return FALSE; - - string++; - if (*string == '/') - string++; - - if (*string != '3') - return FALSE; - string++; - if (*string != '0') - return FALSE; - string++; - if (*string != '0') - return FALSE; - string++; - if (*string == '-') - string++; - - /* In ELF linker scripts, we typically express the architecture/machine - as architecture:machine. - - So if we've matched so far and encounter a colon, try to match the - string following the colon. */ - if (*string == ':') - { - string++; - return h8300_scan (info, string); - } - - if (*string == 'h' || *string == 'H') - { - string++; - if (*string == 'n' || *string == 'N') - return (info->mach == bfd_mach_h8300hn); - - return (info->mach == bfd_mach_h8300h); - } - else if (*string == 's' || *string == 'S') - { - string++; - if (*string == 'n' || *string == 'N') - return (info->mach == bfd_mach_h8300sn); - - if (*string == 'x' || *string == 'X') - { - string++; - if (*string == 'n' || *string == 'N') - return (info->mach == bfd_mach_h8300sxn); - - return (info->mach == bfd_mach_h8300sx); - } - - return (info->mach == bfd_mach_h8300s); - } - else - return info->mach == bfd_mach_h8300; -} - -/* This routine is provided two arch_infos and works out the machine - which would be compatible with both and returns a pointer to its - info structure. */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type *in, const bfd_arch_info_type *out) -{ - if (in->arch != out->arch) - return 0; - if (in->mach == bfd_mach_h8300sx && out->mach == bfd_mach_h8300s) - return in; - if (in->mach == bfd_mach_h8300s && out->mach == bfd_mach_h8300sx) - return out; - if (in->mach == bfd_mach_h8300sxn && out->mach == bfd_mach_h8300sn) - return in; - if (in->mach == bfd_mach_h8300sn && out->mach == bfd_mach_h8300sxn) - return out; - /* It's really not a good idea to mix and match modes. */ - if (in->mach != out->mach) - return 0; - else - return in; -} - -static const bfd_arch_info_type h8300sxn_info_struct = -{ - 32, /* 32 bits in a word */ - 16, /* 16 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_h8300, - bfd_mach_h8300sxn, - "h8300sxn", /* arch_name */ - "h8300sxn", /* printable name */ - 1, - FALSE, /* the default machine */ - compatible, - h8300_scan, - bfd_arch_default_fill, - 0 -}; - -static const bfd_arch_info_type h8300sx_info_struct = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_h8300, - bfd_mach_h8300sx, - "h8300sx", /* arch_name */ - "h8300sx", /* printable name */ - 1, - FALSE, /* the default machine */ - compatible, - h8300_scan, - bfd_arch_default_fill, - &h8300sxn_info_struct -}; - -static const bfd_arch_info_type h8300sn_info_struct = -{ - 32, /* 32 bits in a word. */ - 16, /* 16 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_h8300, - bfd_mach_h8300sn, - "h8300sn", /* Architecture name. */ - "h8300sn", /* Printable name. */ - 1, - FALSE, /* The default machine. */ - compatible, - h8300_scan, - bfd_arch_default_fill, - &h8300sx_info_struct -}; - -static const bfd_arch_info_type h8300hn_info_struct = -{ - 32, /* 32 bits in a word. */ - 16, /* 16 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_h8300, - bfd_mach_h8300hn, - "h8300hn", /* Architecture name. */ - "h8300hn", /* Printable name. */ - 1, - FALSE, /* The default machine. */ - compatible, - h8300_scan, - bfd_arch_default_fill, - &h8300sn_info_struct -}; - -static const bfd_arch_info_type h8300s_info_struct = -{ - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_h8300, - bfd_mach_h8300s, - "h8300s", /* Architecture name. */ - "h8300s", /* Printable name. */ - 1, - FALSE, /* The default machine. */ - compatible, - h8300_scan, - bfd_arch_default_fill, - & h8300hn_info_struct -}; - -static const bfd_arch_info_type h8300h_info_struct = -{ - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_h8300, - bfd_mach_h8300h, - "h8300h", /* Architecture name. */ - "h8300h", /* Printable name. */ - 1, - FALSE, /* The default machine. */ - compatible, - h8300_scan, - bfd_arch_default_fill, - &h8300s_info_struct -}; - -const bfd_arch_info_type bfd_h8300_arch = -{ - 16, /* 16 bits in a word. */ - 16, /* 16 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_h8300, - bfd_mach_h8300, - "h8300", /* Architecture name. */ - "h8300", /* Printable name. */ - 1, - TRUE, /* The default machine. */ - compatible, - h8300_scan, - bfd_arch_default_fill, - &h8300h_info_struct -}; - -/* Pad the given address to 32 bits, converting 16-bit and 24-bit - addresses into the values they would have had on a h8s target. */ - -bfd_vma -bfd_h8300_pad_address (bfd *abfd, bfd_vma address) -{ - /* Cope with bfd_vma's larger than 32 bits. */ - address &= 0xffffffffu; - - switch (bfd_get_mach (abfd)) - { - case bfd_mach_h8300: - case bfd_mach_h8300hn: - case bfd_mach_h8300sn: - case bfd_mach_h8300sxn: - /* Sign extend a 16-bit address. */ - if (address >= 0x8000) - return address | 0xffff0000u; - return address; - - case bfd_mach_h8300h: - /* Sign extend a 24-bit address. */ - if (address >= 0x800000) - return address | 0xff000000u; - return address; - - case bfd_mach_h8300s: - case bfd_mach_h8300sx: - return address; - - default: - abort (); - } -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-h8500.c b/sdcc/support/sdbinutils/bfd/cpu-h8500.c deleted file mode 100644 index 06dc9b9df..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-h8500.c +++ /dev/null @@ -1,59 +0,0 @@ -/* BFD library support routines for the H8/500 architecture. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -static bfd_boolean scan_mach - (const struct bfd_arch_info *, const char *); - -static bfd_boolean -scan_mach (const struct bfd_arch_info *info ATTRIBUTE_UNUSED, - const char *string) -{ - if (strcmp (string,"h8/500") == 0) - return TRUE; - if (strcmp (string,"H8/500") == 0) - return TRUE; - if (strcmp (string,"h8500") == 0) - return TRUE; - if (strcmp (string,"H8500") == 0) - return TRUE; - return FALSE; -} - -const bfd_arch_info_type bfd_h8500_arch = -{ - 16, /* 16 bits in a word */ - 24, /* 24 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_h8500, - 0, /* only 1 machine */ - "h8500", /* arch_name */ - "h8500", /* printable name */ - 1, - TRUE, /* the default machine */ - bfd_default_compatible, - scan_mach, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-hppa.c b/sdcc/support/sdbinutils/bfd/cpu-hppa.c deleted file mode 100644 index b7c39330c..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-hppa.c +++ /dev/null @@ -1,93 +0,0 @@ -/* BFD support for the HP Precision Architecture architecture. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static const bfd_arch_info_type bfd_hppa10_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_hppa, - bfd_mach_hppa10, /* By convention PA1.0 = 10 */ - "hppa", - "hppa1.0", - 3, - TRUE, /* Unless we use 1.1 specific features */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; - -/* PA2.0 in narrow mode */ -static const bfd_arch_info_type bfd_hppa20_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_hppa, - bfd_mach_hppa20, /* By convention PA2.0 = 20 */ - "hppa", - "hppa2.0", - 3, - FALSE, /* Unless we use 1.1 specific features */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_hppa10_arch, -}; - -/* PA2.0 in wide mode */ -static const bfd_arch_info_type bfd_hppa20w_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_hppa, - bfd_mach_hppa20w, /* ??? How best to describe wide mode here? */ - "hppa", - "hppa2.0w", - 3, - FALSE, /* Unless we use 1.1 specific features */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_hppa20_arch, -}; - -const bfd_arch_info_type bfd_hppa_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_hppa, - bfd_mach_hppa11, /* By convention PA1.1 = 11 */ - "hppa", - "hppa1.1", - 3, - FALSE, /* 1.1 specific features used */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_hppa20w_arch, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-i370.c b/sdcc/support/sdbinutils/bfd/cpu-i370.c deleted file mode 100644 index 7ca4f7f8f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-i370.c +++ /dev/null @@ -1,77 +0,0 @@ -/* BFD i370 CPU definition - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed by Ian Lance Taylor, Cygnus Support. - Hacked by Linas Vepstas in 1998, 1999 - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static const bfd_arch_info_type arch_info_struct[] = -{ - /* Hack alert: old old machines are really 16 and 24 bit arch ... */ - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_i370, - 360, /* For the 360. */ - "i370", - "i370:360", - 3, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[1] - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_i370, - 370, /* For the 370. */ - "i370", - "i370:370", - 3, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0 - }, -}; - -const bfd_arch_info_type bfd_i370_arch = -{ - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_i370, - 0, /* For the 360/370 common architecture. */ - "i370", - "i370:common", - 3, - TRUE, /* The default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - & arch_info_struct[0] -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-i386.c b/sdcc/support/sdbinutils/bfd/cpu-i386.c deleted file mode 100644 index 6f673793f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-i386.c +++ /dev/null @@ -1,302 +0,0 @@ -/* BFD support for the Intel 386 architecture. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" - -extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, - bfd_boolean); - -static const bfd_arch_info_type * -bfd_i386_compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b) -{ - const bfd_arch_info_type *compat = bfd_default_compatible (a, b); - - /* Don't allow mixing x64_32 with x86_64. */ - if (compat - && (a->mach & bfd_mach_x64_32) != (b->mach & bfd_mach_x64_32)) - compat = NULL; - - return compat; -} - -/* Fill the buffer with zero or nop instruction if CODE is TRUE. Use - multi byte nop instructions if LONG_NOP is TRUE. */ - -static void * -bfd_arch_i386_fill (bfd_size_type count, bfd_boolean code, - bfd_boolean long_nop) -{ - /* nop */ - static const char nop_1[] = { 0x90 }; - /* xchg %ax,%ax */ - static const char nop_2[] = { 0x66, 0x90 }; - /* nopl (%[re]ax) */ - static const char nop_3[] = { 0x0f, 0x1f, 0x00 }; - /* nopl 0(%[re]ax) */ - static const char nop_4[] = { 0x0f, 0x1f, 0x40, 0x00 }; - /* nopl 0(%[re]ax,%[re]ax,1) */ - static const char nop_5[] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; - /* nopw 0(%[re]ax,%[re]ax,1) */ - static const char nop_6[] = { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 }; - /* nopl 0L(%[re]ax) */ - static const char nop_7[] = { 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 }; - /* nopl 0L(%[re]ax,%[re]ax,1) */ - static const char nop_8[] = - { 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; - /* nopw 0L(%[re]ax,%[re]ax,1) */ - static const char nop_9[] = - { 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; - /* nopw %cs:0L(%[re]ax,%[re]ax,1) */ - static const char nop_10[] = - { 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static const char *const nops[] = - { nop_1, nop_2, nop_3, nop_4, nop_5, - nop_6, nop_7, nop_8, nop_9, nop_10 }; - bfd_size_type nop_size = long_nop ? ARRAY_SIZE (nops) : 2; - - void *fill = bfd_malloc (count); - if (fill == NULL) - return fill; - - if (code) - { - bfd_byte *p = fill; - while (count >= nop_size) - { - memcpy (p, nops[nop_size - 1], nop_size); - p += nop_size; - count -= nop_size; - } - if (count != 0) - memcpy (p, nops[count - 1], count); - } - else - memset (fill, 0, count); - - return fill; -} - -/* Fill the buffer with zero or short nop instruction if CODE is TRUE. */ - -void * -bfd_arch_i386_short_nop_fill (bfd_size_type count, - bfd_boolean is_bigendian ATTRIBUTE_UNUSED, - bfd_boolean code) -{ - return bfd_arch_i386_fill (count, code, FALSE); -} - -/* Fill the buffer with zero or long nop instruction if CODE is TRUE. */ - -static void * -bfd_arch_i386_long_nop_fill (bfd_size_type count, - bfd_boolean is_bigendian ATTRIBUTE_UNUSED, - bfd_boolean code) -{ - return bfd_arch_i386_fill (count, code, TRUE); -} - -/* Fill the buffer with zero, or one-byte nop instructions if CODE is TRUE. */ - -static void * -bfd_arch_i386_onebyte_nop_fill (bfd_size_type count, - bfd_boolean is_bigendian ATTRIBUTE_UNUSED, - bfd_boolean code) -{ - void *fill = bfd_malloc (count); - if (fill != NULL) - memset (fill, code ? 0x90 : 0, count); - return fill; -} - - -static const bfd_arch_info_type bfd_x64_32_nacl_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_x64_32_nacl, - "i386", - "i386:x64-32:nacl", - 3, - FALSE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_onebyte_nop_fill, - NULL -}; - -static const bfd_arch_info_type bfd_x86_64_nacl_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_x86_64_nacl, - "i386", - "i386:x86-64:nacl", - 3, - FALSE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_onebyte_nop_fill, - &bfd_x64_32_nacl_arch -}; - -const bfd_arch_info_type bfd_i386_nacl_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_i386_i386_nacl, - "i386", - "i386:nacl", - 3, - TRUE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_onebyte_nop_fill, - &bfd_x86_64_nacl_arch -}; - -static const bfd_arch_info_type bfd_x64_32_arch_intel_syntax = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_x64_32_intel_syntax, - "i386:intel", - "i386:x64-32:intel", - 3, - FALSE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_long_nop_fill, - &bfd_i386_nacl_arch -}; - -static 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_i386_compatible, - bfd_default_scan, - bfd_arch_i386_long_nop_fill, - &bfd_x64_32_arch_intel_syntax, -}; - -static 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_i386_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - &bfd_x86_64_arch_intel_syntax -}; - -static const bfd_arch_info_type i8086_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address (well, not really) */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_i386_i8086, - "i8086", - "i8086", - 3, - FALSE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - &bfd_i386_arch_intel_syntax -}; - -static const bfd_arch_info_type bfd_x64_32_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_x64_32, - "i386", - "i386:x64-32", - 3, - FALSE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_long_nop_fill, - &i8086_arch -}; - -static const bfd_arch_info_type bfd_x86_64_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i386, - bfd_mach_x86_64, - "i386", - "i386:x86-64", - 3, - FALSE, - bfd_i386_compatible, - bfd_default_scan, - bfd_arch_i386_long_nop_fill, - &bfd_x64_32_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_i386_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - &bfd_x86_64_arch -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-i860.c b/sdcc/support/sdbinutils/bfd/cpu-i860.c deleted file mode 100644 index 7f6eb4bea..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-i860.c +++ /dev/null @@ -1,42 +0,0 @@ -/* BFD support for the Intel 860 architecture. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - Created mostly by substituting "860" for "386" in cpu-i386.c - Harry Dolan , October 1995 - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_i860_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_i860, /* Architecture */ - 0, /* Only one machine */ - "i860", /* Architecture name */ - "i860", /* Printable name */ - 3, /* Section alignment exponent */ - TRUE, /* Is this the default architecture? */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, /* Next in list */ - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-i960.c b/sdcc/support/sdbinutils/bfd/cpu-i960.c deleted file mode 100644 index f1333dbd5..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-i960.c +++ /dev/null @@ -1,172 +0,0 @@ -/* BFD library support routines for the i960 architecture. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* This routine is provided a string, and tries to work out if it - could possibly refer to the i960 machine pointed at in the - info_struct pointer */ - -static bfd_boolean -scan_960_mach (const bfd_arch_info_type *ap, - const char *string) -{ - unsigned long machine; - int fail_because_not_80960 = FALSE; - - /* Look for the string i960 at the front of the string. */ - if (strncasecmp ("i960", string, 4) == 0) - { - string += 4; - - /* i960 on it's own means core to us. */ - if (* string == 0) - return ap->mach == bfd_mach_i960_core; - - /* "i960:*" is valid, anything else is not. */ - if (* string != ':') - return FALSE; - - string ++; - } - /* In some bfds the cpu-id is written as "80960KA", "80960KB", - "80960CA" or "80960MC". */ - else if (CONST_STRNEQ (string, "80960")) - { - string += 5; - - /* Set this to TRUE here. If a correct matching postfix - is detected below it will be reset to FALSE. */ - fail_because_not_80960 = TRUE; - } - /* No match, can't be us. */ - else - return FALSE; - - if (* string == '\0') - return FALSE; - - if (string[0] == 'c' && string[1] == 'o' && string[2] == 'r' && - string[3] == 'e' && string[4] == '\0') - machine = bfd_mach_i960_core; - else if (strcasecmp (string, "ka_sa") == 0) - machine = bfd_mach_i960_ka_sa; - else if (strcasecmp (string, "kb_sb") == 0) - machine = bfd_mach_i960_kb_sb; - else if (string[1] == '\0' || string[2] != '\0') /* rest are 2-char. */ - return FALSE; - else if (string[0] == 'k' && string[1] == 'b') - { machine = bfd_mach_i960_kb_sb; fail_because_not_80960 = FALSE; } - else if (string[0] == 's' && string[1] == 'b') - machine = bfd_mach_i960_kb_sb; - else if (string[0] == 'm' && string[1] == 'c') - { machine = bfd_mach_i960_mc; fail_because_not_80960 = FALSE; } - else if (string[0] == 'x' && string[1] == 'a') - machine = bfd_mach_i960_xa; - else if (string[0] == 'c' && string[1] == 'a') - { machine = bfd_mach_i960_ca; fail_because_not_80960 = FALSE; } - else if (string[0] == 'k' && string[1] == 'a') - { machine = bfd_mach_i960_ka_sa; fail_because_not_80960 = FALSE; } - else if (string[0] == 's' && string[1] == 'a') - machine = bfd_mach_i960_ka_sa; - else if (string[0] == 'j' && string[1] == 'x') - machine = bfd_mach_i960_jx; - else if (string[0] == 'h' && string[1] == 'x') - machine = bfd_mach_i960_hx; - else - return FALSE; - - if (fail_because_not_80960) - return FALSE; - - if (machine == ap->mach) - return TRUE; - - return FALSE; -} - -/* This routine is provided two arch_infos and works out the i960 - machine which would be compatible with both and returns a pointer - to its info structure */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b) -{ - - /* The i960 has distinct subspecies which may not interbreed: - CORE CA - CORE KA KB MC XA - CORE HX JX - Any architecture on the same line is compatible, the one on - the right is the least restrictive. - - We represent this information in an array, each machine to a side */ - -#define ERROR 0 -#define CORE bfd_mach_i960_core /*1*/ -#define KA bfd_mach_i960_ka_sa /*2*/ -#define KB bfd_mach_i960_kb_sb /*3*/ -#define MC bfd_mach_i960_mc /*4*/ -#define XA bfd_mach_i960_xa /*5*/ -#define CA bfd_mach_i960_ca /*6*/ -#define JX bfd_mach_i960_jx /*7*/ -#define HX bfd_mach_i960_hx /*8*/ -#define MAX_ARCH ((int)HX) - - static const unsigned long matrix[MAX_ARCH+1][MAX_ARCH+1] = - { - { ERROR, CORE, KA, KB, MC, XA, CA, JX, HX }, - { CORE, CORE, KA, KB, MC, XA, CA, JX, HX }, - { KA, KA, KA, KB, MC, XA, ERROR, ERROR, ERROR}, - { KB, KB, KB, KB, MC, XA, ERROR, ERROR, ERROR}, - { MC, MC, MC, MC, MC, XA, ERROR, ERROR, ERROR}, - { XA, XA, XA, XA, XA, XA, ERROR, ERROR, ERROR}, - { CA, CA, ERROR, ERROR, ERROR, ERROR, CA, ERROR, ERROR}, - { JX, JX, ERROR, ERROR, ERROR, ERROR, ERROR, JX, HX }, - { HX, HX, ERROR, ERROR, ERROR, ERROR, ERROR, HX, HX }, - }; - - if (a->arch != b->arch || matrix[a->mach][b->mach] == ERROR) - return NULL; - - return (a->mach == matrix[a->mach][b->mach]) ? a : b; -} - -#define N(a,b,d,n) \ -{ 32, 32, 8,bfd_arch_i960,a,"i960",b,3,d,compatible,scan_960_mach, \ - bfd_arch_default_fill, n,} - -static const bfd_arch_info_type arch_info_struct[] = -{ - N(bfd_mach_i960_ka_sa,"i960:ka_sa",FALSE, &arch_info_struct[1]), - N(bfd_mach_i960_kb_sb,"i960:kb_sb",FALSE, &arch_info_struct[2]), - N(bfd_mach_i960_mc, "i960:mc", FALSE, &arch_info_struct[3]), - N(bfd_mach_i960_xa, "i960:xa", FALSE, &arch_info_struct[4]), - N(bfd_mach_i960_ca, "i960:ca", FALSE, &arch_info_struct[5]), - N(bfd_mach_i960_jx, "i960:jx", FALSE, &arch_info_struct[6]), - N(bfd_mach_i960_hx, "i960:hx", FALSE, 0), -}; - -const bfd_arch_info_type bfd_i960_arch = - N(bfd_mach_i960_core, "i960:core", TRUE, &arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-ia64-opc.c b/sdcc/support/sdbinutils/bfd/cpu-ia64-opc.c deleted file mode 100644 index 0153e9e7f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-ia64-opc.c +++ /dev/null @@ -1,669 +0,0 @@ -/* Copyright (C) 1998-2018 Free Software Foundation, Inc. - Contributed by David Mosberger-Tang - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* Logically, this code should be part of libopcode but since some of - the operand insertion/extraction functions help bfd to implement - relocations, this code is included as part of cpu-ia64.c. This - avoids circular dependencies between libopcode and libbfd and also - obviates the need for applications to link in libopcode when all - they really want is libbfd. - - --davidm Mon Apr 13 22:14:02 1998 */ - -#include "../opcodes/ia64-opc.h" - -#define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) - -static const char* -ins_rsvd (const struct ia64_operand *self ATTRIBUTE_UNUSED, - ia64_insn value ATTRIBUTE_UNUSED, ia64_insn *code ATTRIBUTE_UNUSED) -{ - return "internal error---this shouldn't happen"; -} - -static const char* -ext_rsvd (const struct ia64_operand *self ATTRIBUTE_UNUSED, - ia64_insn code ATTRIBUTE_UNUSED, ia64_insn *valuep ATTRIBUTE_UNUSED) -{ - return "internal error---this shouldn't happen"; -} - -static const char* -ins_const (const struct ia64_operand *self ATTRIBUTE_UNUSED, - ia64_insn value ATTRIBUTE_UNUSED, ia64_insn *code ATTRIBUTE_UNUSED) -{ - return 0; -} - -static const char* -ext_const (const struct ia64_operand *self ATTRIBUTE_UNUSED, - ia64_insn code ATTRIBUTE_UNUSED, ia64_insn *valuep ATTRIBUTE_UNUSED) -{ - return 0; -} - -static const char* -ins_reg (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - if (value >= 1u << self->field[0].bits) - return "register number out of range"; - - *code |= value << self->field[0].shift; - return 0; -} - -static const char* -ext_reg (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - *valuep = ((code >> self->field[0].shift) - & ((1u << self->field[0].bits) - 1)); - return 0; -} - -static const char* -ins_immu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - ia64_insn new_insn = 0; - int i; - - for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) - { - new_insn |= ((value & ((((ia64_insn) 1) << self->field[i].bits) - 1)) - << self->field[i].shift); - value >>= self->field[i].bits; - } - if (value) - return "integer operand out of range"; - - *code |= new_insn; - return 0; -} - -static const char* -ext_immu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - BFD_HOST_U_64_BIT value = 0; - int i, bits = 0, total = 0; - - for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) - { - bits = self->field[i].bits; - value |= ((code >> self->field[i].shift) - & ((((BFD_HOST_U_64_BIT) 1) << bits) - 1)) << total; - total += bits; - } - *valuep = value; - return 0; -} - -static const char* -ins_immu5b (const struct ia64_operand *self, ia64_insn value, - ia64_insn *code) -{ - if (value < 32 || value > 63) - return "value must be between 32 and 63"; - return ins_immu (self, value - 32, code); -} - -static const char* -ext_immu5b (const struct ia64_operand *self, ia64_insn code, - ia64_insn *valuep) -{ - const char *result; - - result = ext_immu (self, code, valuep); - if (result) - return result; - - *valuep = *valuep + 32; - return 0; -} - -static const char* -ins_immus8 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - if (value & 0x7) - return "value not an integer multiple of 8"; - return ins_immu (self, value >> 3, code); -} - -static const char* -ext_immus8 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - const char *result; - - result = ext_immu (self, code, valuep); - if (result) - return result; - - *valuep = *valuep << 3; - return 0; -} - -static const char* -ins_imms_scaled (const struct ia64_operand *self, ia64_insn value, - ia64_insn *code, int scale) -{ - BFD_HOST_64_BIT svalue = value, sign_bit = 0; - ia64_insn new_insn = 0; - int i; - - svalue >>= scale; - - for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) - { - new_insn |= ((svalue & ((((ia64_insn) 1) << self->field[i].bits) - 1)) - << self->field[i].shift); - sign_bit = (svalue >> (self->field[i].bits - 1)) & 1; - svalue >>= self->field[i].bits; - } - if ((!sign_bit && svalue != 0) || (sign_bit && svalue != -1)) - return "integer operand out of range"; - - *code |= new_insn; - return 0; -} - -static const char* -ext_imms_scaled (const struct ia64_operand *self, ia64_insn code, - ia64_insn *valuep, int scale) -{ - int i, bits = 0, total = 0; - BFD_HOST_64_BIT val = 0, sign; - - for (i = 0; i < NELEMS (self->field) && self->field[i].bits; ++i) - { - bits = self->field[i].bits; - val |= ((code >> self->field[i].shift) - & ((((BFD_HOST_U_64_BIT) 1) << bits) - 1)) << total; - total += bits; - } - /* sign extend: */ - sign = (BFD_HOST_64_BIT) 1 << (total - 1); - val = (val ^ sign) - sign; - - *valuep = (val << scale); - return 0; -} - -static const char* -ins_imms (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - return ins_imms_scaled (self, value, code, 0); -} - -static const char* -ins_immsu4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - value = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000; - - return ins_imms_scaled (self, value, code, 0); -} - -static const char* -ext_imms (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - return ext_imms_scaled (self, code, valuep, 0); -} - -static const char* -ins_immsm1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - --value; - return ins_imms_scaled (self, value, code, 0); -} - -static const char* -ins_immsm1u4 (const struct ia64_operand *self, ia64_insn value, - ia64_insn *code) -{ - value = ((value & 0xffffffff) ^ 0x80000000) - 0x80000000; - - --value; - return ins_imms_scaled (self, value, code, 0); -} - -static const char* -ext_immsm1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - const char *res = ext_imms_scaled (self, code, valuep, 0); - - ++*valuep; - return res; -} - -static const char* -ins_imms1 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - return ins_imms_scaled (self, value, code, 1); -} - -static const char* -ext_imms1 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - return ext_imms_scaled (self, code, valuep, 1); -} - -static const char* -ins_imms4 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - return ins_imms_scaled (self, value, code, 4); -} - -static const char* -ext_imms4 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - return ext_imms_scaled (self, code, valuep, 4); -} - -static const char* -ins_imms16 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - return ins_imms_scaled (self, value, code, 16); -} - -static const char* -ext_imms16 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - return ext_imms_scaled (self, code, valuep, 16); -} - -static const char* -ins_cimmu (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - ia64_insn mask = (((ia64_insn) 1) << self->field[0].bits) - 1; - return ins_immu (self, value ^ mask, code); -} - -static const char* -ext_cimmu (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - const char *result; - ia64_insn mask; - - mask = (((ia64_insn) 1) << self->field[0].bits) - 1; - result = ext_immu (self, code, valuep); - if (!result) - { - mask = (((ia64_insn) 1) << self->field[0].bits) - 1; - *valuep ^= mask; - } - return result; -} - -static const char* -ins_cnt (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - --value; - if (value >= ((BFD_HOST_U_64_BIT) 1) << self->field[0].bits) - return "count out of range"; - - *code |= value << self->field[0].shift; - return 0; -} - -static const char* -ext_cnt (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - *valuep = ((code >> self->field[0].shift) - & ((((BFD_HOST_U_64_BIT) 1) << self->field[0].bits) - 1)) + 1; - return 0; -} - -static const char* -ins_cnt2b (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - --value; - - if (value > 2) - return "count must be in range 1..3"; - - *code |= value << self->field[0].shift; - return 0; -} - -static const char* -ext_cnt2b (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - *valuep = ((code >> self->field[0].shift) & 0x3) + 1; - return 0; -} - -static const char* -ins_cnt2c (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - switch (value) - { - case 0: value = 0; break; - case 7: value = 1; break; - case 15: value = 2; break; - case 16: value = 3; break; - default: return "count must be 0, 7, 15, or 16"; - } - *code |= value << self->field[0].shift; - return 0; -} - -static const char* -ext_cnt2c (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - ia64_insn value; - - value = (code >> self->field[0].shift) & 0x3; - switch (value) - { - case 0: value = 0; break; - case 1: value = 7; break; - case 2: value = 15; break; - case 3: value = 16; break; - } - *valuep = value; - return 0; -} - -static const char* -ins_cnt6a (const struct ia64_operand *self, ia64_insn value, - ia64_insn *code) -{ - if (value < 1 || value > 64) - return "value must be between 1 and 64"; - return ins_immu (self, value - 1, code); -} - -static const char* -ext_cnt6a (const struct ia64_operand *self, ia64_insn code, - ia64_insn *valuep) -{ - const char *result; - - result = ext_immu (self, code, valuep); - if (result) - return result; - - *valuep = *valuep + 1; - return 0; -} - -static const char* -ins_strd5b (const struct ia64_operand *self, ia64_insn value, - ia64_insn *code) -{ - if ( value & 0x3f ) - return "value must be a multiple of 64"; - return ins_imms_scaled (self, value, code, 6); -} - -static const char* -ext_strd5b (const struct ia64_operand *self, ia64_insn code, - ia64_insn *valuep) -{ - return ext_imms_scaled (self, code, valuep, 6); -} - - -static const char* -ins_inc3 (const struct ia64_operand *self, ia64_insn value, ia64_insn *code) -{ - BFD_HOST_64_BIT val = value; - BFD_HOST_U_64_BIT sign = 0; - - if (val < 0) - { - sign = 0x4; - value = -value; - } - switch (value) - { - case 1: value = 3; break; - case 4: value = 2; break; - case 8: value = 1; break; - case 16: value = 0; break; - default: return "count must be +/- 1, 4, 8, or 16"; - } - *code |= (sign | value) << self->field[0].shift; - return 0; -} - -static const char* -ext_inc3 (const struct ia64_operand *self, ia64_insn code, ia64_insn *valuep) -{ - BFD_HOST_64_BIT val; - int negate; - - val = (code >> self->field[0].shift) & 0x7; - negate = val & 0x4; - switch (val & 0x3) - { - case 0: val = 16; break; - case 1: val = 8; break; - case 2: val = 4; break; - case 3: val = 1; break; - } - if (negate) - val = -val; - - *valuep = val; - return 0; -} - -#define CST IA64_OPND_CLASS_CST -#define REG IA64_OPND_CLASS_REG -#define IND IA64_OPND_CLASS_IND -#define ABS IA64_OPND_CLASS_ABS -#define REL IA64_OPND_CLASS_REL - -#define SDEC IA64_OPND_FLAG_DECIMAL_SIGNED -#define UDEC IA64_OPND_FLAG_DECIMAL_UNSIGNED - -const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] = - { - /* constants: */ - { CST, ins_const, ext_const, "NIL", {{ 0, 0}}, 0, "" }, - { CST, ins_const, ext_const, "ar.csd", {{ 0, 0}}, 0, "ar.csd" }, - { CST, ins_const, ext_const, "ar.ccv", {{ 0, 0}}, 0, "ar.ccv" }, - { CST, ins_const, ext_const, "ar.pfs", {{ 0, 0}}, 0, "ar.pfs" }, - { CST, ins_const, ext_const, "1", {{ 0, 0}}, 0, "1" }, - { CST, ins_const, ext_const, "8", {{ 0, 0}}, 0, "8" }, - { CST, ins_const, ext_const, "16", {{ 0, 0}}, 0, "16" }, - { CST, ins_const, ext_const, "r0", {{ 0, 0}}, 0, "r0" }, - { CST, ins_const, ext_const, "ip", {{ 0, 0}}, 0, "ip" }, - { CST, ins_const, ext_const, "pr", {{ 0, 0}}, 0, "pr" }, - { CST, ins_const, ext_const, "pr.rot", {{ 0, 0}}, 0, "pr.rot" }, - { CST, ins_const, ext_const, "psr", {{ 0, 0}}, 0, "psr" }, - { CST, ins_const, ext_const, "psr.l", {{ 0, 0}}, 0, "psr.l" }, - { CST, ins_const, ext_const, "psr.um", {{ 0, 0}}, 0, "psr.um" }, - - /* register operands: */ - { REG, ins_reg, ext_reg, "ar", {{ 7, 20}}, 0, /* AR3 */ - "an application register" }, - { REG, ins_reg, ext_reg, "b", {{ 3, 6}}, 0, /* B1 */ - "a branch register" }, - { REG, ins_reg, ext_reg, "b", {{ 3, 13}}, 0, /* B2 */ - "a branch register"}, - { REG, ins_reg, ext_reg, "cr", {{ 7, 20}}, 0, /* CR */ - "a control register"}, - { REG, ins_reg, ext_reg, "f", {{ 7, 6}}, 0, /* F1 */ - "a floating-point register" }, - { REG, ins_reg, ext_reg, "f", {{ 7, 13}}, 0, /* F2 */ - "a floating-point register" }, - { REG, ins_reg, ext_reg, "f", {{ 7, 20}}, 0, /* F3 */ - "a floating-point register" }, - { REG, ins_reg, ext_reg, "f", {{ 7, 27}}, 0, /* F4 */ - "a floating-point register" }, - { REG, ins_reg, ext_reg, "p", {{ 6, 6}}, 0, /* P1 */ - "a predicate register" }, - { REG, ins_reg, ext_reg, "p", {{ 6, 27}}, 0, /* P2 */ - "a predicate register" }, - { REG, ins_reg, ext_reg, "r", {{ 7, 6}}, 0, /* R1 */ - "a general register" }, - { REG, ins_reg, ext_reg, "r", {{ 7, 13}}, 0, /* R2 */ - "a general register" }, - { REG, ins_reg, ext_reg, "r", {{ 7, 20}}, 0, /* R3 */ - "a general register" }, - { REG, ins_reg, ext_reg, "r", {{ 2, 20}}, 0, /* R3_2 */ - "a general register r0-r3" }, - { REG, ins_reg, ext_reg, "dahr", {{ 3, 23}}, 0, /* DAHR */ - "a dahr register dahr0-7" }, - - /* memory operands: */ - { IND, ins_reg, ext_reg, "", {{7, 20}}, 0, /* MR3 */ - "a memory address" }, - - /* indirect operands: */ - { IND, ins_reg, ext_reg, "cpuid", {{7, 20}}, 0, /* CPUID_R3 */ - "a cpuid register" }, - { IND, ins_reg, ext_reg, "dbr", {{7, 20}}, 0, /* DBR_R3 */ - "a dbr register" }, - { IND, ins_reg, ext_reg, "dtr", {{7, 20}}, 0, /* DTR_R3 */ - "a dtr register" }, - { IND, ins_reg, ext_reg, "itr", {{7, 20}}, 0, /* ITR_R3 */ - "an itr register" }, - { IND, ins_reg, ext_reg, "ibr", {{7, 20}}, 0, /* IBR_R3 */ - "an ibr register" }, - { IND, ins_reg, ext_reg, "msr", {{7, 20}}, 0, /* MSR_R3 */ - "an msr register" }, - { IND, ins_reg, ext_reg, "pkr", {{7, 20}}, 0, /* PKR_R3 */ - "a pkr register" }, - { IND, ins_reg, ext_reg, "pmc", {{7, 20}}, 0, /* PMC_R3 */ - "a pmc register" }, - { IND, ins_reg, ext_reg, "pmd", {{7, 20}}, 0, /* PMD_R3 */ - "a pmd register" }, - { IND, ins_reg, ext_reg, "dahr", {{7, 20}}, 0, /* DAHR_R3 */ - "a dahr register" }, - { IND, ins_reg, ext_reg, "rr", {{7, 20}}, 0, /* RR_R3 */ - "an rr register" }, - - /* immediate operands: */ - { ABS, ins_cimmu, ext_cimmu, 0, {{ 5, 20 }}, UDEC, /* CCNT5 */ - "a 5-bit count (0-31)" }, - { ABS, ins_cnt, ext_cnt, 0, {{ 2, 27 }}, UDEC, /* CNT2a */ - "a 2-bit count (1-4)" }, - { ABS, ins_cnt2b, ext_cnt2b, 0, {{ 2, 27 }}, UDEC, /* CNT2b */ - "a 2-bit count (1-3)" }, - { ABS, ins_cnt2c, ext_cnt2c, 0, {{ 2, 30 }}, UDEC, /* CNT2c */ - "a count (0, 7, 15, or 16)" }, - { ABS, ins_immu, ext_immu, 0, {{ 5, 14}}, UDEC, /* CNT5 */ - "a 5-bit count (0-31)" }, - { ABS, ins_immu, ext_immu, 0, {{ 6, 27}}, UDEC, /* CNT6 */ - "a 6-bit count (0-63)" }, - { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 20}}, UDEC, /* CPOS6a */ - "a 6-bit bit pos (0-63)" }, - { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 14}}, UDEC, /* CPOS6b */ - "a 6-bit bit pos (0-63)" }, - { ABS, ins_cimmu, ext_cimmu, 0, {{ 6, 31}}, UDEC, /* CPOS6c */ - "a 6-bit bit pos (0-63)" }, - { ABS, ins_imms, ext_imms, 0, {{ 1, 36}}, SDEC, /* IMM1 */ - "a 1-bit integer (-1, 0)" }, - { ABS, ins_immu, ext_immu, 0, {{ 2, 13}}, UDEC, /* IMMU2 */ - "a 2-bit unsigned (0-3)" }, - { ABS, ins_immu5b, ext_immu5b, 0, {{ 5, 14}}, UDEC, /* IMMU5b */ - "a 5-bit unsigned (32 + (0-31))" }, - { ABS, ins_immu, ext_immu, 0, {{ 7, 13}}, 0, /* IMMU7a */ - "a 7-bit unsigned (0-127)" }, - { ABS, ins_immu, ext_immu, 0, {{ 7, 20}}, 0, /* IMMU7b */ - "a 7-bit unsigned (0-127)" }, - { ABS, ins_immu, ext_immu, 0, {{ 7, 13}}, UDEC, /* SOF */ - "a frame size (register count)" }, - { ABS, ins_immu, ext_immu, 0, {{ 7, 20}}, UDEC, /* SOL */ - "a local register count" }, - { ABS, ins_immus8,ext_immus8,0, {{ 4, 27}}, UDEC, /* SOR */ - "a rotating register count (integer multiple of 8)" }, - { ABS, ins_imms, ext_imms, 0, /* IMM8 */ - {{ 7, 13}, { 1, 36}}, SDEC, - "an 8-bit integer (-128-127)" }, - { ABS, ins_immsu4, ext_imms, 0, /* IMM8U4 */ - {{ 7, 13}, { 1, 36}}, SDEC, - "an 8-bit signed integer for 32-bit unsigned compare (-128-127)" }, - { ABS, ins_immsm1, ext_immsm1, 0, /* IMM8M1 */ - {{ 7, 13}, { 1, 36}}, SDEC, - "an 8-bit integer (-127-128)" }, - { ABS, ins_immsm1u4, ext_immsm1, 0, /* IMM8M1U4 */ - {{ 7, 13}, { 1, 36}}, SDEC, - "an 8-bit integer for 32-bit unsigned compare (-127-(-1),1-128,0x100000000)" }, - { ABS, ins_immsm1, ext_immsm1, 0, /* IMM8M1U8 */ - {{ 7, 13}, { 1, 36}}, SDEC, - "an 8-bit integer for 64-bit unsigned compare (-127-(-1),1-128,0x10000000000000000)" }, - { ABS, ins_immu, ext_immu, 0, {{ 2, 33}, { 7, 20}}, 0, /* IMMU9 */ - "a 9-bit unsigned (0-511)" }, - { ABS, ins_imms, ext_imms, 0, /* IMM9a */ - {{ 7, 6}, { 1, 27}, { 1, 36}}, SDEC, - "a 9-bit integer (-256-255)" }, - { ABS, ins_imms, ext_imms, 0, /* IMM9b */ - {{ 7, 13}, { 1, 27}, { 1, 36}}, SDEC, - "a 9-bit integer (-256-255)" }, - { ABS, ins_imms, ext_imms, 0, /* IMM14 */ - {{ 7, 13}, { 6, 27}, { 1, 36}}, SDEC, - "a 14-bit integer (-8192-8191)" }, - { ABS, ins_immu, ext_immu, 0, /* IMMU16 */ - {{4, 6}, {11, 12}, { 1, 36}}, UDEC, - "a 16-bit unsigned" }, - { ABS, ins_imms1, ext_imms1, 0, /* IMM17 */ - {{ 7, 6}, { 8, 24}, { 1, 36}}, 0, - "a 17-bit integer (-65536-65535)" }, - { ABS, ins_immu, ext_immu, 0, /* IMMU19 */ - {{4, 6}, {14, 12}, { 1, 36}}, UDEC, - "a 19-bit unsigned" }, - { ABS, ins_immu, ext_immu, 0, {{20, 6}, { 1, 36}}, 0, /* IMMU21 */ - "a 21-bit unsigned" }, - { ABS, ins_imms, ext_imms, 0, /* IMM22 */ - {{ 7, 13}, { 9, 27}, { 5, 22}, { 1, 36}}, SDEC, - "a 22-bit signed integer" }, - { ABS, ins_immu, ext_immu, 0, /* IMMU24 */ - {{21, 6}, { 2, 31}, { 1, 36}}, 0, - "a 24-bit unsigned" }, - { ABS, ins_imms16,ext_imms16,0, {{27, 6}, { 1, 36}}, 0, /* IMM44 */ - "a 44-bit unsigned (least 16 bits ignored/zeroes)" }, - { ABS, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* IMMU62 */ - "a 62-bit unsigned" }, - { ABS, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* IMMU64 */ - "a 64-bit unsigned" }, - { ABS, ins_inc3, ext_inc3, 0, {{ 3, 13}}, SDEC, /* INC3 */ - "an increment (+/- 1, 4, 8, or 16)" }, - { ABS, ins_cnt, ext_cnt, 0, {{ 4, 27}}, UDEC, /* LEN4 */ - "a 4-bit length (1-16)" }, - { ABS, ins_cnt, ext_cnt, 0, {{ 6, 27}}, UDEC, /* LEN6 */ - "a 6-bit length (1-64)" }, - { ABS, ins_immu, ext_immu, 0, {{ 4, 20}}, 0, /* MBTYPE4 */ - "a mix type (@rev, @mix, @shuf, @alt, or @brcst)" }, - { ABS, ins_immu, ext_immu, 0, {{ 8, 20}}, 0, /* MBTYPE8 */ - "an 8-bit mix type" }, - { ABS, ins_immu, ext_immu, 0, {{ 6, 14}}, UDEC, /* POS6 */ - "a 6-bit bit pos (0-63)" }, - { REL, ins_imms4, ext_imms4, 0, {{ 7, 6}, { 2, 33}}, 0, /* TAG13 */ - "a branch tag" }, - { REL, ins_imms4, ext_imms4, 0, {{ 9, 24}}, 0, /* TAG13b */ - "a branch tag" }, - { REL, ins_imms4, ext_imms4, 0, {{20, 6}, { 1, 36}}, 0, /* TGT25 */ - "a branch target" }, - { REL, ins_imms4, ext_imms4, 0, /* TGT25b */ - {{ 7, 6}, {13, 20}, { 1, 36}}, 0, - "a branch target" }, - { REL, ins_imms4, ext_imms4, 0, {{20, 13}, { 1, 36}}, 0, /* TGT25c */ - "a branch target" }, - { REL, ins_rsvd, ext_rsvd, 0, {{0, 0}}, 0, /* TGT64 */ - "a branch target" }, - - { ABS, ins_const, ext_const, 0, {{0, 0}}, 0, /* LDXMOV */ - "ldxmov target" }, - { ABS, ins_cnt6a, ext_cnt6a, 0, {{6, 6}}, UDEC, /* CNT6a */ - "lfetch count" }, - { ABS, ins_strd5b, ext_strd5b, 0, {{5, 13}}, SDEC, /* STRD5b*/ - "lfetch stride" }, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-ia64.c b/sdcc/support/sdbinutils/bfd/cpu-ia64.c deleted file mode 100644 index 8aa5e80ad..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-ia64.c +++ /dev/null @@ -1,60 +0,0 @@ -/* BFD support for the ia64 architecture. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - Contributed by David Mosberger-Tang - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_ia64_elf32_arch = - { - 64, /* 64 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_ia64, - bfd_mach_ia64_elf32, - "ia64", - "ia64-elf32", - 3, /* log2 of section alignment */ - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; - -const bfd_arch_info_type bfd_ia64_arch = - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_ia64, - bfd_mach_ia64_elf64, - "ia64", - "ia64-elf64", - 3, /* log2 of section alignment */ - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_ia64_elf32_arch, - }; - -#include "cpu-ia64-opc.c" diff --git a/sdcc/support/sdbinutils/bfd/cpu-iamcu.c b/sdcc/support/sdbinutils/bfd/cpu-iamcu.c deleted file mode 100644 index 023290e4b..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-iamcu.c +++ /dev/null @@ -1,60 +0,0 @@ -/* BFD support for the Intel MCU architecture. - Copyright (C) 2015-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, - bfd_boolean); - -static const bfd_arch_info_type bfd_iamcu_arch_intel_syntax = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_iamcu, - bfd_mach_i386_iamcu_intel_syntax, - "iamcu:intel", - "iamcu:intel", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - 0 -}; - -const bfd_arch_info_type bfd_iamcu_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_iamcu, - bfd_mach_i386_iamcu, - "iamcu", - "iamcu", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - &bfd_iamcu_arch_intel_syntax -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-ip2k.c b/sdcc/support/sdbinutils/bfd/cpu-ip2k.c deleted file mode 100644 index 51499c624..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-ip2k.c +++ /dev/null @@ -1,57 +0,0 @@ -/* BFD support for the Scenix IP2xxx processor. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_ip2k_nonext_arch = -{ - 32, /* Bits per word - not really true. */ - 16, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_ip2k, /* Architecture. */ - bfd_mach_ip2022, /* Machine. */ - "ip2k", /* Architecture name. */ - "ip2022", /* Machine name. */ - 1, /* Section align power. */ - FALSE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; - -const bfd_arch_info_type bfd_ip2k_arch = -{ - 32, /* Bits per word - not really true. */ - 16, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_ip2k, /* Architecture. */ - bfd_mach_ip2022ext, /* Machine. */ - "ip2k", /* Architecture name. */ - "ip2022ext", /* Machine name. */ - 1, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - & bfd_ip2k_nonext_arch /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-iq2000.c b/sdcc/support/sdbinutils/bfd/cpu-iq2000.c deleted file mode 100644 index a09f43a9e..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-iq2000.c +++ /dev/null @@ -1,59 +0,0 @@ -/* BFD support for the Vitesse IQ2000 processor. - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static const bfd_arch_info_type arch_info_struct[] = -{ - { - 32, /* bits per word */ - 32, /* bits per address */ - 8, /* bits per byte */ - bfd_arch_iq2000, /* architecture */ - bfd_mach_iq10, /* machine */ - "iq2000", /* architecture name */ - "iq10", /* printable name */ - 3, /* section align power */ - FALSE, /* the default ? */ - bfd_default_compatible, /* architecture comparison fn */ - bfd_default_scan, /* string to architecture convert fn */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* next in list */ - } -}; - -const bfd_arch_info_type bfd_iq2000_arch = -{ - 32, /* bits per word */ - 32, /* bits per address */ - 8, /* bits per byte */ - bfd_arch_iq2000, /* architecture */ - bfd_mach_iq2000, /* machine */ - "iq2000", /* architecture name */ - "iq2000", /* printable name */ - 3, /* section align power */ - TRUE, /* the default ? */ - bfd_default_compatible, /* architecture comparison fn */ - bfd_default_scan, /* string to architecture convert fn */ - bfd_arch_default_fill, /* Default fill. */ - &arch_info_struct[0], /* next in list */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-k1om.c b/sdcc/support/sdbinutils/bfd/cpu-k1om.c deleted file mode 100644 index bc8d8894b..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-k1om.c +++ /dev/null @@ -1,60 +0,0 @@ -/* BFD support for the Intel K1OM architecture. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, - bfd_boolean); - -static const bfd_arch_info_type bfd_k1om_arch_intel_syntax = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_k1om, - bfd_mach_k1om_intel_syntax, - "k1om:intel", - "k1om:intel", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - 0 -}; - -const bfd_arch_info_type bfd_k1om_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_k1om, - bfd_mach_k1om, - "k1om", - "k1om", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - &bfd_k1om_arch_intel_syntax -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-l1om.c b/sdcc/support/sdbinutils/bfd/cpu-l1om.c deleted file mode 100644 index 2cf665f20..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-l1om.c +++ /dev/null @@ -1,60 +0,0 @@ -/* BFD support for the Intel L1OM architecture. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -extern void * bfd_arch_i386_short_nop_fill (bfd_size_type, bfd_boolean, - bfd_boolean); - -static const bfd_arch_info_type bfd_l1om_arch_intel_syntax = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_l1om, - bfd_mach_l1om_intel_syntax, - "l1om:intel", - "l1om:intel", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - 0 -}; - -const bfd_arch_info_type bfd_l1om_arch = -{ - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_l1om, - bfd_mach_l1om, - "l1om", - "l1om", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_i386_short_nop_fill, - &bfd_l1om_arch_intel_syntax -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-lm32.c b/sdcc/support/sdbinutils/bfd/cpu-lm32.c deleted file mode 100644 index ea21d2d02..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-lm32.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the Lattice Mico32 architecture. - Copyright (C) 2008-2018 Free Software Foundation, Inc. - Contributed by Jon Beniston - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_lm32_arch = -{ - 32, /* Bits in word. */ - 32, /* Bits in address. */ - 8, /* Bits in byte. */ - bfd_arch_lm32, /* Enum bfd_architecture. */ - bfd_mach_lm32, /* Machine number. */ - "lm32", /* Architecture name. */ - "lm32", /* Printable name. */ - 4, /* Alignment. */ - TRUE, /* Is this the default machine for the target. */ - bfd_default_compatible, /* Function callback to test if two files have compatible machines. */ - bfd_default_scan, - bfd_arch_default_fill, - NULL /* Next. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m10200.c b/sdcc/support/sdbinutils/bfd/cpu-m10200.c deleted file mode 100644 index cd45948fa..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m10200.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the Matsushita 10200 processor - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_mn10200_arch = - { - 16, /* 16 bits in a word */ - 24, /* 16 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_mn10200, - 200, - "mn10200", - "mn10200", - 2, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m10300.c b/sdcc/support/sdbinutils/bfd/cpu-m10300.c deleted file mode 100644 index 33676baaf..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m10300.c +++ /dev/null @@ -1,74 +0,0 @@ -/* BFD support for the Matsushita 10300 processor - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_am33_2_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_mn10300, - 332, - "am33_2", - "am33-2", - 2, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; - -const bfd_arch_info_type bfd_am33_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_mn10300, - 330, - "am33", - "am33", - 2, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_am33_2_arch, - }; - -const bfd_arch_info_type bfd_mn10300_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_mn10300, - 300, - "mn10300", - "mn10300", - 2, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_am33_arch, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m32c.c b/sdcc/support/sdbinutils/bfd/cpu-m32c.c deleted file mode 100644 index 04d0599a4..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m32c.c +++ /dev/null @@ -1,72 +0,0 @@ -/* BFD support for the M16C/M32C processors. - Copyright (C) 2004-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -/* Like bfd_default_scan but if the string is just "m32c" then - skip the m16c architecture. */ - -static bfd_boolean -m32c_scan (const bfd_arch_info_type * info, const char * string) -{ - if (strcmp (string, "m32c") == 0 - && info->mach == bfd_mach_m16c) - return FALSE; - - return bfd_default_scan (info, string); -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - { - 32, /* bits per word */ - 32, /* bits per address */ - 8, /* bits per byte */ - bfd_arch_m32c, /* architecture */ - bfd_mach_m32c, /* machine */ - "m32c", /* architecture name */ - "m32c", /* printable name */ - 3, /* section align power */ - FALSE, /* the default ? */ - bfd_default_compatible, /* architecture comparison fn */ - m32c_scan, /* string to architecture convert fn */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* next in list */ - }, -}; - -const bfd_arch_info_type bfd_m32c_arch = -{ - 32, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_m32c, /* Architecture. */ - bfd_mach_m16c, /* Machine. */ - "m32c", /* Architecture name. */ - "m16c", /* Printable name. */ - 4, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - m32c_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - &arch_info_struct[0], /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m32r.c b/sdcc/support/sdbinutils/bfd/cpu-m32r.c deleted file mode 100644 index 47e9c6a76..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m32r.c +++ /dev/null @@ -1,39 +0,0 @@ -/* BFD support for the M32R processor. - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#define N(number, print, default, next) \ -{ 32, 32, 8, bfd_arch_m32r, number, "m32r", print, 4, default, \ - bfd_default_compatible, bfd_default_scan, bfd_arch_default_fill, next } - -#define M32R2_NEXT & arch_info_struct [1] -#define NEXT & arch_info_struct [0] - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (bfd_mach_m32rx, "m32rx", FALSE, M32R2_NEXT) , - N (bfd_mach_m32r2, "m32r2", FALSE, NULL) -}; - -const bfd_arch_info_type bfd_m32r_arch = - N (bfd_mach_m32r, "m32r", TRUE, NEXT); diff --git a/sdcc/support/sdbinutils/bfd/cpu-m68hc11.c b/sdcc/support/sdbinutils/bfd/cpu-m68hc11.c deleted file mode 100644 index b1e7358da..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m68hc11.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the Motorola 68HC11 processor - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_m68hc11_arch = -{ - 16, /* 16 bits in a word */ - 16, /* 16 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_m68hc11, - 0, - "m68hc11", - "m68hc11", - 4, /* section alignment power */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m68hc12.c b/sdcc/support/sdbinutils/bfd/cpu-m68hc12.c deleted file mode 100644 index 22a87070e..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m68hc12.c +++ /dev/null @@ -1,57 +0,0 @@ -/* BFD support for the Motorola 68HC12 processor - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_m68hc12s_arch = -{ - 16, /* 16 bits in a word */ - 32, /* 16 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_m68hc12, - bfd_mach_m6812s, - "m68hc12:HCS12", - "m68hc12", - 4, /* section alignment power */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; - -const bfd_arch_info_type bfd_m68hc12_arch = -{ - 16, /* 16 bits in a word */ - 32, /* 16 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_m68hc12, - 0, - "m68hc12", - "m68hc12", - 4, /* section alignment power */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_m68hc12s_arch, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m68k.c b/sdcc/support/sdbinutils/bfd/cpu-m68k.c deleted file mode 100644 index fb2a7f405..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m68k.c +++ /dev/null @@ -1,273 +0,0 @@ -/* BFD library support routines for architectures. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "opcode/m68k.h" - -static const bfd_arch_info_type * -bfd_m68k_compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b); - -#define N(name, print,d,next) \ -{ 32, 32, 8, bfd_arch_m68k, name, "m68k",print,2,d,bfd_m68k_compatible, \ - bfd_default_scan, bfd_arch_default_fill, next, } - -static const bfd_arch_info_type arch_info_struct[] = - { - N(bfd_mach_m68000, "m68k:68000", FALSE, &arch_info_struct[1]), - N(bfd_mach_m68008, "m68k:68008", FALSE, &arch_info_struct[2]), - N(bfd_mach_m68010, "m68k:68010", FALSE, &arch_info_struct[3]), - N(bfd_mach_m68020, "m68k:68020", FALSE, &arch_info_struct[4]), - N(bfd_mach_m68030, "m68k:68030", FALSE, &arch_info_struct[5]), - N(bfd_mach_m68040, "m68k:68040", FALSE, &arch_info_struct[6]), - N(bfd_mach_m68060, "m68k:68060", FALSE, &arch_info_struct[7]), - N(bfd_mach_cpu32, "m68k:cpu32", FALSE, &arch_info_struct[8]), - N(bfd_mach_fido, "m68k:fido", FALSE, &arch_info_struct[9]), - - /* Various combinations of CF architecture features */ - N(bfd_mach_mcf_isa_a_nodiv, "m68k:isa-a:nodiv", - FALSE, &arch_info_struct[10]), - N(bfd_mach_mcf_isa_a, "m68k:isa-a", - FALSE, &arch_info_struct[11]), - N(bfd_mach_mcf_isa_a_mac, "m68k:isa-a:mac", - FALSE, &arch_info_struct[12]), - N(bfd_mach_mcf_isa_a_emac, "m68k:isa-a:emac", - FALSE, &arch_info_struct[13]), - N(bfd_mach_mcf_isa_aplus, "m68k:isa-aplus", - FALSE, &arch_info_struct[14]), - N(bfd_mach_mcf_isa_aplus_mac, "m68k:isa-aplus:mac", - FALSE, &arch_info_struct[15]), - N(bfd_mach_mcf_isa_aplus_emac, "m68k:isa-aplus:emac", - FALSE, &arch_info_struct[16]), - N(bfd_mach_mcf_isa_b_nousp, "m68k:isa-b:nousp", - FALSE, &arch_info_struct[17]), - N(bfd_mach_mcf_isa_b_nousp_mac, "m68k:isa-b:nousp:mac", - FALSE, &arch_info_struct[18]), - N(bfd_mach_mcf_isa_b_nousp_emac, "m68k:isa-b:nousp:emac", - FALSE, &arch_info_struct[19]), - N(bfd_mach_mcf_isa_b, "m68k:isa-b", - FALSE, &arch_info_struct[20]), - N(bfd_mach_mcf_isa_b_mac, "m68k:isa-b:mac", - FALSE, &arch_info_struct[21]), - N(bfd_mach_mcf_isa_b_emac, "m68k:isa-b:emac", - FALSE, &arch_info_struct[22]), - N(bfd_mach_mcf_isa_b_float, "m68k:isa-b:float", - FALSE, &arch_info_struct[23]), - N(bfd_mach_mcf_isa_b_float_mac, "m68k:isa-b:float:mac", - FALSE, &arch_info_struct[24]), - N(bfd_mach_mcf_isa_b_float_emac, "m68k:isa-b:float:emac", - FALSE, &arch_info_struct[25]), - N(bfd_mach_mcf_isa_c, "m68k:isa-c", - FALSE, &arch_info_struct[26]), - N(bfd_mach_mcf_isa_c_mac, "m68k:isa-c:mac", - FALSE, &arch_info_struct[27]), - N(bfd_mach_mcf_isa_c_emac, "m68k:isa-c:emac", - FALSE, &arch_info_struct[28]), - N(bfd_mach_mcf_isa_c_nodiv, "m68k:isa-c:nodiv", - FALSE, &arch_info_struct[29]), - N(bfd_mach_mcf_isa_c_nodiv_mac, "m68k:isa-c:nodiv:mac", - FALSE, &arch_info_struct[30]), - N(bfd_mach_mcf_isa_c_nodiv_emac, "m68k:isa-c:nodiv:emac", - FALSE, &arch_info_struct[31]), - - /* Legacy names for CF architectures */ - N(bfd_mach_mcf_isa_a_nodiv, "m68k:5200", FALSE, &arch_info_struct[32]), - N(bfd_mach_mcf_isa_a_mac,"m68k:5206e", FALSE, &arch_info_struct[33]), - N(bfd_mach_mcf_isa_a_mac, "m68k:5307", FALSE, &arch_info_struct[34]), - N(bfd_mach_mcf_isa_b_nousp_mac, "m68k:5407", FALSE, &arch_info_struct[35]), - N(bfd_mach_mcf_isa_aplus_emac, "m68k:528x", FALSE, &arch_info_struct[36]), - N(bfd_mach_mcf_isa_aplus_emac, "m68k:521x", FALSE, &arch_info_struct[37]), - N(bfd_mach_mcf_isa_a_emac, "m68k:5249", FALSE, &arch_info_struct[38]), - N(bfd_mach_mcf_isa_b_float_emac, "m68k:547x", - FALSE, &arch_info_struct[39]), - N(bfd_mach_mcf_isa_b_float_emac, "m68k:548x", - FALSE, &arch_info_struct[40]), - N(bfd_mach_mcf_isa_b_float_emac, "m68k:cfv4e", FALSE, 0), - }; - -const bfd_arch_info_type bfd_m68k_arch = - N(0, "m68k", TRUE, &arch_info_struct[0]); - -/* Table indexed by bfd_mach_arch number indicating which - architectural features are supported. */ -static const unsigned m68k_arch_features[] = -{ - 0, - m68000|m68881|m68851, - m68000|m68881|m68851, - m68010|m68881|m68851, - m68020|m68881|m68851, - m68030|m68881|m68851, - m68040|m68881|m68851, - m68060|m68881|m68851, - cpu32|m68881, - fido_a|m68881, - mcfisa_a, - mcfisa_a|mcfhwdiv, - mcfisa_a|mcfhwdiv|mcfmac, - mcfisa_a|mcfhwdiv|mcfemac, - mcfisa_a|mcfisa_aa|mcfhwdiv|mcfusp, - mcfisa_a|mcfisa_aa|mcfhwdiv|mcfusp|mcfmac, - mcfisa_a|mcfisa_aa|mcfhwdiv|mcfusp|mcfemac, - mcfisa_a|mcfhwdiv|mcfisa_b, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfemac, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|mcfmac, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|mcfemac, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfmac, - mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac, - mcfisa_a|mcfhwdiv|mcfisa_c|mcfusp, - mcfisa_a|mcfhwdiv|mcfisa_c|mcfusp|mcfmac, - mcfisa_a|mcfhwdiv|mcfisa_c|mcfusp|mcfemac, - mcfisa_a|mcfisa_c|mcfusp, - mcfisa_a|mcfisa_c|mcfusp|mcfmac, - mcfisa_a|mcfisa_c|mcfusp|mcfemac, -}; - -/* Return the count of bits set in MASK */ -static unsigned -bit_count (unsigned mask) -{ - unsigned ix; - - for (ix = 0; mask; ix++) - /* Clear the LSB set */ - mask ^= mask & -mask; - return ix; -} - -/* Return the architectural features supported by MACH */ - -unsigned -bfd_m68k_mach_to_features (int mach) -{ - if ((unsigned)mach - >= sizeof (m68k_arch_features) / sizeof (m68k_arch_features[0])) - mach = 0; - return m68k_arch_features[mach]; -} - -/* Return the bfd machine that most closely represents the - architectural features. We find the machine with the smallest - number of additional features. If there is no such machine, we - find the one with the smallest number of missing features. */ - -int bfd_m68k_features_to_mach (unsigned features) -{ - int superset = 0, subset = 0; - unsigned extra = 99, missing = 99; - unsigned ix; - - for (ix = 0; - ix != sizeof (m68k_arch_features) / sizeof (m68k_arch_features[0]); - ix++) - { - unsigned this_extra, this_missing; - - if (m68k_arch_features[ix] == features) - return ix; - this_extra = bit_count (m68k_arch_features[ix] & ~features); - if (this_extra < extra) - { - extra = this_extra; - superset = ix; - } - - this_missing = bit_count (features & ~m68k_arch_features[ix]); - if (this_missing < missing) - { - missing = this_missing; - superset = ix; - } - } - return superset ? superset : subset; -} - -static const bfd_arch_info_type * -bfd_m68k_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) - return b; - if (!b->mach) - return a; - - if (a->mach <= bfd_mach_m68060 && b->mach <= bfd_mach_m68060) - /* Merge m68k machine. */ - return a->mach > b->mach ? a : b; - else if (a->mach >= bfd_mach_cpu32 && b->mach >= bfd_mach_cpu32) - { - /* Merge the machine features. */ - unsigned features = (bfd_m68k_mach_to_features (a->mach) - | bfd_m68k_mach_to_features (b->mach)); - - /* CPU32 and Coldfire are incompatible. */ - if ((~features & (cpu32 | mcfisa_a)) == 0) - return NULL; - - /* Fido and Coldfire are incompatible. */ - if ((~features & (fido_a | mcfisa_a)) == 0) - return NULL; - - /* ISA A+ and ISA B are incompatible. */ - if ((~features & (mcfisa_aa | mcfisa_b)) == 0) - return NULL; - - /* ISA B and ISA C are incompatible. */ - if ((~features & (mcfisa_b | mcfisa_c)) == 0) - return NULL; - - /* MAC and EMAC code cannot be merged. */ - if ((~features & (mcfmac | mcfemac)) == 0) - return NULL; - - /* CPU32 is compatible with Fido except that Fido does not - support tbl instructions. Warn when the user wants to mix - the two. */ - if ((a->mach == bfd_mach_cpu32 && b->mach == bfd_mach_fido) - || (a->mach == bfd_mach_fido && b->mach == bfd_mach_cpu32)) - { - static int cpu32_fido_mix_warning; - if (!cpu32_fido_mix_warning) - { - cpu32_fido_mix_warning = 1; - _bfd_error_handler ("warning: linking CPU32 objects with fido objects"); - } - return bfd_lookup_arch (a->arch, - bfd_m68k_features_to_mach (fido_a | m68881)); - } - - return bfd_lookup_arch (a->arch, bfd_m68k_features_to_mach (features)); - } - else - /* They are incompatible. */ - return NULL; -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-m88k.c b/sdcc/support/sdbinutils/bfd/cpu-m88k.c deleted file mode 100644 index 840efb38c..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m88k.c +++ /dev/null @@ -1,41 +0,0 @@ -/* bfd back-end for m88k support - Copyright (C) 1990-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_m88k_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_m88k, - 88100, /* only 1 machine */ - "m88k", - "m88k:88100", - 3, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-m9s12x.c b/sdcc/support/sdbinutils/bfd/cpu-m9s12x.c deleted file mode 100644 index b2e3daefb..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m9s12x.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the Freescale 9S12X processor - Copyright (C) 2008-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_m9s12x_arch = -{ - 16, /* 16 bits in a word. */ - 32, /* 16 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_m9s12x, - 0, - "m9s12x", - "m9s12x", - 4, /* Section alignment power. */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; - diff --git a/sdcc/support/sdbinutils/bfd/cpu-m9s12xg.c b/sdcc/support/sdbinutils/bfd/cpu-m9s12xg.c deleted file mode 100644 index 19c32390f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-m9s12xg.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the Freescale 9S12-XGATE co-processor - Copyright (C) 2008-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_m9s12xg_arch = -{ - 16, /* 16 bits in a word. */ - 32, /* 16 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_m9s12xg, - 0, - "m9s12xg", - "m9s12xg", - 4, /* Section alignment power. */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; - diff --git a/sdcc/support/sdbinutils/bfd/cpu-mcore.c b/sdcc/support/sdbinutils/bfd/cpu-mcore.c deleted file mode 100644 index 727383187..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-mcore.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD library support routines for Motorola's MCore architecture - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_mcore_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_mcore, /* Architecture */ - 0, /* Machine number - 0 for now */ - "MCore", /* Architecture name */ - "MCore", /* Printable name */ - 3, /* Section align power */ - TRUE, /* Is this the default architecture ? */ - bfd_default_compatible, /* Architecture comparison function */ - bfd_default_scan, /* String to architecture conversion */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-mep.c b/sdcc/support/sdbinutils/bfd/cpu-mep.c deleted file mode 100644 index 3719386a6..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-mep.c +++ /dev/null @@ -1,30 +0,0 @@ -/* BFD support for the Toshiba Media Engine Processor. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#define MA(x, n, def, y) { 32, 32, 8, bfd_arch_mep, x, "mep", n, \ - 2, def, bfd_default_compatible, bfd_default_scan, \ - bfd_arch_default_fill, y } - -static const bfd_arch_info_type bfd_c5_arch = MA (bfd_mach_mep_c5, "c5", FALSE, NULL); -static const bfd_arch_info_type bfd_h1_arch = MA (bfd_mach_mep_h1, "h1", FALSE, & bfd_c5_arch); -const bfd_arch_info_type bfd_mep_arch = MA (bfd_mach_mep, "mep", TRUE, & bfd_h1_arch); diff --git a/sdcc/support/sdbinutils/bfd/cpu-metag.c b/sdcc/support/sdbinutils/bfd/cpu-metag.c deleted file mode 100644 index 23c8d0c4f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-metag.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the Imagination Technologies Meta processor. - Copyright (C) 2013-2018 Free Software Foundation, Inc. - Contributed by Imagination Technologies Ltd. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_metag_arch = -{ - 32, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_metag, /* Architecture. */ - bfd_mach_metag, /* Machine. */ - "metag", /* Architecture name. */ - "metag", /* Printable name. */ - 4, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-microblaze.c b/sdcc/support/sdbinutils/bfd/cpu-microblaze.c deleted file mode 100644 index 2ccf7242f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-microblaze.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD Xilinx MicroBlaze architecture definition - - Copyright (C) 2009-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_microblaze_arch = -{ - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_microblaze, /* Architecture. */ - 0, /* Machine number - 0 for now. */ - "microblaze", /* Architecture name. */ - "MicroBlaze", /* Printable name. */ - 3, /* Section align power. */ - TRUE, /* Is this the default architecture ? */ - bfd_default_compatible, /* Architecture comparison function. */ - bfd_default_scan, /* String to architecture conversion. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-mips.c b/sdcc/support/sdbinutils/bfd/cpu-mips.c deleted file mode 100644 index cb50c6437..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-mips.c +++ /dev/null @@ -1,169 +0,0 @@ -/* bfd back-end for mips support - Copyright (C) 1990-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -static const bfd_arch_info_type *mips_compatible - (const bfd_arch_info_type *, const bfd_arch_info_type *); - -/* The default routine tests bits_per_word, which is wrong on mips as - mips word size doesn't correlate with reloc size. */ - -static const bfd_arch_info_type * -mips_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) -{ - if (a->arch != b->arch) - return NULL; - - /* Machine compatibility is checked in - _bfd_mips_elf_merge_private_bfd_data. */ - - return a; -} - -#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ - { \ - BITS_WORD, /* bits in a word */ \ - BITS_ADDR, /* bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_mips, \ - NUMBER, \ - "mips", \ - PRINT, \ - 3, \ - DEFAULT, \ - mips_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - NEXT, \ - } - -enum -{ - I_mips3000, - I_mips3900, - I_mips4000, - I_mips4010, - I_mips4100, - I_mips4111, - I_mips4120, - I_mips4300, - I_mips4400, - I_mips4600, - I_mips4650, - I_mips5000, - I_mips5400, - I_mips5500, - I_mips5900, - I_mips6000, - I_mips7000, - I_mips8000, - I_mips9000, - I_mips10000, - I_mips12000, - I_mips14000, - I_mips16000, - I_mips16, - I_mips5, - I_mipsisa32, - I_mipsisa32r2, - I_mipsisa32r3, - I_mipsisa32r5, - I_mipsisa32r6, - I_mipsisa64, - I_mipsisa64r2, - I_mipsisa64r3, - I_mipsisa64r5, - I_mipsisa64r6, - I_sb1, - I_loongson_2e, - I_loongson_2f, - I_loongson_3a, - I_mipsocteon, - I_mipsocteonp, - I_mipsocteon2, - I_mipsocteon3, - I_xlr, - I_interaptiv_mr2, - I_micromips -}; - -#define NN(index) (&arch_info_struct[(index) + 1]) - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (32, 32, bfd_mach_mips3000, "mips:3000", FALSE, NN(I_mips3000)), - N (32, 32, bfd_mach_mips3900, "mips:3900", FALSE, NN(I_mips3900)), - N (64, 64, bfd_mach_mips4000, "mips:4000", FALSE, NN(I_mips4000)), - N (32, 32, bfd_mach_mips4010, "mips:4010", FALSE, NN(I_mips4010)), - N (64, 64, bfd_mach_mips4100, "mips:4100", FALSE, NN(I_mips4100)), - N (64, 64, bfd_mach_mips4111, "mips:4111", FALSE, NN(I_mips4111)), - N (64, 64, bfd_mach_mips4120, "mips:4120", FALSE, NN(I_mips4120)), - N (64, 64, bfd_mach_mips4300, "mips:4300", FALSE, NN(I_mips4300)), - N (64, 64, bfd_mach_mips4400, "mips:4400", FALSE, NN(I_mips4400)), - N (64, 64, bfd_mach_mips4600, "mips:4600", FALSE, NN(I_mips4600)), - N (64, 64, bfd_mach_mips4650, "mips:4650", FALSE, NN(I_mips4650)), - N (64, 64, bfd_mach_mips5000, "mips:5000", FALSE, NN(I_mips5000)), - N (64, 64, bfd_mach_mips5400, "mips:5400", FALSE, NN(I_mips5400)), - N (64, 64, bfd_mach_mips5500, "mips:5500", FALSE, NN(I_mips5500)), - N (64, 32, bfd_mach_mips5900, "mips:5900", FALSE, NN(I_mips5900)), - N (32, 32, bfd_mach_mips6000, "mips:6000", FALSE, NN(I_mips6000)), - N (64, 64, bfd_mach_mips7000, "mips:7000", FALSE, NN(I_mips7000)), - N (64, 64, bfd_mach_mips8000, "mips:8000", FALSE, NN(I_mips8000)), - N (64, 64, bfd_mach_mips9000, "mips:9000", FALSE, NN(I_mips9000)), - N (64, 64, bfd_mach_mips10000,"mips:10000", FALSE, NN(I_mips10000)), - N (64, 64, bfd_mach_mips12000,"mips:12000", FALSE, NN(I_mips12000)), - N (64, 64, bfd_mach_mips14000,"mips:14000", FALSE, NN(I_mips14000)), - N (64, 64, bfd_mach_mips16000,"mips:16000", FALSE, NN(I_mips16000)), - N (64, 64, bfd_mach_mips16, "mips:16", FALSE, NN(I_mips16)), - N (64, 64, bfd_mach_mips5, "mips:mips5", FALSE, NN(I_mips5)), - N (32, 32, bfd_mach_mipsisa32, "mips:isa32", FALSE, NN(I_mipsisa32)), - N (32, 32, bfd_mach_mipsisa32r2,"mips:isa32r2", FALSE, NN(I_mipsisa32r2)), - N (32, 32, bfd_mach_mipsisa32r3,"mips:isa32r3", FALSE, NN(I_mipsisa32r3)), - N (32, 32, bfd_mach_mipsisa32r5,"mips:isa32r5", FALSE, NN(I_mipsisa32r5)), - N (32, 32, bfd_mach_mipsisa32r6,"mips:isa32r6", FALSE, NN(I_mipsisa32r6)), - N (64, 64, bfd_mach_mipsisa64, "mips:isa64", FALSE, NN(I_mipsisa64)), - N (64, 64, bfd_mach_mipsisa64r2,"mips:isa64r2", FALSE, NN(I_mipsisa64r2)), - N (64, 64, bfd_mach_mipsisa64r3,"mips:isa64r3", FALSE, NN(I_mipsisa64r3)), - N (64, 64, bfd_mach_mipsisa64r5,"mips:isa64r5", FALSE, NN(I_mipsisa64r5)), - N (64, 64, bfd_mach_mipsisa64r6,"mips:isa64r6", FALSE, NN(I_mipsisa64r6)), - N (64, 64, bfd_mach_mips_sb1, "mips:sb1", FALSE, NN(I_sb1)), - N (64, 64, bfd_mach_mips_loongson_2e, "mips:loongson_2e", FALSE, NN(I_loongson_2e)), - N (64, 64, bfd_mach_mips_loongson_2f, "mips:loongson_2f", FALSE, NN(I_loongson_2f)), - N (64, 64, bfd_mach_mips_loongson_3a, "mips:loongson_3a", FALSE, NN(I_loongson_3a)), - N (64, 64, bfd_mach_mips_octeon,"mips:octeon", FALSE, NN(I_mipsocteon)), - N (64, 64, bfd_mach_mips_octeonp,"mips:octeon+", FALSE, NN(I_mipsocteonp)), - N (64, 64, bfd_mach_mips_octeon2,"mips:octeon2", FALSE, NN(I_mipsocteon2)), - N (64, 64, bfd_mach_mips_octeon3, "mips:octeon3", FALSE, NN(I_mipsocteon3)), - N (64, 64, bfd_mach_mips_xlr, "mips:xlr", FALSE, NN(I_xlr)), - N (32, 32, bfd_mach_mips_interaptiv_mr2, "mips:interaptiv-mr2", FALSE, - NN(I_interaptiv_mr2)), - N (64, 64, bfd_mach_mips_micromips,"mips:micromips",FALSE,0) -}; - -/* The default architecture is mips:3000, but with a machine number of - zero. This lets the linker distinguish between a default setting - of mips, and an explicit setting of mips:3000. */ - -const bfd_arch_info_type bfd_mips_arch = -N (32, 32, 0, "mips", TRUE, &arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-mmix.c b/sdcc/support/sdbinutils/bfd/cpu-mmix.c deleted file mode 100644 index b8d44d0fe..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-mmix.c +++ /dev/null @@ -1,43 +0,0 @@ -/* BFD library support routines for MMIX. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - Contributed by Hans-Peter Nilsson (hp@bitrange.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type -bfd_mmix_arch = - { - 64, /* 64 bits in a word. */ - 64, /* 64 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_mmix, /* Architecture. */ - 0, /* Machine number - 0 for now. */ - /* Sorry, these are by custom and creeping assumption lower-case. */ - "mmix", /* Architecture name. */ - "mmix", /* Printable name. */ - 3, /* Section align power. */ - TRUE, /* This is the default architecture. */ - bfd_default_compatible, /* Architecture comparison function. */ - bfd_default_scan, /* String to architecture conversion. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-moxie.c b/sdcc/support/sdbinutils/bfd/cpu-moxie.c deleted file mode 100644 index 03eb55c20..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-moxie.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the moxie processor. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Written by Anthony Green - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - - -const bfd_arch_info_type bfd_moxie_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_moxie, /* enum bfd_architecture arch. */ - bfd_mach_moxie, - "moxie", /* Arch name. */ - "moxie", /* Printable name. */ - 2, /* Unsigned int section alignment power. */ - TRUE, /* The one and only. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-msp430.c b/sdcc/support/sdbinutils/bfd/cpu-msp430.c deleted file mode 100644 index 5ab9e4058..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-msp430.c +++ /dev/null @@ -1,138 +0,0 @@ -/* BFD library support routines for the MSP architecture. - Copyright (C) 2002-2018 Free Software Foundation, Inc. - Contributed by Dmitry Diky - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* This routine is provided two arch_infos and works out which MSP - machine which would be compatible with both and returns a pointer - to its info structure. */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type * a, - const bfd_arch_info_type * b) -{ - /* If a & b are for different architectures we can do nothing. */ - if (a->arch != b->arch) - return NULL; - - if (a->mach <= b->mach) - return b; - - return a; -} - -#define N(addr_bits, machine, print, default, next) \ -{ \ - 16, /* 16 bits in a word. */ \ - addr_bits, /* Bits in an address. */ \ - 8, /* 8 bits in a byte. */ \ - bfd_arch_msp430, \ - machine, /* Machine number. */ \ - "msp430", /* Architecture name. */ \ - print, /* Printable name. */ \ - 1, /* Section align power. */ \ - default, /* The default machine. */ \ - compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - next \ -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - /* msp430x11x. */ - N (16, bfd_mach_msp11, "MSP430", FALSE, & arch_info_struct[1]), - - /* msp430x11x1. */ - N (16, bfd_mach_msp110, "MSP430x11x1", FALSE, & arch_info_struct[2]), - - /* msp430x12x. */ - N (16, bfd_mach_msp12, "MSP430x12", FALSE, & arch_info_struct[3]), - - /* msp430x13x. */ - N (16, bfd_mach_msp13, "MSP430x13", FALSE, & arch_info_struct[4]), - - /* msp430x14x. */ - N (16, bfd_mach_msp14, "MSP430x14", FALSE, & arch_info_struct[5]), - - /* msp430x15x. */ - N (16, bfd_mach_msp15, "MSP430x15", FALSE, & arch_info_struct[6]), - - /* msp430x16x. */ - N (16, bfd_mach_msp16, "MSP430x16", FALSE, & arch_info_struct[7]), - - /* msp430x20x. */ - N (16, bfd_mach_msp20, "MSP430x20", FALSE, & arch_info_struct[8]), - - /* msp430x21x. */ - N (16, bfd_mach_msp21, "MSP430x21", FALSE, & arch_info_struct[9]), - - /* msp430x22x. */ - N (16, bfd_mach_msp22, "MSP430x22", FALSE, & arch_info_struct[10]), - - /* msp430x23x. */ - N (16, bfd_mach_msp23, "MSP430x23", FALSE, & arch_info_struct[11]), - - /* msp430x24x. */ - N (16, bfd_mach_msp24, "MSP430x24", FALSE, & arch_info_struct[12]), - - /* msp430x26x. */ - N (16, bfd_mach_msp26, "MSP430x26", FALSE, & arch_info_struct[13]), - - /* msp430x31x. */ - N (16, bfd_mach_msp31, "MSP430x31", FALSE, & arch_info_struct[14]), - - /* msp430x32x. */ - N (16, bfd_mach_msp32, "MSP430x32", FALSE, & arch_info_struct[15]), - - /* msp430x33x. */ - N (16, bfd_mach_msp33, "MSP430x33", FALSE, & arch_info_struct[16]), - - /* msp430x41x. */ - N (16, bfd_mach_msp41, "MSP430x41", FALSE, & arch_info_struct[17]), - - /* msp430x42x. */ - N (16, bfd_mach_msp42, "MSP430x42", FALSE, & arch_info_struct[18]), - - /* msp430x43x. */ - N (16, bfd_mach_msp43, "MSP430x43", FALSE, & arch_info_struct[19]), - - /* msp430x44x. */ - N (16, bfd_mach_msp43, "MSP430x44", FALSE, & arch_info_struct[20]), - - /* msp430x46x. */ - N (16, bfd_mach_msp46, "MSP430x46", FALSE, & arch_info_struct[21]), - - /* msp430x47x. */ - N (16, bfd_mach_msp47, "MSP430x47", FALSE, & arch_info_struct[22]), - - /* msp430x54x. */ - N (16, bfd_mach_msp54, "MSP430x54", FALSE, & arch_info_struct[23]), - - N (32, bfd_mach_msp430x, "MSP430X", FALSE, NULL) - -}; - -const bfd_arch_info_type bfd_msp430_arch = - N (16, bfd_mach_msp14, "msp:14", TRUE, & arch_info_struct[0]); - diff --git a/sdcc/support/sdbinutils/bfd/cpu-mt.c b/sdcc/support/sdbinutils/bfd/cpu-mt.c deleted file mode 100644 index 1592d1370..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-mt.c +++ /dev/null @@ -1,75 +0,0 @@ -/* BFD support for the Morpho Technologies MT processor. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type arch_info_struct[] = -{ -{ - 32, /* Bits per word - not really true. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_mt, /* Architecture. */ - bfd_mach_mrisc2, /* Machine. */ - "mt", /* Architecture name. */ - "ms1-003", /* Printable name. */ - 1, /* Section align power. */ - FALSE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - &arch_info_struct[1] /* Next in list. */ -}, -{ - 32, /* Bits per word - not really true. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_mt, /* Architecture. */ - bfd_mach_ms2, /* Machine. */ - "mt", /* Architecture name. */ - "ms2", /* Printable name. */ - 1, /* Section align power. */ - FALSE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}, -}; - -const bfd_arch_info_type bfd_mt_arch = -{ - 32, /* Bits per word - not really true. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_mt, /* Architecture. */ - bfd_mach_ms1, /* Machine. */ - "mt", /* Architecture name. */ - "ms1", /* Printable name. */ - 1, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - &arch_info_struct[0] /* Next in list. */ -}; - diff --git a/sdcc/support/sdbinutils/bfd/cpu-nds32.c b/sdcc/support/sdbinutils/bfd/cpu-nds32.c deleted file mode 100644 index 2dbf20bed..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-nds32.c +++ /dev/null @@ -1,45 +0,0 @@ -/* BFD support for the NDS32 processor - Copyright (C) 2012-2018 Free Software Foundation, Inc. - Contributed by Andes Technology Corporation. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -#define N(number, print, default, next) \ - {32, 32, 8, bfd_arch_nds32, number, "nds32", print, 4, default, \ - bfd_default_compatible, bfd_default_scan, bfd_arch_default_fill, next } - -#define NEXT &arch_info_struct[0] -#define NDS32V2_NEXT &arch_info_struct[1] -#define NDS32V3_NEXT &arch_info_struct[2] -#define NDS32V3M_NEXT &arch_info_struct[3] - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (bfd_mach_n1h, "n1h", FALSE, NDS32V2_NEXT), - N (bfd_mach_n1h_v2, "n1h_v2", FALSE, NDS32V3_NEXT), - N (bfd_mach_n1h_v3, "n1h_v3", FALSE, NDS32V3M_NEXT), - N (bfd_mach_n1h_v3m, "n1h_v3m", FALSE, NULL), -}; - -const bfd_arch_info_type bfd_nds32_arch = - N (bfd_mach_n1, "n1h", TRUE, NEXT); diff --git a/sdcc/support/sdbinutils/bfd/cpu-nios2.c b/sdcc/support/sdbinutils/bfd/cpu-nios2.c deleted file mode 100644 index f67b3213b..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-nios2.c +++ /dev/null @@ -1,74 +0,0 @@ -/* BFD support for the Altera Nios II processor. - Copyright (C) 2012-2018 Free Software Foundation, Inc. - Contributed by Nigel Gray (ngray@altera.com). - Contributed by Mentor Graphics, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static const bfd_arch_info_type * -nios2_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 == bfd_mach_nios2) - return a; - else if (b->mach == bfd_mach_nios2) - return b; - else if (a->mach != b->mach) - return NULL; - - return a; -} - -#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ - { \ - BITS_WORD, /* bits in a word */ \ - BITS_ADDR, /* bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_nios2, \ - NUMBER, \ - "nios2", \ - PRINT, \ - 3, \ - DEFAULT, \ - nios2_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - NEXT \ - } - -#define NIOS2R1_NEXT &arch_info_struct[0] -#define NIOS2R2_NEXT &arch_info_struct[1] - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (32, 32, bfd_mach_nios2r1, "nios2:r1", FALSE, NIOS2R2_NEXT), - N (32, 32, bfd_mach_nios2r2, "nios2:r2", FALSE, NULL), -}; - -const bfd_arch_info_type bfd_nios2_arch = - N (32, 32, 0, "nios2", TRUE, NIOS2R1_NEXT); diff --git a/sdcc/support/sdbinutils/bfd/cpu-ns32k.c b/sdcc/support/sdbinutils/bfd/cpu-ns32k.c deleted file mode 100644 index cbd62d3a5..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-ns32k.c +++ /dev/null @@ -1,814 +0,0 @@ -/* BFD support for the ns32k architecture. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Almost totally rewritten by Ian Dall from initial work - by Andrew Cagney. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "ns32k.h" - -#define N(machine, printable, d, next) \ -{ 32, 32, 8, bfd_arch_ns32k, machine, "ns32k",printable,3,d, \ - bfd_default_compatible,bfd_default_scan,bfd_arch_default_fill,next, } - -static const bfd_arch_info_type arch_info_struct[] = -{ - N(32532,"ns32k:32532",TRUE, 0), /* The word ns32k will match this too. */ -}; - -const bfd_arch_info_type bfd_ns32k_arch = - N(32032,"ns32k:32032",FALSE, &arch_info_struct[0]); - -bfd_vma -_bfd_ns32k_get_displacement (bfd_byte *buffer, int size) -{ - bfd_signed_vma value; - - switch (size) - { - case 1: - value = ((*buffer & 0x7f) ^ 0x40) - 0x40; - break; - - case 2: - value = ((*buffer++ & 0x3f) ^ 0x20) - 0x20; - value = (value << 8) | (0xff & *buffer); - break; - - case 4: - value = ((*buffer++ & 0x3f) ^ 0x20) - 0x20; - value = (value << 8) | (0xff & *buffer++); - value = (value << 8) | (0xff & *buffer++); - value = (value << 8) | (0xff & *buffer); - break; - - default: - abort (); - return 0; - } - - return value; -} - -void -_bfd_ns32k_put_displacement (bfd_vma value, bfd_byte *buffer, int size) -{ - switch (size) - { - case 1: - value &= 0x7f; - *buffer++ = value; - break; - - case 2: - value &= 0x3fff; - value |= 0x8000; - *buffer++ = (value >> 8); - *buffer++ = value; - break; - - case 4: - value |= (bfd_vma) 0xc0000000; - *buffer++ = (value >> 24); - *buffer++ = (value >> 16); - *buffer++ = (value >> 8); - *buffer++ = value; - break; - } - return; -} - -bfd_vma -_bfd_ns32k_get_immediate (bfd_byte *buffer, int size) -{ - bfd_vma value = 0; - - switch (size) - { - case 4: - value = (value << 8) | (*buffer++ & 0xff); - value = (value << 8) | (*buffer++ & 0xff); - /* Fall through. */ - case 2: - value = (value << 8) | (*buffer++ & 0xff); - /* Fall through. */ - case 1: - value = (value << 8) | (*buffer++ & 0xff); - break; - default: - abort (); - } - return value; -} - -void -_bfd_ns32k_put_immediate (bfd_vma value, bfd_byte *buffer, int size) -{ - buffer += size - 1; - switch (size) - { - case 4: - *buffer-- = (value & 0xff); value >>= 8; - *buffer-- = (value & 0xff); value >>= 8; - /* Fall through. */ - case 2: - *buffer-- = (value & 0xff); value >>= 8; - /* Fall through. */ - case 1: - *buffer-- = (value & 0xff); value >>= 8; - } -} - -/* This is just like the standard perform_relocation except we - use get_data and put_data which know about the ns32k storage - methods. This is probably a lot more complicated than it - needs to be! */ - -static bfd_reloc_status_type -do_ns32k_reloc (bfd * abfd, - arelent * reloc_entry, - struct bfd_symbol * symbol, - void * data, - asection * input_section, - bfd * output_bfd, - char ** error_message ATTRIBUTE_UNUSED, - bfd_vma (* get_data) (bfd_byte *, int), - void (* put_data) (bfd_vma, bfd_byte *, int)) -{ - int overflow = 0; - bfd_vma relocation; - bfd_reloc_status_type flag = bfd_reloc_ok; - bfd_size_type addr = reloc_entry->address; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - asection *reloc_target_output_section; - bfd_byte *location; - - if (bfd_is_abs_section (symbol->section) - && output_bfd != (bfd *) NULL) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* If we are not producing 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 == (bfd *) NULL) - flag = bfd_reloc_undefined; - - /* 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 != NULL && ! 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) - relocation -= reloc_entry->address; - } - - if (output_bfd != (bfd *) NULL) - { - if (! howto->partial_inplace) - { - /* This is a partial relocation, and we want to apply the relocation - to the reloc entry rather than the raw data. Modify the reloc - inplace to reflect what we now know. */ - reloc_entry->addend = relocation; - reloc_entry->address += input_section->output_offset; - return flag; - } - else - { - /* This is a partial relocation, but inplace, so modify the - reloc record a bit. - - If we've relocated with a symbol with a section, change - into a ref to the section belonging to the symbol. */ - - reloc_entry->address += input_section->output_offset; - - /* WTF?? */ - if (abfd->xvec->flavour == bfd_target_coff_flavour) - { - /* 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) - { - bfd_vma check; - - /* Get the value that will be used for the relocation, but - starting at bit position zero. */ - if (howto->rightshift > howto->bitpos) - check = relocation >> (howto->rightshift - howto->bitpos); - else - check = relocation << (howto->bitpos - howto->rightshift); - switch (howto->complain_on_overflow) - { - case complain_overflow_signed: - { - /* Assumes two's complement. */ - bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; - bfd_signed_vma reloc_signed_min = ~reloc_signed_max; - - /* The above right shift is incorrect for a signed value. - Fix it up by forcing on the upper bits. */ - if (howto->rightshift > howto->bitpos - && (bfd_signed_vma) relocation < 0) - check |= ((bfd_vma) - 1 - & ~((bfd_vma) - 1 - >> (howto->rightshift - howto->bitpos))); - if ((bfd_signed_vma) check > reloc_signed_max - || (bfd_signed_vma) check < reloc_signed_min) - flag = bfd_reloc_overflow; - } - break; - case complain_overflow_unsigned: - { - /* Assumes two's complement. This expression avoids - overflow if howto->bitsize is the number of bits in - bfd_vma. */ - bfd_vma reloc_unsigned_max = - (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if ((bfd_vma) check > reloc_unsigned_max) - flag = bfd_reloc_overflow; - } - break; - case complain_overflow_bitfield: - { - /* Assumes two's complement. This expression avoids - overflow if howto->bitsize is the number of bits in - bfd_vma. */ - bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if (((bfd_vma) check & ~reloc_bits) != 0 - && (((bfd_vma) check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits))) - { - /* The above right shift is incorrect for a signed - value. See if turning on the upper bits fixes the - overflow. */ - if (howto->rightshift > howto->bitpos - && (bfd_signed_vma) relocation < 0) - { - check |= ((bfd_vma) - 1 - & ~((bfd_vma) - 1 - >> (howto->rightshift - howto->bitpos))); - if (((bfd_vma) check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits)) - flag = bfd_reloc_overflow; - } - else - flag = bfd_reloc_overflow; - } - } - break; - default: - abort (); - } - } - - /* 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)) - - location = (bfd_byte *) data + addr; - switch (howto->size) - { - case 0: - { - bfd_vma x = get_data (location, 1); - DOIT (x); - put_data ((bfd_vma) x, location, 1); - } - break; - - case 1: - if (relocation) - { - bfd_vma x = get_data (location, 2); - DOIT (x); - put_data ((bfd_vma) x, location, 2); - } - break; - case 2: - if (relocation) - { - bfd_vma x = get_data (location, 4); - DOIT (x); - put_data ((bfd_vma) x, location, 4); - } - break; - case -2: - { - bfd_vma x = get_data (location, 4); - relocation = -relocation; - DOIT(x); - put_data ((bfd_vma) x, location, 4); - } - break; - - case 3: - /* Do nothing. */ - break; - - case 4: -#ifdef BFD64 - if (relocation) - { - bfd_vma x = get_data (location, 8); - DOIT (x); - put_data (x, location, 8); - } -#else - abort (); -#endif - break; - default: - return bfd_reloc_other; - } - if ((howto->complain_on_overflow != complain_overflow_dont) && overflow) - return bfd_reloc_overflow; - - return flag; -} - -/* Relocate a given location using a given value and howto. */ - -bfd_reloc_status_type -_bfd_do_ns32k_reloc_contents (reloc_howto_type *howto, - bfd *input_bfd ATTRIBUTE_UNUSED, - bfd_vma relocation, - bfd_byte *location, - bfd_vma (*get_data) (bfd_byte *, int), - void (*put_data) (bfd_vma, bfd_byte *, int)) -{ - int size; - bfd_vma x; - bfd_boolean overflow; - - /* If the size is negative, negate RELOCATION. This isn't very - general. */ - if (howto->size < 0) - relocation = -relocation; - - /* Get the value we are going to relocate. */ - size = bfd_get_reloc_size (howto); - switch (size) - { - default: - abort (); - case 0: - return bfd_reloc_ok; - case 1: - case 2: - case 4: -#ifdef BFD64 - case 8: -#endif - x = get_data (location, size); - 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. */ - overflow = FALSE; - if (howto->complain_on_overflow != complain_overflow_dont) - { - bfd_vma check; - bfd_signed_vma signed_check; - bfd_vma add; - bfd_signed_vma signed_add; - - if (howto->rightshift == 0) - { - check = relocation; - signed_check = (bfd_signed_vma) relocation; - } - else - { - /* Drop unwanted bits from the value we are relocating to. */ - check = relocation >> howto->rightshift; - - /* If this is a signed value, the rightshift just dropped - leading 1 bits (assuming twos complement). */ - if ((bfd_signed_vma) relocation >= 0) - signed_check = check; - else - signed_check = (check - | ((bfd_vma) - 1 - & ~((bfd_vma) - 1 >> howto->rightshift))); - } - - /* Get the value from the object file. */ - add = x & howto->src_mask; - - /* Get the value from the object file with an appropriate sign. - The expression involving howto->src_mask isolates the upper - bit of src_mask. If that bit is set in the value we are - adding, it is negative, and we subtract out that number times - two. If src_mask includes the highest possible bit, then we - can not get the upper bit, but that does not matter since - signed_add needs no adjustment to become negative in that - case. */ - signed_add = add; - if ((add & (((~howto->src_mask) >> 1) & howto->src_mask)) != 0) - signed_add -= (((~howto->src_mask) >> 1) & howto->src_mask) << 1; - - /* Add the value from the object file, shifted so that it is a - straight number. */ - if (howto->bitpos == 0) - { - check += add; - signed_check += signed_add; - } - else - { - check += add >> howto->bitpos; - - /* For the signed case we use ADD, rather than SIGNED_ADD, - to avoid warnings from SVR4 cc. This is OK since we - explicitly handle the sign bits. */ - if (signed_add >= 0) - signed_check += add >> howto->bitpos; - else - signed_check += ((add >> howto->bitpos) - | ((bfd_vma) - 1 - & ~((bfd_vma) - 1 >> howto->bitpos))); - } - - switch (howto->complain_on_overflow) - { - case complain_overflow_signed: - { - /* Assumes two's complement. */ - bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; - bfd_signed_vma reloc_signed_min = ~reloc_signed_max; - - if (signed_check > reloc_signed_max - || signed_check < reloc_signed_min) - overflow = TRUE; - } - break; - case complain_overflow_unsigned: - { - /* Assumes two's complement. This expression avoids - overflow if howto->bitsize is the number of bits in - bfd_vma. */ - bfd_vma reloc_unsigned_max = - (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if (check > reloc_unsigned_max) - overflow = TRUE; - } - break; - case complain_overflow_bitfield: - { - /* Assumes two's complement. This expression avoids - overflow if howto->bitsize is the number of bits in - bfd_vma. */ - bfd_vma reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if ((check & ~reloc_bits) != 0 - && (((bfd_vma) signed_check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits))) - overflow = TRUE; - } - break; - default: - abort (); - } - } - - /* Put RELOCATION in the right bits. */ - relocation >>= (bfd_vma) howto->rightshift; - relocation <<= (bfd_vma) howto->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: - case 2: - case 4: -#ifdef BFD64 - case 8: -#endif - put_data (x, location, size); - break; - } - - return overflow ? bfd_reloc_overflow : bfd_reloc_ok; -} - -bfd_reloc_status_type -_bfd_ns32k_reloc_disp (bfd *abfd, - arelent *reloc_entry, - struct bfd_symbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - return do_ns32k_reloc (abfd, reloc_entry, symbol, data, input_section, - output_bfd, error_message, - _bfd_ns32k_get_displacement, - _bfd_ns32k_put_displacement); -} - -bfd_reloc_status_type -_bfd_ns32k_reloc_imm (bfd *abfd, - arelent *reloc_entry, - struct bfd_symbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - return do_ns32k_reloc (abfd, reloc_entry, symbol, data, input_section, - output_bfd, error_message, _bfd_ns32k_get_immediate, - _bfd_ns32k_put_immediate); -} - -bfd_reloc_status_type -_bfd_ns32k_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_ns32k_relocate_contents (howto, input_bfd, relocation, - contents + address); -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-or1k.c b/sdcc/support/sdbinutils/bfd/cpu-or1k.c deleted file mode 100644 index 8cf6aacf6..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-or1k.c +++ /dev/null @@ -1,59 +0,0 @@ -/* BFD support for the OpenRISC 1000 architecture. - Copyright (C) 2002-2018 Free Software Foundation, Inc. - Contributed for OR32 by Ivan Guzvinec - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_or1k_arch; -const bfd_arch_info_type bfd_or1knd_arch; - -const bfd_arch_info_type bfd_or1k_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_or1k, - bfd_mach_or1k, - "or1k", - "or1k", - 4, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_or1knd_arch, - }; - -const bfd_arch_info_type bfd_or1knd_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_or1k, - bfd_mach_or1knd, - "or1knd", - "or1knd", - 4, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - NULL, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-pdp11.c b/sdcc/support/sdbinutils/bfd/cpu-pdp11.c deleted file mode 100644 index 2b0567f91..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-pdp11.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD back-end for PDP-11 support. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_pdp11_arch = - { - 16, /* 16 bits in a word */ - 16, /* 16 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_pdp11, - 0, /* only 1 machine */ - "pdp11", - "pdp11", - 1, /* alignment = 16 bit */ - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; - diff --git a/sdcc/support/sdbinutils/bfd/cpu-pj.c b/sdcc/support/sdbinutils/bfd/cpu-pj.c deleted file mode 100644 index d7caac957..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-pj.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD library support routines for the Pico Java architecture. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Hacked by Steve Chamberlain of Transmeta. sac@pobox.com - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_pj_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_pj, - 0, - "pj", /* arch_name */ - "pj", /* printable name */ - 1, - TRUE, /* the default machine */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0 -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-powerpc.c b/sdcc/support/sdbinutils/bfd/cpu-powerpc.c deleted file mode 100644 index 406cb0936..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-powerpc.c +++ /dev/null @@ -1,422 +0,0 @@ -/* BFD PowerPC CPU definition - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* The common PowerPC architecture is compatible with the RS/6000. */ - -static const bfd_arch_info_type * -powerpc_compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b) -{ - BFD_ASSERT (a->arch == bfd_arch_powerpc); - switch (b->arch) - { - default: - return NULL; - case bfd_arch_powerpc: - if (a->mach == bfd_mach_ppc_vle && b->bits_per_word == 32) - return a; - if (b->mach == bfd_mach_ppc_vle && a->bits_per_word == 32) - return b; - return bfd_default_compatible (a, b); - case bfd_arch_rs6000: - if (b->mach == bfd_mach_rs6k) - return a; - return NULL; - } - /*NOTREACHED*/ -} - -const bfd_arch_info_type bfd_powerpc_archs[] = -{ -#if BFD_DEFAULT_TARGET_SIZE == 64 - /* Default arch must come first. */ - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc64, - "powerpc", - "powerpc:common64", - 3, - TRUE, /* default for 64 bit target */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[1] - }, - /* elf32-ppc:ppc_elf_object_p relies on the default 32 bit arch - being immediately after the 64 bit default. */ - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc, /* for the POWER/PowerPC common architecture */ - "powerpc", - "powerpc:common", - 3, - FALSE, - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[2], - }, -#else - /* Default arch must come first. */ - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc, /* for the POWER/PowerPC common architecture */ - "powerpc", - "powerpc:common", - 3, - TRUE, /* default for 32 bit target */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[1], - }, - /* elf64-ppc:ppc64_elf_object_p relies on the default 64 bit arch - being immediately after the 32 bit default. */ - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc64, - "powerpc", - "powerpc:common64", - 3, - FALSE, - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[2] - }, -#endif - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_603, - "powerpc", - "powerpc:603", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[3] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_ec603e, - "powerpc", - "powerpc:EC603e", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[4] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_604, - "powerpc", - "powerpc:604", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[5] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_403, - "powerpc", - "powerpc:403", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[6] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_601, - "powerpc", - "powerpc:601", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[7] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_620, - "powerpc", - "powerpc:620", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[8] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_630, - "powerpc", - "powerpc:630", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[9] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_a35, - "powerpc", - "powerpc:a35", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[10] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_rs64ii, - "powerpc", - "powerpc:rs64ii", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[11] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_rs64iii, - "powerpc", - "powerpc:rs64iii", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[12] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_7400, - "powerpc", - "powerpc:7400", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[13] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_e500, - "powerpc", - "powerpc:e500", - 3, - FALSE, - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[14] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_e500mc, - "powerpc", - "powerpc:e500mc", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[15] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_e500mc64, - "powerpc", - "powerpc:e500mc64", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[16] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_860, - "powerpc", - "powerpc:MPC8XX", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[17] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_750, - "powerpc", - "powerpc:750", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[18] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_titan, - "powerpc", - "powerpc:titan", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[19] - }, - { - 16, /* 16 or 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_vle, - "powerpc", - "powerpc:vle", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[20] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_e5500, - "powerpc", - "powerpc:e5500", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_powerpc_archs[21] - }, - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_powerpc, - bfd_mach_ppc_e6500, - "powerpc", - "powerpc:e6500", - 3, - FALSE, /* not the default */ - powerpc_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0 - } -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-pru.c b/sdcc/support/sdbinutils/bfd/cpu-pru.c deleted file mode 100644 index 0d572c51d..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-pru.c +++ /dev/null @@ -1,43 +0,0 @@ -/* BFD support for the TI PRU microprocessor. - Copyright (C) 2014-2018 Free Software Foundation, Inc. - Contributed by Dimitar Dimitrov - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ - { \ - BITS_WORD, /* bits in a word */ \ - BITS_ADDR, /* bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_pru, \ - NUMBER, \ - "pru", \ - PRINT, \ - 3, \ - DEFAULT, \ - bfd_default_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - NEXT \ - } - -const bfd_arch_info_type bfd_pru_arch = N (32, 32, 0, "pru", TRUE, NULL); diff --git a/sdcc/support/sdbinutils/bfd/cpu-riscv.c b/sdcc/support/sdbinutils/bfd/cpu-riscv.c deleted file mode 100644 index b2ab7e828..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-riscv.c +++ /dev/null @@ -1,79 +0,0 @@ -/* BFD backend for RISC-V - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - Contributed by Andrew Waterman (andrew@sifive.com). - Based on MIPS target. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING3. If not, - see . */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -/* This routine is provided two arch_infos and returns an arch_info - that is compatible with both, or NULL if none exists. */ - -static const bfd_arch_info_type * -riscv_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) -{ - if (a->arch != b->arch) - return NULL; - - /* Machine compatibility is checked in - _bfd_riscv_elf_merge_private_bfd_data. */ - - return a; -} - -#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ - { \ - BITS_WORD, /* bits in a word */ \ - BITS_ADDR, /* bits in an address */ \ - 8, /* 8 bits in a byte */ \ - bfd_arch_riscv, \ - NUMBER, \ - "riscv", \ - PRINT, \ - 3, \ - DEFAULT, \ - riscv_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - NEXT, \ - } - -/* This enum must be kept in the same order as arch_info_struct. */ -enum -{ - I_riscv64, - I_riscv32 -}; - -#define NN(index) (&arch_info_struct[(index) + 1]) - -/* This array must be kept in the same order as the anonymous enum above, - and each entry except the last should end with NN (my enum value). */ -static const bfd_arch_info_type arch_info_struct[] = -{ - N (64, 64, bfd_mach_riscv64, "riscv:rv64", FALSE, NN (I_riscv64)), - N (32, 32, bfd_mach_riscv32, "riscv:rv32", FALSE, 0) -}; - -/* The default architecture is riscv:rv64. */ - -const bfd_arch_info_type bfd_riscv_arch = - N (64, 64, 0, "riscv", TRUE, &arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-rl78.c b/sdcc/support/sdbinutils/bfd/cpu-rl78.c deleted file mode 100644 index 62095bf71..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-rl78.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the RL78 processor. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_rl78_arch = -{ - 32, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_rl78, /* Architecture. */ - bfd_mach_rl78, /* Machine. */ - "rl78", /* Architecture name. */ - "rl78", /* Printable name. */ - 4, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-rs6000.c b/sdcc/support/sdbinutils/bfd/cpu-rs6000.c deleted file mode 100644 index a429873be..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-rs6000.c +++ /dev/null @@ -1,113 +0,0 @@ -/* BFD back-end for rs6000 support - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Mimi Phuong-Thao Vo of IBM - and John Gilmore 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* The RS/6000 architecture is compatible with the PowerPC common - architecture. */ - -static const bfd_arch_info_type * -rs6000_compatible (const bfd_arch_info_type *a, - const bfd_arch_info_type *b) -{ - BFD_ASSERT (a->arch == bfd_arch_rs6000); - switch (b->arch) - { - default: - return NULL; - case bfd_arch_rs6000: - return bfd_default_compatible (a, b); - case bfd_arch_powerpc: - if (a->mach == bfd_mach_rs6k) - return b; - return NULL; - } - /*NOTREACHED*/ -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_rs6000, - bfd_mach_rs6k_rs1, - "rs6000", - "rs6000:rs1", - 3, - FALSE, /* not the default */ - rs6000_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[1] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_rs6000, - bfd_mach_rs6k_rsc, - "rs6000", - "rs6000:rsc", - 3, - FALSE, /* not the default */ - rs6000_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[2] - }, - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_rs6000, - bfd_mach_rs6k_rs2, - "rs6000", - "rs6000:rs2", - 3, - FALSE, /* not the default */ - rs6000_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0 - } -}; - -const bfd_arch_info_type bfd_rs6000_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_rs6000, - bfd_mach_rs6k, /* POWER common architecture */ - "rs6000", - "rs6000:6000", - 3, - TRUE, /* the default */ - rs6000_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[0] - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-rx.c b/sdcc/support/sdbinutils/bfd/cpu-rx.c deleted file mode 100644 index 217772d02..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-rx.c +++ /dev/null @@ -1,59 +0,0 @@ -/* BFD support for the RX processor. - Copyright (C) 2008-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static const bfd_arch_info_type arch_info_struct[] = -{ - { - 32, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_rx, /* Architecture. */ - bfd_mach_rx, /* Machine. */ - "rx", /* Architecture name. */ - "rx", /* Printable name. */ - 3, /* Section align power. */ - FALSE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ - }, -}; - -const bfd_arch_info_type bfd_rx_arch = -{ - 32, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_rx, /* Architecture. */ - bfd_mach_rx, /* Machine. */ - "rx", /* Architecture name. */ - "rx", /* Printable name. */ - 4, /* Section align power. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - & arch_info_struct[0], /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-s390.c b/sdcc/support/sdbinutils/bfd/cpu-s390.c deleted file mode 100644 index 82eb7f19f..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-s390.c +++ /dev/null @@ -1,53 +0,0 @@ -/* BFD support for the s390 processor. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Carl B. Pedersen and Martin Schwidefsky. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -#define N(bits, number, print, is_default, next) \ - { \ - bits, /* bits in a word */ \ - bits, /* bits in an address */ \ - 8, /* bits in a byte */ \ - bfd_arch_s390, \ - number, \ - "s390", \ - print, \ - 3, /* section alignment power */ \ - is_default, \ - bfd_default_compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - next \ - } - -#if BFD_DEFAULT_TARGET_SIZE == 64 -static const bfd_arch_info_type bfd_s390_31_arch = - N (32, bfd_mach_s390_31, "s390:31-bit", FALSE, NULL); -const bfd_arch_info_type bfd_s390_arch = - N (64, bfd_mach_s390_64, "s390:64-bit", TRUE, &bfd_s390_31_arch); -#else -static const bfd_arch_info_type bfd_s390_64_arch = - N (64, bfd_mach_s390_64, "s390:64-bit", FALSE, NULL); -const bfd_arch_info_type bfd_s390_arch = - N (32, bfd_mach_s390_31, "s390:31-bit", TRUE, &bfd_s390_64_arch); -#endif diff --git a/sdcc/support/sdbinutils/bfd/cpu-score.c b/sdcc/support/sdbinutils/bfd/cpu-score.c deleted file mode 100644 index baa8d8922..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-score.c +++ /dev/null @@ -1,69 +0,0 @@ -/* BFD support for the score processor - Copyright (C) 2006-2018 Free Software Foundation, Inc. - Contributed by - Brain.lin (brain.lin@sunplusct.com) - Mei Ligang (ligang@sunnorth.com.cn) - Pei-Lin Tsai (pltsai@sunplus.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -/* This routine is provided two arch_infos and works out which Score - machine which would be compatible with both and returns a pointer - to its info structure. */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type * a, const bfd_arch_info_type * b) -{ - /* If a & b are for different architectures we can do nothing. */ - if (a->arch != b->arch) - return NULL; - - if (a->mach != b->mach) - return NULL; - - return a; -} - -#define N(addr_bits, machine, print, default, next) \ -{ \ - 32, /* 16 bits in a word. */ \ - 32, /* Bits in an address. */ \ - 8, /* 8 bits in a byte. */ \ - bfd_arch_score, \ - machine, /* Machine number. */ \ - "score", /* Architecture name. */ \ - print, /* Printable name. */ \ - 4, /* Section align power. */ \ - default, /* The default machine. */ \ - compatible, \ - bfd_default_scan, \ - bfd_arch_default_fill, \ - next \ -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (16, bfd_mach_score3, "score3", FALSE, NULL), -}; - -const bfd_arch_info_type bfd_score_arch = - N (16, bfd_mach_score7, "score7", TRUE, & arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-sh.c b/sdcc/support/sdbinutils/bfd/cpu-sh.c deleted file mode 100644 index 0ab0c75b9..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-sh.c +++ /dev/null @@ -1,498 +0,0 @@ -/* BFD library support routines for the Renesas / SuperH SH architecture. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "../opcodes/sh-opc.h" - -#define SH_NEXT arch_info_struct + 0 -#define SH2_NEXT arch_info_struct + 1 -#define SH2E_NEXT arch_info_struct + 2 -#define SH_DSP_NEXT arch_info_struct + 3 -#define SH3_NEXT arch_info_struct + 4 -#define SH3_NOMMU_NEXT arch_info_struct + 5 -#define SH3_DSP_NEXT arch_info_struct + 6 -#define SH3E_NEXT arch_info_struct + 7 -#define SH4_NEXT arch_info_struct + 8 -#define SH4A_NEXT arch_info_struct + 9 -#define SH4AL_DSP_NEXT arch_info_struct + 10 -#define SH4_NOFPU_NEXT arch_info_struct + 11 -#define SH4_NOMMU_NOFPU_NEXT arch_info_struct + 12 -#define SH4A_NOFPU_NEXT arch_info_struct + 13 -#define SH2A_NEXT arch_info_struct + 14 -#define SH2A_NOFPU_NEXT arch_info_struct + 15 -#define SH2A_NOFPU_OR_SH4_NOMMU_NOFPU_NEXT arch_info_struct + 16 -#define SH2A_NOFPU_OR_SH3_NOMMU_NEXT arch_info_struct + 17 -#define SH2A_OR_SH4_NEXT arch_info_struct + 18 -#define SH2A_OR_SH3E_NEXT arch_info_struct + 19 -#define SH64_NEXT NULL - -static const bfd_arch_info_type arch_info_struct[] = -{ - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2, - "sh", /* Architecture name. */ - "sh2", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2e, - "sh", /* Architecture name. */ - "sh2e", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2E_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh_dsp, - "sh", /* Architecture name. */ - "sh-dsp", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH_DSP_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh3, - "sh", /* Architecture name. */ - "sh3", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH3_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh3_nommu, - "sh", /* Architecture name. */ - "sh3-nommu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH3_NOMMU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh3_dsp, - "sh", /* Architecture name. */ - "sh3-dsp", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH3_DSP_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh3e, - "sh", /* Architecture name. */ - "sh3e", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH3E_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh4, - "sh", /* Architecture name. */ - "sh4", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH4_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh4a, - "sh", /* Architecture name. */ - "sh4a", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH4A_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh4al_dsp, - "sh", /* Architecture name. */ - "sh4al-dsp", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH4AL_DSP_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh4_nofpu, - "sh", /* Architecture name. */ - "sh4-nofpu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH4_NOFPU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh4_nommu_nofpu, - "sh", /* Architecture name. */ - "sh4-nommu-nofpu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH4_NOMMU_NOFPU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh4a_nofpu, - "sh", /* Architecture name. */ - "sh4a-nofpu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH4A_NOFPU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2a, - "sh", /* Architecture name. */ - "sh2a", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2A_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2a_nofpu, - "sh", /* Architecture name. */ - "sh2a-nofpu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2A_NOFPU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu, - "sh", /* Architecture name. */ - "sh2a-nofpu-or-sh4-nommu-nofpu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2A_NOFPU_OR_SH4_NOMMU_NOFPU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2a_nofpu_or_sh3_nommu, - "sh", /* Architecture name. . */ - "sh2a-nofpu-or-sh3-nommu", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2A_NOFPU_OR_SH3_NOMMU_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2a_or_sh4, - "sh", /* Architecture name. */ - "sh2a-or-sh4", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2A_OR_SH4_NEXT - }, - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh2a_or_sh3e, - "sh", /* Architecture name. */ - "sh2a-or-sh3e", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH2A_OR_SH3E_NEXT - }, - { - 64, /* 64 bits in a word. */ - 64, /* 64 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh5, - "sh", /* Architecture name. */ - "sh5", /* Machine name. */ - 1, - FALSE, /* Not the default. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH64_NEXT - }, -}; - -const bfd_arch_info_type bfd_sh_arch = -{ - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_sh, - bfd_mach_sh, - "sh", /* Architecture name. */ - "sh", /* Machine name. */ - 1, - TRUE, /* The default machine. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - SH_NEXT -}; - - -/* This table defines the mappings from the BFD internal numbering - system to the opcodes internal flags system. - It is used by the functions defined below. - The prototypes for these SH specific functions are found in - sh-opc.h . */ - -static struct { unsigned long bfd_mach, arch, arch_up; } bfd_to_arch_table[] = -{ - { bfd_mach_sh, arch_sh1, arch_sh_up }, - { bfd_mach_sh2, arch_sh2, arch_sh2_up }, - { bfd_mach_sh2e, arch_sh2e, arch_sh2e_up }, - { bfd_mach_sh_dsp, arch_sh_dsp, arch_sh_dsp_up }, - { bfd_mach_sh2a, arch_sh2a, arch_sh2a_up }, - { bfd_mach_sh2a_nofpu, arch_sh2a_nofpu, arch_sh2a_nofpu_up }, - - { bfd_mach_sh2a_nofpu_or_sh4_nommu_nofpu, arch_sh2a_nofpu_or_sh4_nommu_nofpu, arch_sh2a_nofpu_or_sh4_nommu_nofpu_up }, - { bfd_mach_sh2a_nofpu_or_sh3_nommu, arch_sh2a_nofpu_or_sh3_nommu, arch_sh2a_nofpu_or_sh3_nommu_up }, - { bfd_mach_sh2a_or_sh4, arch_sh2a_or_sh4, arch_sh2a_or_sh4_up }, - { bfd_mach_sh2a_or_sh3e, arch_sh2a_or_sh3e, arch_sh2a_or_sh3e_up }, - - { bfd_mach_sh3, arch_sh3, arch_sh3_up }, - { bfd_mach_sh3_nommu, arch_sh3_nommu, arch_sh3_nommu_up }, - { bfd_mach_sh3_dsp, arch_sh3_dsp, arch_sh3_dsp_up }, - { bfd_mach_sh3e, arch_sh3e, arch_sh3e_up }, - { bfd_mach_sh4, arch_sh4, arch_sh4_up }, - { bfd_mach_sh4a, arch_sh4a, arch_sh4a_up }, - { bfd_mach_sh4al_dsp, arch_sh4al_dsp, arch_sh4al_dsp_up }, - { bfd_mach_sh4_nofpu, arch_sh4_nofpu, arch_sh4_nofpu_up }, - { bfd_mach_sh4_nommu_nofpu, arch_sh4_nommu_nofpu, arch_sh4_nommu_nofpu_up }, - { bfd_mach_sh4a_nofpu, arch_sh4a_nofpu, arch_sh4a_nofpu_up }, - { 0, 0, 0 } /* Terminator. */ -}; - - -/* Convert a BFD mach number into the right opcodes arch flags - using the table above. */ - -unsigned int -sh_get_arch_from_bfd_mach (unsigned long mach) -{ - int i = 0; - - while (bfd_to_arch_table[i].bfd_mach != 0) - if (bfd_to_arch_table[i].bfd_mach == mach) - return bfd_to_arch_table[i].arch; - else - i++; - - /* Machine not found. */ - BFD_FAIL(); - - return SH_ARCH_UNKNOWN_ARCH; -} - - -/* Convert a BFD mach number into a set of opcodes arch flags - describing all the compatible architectures (i.e. arch_up) - using the table above. */ - -unsigned int -sh_get_arch_up_from_bfd_mach (unsigned long mach) -{ - int i = 0; - - while (bfd_to_arch_table[i].bfd_mach != 0) - if (bfd_to_arch_table[i].bfd_mach == mach) - return bfd_to_arch_table[i].arch_up; - else - i++; - - /* Machine not found. */ - BFD_FAIL(); - - return SH_ARCH_UNKNOWN_ARCH; -} - - -/* Convert an arbitary arch_set - not necessarily corresponding - directly to anything in the table above - to the most generic - architecture which supports all the required features, and - return the corresponding BFD mach. */ - -unsigned long -sh_get_bfd_mach_from_arch_set (unsigned int arch_set) -{ - unsigned long result = 0; - unsigned int best = ~arch_set; - unsigned int co_mask = ~0; - int i = 0; - - /* If arch_set permits variants with no coprocessor then do not allow - the other irrelevant co-processor bits to influence the choice: - e.g. if dsp is disallowed by arch_set, then the algorithm would - prefer fpu variants over nofpu variants because they also disallow - dsp - even though the nofpu would be the most correct choice. - This assumes that EVERY fpu/dsp variant has a no-coprocessor - counter-part, or their non-fpu/dsp instructions do not have the - no co-processor bit set. */ - if (arch_set & arch_sh_no_co) - co_mask = ~(arch_sh_sp_fpu | arch_sh_dp_fpu | arch_sh_has_dsp); - - while (bfd_to_arch_table[i].bfd_mach != 0) - { - unsigned int try = bfd_to_arch_table[i].arch_up & co_mask; - - /* Conceptually: Find the architecture with the least number - of extra features or, if they have the same number, then - the greatest number of required features. Disregard - architectures where the required features alone do - not describe a valid architecture. */ - if (((try & ~arch_set) < (best & ~arch_set) - || ((try & ~arch_set) == (best & ~arch_set) - && (~try & arch_set) < (~best & arch_set))) - && SH_MERGE_ARCH_SET_VALID (try, arch_set)) - { - result = bfd_to_arch_table[i].bfd_mach; - best = try; - } - - i++; - } - - /* This might happen if a new variant is added to sh-opc.h - but no corresponding entry is added to the table above. */ - BFD_ASSERT (result != 0); - - return result; -} diff --git a/sdcc/support/sdbinutils/bfd/cpu-sparc.c b/sdcc/support/sdbinutils/bfd/cpu-sparc.c deleted file mode 100644 index 4de35e0b8..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-sparc.c +++ /dev/null @@ -1,359 +0,0 @@ -/* BFD support for the SPARC architecture. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static const bfd_arch_info_type arch_info_struct[] = -{ - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_sparclet, - "sparc", - "sparc:sparclet", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[1], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_sparclite, - "sparc", - "sparc:sparclite", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[2], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plus, - "sparc", - "sparc:v8plus", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[3], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusa, - "sparc", - "sparc:v8plusa", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[4], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_sparclite_le, - "sparc", - "sparc:sparclite_le", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[5], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9, - "sparc", - "sparc:v9", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[6], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9a, - "sparc", - "sparc:v9a", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[7], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusb, - "sparc", - "sparc:v8plusb", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[8], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9b, - "sparc", - "sparc:v9b", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[9], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusc, - "sparc", - "sparc:v8plusc", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[10], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9c, - "sparc", - "sparc:v9c", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[11], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusd, - "sparc", - "sparc:v8plusd", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[12], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9d, - "sparc", - "sparc:v9d", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[13], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8pluse, - "sparc", - "sparc:v8pluse", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[14], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9e, - "sparc", - "sparc:v9e", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[15], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusv, - "sparc", - "sparc:v8plusv", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[16], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9v, - "sparc", - "sparc:v9v", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[17], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusm, - "sparc", - "sparc:v8plusm", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[18], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9m, - "sparc", - "sparc:v9m", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[19], - }, - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v8plusm8, - "sparc", - "sparc:v8plusm8", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[20], - }, - { - 64, /* bits in a word */ - 64, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc_v9m8, - "sparc", - "sparc:v9m8", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - } -}; - -const bfd_arch_info_type bfd_sparc_arch = - { - 32, /* bits in a word */ - 32, /* bits in an address */ - 8, /* bits in a byte */ - bfd_arch_sparc, - bfd_mach_sparc, - "sparc", - "sparc", - 3, - TRUE, /* the default */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &arch_info_struct[0], - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-spu.c b/sdcc/support/sdbinutils/bfd/cpu-spu.c deleted file mode 100644 index 0ca3228bf..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-spu.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2006-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - - -static const bfd_arch_info_type * -spu_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) -{ - BFD_ASSERT (a->arch == bfd_arch_spu); - switch (b->arch) - { - default: - return NULL; - case bfd_arch_spu: - return bfd_default_compatible (a, b); - } - /*NOTREACHED*/ -} - -const bfd_arch_info_type bfd_spu_arch[] = -{ - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_spu, /* architecture */ - bfd_mach_spu, /* machine */ - "spu", /* architecture name */ - "spu:256K", /* printable name */ - 3, /* aligned power */ - TRUE, /* the default machine for the architecture */ - spu_compatible, /* the spu is only compatible with itself, see above */ - bfd_default_scan, - bfd_arch_default_fill, - 0, /* next -- there are none! */ - } -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-tic30.c b/sdcc/support/sdbinutils/bfd/cpu-tic30.c deleted file mode 100644 index d06d4ec6d..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tic30.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the Texas Instruments TMS320C30 architecture. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_tic30_arch = -{ - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_tic30, - 0, /* only 1 machine */ - "tic30", - "tms320c30", - 2, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-tic4x.c b/sdcc/support/sdbinutils/bfd/cpu-tic4x.c deleted file mode 100644 index aa2df1754..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tic4x.c +++ /dev/null @@ -1,83 +0,0 @@ -/* bfd back-end for TMS320C[34]x support - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - Contributed by Michael Hayes (m.hayes@elec.canterbury.ac.nz) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -static bfd_boolean -tic4x_scan (const struct bfd_arch_info *info, - const char *string) -{ - /* Allow strings of form [ti][Cc][34][0-9], let's not be too picky - about strange numbered machines in C3x or C4x series. */ - if (string[0] == 't' && string[1] == 'i') - string += 2; - if (*string == 'C' || *string == 'c') - string++; - if (string[1] < '0' && string[1] > '9') - return FALSE; - - if (*string == '3') - return (info->mach == bfd_mach_tic3x); - else if (*string == '4') - return info->mach == bfd_mach_tic4x; - - return FALSE; -} - - -const bfd_arch_info_type bfd_tic3x_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 32, /* 32 bits in a byte. */ - bfd_arch_tic4x, - bfd_mach_tic3x, /* Machine number. */ - "tic3x", /* Architecture name. */ - "tms320c3x", /* Printable name. */ - 0, /* Alignment power. */ - FALSE, /* Not the default architecture. */ - bfd_default_compatible, - tic4x_scan, - bfd_arch_default_fill, - 0 - }; - -const bfd_arch_info_type bfd_tic4x_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 32, /* 32 bits in a byte. */ - bfd_arch_tic4x, - bfd_mach_tic4x, /* Machine number. */ - "tic4x", /* Architecture name. */ - "tms320c4x", /* Printable name. */ - 0, /* Alignment power. */ - TRUE, /* The default architecture. */ - bfd_default_compatible, - tic4x_scan, - bfd_arch_default_fill, - &bfd_tic3x_arch, - }; - - diff --git a/sdcc/support/sdbinutils/bfd/cpu-tic54x.c b/sdcc/support/sdbinutils/bfd/cpu-tic54x.c deleted file mode 100644 index 73beb46d7..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tic54x.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the Texas Instruments TMS320C54X architecture. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_tic54x_arch = -{ - 16, /* 16 bits in a word */ - 16, /* 16 bits in an address (except '548) */ - 16, /* 16 bits in a byte */ - bfd_arch_tic54x, - 0, /* only 1 machine */ - "tic54x", - "tms320c54x", - 1, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-tic6x.c b/sdcc/support/sdbinutils/bfd/cpu-tic6x.c deleted file mode 100644 index de187317a..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tic6x.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the TI C6X processor. - Copyright (C) 2010-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_tic6x_arch = - { - 32, /* 32 bits in a word. */ - 32, /* 32 bits in an address. */ - 8, /* 8 bits in a byte. */ - bfd_arch_tic6x, /* Architecture. */ - 0, /* No BFD machine numbers needed. */ - "tic6x", /* Architecture name. */ - "tic6x", /* Printable name. */ - 2, /* Section alignment power. */ - TRUE, /* Default machine for this architecture. */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-tic80.c b/sdcc/support/sdbinutils/bfd/cpu-tic80.c deleted file mode 100644 index 0048749b5..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tic80.c +++ /dev/null @@ -1,41 +0,0 @@ -/* bfd back-end for TI TMS320C80 (MVP) support - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Written by Fred Fish at Cygnus support (fnf@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_tic80_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_tic80, /* bfd_architecture enum */ - 0, /* only 1 machine */ - "tic80", /* architecture name */ - "tic80", /* printable name */ - 2, /* section alignment power */ - TRUE, /* default machine for architecture */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - NULL, /* Pointer to next in chain */ - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-tilegx.c b/sdcc/support/sdbinutils/bfd/cpu-tilegx.c deleted file mode 100644 index f9351242a..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tilegx.c +++ /dev/null @@ -1,57 +0,0 @@ -/* BFD support for the TILE-Gx processor. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_tilegx32_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_tilegx, - bfd_mach_tilegx32, - "tilegx32", - "tilegx32", - 3, - FALSE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; - -const bfd_arch_info_type bfd_tilegx_arch = - { - 64, /* 64 bits in a word */ - 64, /* 64 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_tilegx, - bfd_mach_tilegx, - "tilegx", - "tilegx", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - &bfd_tilegx32_arch, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-tilepro.c b/sdcc/support/sdbinutils/bfd/cpu-tilepro.c deleted file mode 100644 index c178c2645..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-tilepro.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the TILEPro processor. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_tilepro_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_tilepro, - bfd_mach_tilepro, - "tilepro", - "tilepro", - 3, - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-v850.c b/sdcc/support/sdbinutils/bfd/cpu-v850.c deleted file mode 100644 index f257c0d9d..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-v850.c +++ /dev/null @@ -1,46 +0,0 @@ -/* BFD support for the NEC V850 processor - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "safe-ctype.h" - -#define N(number, print, default, next) \ -{ 32, 32, 8, bfd_arch_v850, number, "v850", print ":old-gcc-abi", 2, default, \ - bfd_default_compatible, bfd_default_scan, bfd_arch_default_fill, next } - -#define NEXT NULL - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (bfd_mach_v850e3v5, "v850e3v5", FALSE, & arch_info_struct[1]), - N (bfd_mach_v850e3v5, "v850e2v4", FALSE, & arch_info_struct[2]), - N (bfd_mach_v850e2v3, "v850e2v3", FALSE, & arch_info_struct[3]), - N (bfd_mach_v850e2, "v850e2", FALSE, & arch_info_struct[4]), - N (bfd_mach_v850e1, "v850e1", FALSE, & arch_info_struct[5]), - N (bfd_mach_v850e, "v850e", FALSE, NULL) -}; - -#undef NEXT -#define NEXT & arch_info_struct[0] - -const bfd_arch_info_type bfd_v850_arch = - N (bfd_mach_v850, "v850", TRUE, NEXT); diff --git a/sdcc/support/sdbinutils/bfd/cpu-v850_rh850.c b/sdcc/support/sdbinutils/bfd/cpu-v850_rh850.c deleted file mode 100644 index ed85a0833..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-v850_rh850.c +++ /dev/null @@ -1,42 +0,0 @@ -/* BFD support for the NEC V850 processor with the RH850 ABI. - Copyright (C) 2012-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "safe-ctype.h" - -#define R(number, print, default, next) \ -{ 32, 32, 8, bfd_arch_v850_rh850, number, "v850", print, 2, default, \ - bfd_default_compatible, bfd_default_scan, bfd_arch_default_fill, next } - -static const bfd_arch_info_type arch_info_struct[] = -{ - R (bfd_mach_v850e3v5, "v850e3v5", FALSE, & arch_info_struct[1]), - R (bfd_mach_v850e3v5, "v850e2v4", FALSE, & arch_info_struct[2]), - R (bfd_mach_v850e2v3, "v850e2v3", FALSE, & arch_info_struct[3]), - R (bfd_mach_v850e2, "v850e2", FALSE, & arch_info_struct[4]), - R (bfd_mach_v850e1, "v850e1", FALSE, & arch_info_struct[5]), - R (bfd_mach_v850e, "v850e", FALSE, & arch_info_struct[6]), - R (bfd_mach_v850, "v850-rh850", FALSE, NULL) /* For backwards compatibility. */ -}; - -const bfd_arch_info_type bfd_v850_rh850_arch = - R (bfd_mach_v850, "v850:rh850", TRUE, & arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-vax.c b/sdcc/support/sdbinutils/bfd/cpu-vax.c deleted file mode 100644 index efdd29a4d..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-vax.c +++ /dev/null @@ -1,41 +0,0 @@ -/* bfd back-end for vax support - Copyright (C) 1990-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_vax_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_vax, - 0, /* only 1 machine */ - "vax", - "vax", - 3, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-visium.c b/sdcc/support/sdbinutils/bfd/cpu-visium.c deleted file mode 100644 index ee1669eca..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-visium.c +++ /dev/null @@ -1,41 +0,0 @@ -/* BFD support for the Visium processor. - - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_visium_arch = -{ - 32, /* bits per word */ - 32, /* bits per address */ - 8, /* bits per byte */ - bfd_arch_visium, /* architecture */ - bfd_mach_visium, /* machine */ - "visium", /* architecture name */ - "visium", /* printable name */ - 2, /* section align power */ - TRUE, /* the default ? */ - bfd_default_compatible, /* architecture comparison fn */ - bfd_default_scan, /* string to architecture convert fn */ - bfd_arch_default_fill, /* default fill */ - NULL /* next in list */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-w65.c b/sdcc/support/sdbinutils/bfd/cpu-w65.c deleted file mode 100644 index fc99abc2d..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-w65.c +++ /dev/null @@ -1,52 +0,0 @@ -/* BFD library support routines for the WDC 65816 architecture. - Copyright (C) 1995-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -static bfd_boolean -scan_mach (const struct bfd_arch_info *info ATTRIBUTE_UNUSED, - const char *string) -{ - if (strcmp(string,"w65") == 0) - return TRUE; - if (strcmp(string,"w65816") == 0) - return TRUE; - return FALSE; -} - -const bfd_arch_info_type bfd_w65_arch = -{ - 16, /* 16 bits in a word */ - 24, /* 24 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_w65, - 0, /* only 1 machine */ - "w65", /* arch_name */ - "w65", /* printable name */ - 1, - TRUE, /* the default machine */ - bfd_default_compatible, - scan_mach, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-wasm32.c b/sdcc/support/sdbinutils/bfd/cpu-wasm32.c deleted file mode 100644 index 0904ec9e5..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-wasm32.c +++ /dev/null @@ -1,36 +0,0 @@ -/* BFD support for the WebAssembly target - Copyright (C) 2017-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" - -#define N(number, print, default, next) \ -{ 32, 32, 8, bfd_arch_wasm32, number, "wasm32", "wasm32", 4, default, bfd_default_compatible, \ - bfd_default_scan, bfd_arch_default_fill, next } - -static const bfd_arch_info_type arch_info_struct[] = -{ - N (bfd_mach_wasm32, "wasm32", TRUE, NULL) -}; - -const bfd_arch_info_type bfd_wasm32_arch = - N (bfd_mach_wasm32, "wasm32", TRUE, & arch_info_struct[0]); diff --git a/sdcc/support/sdbinutils/bfd/cpu-we32k.c b/sdcc/support/sdbinutils/bfd/cpu-we32k.c deleted file mode 100644 index e64b9d0ff..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-we32k.c +++ /dev/null @@ -1,41 +0,0 @@ -/* bfd back-end for we32k support - Copyright (C) 1992-2018 Free Software Foundation, Inc. - Contributed by Brendan Kehoe (brendan@cs.widener.edu). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_we32k_arch = - { - 32, /* 32 bits in a word */ - 32, /* 32 bits in an address */ - 8, /* 8 bits in a byte */ - bfd_arch_we32k, - 32000, /* only 1 machine */ - "we32k", - "we32k:32000", - 3, - TRUE, /* the one and only */ - bfd_default_compatible, - bfd_default_scan , - bfd_arch_default_fill, - 0, - }; diff --git a/sdcc/support/sdbinutils/bfd/cpu-xc16x.c b/sdcc/support/sdbinutils/bfd/cpu-xc16x.c deleted file mode 100644 index 6db0adacc..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-xc16x.c +++ /dev/null @@ -1,76 +0,0 @@ -/* BFD support for the Infineon XC16X Microcontroller. - Copyright (C) 2006-2018 Free Software Foundation, Inc. - Contributed by KPIT Cummins Infosystems - - This file is part of BFD, the Binary File Descriptor library. - Contributed by Anil Paranjpe(anilp1@kpitcummins.com) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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 "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type xc16xs_info_struct = -{ - 16, /* Bits per word. */ - 16, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_xc16x, /* Architecture. */ - bfd_mach_xc16xs, /* Machine. */ - "xc16x", /* Architecture name. */ - "xc16xs", /* Printable name. */ - 1, /* Section alignment - 16 bit. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; - -const bfd_arch_info_type xc16xl_info_struct = -{ - 16, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_xc16x, /* Architecture. */ - bfd_mach_xc16xl, /* Machine. */ - "xc16x", /* Architecture name. */ - "xc16xl", /* Printable name. */ - 1, /* Section alignment - 16 bit. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - & xc16xs_info_struct /* Next in list. */ -}; - -const bfd_arch_info_type bfd_xc16x_arch = -{ - 16, /* Bits per word. */ - 16, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_xc16x, /* Architecture. */ - bfd_mach_xc16x, /* Machine. */ - "xc16x", /* Architecture name. */ - "xc16x", /* Printable name. */ - 1, /* Section alignment - 16 bit. */ - TRUE, /* The default ? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - & xc16xl_info_struct /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-xgate.c b/sdcc/support/sdbinutils/bfd/cpu-xgate.c deleted file mode 100644 index 3b5f6d395..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-xgate.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the Freescale XGATE processor - Copyright (C) 2010-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_xgate_arch = -{ - 16, /* 16 bits in a word. */ - 32, /* 32 bits used as 16 bit address and PPAGE value. */ - 8, /* 8 bits in a byte. */ - bfd_arch_xgate, - bfd_mach_xgate, - "xgate", - "xgate", - 4, /* Section alignment power. */ - TRUE, - bfd_default_compatible, - bfd_default_scan, - bfd_arch_default_fill, - 0, -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-xstormy16.c b/sdcc/support/sdbinutils/bfd/cpu-xstormy16.c deleted file mode 100644 index 594000ddc..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-xstormy16.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the XSTORMY16 processor. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_xstormy16_arch = -{ - 16, /* bits per word */ - 32, /* bits per address */ - 8, /* bits per byte */ - bfd_arch_xstormy16, /* architecture */ - bfd_mach_xstormy16, /* machine */ - "xstormy16", /* architecture name */ - "xstormy16", /* printable name */ - 2, /* section align power */ - TRUE, /* the default ? */ - bfd_default_compatible, /* architecture comparison fn */ - bfd_default_scan, /* string to architecture convert fn */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* next in list */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-xtensa.c b/sdcc/support/sdbinutils/bfd/cpu-xtensa.c deleted file mode 100644 index c963ffcc9..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-xtensa.c +++ /dev/null @@ -1,40 +0,0 @@ -/* BFD support for the Xtensa processor. - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" - -const bfd_arch_info_type bfd_xtensa_arch = -{ - 32, /* Bits per word. */ - 32, /* Bits per address. */ - 8, /* Bits per byte. */ - bfd_arch_xtensa, /* Architecture. */ - bfd_mach_xtensa, /* Machine. */ - "xtensa", /* Architecture name. */ - "xtensa", /* Printable name. */ - 4, /* Section align power. */ - TRUE, /* The default? */ - bfd_default_compatible, /* Architecture comparison fn. */ - bfd_default_scan, /* String to architecture convert fn. */ - bfd_arch_default_fill, /* Default fill. */ - NULL /* Next in list. */ -}; diff --git a/sdcc/support/sdbinutils/bfd/cpu-z8k.c b/sdcc/support/sdbinutils/bfd/cpu-z8k.c deleted file mode 100644 index cacb2c466..000000000 --- a/sdcc/support/sdbinutils/bfd/cpu-z8k.c +++ /dev/null @@ -1,48 +0,0 @@ -/* BFD library support routines for the Z800n architecture. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - Hacked 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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" - -/* This routine is provided two arch_infos and returns whether - they'd be compatible */ - -static const bfd_arch_info_type * -compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) -{ - if (a->arch != b->arch || a->mach != b->mach) - return NULL; - return a; -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - { 32, 16, 8, bfd_arch_z8k, bfd_mach_z8002, "z8k", "z8002", 1, FALSE, - compatible, bfd_default_scan, bfd_arch_default_fill, 0 } -}; - -const bfd_arch_info_type bfd_z8k_arch = -{ - 32, 32, 8, bfd_arch_z8k, bfd_mach_z8001, "z8k", "z8001", 1, TRUE, - compatible, bfd_default_scan, bfd_arch_default_fill, - &arch_info_struct[0] -}; diff --git a/sdcc/support/sdbinutils/bfd/demo64.c b/sdcc/support/sdbinutils/bfd/demo64.c deleted file mode 100644 index f0a99b4b1..000000000 --- a/sdcc/support/sdbinutils/bfd/demo64.c +++ /dev/null @@ -1,30 +0,0 @@ -/* BFD backend for demonstration 64-bit a.out binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define ARCH_SIZE 64 - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (aout64_,OP) - -#define TARGETNAME "demo64" -#include "aoutf1.h" diff --git a/sdcc/support/sdbinutils/bfd/dwarf1.c b/sdcc/support/sdbinutils/bfd/dwarf1.c deleted file mode 100644 index 71bc57bfd..000000000 --- a/sdcc/support/sdbinutils/bfd/dwarf1.c +++ /dev/null @@ -1,583 +0,0 @@ -/* DWARF 1 find nearest line (_bfd_dwarf1_find_nearest_line). - Copyright (C) 1998-2018 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 3 of the License, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public 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 "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; - - /* Pointer to the symbol table. */ - asymbol** syms; - - /* 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. */ - bfd_byte *debug_section; - - /* Pointer to the end of the .debug_info section memory buffer. */ - bfd_byte *debug_section_end; - - /* The buffer for the .line section. */ - bfd_byte *line_section; - - /* End of that buffer. */ - bfd_byte *line_section_end; - - /* The current or next unread die within the .debug section. */ - bfd_byte *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. */ - bfd_byte *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 = (struct dwarf1_unit *) bfd_zalloc (stash->abfd, amt); - if (x) - { - 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 = (struct dwarf1_func *) bfd_zalloc (stash->abfd, amt); - if (x) - { - 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, - bfd_byte * aDiePtr, - bfd_byte * aDiePtrEnd) -{ - bfd_byte *this_die = aDiePtr; - bfd_byte *xptr = this_die; - - memset (aDieInfo, 0, sizeof (* aDieInfo)); - - /* First comes the length. */ - if (xptr + 4 > aDiePtrEnd) - return FALSE; - aDieInfo->length = bfd_get_32 (abfd, xptr); - xptr += 4; - if (aDieInfo->length == 0 - || this_die + aDieInfo->length > aDiePtrEnd) - return FALSE; - aDiePtrEnd = this_die + aDieInfo->length; - if (aDieInfo->length < 6) - { - /* Just padding bytes. */ - aDieInfo->tag = TAG_padding; - return TRUE; - } - - /* Then the tag. */ - if (xptr + 2 > aDiePtrEnd) - return FALSE; - aDieInfo->tag = bfd_get_16 (abfd, xptr); - xptr += 2; - - /* Then the attributes. */ - while (xptr + 2 <= aDiePtrEnd) - { - 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, xptr); - xptr += 2; - - switch (FORM_FROM_ATTR (attr)) - { - case FORM_DATA2: - xptr += 2; - break; - case FORM_DATA4: - case FORM_REF: - if (xptr + 4 <= aDiePtrEnd) - { - if (attr == AT_sibling) - aDieInfo->sibling = bfd_get_32 (abfd, xptr); - else if (attr == AT_stmt_list) - { - aDieInfo->stmt_list_offset = bfd_get_32 (abfd, xptr); - aDieInfo->has_stmt_list = 1; - } - } - xptr += 4; - break; - case FORM_DATA8: - xptr += 8; - break; - case FORM_ADDR: - if (xptr + 4 <= aDiePtrEnd) - { - if (attr == AT_low_pc) - aDieInfo->low_pc = bfd_get_32 (abfd, xptr); - else if (attr == AT_high_pc) - aDieInfo->high_pc = bfd_get_32 (abfd, xptr); - } - xptr += 4; - break; - case FORM_BLOCK2: - if (xptr + 2 <= aDiePtrEnd) - xptr += bfd_get_16 (abfd, xptr); - xptr += 2; - break; - case FORM_BLOCK4: - if (xptr + 4 <= aDiePtrEnd) - xptr += bfd_get_32 (abfd, xptr); - xptr += 4; - break; - case FORM_STRING: - if (attr == AT_name) - aDieInfo->name = (char *) xptr; - xptr += strnlen ((char *) xptr, aDiePtrEnd - 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) -{ - bfd_byte *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_simple_get_relocated_section_contents - (stash->abfd, msec, NULL, stash->syms); - - if (! stash->line_section) - return FALSE; - - stash->line_section_end = stash->line_section + size; - } - - xptr = stash->line_section + aUnit->stmt_list_offset; - if (xptr + 8 <= stash->line_section_end) - { - unsigned long eachLine; - bfd_byte *tblend; - unsigned long base; - bfd_size_type amt; - - /* First comes the length. */ - tblend = bfd_get_32 (stash->abfd, (bfd_byte *) xptr) + xptr; - xptr += 4; - - /* Then the base address for each address in the table. */ - base = bfd_get_32 (stash->abfd, (bfd_byte *) xptr); - xptr += 4; - - /* How many line entrys? - 10 = 4 (line number) + 2 (pos in line) + 4 (address in line). */ - aUnit->line_count = (tblend - xptr) / 10; - - /* Allocate an array for the entries. */ - amt = sizeof (struct linenumber) * aUnit->line_count; - aUnit->linenumber_table = (struct linenumber *) bfd_alloc (stash->abfd, - amt); - if (!aUnit->linenumber_table) - return FALSE; - - for (eachLine = 0; eachLine < aUnit->line_count; eachLine++) - { - if (xptr + 10 > stash->line_section_end) - { - aUnit->line_count = eachLine; - break; - } - /* 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) -{ - bfd_byte *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); - if (!aFunc) - return FALSE; - - 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, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *linenumber_ptr) -{ - struct dwarf1_debug *stash = elf_tdata (abfd)->dwarf1_find_line_info; - - struct dwarf1_unit* eachUnit; - - /* What address are we looking for? */ - unsigned long addr = (unsigned long)(offset + section->vma); - - *filename_ptr = NULL; - *functionname_ptr = NULL; - *linenumber_ptr = 0; - - if (! stash) - { - asection *msec; - bfd_size_type size = sizeof (struct dwarf1_debug); - - stash = elf_tdata (abfd)->dwarf1_find_line_info - = (struct dwarf1_debug *) bfd_zalloc (abfd, size); - - if (! stash) - return FALSE; - - msec = bfd_get_section_by_name (abfd, ".debug"); - if (! msec) - /* No dwarf1 info. Note that at this point the stash - has been allocated, but contains zeros, this lets - future calls to this function fail quicker. */ - return FALSE; - - size = msec->rawsize ? msec->rawsize : msec->size; - stash->debug_section - = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, - symbols); - - if (! stash->debug_section) - return FALSE; - - stash->debug_section_end = stash->debug_section + size; - stash->currentDie = stash->debug_section; - stash->abfd = abfd; - stash->syms = symbols; - } - - /* 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); - if (!aUnit) - return FALSE; - - 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/sdcc/support/sdbinutils/bfd/dwarf2.c b/sdcc/support/sdbinutils/bfd/dwarf2.c deleted file mode 100644 index a4a0dda20..000000000 --- a/sdcc/support/sdbinutils/bfd/dwarf2.c +++ /dev/null @@ -1,5064 +0,0 @@ -/* DWARF 2 support. - Copyright (C) 1994-2018 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 3 of the License, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public 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 "libiberty.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "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 maximum_ops_per_insn; - 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 adjusted_section -{ - asection *section; - bfd_vma adj_vma; -}; - -struct dwarf2_debug -{ - /* A list of all previously read comp_units. */ - struct comp_unit *all_comp_units; - - /* Last comp unit in list above. */ - struct comp_unit *last_comp_unit; - - /* Names of the debug sections. */ - const struct dwarf_debug_section *debug_sections; - - /* 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 original bfd for which debug was loaded. This is what - we use to compare and so check that the cached debug data is still - valid - it saves having to possibly dereference the gnu_debuglink each - time. */ - bfd *orig_bfd; - - /* Pointer to the bfd, section and address of the beginning of the - section. The bfd might be different than expected because of - gnu_debuglink sections. */ - bfd *bfd_ptr; - asection *sec; - bfd_byte *sec_info_ptr; - - /* Support for alternate debug info sections created by the DWZ utility: - This includes a pointer to an alternate bfd which contains *extra*, - possibly duplicate debug sections, and pointers to the loaded - .debug_str and .debug_info sections from this bfd. */ - bfd * alt_bfd_ptr; - bfd_byte * alt_dwarf_str_buffer; - bfd_size_type alt_dwarf_str_size; - bfd_byte * alt_dwarf_info_buffer; - bfd_size_type alt_dwarf_info_size; - - /* A pointer to the memory block allocated for info_ptr. Neither - info_ptr nor sec_info_ptr are guaranteed to stay pointing to the - beginning of the malloc block. */ - bfd_byte *info_ptr_memory; - - /* 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. */ - bfd_size_type dwarf_abbrev_size; - - /* Buffer for decode_line_info. */ - bfd_byte *dwarf_line_buffer; - - /* Length of the loaded .debug_line section. */ - bfd_size_type dwarf_line_size; - - /* Pointer to the .debug_str section loaded into memory. */ - bfd_byte *dwarf_str_buffer; - - /* Length of the loaded .debug_str section. */ - bfd_size_type dwarf_str_size; - - /* Pointer to the .debug_line_str section loaded into memory. */ - bfd_byte *dwarf_line_str_buffer; - - /* Length of the loaded .debug_line_str section. */ - bfd_size_type dwarf_line_str_size; - - /* Pointer to the .debug_ranges section loaded into memory. */ - bfd_byte *dwarf_ranges_buffer; - - /* Length of the loaded .debug_ranges section. */ - bfd_size_type 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; - - /* Section VMAs at the time the stash was built. */ - bfd_vma *sec_vma; - - /* Number of sections whose VMA we must adjust. */ - int adjusted_section_count; - - /* Array of sections with adjusted VMA. */ - struct adjusted_section *adjusted_sections; - - /* Number of times find_line is called. This is used in - the heuristic for enabling the info hash tables. */ - int info_hash_count; - -#define STASH_INFO_HASH_TRIGGER 100 - - /* Hash table mapping symbol names to function infos. */ - struct info_hash_table *funcinfo_hash_table; - - /* Hash table mapping symbol names to variable infos. */ - struct info_hash_table *varinfo_hash_table; - - /* Head of comp_unit list in the last hash table update. */ - struct comp_unit *hash_units_head; - - /* Status of info hash. */ - int info_hash_status; -#define STASH_INFO_HASH_OFF 0 -#define STASH_INFO_HASH_ON 1 -#define STASH_INFO_HASH_DISABLED 2 - - /* True if we opened bfd_ptr. */ - bfd_boolean close_on_cleanup; -}; - -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; - - /* Likewise, chain the compilation unit read after this one. - The comp units are stored in reversed reading order. */ - struct comp_unit *prev_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; - - /* DW_AT_language. */ - int lang; - - /* 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 table of function information references searchable by address. */ - struct lookup_funcinfo *lookup_funcinfo_table; - - /* Number of functions in the function_table and sorted_function_table. */ - bfd_size_type number_of_functions; - - /* A list of the variables found in this comp. unit. */ - struct varinfo *variable_table; - - /* Pointer to dwarf2_debug structure. */ - struct dwarf2_debug *stash; - - /* DWARF format version for this unit - from unit header. */ - int version; - - /* 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; - - /* TRUE if symbols are cached in hash table for faster lookup by name. */ - bfd_boolean cached; -}; - -/* 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; - bfd_vma implicit_const; -}; - -/* Map of uncompressed DWARF debug section name to compressed one. It - is terminated by NULL uncompressed_name. */ - -const struct dwarf_debug_section dwarf_debug_sections[] = -{ - { ".debug_abbrev", ".zdebug_abbrev" }, - { ".debug_aranges", ".zdebug_aranges" }, - { ".debug_frame", ".zdebug_frame" }, - { ".debug_info", ".zdebug_info" }, - { ".debug_info", ".zdebug_info" }, - { ".debug_line", ".zdebug_line" }, - { ".debug_loc", ".zdebug_loc" }, - { ".debug_macinfo", ".zdebug_macinfo" }, - { ".debug_macro", ".zdebug_macro" }, - { ".debug_pubnames", ".zdebug_pubnames" }, - { ".debug_pubtypes", ".zdebug_pubtypes" }, - { ".debug_ranges", ".zdebug_ranges" }, - { ".debug_static_func", ".zdebug_static_func" }, - { ".debug_static_vars", ".zdebug_static_vars" }, - { ".debug_str", ".zdebug_str", }, - { ".debug_str", ".zdebug_str", }, - { ".debug_line_str", ".zdebug_line_str", }, - { ".debug_types", ".zdebug_types" }, - /* GNU DWARF 1 extensions */ - { ".debug_sfnames", ".zdebug_sfnames" }, - { ".debug_srcinfo", ".zebug_srcinfo" }, - /* SGI/MIPS DWARF 2 extensions */ - { ".debug_funcnames", ".zdebug_funcnames" }, - { ".debug_typenames", ".zdebug_typenames" }, - { ".debug_varnames", ".zdebug_varnames" }, - { ".debug_weaknames", ".zdebug_weaknames" }, - { NULL, NULL }, -}; - -/* NB/ Numbers in this enum must match up with indicies - into the dwarf_debug_sections[] array above. */ -enum dwarf_debug_section_enum -{ - debug_abbrev = 0, - debug_aranges, - debug_frame, - debug_info, - debug_info_alt, - debug_line, - debug_loc, - debug_macinfo, - debug_macro, - debug_pubnames, - debug_pubtypes, - debug_ranges, - debug_static_func, - debug_static_vars, - debug_str, - debug_str_alt, - debug_line_str, - debug_types, - debug_sfnames, - debug_srcinfo, - debug_funcnames, - debug_typenames, - debug_varnames, - debug_weaknames, - debug_max -}; - -/* A static assertion. */ -extern int dwarf_debug_section_assert[ARRAY_SIZE (dwarf_debug_sections) - == debug_max + 1 ? 1 : -1]; - -#ifndef ABBREV_HASH_SIZE -#define ABBREV_HASH_SIZE 121 -#endif -#ifndef ATTR_ALLOC_CHUNK -#define ATTR_ALLOC_CHUNK 4 -#endif - -/* Variable and function hash tables. This is used to speed up look-up - in lookup_symbol_in_var_table() and lookup_symbol_in_function_table(). - In order to share code between variable and function infos, we use - a list of untyped pointer for all variable/function info associated with - a symbol. We waste a bit of memory for list with one node but that - simplifies the code. */ - -struct info_list_node -{ - struct info_list_node *next; - void *info; -}; - -/* Info hash entry. */ -struct info_hash_entry -{ - struct bfd_hash_entry root; - struct info_list_node *head; -}; - -struct info_hash_table -{ - struct bfd_hash_table base; -}; - -/* Function to create a new entry in info hash table. */ - -static struct bfd_hash_entry * -info_hash_table_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct info_hash_entry *ret = (struct info_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - derived class. */ - if (ret == NULL) - { - ret = (struct info_hash_entry *) bfd_hash_allocate (table, - sizeof (* ret)); - if (ret == NULL) - return NULL; - } - - /* Call the allocation method of the base class. */ - ret = ((struct info_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - - /* Initialize the local fields here. */ - if (ret) - ret->head = NULL; - - return (struct bfd_hash_entry *) ret; -} - -/* Function to create a new info hash table. It returns a pointer to the - newly created table or NULL if there is any error. We need abfd - solely for memory allocation. */ - -static struct info_hash_table * -create_info_hash_table (bfd *abfd) -{ - struct info_hash_table *hash_table; - - hash_table = ((struct info_hash_table *) - bfd_alloc (abfd, sizeof (struct info_hash_table))); - if (!hash_table) - return hash_table; - - if (!bfd_hash_table_init (&hash_table->base, info_hash_table_newfunc, - sizeof (struct info_hash_entry))) - { - bfd_release (abfd, hash_table); - return NULL; - } - - return hash_table; -} - -/* Insert an info entry into an info hash table. We do not check of - duplicate entries. Also, the caller need to guarantee that the - right type of info in inserted as info is passed as a void* pointer. - This function returns true if there is no error. */ - -static bfd_boolean -insert_info_hash_table (struct info_hash_table *hash_table, - const char *key, - void *info, - bfd_boolean copy_p) -{ - struct info_hash_entry *entry; - struct info_list_node *node; - - entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base, - key, TRUE, copy_p); - if (!entry) - return FALSE; - - node = (struct info_list_node *) bfd_hash_allocate (&hash_table->base, - sizeof (*node)); - if (!node) - return FALSE; - - node->info = info; - node->next = entry->head; - entry->head = node; - - return TRUE; -} - -/* Look up an info entry list from an info hash table. Return NULL - if there is none. */ - -static struct info_list_node * -lookup_info_hash_table (struct info_hash_table *hash_table, const char *key) -{ - struct info_hash_entry *entry; - - entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base, key, - FALSE, FALSE); - return entry ? entry->head : NULL; -} - -/* Read a section into its appropriate place in the dwarf2_debug - struct (indicated by SECTION_BUFFER and SECTION_SIZE). If SYMS is - not NULL, use bfd_simple_get_relocated_section_contents to read the - section contents, otherwise use bfd_get_section_contents. Fail if - the located section does not contain at least OFFSET bytes. */ - -static bfd_boolean -read_section (bfd * abfd, - const struct dwarf_debug_section *sec, - asymbol ** syms, - bfd_uint64_t offset, - bfd_byte ** section_buffer, - bfd_size_type * section_size) -{ - asection *msec; - const char *section_name = sec->uncompressed_name; - bfd_byte *contents = *section_buffer; - - /* The section may have already been read. */ - if (contents == NULL) - { - msec = bfd_get_section_by_name (abfd, section_name); - if (! msec) - { - section_name = sec->compressed_name; - if (section_name != NULL) - msec = bfd_get_section_by_name (abfd, section_name); - } - if (! msec) - { - _bfd_error_handler (_("Dwarf Error: Can't find %s section."), - sec->uncompressed_name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - *section_size = msec->rawsize ? msec->rawsize : msec->size; - /* Paranoia - alloc one extra so that we can make sure a string - section is NUL terminated. */ - contents = (bfd_byte *) bfd_malloc (*section_size + 1); - if (contents == NULL) - return FALSE; - if (syms - ? !bfd_simple_get_relocated_section_contents (abfd, msec, contents, - syms) - : !bfd_get_section_contents (abfd, msec, contents, 0, *section_size)) - { - free (contents); - return FALSE; - } - contents[*section_size] = 0; - *section_buffer = contents; - } - - /* It is possible to get a bad value for the offset into the section - that the client wants. Validate it here to avoid trouble later. */ - if (offset != 0 && offset >= *section_size) - { - /* xgettext: c-format */ - _bfd_error_handler (_("Dwarf Error: Offset (%llu)" - " greater than or equal to %s size (%Lu)."), - (long long) offset, section_name, *section_size); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - return TRUE; -} - -/* Read dwarf information from a buffer. */ - -static unsigned int -read_1_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end) -{ - if (buf + 1 > end) - return 0; - return bfd_get_8 (abfd, buf); -} - -static int -read_1_signed_byte (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *buf, bfd_byte *end) -{ - if (buf + 1 > end) - return 0; - return bfd_get_signed_8 (abfd, buf); -} - -static unsigned int -read_2_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) -{ - if (buf + 2 > end) - return 0; - return bfd_get_16 (abfd, buf); -} - -static unsigned int -read_4_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) -{ - if (buf + 4 > end) - return 0; - return bfd_get_32 (abfd, buf); -} - -static bfd_uint64_t -read_8_bytes (bfd *abfd, bfd_byte *buf, bfd_byte *end) -{ - if (buf + 8 > end) - return 0; - return bfd_get_64 (abfd, buf); -} - -static bfd_byte * -read_n_bytes (bfd *abfd ATTRIBUTE_UNUSED, - bfd_byte *buf, - bfd_byte *end, - unsigned int size ATTRIBUTE_UNUSED) -{ - if (buf + size > end) - return NULL; - return buf; -} - -/* Scans a NUL terminated string starting at BUF, returning a pointer to it. - Returns the number of characters in the string, *including* the NUL byte, - in BYTES_READ_PTR. This value is set even if the function fails. Bytes - at or beyond BUF_END will not be read. Returns NULL if there was a - problem, or if the string is empty. */ - -static char * -read_string (bfd * abfd ATTRIBUTE_UNUSED, - bfd_byte * buf, - bfd_byte * buf_end, - unsigned int * bytes_read_ptr) -{ - bfd_byte *str = buf; - - if (buf >= buf_end) - { - * bytes_read_ptr = 0; - return NULL; - } - - if (*str == '\0') - { - * bytes_read_ptr = 1; - return NULL; - } - - while (buf < buf_end) - if (* buf ++ == 0) - { - * bytes_read_ptr = buf - str; - return (char *) str; - } - - * bytes_read_ptr = buf - str; - return NULL; -} - -/* Reads an offset from BUF and then locates the string at this offset - inside the debug string section. Returns a pointer to the string. - Returns the number of bytes read from BUF, *not* the length of the string, - in BYTES_READ_PTR. This value is set even if the function fails. Bytes - at or beyond BUF_END will not be read from BUF. Returns NULL if there was - a problem, or if the string is empty. Does not check for NUL termination - of the string. */ - -static char * -read_indirect_string (struct comp_unit * unit, - bfd_byte * buf, - bfd_byte * buf_end, - unsigned int * bytes_read_ptr) -{ - bfd_uint64_t offset; - struct dwarf2_debug *stash = unit->stash; - char *str; - - if (buf + unit->offset_size > buf_end) - { - * bytes_read_ptr = 0; - return NULL; - } - - if (unit->offset_size == 4) - offset = read_4_bytes (unit->abfd, buf, buf_end); - else - offset = read_8_bytes (unit->abfd, buf, buf_end); - - *bytes_read_ptr = unit->offset_size; - - if (! read_section (unit->abfd, &stash->debug_sections[debug_str], - stash->syms, offset, - &stash->dwarf_str_buffer, &stash->dwarf_str_size)) - return NULL; - - if (offset >= stash->dwarf_str_size) - return NULL; - str = (char *) stash->dwarf_str_buffer + offset; - if (*str == '\0') - return NULL; - return str; -} - -/* Like read_indirect_string but from .debug_line_str section. */ - -static char * -read_indirect_line_string (struct comp_unit * unit, - bfd_byte * buf, - bfd_byte * buf_end, - unsigned int * bytes_read_ptr) -{ - bfd_uint64_t offset; - struct dwarf2_debug *stash = unit->stash; - char *str; - - if (buf + unit->offset_size > buf_end) - { - * bytes_read_ptr = 0; - return NULL; - } - - if (unit->offset_size == 4) - offset = read_4_bytes (unit->abfd, buf, buf_end); - else - offset = read_8_bytes (unit->abfd, buf, buf_end); - - *bytes_read_ptr = unit->offset_size; - - if (! read_section (unit->abfd, &stash->debug_sections[debug_line_str], - stash->syms, offset, - &stash->dwarf_line_str_buffer, - &stash->dwarf_line_str_size)) - return NULL; - - if (offset >= stash->dwarf_line_str_size) - return NULL; - str = (char *) stash->dwarf_line_str_buffer + offset; - if (*str == '\0') - return NULL; - return str; -} - -/* Like read_indirect_string but uses a .debug_str located in - an alternate file pointed to by the .gnu_debugaltlink section. - Used to impement DW_FORM_GNU_strp_alt. */ - -static char * -read_alt_indirect_string (struct comp_unit * unit, - bfd_byte * buf, - bfd_byte * buf_end, - unsigned int * bytes_read_ptr) -{ - bfd_uint64_t offset; - struct dwarf2_debug *stash = unit->stash; - char *str; - - if (buf + unit->offset_size > buf_end) - { - * bytes_read_ptr = 0; - return NULL; - } - - if (unit->offset_size == 4) - offset = read_4_bytes (unit->abfd, buf, buf_end); - else - offset = read_8_bytes (unit->abfd, buf, buf_end); - - *bytes_read_ptr = unit->offset_size; - - if (stash->alt_bfd_ptr == NULL) - { - bfd * debug_bfd; - char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR); - - if (debug_filename == NULL) - return NULL; - - if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL - || ! bfd_check_format (debug_bfd, bfd_object)) - { - if (debug_bfd) - bfd_close (debug_bfd); - - /* FIXME: Should we report our failure to follow the debuglink ? */ - free (debug_filename); - return NULL; - } - stash->alt_bfd_ptr = debug_bfd; - } - - if (! read_section (unit->stash->alt_bfd_ptr, - stash->debug_sections + debug_str_alt, - NULL, /* FIXME: Do we need to load alternate symbols ? */ - offset, - &stash->alt_dwarf_str_buffer, - &stash->alt_dwarf_str_size)) - return NULL; - - if (offset >= stash->alt_dwarf_str_size) - return NULL; - str = (char *) stash->alt_dwarf_str_buffer + offset; - if (*str == '\0') - return NULL; - - return str; -} - -/* Resolve an alternate reference from UNIT at OFFSET. - Returns a pointer into the loaded alternate CU upon success - or NULL upon failure. */ - -static bfd_byte * -read_alt_indirect_ref (struct comp_unit * unit, - bfd_uint64_t offset) -{ - struct dwarf2_debug *stash = unit->stash; - - if (stash->alt_bfd_ptr == NULL) - { - bfd * debug_bfd; - char * debug_filename = bfd_follow_gnu_debugaltlink (unit->abfd, DEBUGDIR); - - if (debug_filename == NULL) - return FALSE; - - if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL - || ! bfd_check_format (debug_bfd, bfd_object)) - { - if (debug_bfd) - bfd_close (debug_bfd); - - /* FIXME: Should we report our failure to follow the debuglink ? */ - free (debug_filename); - return NULL; - } - stash->alt_bfd_ptr = debug_bfd; - } - - if (! read_section (unit->stash->alt_bfd_ptr, - stash->debug_sections + debug_info_alt, - NULL, /* FIXME: Do we need to load alternate symbols ? */ - offset, - &stash->alt_dwarf_info_buffer, - &stash->alt_dwarf_info_size)) - return NULL; - - if (offset >= stash->alt_dwarf_info_size) - return NULL; - return stash->alt_dwarf_info_buffer + offset; -} - -static bfd_uint64_t -read_address (struct comp_unit *unit, bfd_byte *buf, bfd_byte * buf_end) -{ - int signed_vma = 0; - - if (bfd_get_flavour (unit->abfd) == bfd_target_elf_flavour) - signed_vma = get_elf_backend_data (unit->abfd)->sign_extend_vma; - - if (buf + unit->addr_size > buf_end) - return 0; - - if (signed_vma) - { - 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; - bfd_byte *abbrev_end; - struct abbrev_info *cur_abbrev; - unsigned int abbrev_number, bytes_read, abbrev_name; - unsigned int abbrev_form, hash_number; - bfd_size_type amt; - - if (! read_section (abfd, &stash->debug_sections[debug_abbrev], - stash->syms, offset, - &stash->dwarf_abbrev_buffer, &stash->dwarf_abbrev_size)) - return NULL; - - if (offset >= stash->dwarf_abbrev_size) - return NULL; - - amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE; - abbrevs = (struct abbrev_info **) bfd_zalloc (abfd, amt); - if (abbrevs == NULL) - return NULL; - - abbrev_ptr = stash->dwarf_abbrev_buffer + offset; - abbrev_end = stash->dwarf_abbrev_buffer + stash->dwarf_abbrev_size; - abbrev_number = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - - /* Loop until we reach an abbrev number of 0. */ - while (abbrev_number) - { - amt = sizeof (struct abbrev_info); - cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt); - if (cur_abbrev == NULL) - return NULL; - - /* Read in abbrev header. */ - cur_abbrev->number = abbrev_number; - cur_abbrev->tag = (enum dwarf_tag) - _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr, abbrev_end); - abbrev_ptr += 1; - - /* Now read in declarations. */ - for (;;) - { - /* Initialize it just to avoid a GCC false warning. */ - bfd_vma implicit_const = -1; - - abbrev_name = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - abbrev_form = _bfd_safe_read_leb128 (abfd, abbrev_ptr, &bytes_read, - FALSE, abbrev_end); - abbrev_ptr += bytes_read; - if (abbrev_form == DW_FORM_implicit_const) - { - implicit_const = _bfd_safe_read_leb128 (abfd, abbrev_ptr, - &bytes_read, TRUE, - abbrev_end); - abbrev_ptr += bytes_read; - } - - if (abbrev_name == 0) - break; - - 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 = (struct attr_abbrev *) 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; - cur_abbrev->attrs[cur_abbrev->num_attrs].implicit_const - = implicit_const; - ++cur_abbrev->num_attrs; - } - - 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 = _bfd_safe_read_leb128 (abfd, abbrev_ptr, - &bytes_read, FALSE, abbrev_end); - abbrev_ptr += bytes_read; - if (lookup_abbrev (abbrev_number, abbrevs) != NULL) - break; - } - - return abbrevs; -} - -/* Returns true if the form is one which has a string value. */ - -static inline bfd_boolean -is_str_attr (enum dwarf_form form) -{ - return (form == DW_FORM_string || form == DW_FORM_strp - || form == DW_FORM_line_strp || form == DW_FORM_GNU_strp_alt); -} - -/* Read and fill in the value of attribute ATTR as described by FORM. - Read data starting from INFO_PTR, but never at or beyond INFO_PTR_END. - Returns an updated INFO_PTR taking into account the amount of data read. */ - -static bfd_byte * -read_attribute_value (struct attribute * attr, - unsigned form, - bfd_vma implicit_const, - struct comp_unit * unit, - bfd_byte * info_ptr, - bfd_byte * info_ptr_end) -{ - bfd *abfd = unit->abfd; - unsigned int bytes_read; - struct dwarf_block *blk; - bfd_size_type amt; - - if (info_ptr >= info_ptr_end && form != DW_FORM_flag_present) - { - _bfd_error_handler (_("Dwarf Error: Info pointer extends beyond end of attributes")); - bfd_set_error (bfd_error_bad_value); - return info_ptr; - } - - attr->form = (enum dwarf_form) form; - - switch (form) - { - case DW_FORM_ref_addr: - /* DW_FORM_ref_addr is an address in DWARF2, and an offset in - DWARF3. */ - if (unit->version == 3 || unit->version == 4) - { - if (unit->offset_size == 4) - attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end); - else - attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end); - info_ptr += unit->offset_size; - break; - } - /* FALLTHROUGH */ - case DW_FORM_addr: - attr->u.val = read_address (unit, info_ptr, info_ptr_end); - info_ptr += unit->addr_size; - break; - case DW_FORM_GNU_ref_alt: - case DW_FORM_sec_offset: - if (unit->offset_size == 4) - attr->u.val = read_4_bytes (unit->abfd, info_ptr, info_ptr_end); - else - attr->u.val = read_8_bytes (unit->abfd, info_ptr, info_ptr_end); - info_ptr += unit->offset_size; - break; - case DW_FORM_block2: - amt = sizeof (struct dwarf_block); - blk = (struct dwarf_block *) bfd_alloc (abfd, amt); - if (blk == NULL) - return NULL; - blk->size = read_2_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 2; - blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); - info_ptr += blk->size; - attr->u.blk = blk; - break; - case DW_FORM_block4: - amt = sizeof (struct dwarf_block); - blk = (struct dwarf_block *) bfd_alloc (abfd, amt); - if (blk == NULL) - return NULL; - blk->size = read_4_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 4; - blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); - info_ptr += blk->size; - attr->u.blk = blk; - break; - case DW_FORM_data2: - attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 2; - break; - case DW_FORM_data4: - attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 4; - break; - case DW_FORM_data8: - attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 8; - break; - case DW_FORM_string: - attr->u.str = read_string (abfd, info_ptr, info_ptr_end, &bytes_read); - info_ptr += bytes_read; - break; - case DW_FORM_strp: - attr->u.str = read_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); - info_ptr += bytes_read; - break; - case DW_FORM_line_strp: - attr->u.str = read_indirect_line_string (unit, info_ptr, info_ptr_end, &bytes_read); - info_ptr += bytes_read; - break; - case DW_FORM_GNU_strp_alt: - attr->u.str = read_alt_indirect_string (unit, info_ptr, info_ptr_end, &bytes_read); - info_ptr += bytes_read; - break; - case DW_FORM_exprloc: - case DW_FORM_block: - amt = sizeof (struct dwarf_block); - blk = (struct dwarf_block *) bfd_alloc (abfd, amt); - if (blk == NULL) - return NULL; - blk->size = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, info_ptr_end); - info_ptr += bytes_read; - blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); - info_ptr += blk->size; - attr->u.blk = blk; - break; - case DW_FORM_block1: - amt = sizeof (struct dwarf_block); - blk = (struct dwarf_block *) bfd_alloc (abfd, amt); - if (blk == NULL) - return NULL; - blk->size = read_1_byte (abfd, info_ptr, info_ptr_end); - info_ptr += 1; - blk->data = read_n_bytes (abfd, info_ptr, info_ptr_end, blk->size); - info_ptr += blk->size; - attr->u.blk = blk; - break; - case DW_FORM_data1: - attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); - info_ptr += 1; - break; - case DW_FORM_flag: - attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); - info_ptr += 1; - break; - case DW_FORM_flag_present: - attr->u.val = 1; - break; - case DW_FORM_sdata: - attr->u.sval = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - TRUE, info_ptr_end); - info_ptr += bytes_read; - break; - case DW_FORM_udata: - attr->u.val = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, info_ptr_end); - info_ptr += bytes_read; - break; - case DW_FORM_ref1: - attr->u.val = read_1_byte (abfd, info_ptr, info_ptr_end); - info_ptr += 1; - break; - case DW_FORM_ref2: - attr->u.val = read_2_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 2; - break; - case DW_FORM_ref4: - attr->u.val = read_4_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 4; - break; - case DW_FORM_ref8: - attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 8; - break; - case DW_FORM_ref_sig8: - attr->u.val = read_8_bytes (abfd, info_ptr, info_ptr_end); - info_ptr += 8; - break; - case DW_FORM_ref_udata: - attr->u.val = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, info_ptr_end); - info_ptr += bytes_read; - break; - case DW_FORM_indirect: - form = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, info_ptr_end); - info_ptr += bytes_read; - if (form == DW_FORM_implicit_const) - { - implicit_const = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - TRUE, info_ptr_end); - info_ptr += bytes_read; - } - info_ptr = read_attribute_value (attr, form, implicit_const, unit, - info_ptr, info_ptr_end); - break; - case DW_FORM_implicit_const: - attr->form = DW_FORM_sdata; - attr->u.sval = implicit_const; - break; - default: - _bfd_error_handler (_("Dwarf Error: Invalid or unhandled FORM value: %#x."), - form); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - 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, - bfd_byte * info_ptr_end) -{ - attr->name = abbrev->name; - info_ptr = read_attribute_value (attr, abbrev->form, abbrev->implicit_const, - unit, info_ptr, info_ptr_end); - return info_ptr; -} - -/* Return whether DW_AT_name will return the same as DW_AT_linkage_name - for a function. */ - -static bfd_boolean -non_mangled (int lang) -{ - switch (lang) - { - default: - return FALSE; - - case DW_LANG_C89: - case DW_LANG_C: - case DW_LANG_Ada83: - case DW_LANG_Cobol74: - case DW_LANG_Cobol85: - case DW_LANG_Fortran77: - case DW_LANG_Pascal83: - case DW_LANG_C99: - case DW_LANG_Ada95: - case DW_LANG_PLI: - case DW_LANG_UPC: - case DW_LANG_C11: - return TRUE; - } -} - -/* Source line information table routines. */ - -#define FILE_ALLOC_CHUNK 5 -#define DIR_ALLOC_CHUNK 5 - -struct line_info -{ - struct line_info * prev_line; - bfd_vma address; - char * filename; - unsigned int line; - unsigned int column; - unsigned int discriminator; - unsigned char op_index; - unsigned char end_sequence; /* End of (sequential) code sequence. */ -}; - -struct fileinfo -{ - char * name; - unsigned int dir; - unsigned int time; - unsigned int size; -}; - -struct line_sequence -{ - bfd_vma low_pc; - struct line_sequence* prev_sequence; - struct line_info* last_line; /* Largest VMA. */ - struct line_info** line_info_lookup; - bfd_size_type num_lines; -}; - -struct line_info_table -{ - bfd * abfd; - unsigned int num_files; - unsigned int num_dirs; - unsigned int num_sequences; - char * comp_dir; - char ** dirs; - struct fileinfo* files; - struct line_sequence* sequences; - 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 -{ - /* Pointer to previous function in list of all functions. */ - struct funcinfo * prev_func; - /* Pointer to function one scope higher. */ - struct funcinfo * caller_func; - /* Source location file name where caller_func inlines this func. */ - char * caller_file; - /* Source location file name. */ - char * file; - /* Source location line number where caller_func inlines this func. */ - int caller_line; - /* Source location line number. */ - int line; - int tag; - bfd_boolean is_linkage; - const char * name; - struct arange arange; - /* Where the symbol is defined. */ - asection * sec; -}; - -struct lookup_funcinfo -{ - /* Function information corresponding to this lookup table entry. */ - struct funcinfo * funcinfo; - - /* The lowest address for this specific function. */ - bfd_vma low_addr; - - /* The highest address of this function before the lookup table is sorted. - The highest address of all prior functions after the lookup table is - sorted, which is used for binary search. */ - bfd_vma high_addr; -}; - -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->op_index > line->op_index)); -} - - -/* 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 bfd_boolean -add_line_info (struct line_info_table *table, - bfd_vma address, - unsigned char op_index, - char *filename, - unsigned int line, - unsigned int column, - unsigned int discriminator, - int end_sequence) -{ - bfd_size_type amt = sizeof (struct line_info); - struct line_sequence* seq = table->sequences; - struct line_info* info = (struct line_info *) bfd_alloc (table->abfd, amt); - - if (info == NULL) - return FALSE; - - /* Set member data of 'info'. */ - info->prev_line = NULL; - info->address = address; - info->op_index = op_index; - info->line = line; - info->column = column; - info->discriminator = discriminator; - info->end_sequence = end_sequence; - - if (filename && filename[0]) - { - info->filename = (char *) bfd_alloc (table->abfd, strlen (filename) + 1); - if (info->filename == NULL) - return FALSE; - 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* - sub-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 (seq - && seq->last_line->address == address - && seq->last_line->op_index == op_index - && seq->last_line->end_sequence == end_sequence) - { - /* We only keep the last entry with the same address and end - sequence. See PR ld/4986. */ - if (table->lcl_head == seq->last_line) - table->lcl_head = info; - info->prev_line = seq->last_line->prev_line; - seq->last_line = info; - } - else if (!seq || seq->last_line->end_sequence) - { - /* Start a new line sequence. */ - amt = sizeof (struct line_sequence); - seq = (struct line_sequence *) bfd_malloc (amt); - if (seq == NULL) - return FALSE; - seq->low_pc = address; - seq->prev_sequence = table->sequences; - seq->last_line = info; - table->lcl_head = info; - table->sequences = seq; - table->num_sequences++; - } - else if (info->end_sequence - || new_line_sorts_after (info, seq->last_line)) - { - /* Normal case: add 'info' to the beginning of the current sequence. */ - info->prev_line = seq->last_line; - seq->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 = seq->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; - if (address < seq->low_pc) - seq->low_pc = address; - } - return TRUE; -} - -/* 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 (filename == NULL) - return strdup (""); - - if (!IS_ABSOLUTE_PATH (filename)) - { - char *dir_name = NULL; - char *subdir_name = NULL; - char *name; - size_t len; - - if (table->files[file - 1].dir - /* PR 17512: file: 0317e960. */ - && table->files[file - 1].dir <= table->num_dirs - /* PR 17512: file: 7f3d2e4b. */ - && table->dirs != NULL) - subdir_name = table->dirs[table->files[file - 1].dir - 1]; - - if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name)) - dir_name = table->comp_dir; - - if (!dir_name) - { - dir_name = subdir_name; - subdir_name = NULL; - } - - if (!dir_name) - return strdup (filename); - - len = strlen (dir_name) + strlen (filename) + 2; - - if (subdir_name) - { - len += strlen (subdir_name) + 1; - name = (char *) bfd_malloc (len); - if (name) - sprintf (name, "%s/%s/%s", dir_name, subdir_name, filename); - } - else - { - name = (char *) bfd_malloc (len); - if (name) - sprintf (name, "%s/%s", dir_name, filename); - } - - return name; - } - - return strdup (filename); -} - -static bfd_boolean -arange_add (const struct comp_unit *unit, struct arange *first_arange, - bfd_vma low_pc, bfd_vma high_pc) -{ - struct arange *arange; - - /* Ignore empty ranges. */ - if (low_pc == high_pc) - return TRUE; - - /* If the first arange is empty, use it. */ - if (first_arange->high == 0) - { - first_arange->low = low_pc; - first_arange->high = high_pc; - return TRUE; - } - - /* Next see if we can cheaply extend an existing range. */ - arange = first_arange; - do - { - if (low_pc == arange->high) - { - arange->high = high_pc; - return TRUE; - } - if (high_pc == arange->low) - { - arange->low = low_pc; - return TRUE; - } - 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 = (struct arange *) bfd_alloc (unit->abfd, sizeof (*arange)); - if (arange == NULL) - return FALSE; - arange->low = low_pc; - arange->high = high_pc; - arange->next = first_arange->next; - first_arange->next = arange; - return TRUE; -} - -/* Compare function for line sequences. */ - -static int -compare_sequences (const void* a, const void* b) -{ - const struct line_sequence* seq1 = a; - const struct line_sequence* seq2 = b; - - /* Sort by low_pc as the primary key. */ - if (seq1->low_pc < seq2->low_pc) - return -1; - if (seq1->low_pc > seq2->low_pc) - return 1; - - /* If low_pc values are equal, sort in reverse order of - high_pc, so that the largest region comes first. */ - if (seq1->last_line->address < seq2->last_line->address) - return 1; - if (seq1->last_line->address > seq2->last_line->address) - return -1; - - if (seq1->last_line->op_index < seq2->last_line->op_index) - return 1; - if (seq1->last_line->op_index > seq2->last_line->op_index) - return -1; - - return 0; -} - -/* Construct the line information table for quick lookup. */ - -static bfd_boolean -build_line_info_table (struct line_info_table * table, - struct line_sequence * seq) -{ - bfd_size_type amt; - struct line_info** line_info_lookup; - struct line_info* each_line; - unsigned int num_lines; - unsigned int line_index; - - if (seq->line_info_lookup != NULL) - return TRUE; - - /* Count the number of line information entries. We could do this while - scanning the debug information, but some entries may be added via - lcl_head without having a sequence handy to increment the number of - lines. */ - num_lines = 0; - for (each_line = seq->last_line; each_line; each_line = each_line->prev_line) - num_lines++; - - if (num_lines == 0) - return TRUE; - - /* Allocate space for the line information lookup table. */ - amt = sizeof (struct line_info*) * num_lines; - line_info_lookup = (struct line_info**) bfd_alloc (table->abfd, amt); - if (line_info_lookup == NULL) - return FALSE; - - /* Create the line information lookup table. */ - line_index = num_lines; - for (each_line = seq->last_line; each_line; each_line = each_line->prev_line) - line_info_lookup[--line_index] = each_line; - - BFD_ASSERT (line_index == 0); - - seq->num_lines = num_lines; - seq->line_info_lookup = line_info_lookup; - - return TRUE; -} - -/* Sort the line sequences for quick lookup. */ - -static bfd_boolean -sort_line_sequences (struct line_info_table* table) -{ - bfd_size_type amt; - struct line_sequence* sequences; - struct line_sequence* seq; - unsigned int n = 0; - unsigned int num_sequences = table->num_sequences; - bfd_vma last_high_pc; - - if (num_sequences == 0) - return TRUE; - - /* Allocate space for an array of sequences. */ - amt = sizeof (struct line_sequence) * num_sequences; - sequences = (struct line_sequence *) bfd_alloc (table->abfd, amt); - if (sequences == NULL) - return FALSE; - - /* Copy the linked list into the array, freeing the original nodes. */ - seq = table->sequences; - for (n = 0; n < num_sequences; n++) - { - struct line_sequence* last_seq = seq; - - BFD_ASSERT (seq); - sequences[n].low_pc = seq->low_pc; - sequences[n].prev_sequence = NULL; - sequences[n].last_line = seq->last_line; - sequences[n].line_info_lookup = NULL; - sequences[n].num_lines = 0; - seq = seq->prev_sequence; - free (last_seq); - } - BFD_ASSERT (seq == NULL); - - qsort (sequences, n, sizeof (struct line_sequence), compare_sequences); - - /* Make the list binary-searchable by trimming overlapping entries - and removing nested entries. */ - num_sequences = 1; - last_high_pc = sequences[0].last_line->address; - for (n = 1; n < table->num_sequences; n++) - { - if (sequences[n].low_pc < last_high_pc) - { - if (sequences[n].last_line->address <= last_high_pc) - /* Skip nested entries. */ - continue; - - /* Trim overlapping entries. */ - sequences[n].low_pc = last_high_pc; - } - last_high_pc = sequences[n].last_line->address; - if (n > num_sequences) - { - /* Close up the gap. */ - sequences[num_sequences].low_pc = sequences[n].low_pc; - sequences[num_sequences].last_line = sequences[n].last_line; - } - num_sequences++; - } - - table->sequences = sequences; - table->num_sequences = num_sequences; - return TRUE; -} - -/* Add directory to TABLE. CUR_DIR memory ownership is taken by TABLE. */ - -static bfd_boolean -line_info_add_include_dir (struct line_info_table *table, char *cur_dir) -{ - if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) - { - char **tmp; - bfd_size_type amt; - - amt = table->num_dirs + DIR_ALLOC_CHUNK; - amt *= sizeof (char *); - - tmp = (char **) bfd_realloc (table->dirs, amt); - if (tmp == NULL) - return FALSE; - table->dirs = tmp; - } - - table->dirs[table->num_dirs++] = cur_dir; - return TRUE; -} - -static bfd_boolean -line_info_add_include_dir_stub (struct line_info_table *table, char *cur_dir, - unsigned int dir ATTRIBUTE_UNUSED, - unsigned int xtime ATTRIBUTE_UNUSED, - unsigned int size ATTRIBUTE_UNUSED) -{ - return line_info_add_include_dir (table, cur_dir); -} - -/* Add file to TABLE. CUR_FILE memory ownership is taken by TABLE. */ - -static bfd_boolean -line_info_add_file_name (struct line_info_table *table, char *cur_file, - unsigned int dir, unsigned int xtime, - unsigned int size) -{ - if ((table->num_files % FILE_ALLOC_CHUNK) == 0) - { - struct fileinfo *tmp; - bfd_size_type amt; - - amt = table->num_files + FILE_ALLOC_CHUNK; - amt *= sizeof (struct fileinfo); - - tmp = (struct fileinfo *) bfd_realloc (table->files, amt); - if (tmp == NULL) - return FALSE; - table->files = tmp; - } - - table->files[table->num_files].name = cur_file; - table->files[table->num_files].dir = dir; - table->files[table->num_files].time = xtime; - table->files[table->num_files].size = size; - table->num_files++; - return TRUE; -} - -/* Read directory or file name entry format, starting with byte of - format count entries, ULEB128 pairs of entry formats, ULEB128 of - entries count and the entries themselves in the described entry - format. */ - -static bfd_boolean -read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, - bfd_byte *buf_end, struct line_info_table *table, - bfd_boolean (*callback) (struct line_info_table *table, - char *cur_file, - unsigned int dir, - unsigned int time, - unsigned int size)) -{ - bfd *abfd = unit->abfd; - bfd_byte format_count, formati; - bfd_vma data_count, datai; - bfd_byte *buf = *bufp; - bfd_byte *format_header_data; - unsigned int bytes_read; - - format_count = read_1_byte (abfd, buf, buf_end); - buf += 1; - format_header_data = buf; - for (formati = 0; formati < format_count; formati++) - { - _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end); - buf += bytes_read; - _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end); - buf += bytes_read; - } - - data_count = _bfd_safe_read_leb128 (abfd, buf, &bytes_read, FALSE, buf_end); - buf += bytes_read; - if (format_count == 0 && data_count != 0) - { - _bfd_error_handler (_("Dwarf Error: Zero format count.")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* PR 22210. Paranoia check. Don't bother running the loop - if we know that we are going to run out of buffer. */ - if (data_count > (bfd_vma) (buf_end - buf)) - { - _bfd_error_handler (_("Dwarf Error: data count (%Lx) larger than buffer size."), - data_count); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - for (datai = 0; datai < data_count; datai++) - { - bfd_byte *format = format_header_data; - struct fileinfo fe; - - memset (&fe, 0, sizeof fe); - for (formati = 0; formati < format_count; formati++) - { - bfd_vma content_type, form; - char *string_trash; - char **stringp = &string_trash; - unsigned int uint_trash, *uintp = &uint_trash; - struct attribute attr; - - content_type = _bfd_safe_read_leb128 (abfd, format, &bytes_read, - FALSE, buf_end); - format += bytes_read; - switch (content_type) - { - case DW_LNCT_path: - stringp = &fe.name; - break; - case DW_LNCT_directory_index: - uintp = &fe.dir; - break; - case DW_LNCT_timestamp: - uintp = &fe.time; - break; - case DW_LNCT_size: - uintp = &fe.size; - break; - case DW_LNCT_MD5: - break; - default: - _bfd_error_handler - (_("Dwarf Error: Unknown format content type %Lu."), - content_type); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - form = _bfd_safe_read_leb128 (abfd, format, &bytes_read, FALSE, - buf_end); - format += bytes_read; - - buf = read_attribute_value (&attr, form, 0, unit, buf, buf_end); - if (buf == NULL) - return FALSE; - switch (form) - { - case DW_FORM_string: - case DW_FORM_line_strp: - *stringp = attr.u.str; - break; - - case DW_FORM_data1: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - case DW_FORM_udata: - *uintp = attr.u.val; - break; - } - } - - if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) - return FALSE; - } - - *bufp = buf; - return TRUE; -} - -/* 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; - unsigned int exop_len; - bfd_size_type amt; - - if (! read_section (abfd, &stash->debug_sections[debug_line], - stash->syms, unit->line_offset, - &stash->dwarf_line_buffer, &stash->dwarf_line_size)) - return NULL; - - amt = sizeof (struct line_info_table); - table = (struct line_info_table *) bfd_alloc (abfd, amt); - if (table == NULL) - return NULL; - table->abfd = abfd; - table->comp_dir = unit->comp_dir; - - table->num_files = 0; - table->files = NULL; - - table->num_dirs = 0; - table->dirs = NULL; - - table->num_sequences = 0; - table->sequences = NULL; - - table->lcl_head = NULL; - - if (stash->dwarf_line_size < 16) - { - _bfd_error_handler - (_("Dwarf Error: Line info section is too small (%Ld)"), - stash->dwarf_line_size); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - line_ptr = stash->dwarf_line_buffer + unit->line_offset; - line_end = stash->dwarf_line_buffer + stash->dwarf_line_size; - - /* Read in the prologue. */ - lh.total_length = read_4_bytes (abfd, line_ptr, line_end); - line_ptr += 4; - offset_size = 4; - if (lh.total_length == 0xffffffff) - { - lh.total_length = read_8_bytes (abfd, line_ptr, line_end); - line_ptr += 8; - offset_size = 8; - } - else if (lh.total_length == 0 && unit->addr_size == 8) - { - /* Handle (non-standard) 64-bit DWARF2 formats. */ - lh.total_length = read_4_bytes (abfd, line_ptr, line_end); - line_ptr += 4; - offset_size = 8; - } - - if (lh.total_length > (size_t) (line_end - line_ptr)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("Dwarf Error: Line info data is bigger (%#Lx)" - " than the space remaining in the section (%#lx)"), - lh.total_length, (unsigned long) (line_end - line_ptr)); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - line_end = line_ptr + lh.total_length; - - lh.version = read_2_bytes (abfd, line_ptr, line_end); - if (lh.version < 2 || lh.version > 5) - { - _bfd_error_handler - (_("Dwarf Error: Unhandled .debug_line version %d."), lh.version); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - line_ptr += 2; - - if (line_ptr + offset_size + (lh.version >= 5 ? 8 : (lh.version >= 4 ? 6 : 5)) - >= line_end) - { - _bfd_error_handler - (_("Dwarf Error: Ran out of room reading prologue")); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - if (lh.version >= 5) - { - unsigned int segment_selector_size; - - /* Skip address size. */ - read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - segment_selector_size = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - if (segment_selector_size != 0) - { - _bfd_error_handler - (_("Dwarf Error: Line info unsupported segment selector size %u."), - segment_selector_size); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - } - - if (offset_size == 4) - lh.prologue_length = read_4_bytes (abfd, line_ptr, line_end); - else - lh.prologue_length = read_8_bytes (abfd, line_ptr, line_end); - line_ptr += offset_size; - - lh.minimum_instruction_length = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - if (lh.version >= 4) - { - lh.maximum_ops_per_insn = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - } - else - lh.maximum_ops_per_insn = 1; - - if (lh.maximum_ops_per_insn == 0) - { - _bfd_error_handler - (_("Dwarf Error: Invalid maximum operations per instruction.")); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - lh.default_is_stmt = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - lh.line_base = read_1_signed_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - lh.line_range = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - lh.opcode_base = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - if (line_ptr + (lh.opcode_base - 1) >= line_end) - { - _bfd_error_handler (_("Dwarf Error: Ran out of room reading opcodes")); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - amt = lh.opcode_base * sizeof (unsigned char); - lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt); - - 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_end); - line_ptr += 1; - } - - if (lh.version >= 5) - { - /* Read directory table. */ - if (!read_formatted_entries (unit, &line_ptr, line_end, table, - line_info_add_include_dir_stub)) - goto fail; - - /* Read file name table. */ - if (!read_formatted_entries (unit, &line_ptr, line_end, table, - line_info_add_file_name)) - goto fail; - } - else - { - /* Read directory table. */ - while ((cur_dir = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) - { - line_ptr += bytes_read; - - if (!line_info_add_include_dir (table, cur_dir)) - goto fail; - } - - line_ptr += bytes_read; - - /* Read file name table. */ - while ((cur_file = read_string (abfd, line_ptr, line_end, &bytes_read)) != NULL) - { - unsigned int dir, xtime, size; - - line_ptr += bytes_read; - - dir = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); - line_ptr += bytes_read; - xtime = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); - line_ptr += bytes_read; - size = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, FALSE, line_end); - line_ptr += bytes_read; - - if (!line_info_add_file_name (table, cur_file, dir, xtime, size)) - goto fail; - } - - 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; - unsigned char op_index = 0; - char * filename = table->num_files ? concat_filename (table, 1) : NULL; - unsigned int line = 1; - unsigned int column = 0; - unsigned int discriminator = 0; - int is_stmt = lh.default_is_stmt; - int end_sequence = 0; - unsigned int dir, xtime, size; - /* 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 && line_ptr < line_end) - { - op_code = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - if (op_code >= lh.opcode_base) - { - /* Special operand. */ - adj_opcode = op_code - lh.opcode_base; - if (lh.line_range == 0) - goto line_fail; - if (lh.maximum_ops_per_insn == 1) - address += (adj_opcode / lh.line_range - * lh.minimum_instruction_length); - else - { - address += ((op_index + adj_opcode / lh.line_range) - / lh.maximum_ops_per_insn - * lh.minimum_instruction_length); - op_index = ((op_index + adj_opcode / lh.line_range) - % lh.maximum_ops_per_insn); - } - line += lh.line_base + (adj_opcode % lh.line_range); - /* Append row to matrix using current values. */ - if (!add_line_info (table, address, op_index, filename, - line, column, discriminator, 0)) - goto line_fail; - discriminator = 0; - if (address < low_pc) - low_pc = address; - if (address > high_pc) - high_pc = address; - } - else switch (op_code) - { - case DW_LNS_extended_op: - exop_len = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - extended_op = read_1_byte (abfd, line_ptr, line_end); - line_ptr += 1; - - switch (extended_op) - { - case DW_LNE_end_sequence: - end_sequence = 1; - if (!add_line_info (table, address, op_index, filename, line, - column, discriminator, end_sequence)) - goto line_fail; - discriminator = 0; - if (address < low_pc) - low_pc = address; - if (address > high_pc) - high_pc = address; - if (!arange_add (unit, &unit->arange, low_pc, high_pc)) - goto line_fail; - break; - case DW_LNE_set_address: - address = read_address (unit, line_ptr, line_end); - op_index = 0; - line_ptr += unit->addr_size; - break; - case DW_LNE_define_file: - cur_file = read_string (abfd, line_ptr, line_end, &bytes_read); - line_ptr += bytes_read; - dir = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - xtime = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - size = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - if (!line_info_add_file_name (table, cur_file, dir, - xtime, size)) - goto line_fail; - break; - case DW_LNE_set_discriminator: - discriminator = - _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - break; - case DW_LNE_HP_source_file_correlation: - line_ptr += exop_len - 1; - break; - default: - _bfd_error_handler - (_("Dwarf Error: mangled line number section.")); - bfd_set_error (bfd_error_bad_value); - line_fail: - if (filename != NULL) - free (filename); - goto fail; - } - break; - case DW_LNS_copy: - if (!add_line_info (table, address, op_index, - filename, line, column, discriminator, 0)) - goto line_fail; - discriminator = 0; - if (address < low_pc) - low_pc = address; - if (address > high_pc) - high_pc = address; - break; - case DW_LNS_advance_pc: - if (lh.maximum_ops_per_insn == 1) - address += (lh.minimum_instruction_length - * _bfd_safe_read_leb128 (abfd, line_ptr, - &bytes_read, - FALSE, line_end)); - else - { - bfd_vma adjust = _bfd_safe_read_leb128 (abfd, line_ptr, - &bytes_read, - FALSE, line_end); - address = ((op_index + adjust) / lh.maximum_ops_per_insn - * lh.minimum_instruction_length); - op_index = (op_index + adjust) % lh.maximum_ops_per_insn; - } - line_ptr += bytes_read; - break; - case DW_LNS_advance_line: - line += _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - TRUE, line_end); - 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 = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - if (filename) - free (filename); - filename = concat_filename (table, file); - break; - } - case DW_LNS_set_column: - column = _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - break; - case DW_LNS_negate_stmt: - is_stmt = (!is_stmt); - break; - case DW_LNS_set_basic_block: - break; - case DW_LNS_const_add_pc: - if (lh.line_range == 0) - goto line_fail; - if (lh.maximum_ops_per_insn == 1) - address += (lh.minimum_instruction_length - * ((255 - lh.opcode_base) / lh.line_range)); - else - { - bfd_vma adjust = ((255 - lh.opcode_base) / lh.line_range); - address += (lh.minimum_instruction_length - * ((op_index + adjust) - / lh.maximum_ops_per_insn)); - op_index = (op_index + adjust) % lh.maximum_ops_per_insn; - } - break; - case DW_LNS_fixed_advance_pc: - address += read_2_bytes (abfd, line_ptr, line_end); - op_index = 0; - line_ptr += 2; - break; - default: - /* Unknown standard opcode, ignore it. */ - for (i = 0; i < lh.standard_opcode_lengths[op_code]; i++) - { - (void) _bfd_safe_read_leb128 (abfd, line_ptr, &bytes_read, - FALSE, line_end); - line_ptr += bytes_read; - } - break; - } - } - - if (filename) - free (filename); - } - - if (sort_line_sequences (table)) - return table; - - fail: - while (table->sequences != NULL) - { - struct line_sequence* seq = table->sequences; - table->sequences = table->sequences->prev_sequence; - free (seq); - } - if (table->files != NULL) - free (table->files); - if (table->dirs != NULL) - free (table->dirs); - return NULL; -} - -/* If ADDR is within TABLE set the output parameters and return the - range of addresses covered by the entry used to fill them out. - Otherwise set * FILENAME_PTR to NULL and return 0. - The parameters FILENAME_PTR, LINENUMBER_PTR and DISCRIMINATOR_PTR - are pointers to the objects to be filled in. */ - -static bfd_vma -lookup_address_in_line_info_table (struct line_info_table *table, - bfd_vma addr, - const char **filename_ptr, - unsigned int *linenumber_ptr, - unsigned int *discriminator_ptr) -{ - struct line_sequence *seq = NULL; - struct line_info *info; - int low, high, mid; - - /* Binary search the array of sequences. */ - low = 0; - high = table->num_sequences; - while (low < high) - { - mid = (low + high) / 2; - seq = &table->sequences[mid]; - if (addr < seq->low_pc) - high = mid; - else if (addr >= seq->last_line->address) - low = mid + 1; - else - break; - } - - /* Check for a valid sequence. */ - if (!seq || addr < seq->low_pc || addr >= seq->last_line->address) - goto fail; - - if (!build_line_info_table (table, seq)) - goto fail; - - /* Binary search the array of line information. */ - low = 0; - high = seq->num_lines; - info = NULL; - while (low < high) - { - mid = (low + high) / 2; - info = seq->line_info_lookup[mid]; - if (addr < info->address) - high = mid; - else if (addr >= seq->line_info_lookup[mid + 1]->address) - low = mid + 1; - else - break; - } - - /* Check for a valid line information entry. */ - if (info - && addr >= info->address - && addr < seq->line_info_lookup[mid + 1]->address - && !(info->end_sequence || info == seq->last_line)) - { - *filename_ptr = info->filename; - *linenumber_ptr = info->line; - if (discriminator_ptr) - *discriminator_ptr = info->discriminator; - return seq->last_line->address - seq->low_pc; - } - -fail: - *filename_ptr = NULL; - return 0; -} - -/* 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; - - return read_section (unit->abfd, &stash->debug_sections[debug_ranges], - stash->syms, 0, - &stash->dwarf_ranges_buffer, - &stash->dwarf_ranges_size); -} - -/* Function table functions. */ - -static int -compare_lookup_funcinfos (const void * a, const void * b) -{ - const struct lookup_funcinfo * lookup1 = a; - const struct lookup_funcinfo * lookup2 = b; - - if (lookup1->low_addr < lookup2->low_addr) - return -1; - if (lookup1->low_addr > lookup2->low_addr) - return 1; - if (lookup1->high_addr < lookup2->high_addr) - return -1; - if (lookup1->high_addr > lookup2->high_addr) - return 1; - - return 0; -} - -static bfd_boolean -build_lookup_funcinfo_table (struct comp_unit * unit) -{ - struct lookup_funcinfo *lookup_funcinfo_table = unit->lookup_funcinfo_table; - unsigned int number_of_functions = unit->number_of_functions; - struct funcinfo *each; - struct lookup_funcinfo *entry; - size_t func_index; - struct arange *range; - bfd_vma low_addr, high_addr; - - if (lookup_funcinfo_table || number_of_functions == 0) - return TRUE; - - /* Create the function info lookup table. */ - lookup_funcinfo_table = (struct lookup_funcinfo *) - bfd_malloc (number_of_functions * sizeof (struct lookup_funcinfo)); - if (lookup_funcinfo_table == NULL) - return FALSE; - - /* Populate the function info lookup table. */ - func_index = number_of_functions; - for (each = unit->function_table; each; each = each->prev_func) - { - entry = &lookup_funcinfo_table[--func_index]; - entry->funcinfo = each; - - /* Calculate the lowest and highest address for this function entry. */ - low_addr = entry->funcinfo->arange.low; - high_addr = entry->funcinfo->arange.high; - - for (range = entry->funcinfo->arange.next; range; range = range->next) - { - if (range->low < low_addr) - low_addr = range->low; - if (range->high > high_addr) - high_addr = range->high; - } - - entry->low_addr = low_addr; - entry->high_addr = high_addr; - } - - BFD_ASSERT (func_index == 0); - - /* Sort the function by address. */ - qsort (lookup_funcinfo_table, - number_of_functions, - sizeof (struct lookup_funcinfo), - compare_lookup_funcinfos); - - /* Calculate the high watermark for each function in the lookup table. */ - high_addr = lookup_funcinfo_table[0].high_addr; - for (func_index = 1; func_index < number_of_functions; func_index++) - { - entry = &lookup_funcinfo_table[func_index]; - if (entry->high_addr > high_addr) - high_addr = entry->high_addr; - else - entry->high_addr = high_addr; - } - - unit->lookup_funcinfo_table = lookup_funcinfo_table; - return TRUE; -} - -/* If ADDR is within UNIT's function tables, set FUNCTION_PTR, and return - TRUE. Note that we need to find the function that has the smallest range - that contains ADDR, to handle inlined functions without depending upon - them being ordered in TABLE by increasing range. */ - -static bfd_boolean -lookup_address_in_function_table (struct comp_unit *unit, - bfd_vma addr, - struct funcinfo **function_ptr) -{ - unsigned int number_of_functions = unit->number_of_functions; - struct lookup_funcinfo* lookup_funcinfo = NULL; - struct funcinfo* funcinfo = NULL; - struct funcinfo* best_fit = NULL; - bfd_vma best_fit_len = 0; - bfd_size_type low, high, mid, first; - struct arange *arange; - - if (number_of_functions == 0) - return FALSE; - - if (!build_lookup_funcinfo_table (unit)) - return FALSE; - - if (unit->lookup_funcinfo_table[number_of_functions - 1].high_addr < addr) - return FALSE; - - /* Find the first function in the lookup table which may contain the - specified address. */ - low = 0; - high = number_of_functions; - first = high; - while (low < high) - { - mid = (low + high) / 2; - lookup_funcinfo = &unit->lookup_funcinfo_table[mid]; - if (addr < lookup_funcinfo->low_addr) - high = mid; - else if (addr >= lookup_funcinfo->high_addr) - low = mid + 1; - else - high = first = mid; - } - - /* Find the 'best' match for the address. The prior algorithm defined the - best match as the function with the smallest address range containing - the specified address. This definition should probably be changed to the - innermost inline routine containing the address, but right now we want - to get the same results we did before. */ - while (first < number_of_functions) - { - if (addr < unit->lookup_funcinfo_table[first].low_addr) - break; - funcinfo = unit->lookup_funcinfo_table[first].funcinfo; - - for (arange = &funcinfo->arange; arange; arange = arange->next) - { - if (addr < arange->low || addr >= arange->high) - continue; - - if (!best_fit - || arange->high - arange->low < best_fit_len - /* The following comparison is designed to return the same - match as the previous algorithm for routines which have the - same best fit length. */ - || (arange->high - arange->low == best_fit_len - && funcinfo > best_fit)) - { - best_fit = funcinfo; - best_fit_len = arange->high - arange->low; - } - } - - first++; - } - - if (!best_fit) - return FALSE; - - *function_ptr = best_fit; - return TRUE; -} - -/* 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; - bfd_vma best_fit_len = 0; - 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_len)) - { - best_fit = each_func; - best_fit_len = arange->high - arange->low; - } - } - } - - 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; - } - - return FALSE; -} - -static bfd_boolean -find_abstract_instance_name (struct comp_unit *unit, - bfd_byte *orig_info_ptr, - struct attribute *attr_ptr, - const char **pname, - bfd_boolean *is_linkage) -{ - bfd *abfd = unit->abfd; - bfd_byte *info_ptr; - bfd_byte *info_ptr_end; - unsigned int abbrev_number, bytes_read, i; - struct abbrev_info *abbrev; - bfd_uint64_t die_ref = attr_ptr->u.val; - struct attribute attr; - const char *name = NULL; - - /* DW_FORM_ref_addr can reference an entry in a different CU. It - is an offset from the .debug_info section, not the current CU. */ - if (attr_ptr->form == DW_FORM_ref_addr) - { - /* We only support DW_FORM_ref_addr within the same file, so - any relocations should be resolved already. Check this by - testing for a zero die_ref; There can't be a valid reference - to the header of a .debug_info section. - DW_FORM_ref_addr is an offset relative to .debug_info. - Normally when using the GNU linker this is accomplished by - emitting a symbolic reference to a label, because .debug_info - sections are linked at zero. When there are multiple section - groups containing .debug_info, as there might be in a - relocatable object file, it would be reasonable to assume that - a symbolic reference to a label in any .debug_info section - might be used. Since we lay out multiple .debug_info - sections at non-zero VMAs (see place_sections), and read - them contiguously into stash->info_ptr_memory, that means - the reference is relative to stash->info_ptr_memory. */ - size_t total; - - info_ptr = unit->stash->info_ptr_memory; - info_ptr_end = unit->stash->info_ptr_end; - total = info_ptr_end - info_ptr; - if (!die_ref || die_ref >= total) - { - _bfd_error_handler - (_("Dwarf Error: Invalid abstract instance DIE ref.")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - info_ptr += die_ref; - - /* Now find the CU containing this pointer. */ - if (info_ptr >= unit->info_ptr_unit && info_ptr < unit->end_ptr) - info_ptr_end = unit->end_ptr; - else - { - /* Check other CUs to see if they contain the abbrev. */ - struct comp_unit * u; - - for (u = unit->prev_unit; u != NULL; u = u->prev_unit) - if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr) - break; - - if (u == NULL) - for (u = unit->next_unit; u != NULL; u = u->next_unit) - if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr) - break; - - if (u) - { - unit = u; - info_ptr_end = unit->end_ptr; - } - /* else FIXME: What do we do now ? */ - } - } - else if (attr_ptr->form == DW_FORM_GNU_ref_alt) - { - info_ptr = read_alt_indirect_ref (unit, die_ref); - if (info_ptr == NULL) - { - _bfd_error_handler - (_("Dwarf Error: Unable to read alt ref %llu."), - (long long) die_ref); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - info_ptr_end = (unit->stash->alt_dwarf_info_buffer - + unit->stash->alt_dwarf_info_size); - - /* FIXME: Do we need to locate the correct CU, in a similar - fashion to the code in the DW_FORM_ref_addr case above ? */ - } - else - { - /* DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8 or - DW_FORM_ref_udata. These are all references relative to the - start of the current CU. */ - size_t total; - - info_ptr = unit->info_ptr_unit; - info_ptr_end = unit->end_ptr; - total = info_ptr_end - info_ptr; - if (!die_ref || die_ref >= total) - { - _bfd_error_handler - (_("Dwarf Error: Invalid abstract instance DIE ref.")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - info_ptr += die_ref; - } - - abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, info_ptr_end); - 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); - return FALSE; - } - else - { - for (i = 0; i < abbrev->num_attrs; ++i) - { - info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, - info_ptr, info_ptr_end); - if (info_ptr == NULL) - break; - /* It doesn't ever make sense for DW_AT_specification to - refer to the same DIE. Stop simple recursion. */ - if (info_ptr == orig_info_ptr) - { - _bfd_error_handler - (_("Dwarf Error: Abstract instance recursion detected.")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - switch (attr.name) - { - case DW_AT_name: - /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name - over DW_AT_name. */ - if (name == NULL && is_str_attr (attr.form)) - { - name = attr.u.str; - if (non_mangled (unit->lang)) - *is_linkage = TRUE; - } - break; - case DW_AT_specification: - if (!find_abstract_instance_name (unit, info_ptr, &attr, - pname, is_linkage)) - return FALSE; - break; - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - /* PR 16949: Corrupt debug info can place - non-string forms into these attributes. */ - if (is_str_attr (attr.form)) - { - name = attr.u.str; - *is_linkage = TRUE; - } - break; - default: - break; - } - } - } - } - *pname = name; - return TRUE; -} - -static bfd_boolean -read_rangelist (struct comp_unit *unit, struct arange *arange, - bfd_uint64_t offset) -{ - bfd_byte *ranges_ptr; - bfd_byte *ranges_end; - bfd_vma base_address = unit->base_address; - - if (! unit->stash->dwarf_ranges_buffer) - { - if (! read_debug_ranges (unit)) - return FALSE; - } - - ranges_ptr = unit->stash->dwarf_ranges_buffer + offset; - if (ranges_ptr < unit->stash->dwarf_ranges_buffer) - return FALSE; - ranges_end = unit->stash->dwarf_ranges_buffer + unit->stash->dwarf_ranges_size; - - for (;;) - { - bfd_vma low_pc; - bfd_vma high_pc; - - /* PR 17512: file: 62cada7d. */ - if (ranges_ptr + 2 * unit->addr_size > ranges_end) - return FALSE; - - low_pc = read_address (unit, ranges_ptr, ranges_end); - ranges_ptr += unit->addr_size; - high_pc = read_address (unit, ranges_ptr, ranges_end); - ranges_ptr += unit->addr_size; - - if (low_pc == 0 && high_pc == 0) - break; - if (low_pc == -1UL && high_pc != -1UL) - base_address = high_pc; - else - { - if (!arange_add (unit, arange, - base_address + low_pc, base_address + high_pc)) - return FALSE; - } - } - return TRUE; -} - -/* 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; - bfd_byte *info_ptr_end = unit->stash->info_ptr_end; - int nesting_level = 0; - struct nest_funcinfo { - struct funcinfo *func; - } *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 = (struct nest_funcinfo *) - bfd_malloc (nested_funcs_size * sizeof (*nested_funcs)); - if (nested_funcs == NULL) - return FALSE; - nested_funcs[nesting_level].func = 0; - - while (nesting_level >= 0) - { - 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; - bfd_boolean high_pc_relative = FALSE; - - /* PR 17512: file: 9f405d9d. */ - if (info_ptr >= info_ptr_end) - goto fail; - - abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, info_ptr_end); - info_ptr += bytes_read; - - if (! abbrev_number) - { - nesting_level--; - continue; - } - - abbrev = lookup_abbrev (abbrev_number, unit->abbrevs); - if (! abbrev) - { - static unsigned int previous_failed_abbrev = -1U; - - /* Avoid multiple reports of the same missing abbrev. */ - if (abbrev_number != previous_failed_abbrev) - { - _bfd_error_handler - (_("Dwarf Error: Could not find abbrev number %u."), - abbrev_number); - previous_failed_abbrev = abbrev_number; - } - bfd_set_error (bfd_error_bad_value); - goto fail; - } - - 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 = (struct funcinfo *) bfd_zalloc (abfd, amt); - if (func == NULL) - goto fail; - func->tag = abbrev->tag; - func->prev_func = unit->function_table; - unit->function_table = func; - unit->number_of_functions++; - BFD_ASSERT (!unit->cached); - - if (func->tag == DW_TAG_inlined_subroutine) - for (i = nesting_level; i-- != 0; ) - if (nested_funcs[i].func) - { - func->caller_func = nested_funcs[i].func; - break; - } - nested_funcs[nesting_level].func = func; - } - else - { - func = NULL; - if (abbrev->tag == DW_TAG_variable) - { - bfd_size_type amt = sizeof (struct varinfo); - var = (struct varinfo *) bfd_zalloc (abfd, amt); - if (var == NULL) - goto fail; - var->tag = abbrev->tag; - var->stack = 1; - var->prev_var = unit->variable_table; - unit->variable_table = var; - /* PR 18205: Missing debug information can cause this - var to be attached to an already cached unit. */ - } - - /* No inline function in scope at this nesting level. */ - nested_funcs[nesting_level].func = 0; - } - - for (i = 0; i < abbrev->num_attrs; ++i) - { - info_ptr = read_attribute (&attr, &abbrev->attrs[i], - unit, info_ptr, info_ptr_end); - if (info_ptr == NULL) - goto fail; - - 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: - case DW_AT_specification: - if (!find_abstract_instance_name (unit, info_ptr, &attr, - &func->name, - &func->is_linkage)) - goto fail; - break; - - case DW_AT_name: - /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name - over DW_AT_name. */ - if (func->name == NULL && is_str_attr (attr.form)) - { - func->name = attr.u.str; - if (non_mangled (unit->lang)) - func->is_linkage = TRUE; - } - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - /* PR 16949: Corrupt debug info can place - non-string forms into these attributes. */ - if (is_str_attr (attr.form)) - { - func->name = attr.u.str; - func->is_linkage = TRUE; - } - break; - - case DW_AT_low_pc: - low_pc = attr.u.val; - break; - - case DW_AT_high_pc: - high_pc = attr.u.val; - high_pc_relative = attr.form != DW_FORM_addr; - break; - - case DW_AT_ranges: - if (!read_rangelist (unit, &func->arange, attr.u.val)) - goto fail; - 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: - if (is_str_attr (attr.form)) - 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: - case DW_FORM_exprloc: - if (attr.u.blk->data != NULL - && *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 (high_pc_relative) - high_pc += low_pc; - - if (func && high_pc != 0) - { - if (!arange_add (unit, &func->arange, low_pc, high_pc)) - goto fail; - } - - if (abbrev->has_children) - { - nesting_level++; - - if (nesting_level >= nested_funcs_size) - { - struct nest_funcinfo *tmp; - - nested_funcs_size *= 2; - tmp = (struct nest_funcinfo *) - bfd_realloc (nested_funcs, - nested_funcs_size * sizeof (*nested_funcs)); - if (tmp == NULL) - goto fail; - nested_funcs = tmp; - } - nested_funcs[nesting_level].func = 0; - } - } - - free (nested_funcs); - return TRUE; - - fail: - free (nested_funcs); - return FALSE; -} - -/* 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 (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; - /* Initialize it just to avoid a GCC false warning. */ - unsigned int addr_size = -1; - 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; - bfd *abfd = stash->bfd_ptr; - bfd_boolean high_pc_relative = FALSE; - enum dwarf_unit_type unit_type; - - version = read_2_bytes (abfd, info_ptr, end_ptr); - info_ptr += 2; - if (version < 2 || version > 5) - { - /* PR 19872: A version number of 0 probably means that there is padding - at the end of the .debug_info section. Gold puts it there when - performing an incremental link, for example. So do not generate - an error, just return a NULL. */ - if (version) - { - _bfd_error_handler - (_("Dwarf Error: found dwarf version '%u', this reader" - " only handles version 2, 3, 4 and 5 information."), version); - bfd_set_error (bfd_error_bad_value); - } - return NULL; - } - - if (version < 5) - unit_type = DW_UT_compile; - else - { - unit_type = read_1_byte (abfd, info_ptr, end_ptr); - info_ptr += 1; - - addr_size = read_1_byte (abfd, info_ptr, end_ptr); - info_ptr += 1; - } - - BFD_ASSERT (offset_size == 4 || offset_size == 8); - if (offset_size == 4) - abbrev_offset = read_4_bytes (abfd, info_ptr, end_ptr); - else - abbrev_offset = read_8_bytes (abfd, info_ptr, end_ptr); - info_ptr += offset_size; - - if (version < 5) - { - addr_size = read_1_byte (abfd, info_ptr, end_ptr); - info_ptr += 1; - } - - if (unit_type == DW_UT_type) - { - /* Skip type signature. */ - info_ptr += 8; - - /* Skip type offset. */ - info_ptr += offset_size; - } - - if (addr_size > sizeof (bfd_vma)) - { - _bfd_error_handler - /* xgettext: c-format */ - (_("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 NULL; - } - - 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 NULL; - } - - /* Read the abbrevs for this compilation unit into a table. */ - abbrevs = read_abbrevs (abfd, abbrev_offset, stash); - if (! abbrevs) - return NULL; - - abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read, - FALSE, end_ptr); - info_ptr += bytes_read; - if (! abbrev_number) - { - /* PR 19872: An abbrev number of 0 probably means that there is padding - at the end of the .debug_abbrev section. Gold puts it there when - performing an incremental link, for example. So do not generate - an error, just return a NULL. */ - return NULL; - } - - 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 NULL; - } - - amt = sizeof (struct comp_unit); - unit = (struct comp_unit *) bfd_zalloc (abfd, amt); - if (unit == NULL) - return NULL; - unit->abfd = abfd; - unit->version = version; - 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, end_ptr); - if (info_ptr == NULL) - return NULL; - - /* 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: - if (is_str_attr (attr.form)) - 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. */ - if (abbrev->tag == DW_TAG_compile_unit) - unit->base_address = low_pc; - break; - - case DW_AT_high_pc: - high_pc = attr.u.val; - high_pc_relative = attr.form != DW_FORM_addr; - break; - - case DW_AT_ranges: - if (!read_rangelist (unit, &unit->arange, attr.u.val)) - return NULL; - break; - - case DW_AT_comp_dir: - { - char *comp_dir = attr.u.str; - - /* PR 17512: file: 1fe726be. */ - if (! is_str_attr (attr.form)) - { - _bfd_error_handler - (_("Dwarf Error: DW_AT_comp_dir attribute encountered with a non-string form.")); - comp_dir = NULL; - } - - if (comp_dir) - { - /* Irix 6.2 native cc prepends .: to the compilation - 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; - } - - case DW_AT_language: - unit->lang = attr.u.val; - break; - - default: - break; - } - } - if (high_pc_relative) - high_pc += low_pc; - if (high_pc != 0) - { - if (!arange_add (unit, &unit->arange, low_pc, high_pc)) - return NULL; - } - - 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, - FUNCTION_PTR, and LINENUMBER_PTR, are pointers to the objects - to be filled in. - - Returns the range of addresses covered by the entry that was used - to fill in *LINENUMBER_PTR or 0 if it was not filled in. */ - -static bfd_vma -comp_unit_find_nearest_line (struct comp_unit *unit, - bfd_vma addr, - const char **filename_ptr, - struct funcinfo **function_ptr, - unsigned int *linenumber_ptr, - unsigned int *discriminator_ptr, - struct dwarf2_debug *stash) -{ - bfd_boolean func_p; - - 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_ptr = NULL; - func_p = lookup_address_in_function_table (unit, addr, function_ptr); - if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine) - stash->inliner_chain = *function_ptr; - - return lookup_address_in_line_info_table (unit->line_table, addr, - filename_ptr, - linenumber_ptr, - discriminator_ptr); -} - -/* Check to see if line info is already decoded in a comp_unit. - If not, decode it. Returns TRUE if no errors were encountered; - FALSE otherwise. */ - -static bfd_boolean -comp_unit_maybe_decode_line_info (struct comp_unit *unit, - 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; - } - } - - return TRUE; -} - -/* 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 (!comp_unit_maybe_decode_line_info (unit, stash)) - return FALSE; - - if (sym->flags & BSF_FUNCTION) - return lookup_symbol_in_function_table (unit, sym, addr, - filename_ptr, - linenumber_ptr); - - return lookup_symbol_in_variable_table (unit, sym, addr, - filename_ptr, - linenumber_ptr); -} - -static struct funcinfo * -reverse_funcinfo_list (struct funcinfo *head) -{ - struct funcinfo *rhead; - struct funcinfo *temp; - - for (rhead = NULL; head; head = temp) - { - temp = head->prev_func; - head->prev_func = rhead; - rhead = head; - } - return rhead; -} - -static struct varinfo * -reverse_varinfo_list (struct varinfo *head) -{ - struct varinfo *rhead; - struct varinfo *temp; - - for (rhead = NULL; head; head = temp) - { - temp = head->prev_var; - head->prev_var = rhead; - rhead = head; - } - return rhead; -} - -/* Extract all interesting funcinfos and varinfos of a compilation - unit into hash tables for faster lookup. Returns TRUE if no - errors were enountered; FALSE otherwise. */ - -static bfd_boolean -comp_unit_hash_info (struct dwarf2_debug *stash, - struct comp_unit *unit, - struct info_hash_table *funcinfo_hash_table, - struct info_hash_table *varinfo_hash_table) -{ - struct funcinfo* each_func; - struct varinfo* each_var; - bfd_boolean okay = TRUE; - - BFD_ASSERT (stash->info_hash_status != STASH_INFO_HASH_DISABLED); - - if (!comp_unit_maybe_decode_line_info (unit, stash)) - return FALSE; - - BFD_ASSERT (!unit->cached); - - /* To preserve the original search order, we went to visit the function - infos in the reversed order of the list. However, making the list - bi-directional use quite a bit of extra memory. So we reverse - the list first, traverse the list in the now reversed order and - finally reverse the list again to get back the original order. */ - unit->function_table = reverse_funcinfo_list (unit->function_table); - for (each_func = unit->function_table; - each_func && okay; - each_func = each_func->prev_func) - { - /* Skip nameless functions. */ - if (each_func->name) - /* There is no need to copy name string into hash table as - name string is either in the dwarf string buffer or - info in the stash. */ - okay = insert_info_hash_table (funcinfo_hash_table, each_func->name, - (void*) each_func, FALSE); - } - unit->function_table = reverse_funcinfo_list (unit->function_table); - if (!okay) - return FALSE; - - /* We do the same for variable infos. */ - unit->variable_table = reverse_varinfo_list (unit->variable_table); - for (each_var = unit->variable_table; - each_var && okay; - each_var = each_var->prev_var) - { - /* Skip stack vars and vars with no files or names. */ - if (each_var->stack == 0 - && each_var->file != NULL - && each_var->name != NULL) - /* There is no need to copy name string into hash table as - name string is either in the dwarf string buffer or - info in the stash. */ - okay = insert_info_hash_table (varinfo_hash_table, each_var->name, - (void*) each_var, FALSE); - } - - unit->variable_table = reverse_varinfo_list (unit->variable_table); - unit->cached = TRUE; - return okay; -} - -/* 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 three permissiable names. The first two are given - by DEBUG_SECTIONS[debug_info] (whose standard DWARF2 names are .debug_info - and .zdebug_info). The third 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 GNU_LINKONCE_INFO ".gnu.linkonce.wi." - -static asection * -find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections, - asection *after_sec) -{ - asection *msec; - const char *look; - - if (after_sec == NULL) - { - look = debug_sections[debug_info].uncompressed_name; - msec = bfd_get_section_by_name (abfd, look); - if (msec != NULL) - return msec; - - look = debug_sections[debug_info].compressed_name; - if (look != NULL) - { - msec = bfd_get_section_by_name (abfd, look); - if (msec != NULL) - return msec; - } - - for (msec = abfd->sections; msec != NULL; msec = msec->next) - if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO)) - return msec; - - return NULL; - } - - for (msec = after_sec->next; msec != NULL; msec = msec->next) - { - look = debug_sections[debug_info].uncompressed_name; - if (strcmp (msec->name, look) == 0) - return msec; - - look = debug_sections[debug_info].compressed_name; - if (look != NULL && strcmp (msec->name, look) == 0) - return msec; - - if (CONST_STRNEQ (msec->name, GNU_LINKONCE_INFO)) - return msec; - } - - return NULL; -} - -/* Transfer VMAs from object file to separate debug file. */ - -static void -set_debug_vma (bfd *orig_bfd, bfd *debug_bfd) -{ - asection *s, *d; - - for (s = orig_bfd->sections, d = debug_bfd->sections; - s != NULL && d != NULL; - s = s->next, d = d->next) - { - if ((d->flags & SEC_DEBUGGING) != 0) - break; - /* ??? Assumes 1-1 correspondence between sections in the - two files. */ - if (strcmp (s->name, d->name) == 0) - { - d->output_section = s->output_section; - d->output_offset = s->output_offset; - d->vma = s->vma; - } - } -} - -/* Unset vmas for adjusted sections in STASH. */ - -static void -unset_sections (struct dwarf2_debug *stash) -{ - int i; - struct adjusted_section *p; - - i = stash->adjusted_section_count; - p = stash->adjusted_sections; - for (; i > 0; i--, p++) - p->section->vma = 0; -} - -/* Set VMAs for allocated and .debug_info sections in ORIG_BFD, a - relocatable object file. VMAs are normally all zero in relocatable - object files, so if we want to distinguish locations in sections by - address we need to set VMAs so the sections do not overlap. We - also set VMA on .debug_info so that when we have multiple - .debug_info sections (or the linkonce variant) they also do not - overlap. The multiple .debug_info sections make up a single - logical section. ??? We should probably do the same for other - debug sections. */ - -static bfd_boolean -place_sections (bfd *orig_bfd, struct dwarf2_debug *stash) -{ - bfd *abfd; - struct adjusted_section *p; - int i; - const char *debug_info_name; - - if (stash->adjusted_section_count != 0) - { - i = stash->adjusted_section_count; - p = stash->adjusted_sections; - for (; i > 0; i--, p++) - p->section->vma = p->adj_vma; - return TRUE; - } - - debug_info_name = stash->debug_sections[debug_info].uncompressed_name; - i = 0; - abfd = orig_bfd; - while (1) - { - asection *sect; - - for (sect = abfd->sections; sect != NULL; sect = sect->next) - { - int is_debug_info; - - if ((sect->output_section != NULL - && sect->output_section != sect - && (sect->flags & SEC_DEBUGGING) == 0) - || sect->vma != 0) - continue; - - is_debug_info = (strcmp (sect->name, debug_info_name) == 0 - || CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)); - - if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd) - && !is_debug_info) - continue; - - i++; - } - if (abfd == stash->bfd_ptr) - break; - abfd = stash->bfd_ptr; - } - - if (i <= 1) - stash->adjusted_section_count = -1; - else - { - bfd_vma last_vma = 0, last_dwarf = 0; - bfd_size_type amt = i * sizeof (struct adjusted_section); - - p = (struct adjusted_section *) bfd_malloc (amt); - if (p == NULL) - return FALSE; - - stash->adjusted_sections = p; - stash->adjusted_section_count = i; - - abfd = orig_bfd; - while (1) - { - asection *sect; - - for (sect = abfd->sections; sect != NULL; sect = sect->next) - { - bfd_size_type sz; - int is_debug_info; - - if ((sect->output_section != NULL - && sect->output_section != sect - && (sect->flags & SEC_DEBUGGING) == 0) - || sect->vma != 0) - continue; - - is_debug_info = (strcmp (sect->name, debug_info_name) == 0 - || CONST_STRNEQ (sect->name, GNU_LINKONCE_INFO)); - - if (!((sect->flags & SEC_ALLOC) != 0 && abfd == orig_bfd) - && !is_debug_info) - continue; - - sz = sect->rawsize ? sect->rawsize : sect->size; - - if (is_debug_info) - { - BFD_ASSERT (sect->alignment_power == 0); - sect->vma = last_dwarf; - last_dwarf += sz; - } - else - { - /* Align the new address to the current section - alignment. */ - last_vma = ((last_vma - + ~(-((bfd_vma) 1 << sect->alignment_power))) - & (-((bfd_vma) 1 << sect->alignment_power))); - sect->vma = last_vma; - last_vma += sz; - } - - p->section = sect; - p->adj_vma = sect->vma; - p++; - } - if (abfd == stash->bfd_ptr) - break; - abfd = stash->bfd_ptr; - } - } - - if (orig_bfd != stash->bfd_ptr) - set_debug_vma (orig_bfd, stash->bfd_ptr); - - return TRUE; -} - -/* Look up a funcinfo by name using the given info hash table. If found, - also update the locations pointed to by filename_ptr and linenumber_ptr. - - This function returns TRUE if a funcinfo that matches the given symbol - and address is found with any error; otherwise it returns FALSE. */ - -static bfd_boolean -info_hash_lookup_funcinfo (struct info_hash_table *hash_table, - asymbol *sym, - bfd_vma addr, - const char **filename_ptr, - unsigned int *linenumber_ptr) -{ - struct funcinfo* each_func; - struct funcinfo* best_fit = NULL; - bfd_vma best_fit_len = 0; - struct info_list_node *node; - struct arange *arange; - const char *name = bfd_asymbol_name (sym); - asection *sec = bfd_get_section (sym); - - for (node = lookup_info_hash_table (hash_table, name); - node; - node = node->next) - { - each_func = (struct funcinfo *) node->info; - for (arange = &each_func->arange; - arange; - arange = arange->next) - { - if ((!each_func->sec || each_func->sec == sec) - && addr >= arange->low - && addr < arange->high - && (!best_fit - || arange->high - arange->low < best_fit_len)) - { - best_fit = each_func; - best_fit_len = arange->high - arange->low; - } - } - } - - if (best_fit) - { - best_fit->sec = sec; - *filename_ptr = best_fit->file; - *linenumber_ptr = best_fit->line; - return TRUE; - } - - return FALSE; -} - -/* Look up a varinfo by name using the given info hash table. If found, - also update the locations pointed to by filename_ptr and linenumber_ptr. - - This function returns TRUE if a varinfo that matches the given symbol - and address is found with any error; otherwise it returns FALSE. */ - -static bfd_boolean -info_hash_lookup_varinfo (struct info_hash_table *hash_table, - 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; - struct info_list_node *node; - - for (node = lookup_info_hash_table (hash_table, name); - node; - node = node->next) - { - each = (struct varinfo *) node->info; - if (each->addr == addr - && (!each->sec || each->sec == sec)) - { - each->sec = sec; - *filename_ptr = each->file; - *linenumber_ptr = each->line; - return TRUE; - } - } - - return FALSE; -} - -/* Update the funcinfo and varinfo info hash tables if they are - not up to date. Returns TRUE if there is no error; otherwise - returns FALSE and disable the info hash tables. */ - -static bfd_boolean -stash_maybe_update_info_hash_tables (struct dwarf2_debug *stash) -{ - struct comp_unit *each; - - /* Exit if hash tables are up-to-date. */ - if (stash->all_comp_units == stash->hash_units_head) - return TRUE; - - if (stash->hash_units_head) - each = stash->hash_units_head->prev_unit; - else - each = stash->last_comp_unit; - - while (each) - { - if (!comp_unit_hash_info (stash, each, stash->funcinfo_hash_table, - stash->varinfo_hash_table)) - { - stash->info_hash_status = STASH_INFO_HASH_DISABLED; - return FALSE; - } - each = each->prev_unit; - } - - stash->hash_units_head = stash->all_comp_units; - return TRUE; -} - -/* Check consistency of info hash tables. This is for debugging only. */ - -static void ATTRIBUTE_UNUSED -stash_verify_info_hash_table (struct dwarf2_debug *stash) -{ - struct comp_unit *each_unit; - struct funcinfo *each_func; - struct varinfo *each_var; - struct info_list_node *node; - bfd_boolean found; - - for (each_unit = stash->all_comp_units; - each_unit; - each_unit = each_unit->next_unit) - { - for (each_func = each_unit->function_table; - each_func; - each_func = each_func->prev_func) - { - if (!each_func->name) - continue; - node = lookup_info_hash_table (stash->funcinfo_hash_table, - each_func->name); - BFD_ASSERT (node); - found = FALSE; - while (node && !found) - { - found = node->info == each_func; - node = node->next; - } - BFD_ASSERT (found); - } - - for (each_var = each_unit->variable_table; - each_var; - each_var = each_var->prev_var) - { - if (!each_var->name || !each_var->file || each_var->stack) - continue; - node = lookup_info_hash_table (stash->varinfo_hash_table, - each_var->name); - BFD_ASSERT (node); - found = FALSE; - while (node && !found) - { - found = node->info == each_var; - node = node->next; - } - BFD_ASSERT (found); - } - } -} - -/* Check to see if we want to enable the info hash tables, which consume - quite a bit of memory. Currently we only check the number times - bfd_dwarf2_find_line is called. In the future, we may also want to - take the number of symbols into account. */ - -static void -stash_maybe_enable_info_hash_tables (bfd *abfd, struct dwarf2_debug *stash) -{ - BFD_ASSERT (stash->info_hash_status == STASH_INFO_HASH_OFF); - - if (stash->info_hash_count++ < STASH_INFO_HASH_TRIGGER) - return; - - /* FIXME: Maybe we should check the reduce_memory_overheads - and optimize fields in the bfd_link_info structure ? */ - - /* Create hash tables. */ - stash->funcinfo_hash_table = create_info_hash_table (abfd); - stash->varinfo_hash_table = create_info_hash_table (abfd); - if (!stash->funcinfo_hash_table || !stash->varinfo_hash_table) - { - /* Turn off info hashes if any allocation above fails. */ - stash->info_hash_status = STASH_INFO_HASH_DISABLED; - return; - } - /* We need a forced update so that the info hash tables will - be created even though there is no compilation unit. That - happens if STASH_INFO_HASH_TRIGGER is 0. */ - stash_maybe_update_info_hash_tables (stash); - stash->info_hash_status = STASH_INFO_HASH_ON; -} - -/* Find the file and line associated with a symbol and address using the - info hash tables of a stash. If there is a match, the function returns - TRUE and update the locations pointed to by filename_ptr and linenumber_ptr; - otherwise it returns FALSE. */ - -static bfd_boolean -stash_find_line_fast (struct dwarf2_debug *stash, - asymbol *sym, - bfd_vma addr, - const char **filename_ptr, - unsigned int *linenumber_ptr) -{ - BFD_ASSERT (stash->info_hash_status == STASH_INFO_HASH_ON); - - if (sym->flags & BSF_FUNCTION) - return info_hash_lookup_funcinfo (stash->funcinfo_hash_table, sym, addr, - filename_ptr, linenumber_ptr); - return info_hash_lookup_varinfo (stash->varinfo_hash_table, sym, addr, - filename_ptr, linenumber_ptr); -} - -/* Save current section VMAs. */ - -static bfd_boolean -save_section_vma (const bfd *abfd, struct dwarf2_debug *stash) -{ - asection *s; - unsigned int i; - - if (abfd->section_count == 0) - return TRUE; - stash->sec_vma = bfd_malloc (sizeof (*stash->sec_vma) * abfd->section_count); - if (stash->sec_vma == NULL) - return FALSE; - for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next) - { - if (s->output_section != NULL) - stash->sec_vma[i] = s->output_section->vma + s->output_offset; - else - stash->sec_vma[i] = s->vma; - } - return TRUE; -} - -/* Compare current section VMAs against those at the time the stash - was created. If find_nearest_line is used in linker warnings or - errors early in the link process, the debug info stash will be - invalid for later calls. This is because we relocate debug info - sections, so the stashed section contents depend on symbol values, - which in turn depend on section VMAs. */ - -static bfd_boolean -section_vma_same (const bfd *abfd, const struct dwarf2_debug *stash) -{ - asection *s; - unsigned int i; - - for (i = 0, s = abfd->sections; i < abfd->section_count; i++, s = s->next) - { - bfd_vma vma; - - if (s->output_section != NULL) - vma = s->output_section->vma + s->output_offset; - else - vma = s->vma; - if (vma != stash->sec_vma[i]) - return FALSE; - } - return TRUE; -} - -/* Read debug information from DEBUG_BFD when DEBUG_BFD is specified. - If DEBUG_BFD is not specified, we read debug information from ABFD - or its gnu_debuglink. The results will be stored in PINFO. - The function returns TRUE iff debug information is ready. */ - -bfd_boolean -_bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, - const struct dwarf_debug_section *debug_sections, - asymbol **symbols, - void **pinfo, - bfd_boolean do_place) -{ - bfd_size_type amt = sizeof (struct dwarf2_debug); - bfd_size_type total_size; - asection *msec; - struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; - - if (stash != NULL) - { - if (stash->orig_bfd == abfd - && section_vma_same (abfd, stash)) - { - /* Check that we did previously find some debug information - before attempting to make use of it. */ - if (stash->bfd_ptr != NULL) - { - if (do_place && !place_sections (abfd, stash)) - return FALSE; - return TRUE; - } - - return FALSE; - } - _bfd_dwarf2_cleanup_debug_info (abfd, pinfo); - memset (stash, 0, amt); - } - else - { - stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt); - if (! stash) - return FALSE; - } - stash->orig_bfd = abfd; - stash->debug_sections = debug_sections; - stash->syms = symbols; - if (!save_section_vma (abfd, stash)) - return FALSE; - - *pinfo = stash; - - if (debug_bfd == NULL) - debug_bfd = abfd; - - msec = find_debug_info (debug_bfd, debug_sections, NULL); - if (msec == NULL && abfd == debug_bfd) - { - char * debug_filename; - - debug_filename = bfd_follow_build_id_debuglink (abfd, DEBUGDIR); - if (debug_filename == NULL) - debug_filename = bfd_follow_gnu_debuglink (abfd, DEBUGDIR); - - if (debug_filename == NULL) - /* No dwarf2 info, and no gnu_debuglink to follow. - Note that at this point the stash has been allocated, but - contains zeros. This lets future calls to this function - fail more quickly. */ - return FALSE; - - /* Set BFD_DECOMPRESS to decompress debug sections. */ - if ((debug_bfd = bfd_openr (debug_filename, NULL)) == NULL - || !(debug_bfd->flags |= BFD_DECOMPRESS, - bfd_check_format (debug_bfd, bfd_object)) - || (msec = find_debug_info (debug_bfd, - debug_sections, NULL)) == NULL - || !bfd_generic_link_read_symbols (debug_bfd)) - { - if (debug_bfd) - bfd_close (debug_bfd); - /* FIXME: Should we report our failure to follow the debuglink ? */ - free (debug_filename); - return FALSE; - } - - symbols = bfd_get_outsymbols (debug_bfd); - stash->syms = symbols; - stash->close_on_cleanup = TRUE; - } - stash->bfd_ptr = debug_bfd; - - if (do_place - && !place_sections (abfd, stash)) - return FALSE; - - /* There can be more than one DWARF2 info section in a BFD these - days. First handle the easy case when there's only one. If - there's more than one, try case two: none of the sections is - compressed. In that case, 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, and 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.) If - some or all sections are compressed, then do things the slow - way, with a bunch of reallocs. */ - - if (! find_debug_info (debug_bfd, debug_sections, msec)) - { - /* Case 1: only one info section. */ - total_size = msec->size; - if (! read_section (debug_bfd, &stash->debug_sections[debug_info], - symbols, 0, - &stash->info_ptr_memory, &total_size)) - return FALSE; - } - else - { - /* Case 2: multiple sections. */ - for (total_size = 0; - msec; - msec = find_debug_info (debug_bfd, debug_sections, msec)) - total_size += msec->size; - - stash->info_ptr_memory = (bfd_byte *) bfd_malloc (total_size); - if (stash->info_ptr_memory == NULL) - return FALSE; - - total_size = 0; - for (msec = find_debug_info (debug_bfd, debug_sections, NULL); - msec; - msec = find_debug_info (debug_bfd, debug_sections, msec)) - { - bfd_size_type size; - - size = msec->size; - if (size == 0) - continue; - - if (!(bfd_simple_get_relocated_section_contents - (debug_bfd, msec, stash->info_ptr_memory + total_size, - symbols))) - return FALSE; - - total_size += size; - } - } - - stash->info_ptr = stash->info_ptr_memory; - stash->info_ptr_end = stash->info_ptr + total_size; - stash->sec = find_debug_info (debug_bfd, debug_sections, NULL); - stash->sec_info_ptr = stash->info_ptr; - return TRUE; -} - -/* Scan the debug information in PINFO looking for a DW_TAG_subprogram - abbrev with a DW_AT_low_pc attached to it. Then lookup that same - symbol in SYMBOLS and return the difference between the low_pc and - the symbol's address. Returns 0 if no suitable symbol could be found. */ - -bfd_signed_vma -_bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo) -{ - struct dwarf2_debug *stash; - struct comp_unit * unit; - - stash = (struct dwarf2_debug *) *pinfo; - - if (stash == NULL) - return 0; - - for (unit = stash->all_comp_units; unit; unit = unit->next_unit) - { - struct funcinfo * func; - - if (unit->function_table == NULL) - { - if (unit->line_table == NULL) - unit->line_table = decode_line_info (unit, stash); - if (unit->line_table != NULL) - scan_unit_for_symbols (unit); - } - - for (func = unit->function_table; func != NULL; func = func->prev_func) - if (func->name && func->arange.low) - { - asymbol ** psym; - - /* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */ - - for (psym = symbols; * psym != NULL; psym++) - { - asymbol * sym = * psym; - - if (sym->flags & BSF_FUNCTION - && sym->section != NULL - && strcmp (sym->name, func->name) == 0) - return ((bfd_signed_vma) func->arange.low) - - ((bfd_signed_vma) (sym->value + sym->section->vma)); - } - } - } - - return 0; -} - -/* Find the source code location of SYMBOL. If SYMBOL is NULL - then find the nearest source code location corresponding to - the address SECTION + OFFSET. - Returns TRUE if the line is found without error and fills in - FILENAME_PTR and LINENUMBER_PTR. In the case where SYMBOL was - NULL the FUNCTIONNAME_PTR is also filled in. - SYMBOLS contains the symbol table for ABFD. - DEBUG_SECTIONS contains the name of the dwarf debug sections. - ADDR_SIZE is the number of bytes in the initial .debug_info length - field and in the abbreviation offset, or zero to indicate that the - default value should be used. */ - -bfd_boolean -_bfd_dwarf2_find_nearest_line (bfd *abfd, - asymbol **symbols, - asymbol *symbol, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *linenumber_ptr, - unsigned int *discriminator_ptr, - const struct dwarf_debug_section *debug_sections, - unsigned int addr_size, - void **pinfo) -{ - /* Read each compilation unit from the section .debug_info, and check - to see if it contains the address we are searching for. If yes, - 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; - struct funcinfo *function = NULL; - bfd_boolean found = FALSE; - bfd_boolean do_line; - - *filename_ptr = NULL; - if (functionname_ptr != NULL) - *functionname_ptr = NULL; - *linenumber_ptr = 0; - if (discriminator_ptr) - *discriminator_ptr = 0; - - if (! _bfd_dwarf2_slurp_debug_info (abfd, NULL, debug_sections, - symbols, pinfo, - (abfd->flags & (EXEC_P | DYNAMIC)) == 0)) - return FALSE; - - stash = (struct dwarf2_debug *) *pinfo; - - do_line = symbol != NULL; - if (do_line) - { - BFD_ASSERT (section == NULL && offset == 0 && functionname_ptr == NULL); - section = bfd_get_section (symbol); - addr = symbol->value; - } - else - { - BFD_ASSERT (section != NULL && functionname_ptr != NULL); - addr = offset; - - /* If we have no SYMBOL but the section we're looking at is not a - code section, then take a look through the list of symbols to see - if we have a symbol at the address we're looking for. If we do - then use this to look up line information. This will allow us to - give file and line results for data symbols. We exclude code - symbols here, if we look up a function symbol and then look up the - line information we'll actually return the line number for the - opening '{' rather than the function definition line. This is - because looking up by symbol uses the line table, in which the - first line for a function is usually the opening '{', while - looking up the function by section + offset uses the - DW_AT_decl_line from the function DW_TAG_subprogram for the line, - which will be the line of the function name. */ - if (symbols != NULL && (section->flags & SEC_CODE) == 0) - { - asymbol **tmp; - - for (tmp = symbols; (*tmp) != NULL; ++tmp) - if ((*tmp)->the_bfd == abfd - && (*tmp)->section == section - && (*tmp)->value == offset - && ((*tmp)->flags & BSF_SECTION_SYM) == 0) - { - symbol = *tmp; - do_line = TRUE; - /* For local symbols, keep going in the hope we find a - global. */ - if ((symbol->flags & BSF_GLOBAL) != 0) - break; - } - } - } - - if (section->output_section) - addr += section->output_section->vma + section->output_offset; - else - addr += section->vma; - - /* A null info_ptr indicates that there is no dwarf2 info - (or that an error occured while setting up the stash). */ - if (! stash->info_ptr) - return FALSE; - - stash->inliner_chain = NULL; - - /* Check the previously read comp. units first. */ - if (do_line) - { - /* The info hash tables use quite a bit of memory. We may not want to - always use them. We use some heuristics to decide if and when to - turn it on. */ - if (stash->info_hash_status == STASH_INFO_HASH_OFF) - stash_maybe_enable_info_hash_tables (abfd, stash); - - /* Keep info hash table up to date if they are available. Note that we - may disable the hash tables if there is any error duing update. */ - if (stash->info_hash_status == STASH_INFO_HASH_ON) - stash_maybe_update_info_hash_tables (stash); - - if (stash->info_hash_status == STASH_INFO_HASH_ON) - { - found = stash_find_line_fast (stash, symbol, addr, filename_ptr, - linenumber_ptr); - if (found) - goto done; - } - else - { - /* Check the previously read comp. units first. */ - for (each = stash->all_comp_units; each; each = each->next_unit) - if ((symbol->flags & BSF_FUNCTION) == 0 - || each->arange.high == 0 - || comp_unit_contains_address (each, addr)) - { - found = comp_unit_find_line (each, symbol, addr, filename_ptr, - linenumber_ptr, stash); - if (found) - goto done; - } - } - } - else - { - bfd_vma min_range = (bfd_vma) -1; - const char * local_filename = NULL; - struct funcinfo *local_function = NULL; - unsigned int local_linenumber = 0; - unsigned int local_discriminator = 0; - - for (each = stash->all_comp_units; each; each = each->next_unit) - { - bfd_vma range = (bfd_vma) -1; - - found = ((each->arange.high == 0 - || comp_unit_contains_address (each, addr)) - && (range = comp_unit_find_nearest_line (each, addr, - & local_filename, - & local_function, - & local_linenumber, - & local_discriminator, - stash)) != 0); - if (found) - { - /* PRs 15935 15994: Bogus debug information may have provided us - with an erroneous match. We attempt to counter this by - selecting the match that has the smallest address range - associated with it. (We are assuming that corrupt debug info - will tend to result in extra large address ranges rather than - extra small ranges). - - This does mean that we scan through all of the CUs associated - with the bfd each time this function is called. But this does - have the benefit of producing consistent results every time the - function is called. */ - if (range <= min_range) - { - if (filename_ptr && local_filename) - * filename_ptr = local_filename; - if (local_function) - function = local_function; - if (discriminator_ptr && local_discriminator) - * discriminator_ptr = local_discriminator; - if (local_linenumber) - * linenumber_ptr = local_linenumber; - min_range = range; - } - } - } - - if (* linenumber_ptr) - { - found = TRUE; - goto done; - } - } - - /* 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 (stash->bfd_ptr, stash->info_ptr, stash->info_ptr_end); - /* A 0xffffff length is the DWARF3 way of indicating - we use 64-bit offsets, instead of 32-bit offsets. */ - if (length == 0xffffffff) - { - offset_size = 8; - length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end); - 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 (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end); - stash->info_ptr += 8; - } - /* In the absence of the hints above, we assume 32-bit DWARF2 - offsets even for targets with 64-bit addresses, because: - a) most of the time these targets will not have generated - more than 2Gb of debug info and so will not need 64-bit - offsets, - and - b) if they do use 64-bit offsets but they are not using - the size hints that are tested for above then they are - not conforming to the DWARF3 standard anyway. */ - else if (addr_size == 8) - { - offset_size = 4; - stash->info_ptr += 4; - } - else - stash->info_ptr += 4; - - if (length > 0) - { - bfd_byte * new_ptr; - - /* PR 21151 */ - if (stash->info_ptr + length > stash->info_ptr_end) - return FALSE; - - each = parse_comp_unit (stash, length, info_ptr_unit, - offset_size); - if (!each) - /* The dwarf information is damaged, don't trust it any - more. */ - break; - - new_ptr = stash->info_ptr + length; - /* PR 17512: file: 1500698c. */ - if (new_ptr < stash->info_ptr) - { - /* A corrupt length value - do not trust the info any more. */ - found = FALSE; - break; - } - else - stash->info_ptr = new_ptr; - - if (stash->all_comp_units) - stash->all_comp_units->prev_unit = each; - else - stash->last_comp_unit = 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 (do_line) - 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)); - else - found = ((each->arange.high == 0 - || comp_unit_contains_address (each, addr)) - && comp_unit_find_nearest_line (each, addr, - filename_ptr, - &function, - linenumber_ptr, - discriminator_ptr, - stash) != 0); - - if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) - == stash->sec->size) - { - stash->sec = find_debug_info (stash->bfd_ptr, debug_sections, - stash->sec); - stash->sec_info_ptr = stash->info_ptr; - } - - if (found) - goto done; - } - } - - done: - if (function) - { - if (!function->is_linkage) - { - asymbol *fun; - bfd_vma sec_vma; - - fun = _bfd_elf_find_function (abfd, symbols, section, offset, - *filename_ptr ? NULL : filename_ptr, - functionname_ptr); - sec_vma = section->vma; - if (section->output_section != NULL) - sec_vma = section->output_section->vma + section->output_offset; - if (fun != NULL - && fun->value + sec_vma == function->arange.low) - function->name = *functionname_ptr; - /* Even if we didn't find a linkage name, say that we have - to stop a repeated search of symbols. */ - function->is_linkage = TRUE; - } - *functionname_ptr = function->name; - } - 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 = (struct dwarf2_debug *) *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, void **pinfo) -{ - struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; - struct comp_unit *each; - - if (abfd == NULL || stash == NULL) - return; - - for (each = stash->all_comp_units; each; each = each->next_unit) - { - struct abbrev_info **abbrevs = each->abbrevs; - struct funcinfo *function_table = each->function_table; - struct varinfo *variable_table = each->variable_table; - 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); - } - - while (function_table) - { - if (function_table->file) - { - free (function_table->file); - function_table->file = NULL; - } - - if (function_table->caller_file) - { - free (function_table->caller_file); - function_table->caller_file = NULL; - } - function_table = function_table->prev_func; - } - - if (each->lookup_funcinfo_table) - { - free (each->lookup_funcinfo_table); - each->lookup_funcinfo_table = NULL; - } - - while (variable_table) - { - if (variable_table->file) - { - free (variable_table->file); - variable_table->file = NULL; - } - - variable_table = variable_table->prev_var; - } - } - - if (stash->funcinfo_hash_table) - bfd_hash_table_free (&stash->funcinfo_hash_table->base); - if (stash->varinfo_hash_table) - bfd_hash_table_free (&stash->varinfo_hash_table->base); - if (stash->dwarf_abbrev_buffer) - free (stash->dwarf_abbrev_buffer); - if (stash->dwarf_line_buffer) - free (stash->dwarf_line_buffer); - if (stash->dwarf_str_buffer) - free (stash->dwarf_str_buffer); - if (stash->dwarf_line_str_buffer) - free (stash->dwarf_line_str_buffer); - if (stash->dwarf_ranges_buffer) - free (stash->dwarf_ranges_buffer); - if (stash->info_ptr_memory) - free (stash->info_ptr_memory); - if (stash->close_on_cleanup) - bfd_close (stash->bfd_ptr); - if (stash->alt_dwarf_str_buffer) - free (stash->alt_dwarf_str_buffer); - if (stash->alt_dwarf_info_buffer) - free (stash->alt_dwarf_info_buffer); - if (stash->sec_vma) - free (stash->sec_vma); - if (stash->adjusted_sections) - free (stash->adjusted_sections); - if (stash->alt_bfd_ptr) - bfd_close (stash->alt_bfd_ptr); -} - -/* Find the function to a particular section and offset, - for error reporting. */ - -asymbol * -_bfd_elf_find_function (bfd *abfd, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr) -{ - struct elf_find_function_cache - { - asection *last_section; - asymbol *func; - const char *filename; - bfd_size_type func_size; - } *cache; - - if (symbols == NULL) - return NULL; - - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - return NULL; - - cache = elf_tdata (abfd)->elf_find_function_cache; - if (cache == NULL) - { - cache = bfd_zalloc (abfd, sizeof (*cache)); - elf_tdata (abfd)->elf_find_function_cache = cache; - if (cache == NULL) - return NULL; - } - if (cache->last_section != section - || cache->func == NULL - || offset < cache->func->value - || offset >= cache->func->value + cache->func_size) - { - asymbol *file; - bfd_vma low_func; - asymbol **p; - /* ??? Given multiple file symbols, it is impossible to reliably - choose the right file name for global symbols. File symbols are - local symbols, and thus all file symbols must sort before any - global symbols. The ELF spec may be interpreted to say that a - file symbol must sort before other local symbols, but currently - ld -r doesn't do this. So, for ld -r output, it is possible to - make a better choice of file name for local symbols by ignoring - file symbols appearing after a given local symbol. */ - enum { nothing_seen, symbol_seen, file_after_symbol_seen } state; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - file = NULL; - low_func = 0; - state = nothing_seen; - cache->filename = NULL; - cache->func = NULL; - cache->func_size = 0; - cache->last_section = section; - - for (p = symbols; *p != NULL; p++) - { - asymbol *sym = *p; - bfd_vma code_off; - bfd_size_type size; - - if ((sym->flags & BSF_FILE) != 0) - { - file = sym; - if (state == symbol_seen) - state = file_after_symbol_seen; - continue; - } - - size = bed->maybe_function_sym (sym, section, &code_off); - if (size != 0 - && code_off <= offset - && (code_off > low_func - || (code_off == low_func - && size > cache->func_size))) - { - cache->func = sym; - cache->func_size = size; - cache->filename = NULL; - low_func = code_off; - if (file != NULL - && ((sym->flags & BSF_LOCAL) != 0 - || state != file_after_symbol_seen)) - cache->filename = bfd_asymbol_name (file); - } - if (state == nothing_seen) - state = symbol_seen; - } - } - - if (cache->func == NULL) - return NULL; - - if (filename_ptr) - *filename_ptr = cache->filename; - if (functionname_ptr) - *functionname_ptr = bfd_asymbol_name (cache->func); - - return cache->func; -} diff --git a/sdcc/support/sdbinutils/bfd/ecoff.c b/sdcc/support/sdbinutils/bfd/ecoff.c deleted file mode 100644 index e9d1eaeb8..000000000 --- a/sdcc/support/sdbinutils/bfd/ecoff.c +++ /dev/null @@ -1,4476 +0,0 @@ -/* Generic ECOFF (Extended-COFF) routines. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Original version by Per Bothner. - Full support added by Ian Lance Taylor, ian@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "aout/ar.h" -#include "aout/stab_gnu.h" - -/* FIXME: We need the definitions of N_SET[ADTB], but aout64.h defines - some other stuff which we don't want and which conflicts with stuff - we do want. */ -#include "libaout.h" -#include "aout/aout64.h" -#undef N_ABS -#undef exec_hdr -#undef obj_sym_filepos - -#include "coff/internal.h" -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/ecoff.h" -#include "libcoff.h" -#include "libecoff.h" -#include "libiberty.h" - -#define streq(a, b) (strcmp ((a), (b)) == 0) -#define strneq(a, b, n) (strncmp ((a), (b), (n)) == 0) - - -/* This stuff is somewhat copied from coffcode.h. */ -static asection bfd_debug_section = -{ - /* name, id, index, next, prev, flags, user_set_vma, */ - "*DEBUG*", 0, 0, NULL, NULL, 0, 0, - /* linker_mark, linker_has_input, gc_mark, compress_status, */ - 0, 0, 1, 0, - /* segment_mark, sec_info_type, use_rela_p, */ - 0, 0, 0, - /* sec_flg0, sec_flg1, sec_flg2, sec_flg3, sec_flg4, sec_flg5, */ - 0, 0, 0, 0, 0, 0, - /* vma, lma, size, rawsize, compressed_size, relax, relax_count, */ - 0, 0, 0, 0, 0, 0, 0, - /* output_offset, output_section, alignment_power, */ - 0, NULL, 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, */ - NULL, - /* symbol_ptr_ptr, */ - NULL, - /* map_head, map_tail */ - { NULL }, { NULL } -}; - -/* Create an ECOFF object. */ - -bfd_boolean -_bfd_ecoff_mkobject (bfd *abfd) -{ - bfd_size_type amt = sizeof (ecoff_data_type); - - abfd->tdata.ecoff_obj_data = (struct ecoff_tdata *) bfd_zalloc (abfd, amt); - if (abfd->tdata.ecoff_obj_data == NULL) - return FALSE; - - return TRUE; -} - -/* This is a hook called by coff_real_object_p to create any backend - specific information. */ - -void * -_bfd_ecoff_mkobject_hook (bfd *abfd, void * filehdr, void * aouthdr) -{ - struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; - struct internal_aouthdr *internal_a = (struct internal_aouthdr *) aouthdr; - ecoff_data_type *ecoff; - - if (! _bfd_ecoff_mkobject (abfd)) - return NULL; - - ecoff = ecoff_data (abfd); - ecoff->gp_size = 8; - ecoff->sym_filepos = internal_f->f_symptr; - - if (internal_a != NULL) - { - int i; - - ecoff->text_start = internal_a->text_start; - ecoff->text_end = internal_a->text_start + internal_a->tsize; - ecoff->gp = internal_a->gp_value; - ecoff->gprmask = internal_a->gprmask; - for (i = 0; i < 4; i++) - ecoff->cprmask[i] = internal_a->cprmask[i]; - ecoff->fprmask = internal_a->fprmask; - if (internal_a->magic == ECOFF_AOUT_ZMAGIC) - abfd->flags |= D_PAGED; - else - abfd->flags &=~ D_PAGED; - } - - /* It turns out that no special action is required by the MIPS or - Alpha ECOFF backends. They have different information in the - a.out header, but we just copy it all (e.g., gprmask, cprmask and - fprmask) and let the swapping routines ensure that only relevant - information is written out. */ - - return (void *) ecoff; -} - -/* Initialize a new section. */ - -bfd_boolean -_bfd_ecoff_new_section_hook (bfd *abfd, asection *section) -{ - unsigned int i; - static struct - { - const char * name; - flagword flags; - } - section_flags [] = - { - { _TEXT, SEC_ALLOC | SEC_CODE | SEC_LOAD }, - { _INIT, SEC_ALLOC | SEC_CODE | SEC_LOAD }, - { _FINI, SEC_ALLOC | SEC_CODE | SEC_LOAD }, - { _DATA, SEC_ALLOC | SEC_DATA | SEC_LOAD }, - { _SDATA, SEC_ALLOC | SEC_DATA | SEC_LOAD }, - { _RDATA, SEC_ALLOC | SEC_DATA | SEC_LOAD | SEC_READONLY}, - { _LIT8, SEC_ALLOC | SEC_DATA | SEC_LOAD | SEC_READONLY}, - { _LIT4, SEC_ALLOC | SEC_DATA | SEC_LOAD | SEC_READONLY}, - { _RCONST, SEC_ALLOC | SEC_DATA | SEC_LOAD | SEC_READONLY}, - { _PDATA, SEC_ALLOC | SEC_DATA | SEC_LOAD | SEC_READONLY}, - { _BSS, SEC_ALLOC}, - { _SBSS, SEC_ALLOC}, - /* An Irix 4 shared libary. */ - { _LIB, SEC_COFF_SHARED_LIBRARY} - }; - - section->alignment_power = 4; - - for (i = 0; i < ARRAY_SIZE (section_flags); i++) - if (streq (section->name, section_flags[i].name)) - { - section->flags |= section_flags[i].flags; - break; - } - - - /* Probably any other section name is SEC_NEVER_LOAD, but I'm - uncertain about .init on some systems and I don't know how shared - libraries work. */ - - return _bfd_generic_new_section_hook (abfd, section); -} - -/* Determine the machine architecture and type. This is called from - the generic COFF routines. It is the inverse of ecoff_get_magic, - below. This could be an ECOFF backend routine, with one version - for each target, but there aren't all that many ECOFF targets. */ - -bfd_boolean -_bfd_ecoff_set_arch_mach_hook (bfd *abfd, void * filehdr) -{ - struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; - enum bfd_architecture arch; - unsigned long mach; - - switch (internal_f->f_magic) - { - case MIPS_MAGIC_1: - case MIPS_MAGIC_LITTLE: - case MIPS_MAGIC_BIG: - arch = bfd_arch_mips; - mach = bfd_mach_mips3000; - break; - - case MIPS_MAGIC_LITTLE2: - case MIPS_MAGIC_BIG2: - /* MIPS ISA level 2: the r6000. */ - arch = bfd_arch_mips; - mach = bfd_mach_mips6000; - break; - - case MIPS_MAGIC_LITTLE3: - case MIPS_MAGIC_BIG3: - /* MIPS ISA level 3: the r4000. */ - arch = bfd_arch_mips; - mach = bfd_mach_mips4000; - break; - - case ALPHA_MAGIC: - arch = bfd_arch_alpha; - mach = 0; - break; - - default: - arch = bfd_arch_obscure; - mach = 0; - break; - } - - return bfd_default_set_arch_mach (abfd, arch, mach); -} - -bfd_boolean -_bfd_ecoff_no_long_sections (bfd *abfd, int enable) -{ - (void) abfd; - (void) enable; - return FALSE; -} - -/* Get the magic number to use based on the architecture and machine. - This is the inverse of _bfd_ecoff_set_arch_mach_hook, above. */ - -static int -ecoff_get_magic (bfd *abfd) -{ - int big, little; - - switch (bfd_get_arch (abfd)) - { - case bfd_arch_mips: - switch (bfd_get_mach (abfd)) - { - default: - case 0: - case bfd_mach_mips3000: - big = MIPS_MAGIC_BIG; - little = MIPS_MAGIC_LITTLE; - break; - - case bfd_mach_mips6000: - big = MIPS_MAGIC_BIG2; - little = MIPS_MAGIC_LITTLE2; - break; - - case bfd_mach_mips4000: - big = MIPS_MAGIC_BIG3; - little = MIPS_MAGIC_LITTLE3; - break; - } - - return bfd_big_endian (abfd) ? big : little; - - case bfd_arch_alpha: - return ALPHA_MAGIC; - - default: - abort (); - return 0; - } -} - -/* Get the section s_flags to use for a section. */ - -static long -ecoff_sec_to_styp_flags (const char *name, flagword flags) -{ - unsigned int i; - static struct - { - const char * name; - long flags; - } - styp_flags [] = - { - { _TEXT, STYP_TEXT }, - { _DATA, STYP_DATA }, - { _SDATA, STYP_SDATA }, - { _RDATA, STYP_RDATA }, - { _LITA, STYP_LITA }, - { _LIT8, STYP_LIT8 }, - { _LIT4, STYP_LIT4 }, - { _BSS, STYP_BSS }, - { _SBSS, STYP_SBSS }, - { _INIT, STYP_ECOFF_INIT }, - { _FINI, STYP_ECOFF_FINI }, - { _PDATA, STYP_PDATA }, - { _XDATA, STYP_XDATA }, - { _LIB, STYP_ECOFF_LIB }, - { _GOT, STYP_GOT }, - { _HASH, STYP_HASH }, - { _DYNAMIC, STYP_DYNAMIC }, - { _LIBLIST, STYP_LIBLIST }, - { _RELDYN, STYP_RELDYN }, - { _CONFLIC, STYP_CONFLIC }, - { _DYNSTR, STYP_DYNSTR }, - { _DYNSYM, STYP_DYNSYM }, - { _RCONST, STYP_RCONST } - }; - long styp = 0; - - for (i = 0; i < ARRAY_SIZE (styp_flags); i++) - if (streq (name, styp_flags[i].name)) - { - styp = styp_flags[i].flags; - break; - } - - if (styp == 0) - { - if (streq (name, _COMMENT)) - { - styp = STYP_COMMENT; - flags &=~ SEC_NEVER_LOAD; - } - else if (flags & SEC_CODE) - styp = STYP_TEXT; - else if (flags & SEC_DATA) - styp = STYP_DATA; - else if (flags & SEC_READONLY) - styp = STYP_RDATA; - else if (flags & SEC_LOAD) - styp = STYP_REG; - else - styp = STYP_BSS; - } - - if (flags & SEC_NEVER_LOAD) - styp |= STYP_NOLOAD; - - return styp; -} - -/* Get the BFD flags to use for a section. */ - -bfd_boolean -_bfd_ecoff_styp_to_sec_flags (bfd *abfd ATTRIBUTE_UNUSED, - void * hdr, - const char *name ATTRIBUTE_UNUSED, - asection *section ATTRIBUTE_UNUSED, - flagword * flags_ptr) -{ - struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; - long styp_flags = internal_s->s_flags; - flagword sec_flags = 0; - - if (styp_flags & STYP_NOLOAD) - sec_flags |= SEC_NEVER_LOAD; - - /* For 386 COFF, at least, an unloadable text or data section is - actually a shared library section. */ - if ((styp_flags & STYP_TEXT) - || (styp_flags & STYP_ECOFF_INIT) - || (styp_flags & STYP_ECOFF_FINI) - || (styp_flags & STYP_DYNAMIC) - || (styp_flags & STYP_LIBLIST) - || (styp_flags & STYP_RELDYN) - || styp_flags == STYP_CONFLIC - || (styp_flags & STYP_DYNSTR) - || (styp_flags & STYP_DYNSYM) - || (styp_flags & STYP_HASH)) - { - if (sec_flags & SEC_NEVER_LOAD) - sec_flags |= SEC_CODE | SEC_COFF_SHARED_LIBRARY; - else - sec_flags |= SEC_CODE | SEC_LOAD | SEC_ALLOC; - } - else if ((styp_flags & STYP_DATA) - || (styp_flags & STYP_RDATA) - || (styp_flags & STYP_SDATA) - || styp_flags == STYP_PDATA - || styp_flags == STYP_XDATA - || (styp_flags & STYP_GOT) - || styp_flags == STYP_RCONST) - { - if (sec_flags & SEC_NEVER_LOAD) - sec_flags |= SEC_DATA | SEC_COFF_SHARED_LIBRARY; - else - sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC; - if ((styp_flags & STYP_RDATA) - || styp_flags == STYP_PDATA - || styp_flags == STYP_RCONST) - sec_flags |= SEC_READONLY; - } - else if ((styp_flags & STYP_BSS) - || (styp_flags & STYP_SBSS)) - sec_flags |= SEC_ALLOC; - else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT) - sec_flags |= SEC_NEVER_LOAD; - else if ((styp_flags & STYP_LITA) - || (styp_flags & STYP_LIT8) - || (styp_flags & STYP_LIT4)) - sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC | SEC_READONLY; - else if (styp_flags & STYP_ECOFF_LIB) - sec_flags |= SEC_COFF_SHARED_LIBRARY; - else - sec_flags |= SEC_ALLOC | SEC_LOAD; - - * flags_ptr = sec_flags; - return TRUE; -} - -/* Read in the symbolic header for an ECOFF object file. */ - -static bfd_boolean -ecoff_slurp_symbolic_header (bfd *abfd) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - bfd_size_type external_hdr_size; - void * raw = NULL; - HDRR *internal_symhdr; - - /* See if we've already read it in. */ - if (ecoff_data (abfd)->debug_info.symbolic_header.magic == - backend->debug_swap.sym_magic) - return TRUE; - - /* See whether there is a symbolic header. */ - if (ecoff_data (abfd)->sym_filepos == 0) - { - bfd_get_symcount (abfd) = 0; - return TRUE; - } - - /* At this point bfd_get_symcount (abfd) holds the number of symbols - as read from the file header, but on ECOFF this is always the - size of the symbolic information header. It would be cleaner to - handle this when we first read the file in coffgen.c. */ - external_hdr_size = backend->debug_swap.external_hdr_size; - if (bfd_get_symcount (abfd) != external_hdr_size) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Read the symbolic information header. */ - raw = bfd_malloc (external_hdr_size); - if (raw == NULL) - goto error_return; - - if (bfd_seek (abfd, ecoff_data (abfd)->sym_filepos, SEEK_SET) != 0 - || bfd_bread (raw, external_hdr_size, abfd) != external_hdr_size) - goto error_return; - internal_symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; - (*backend->debug_swap.swap_hdr_in) (abfd, raw, internal_symhdr); - - if (internal_symhdr->magic != backend->debug_swap.sym_magic) - { - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - - /* Now we can get the correct number of symbols. */ - bfd_get_symcount (abfd) = (internal_symhdr->isymMax - + internal_symhdr->iextMax); - - if (raw != NULL) - free (raw); - return TRUE; - error_return: - if (raw != NULL) - free (raw); - return FALSE; -} - -/* Read in and swap the important symbolic information for an ECOFF - object file. This is called by gdb via the read_debug_info entry - point in the backend structure. */ - -bfd_boolean -_bfd_ecoff_slurp_symbolic_info (bfd *abfd, - asection *ignore ATTRIBUTE_UNUSED, - struct ecoff_debug_info *debug) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - HDRR *internal_symhdr; - bfd_size_type raw_base; - bfd_size_type raw_size; - void * raw; - bfd_size_type external_fdr_size; - char *fraw_src; - char *fraw_end; - struct fdr *fdr_ptr; - bfd_size_type raw_end; - bfd_size_type cb_end; - file_ptr pos; - - BFD_ASSERT (debug == &ecoff_data (abfd)->debug_info); - - /* Check whether we've already gotten it, and whether there's any to - get. */ - if (ecoff_data (abfd)->raw_syments != NULL) - return TRUE; - if (ecoff_data (abfd)->sym_filepos == 0) - { - bfd_get_symcount (abfd) = 0; - return TRUE; - } - - if (! ecoff_slurp_symbolic_header (abfd)) - return FALSE; - - internal_symhdr = &debug->symbolic_header; - - /* Read all the symbolic information at once. */ - raw_base = (ecoff_data (abfd)->sym_filepos - + backend->debug_swap.external_hdr_size); - - /* Alpha ecoff makes the determination of raw_size difficult. It has - an undocumented debug data section between the symhdr and the first - documented section. And the ordering of the sections varies between - statically and dynamically linked executables. - If bfd supports SEEK_END someday, this code could be simplified. */ - raw_end = 0; - -#define UPDATE_RAW_END(start, count, size) \ - cb_end = internal_symhdr->start + internal_symhdr->count * (size); \ - if (cb_end > raw_end) \ - raw_end = cb_end - - UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char)); - UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size); - UPDATE_RAW_END (cbPdOffset, ipdMax, backend->debug_swap.external_pdr_size); - UPDATE_RAW_END (cbSymOffset, isymMax, backend->debug_swap.external_sym_size); - /* eraxxon@alumni.rice.edu: ioptMax refers to the size of the - optimization symtab, not the number of entries. */ - UPDATE_RAW_END (cbOptOffset, ioptMax, sizeof (char)); - UPDATE_RAW_END (cbAuxOffset, iauxMax, sizeof (union aux_ext)); - UPDATE_RAW_END (cbSsOffset, issMax, sizeof (char)); - UPDATE_RAW_END (cbSsExtOffset, issExtMax, sizeof (char)); - UPDATE_RAW_END (cbFdOffset, ifdMax, backend->debug_swap.external_fdr_size); - UPDATE_RAW_END (cbRfdOffset, crfd, backend->debug_swap.external_rfd_size); - UPDATE_RAW_END (cbExtOffset, iextMax, backend->debug_swap.external_ext_size); - -#undef UPDATE_RAW_END - - raw_size = raw_end - raw_base; - if (raw_size == 0) - { - ecoff_data (abfd)->sym_filepos = 0; - return TRUE; - } - raw = bfd_alloc (abfd, raw_size); - if (raw == NULL) - return FALSE; - - pos = ecoff_data (abfd)->sym_filepos; - pos += backend->debug_swap.external_hdr_size; - if (bfd_seek (abfd, pos, SEEK_SET) != 0 - || bfd_bread (raw, raw_size, abfd) != raw_size) - { - bfd_release (abfd, raw); - return FALSE; - } - - ecoff_data (abfd)->raw_syments = raw; - - /* Get pointers for the numeric offsets in the HDRR structure. */ -#define FIX(off1, off2, type) \ - if (internal_symhdr->off1 == 0) \ - debug->off2 = NULL; \ - else \ - debug->off2 = (type) ((char *) raw \ - + (internal_symhdr->off1 \ - - raw_base)) - - FIX (cbLineOffset, line, unsigned char *); - FIX (cbDnOffset, external_dnr, void *); - FIX (cbPdOffset, external_pdr, void *); - FIX (cbSymOffset, external_sym, void *); - FIX (cbOptOffset, external_opt, void *); - FIX (cbAuxOffset, external_aux, union aux_ext *); - FIX (cbSsOffset, ss, char *); - FIX (cbSsExtOffset, ssext, char *); - FIX (cbFdOffset, external_fdr, void *); - FIX (cbRfdOffset, external_rfd, void *); - FIX (cbExtOffset, external_ext, void *); -#undef FIX - - /* I don't want to always swap all the data, because it will just - waste time and most programs will never look at it. The only - time the linker needs most of the debugging information swapped - is when linking big-endian and little-endian MIPS object files - together, which is not a common occurrence. - - We need to look at the fdr to deal with a lot of information in - the symbols, so we swap them here. */ - debug->fdr = (FDR *) bfd_alloc2 (abfd, internal_symhdr->ifdMax, - sizeof (struct fdr)); - if (debug->fdr == NULL) - return FALSE; - external_fdr_size = backend->debug_swap.external_fdr_size; - fdr_ptr = debug->fdr; - fraw_src = (char *) debug->external_fdr; - /* PR 17512: file: 3372-1243-0.004. */ - if (fraw_src == NULL && internal_symhdr->ifdMax > 0) - return FALSE; - fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size; - for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) - (*backend->debug_swap.swap_fdr_in) (abfd, (void *) fraw_src, fdr_ptr); - - return TRUE; -} - -/* ECOFF symbol table routines. The ECOFF symbol table is described - in gcc/mips-tfile.c. */ - -/* ECOFF uses two common sections. One is the usual one, and the - other is for small objects. All the small objects are kept - together, and then referenced via the gp pointer, which yields - faster assembler code. This is what we use for the small common - section. */ -static asection ecoff_scom_section; -static asymbol ecoff_scom_symbol; -static asymbol *ecoff_scom_symbol_ptr; - -/* Create an empty symbol. */ - -asymbol * -_bfd_ecoff_make_empty_symbol (bfd *abfd) -{ - ecoff_symbol_type *new_symbol; - bfd_size_type amt = sizeof (ecoff_symbol_type); - - new_symbol = (ecoff_symbol_type *) bfd_zalloc (abfd, amt); - if (new_symbol == NULL) - return NULL; - new_symbol->symbol.section = NULL; - new_symbol->fdr = NULL; - new_symbol->local = FALSE; - new_symbol->native = NULL; - new_symbol->symbol.the_bfd = abfd; - return &new_symbol->symbol; -} - -/* Set the BFD flags and section for an ECOFF symbol. */ - -static bfd_boolean -ecoff_set_symbol_info (bfd *abfd, - SYMR *ecoff_sym, - asymbol *asym, - int ext, - int weak) -{ - asym->the_bfd = abfd; - asym->value = ecoff_sym->value; - asym->section = &bfd_debug_section; - asym->udata.i = 0; - - /* Most symbol types are just for debugging. */ - switch (ecoff_sym->st) - { - case stGlobal: - case stStatic: - case stLabel: - case stProc: - case stStaticProc: - break; - case stNil: - if (ECOFF_IS_STAB (ecoff_sym)) - { - asym->flags = BSF_DEBUGGING; - return TRUE; - } - break; - default: - asym->flags = BSF_DEBUGGING; - return TRUE; - } - - if (weak) - asym->flags = BSF_EXPORT | BSF_WEAK; - else if (ext) - asym->flags = BSF_EXPORT | BSF_GLOBAL; - else - { - asym->flags = BSF_LOCAL; - /* Normally, a local stProc symbol will have a corresponding - external symbol. We mark the local symbol as a debugging - symbol, in order to prevent nm from printing both out. - Similarly, we mark stLabel and stabs symbols as debugging - symbols. In both cases, we do want to set the value - correctly based on the symbol class. */ - if (ecoff_sym->st == stProc - || ecoff_sym->st == stLabel - || ECOFF_IS_STAB (ecoff_sym)) - asym->flags |= BSF_DEBUGGING; - } - - if (ecoff_sym->st == stProc || ecoff_sym->st == stStaticProc) - asym->flags |= BSF_FUNCTION; - - switch (ecoff_sym->sc) - { - case scNil: - /* Used for compiler generated labels. Leave them in the - debugging section, and mark them as local. If BSF_DEBUGGING - is set, then nm does not display them for some reason. If no - flags are set then the linker whines about them. */ - asym->flags = BSF_LOCAL; - break; - case scText: - asym->section = bfd_make_section_old_way (abfd, _TEXT); - asym->value -= asym->section->vma; - break; - case scData: - asym->section = bfd_make_section_old_way (abfd, _DATA); - asym->value -= asym->section->vma; - break; - case scBss: - asym->section = bfd_make_section_old_way (abfd, _BSS); - asym->value -= asym->section->vma; - break; - case scRegister: - asym->flags = BSF_DEBUGGING; - break; - case scAbs: - asym->section = bfd_abs_section_ptr; - break; - case scUndefined: - asym->section = bfd_und_section_ptr; - asym->flags = 0; - asym->value = 0; - break; - case scCdbLocal: - case scBits: - case scCdbSystem: - case scRegImage: - case scInfo: - case scUserStruct: - asym->flags = BSF_DEBUGGING; - break; - case scSData: - asym->section = bfd_make_section_old_way (abfd, ".sdata"); - asym->value -= asym->section->vma; - break; - case scSBss: - asym->section = bfd_make_section_old_way (abfd, ".sbss"); - asym->value -= asym->section->vma; - break; - case scRData: - asym->section = bfd_make_section_old_way (abfd, ".rdata"); - asym->value -= asym->section->vma; - break; - case scVar: - asym->flags = BSF_DEBUGGING; - break; - case scCommon: - if (asym->value > ecoff_data (abfd)->gp_size) - { - asym->section = bfd_com_section_ptr; - asym->flags = 0; - break; - } - /* Fall through. */ - case scSCommon: - if (ecoff_scom_section.name == NULL) - { - /* Initialize the small common section. */ - ecoff_scom_section.name = SCOMMON; - ecoff_scom_section.flags = SEC_IS_COMMON; - ecoff_scom_section.output_section = &ecoff_scom_section; - ecoff_scom_section.symbol = &ecoff_scom_symbol; - ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; - ecoff_scom_symbol.name = SCOMMON; - ecoff_scom_symbol.flags = BSF_SECTION_SYM; - ecoff_scom_symbol.section = &ecoff_scom_section; - ecoff_scom_symbol_ptr = &ecoff_scom_symbol; - } - asym->section = &ecoff_scom_section; - asym->flags = 0; - break; - case scVarRegister: - case scVariant: - asym->flags = BSF_DEBUGGING; - break; - case scSUndefined: - asym->section = bfd_und_section_ptr; - asym->flags = 0; - asym->value = 0; - break; - case scInit: - asym->section = bfd_make_section_old_way (abfd, ".init"); - asym->value -= asym->section->vma; - break; - case scBasedVar: - case scXData: - case scPData: - asym->flags = BSF_DEBUGGING; - break; - case scFini: - asym->section = bfd_make_section_old_way (abfd, ".fini"); - asym->value -= asym->section->vma; - break; - case scRConst: - asym->section = bfd_make_section_old_way (abfd, ".rconst"); - asym->value -= asym->section->vma; - break; - default: - break; - } - - /* Look for special constructors symbols and make relocation entries - in a special construction section. These are produced by the - -fgnu-linker argument to g++. */ - if (ECOFF_IS_STAB (ecoff_sym)) - { - switch (ECOFF_UNMARK_STAB (ecoff_sym->index)) - { - default: - break; - - case N_SETA: - case N_SETT: - case N_SETD: - case N_SETB: - /* Mark the symbol as a constructor. */ - asym->flags |= BSF_CONSTRUCTOR; - break; - } - } - return TRUE; -} - -/* Read an ECOFF symbol table. */ - -bfd_boolean -_bfd_ecoff_slurp_symbol_table (bfd *abfd) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - const bfd_size_type external_ext_size - = backend->debug_swap.external_ext_size; - const bfd_size_type external_sym_size - = backend->debug_swap.external_sym_size; - void (* const swap_ext_in) (bfd *, void *, EXTR *) - = backend->debug_swap.swap_ext_in; - void (* const swap_sym_in) (bfd *, void *, SYMR *) - = backend->debug_swap.swap_sym_in; - ecoff_symbol_type *internal; - ecoff_symbol_type *internal_ptr; - char *eraw_src; - char *eraw_end; - FDR *fdr_ptr; - FDR *fdr_end; - - /* If we've already read in the symbol table, do nothing. */ - if (ecoff_data (abfd)->canonical_symbols != NULL) - return TRUE; - - /* Get the symbolic information. */ - if (! _bfd_ecoff_slurp_symbolic_info (abfd, NULL, - &ecoff_data (abfd)->debug_info)) - return FALSE; - if (bfd_get_symcount (abfd) == 0) - return TRUE; - - internal = (ecoff_symbol_type *) bfd_alloc2 (abfd, bfd_get_symcount (abfd), - sizeof (ecoff_symbol_type)); - if (internal == NULL) - return FALSE; - - internal_ptr = internal; - eraw_src = (char *) ecoff_data (abfd)->debug_info.external_ext; - eraw_end = (eraw_src - + (ecoff_data (abfd)->debug_info.symbolic_header.iextMax - * external_ext_size)); - for (; eraw_src < eraw_end; eraw_src += external_ext_size, internal_ptr++) - { - EXTR internal_esym; - - (*swap_ext_in) (abfd, (void *) eraw_src, &internal_esym); - - /* PR 17512: file: 3372-1000-0.004. */ - if (internal_esym.asym.iss >= ecoff_data (abfd)->debug_info.symbolic_header.issExtMax - || internal_esym.asym.iss < 0) - return FALSE; - - internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext - + internal_esym.asym.iss); - - if (!ecoff_set_symbol_info (abfd, &internal_esym.asym, - &internal_ptr->symbol, 1, - internal_esym.weakext)) - return FALSE; - - /* The alpha uses a negative ifd field for section symbols. */ - if (internal_esym.ifd >= 0) - { - /* PR 17512: file: 3372-1983-0.004. */ - if (internal_esym.ifd >= ecoff_data (abfd)->debug_info.symbolic_header.ifdMax) - internal_ptr->fdr = NULL; - else - internal_ptr->fdr = (ecoff_data (abfd)->debug_info.fdr - + internal_esym.ifd); - } - else - internal_ptr->fdr = NULL; - internal_ptr->local = FALSE; - internal_ptr->native = (void *) eraw_src; - } - - /* The local symbols must be accessed via the fdr's, because the - string and aux indices are relative to the fdr information. */ - fdr_ptr = ecoff_data (abfd)->debug_info.fdr; - fdr_end = fdr_ptr + ecoff_data (abfd)->debug_info.symbolic_header.ifdMax; - for (; fdr_ptr < fdr_end; fdr_ptr++) - { - char *lraw_src; - char *lraw_end; - - lraw_src = ((char *) ecoff_data (abfd)->debug_info.external_sym - + fdr_ptr->isymBase * external_sym_size); - lraw_end = lraw_src + fdr_ptr->csym * external_sym_size; - for (; - lraw_src < lraw_end; - lraw_src += external_sym_size, internal_ptr++) - { - SYMR internal_sym; - - (*swap_sym_in) (abfd, (void *) lraw_src, &internal_sym); - internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ss - + fdr_ptr->issBase - + internal_sym.iss); - if (!ecoff_set_symbol_info (abfd, &internal_sym, - &internal_ptr->symbol, 0, 0)) - return FALSE; - internal_ptr->fdr = fdr_ptr; - internal_ptr->local = TRUE; - internal_ptr->native = (void *) lraw_src; - } - } - - /* PR 17512: file: 3372-3080-0.004. - A discrepancy between ecoff_data (abfd)->debug_info.symbolic_header.isymMax - and ecoff_data (abfd)->debug_info.symbolic_header.ifdMax can mean that - we have fewer symbols than we were expecting. Allow for this by updating - the symbol count and warning the user. */ - if (internal_ptr - internal < (ptrdiff_t) bfd_get_symcount (abfd)) - { - bfd_get_symcount (abfd) = internal_ptr - internal; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: isymMax (%ld) is greater than ifdMax (%ld)"), - abfd, ecoff_data (abfd)->debug_info.symbolic_header.isymMax, - ecoff_data (abfd)->debug_info.symbolic_header.ifdMax); - } - - ecoff_data (abfd)->canonical_symbols = internal; - - return TRUE; -} - -/* Return the amount of space needed for the canonical symbols. */ - -long -_bfd_ecoff_get_symtab_upper_bound (bfd *abfd) -{ - if (! _bfd_ecoff_slurp_symbolic_info (abfd, NULL, - &ecoff_data (abfd)->debug_info)) - return -1; - - if (bfd_get_symcount (abfd) == 0) - return 0; - - return (bfd_get_symcount (abfd) + 1) * (sizeof (ecoff_symbol_type *)); -} - -/* Get the canonical symbols. */ - -long -_bfd_ecoff_canonicalize_symtab (bfd *abfd, asymbol **alocation) -{ - unsigned int counter = 0; - ecoff_symbol_type *symbase; - ecoff_symbol_type **location = (ecoff_symbol_type **) alocation; - - if (! _bfd_ecoff_slurp_symbol_table (abfd)) - return -1; - if (bfd_get_symcount (abfd) == 0) - return 0; - - symbase = ecoff_data (abfd)->canonical_symbols; - while (counter < bfd_get_symcount (abfd)) - { - *(location++) = symbase++; - counter++; - } - *location++ = NULL; - return bfd_get_symcount (abfd); -} - -/* Turn ECOFF type information into a printable string. - ecoff_emit_aggregate and ecoff_type_to_string are from - gcc/mips-tdump.c, with swapping added and used_ptr removed. */ - -/* Write aggregate information to a string. */ - -static void -ecoff_emit_aggregate (bfd *abfd, - FDR *fdr, - char *string, - RNDXR *rndx, - long isym, - const char *which) -{ - const struct ecoff_debug_swap * const debug_swap = - &ecoff_backend (abfd)->debug_swap; - struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info; - unsigned int ifd = rndx->rfd; - unsigned int indx = rndx->index; - const char *name; - - if (ifd == 0xfff) - ifd = isym; - - /* An ifd of -1 is an opaque type. An escaped index of 0 is a - struct return type of a procedure compiled without -g. */ - if (ifd == 0xffffffff - || (rndx->rfd == 0xfff && indx == 0)) - name = ""; - else if (indx == indexNil) - name = ""; - else - { - SYMR sym; - - if (debug_info->external_rfd == NULL) - fdr = debug_info->fdr + ifd; - else - { - RFDT rfd; - - (*debug_swap->swap_rfd_in) (abfd, - ((char *) debug_info->external_rfd - + ((fdr->rfdBase + ifd) - * debug_swap->external_rfd_size)), - &rfd); - fdr = debug_info->fdr + rfd; - } - - indx += fdr->isymBase; - - (*debug_swap->swap_sym_in) (abfd, - ((char *) debug_info->external_sym - + indx * debug_swap->external_sym_size), - &sym); - - name = debug_info->ss + fdr->issBase + sym.iss; - } - - sprintf (string, - "%s %s { ifd = %u, index = %lu }", - which, name, ifd, - ((unsigned long) indx - + debug_info->symbolic_header.iextMax)); -} - -/* Convert the type information to string format. */ - -static char * -ecoff_type_to_string (bfd *abfd, FDR *fdr, unsigned int indx) -{ - union aux_ext *aux_ptr; - int bigendian; - AUXU u; - struct qual - { - unsigned int type; - int low_bound; - int high_bound; - int stride; - } qualifiers[7]; - unsigned int basic_type; - int i; - char buffer1[1024]; - static char buffer2[1024]; - char *p1 = buffer1; - char *p2 = buffer2; - RNDXR rndx; - - aux_ptr = ecoff_data (abfd)->debug_info.external_aux + fdr->iauxBase; - bigendian = fdr->fBigendian; - - for (i = 0; i < 7; i++) - { - qualifiers[i].low_bound = 0; - qualifiers[i].high_bound = 0; - qualifiers[i].stride = 0; - } - - if (AUX_GET_ISYM (bigendian, &aux_ptr[indx]) == (bfd_vma) -1) - return "-1 (no type)"; - _bfd_ecoff_swap_tir_in (bigendian, &aux_ptr[indx++].a_ti, &u.ti); - - basic_type = u.ti.bt; - qualifiers[0].type = u.ti.tq0; - qualifiers[1].type = u.ti.tq1; - qualifiers[2].type = u.ti.tq2; - qualifiers[3].type = u.ti.tq3; - qualifiers[4].type = u.ti.tq4; - qualifiers[5].type = u.ti.tq5; - qualifiers[6].type = tqNil; - - /* Go get the basic type. */ - switch (basic_type) - { - case btNil: /* Undefined. */ - strcpy (p1, "nil"); - break; - - case btAdr: /* Address - integer same size as pointer. */ - strcpy (p1, "address"); - break; - - case btChar: /* Character. */ - strcpy (p1, "char"); - break; - - case btUChar: /* Unsigned character. */ - strcpy (p1, "unsigned char"); - break; - - case btShort: /* Short. */ - strcpy (p1, "short"); - break; - - case btUShort: /* Unsigned short. */ - strcpy (p1, "unsigned short"); - break; - - case btInt: /* Int. */ - strcpy (p1, "int"); - break; - - case btUInt: /* Unsigned int. */ - strcpy (p1, "unsigned int"); - break; - - case btLong: /* Long. */ - strcpy (p1, "long"); - break; - - case btULong: /* Unsigned long. */ - strcpy (p1, "unsigned long"); - break; - - case btFloat: /* Float (real). */ - strcpy (p1, "float"); - break; - - case btDouble: /* Double (real). */ - strcpy (p1, "double"); - break; - - /* Structures add 1-2 aux words: - 1st word is [ST_RFDESCAPE, offset] pointer to struct def; - 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ - - case btStruct: /* Structure (Record). */ - _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); - ecoff_emit_aggregate (abfd, fdr, p1, &rndx, - (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), - "struct"); - indx++; /* Skip aux words. */ - break; - - /* Unions add 1-2 aux words: - 1st word is [ST_RFDESCAPE, offset] pointer to union def; - 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ - - case btUnion: /* Union. */ - _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); - ecoff_emit_aggregate (abfd, fdr, p1, &rndx, - (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), - "union"); - indx++; /* Skip aux words. */ - break; - - /* Enumerations add 1-2 aux words: - 1st word is [ST_RFDESCAPE, offset] pointer to enum def; - 2nd word is file index if 1st word rfd is ST_RFDESCAPE. */ - - case btEnum: /* Enumeration. */ - _bfd_ecoff_swap_rndx_in (bigendian, &aux_ptr[indx].a_rndx, &rndx); - ecoff_emit_aggregate (abfd, fdr, p1, &rndx, - (long) AUX_GET_ISYM (bigendian, &aux_ptr[indx+1]), - "enum"); - indx++; /* Skip aux words. */ - break; - - case btTypedef: /* Defined via a typedef, isymRef points. */ - strcpy (p1, "typedef"); - break; - - case btRange: /* Subrange of int. */ - strcpy (p1, "subrange"); - break; - - case btSet: /* Pascal sets. */ - strcpy (p1, "set"); - break; - - case btComplex: /* Fortran complex. */ - strcpy (p1, "complex"); - break; - - case btDComplex: /* Fortran double complex. */ - strcpy (p1, "double complex"); - break; - - case btIndirect: /* Forward or unnamed typedef. */ - strcpy (p1, "forward/unamed typedef"); - break; - - case btFixedDec: /* Fixed Decimal. */ - strcpy (p1, "fixed decimal"); - break; - - case btFloatDec: /* Float Decimal. */ - strcpy (p1, "float decimal"); - break; - - case btString: /* Varying Length Character String. */ - strcpy (p1, "string"); - break; - - case btBit: /* Aligned Bit String. */ - strcpy (p1, "bit"); - break; - - case btPicture: /* Picture. */ - strcpy (p1, "picture"); - break; - - case btVoid: /* Void. */ - strcpy (p1, "void"); - break; - - default: - sprintf (p1, _("Unknown basic type %d"), (int) basic_type); - break; - } - - p1 += strlen (buffer1); - - /* If this is a bitfield, get the bitsize. */ - if (u.ti.fBitfield) - { - int bitsize; - - bitsize = AUX_GET_WIDTH (bigendian, &aux_ptr[indx++]); - sprintf (p1, " : %d", bitsize); - p1 += strlen (buffer1); - } - - /* Deal with any qualifiers. */ - if (qualifiers[0].type != tqNil) - { - /* Snarf up any array bounds in the correct order. Arrays - store 5 successive words in the aux. table: - word 0 RNDXR to type of the bounds (ie, int) - word 1 Current file descriptor index - word 2 low bound - word 3 high bound (or -1 if []) - word 4 stride size in bits. */ - for (i = 0; i < 7; i++) - { - if (qualifiers[i].type == tqArray) - { - qualifiers[i].low_bound = - AUX_GET_DNLOW (bigendian, &aux_ptr[indx+2]); - qualifiers[i].high_bound = - AUX_GET_DNHIGH (bigendian, &aux_ptr[indx+3]); - qualifiers[i].stride = - AUX_GET_WIDTH (bigendian, &aux_ptr[indx+4]); - indx += 5; - } - } - - /* Now print out the qualifiers. */ - for (i = 0; i < 6; i++) - { - switch (qualifiers[i].type) - { - case tqNil: - case tqMax: - break; - - case tqPtr: - strcpy (p2, "ptr to "); - p2 += sizeof ("ptr to ")-1; - break; - - case tqVol: - strcpy (p2, "volatile "); - p2 += sizeof ("volatile ")-1; - break; - - case tqFar: - strcpy (p2, "far "); - p2 += sizeof ("far ")-1; - break; - - case tqProc: - strcpy (p2, "func. ret. "); - p2 += sizeof ("func. ret. "); - break; - - case tqArray: - { - int first_array = i; - int j; - - /* Print array bounds reversed (ie, in the order the C - programmer writes them). C is such a fun language.... */ - while (i < 5 && qualifiers[i+1].type == tqArray) - i++; - - for (j = i; j >= first_array; j--) - { - strcpy (p2, "array ["); - p2 += sizeof ("array [")-1; - if (qualifiers[j].low_bound != 0) - sprintf (p2, - "%ld:%ld {%ld bits}", - (long) qualifiers[j].low_bound, - (long) qualifiers[j].high_bound, - (long) qualifiers[j].stride); - - else if (qualifiers[j].high_bound != -1) - sprintf (p2, - "%ld {%ld bits}", - (long) (qualifiers[j].high_bound + 1), - (long) (qualifiers[j].stride)); - - else - sprintf (p2, " {%ld bits}", (long) (qualifiers[j].stride)); - - p2 += strlen (p2); - strcpy (p2, "] of "); - p2 += sizeof ("] of ")-1; - } - } - break; - } - } - } - - strcpy (p2, buffer1); - return buffer2; -} - -/* Return information about ECOFF symbol SYMBOL in RET. */ - -void -_bfd_ecoff_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, - asymbol *symbol, - symbol_info *ret) -{ - bfd_symbol_info (symbol, ret); -} - -/* Return whether this is a local label. */ - -bfd_boolean -_bfd_ecoff_bfd_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, - const char *name) -{ - return name[0] == '$'; -} - -/* Print information about an ECOFF symbol. */ - -void -_bfd_ecoff_print_symbol (bfd *abfd, - void * filep, - asymbol *symbol, - bfd_print_symbol_type how) -{ - const struct ecoff_debug_swap * const debug_swap - = &ecoff_backend (abfd)->debug_swap; - FILE *file = (FILE *)filep; - - switch (how) - { - case bfd_print_symbol_name: - fprintf (file, "%s", symbol->name); - break; - case bfd_print_symbol_more: - if (ecoffsymbol (symbol)->local) - { - SYMR ecoff_sym; - - (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_sym); - fprintf (file, "ecoff local "); - fprintf_vma (file, (bfd_vma) ecoff_sym.value); - fprintf (file, " %x %x", (unsigned) ecoff_sym.st, - (unsigned) ecoff_sym.sc); - } - else - { - EXTR ecoff_ext; - - (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_ext); - fprintf (file, "ecoff extern "); - fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); - fprintf (file, " %x %x", (unsigned) ecoff_ext.asym.st, - (unsigned) ecoff_ext.asym.sc); - } - break; - case bfd_print_symbol_all: - /* Print out the symbols in a reasonable way. */ - { - char type; - int pos; - EXTR ecoff_ext; - char jmptbl; - char cobol_main; - char weakext; - - if (ecoffsymbol (symbol)->local) - { - (*debug_swap->swap_sym_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_ext.asym); - type = 'l'; - pos = ((((char *) ecoffsymbol (symbol)->native - - (char *) ecoff_data (abfd)->debug_info.external_sym) - / debug_swap->external_sym_size) - + ecoff_data (abfd)->debug_info.symbolic_header.iextMax); - jmptbl = ' '; - cobol_main = ' '; - weakext = ' '; - } - else - { - (*debug_swap->swap_ext_in) (abfd, ecoffsymbol (symbol)->native, - &ecoff_ext); - type = 'e'; - pos = (((char *) ecoffsymbol (symbol)->native - - (char *) ecoff_data (abfd)->debug_info.external_ext) - / debug_swap->external_ext_size); - jmptbl = ecoff_ext.jmptbl ? 'j' : ' '; - cobol_main = ecoff_ext.cobol_main ? 'c' : ' '; - weakext = ecoff_ext.weakext ? 'w' : ' '; - } - - fprintf (file, "[%3d] %c ", - pos, type); - fprintf_vma (file, (bfd_vma) ecoff_ext.asym.value); - fprintf (file, " st %x sc %x indx %x %c%c%c %s", - (unsigned) ecoff_ext.asym.st, - (unsigned) ecoff_ext.asym.sc, - (unsigned) ecoff_ext.asym.index, - jmptbl, cobol_main, weakext, - symbol->name); - - if (ecoffsymbol (symbol)->fdr != NULL - && ecoff_ext.asym.index != indexNil) - { - FDR *fdr; - unsigned int indx; - int bigendian; - bfd_size_type sym_base; - union aux_ext *aux_base; - - fdr = ecoffsymbol (symbol)->fdr; - indx = ecoff_ext.asym.index; - - /* sym_base is used to map the fdr relative indices which - appear in the file to the position number which we are - using. */ - sym_base = fdr->isymBase; - if (ecoffsymbol (symbol)->local) - sym_base += - ecoff_data (abfd)->debug_info.symbolic_header.iextMax; - - /* aux_base is the start of the aux entries for this file; - asym.index is an offset from this. */ - aux_base = (ecoff_data (abfd)->debug_info.external_aux - + fdr->iauxBase); - - /* The aux entries are stored in host byte order; the - order is indicated by a bit in the fdr. */ - bigendian = fdr->fBigendian; - - /* This switch is basically from gcc/mips-tdump.c. */ - switch (ecoff_ext.asym.st) - { - case stNil: - case stLabel: - break; - - case stFile: - case stBlock: - fprintf (file, _("\n End+1 symbol: %ld"), - (long) (indx + sym_base)); - break; - - case stEnd: - if (ecoff_ext.asym.sc == scText - || ecoff_ext.asym.sc == scInfo) - fprintf (file, _("\n First symbol: %ld"), - (long) (indx + sym_base)); - else - fprintf (file, _("\n First symbol: %ld"), - ((long) - (AUX_GET_ISYM (bigendian, - &aux_base[ecoff_ext.asym.index]) - + sym_base))); - break; - - case stProc: - case stStaticProc: - if (ECOFF_IS_STAB (&ecoff_ext.asym)) - ; - else if (ecoffsymbol (symbol)->local) - /* xgettext:c-format */ - fprintf (file, _("\n End+1 symbol: %-7ld Type: %s"), - ((long) - (AUX_GET_ISYM (bigendian, - &aux_base[ecoff_ext.asym.index]) - + sym_base)), - ecoff_type_to_string (abfd, fdr, indx + 1)); - else - fprintf (file, _("\n Local symbol: %ld"), - ((long) indx - + (long) sym_base - + (ecoff_data (abfd) - ->debug_info.symbolic_header.iextMax))); - break; - - case stStruct: - fprintf (file, _("\n struct; End+1 symbol: %ld"), - (long) (indx + sym_base)); - break; - - case stUnion: - fprintf (file, _("\n union; End+1 symbol: %ld"), - (long) (indx + sym_base)); - break; - - case stEnum: - fprintf (file, _("\n enum; End+1 symbol: %ld"), - (long) (indx + sym_base)); - break; - - default: - if (! ECOFF_IS_STAB (&ecoff_ext.asym)) - fprintf (file, _("\n Type: %s"), - ecoff_type_to_string (abfd, fdr, indx)); - break; - } - } - } - break; - } -} - -/* Read in the relocs for a section. */ - -static bfd_boolean -ecoff_slurp_reloc_table (bfd *abfd, - asection *section, - asymbol **symbols) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - arelent *internal_relocs; - bfd_size_type external_reloc_size; - bfd_size_type amt; - char *external_relocs; - arelent *rptr; - unsigned int i; - - if (section->relocation != NULL - || section->reloc_count == 0 - || (section->flags & SEC_CONSTRUCTOR) != 0) - return TRUE; - - if (! _bfd_ecoff_slurp_symbol_table (abfd)) - return FALSE; - - amt = section->reloc_count; - amt *= sizeof (arelent); - internal_relocs = (arelent *) bfd_alloc (abfd, amt); - - external_reloc_size = backend->external_reloc_size; - amt = external_reloc_size * section->reloc_count; - external_relocs = (char *) bfd_alloc (abfd, amt); - if (internal_relocs == NULL || external_relocs == NULL) - return FALSE; - if (bfd_seek (abfd, section->rel_filepos, SEEK_SET) != 0) - return FALSE; - if (bfd_bread (external_relocs, amt, abfd) != amt) - return FALSE; - - for (i = 0, rptr = internal_relocs; i < section->reloc_count; i++, rptr++) - { - struct internal_reloc intern; - - (*backend->swap_reloc_in) (abfd, - external_relocs + i * external_reloc_size, - &intern); - - if (intern.r_extern) - { - /* r_symndx is an index into the external symbols. */ - BFD_ASSERT (intern.r_symndx >= 0 - && (intern.r_symndx - < (ecoff_data (abfd) - ->debug_info.symbolic_header.iextMax))); - rptr->sym_ptr_ptr = symbols + intern.r_symndx; - rptr->addend = 0; - } - else if (intern.r_symndx == RELOC_SECTION_NONE - || intern.r_symndx == RELOC_SECTION_ABS) - { - rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - rptr->addend = 0; - } - else - { - const char *sec_name; - asection *sec; - - /* r_symndx is a section key. */ - switch (intern.r_symndx) - { - case RELOC_SECTION_TEXT: sec_name = _TEXT; break; - case RELOC_SECTION_RDATA: sec_name = _RDATA; break; - case RELOC_SECTION_DATA: sec_name = _DATA; break; - case RELOC_SECTION_SDATA: sec_name = _SDATA; break; - case RELOC_SECTION_SBSS: sec_name = _SBSS; break; - case RELOC_SECTION_BSS: sec_name = _BSS; break; - case RELOC_SECTION_INIT: sec_name = _INIT; break; - case RELOC_SECTION_LIT8: sec_name = _LIT8; break; - case RELOC_SECTION_LIT4: sec_name = _LIT4; break; - case RELOC_SECTION_XDATA: sec_name = _XDATA; break; - case RELOC_SECTION_PDATA: sec_name = _PDATA; break; - case RELOC_SECTION_FINI: sec_name = _FINI; break; - case RELOC_SECTION_LITA: sec_name = _LITA; break; - case RELOC_SECTION_RCONST: sec_name = _RCONST; break; - default: abort (); - } - - sec = bfd_get_section_by_name (abfd, sec_name); - if (sec == NULL) - abort (); - rptr->sym_ptr_ptr = sec->symbol_ptr_ptr; - - rptr->addend = - bfd_get_section_vma (abfd, sec); - } - - rptr->address = intern.r_vaddr - bfd_get_section_vma (abfd, section); - - /* Let the backend select the howto field and do any other - required processing. */ - (*backend->adjust_reloc_in) (abfd, &intern, rptr); - } - - bfd_release (abfd, external_relocs); - - section->relocation = internal_relocs; - - return TRUE; -} - -/* Get a canonical list of relocs. */ - -long -_bfd_ecoff_canonicalize_reloc (bfd *abfd, - asection *section, - arelent **relptr, - asymbol **symbols) -{ - unsigned int count; - - if (section->flags & SEC_CONSTRUCTOR) - { - arelent_chain *chain; - - /* This section has relocs made up by us, not the file, so take - them out of their chain and place them into the data area - provided. */ - for (count = 0, chain = section->constructor_chain; - count < section->reloc_count; - count++, chain = chain->next) - *relptr++ = &chain->relent; - } - else - { - arelent *tblptr; - - if (! ecoff_slurp_reloc_table (abfd, section, symbols)) - return -1; - - tblptr = section->relocation; - - for (count = 0; count < section->reloc_count; count++) - *relptr++ = tblptr++; - } - - *relptr = NULL; - - return section->reloc_count; -} - -/* Provided a BFD, a section and an offset into the section, calculate - and return the name of the source file and the line nearest to the - wanted location. */ - -bfd_boolean -_bfd_ecoff_find_nearest_line (bfd *abfd, - asymbol **symbols ATTRIBUTE_UNUSED, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *retline_ptr, - unsigned int *discriminator_ptr) -{ - const struct ecoff_debug_swap * const debug_swap - = &ecoff_backend (abfd)->debug_swap; - struct ecoff_debug_info * const debug_info = &ecoff_data (abfd)->debug_info; - struct ecoff_find_line *line_info; - - /* Make sure we have the FDR's. */ - if (! _bfd_ecoff_slurp_symbolic_info (abfd, NULL, debug_info) - || bfd_get_symcount (abfd) == 0) - return FALSE; - - if (ecoff_data (abfd)->find_line_info == NULL) - { - bfd_size_type amt = sizeof (struct ecoff_find_line); - - ecoff_data (abfd)->find_line_info = - (struct ecoff_find_line *) bfd_zalloc (abfd, amt); - if (ecoff_data (abfd)->find_line_info == NULL) - return FALSE; - } - - if (discriminator_ptr) - *discriminator_ptr = 0; - line_info = ecoff_data (abfd)->find_line_info; - return _bfd_ecoff_locate_line (abfd, section, offset, debug_info, - debug_swap, line_info, filename_ptr, - functionname_ptr, retline_ptr); -} - -/* Copy private BFD data. This is called by objcopy and strip. We - use it to copy the ECOFF debugging information from one BFD to the - other. It would be theoretically possible to represent the ECOFF - debugging information in the symbol table. However, it would be a - lot of work, and there would be little gain (gas, gdb, and ld - already access the ECOFF debugging information via the - ecoff_debug_info structure, and that structure would have to be - retained in order to support ECOFF debugging in MIPS ELF). - - The debugging information for the ECOFF external symbols comes from - the symbol table, so this function only handles the other debugging - information. */ - -bfd_boolean -_bfd_ecoff_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - struct ecoff_debug_info *iinfo = &ecoff_data (ibfd)->debug_info; - struct ecoff_debug_info *oinfo = &ecoff_data (obfd)->debug_info; - int i; - asymbol **sym_ptr_ptr; - size_t c; - bfd_boolean local; - - /* We only want to copy information over if both BFD's use ECOFF - format. */ - if (bfd_get_flavour (ibfd) != bfd_target_ecoff_flavour - || bfd_get_flavour (obfd) != bfd_target_ecoff_flavour) - return TRUE; - - /* Copy the GP value and the register masks. */ - ecoff_data (obfd)->gp = ecoff_data (ibfd)->gp; - ecoff_data (obfd)->gprmask = ecoff_data (ibfd)->gprmask; - ecoff_data (obfd)->fprmask = ecoff_data (ibfd)->fprmask; - for (i = 0; i < 3; i++) - ecoff_data (obfd)->cprmask[i] = ecoff_data (ibfd)->cprmask[i]; - - /* Copy the version stamp. */ - oinfo->symbolic_header.vstamp = iinfo->symbolic_header.vstamp; - - /* If there are no symbols, don't copy any debugging information. */ - c = bfd_get_symcount (obfd); - sym_ptr_ptr = bfd_get_outsymbols (obfd); - if (c == 0 || sym_ptr_ptr == NULL) - return TRUE; - - /* See if there are any local symbols. */ - local = FALSE; - for (; c > 0; c--, sym_ptr_ptr++) - { - if (ecoffsymbol (*sym_ptr_ptr)->local) - { - local = TRUE; - break; - } - } - - if (local) - { - /* There are some local symbols. We just bring over all the - debugging information. FIXME: This is not quite the right - thing to do. If the user has asked us to discard all - debugging information, then we are probably going to wind up - keeping it because there will probably be some local symbol - which objcopy did not discard. We should actually break - apart the debugging information and only keep that which - applies to the symbols we want to keep. */ - oinfo->symbolic_header.ilineMax = iinfo->symbolic_header.ilineMax; - oinfo->symbolic_header.cbLine = iinfo->symbolic_header.cbLine; - oinfo->line = iinfo->line; - - oinfo->symbolic_header.idnMax = iinfo->symbolic_header.idnMax; - oinfo->external_dnr = iinfo->external_dnr; - - oinfo->symbolic_header.ipdMax = iinfo->symbolic_header.ipdMax; - oinfo->external_pdr = iinfo->external_pdr; - - oinfo->symbolic_header.isymMax = iinfo->symbolic_header.isymMax; - oinfo->external_sym = iinfo->external_sym; - - oinfo->symbolic_header.ioptMax = iinfo->symbolic_header.ioptMax; - oinfo->external_opt = iinfo->external_opt; - - oinfo->symbolic_header.iauxMax = iinfo->symbolic_header.iauxMax; - oinfo->external_aux = iinfo->external_aux; - - oinfo->symbolic_header.issMax = iinfo->symbolic_header.issMax; - oinfo->ss = iinfo->ss; - - oinfo->symbolic_header.ifdMax = iinfo->symbolic_header.ifdMax; - oinfo->external_fdr = iinfo->external_fdr; - - oinfo->symbolic_header.crfd = iinfo->symbolic_header.crfd; - oinfo->external_rfd = iinfo->external_rfd; - } - else - { - /* We are discarding all the local symbol information. Look - through the external symbols and remove all references to FDR - or aux information. */ - c = bfd_get_symcount (obfd); - sym_ptr_ptr = bfd_get_outsymbols (obfd); - for (; c > 0; c--, sym_ptr_ptr++) - { - EXTR esym; - - (*(ecoff_backend (obfd)->debug_swap.swap_ext_in)) - (obfd, ecoffsymbol (*sym_ptr_ptr)->native, &esym); - esym.ifd = ifdNil; - esym.asym.index = indexNil; - (*(ecoff_backend (obfd)->debug_swap.swap_ext_out)) - (obfd, &esym, ecoffsymbol (*sym_ptr_ptr)->native); - } - } - - return TRUE; -} - -/* Set the architecture. The supported architecture is stored in the - backend pointer. We always set the architecture anyhow, since many - callers ignore the return value. */ - -bfd_boolean -_bfd_ecoff_set_arch_mach (bfd *abfd, - enum bfd_architecture arch, - unsigned long machine) -{ - bfd_default_set_arch_mach (abfd, arch, machine); - return arch == ecoff_backend (abfd)->arch; -} - -/* Get the size of the section headers. */ - -int -_bfd_ecoff_sizeof_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - asection *current; - int c; - int ret; - - c = 0; - for (current = abfd->sections; - current != NULL; - current = current->next) - ++c; - - ret = (bfd_coff_filhsz (abfd) - + bfd_coff_aoutsz (abfd) - + c * bfd_coff_scnhsz (abfd)); - return (int) BFD_ALIGN (ret, 16); -} - -/* Get the contents of a section. */ - -bfd_boolean -_bfd_ecoff_get_section_contents (bfd *abfd, - asection *section, - void * location, - file_ptr offset, - bfd_size_type count) -{ - return _bfd_generic_get_section_contents (abfd, section, location, - offset, count); -} - -/* Sort sections by VMA, but put SEC_ALLOC sections first. This is - called via qsort. */ - -static int -ecoff_sort_hdrs (const void * arg1, const void * arg2) -{ - const asection *hdr1 = *(const asection **) arg1; - const asection *hdr2 = *(const asection **) arg2; - - if ((hdr1->flags & SEC_ALLOC) != 0) - { - if ((hdr2->flags & SEC_ALLOC) == 0) - return -1; - } - else - { - if ((hdr2->flags & SEC_ALLOC) != 0) - return 1; - } - if (hdr1->vma < hdr2->vma) - return -1; - else if (hdr1->vma > hdr2->vma) - return 1; - else - return 0; -} - -/* Calculate the file position for each section, and set - reloc_filepos. */ - -static bfd_boolean -ecoff_compute_section_file_positions (bfd *abfd) -{ - file_ptr sofar, file_sofar; - asection **sorted_hdrs; - asection *current; - unsigned int i; - file_ptr old_sofar; - bfd_boolean rdata_in_text; - bfd_boolean first_data, first_nonalloc; - const bfd_vma round = ecoff_backend (abfd)->round; - bfd_size_type amt; - - sofar = _bfd_ecoff_sizeof_headers (abfd, NULL); - file_sofar = sofar; - - /* Sort the sections by VMA. */ - amt = abfd->section_count; - amt *= sizeof (asection *); - sorted_hdrs = (asection **) bfd_malloc (amt); - if (sorted_hdrs == NULL) - return FALSE; - for (current = abfd->sections, i = 0; - current != NULL; - current = current->next, i++) - sorted_hdrs[i] = current; - BFD_ASSERT (i == abfd->section_count); - - qsort (sorted_hdrs, abfd->section_count, sizeof (asection *), - ecoff_sort_hdrs); - - /* Some versions of the OSF linker put the .rdata section in the - text segment, and some do not. */ - rdata_in_text = ecoff_backend (abfd)->rdata_in_text; - if (rdata_in_text) - { - for (i = 0; i < abfd->section_count; i++) - { - current = sorted_hdrs[i]; - if (streq (current->name, _RDATA)) - break; - if ((current->flags & SEC_CODE) == 0 - && ! streq (current->name, _PDATA) - && ! streq (current->name, _RCONST)) - { - rdata_in_text = FALSE; - break; - } - } - } - ecoff_data (abfd)->rdata_in_text = rdata_in_text; - - first_data = TRUE; - first_nonalloc = TRUE; - for (i = 0; i < abfd->section_count; i++) - { - unsigned int alignment_power; - - current = sorted_hdrs[i]; - - /* For the Alpha ECOFF .pdata section the lnnoptr field is - supposed to indicate the number of .pdata entries that are - really in the section. Each entry is 8 bytes. We store this - away in line_filepos before increasing the section size. */ - if (streq (current->name, _PDATA)) - current->line_filepos = current->size / 8; - - alignment_power = current->alignment_power; - - /* On Ultrix, the data sections in an executable file must be - aligned to a page boundary within the file. This does not - affect the section size, though. FIXME: Does this work for - other platforms? It requires some modification for the - Alpha, because .rdata on the Alpha goes with the text, not - the data. */ - if ((abfd->flags & EXEC_P) != 0 - && (abfd->flags & D_PAGED) != 0 - && ! first_data - && (current->flags & SEC_CODE) == 0 - && (! rdata_in_text - || ! streq (current->name, _RDATA)) - && ! streq (current->name, _PDATA) - && ! streq (current->name, _RCONST)) - { - sofar = (sofar + round - 1) &~ (round - 1); - file_sofar = (file_sofar + round - 1) &~ (round - 1); - first_data = FALSE; - } - else if (streq (current->name, _LIB)) - { - /* On Irix 4, the location of contents of the .lib section - from a shared library section is also rounded up to a - page boundary. */ - - sofar = (sofar + round - 1) &~ (round - 1); - file_sofar = (file_sofar + round - 1) &~ (round - 1); - } - else if (first_nonalloc - && (current->flags & SEC_ALLOC) == 0 - && (abfd->flags & D_PAGED) != 0) - { - /* Skip up to the next page for an unallocated section, such - as the .comment section on the Alpha. This leaves room - for the .bss section. */ - first_nonalloc = FALSE; - sofar = (sofar + round - 1) &~ (round - 1); - file_sofar = (file_sofar + round - 1) &~ (round - 1); - } - - /* Align the sections in the file to the same boundary on - which they are aligned in virtual memory. */ - sofar = BFD_ALIGN (sofar, 1 << alignment_power); - if ((current->flags & SEC_HAS_CONTENTS) != 0) - file_sofar = BFD_ALIGN (file_sofar, 1 << alignment_power); - - if ((abfd->flags & D_PAGED) != 0 - && (current->flags & SEC_ALLOC) != 0) - { - sofar += (current->vma - sofar) % round; - if ((current->flags & SEC_HAS_CONTENTS) != 0) - file_sofar += (current->vma - file_sofar) % round; - } - - if ((current->flags & (SEC_HAS_CONTENTS | SEC_LOAD)) != 0) - current->filepos = file_sofar; - - sofar += current->size; - if ((current->flags & SEC_HAS_CONTENTS) != 0) - file_sofar += current->size; - - /* Make sure that this section is of the right size too. */ - old_sofar = sofar; - sofar = BFD_ALIGN (sofar, 1 << alignment_power); - if ((current->flags & SEC_HAS_CONTENTS) != 0) - file_sofar = BFD_ALIGN (file_sofar, 1 << alignment_power); - current->size += sofar - old_sofar; - } - - free (sorted_hdrs); - sorted_hdrs = NULL; - - ecoff_data (abfd)->reloc_filepos = file_sofar; - - return TRUE; -} - -/* Determine the location of the relocs for all the sections in the - output file, as well as the location of the symbolic debugging - information. */ - -static bfd_size_type -ecoff_compute_reloc_file_positions (bfd *abfd) -{ - const bfd_size_type external_reloc_size = - ecoff_backend (abfd)->external_reloc_size; - file_ptr reloc_base; - bfd_size_type reloc_size; - asection *current; - file_ptr sym_base; - - if (! abfd->output_has_begun) - { - if (! ecoff_compute_section_file_positions (abfd)) - abort (); - abfd->output_has_begun = TRUE; - } - - reloc_base = ecoff_data (abfd)->reloc_filepos; - - reloc_size = 0; - for (current = abfd->sections; - current != NULL; - current = current->next) - { - if (current->reloc_count == 0) - current->rel_filepos = 0; - else - { - bfd_size_type relsize; - - current->rel_filepos = reloc_base; - relsize = current->reloc_count * external_reloc_size; - reloc_size += relsize; - reloc_base += relsize; - } - } - - sym_base = ecoff_data (abfd)->reloc_filepos + reloc_size; - - /* At least on Ultrix, the symbol table of an executable file must - be aligned to a page boundary. FIXME: Is this true on other - platforms? */ - if ((abfd->flags & EXEC_P) != 0 - && (abfd->flags & D_PAGED) != 0) - sym_base = ((sym_base + ecoff_backend (abfd)->round - 1) - &~ (ecoff_backend (abfd)->round - 1)); - - ecoff_data (abfd)->sym_filepos = sym_base; - - return reloc_size; -} - -/* Set the contents of a section. */ - -bfd_boolean -_bfd_ecoff_set_section_contents (bfd *abfd, - asection *section, - const void * location, - file_ptr offset, - bfd_size_type count) -{ - file_ptr pos; - - /* This must be done first, because bfd_set_section_contents is - going to set output_has_begun to TRUE. */ - if (! abfd->output_has_begun - && ! ecoff_compute_section_file_positions (abfd)) - return FALSE; - - /* Handle the .lib section specially so that Irix 4 shared libraries - work out. See coff_set_section_contents in coffcode.h. */ - if (streq (section->name, _LIB)) - { - bfd_byte *rec, *recend; - - rec = (bfd_byte *) location; - recend = rec + count; - while (rec < recend) - { - ++section->lma; - rec += bfd_get_32 (abfd, rec) * 4; - } - - BFD_ASSERT (rec == recend); - } - - if (count == 0) - return TRUE; - - pos = section->filepos + offset; - if (bfd_seek (abfd, pos, SEEK_SET) != 0 - || bfd_bwrite (location, count, abfd) != count) - return FALSE; - - return TRUE; -} - -/* Get the GP value for an ECOFF file. This is a hook used by - nlmconv. */ - -bfd_vma -bfd_ecoff_get_gp_value (bfd *abfd) -{ - if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour - || bfd_get_format (abfd) != bfd_object) - { - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - - return ecoff_data (abfd)->gp; -} - -/* Set the GP value for an ECOFF file. This is a hook used by the - assembler. */ - -bfd_boolean -bfd_ecoff_set_gp_value (bfd *abfd, bfd_vma gp_value) -{ - if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour - || bfd_get_format (abfd) != bfd_object) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - ecoff_data (abfd)->gp = gp_value; - - return TRUE; -} - -/* Set the register masks for an ECOFF file. This is a hook used by - the assembler. */ - -bfd_boolean -bfd_ecoff_set_regmasks (bfd *abfd, - unsigned long gprmask, - unsigned long fprmask, - unsigned long *cprmask) -{ - ecoff_data_type *tdata; - - if (bfd_get_flavour (abfd) != bfd_target_ecoff_flavour - || bfd_get_format (abfd) != bfd_object) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - tdata = ecoff_data (abfd); - tdata->gprmask = gprmask; - tdata->fprmask = fprmask; - if (cprmask != NULL) - { - int i; - - for (i = 0; i < 3; i++) - tdata->cprmask[i] = cprmask[i]; - } - - return TRUE; -} - -/* Get ECOFF EXTR information for an external symbol. This function - is passed to bfd_ecoff_debug_externals. */ - -static bfd_boolean -ecoff_get_extr (asymbol *sym, EXTR *esym) -{ - ecoff_symbol_type *ecoff_sym_ptr; - bfd *input_bfd; - - if (bfd_asymbol_flavour (sym) != bfd_target_ecoff_flavour - || ecoffsymbol (sym)->native == NULL) - { - /* Don't include debugging, local, or section symbols. */ - if ((sym->flags & BSF_DEBUGGING) != 0 - || (sym->flags & BSF_LOCAL) != 0 - || (sym->flags & BSF_SECTION_SYM) != 0) - return FALSE; - - esym->jmptbl = 0; - esym->cobol_main = 0; - esym->weakext = (sym->flags & BSF_WEAK) != 0; - esym->reserved = 0; - esym->ifd = ifdNil; - /* FIXME: we can do better than this for st and sc. */ - esym->asym.st = stGlobal; - esym->asym.sc = scAbs; - esym->asym.reserved = 0; - esym->asym.index = indexNil; - return TRUE; - } - - ecoff_sym_ptr = ecoffsymbol (sym); - - if (ecoff_sym_ptr->local) - return FALSE; - - input_bfd = bfd_asymbol_bfd (sym); - (*(ecoff_backend (input_bfd)->debug_swap.swap_ext_in)) - (input_bfd, ecoff_sym_ptr->native, esym); - - /* If the symbol was defined by the linker, then esym will be - undefined but sym will not be. Get a better class for such a - symbol. */ - if ((esym->asym.sc == scUndefined - || esym->asym.sc == scSUndefined) - && ! bfd_is_und_section (bfd_get_section (sym))) - esym->asym.sc = scAbs; - - /* Adjust the FDR index for the symbol by that used for the input - BFD. */ - if (esym->ifd != -1) - { - struct ecoff_debug_info *input_debug; - - input_debug = &ecoff_data (input_bfd)->debug_info; - BFD_ASSERT (esym->ifd < input_debug->symbolic_header.ifdMax); - if (input_debug->ifdmap != NULL) - esym->ifd = input_debug->ifdmap[esym->ifd]; - } - - return TRUE; -} - -/* Set the external symbol index. This routine is passed to - bfd_ecoff_debug_externals. */ - -static void -ecoff_set_index (asymbol *sym, bfd_size_type indx) -{ - ecoff_set_sym_index (sym, indx); -} - -/* Write out an ECOFF file. */ - -bfd_boolean -_bfd_ecoff_write_object_contents (bfd *abfd) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - const bfd_vma round = backend->round; - const bfd_size_type filhsz = bfd_coff_filhsz (abfd); - const bfd_size_type aoutsz = bfd_coff_aoutsz (abfd); - const bfd_size_type scnhsz = bfd_coff_scnhsz (abfd); - const bfd_size_type external_hdr_size - = backend->debug_swap.external_hdr_size; - const bfd_size_type external_reloc_size = backend->external_reloc_size; - void (* const adjust_reloc_out) (bfd *, const arelent *, struct internal_reloc *) - = backend->adjust_reloc_out; - void (* const swap_reloc_out) (bfd *, const struct internal_reloc *, void *) - = backend->swap_reloc_out; - struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info; - HDRR * const symhdr = &debug->symbolic_header; - asection *current; - unsigned int count; - bfd_size_type reloc_size; - bfd_size_type text_size; - bfd_vma text_start; - bfd_boolean set_text_start; - bfd_size_type data_size; - bfd_vma data_start; - bfd_boolean set_data_start; - bfd_size_type bss_size; - void * buff = NULL; - void * reloc_buff = NULL; - struct internal_filehdr internal_f; - struct internal_aouthdr internal_a; - int i; - - /* Determine where the sections and relocs will go in the output - file. */ - reloc_size = ecoff_compute_reloc_file_positions (abfd); - - count = 1; - for (current = abfd->sections; - current != NULL; - current = current->next) - { - current->target_index = count; - ++count; - } - - if ((abfd->flags & D_PAGED) != 0) - text_size = _bfd_ecoff_sizeof_headers (abfd, NULL); - else - text_size = 0; - text_start = 0; - set_text_start = FALSE; - data_size = 0; - data_start = 0; - set_data_start = FALSE; - bss_size = 0; - - /* Write section headers to the file. */ - - /* Allocate buff big enough to hold a section header, - file header, or a.out header. */ - { - bfd_size_type siz; - - siz = scnhsz; - if (siz < filhsz) - siz = filhsz; - if (siz < aoutsz) - siz = aoutsz; - buff = bfd_malloc (siz); - if (buff == NULL) - goto error_return; - } - - internal_f.f_nscns = 0; - if (bfd_seek (abfd, (file_ptr) (filhsz + aoutsz), SEEK_SET) != 0) - goto error_return; - - for (current = abfd->sections; - current != NULL; - current = current->next) - { - struct internal_scnhdr section; - bfd_vma vma; - - ++internal_f.f_nscns; - - strncpy (section.s_name, current->name, sizeof section.s_name); - - /* This seems to be correct for Irix 4 shared libraries. */ - vma = bfd_get_section_vma (abfd, current); - if (streq (current->name, _LIB)) - section.s_vaddr = 0; - else - section.s_vaddr = vma; - - section.s_paddr = current->lma; - section.s_size = current->size; - - /* If this section is unloadable then the scnptr will be 0. */ - if ((current->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) - section.s_scnptr = 0; - else - section.s_scnptr = current->filepos; - section.s_relptr = current->rel_filepos; - - /* FIXME: the lnnoptr of the .sbss or .sdata section of an - object file produced by the assembler is supposed to point to - information about how much room is required by objects of - various different sizes. I think this only matters if we - want the linker to compute the best size to use, or - something. I don't know what happens if the information is - not present. */ - if (! streq (current->name, _PDATA)) - section.s_lnnoptr = 0; - else - { - /* The Alpha ECOFF .pdata section uses the lnnoptr field to - hold the number of entries in the section (each entry is - 8 bytes). We stored this in the line_filepos field in - ecoff_compute_section_file_positions. */ - section.s_lnnoptr = current->line_filepos; - } - - section.s_nreloc = current->reloc_count; - section.s_nlnno = 0; - section.s_flags = ecoff_sec_to_styp_flags (current->name, - current->flags); - - if (bfd_coff_swap_scnhdr_out (abfd, (void *) §ion, buff) == 0 - || bfd_bwrite (buff, scnhsz, abfd) != scnhsz) - goto error_return; - - if ((section.s_flags & STYP_TEXT) != 0 - || ((section.s_flags & STYP_RDATA) != 0 - && ecoff_data (abfd)->rdata_in_text) - || section.s_flags == STYP_PDATA - || (section.s_flags & STYP_DYNAMIC) != 0 - || (section.s_flags & STYP_LIBLIST) != 0 - || (section.s_flags & STYP_RELDYN) != 0 - || section.s_flags == STYP_CONFLIC - || (section.s_flags & STYP_DYNSTR) != 0 - || (section.s_flags & STYP_DYNSYM) != 0 - || (section.s_flags & STYP_HASH) != 0 - || (section.s_flags & STYP_ECOFF_INIT) != 0 - || (section.s_flags & STYP_ECOFF_FINI) != 0 - || section.s_flags == STYP_RCONST) - { - text_size += current->size; - if (! set_text_start || text_start > vma) - { - text_start = vma; - set_text_start = TRUE; - } - } - else if ((section.s_flags & STYP_RDATA) != 0 - || (section.s_flags & STYP_DATA) != 0 - || (section.s_flags & STYP_LITA) != 0 - || (section.s_flags & STYP_LIT8) != 0 - || (section.s_flags & STYP_LIT4) != 0 - || (section.s_flags & STYP_SDATA) != 0 - || section.s_flags == STYP_XDATA - || (section.s_flags & STYP_GOT) != 0) - { - data_size += current->size; - if (! set_data_start || data_start > vma) - { - data_start = vma; - set_data_start = TRUE; - } - } - else if ((section.s_flags & STYP_BSS) != 0 - || (section.s_flags & STYP_SBSS) != 0) - bss_size += current->size; - else if (section.s_flags == 0 - || (section.s_flags & STYP_ECOFF_LIB) != 0 - || section.s_flags == STYP_COMMENT) - /* Do nothing. */ ; - else - abort (); - } - - /* Set up the file header. */ - internal_f.f_magic = ecoff_get_magic (abfd); - - /* We will NOT put a fucking timestamp in the header here. Every - time you put it back, I will come in and take it out again. I'm - sorry. This field does not belong here. We fill it with a 0 so - it compares the same but is not a reasonable time. -- - gnu@cygnus.com. */ - internal_f.f_timdat = 0; - - if (bfd_get_symcount (abfd) != 0) - { - /* The ECOFF f_nsyms field is not actually the number of - symbols, it's the size of symbolic information header. */ - internal_f.f_nsyms = external_hdr_size; - internal_f.f_symptr = ecoff_data (abfd)->sym_filepos; - } - else - { - internal_f.f_nsyms = 0; - internal_f.f_symptr = 0; - } - - internal_f.f_opthdr = aoutsz; - - internal_f.f_flags = F_LNNO; - if (reloc_size == 0) - internal_f.f_flags |= F_RELFLG; - if (bfd_get_symcount (abfd) == 0) - internal_f.f_flags |= F_LSYMS; - if (abfd->flags & EXEC_P) - internal_f.f_flags |= F_EXEC; - - if (bfd_little_endian (abfd)) - internal_f.f_flags |= F_AR32WR; - else - internal_f.f_flags |= F_AR32W; - - /* Set up the ``optional'' header. */ - if ((abfd->flags & D_PAGED) != 0) - internal_a.magic = ECOFF_AOUT_ZMAGIC; - else - internal_a.magic = ECOFF_AOUT_OMAGIC; - - /* FIXME: Is this really correct? */ - internal_a.vstamp = symhdr->vstamp; - - /* At least on Ultrix, these have to be rounded to page boundaries. - FIXME: Is this true on other platforms? */ - if ((abfd->flags & D_PAGED) != 0) - { - internal_a.tsize = (text_size + round - 1) &~ (round - 1); - internal_a.text_start = text_start &~ (round - 1); - internal_a.dsize = (data_size + round - 1) &~ (round - 1); - internal_a.data_start = data_start &~ (round - 1); - } - else - { - internal_a.tsize = text_size; - internal_a.text_start = text_start; - internal_a.dsize = data_size; - internal_a.data_start = data_start; - } - - /* On Ultrix, the initial portions of the .sbss and .bss segments - are at the end of the data section. The bsize field in the - optional header records how many bss bytes are required beyond - those in the data section. The value is not rounded to a page - boundary. */ - if (bss_size < internal_a.dsize - data_size) - bss_size = 0; - else - bss_size -= internal_a.dsize - data_size; - internal_a.bsize = bss_size; - internal_a.bss_start = internal_a.data_start + internal_a.dsize; - - internal_a.entry = bfd_get_start_address (abfd); - - internal_a.gp_value = ecoff_data (abfd)->gp; - - internal_a.gprmask = ecoff_data (abfd)->gprmask; - internal_a.fprmask = ecoff_data (abfd)->fprmask; - for (i = 0; i < 4; i++) - internal_a.cprmask[i] = ecoff_data (abfd)->cprmask[i]; - - /* Let the backend adjust the headers if necessary. */ - if (backend->adjust_headers) - { - if (! (*backend->adjust_headers) (abfd, &internal_f, &internal_a)) - goto error_return; - } - - /* Write out the file header and the optional header. */ - if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) - goto error_return; - - bfd_coff_swap_filehdr_out (abfd, (void *) &internal_f, buff); - if (bfd_bwrite (buff, filhsz, abfd) != filhsz) - goto error_return; - - bfd_coff_swap_aouthdr_out (abfd, (void *) &internal_a, buff); - if (bfd_bwrite (buff, aoutsz, abfd) != aoutsz) - goto error_return; - - /* Build the external symbol information. This must be done before - writing out the relocs so that we know the symbol indices. We - don't do this if this BFD was created by the backend linker, - since it will have already handled the symbols and relocs. */ - if (! ecoff_data (abfd)->linker) - { - symhdr->iextMax = 0; - symhdr->issExtMax = 0; - debug->external_ext = debug->external_ext_end = NULL; - debug->ssext = debug->ssext_end = NULL; - if (! bfd_ecoff_debug_externals (abfd, debug, &backend->debug_swap, - (abfd->flags & EXEC_P) == 0, - ecoff_get_extr, ecoff_set_index)) - goto error_return; - - /* Write out the relocs. */ - for (current = abfd->sections; - current != NULL; - current = current->next) - { - arelent **reloc_ptr_ptr; - arelent **reloc_end; - char *out_ptr; - bfd_size_type amt; - - if (current->reloc_count == 0) - continue; - - amt = current->reloc_count * external_reloc_size; - reloc_buff = bfd_alloc (abfd, amt); - if (reloc_buff == NULL) - goto error_return; - - reloc_ptr_ptr = current->orelocation; - reloc_end = reloc_ptr_ptr + current->reloc_count; - out_ptr = (char *) reloc_buff; - - for (; - reloc_ptr_ptr < reloc_end; - reloc_ptr_ptr++, out_ptr += external_reloc_size) - { - arelent *reloc; - asymbol *sym; - struct internal_reloc in; - - memset ((void *) &in, 0, sizeof in); - - reloc = *reloc_ptr_ptr; - sym = *reloc->sym_ptr_ptr; - - /* If the howto field has not been initialised then skip this reloc. - This assumes that an error message has been issued elsewhere. */ - if (reloc->howto == NULL) - continue; - - in.r_vaddr = (reloc->address - + bfd_get_section_vma (abfd, current)); - in.r_type = reloc->howto->type; - - if ((sym->flags & BSF_SECTION_SYM) == 0) - { - in.r_symndx = ecoff_get_sym_index (*reloc->sym_ptr_ptr); - in.r_extern = 1; - } - else - { - const char *name; - unsigned int j; - static struct - { - const char * name; - long r_symndx; - } - section_symndx [] = - { - { _TEXT, RELOC_SECTION_TEXT }, - { _RDATA, RELOC_SECTION_RDATA }, - { _DATA, RELOC_SECTION_DATA }, - { _SDATA, RELOC_SECTION_SDATA }, - { _SBSS, RELOC_SECTION_SBSS }, - { _BSS, RELOC_SECTION_BSS }, - { _INIT, RELOC_SECTION_INIT }, - { _LIT8, RELOC_SECTION_LIT8 }, - { _LIT4, RELOC_SECTION_LIT4 }, - { _XDATA, RELOC_SECTION_XDATA }, - { _PDATA, RELOC_SECTION_PDATA }, - { _FINI, RELOC_SECTION_FINI }, - { _LITA, RELOC_SECTION_LITA }, - { "*ABS*", RELOC_SECTION_ABS }, - { _RCONST, RELOC_SECTION_RCONST } - }; - - name = bfd_get_section_name (abfd, bfd_get_section (sym)); - - for (j = 0; j < ARRAY_SIZE (section_symndx); j++) - if (streq (name, section_symndx[j].name)) - { - in.r_symndx = section_symndx[j].r_symndx; - break; - } - - if (j == ARRAY_SIZE (section_symndx)) - abort (); - in.r_extern = 0; - } - - (*adjust_reloc_out) (abfd, reloc, &in); - - (*swap_reloc_out) (abfd, &in, (void *) out_ptr); - } - - if (bfd_seek (abfd, current->rel_filepos, SEEK_SET) != 0) - goto error_return; - amt = current->reloc_count * external_reloc_size; - if (bfd_bwrite (reloc_buff, amt, abfd) != amt) - goto error_return; - bfd_release (abfd, reloc_buff); - reloc_buff = NULL; - } - - /* Write out the symbolic debugging information. */ - if (bfd_get_symcount (abfd) > 0) - { - /* Write out the debugging information. */ - if (! bfd_ecoff_write_debug (abfd, debug, &backend->debug_swap, - ecoff_data (abfd)->sym_filepos)) - goto error_return; - } - } - - /* The .bss section of a demand paged executable must receive an - entire page. If there are symbols, the symbols will start on the - next page. If there are no symbols, we must fill out the page by - hand. */ - if (bfd_get_symcount (abfd) == 0 - && (abfd->flags & EXEC_P) != 0 - && (abfd->flags & D_PAGED) != 0) - { - char c; - - if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, - SEEK_SET) != 0) - goto error_return; - if (bfd_bread (&c, (bfd_size_type) 1, abfd) == 0) - c = 0; - if (bfd_seek (abfd, (file_ptr) ecoff_data (abfd)->sym_filepos - 1, - SEEK_SET) != 0) - goto error_return; - if (bfd_bwrite (&c, (bfd_size_type) 1, abfd) != 1) - goto error_return; - } - - if (reloc_buff != NULL) - bfd_release (abfd, reloc_buff); - if (buff != NULL) - free (buff); - return TRUE; - error_return: - if (reloc_buff != NULL) - bfd_release (abfd, reloc_buff); - if (buff != NULL) - free (buff); - return FALSE; -} - -/* Archive handling. ECOFF uses what appears to be a unique type of - archive header (armap). The byte ordering of the armap and the - contents are encoded in the name of the armap itself. At least for - now, we only support archives with the same byte ordering in the - armap and the contents. - - The first four bytes in the armap are the number of symbol - definitions. This is always a power of two. - - This is followed by the symbol definitions. Each symbol definition - occupies 8 bytes. The first four bytes are the offset from the - start of the armap strings to the null-terminated string naming - this symbol. The second four bytes are the file offset to the - archive member which defines this symbol. If the second four bytes - are 0, then this is not actually a symbol definition, and it should - be ignored. - - The symbols are hashed into the armap with a closed hashing scheme. - See the functions below for the details of the algorithm. - - After the symbol definitions comes four bytes holding the size of - the string table, followed by the string table itself. */ - -/* The name of an archive headers looks like this: - __________E[BL]E[BL]_ (with a trailing space). - The trailing space is changed to an X if the archive is changed to - indicate that the armap is out of date. - - The Alpha seems to use ________64E[BL]E[BL]_. */ - -#define ARMAP_BIG_ENDIAN 'B' -#define ARMAP_LITTLE_ENDIAN 'L' -#define ARMAP_MARKER 'E' -#define ARMAP_START_LENGTH 10 -#define ARMAP_HEADER_MARKER_INDEX 10 -#define ARMAP_HEADER_ENDIAN_INDEX 11 -#define ARMAP_OBJECT_MARKER_INDEX 12 -#define ARMAP_OBJECT_ENDIAN_INDEX 13 -#define ARMAP_END_INDEX 14 -#define ARMAP_END "_ " - -/* This is a magic number used in the hashing algorithm. */ -#define ARMAP_HASH_MAGIC 0x9dd68ab5 - -/* This returns the hash value to use for a string. It also sets - *REHASH to the rehash adjustment if the first slot is taken. SIZE - is the number of entries in the hash table, and HLOG is the log - base 2 of SIZE. */ - -static unsigned int -ecoff_armap_hash (const char *s, - unsigned int *rehash, - unsigned int size, - unsigned int hlog) -{ - unsigned int hash; - - if (hlog == 0) - return 0; - hash = *s++; - while (*s != '\0') - hash = ((hash >> 27) | (hash << 5)) + *s++; - hash *= ARMAP_HASH_MAGIC; - *rehash = (hash & (size - 1)) | 1; - return hash >> (32 - hlog); -} - -/* Read in the armap. */ - -bfd_boolean -_bfd_ecoff_slurp_armap (bfd *abfd) -{ - char nextname[17]; - unsigned int i; - struct areltdata *mapdata; - bfd_size_type parsed_size; - char *raw_armap; - struct artdata *ardata; - unsigned int count; - char *raw_ptr; - carsym *symdef_ptr; - char *stringbase; - bfd_size_type amt; - - /* Get the name of the first element. */ - i = bfd_bread ((void *) nextname, (bfd_size_type) 16, abfd); - if (i == 0) - return TRUE; - if (i != 16) - return FALSE; - - if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) - return FALSE; - - /* Irix 4.0.5F apparently can use either an ECOFF armap or a - standard COFF armap. We could move the ECOFF armap stuff into - bfd_slurp_armap, but that seems inappropriate since no other - target uses this format. Instead, we check directly for a COFF - armap. */ - if (CONST_STRNEQ (nextname, "/ ")) - return bfd_slurp_armap (abfd); - - /* See if the first element is an armap. */ - if (! strneq (nextname, ecoff_backend (abfd)->armap_start, ARMAP_START_LENGTH) - || nextname[ARMAP_HEADER_MARKER_INDEX] != ARMAP_MARKER - || (nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN - && nextname[ARMAP_HEADER_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) - || nextname[ARMAP_OBJECT_MARKER_INDEX] != ARMAP_MARKER - || (nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_BIG_ENDIAN - && nextname[ARMAP_OBJECT_ENDIAN_INDEX] != ARMAP_LITTLE_ENDIAN) - || ! strneq (nextname + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1)) - { - bfd_has_map (abfd) = FALSE; - return TRUE; - } - - /* Make sure we have the right byte ordering. */ - if (((nextname[ARMAP_HEADER_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) - ^ (bfd_header_big_endian (abfd))) - || ((nextname[ARMAP_OBJECT_ENDIAN_INDEX] == ARMAP_BIG_ENDIAN) - ^ (bfd_big_endian (abfd)))) - { - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - /* Read in the armap. */ - ardata = bfd_ardata (abfd); - mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); - if (mapdata == NULL) - return FALSE; - parsed_size = mapdata->parsed_size; - free (mapdata); - - raw_armap = (char *) bfd_alloc (abfd, parsed_size); - if (raw_armap == NULL) - return FALSE; - - if (bfd_bread ((void *) raw_armap, parsed_size, abfd) != parsed_size) - { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_malformed_archive); - bfd_release (abfd, (void *) raw_armap); - return FALSE; - } - - ardata->tdata = (void *) raw_armap; - - count = H_GET_32 (abfd, raw_armap); - - ardata->symdef_count = 0; - ardata->cache = NULL; - - /* This code used to overlay the symdefs over the raw archive data, - but that doesn't work on a 64 bit host. */ - stringbase = raw_armap + count * 8 + 8; - -#ifdef CHECK_ARMAP_HASH - { - unsigned int hlog; - - /* Double check that I have the hashing algorithm right by making - sure that every symbol can be looked up successfully. */ - hlog = 0; - for (i = 1; i < count; i <<= 1) - hlog++; - BFD_ASSERT (i == count); - - raw_ptr = raw_armap + 4; - for (i = 0; i < count; i++, raw_ptr += 8) - { - unsigned int name_offset, file_offset; - unsigned int hash, rehash, srch; - - name_offset = H_GET_32 (abfd, raw_ptr); - file_offset = H_GET_32 (abfd, (raw_ptr + 4)); - if (file_offset == 0) - continue; - hash = ecoff_armap_hash (stringbase + name_offset, &rehash, count, - hlog); - if (hash == i) - continue; - - /* See if we can rehash to this location. */ - for (srch = (hash + rehash) & (count - 1); - srch != hash && srch != i; - srch = (srch + rehash) & (count - 1)) - BFD_ASSERT (H_GET_32 (abfd, (raw_armap + 8 + srch * 8)) != 0); - BFD_ASSERT (srch == i); - } - } - -#endif /* CHECK_ARMAP_HASH */ - - raw_ptr = raw_armap + 4; - for (i = 0; i < count; i++, raw_ptr += 8) - if (H_GET_32 (abfd, (raw_ptr + 4)) != 0) - ++ardata->symdef_count; - - amt = ardata->symdef_count; - amt *= sizeof (carsym); - symdef_ptr = (carsym *) bfd_alloc (abfd, amt); - if (!symdef_ptr) - return FALSE; - - ardata->symdefs = symdef_ptr; - - raw_ptr = raw_armap + 4; - for (i = 0; i < count; i++, raw_ptr += 8) - { - unsigned int name_offset, file_offset; - - file_offset = H_GET_32 (abfd, (raw_ptr + 4)); - if (file_offset == 0) - continue; - name_offset = H_GET_32 (abfd, raw_ptr); - symdef_ptr->name = stringbase + name_offset; - symdef_ptr->file_offset = file_offset; - ++symdef_ptr; - } - - ardata->first_file_filepos = bfd_tell (abfd); - /* Pad to an even boundary. */ - ardata->first_file_filepos += ardata->first_file_filepos % 2; - - bfd_has_map (abfd) = TRUE; - - return TRUE; -} - -/* Write out an armap. */ - -bfd_boolean -_bfd_ecoff_write_armap (bfd *abfd, - unsigned int elength, - struct orl *map, - unsigned int orl_count, - int stridx) -{ - unsigned int hashsize, hashlog; - bfd_size_type symdefsize; - int padit; - unsigned int stringsize; - unsigned int mapsize; - file_ptr firstreal; - struct ar_hdr hdr; - struct stat statbuf; - unsigned int i; - bfd_byte temp[4]; - bfd_byte *hashtable; - bfd *current; - bfd *last_elt; - - /* Ultrix appears to use as a hash table size the least power of two - greater than twice the number of entries. */ - for (hashlog = 0; ((unsigned int) 1 << hashlog) <= 2 * orl_count; hashlog++) - ; - hashsize = 1 << hashlog; - - symdefsize = hashsize * 8; - padit = stridx % 2; - stringsize = stridx + padit; - - /* Include 8 bytes to store symdefsize and stringsize in output. */ - mapsize = symdefsize + stringsize + 8; - - firstreal = SARMAG + sizeof (struct ar_hdr) + mapsize + elength; - - memset ((void *) &hdr, 0, sizeof hdr); - - /* Work out the ECOFF armap name. */ - strcpy (hdr.ar_name, ecoff_backend (abfd)->armap_start); - hdr.ar_name[ARMAP_HEADER_MARKER_INDEX] = ARMAP_MARKER; - hdr.ar_name[ARMAP_HEADER_ENDIAN_INDEX] = - (bfd_header_big_endian (abfd) - ? ARMAP_BIG_ENDIAN - : ARMAP_LITTLE_ENDIAN); - hdr.ar_name[ARMAP_OBJECT_MARKER_INDEX] = ARMAP_MARKER; - hdr.ar_name[ARMAP_OBJECT_ENDIAN_INDEX] = - bfd_big_endian (abfd) ? ARMAP_BIG_ENDIAN : ARMAP_LITTLE_ENDIAN; - memcpy (hdr.ar_name + ARMAP_END_INDEX, ARMAP_END, sizeof ARMAP_END - 1); - - /* Write the timestamp of the archive header to be just a little bit - later than the timestamp of the file, otherwise the linker will - complain that the index is out of date. Actually, the Ultrix - linker just checks the archive name; the GNU linker may check the - date. */ - stat (abfd->filename, &statbuf); - _bfd_ar_spacepad (hdr.ar_date, sizeof (hdr.ar_date), "%ld", - (long) (statbuf.st_mtime + 60)); - - /* The DECstation uses zeroes for the uid, gid and mode of the - armap. */ - hdr.ar_uid[0] = '0'; - hdr.ar_gid[0] = '0'; - /* Building gcc ends up extracting the armap as a file - twice. */ - hdr.ar_mode[0] = '6'; - hdr.ar_mode[1] = '4'; - hdr.ar_mode[2] = '4'; - - _bfd_ar_spacepad (hdr.ar_size, sizeof (hdr.ar_size), "%-10ld", mapsize); - - hdr.ar_fmag[0] = '`'; - hdr.ar_fmag[1] = '\012'; - - /* Turn all null bytes in the header into spaces. */ - for (i = 0; i < sizeof (struct ar_hdr); i++) - if (((char *) (&hdr))[i] == '\0') - (((char *) (&hdr))[i]) = ' '; - - if (bfd_bwrite ((void *) &hdr, (bfd_size_type) sizeof (struct ar_hdr), abfd) - != sizeof (struct ar_hdr)) - return FALSE; - - H_PUT_32 (abfd, hashsize, temp); - if (bfd_bwrite ((void *) temp, (bfd_size_type) 4, abfd) != 4) - return FALSE; - - hashtable = (bfd_byte *) bfd_zalloc (abfd, symdefsize); - if (!hashtable) - return FALSE; - - current = abfd->archive_head; - last_elt = current; - for (i = 0; i < orl_count; i++) - { - unsigned int hash, rehash = 0; - - /* Advance firstreal to the file position of this archive - element. */ - if (map[i].u.abfd != last_elt) - { - do - { - firstreal += arelt_size (current) + sizeof (struct ar_hdr); - firstreal += firstreal % 2; - current = current->archive_next; - } - while (current != map[i].u.abfd); - } - - last_elt = current; - - hash = ecoff_armap_hash (*map[i].name, &rehash, hashsize, hashlog); - if (H_GET_32 (abfd, (hashtable + (hash * 8) + 4)) != 0) - { - unsigned int srch; - - /* The desired slot is already taken. */ - for (srch = (hash + rehash) & (hashsize - 1); - srch != hash; - srch = (srch + rehash) & (hashsize - 1)) - if (H_GET_32 (abfd, (hashtable + (srch * 8) + 4)) == 0) - break; - - BFD_ASSERT (srch != hash); - - hash = srch; - } - - H_PUT_32 (abfd, map[i].namidx, (hashtable + hash * 8)); - H_PUT_32 (abfd, firstreal, (hashtable + hash * 8 + 4)); - } - - if (bfd_bwrite ((void *) hashtable, symdefsize, abfd) != symdefsize) - return FALSE; - - bfd_release (abfd, hashtable); - - /* Now write the strings. */ - H_PUT_32 (abfd, stringsize, temp); - if (bfd_bwrite ((void *) temp, (bfd_size_type) 4, abfd) != 4) - return FALSE; - for (i = 0; i < orl_count; i++) - { - bfd_size_type len; - - len = strlen (*map[i].name) + 1; - if (bfd_bwrite ((void *) (*map[i].name), len, abfd) != len) - return FALSE; - } - - /* The spec sez this should be a newline. But in order to be - bug-compatible for DECstation ar we use a null. */ - if (padit) - { - if (bfd_bwrite ("", (bfd_size_type) 1, abfd) != 1) - return FALSE; - } - - return TRUE; -} - -/* ECOFF linker code. */ - -/* Routine to create an entry in an ECOFF link hash table. */ - -static struct bfd_hash_entry * -ecoff_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct ecoff_link_hash_entry *ret = (struct ecoff_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = ((struct ecoff_link_hash_entry *) - bfd_hash_allocate (table, sizeof (struct ecoff_link_hash_entry))); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct ecoff_link_hash_entry *) - _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - - if (ret) - { - /* Set local fields. */ - ret->indx = -1; - ret->abfd = NULL; - ret->written = 0; - ret->small = 0; - } - memset ((void *) &ret->esym, 0, sizeof ret->esym); - - return (struct bfd_hash_entry *) ret; -} - -/* Create an ECOFF link hash table. */ - -struct bfd_link_hash_table * -_bfd_ecoff_bfd_link_hash_table_create (bfd *abfd) -{ - struct ecoff_link_hash_table *ret; - bfd_size_type amt = sizeof (struct ecoff_link_hash_table); - - ret = (struct ecoff_link_hash_table *) bfd_malloc (amt); - if (ret == NULL) - return NULL; - if (!_bfd_link_hash_table_init (&ret->root, abfd, - ecoff_link_hash_newfunc, - sizeof (struct ecoff_link_hash_entry))) - { - free (ret); - return NULL; - } - return &ret->root; -} - -/* Look up an entry in an ECOFF link hash table. */ - -#define ecoff_link_hash_lookup(table, string, create, copy, follow) \ - ((struct ecoff_link_hash_entry *) \ - bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) - -/* Get the ECOFF link hash table from the info structure. This is - just a cast. */ - -#define ecoff_hash_table(p) ((struct ecoff_link_hash_table *) ((p)->hash)) - -/* Add the external symbols of an object file to the global linker - hash table. The external symbols and strings we are passed are - just allocated on the stack, and will be discarded. We must - explicitly save any information we may need later on in the link. - We do not want to read the external symbol information again. */ - -static bfd_boolean -ecoff_link_add_externals (bfd *abfd, - struct bfd_link_info *info, - void * external_ext, - char *ssext) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - void (* const swap_ext_in) (bfd *, void *, EXTR *) - = backend->debug_swap.swap_ext_in; - bfd_size_type external_ext_size = backend->debug_swap.external_ext_size; - unsigned long ext_count; - struct bfd_link_hash_entry **sym_hash; - char *ext_ptr; - char *ext_end; - bfd_size_type amt; - - ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax; - - amt = ext_count; - amt *= sizeof (struct bfd_link_hash_entry *); - sym_hash = (struct bfd_link_hash_entry **) bfd_alloc (abfd, amt); - if (!sym_hash) - return FALSE; - ecoff_data (abfd)->sym_hashes = (struct ecoff_link_hash_entry **) sym_hash; - - ext_ptr = (char *) external_ext; - ext_end = ext_ptr + ext_count * external_ext_size; - for (; ext_ptr < ext_end; ext_ptr += external_ext_size, sym_hash++) - { - EXTR esym; - bfd_boolean skip; - bfd_vma value; - asection *section; - const char *name; - struct ecoff_link_hash_entry *h; - - *sym_hash = NULL; - - (*swap_ext_in) (abfd, (void *) ext_ptr, &esym); - - /* Skip debugging symbols. */ - skip = FALSE; - switch (esym.asym.st) - { - case stGlobal: - case stStatic: - case stLabel: - case stProc: - case stStaticProc: - break; - default: - skip = TRUE; - break; - } - - if (skip) - continue; - - /* Get the information for this symbol. */ - value = esym.asym.value; - switch (esym.asym.sc) - { - default: - case scNil: - case scRegister: - case scCdbLocal: - case scBits: - case scCdbSystem: - case scRegImage: - case scInfo: - case scUserStruct: - case scVar: - case scVarRegister: - case scVariant: - case scBasedVar: - case scXData: - case scPData: - section = NULL; - break; - case scText: - section = bfd_make_section_old_way (abfd, _TEXT); - value -= section->vma; - break; - case scData: - section = bfd_make_section_old_way (abfd, _DATA); - value -= section->vma; - break; - case scBss: - section = bfd_make_section_old_way (abfd, _BSS); - value -= section->vma; - break; - case scAbs: - section = bfd_abs_section_ptr; - break; - case scUndefined: - section = bfd_und_section_ptr; - break; - case scSData: - section = bfd_make_section_old_way (abfd, _SDATA); - value -= section->vma; - break; - case scSBss: - section = bfd_make_section_old_way (abfd, _SBSS); - value -= section->vma; - break; - case scRData: - section = bfd_make_section_old_way (abfd, _RDATA); - value -= section->vma; - break; - case scCommon: - if (value > ecoff_data (abfd)->gp_size) - { - section = bfd_com_section_ptr; - break; - } - /* Fall through. */ - case scSCommon: - if (ecoff_scom_section.name == NULL) - { - /* Initialize the small common section. */ - ecoff_scom_section.name = SCOMMON; - ecoff_scom_section.flags = SEC_IS_COMMON; - ecoff_scom_section.output_section = &ecoff_scom_section; - ecoff_scom_section.symbol = &ecoff_scom_symbol; - ecoff_scom_section.symbol_ptr_ptr = &ecoff_scom_symbol_ptr; - ecoff_scom_symbol.name = SCOMMON; - ecoff_scom_symbol.flags = BSF_SECTION_SYM; - ecoff_scom_symbol.section = &ecoff_scom_section; - ecoff_scom_symbol_ptr = &ecoff_scom_symbol; - } - section = &ecoff_scom_section; - break; - case scSUndefined: - section = bfd_und_section_ptr; - break; - case scInit: - section = bfd_make_section_old_way (abfd, _INIT); - value -= section->vma; - break; - case scFini: - section = bfd_make_section_old_way (abfd, _FINI); - value -= section->vma; - break; - case scRConst: - section = bfd_make_section_old_way (abfd, _RCONST); - value -= section->vma; - break; - } - - if (section == NULL) - continue; - - name = ssext + esym.asym.iss; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, name, - (flagword) (esym.weakext ? BSF_WEAK : BSF_GLOBAL), - section, value, NULL, TRUE, TRUE, sym_hash))) - return FALSE; - - h = (struct ecoff_link_hash_entry *) *sym_hash; - - /* If we are building an ECOFF hash table, save the external - symbol information. */ - if (bfd_get_flavour (info->output_bfd) == bfd_get_flavour (abfd)) - { - if (h->abfd == NULL - || (! bfd_is_und_section (section) - && (! bfd_is_com_section (section) - || (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak)))) - { - h->abfd = abfd; - h->esym = esym; - } - - /* Remember whether this symbol was small undefined. */ - if (esym.asym.sc == scSUndefined) - h->small = 1; - - /* If this symbol was ever small undefined, it needs to wind - up in a GP relative section. We can't control the - section of a defined symbol, but we can control the - section of a common symbol. This case is actually needed - on Ultrix 4.2 to handle the symbol cred in -lckrb. */ - if (h->small - && h->root.type == bfd_link_hash_common - && streq (h->root.u.c.p->section->name, SCOMMON)) - { - h->root.u.c.p->section = bfd_make_section_old_way (abfd, - SCOMMON); - h->root.u.c.p->section->flags = SEC_ALLOC; - if (h->esym.asym.sc == scCommon) - h->esym.asym.sc = scSCommon; - } - } - } - - return TRUE; -} - -/* Add symbols from an ECOFF object file to the global linker hash - table. */ - -static bfd_boolean -ecoff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) -{ - HDRR *symhdr; - bfd_size_type external_ext_size; - void * external_ext = NULL; - bfd_size_type esize; - char *ssext = NULL; - bfd_boolean result; - - if (! ecoff_slurp_symbolic_header (abfd)) - return FALSE; - - /* If there are no symbols, we don't want it. */ - if (bfd_get_symcount (abfd) == 0) - return TRUE; - - symhdr = &ecoff_data (abfd)->debug_info.symbolic_header; - - /* Read in the external symbols and external strings. */ - external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size; - esize = symhdr->iextMax * external_ext_size; - external_ext = bfd_malloc (esize); - if (external_ext == NULL && esize != 0) - goto error_return; - - if (bfd_seek (abfd, (file_ptr) symhdr->cbExtOffset, SEEK_SET) != 0 - || bfd_bread (external_ext, esize, abfd) != esize) - goto error_return; - - ssext = (char *) bfd_malloc ((bfd_size_type) symhdr->issExtMax); - if (ssext == NULL && symhdr->issExtMax != 0) - goto error_return; - - if (bfd_seek (abfd, (file_ptr) symhdr->cbSsExtOffset, SEEK_SET) != 0 - || (bfd_bread (ssext, (bfd_size_type) symhdr->issExtMax, abfd) - != (bfd_size_type) symhdr->issExtMax)) - goto error_return; - - result = ecoff_link_add_externals (abfd, info, external_ext, ssext); - - if (ssext != NULL) - free (ssext); - if (external_ext != NULL) - free (external_ext); - return result; - - error_return: - if (ssext != NULL) - free (ssext); - if (external_ext != NULL) - free (external_ext); - return FALSE; -} - -/* This is called if we used _bfd_generic_link_add_archive_symbols - because we were not dealing with an ECOFF archive. */ - -static bfd_boolean -ecoff_link_check_archive_element (bfd *abfd, - struct bfd_link_info *info, - struct bfd_link_hash_entry *h, - const char *name, - bfd_boolean *pneeded) -{ - *pneeded = FALSE; - - /* Unlike the generic linker, we do not pull in elements because - of common symbols. */ - if (h->type != bfd_link_hash_undefined) - return TRUE; - - /* Include this element? */ - if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd)) - return TRUE; - *pneeded = TRUE; - - return ecoff_link_add_object_symbols (abfd, info); -} - -/* Add the symbols from an archive file to the global hash table. - This looks through the undefined symbols, looks each one up in the - archive hash table, and adds any associated object file. We do not - use _bfd_generic_link_add_archive_symbols because ECOFF archives - already have a hash table, so there is no reason to construct - another one. */ - -static bfd_boolean -ecoff_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - const bfd_byte *raw_armap; - struct bfd_link_hash_entry **pundef; - unsigned int armap_count; - unsigned int armap_log; - unsigned int i; - const bfd_byte *hashtable; - const char *stringbase; - - 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; - } - - /* If we don't have any raw data for this archive, as can happen on - Irix 4.0.5F, we call the generic routine. - FIXME: We should be more clever about this, since someday tdata - may get to something for a generic archive. */ - raw_armap = (const bfd_byte *) bfd_ardata (abfd)->tdata; - if (raw_armap == NULL) - return (_bfd_generic_link_add_archive_symbols - (abfd, info, ecoff_link_check_archive_element)); - - armap_count = H_GET_32 (abfd, raw_armap); - - armap_log = 0; - for (i = 1; i < armap_count; i <<= 1) - armap_log++; - BFD_ASSERT (i == armap_count); - - hashtable = raw_armap + 4; - stringbase = (const char *) raw_armap + armap_count * 8 + 8; - - /* Look through the list of undefined symbols. */ - pundef = &info->hash->undefs; - while (*pundef != NULL) - { - struct bfd_link_hash_entry *h; - unsigned int hash, rehash = 0; - unsigned int file_offset; - const char *name; - bfd *element; - - 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. */ - if (*pundef != info->hash->undefs_tail) - *pundef = (*pundef)->u.undef.next; - else - pundef = &(*pundef)->u.undef.next; - continue; - } - - /* Native ECOFF linkers do not pull in archive elements merely - to satisfy common definitions, so neither do we. We leave - them on the list, though, in case we are linking against some - other object format. */ - if (h->type != bfd_link_hash_undefined) - { - pundef = &(*pundef)->u.undef.next; - continue; - } - - /* Look for this symbol in the archive hash table. */ - hash = ecoff_armap_hash (h->root.string, &rehash, armap_count, - armap_log); - - file_offset = H_GET_32 (abfd, hashtable + (hash * 8) + 4); - if (file_offset == 0) - { - /* Nothing in this slot. */ - pundef = &(*pundef)->u.undef.next; - continue; - } - - name = stringbase + H_GET_32 (abfd, hashtable + (hash * 8)); - if (name[0] != h->root.string[0] - || ! streq (name, h->root.string)) - { - unsigned int srch; - bfd_boolean found; - - /* That was the wrong symbol. Try rehashing. */ - found = FALSE; - for (srch = (hash + rehash) & (armap_count - 1); - srch != hash; - srch = (srch + rehash) & (armap_count - 1)) - { - file_offset = H_GET_32 (abfd, hashtable + (srch * 8) + 4); - if (file_offset == 0) - break; - name = stringbase + H_GET_32 (abfd, hashtable + (srch * 8)); - if (name[0] == h->root.string[0] - && streq (name, h->root.string)) - { - found = TRUE; - break; - } - } - - if (! found) - { - pundef = &(*pundef)->u.undef.next; - continue; - } - - hash = srch; - } - - element = (*backend->get_elt_at_filepos) (abfd, (file_ptr) file_offset); - if (element == NULL) - return FALSE; - - if (! bfd_check_format (element, bfd_object)) - return FALSE; - - /* Unlike the generic linker, we know that this element provides - a definition for an undefined symbol and we know that we want - to include it. We don't need to check anything. */ - if (!(*info->callbacks - ->add_archive_element) (info, element, name, &element)) - return FALSE; - if (! ecoff_link_add_object_symbols (element, info)) - return FALSE; - - pundef = &(*pundef)->u.undef.next; - } - - return TRUE; -} - -/* Given an ECOFF BFD, add symbols to the global hash table as - appropriate. */ - -bfd_boolean -_bfd_ecoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) -{ - switch (bfd_get_format (abfd)) - { - case bfd_object: - return ecoff_link_add_object_symbols (abfd, info); - case bfd_archive: - return ecoff_link_add_archive_symbols (abfd, info); - default: - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } -} - - -/* ECOFF final link routines. */ - -/* Structure used to pass information to ecoff_link_write_external. */ - -struct extsym_info -{ - bfd *abfd; - struct bfd_link_info *info; -}; - -/* Accumulate the debugging information for an input BFD into the - output BFD. This must read in the symbolic information of the - input BFD. */ - -static bfd_boolean -ecoff_final_link_debug_accumulate (bfd *output_bfd, - bfd *input_bfd, - struct bfd_link_info *info, - void * handle) -{ - struct ecoff_debug_info * const debug = &ecoff_data (input_bfd)->debug_info; - const struct ecoff_debug_swap * const swap = - &ecoff_backend (input_bfd)->debug_swap; - HDRR *symhdr = &debug->symbolic_header; - bfd_boolean ret; - -#define READ(ptr, offset, count, size, type) \ - if (symhdr->count == 0) \ - debug->ptr = NULL; \ - else \ - { \ - bfd_size_type amt = (bfd_size_type) size * symhdr->count; \ - debug->ptr = (type) bfd_malloc (amt); \ - if (debug->ptr == NULL) \ - { \ - ret = FALSE; \ - goto return_something; \ - } \ - if (bfd_seek (input_bfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \ - || bfd_bread (debug->ptr, amt, input_bfd) != amt) \ - { \ - ret = FALSE; \ - goto return_something; \ - } \ - } - - /* If raw_syments is not NULL, then the data was already by read by - _bfd_ecoff_slurp_symbolic_info. */ - if (ecoff_data (input_bfd)->raw_syments == NULL) - { - READ (line, cbLineOffset, cbLine, sizeof (unsigned char), - unsigned char *); - READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *); - READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *); - READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *); - READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *); - READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), - union aux_ext *); - READ (ss, cbSsOffset, issMax, sizeof (char), char *); - READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *); - READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *); - } -#undef READ - - /* We do not read the external strings or the external symbols. */ - - ret = (bfd_ecoff_debug_accumulate - (handle, output_bfd, &ecoff_data (output_bfd)->debug_info, - &ecoff_backend (output_bfd)->debug_swap, - input_bfd, debug, swap, info)); - - return_something: - if (ecoff_data (input_bfd)->raw_syments == NULL) - { - if (debug->line != NULL) - free (debug->line); - if (debug->external_dnr != NULL) - free (debug->external_dnr); - if (debug->external_pdr != NULL) - free (debug->external_pdr); - if (debug->external_sym != NULL) - free (debug->external_sym); - if (debug->external_opt != NULL) - free (debug->external_opt); - if (debug->external_aux != NULL) - free (debug->external_aux); - if (debug->ss != NULL) - free (debug->ss); - if (debug->external_fdr != NULL) - free (debug->external_fdr); - if (debug->external_rfd != NULL) - free (debug->external_rfd); - - /* Make sure we don't accidentally follow one of these pointers - into freed memory. */ - debug->line = NULL; - debug->external_dnr = NULL; - debug->external_pdr = NULL; - debug->external_sym = NULL; - debug->external_opt = NULL; - debug->external_aux = NULL; - debug->ss = NULL; - debug->external_fdr = NULL; - debug->external_rfd = NULL; - } - - return ret; -} - -/* Relocate and write an ECOFF section into an ECOFF output file. */ - -static bfd_boolean -ecoff_indirect_link_order (bfd *output_bfd, - struct bfd_link_info *info, - asection *output_section, - struct bfd_link_order *link_order) -{ - asection *input_section; - bfd *input_bfd; - bfd_byte *contents = NULL; - bfd_size_type external_reloc_size; - bfd_size_type external_relocs_size; - void * external_relocs = NULL; - - 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); - - /* Get the section contents. */ - if (!bfd_malloc_and_get_section (input_bfd, input_section, &contents)) - goto error_return; - - /* Get the relocs. If we are relaxing MIPS code, they will already - have been read in. Otherwise, we read them in now. */ - external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size; - external_relocs_size = external_reloc_size * input_section->reloc_count; - - external_relocs = bfd_malloc (external_relocs_size); - if (external_relocs == NULL && external_relocs_size != 0) - goto error_return; - - if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 - || (bfd_bread (external_relocs, external_relocs_size, input_bfd) - != external_relocs_size)) - goto error_return; - - /* Relocate the section contents. */ - if (! ((*ecoff_backend (input_bfd)->relocate_section) - (output_bfd, info, input_bfd, input_section, contents, - external_relocs))) - goto error_return; - - /* Write out the relocated section. */ - if (! bfd_set_section_contents (output_bfd, - output_section, - contents, - input_section->output_offset, - input_section->size)) - goto error_return; - - /* If we are producing relocatable output, the relocs were - modified, and we write them out now. We use the reloc_count - field of output_section to keep track of the number of relocs we - have output so far. */ - if (bfd_link_relocatable (info)) - { - file_ptr pos = (output_section->rel_filepos - + output_section->reloc_count * external_reloc_size); - if (bfd_seek (output_bfd, pos, SEEK_SET) != 0 - || (bfd_bwrite (external_relocs, external_relocs_size, output_bfd) - != external_relocs_size)) - goto error_return; - output_section->reloc_count += input_section->reloc_count; - } - - if (contents != NULL) - free (contents); - if (external_relocs != NULL) - free (external_relocs); - return TRUE; - - error_return: - if (contents != NULL) - free (contents); - if (external_relocs != NULL) - free (external_relocs); - return FALSE; -} - -/* Generate a reloc when linking an ECOFF file. This is a reloc - requested by the linker, and does come from any input file. This - is used to build constructor and destructor tables when linking - with -Ur. */ - -static bfd_boolean -ecoff_reloc_link_order (bfd *output_bfd, - struct bfd_link_info *info, - asection *output_section, - struct bfd_link_order *link_order) -{ - enum bfd_link_order_type type; - asection *section; - bfd_vma addend; - arelent rel; - struct internal_reloc in; - bfd_size_type external_reloc_size; - bfd_byte *rbuf; - bfd_boolean ok; - file_ptr pos; - - type = link_order->type; - section = NULL; - addend = link_order->u.reloc.p->addend; - - /* We set up an arelent to pass to the backend adjust_reloc_out - routine. */ - rel.address = link_order->offset; - - rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); - if (rel.howto == 0) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (type == bfd_section_reloc_link_order) - { - section = link_order->u.reloc.p->u.section; - rel.sym_ptr_ptr = section->symbol_ptr_ptr; - } - else - { - struct bfd_link_hash_entry *h; - - /* Treat a reloc against a defined symbol as though it were - actually against the section. */ - h = bfd_wrapped_link_hash_lookup (output_bfd, info, - link_order->u.reloc.p->u.name, - FALSE, FALSE, FALSE); - if (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - { - type = bfd_section_reloc_link_order; - section = h->u.def.section->output_section; - /* 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->vma + h->u.def.section->output_offset; - } - else - { - /* We can't set up a reloc against a symbol correctly, - because we have no asymbol structure. Currently no - adjust_reloc_out routine cares. */ - rel.sym_ptr_ptr = NULL; - } - } - - /* All ECOFF relocs are in-place. Put the addend into the object - file. */ - - BFD_ASSERT (rel.howto->partial_inplace); - if (addend != 0) - { - bfd_size_type size; - bfd_reloc_status_type rstat; - bfd_byte *buf; - - size = bfd_get_reloc_size (rel.howto); - buf = (bfd_byte *) bfd_zmalloc (size); - if (buf == NULL && size != 0) - return FALSE; - rstat = _bfd_relocate_contents (rel.howto, output_bfd, - (bfd_vma) addend, buf); - switch (rstat) - { - case bfd_reloc_ok: - break; - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, NULL, - (link_order->type == bfd_section_reloc_link_order - ? bfd_section_name (output_bfd, section) - : link_order->u.reloc.p->u.name), - rel.howto->name, addend, NULL, NULL, (bfd_vma) 0); - break; - } - ok = bfd_set_section_contents (output_bfd, output_section, (void *) buf, - (file_ptr) link_order->offset, size); - free (buf); - if (! ok) - return FALSE; - } - - rel.addend = 0; - - /* Move the information into an internal_reloc structure. */ - in.r_vaddr = (rel.address - + bfd_get_section_vma (output_bfd, output_section)); - in.r_type = rel.howto->type; - - if (type == bfd_symbol_reloc_link_order) - { - struct ecoff_link_hash_entry *h; - - h = ((struct ecoff_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->indx != -1) - in.r_symndx = h->indx; - else - { - (*info->callbacks->unattached_reloc) - (info, link_order->u.reloc.p->u.name, NULL, NULL, (bfd_vma) 0); - in.r_symndx = 0; - } - in.r_extern = 1; - } - else - { - const char *name; - unsigned int i; - static struct - { - const char * name; - long r_symndx; - } - section_symndx [] = - { - { _TEXT, RELOC_SECTION_TEXT }, - { _RDATA, RELOC_SECTION_RDATA }, - { _DATA, RELOC_SECTION_DATA }, - { _SDATA, RELOC_SECTION_SDATA }, - { _SBSS, RELOC_SECTION_SBSS }, - { _BSS, RELOC_SECTION_BSS }, - { _INIT, RELOC_SECTION_INIT }, - { _LIT8, RELOC_SECTION_LIT8 }, - { _LIT4, RELOC_SECTION_LIT4 }, - { _XDATA, RELOC_SECTION_XDATA }, - { _PDATA, RELOC_SECTION_PDATA }, - { _FINI, RELOC_SECTION_FINI }, - { _LITA, RELOC_SECTION_LITA }, - { "*ABS*", RELOC_SECTION_ABS }, - { _RCONST, RELOC_SECTION_RCONST } - }; - - name = bfd_get_section_name (output_bfd, section); - - for (i = 0; i < ARRAY_SIZE (section_symndx); i++) - if (streq (name, section_symndx[i].name)) - { - in.r_symndx = section_symndx[i].r_symndx; - break; - } - - if (i == ARRAY_SIZE (section_symndx)) - abort (); - - in.r_extern = 0; - } - - /* Let the BFD backend adjust the reloc. */ - (*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in); - - /* Get some memory and swap out the reloc. */ - external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size; - rbuf = (bfd_byte *) bfd_malloc (external_reloc_size); - if (rbuf == NULL) - return FALSE; - - (*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (void *) rbuf); - - pos = (output_section->rel_filepos - + output_section->reloc_count * external_reloc_size); - ok = (bfd_seek (output_bfd, pos, SEEK_SET) == 0 - && (bfd_bwrite ((void *) rbuf, external_reloc_size, output_bfd) - == external_reloc_size)); - - if (ok) - ++output_section->reloc_count; - - free (rbuf); - - return ok; -} - -/* Put out information for an external symbol. These come only from - the hash table. */ - -static bfd_boolean -ecoff_link_write_external (struct bfd_hash_entry *bh, void * data) -{ - struct ecoff_link_hash_entry *h = (struct ecoff_link_hash_entry *) bh; - struct extsym_info *einfo = (struct extsym_info *) data; - bfd *output_bfd = einfo->abfd; - bfd_boolean strip; - - if (h->root.type == bfd_link_hash_warning) - { - h = (struct ecoff_link_hash_entry *) h->root.u.i.link; - if (h->root.type == bfd_link_hash_new) - return TRUE; - } - - /* We need to check if this symbol is being stripped. */ - if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - strip = FALSE; - else if (einfo->info->strip == strip_all - || (einfo->info->strip == strip_some - && bfd_hash_lookup (einfo->info->keep_hash, - h->root.root.string, - FALSE, FALSE) == NULL)) - strip = TRUE; - else - strip = FALSE; - - if (strip || h->written) - return TRUE; - - if (h->abfd == NULL) - { - h->esym.jmptbl = 0; - h->esym.cobol_main = 0; - h->esym.weakext = 0; - h->esym.reserved = 0; - h->esym.ifd = ifdNil; - h->esym.asym.value = 0; - h->esym.asym.st = stGlobal; - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - h->esym.asym.sc = scAbs; - else - { - asection *output_section; - const char *name; - unsigned int i; - static struct - { - const char * name; - int sc; - } - section_storage_classes [] = - { - { _TEXT, scText }, - { _DATA, scData }, - { _SDATA, scSData }, - { _RDATA, scRData }, - { _BSS, scBss }, - { _SBSS, scSBss }, - { _INIT, scInit }, - { _FINI, scFini }, - { _PDATA, scPData }, - { _XDATA, scXData }, - { _RCONST, scRConst } - }; - - output_section = h->root.u.def.section->output_section; - name = bfd_section_name (output_section->owner, output_section); - - for (i = 0; i < ARRAY_SIZE (section_storage_classes); i++) - if (streq (name, section_storage_classes[i].name)) - { - h->esym.asym.sc = section_storage_classes[i].sc; - break; - } - - if (i == ARRAY_SIZE (section_storage_classes)) - h->esym.asym.sc = scAbs; - } - - h->esym.asym.reserved = 0; - h->esym.asym.index = indexNil; - } - else if (h->esym.ifd != -1) - { - struct ecoff_debug_info *debug; - - /* Adjust the FDR index for the symbol by that used for the - input BFD. */ - debug = &ecoff_data (h->abfd)->debug_info; - BFD_ASSERT (h->esym.ifd >= 0 - && h->esym.ifd < debug->symbolic_header.ifdMax); - h->esym.ifd = debug->ifdmap[h->esym.ifd]; - } - - switch (h->root.type) - { - default: - case bfd_link_hash_warning: - case bfd_link_hash_new: - abort (); - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - if (h->esym.asym.sc != scUndefined - && h->esym.asym.sc != scSUndefined) - h->esym.asym.sc = scUndefined; - break; - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - if (h->esym.asym.sc == scUndefined - || h->esym.asym.sc == scSUndefined) - h->esym.asym.sc = scAbs; - else if (h->esym.asym.sc == scCommon) - h->esym.asym.sc = scBss; - else if (h->esym.asym.sc == scSCommon) - h->esym.asym.sc = scSBss; - h->esym.asym.value = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - break; - case bfd_link_hash_common: - if (h->esym.asym.sc != scCommon - && h->esym.asym.sc != scSCommon) - h->esym.asym.sc = scCommon; - h->esym.asym.value = h->root.u.c.size; - break; - case bfd_link_hash_indirect: - /* We ignore these symbols, since the indirected symbol is - already in the hash table. */ - return TRUE; - } - - /* bfd_ecoff_debug_one_external uses iextMax to keep track of the - symbol number. */ - h->indx = ecoff_data (output_bfd)->debug_info.symbolic_header.iextMax; - h->written = 1; - - return (bfd_ecoff_debug_one_external - (output_bfd, &ecoff_data (output_bfd)->debug_info, - &ecoff_backend (output_bfd)->debug_swap, h->root.root.string, - &h->esym)); -} - -/* ECOFF final link routine. This looks through all the input BFDs - and gathers together all the debugging information, and then - processes all the link order information. This may cause it to - close and reopen some input BFDs; I'll see how bad this is. */ - -bfd_boolean -_bfd_ecoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info) -{ - const struct ecoff_backend_data * const backend = ecoff_backend (abfd); - struct ecoff_debug_info * const debug = &ecoff_data (abfd)->debug_info; - HDRR *symhdr; - void * handle; - bfd *input_bfd; - asection *o; - struct bfd_link_order *p; - struct extsym_info einfo; - - /* We accumulate the debugging information counts in the symbolic - header. */ - symhdr = &debug->symbolic_header; - symhdr->vstamp = 0; - symhdr->ilineMax = 0; - symhdr->cbLine = 0; - symhdr->idnMax = 0; - symhdr->ipdMax = 0; - symhdr->isymMax = 0; - symhdr->ioptMax = 0; - symhdr->iauxMax = 0; - symhdr->issMax = 0; - symhdr->issExtMax = 0; - symhdr->ifdMax = 0; - symhdr->crfd = 0; - symhdr->iextMax = 0; - - /* We accumulate the debugging information itself in the debug_info - structure. */ - debug->line = NULL; - debug->external_dnr = NULL; - debug->external_pdr = NULL; - debug->external_sym = NULL; - debug->external_opt = NULL; - debug->external_aux = NULL; - debug->ss = NULL; - debug->ssext = debug->ssext_end = NULL; - debug->external_fdr = NULL; - debug->external_rfd = NULL; - debug->external_ext = debug->external_ext_end = NULL; - - handle = bfd_ecoff_debug_init (abfd, debug, &backend->debug_swap, info); - if (handle == NULL) - return FALSE; - - /* Accumulate the debugging symbols from each input BFD. */ - for (input_bfd = info->input_bfds; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_boolean ret; - - if (bfd_get_flavour (input_bfd) == bfd_target_ecoff_flavour) - { - /* Arbitrarily set the symbolic header vstamp to the vstamp - of the first object file in the link. */ - if (symhdr->vstamp == 0) - symhdr->vstamp - = ecoff_data (input_bfd)->debug_info.symbolic_header.vstamp; - ret = ecoff_final_link_debug_accumulate (abfd, input_bfd, info, - handle); - } - else - ret = bfd_ecoff_debug_accumulate_other (handle, abfd, - debug, &backend->debug_swap, - input_bfd, info); - if (! ret) - return FALSE; - - /* Combine the register masks. */ - ecoff_data (abfd)->gprmask |= ecoff_data (input_bfd)->gprmask; - ecoff_data (abfd)->fprmask |= ecoff_data (input_bfd)->fprmask; - ecoff_data (abfd)->cprmask[0] |= ecoff_data (input_bfd)->cprmask[0]; - ecoff_data (abfd)->cprmask[1] |= ecoff_data (input_bfd)->cprmask[1]; - ecoff_data (abfd)->cprmask[2] |= ecoff_data (input_bfd)->cprmask[2]; - ecoff_data (abfd)->cprmask[3] |= ecoff_data (input_bfd)->cprmask[3]; - } - - /* Write out the external symbols. */ - einfo.abfd = abfd; - einfo.info = info; - bfd_hash_traverse (&info->hash->table, ecoff_link_write_external, &einfo); - - if (bfd_link_relocatable (info)) - { - /* We need to make a pass over the link_orders to count up the - number of relocations we will need to output, so that we know - how much space they will take up. */ - 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_indirect_link_order) - o->reloc_count += p->u.indirect.section->reloc_count; - else if (p->type == bfd_section_reloc_link_order - || p->type == bfd_symbol_reloc_link_order) - ++o->reloc_count; - } - } - - /* Compute the reloc and symbol file positions. */ - ecoff_compute_reloc_file_positions (abfd); - - /* Write out the debugging information. */ - if (! bfd_ecoff_write_accumulated_debug (handle, abfd, debug, - &backend->debug_swap, info, - ecoff_data (abfd)->sym_filepos)) - return FALSE; - - bfd_ecoff_debug_free (handle, abfd, debug, &backend->debug_swap, info); - - if (bfd_link_relocatable (info)) - { - /* Now reset the reloc_count field of the sections in the output - BFD to 0, so that we can use them to keep track of how many - relocs we have output thus far. */ - for (o = abfd->sections; o != NULL; o = o->next) - o->reloc_count = 0; - } - - /* Get a value for the GP register. */ - if (ecoff_data (abfd)->gp == 0) - { - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); - if (h != NULL - && h->type == bfd_link_hash_defined) - ecoff_data (abfd)->gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - else if (bfd_link_relocatable (info)) - { - bfd_vma lo; - - /* Make up a value. */ - lo = (bfd_vma) -1; - for (o = abfd->sections; o != NULL; o = o->next) - { - if (o->vma < lo - && (streq (o->name, _SBSS) - || streq (o->name, _SDATA) - || streq (o->name, _LIT4) - || streq (o->name, _LIT8) - || streq (o->name, _LITA))) - lo = o->vma; - } - ecoff_data (abfd)->gp = lo + 0x8000; - } - else - { - /* If the relocate_section function needs to do a reloc - involving the GP value, it should make a reloc_dangerous - callback to warn that GP is not defined. */ - } - } - - 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 (p->u.indirect.section->owner) - == bfd_target_ecoff_flavour)) - { - if (! ecoff_indirect_link_order (abfd, info, o, p)) - return FALSE; - } - else if (p->type == bfd_section_reloc_link_order - || p->type == bfd_symbol_reloc_link_order) - { - if (! ecoff_reloc_link_order (abfd, info, o, p)) - return FALSE; - } - else - { - if (! _bfd_default_link_order (abfd, info, o, p)) - return FALSE; - } - } - } - - bfd_get_symcount (abfd) = symhdr->iextMax + symhdr->isymMax; - - ecoff_data (abfd)->linker = TRUE; - - return TRUE; -} diff --git a/sdcc/support/sdbinutils/bfd/ecofflink.c b/sdcc/support/sdbinutils/bfd/ecofflink.c deleted file mode 100644 index 6e25ed030..000000000 --- a/sdcc/support/sdbinutils/bfd/ecofflink.c +++ /dev/null @@ -1,2477 +0,0 @@ -/* Routines to link ECOFF debugging information. - Copyright (C) 1993-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "objalloc.h" -#include "aout/stab_gnu.h" -#include "coff/internal.h" -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/ecoff.h" -#include "libcoff.h" -#include "libecoff.h" - -/* Routines to swap auxiliary information in and out. I am assuming - that the auxiliary information format is always going to be target - independent. */ - -/* Swap in a type information record. - BIGEND says whether AUX symbols are big-endian or little-endian; this - info comes from the file header record (fh-fBigendian). */ - -void -_bfd_ecoff_swap_tir_in (int bigend, const struct tir_ext *ext_copy, - TIR *intern) -{ - struct tir_ext ext[1]; - - *ext = *ext_copy; /* Make it reasonable to do in-place. */ - - /* now the fun stuff... */ - if (bigend) - { - intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_BIG); - intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_BIG); - intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_BIG) - >> TIR_BITS1_BT_SH_BIG; - intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_BIG) - >> TIR_BITS_TQ4_SH_BIG; - intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_BIG) - >> TIR_BITS_TQ5_SH_BIG; - intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_BIG) - >> TIR_BITS_TQ0_SH_BIG; - intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_BIG) - >> TIR_BITS_TQ1_SH_BIG; - intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_BIG) - >> TIR_BITS_TQ2_SH_BIG; - intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_BIG) - >> TIR_BITS_TQ3_SH_BIG; - } - else - { - intern->fBitfield = 0 != (ext->t_bits1[0] & TIR_BITS1_FBITFIELD_LITTLE); - intern->continued = 0 != (ext->t_bits1[0] & TIR_BITS1_CONTINUED_LITTLE); - intern->bt = (ext->t_bits1[0] & TIR_BITS1_BT_LITTLE) - >> TIR_BITS1_BT_SH_LITTLE; - intern->tq4 = (ext->t_tq45[0] & TIR_BITS_TQ4_LITTLE) - >> TIR_BITS_TQ4_SH_LITTLE; - intern->tq5 = (ext->t_tq45[0] & TIR_BITS_TQ5_LITTLE) - >> TIR_BITS_TQ5_SH_LITTLE; - intern->tq0 = (ext->t_tq01[0] & TIR_BITS_TQ0_LITTLE) - >> TIR_BITS_TQ0_SH_LITTLE; - intern->tq1 = (ext->t_tq01[0] & TIR_BITS_TQ1_LITTLE) - >> TIR_BITS_TQ1_SH_LITTLE; - intern->tq2 = (ext->t_tq23[0] & TIR_BITS_TQ2_LITTLE) - >> TIR_BITS_TQ2_SH_LITTLE; - intern->tq3 = (ext->t_tq23[0] & TIR_BITS_TQ3_LITTLE) - >> TIR_BITS_TQ3_SH_LITTLE; - } - -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out a type information record. - BIGEND says whether AUX symbols are big-endian or little-endian; this - info comes from the file header record (fh-fBigendian). */ - -void -_bfd_ecoff_swap_tir_out (int bigend, - const TIR *intern_copy, - struct tir_ext *ext) -{ - TIR intern[1]; - - *intern = *intern_copy; /* Make it reasonable to do in-place. */ - - /* now the fun stuff... */ - if (bigend) - { - ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_BIG : 0) - | (intern->continued ? TIR_BITS1_CONTINUED_BIG : 0) - | ((intern->bt << TIR_BITS1_BT_SH_BIG) - & TIR_BITS1_BT_BIG)); - ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_BIG) - & TIR_BITS_TQ4_BIG) - | ((intern->tq5 << TIR_BITS_TQ5_SH_BIG) - & TIR_BITS_TQ5_BIG)); - ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_BIG) - & TIR_BITS_TQ0_BIG) - | ((intern->tq1 << TIR_BITS_TQ1_SH_BIG) - & TIR_BITS_TQ1_BIG)); - ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_BIG) - & TIR_BITS_TQ2_BIG) - | ((intern->tq3 << TIR_BITS_TQ3_SH_BIG) - & TIR_BITS_TQ3_BIG)); - } - else - { - ext->t_bits1[0] = ((intern->fBitfield ? TIR_BITS1_FBITFIELD_LITTLE : 0) - | (intern->continued ? TIR_BITS1_CONTINUED_LITTLE : 0) - | ((intern->bt << TIR_BITS1_BT_SH_LITTLE) - & TIR_BITS1_BT_LITTLE)); - ext->t_tq45[0] = (((intern->tq4 << TIR_BITS_TQ4_SH_LITTLE) - & TIR_BITS_TQ4_LITTLE) - | ((intern->tq5 << TIR_BITS_TQ5_SH_LITTLE) - & TIR_BITS_TQ5_LITTLE)); - ext->t_tq01[0] = (((intern->tq0 << TIR_BITS_TQ0_SH_LITTLE) - & TIR_BITS_TQ0_LITTLE) - | ((intern->tq1 << TIR_BITS_TQ1_SH_LITTLE) - & TIR_BITS_TQ1_LITTLE)); - ext->t_tq23[0] = (((intern->tq2 << TIR_BITS_TQ2_SH_LITTLE) - & TIR_BITS_TQ2_LITTLE) - | ((intern->tq3 << TIR_BITS_TQ3_SH_LITTLE) - & TIR_BITS_TQ3_LITTLE)); - } - -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in a relative symbol record. BIGEND says whether it is in - big-endian or little-endian format.*/ - -void -_bfd_ecoff_swap_rndx_in (int bigend, - const struct rndx_ext *ext_copy, - RNDXR *intern) -{ - struct rndx_ext ext[1]; - - *ext = *ext_copy; /* Make it reasonable to do in-place. */ - - /* now the fun stuff... */ - if (bigend) - { - intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_BIG) - | ((ext->r_bits[1] & RNDX_BITS1_RFD_BIG) - >> RNDX_BITS1_RFD_SH_BIG); - intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_BIG) - << RNDX_BITS1_INDEX_SH_LEFT_BIG) - | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_BIG) - | (ext->r_bits[3] << RNDX_BITS3_INDEX_SH_LEFT_BIG); - } - else - { - intern->rfd = (ext->r_bits[0] << RNDX_BITS0_RFD_SH_LEFT_LITTLE) - | ((ext->r_bits[1] & RNDX_BITS1_RFD_LITTLE) - << RNDX_BITS1_RFD_SH_LEFT_LITTLE); - intern->index = ((ext->r_bits[1] & RNDX_BITS1_INDEX_LITTLE) - >> RNDX_BITS1_INDEX_SH_LITTLE) - | (ext->r_bits[2] << RNDX_BITS2_INDEX_SH_LEFT_LITTLE) - | ((unsigned int) ext->r_bits[3] - << RNDX_BITS3_INDEX_SH_LEFT_LITTLE); - } - -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out a relative symbol record. BIGEND says whether it is in - big-endian or little-endian format.*/ - -void -_bfd_ecoff_swap_rndx_out (int bigend, - const RNDXR *intern_copy, - struct rndx_ext *ext) -{ - RNDXR intern[1]; - - *intern = *intern_copy; /* Make it reasonable to do in-place. */ - - /* now the fun stuff... */ - if (bigend) - { - ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_BIG; - ext->r_bits[1] = (((intern->rfd << RNDX_BITS1_RFD_SH_BIG) - & RNDX_BITS1_RFD_BIG) - | ((intern->index >> RNDX_BITS1_INDEX_SH_LEFT_BIG) - & RNDX_BITS1_INDEX_BIG)); - ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_BIG; - ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_BIG; - } - else - { - ext->r_bits[0] = intern->rfd >> RNDX_BITS0_RFD_SH_LEFT_LITTLE; - ext->r_bits[1] = (((intern->rfd >> RNDX_BITS1_RFD_SH_LEFT_LITTLE) - & RNDX_BITS1_RFD_LITTLE) - | ((intern->index << RNDX_BITS1_INDEX_SH_LITTLE) - & RNDX_BITS1_INDEX_LITTLE)); - ext->r_bits[2] = intern->index >> RNDX_BITS2_INDEX_SH_LEFT_LITTLE; - ext->r_bits[3] = intern->index >> RNDX_BITS3_INDEX_SH_LEFT_LITTLE; - } - -#ifdef TEST - if (memcmp ((char *)ext, (char *)intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* The minimum amount of data to allocate. */ -#define ALLOC_SIZE (4064) - -/* Add bytes to a buffer. Return success. */ - -static bfd_boolean -ecoff_add_bytes (char **buf, char **bufend, size_t need) -{ - size_t have; - size_t want; - char *newbuf; - - have = *bufend - *buf; - if (have > need) - want = ALLOC_SIZE; - else - { - want = need - have; - if (want < ALLOC_SIZE) - want = ALLOC_SIZE; - } - newbuf = (char *) bfd_realloc (*buf, (bfd_size_type) have + want); - if (newbuf == NULL) - return FALSE; - *buf = newbuf; - *bufend = *buf + have + want; - return TRUE; -} - -/* We keep a hash table which maps strings to numbers. We use it to - map FDR names to indices in the output file, and to map local - strings when combining stabs debugging information. */ - -struct string_hash_entry -{ - struct bfd_hash_entry root; - /* FDR index or string table offset. */ - long val; - /* Next entry in string table. */ - struct string_hash_entry *next; -}; - -struct string_hash_table -{ - struct bfd_hash_table table; -}; - -/* 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->val = -1; - ret->next = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Look up an entry in an string hash table. */ - -#define string_hash_lookup(t, string, create, copy) \ - ((struct string_hash_entry *) \ - bfd_hash_lookup (&(t)->table, (string), (create), (copy))) - -/* We can't afford to read in all the debugging information when we do - a link. Instead, we build a list of these structures to show how - different parts of the input file map to the output file. */ - -struct shuffle -{ - /* The next entry in this linked list. */ - struct shuffle *next; - /* The length of the information. */ - unsigned long size; - /* Whether this information comes from a file or not. */ - bfd_boolean filep; - union - { - struct - { - /* The BFD the data comes from. */ - bfd *input_bfd; - /* The offset within input_bfd. */ - file_ptr offset; - } file; - /* The data to be written out. */ - void * memory; - } u; -}; - -/* This structure holds information across calls to - bfd_ecoff_debug_accumulate. */ - -struct accumulate -{ - /* The FDR hash table. */ - struct string_hash_table fdr_hash; - /* The strings hash table. */ - struct string_hash_table str_hash; - /* Linked lists describing how to shuffle the input debug - information into the output file. We keep a pointer to both the - head and the tail. */ - struct shuffle *line; - struct shuffle *line_end; - struct shuffle *pdr; - struct shuffle *pdr_end; - struct shuffle *sym; - struct shuffle *sym_end; - struct shuffle *opt; - struct shuffle *opt_end; - struct shuffle *aux; - struct shuffle *aux_end; - struct shuffle *ss; - struct shuffle *ss_end; - struct string_hash_entry *ss_hash; - struct string_hash_entry *ss_hash_end; - struct shuffle *fdr; - struct shuffle *fdr_end; - struct shuffle *rfd; - struct shuffle *rfd_end; - /* The size of the largest file shuffle. */ - unsigned long largest_file_shuffle; - /* An objalloc for debugging information. */ - struct objalloc *memory; -}; - -/* Add a file entry to a shuffle list. */ - -static bfd_boolean -add_file_shuffle (struct accumulate *ainfo, - struct shuffle **head, - struct shuffle **tail, - bfd *input_bfd, - file_ptr offset, - unsigned long size) -{ - struct shuffle *n; - - if (*tail != (struct shuffle *) NULL - && (*tail)->filep - && (*tail)->u.file.input_bfd == input_bfd - && (*tail)->u.file.offset + (*tail)->size == (unsigned long) offset) - { - /* Just merge this entry onto the existing one. */ - (*tail)->size += size; - if ((*tail)->size > ainfo->largest_file_shuffle) - ainfo->largest_file_shuffle = (*tail)->size; - return TRUE; - } - - n = (struct shuffle *) objalloc_alloc (ainfo->memory, - sizeof (struct shuffle)); - if (!n) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - n->next = NULL; - n->size = size; - n->filep = TRUE; - n->u.file.input_bfd = input_bfd; - n->u.file.offset = offset; - if (*head == (struct shuffle *) NULL) - *head = n; - if (*tail != (struct shuffle *) NULL) - (*tail)->next = n; - *tail = n; - if (size > ainfo->largest_file_shuffle) - ainfo->largest_file_shuffle = size; - return TRUE; -} - -/* Add a memory entry to a shuffle list. */ - -static bfd_boolean -add_memory_shuffle (struct accumulate *ainfo, - struct shuffle **head, - struct shuffle **tail, - bfd_byte *data, - unsigned long size) -{ - struct shuffle *n; - - n = (struct shuffle *) objalloc_alloc (ainfo->memory, - sizeof (struct shuffle)); - if (!n) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - n->next = NULL; - n->size = size; - n->filep = FALSE; - n->u.memory = data; - if (*head == (struct shuffle *) NULL) - *head = n; - if (*tail != (struct shuffle *) NULL) - (*tail)->next = n; - *tail = n; - return TRUE; -} - -/* Initialize the FDR hash table. This returns a handle which is then - passed in to bfd_ecoff_debug_accumulate, et. al. */ - -void * -bfd_ecoff_debug_init (bfd *output_bfd ATTRIBUTE_UNUSED, - struct ecoff_debug_info *output_debug, - const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct accumulate *ainfo; - bfd_size_type amt = sizeof (struct accumulate); - - ainfo = (struct accumulate *) bfd_malloc (amt); - if (!ainfo) - return NULL; - if (!bfd_hash_table_init_n (&ainfo->fdr_hash.table, string_hash_newfunc, - sizeof (struct string_hash_entry), 1021)) - return NULL; - - ainfo->line = NULL; - ainfo->line_end = NULL; - ainfo->pdr = NULL; - ainfo->pdr_end = NULL; - ainfo->sym = NULL; - ainfo->sym_end = NULL; - ainfo->opt = NULL; - ainfo->opt_end = NULL; - ainfo->aux = NULL; - ainfo->aux_end = NULL; - ainfo->ss = NULL; - ainfo->ss_end = NULL; - ainfo->ss_hash = NULL; - ainfo->ss_hash_end = NULL; - ainfo->fdr = NULL; - ainfo->fdr_end = NULL; - ainfo->rfd = NULL; - ainfo->rfd_end = NULL; - - ainfo->largest_file_shuffle = 0; - - if (! bfd_link_relocatable (info)) - { - if (!bfd_hash_table_init (&ainfo->str_hash.table, string_hash_newfunc, - sizeof (struct string_hash_entry))) - return NULL; - - /* The first entry in the string table is the empty string. */ - output_debug->symbolic_header.issMax = 1; - } - - ainfo->memory = objalloc_create (); - if (ainfo->memory == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - - return ainfo; -} - -/* Free the accumulated debugging information. */ - -void -bfd_ecoff_debug_free (void * handle, - bfd *output_bfd ATTRIBUTE_UNUSED, - struct ecoff_debug_info *output_debug ATTRIBUTE_UNUSED, - const struct ecoff_debug_swap *output_swap ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - - bfd_hash_table_free (&ainfo->fdr_hash.table); - - if (! bfd_link_relocatable (info)) - bfd_hash_table_free (&ainfo->str_hash.table); - - objalloc_free (ainfo->memory); - - free (ainfo); -} - -/* Accumulate the debugging information from INPUT_BFD into - OUTPUT_BFD. The INPUT_DEBUG argument points to some ECOFF - debugging information which we want to link into the information - pointed to by the OUTPUT_DEBUG argument. OUTPUT_SWAP and - INPUT_SWAP point to the swapping information needed. INFO is the - linker information structure. HANDLE is returned by - bfd_ecoff_debug_init. */ - -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 *info) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - void (* const swap_sym_in) (bfd *, void *, SYMR *) - = input_swap->swap_sym_in; - void (* const swap_rfd_in) (bfd *, void *, RFDT *) - = input_swap->swap_rfd_in; - void (* const swap_sym_out) (bfd *, const SYMR *, void *) - = output_swap->swap_sym_out; - void (* const swap_fdr_out) (bfd *, const FDR *, void *) - = output_swap->swap_fdr_out; - void (* const swap_rfd_out) (bfd *, const RFDT *, void *) - = output_swap->swap_rfd_out; - bfd_size_type external_pdr_size = output_swap->external_pdr_size; - bfd_size_type external_sym_size = output_swap->external_sym_size; - bfd_size_type external_opt_size = output_swap->external_opt_size; - bfd_size_type external_fdr_size = output_swap->external_fdr_size; - bfd_size_type external_rfd_size = output_swap->external_rfd_size; - HDRR * const output_symhdr = &output_debug->symbolic_header; - HDRR * const input_symhdr = &input_debug->symbolic_header; - bfd_vma section_adjust[scMax]; - asection *sec; - bfd_byte *fdr_start; - bfd_byte *fdr_ptr; - bfd_byte *fdr_end; - bfd_size_type fdr_add; - unsigned int copied; - RFDT i; - unsigned long sz; - bfd_byte *rfd_out; - bfd_byte *rfd_in; - bfd_byte *rfd_end; - long newrfdbase = 0; - long oldrfdbase = 0; - bfd_byte *fdr_out; - bfd_size_type amt; - - /* Use section_adjust to hold the value to add to a symbol in a - particular section. */ - memset (section_adjust, 0, sizeof section_adjust); - -#define SET(name, indx) \ - sec = bfd_get_section_by_name (input_bfd, name); \ - if (sec != NULL) \ - section_adjust[indx] = (sec->output_section->vma \ - + sec->output_offset \ - - sec->vma); - - SET (".text", scText); - SET (".data", scData); - SET (".bss", scBss); - SET (".sdata", scSData); - SET (".sbss", scSBss); - /* scRdata section may be either .rdata or .rodata. */ - SET (".rdata", scRData); - SET (".rodata", scRData); - SET (".init", scInit); - SET (".fini", scFini); - SET (".rconst", scRConst); - -#undef SET - - /* Find all the debugging information based on the FDR's. We need - to handle them whether they are swapped or not. */ - if (input_debug->fdr != (FDR *) NULL) - { - fdr_start = (bfd_byte *) input_debug->fdr; - fdr_add = sizeof (FDR); - } - else - { - fdr_start = (bfd_byte *) input_debug->external_fdr; - fdr_add = input_swap->external_fdr_size; - } - fdr_end = fdr_start + input_symhdr->ifdMax * fdr_add; - - amt = input_symhdr->ifdMax; - amt *= sizeof (RFDT); - input_debug->ifdmap = (RFDT *) bfd_alloc (input_bfd, amt); - - sz = (input_symhdr->crfd + input_symhdr->ifdMax) * external_rfd_size; - rfd_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); - if (!input_debug->ifdmap || !rfd_out) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - if (!add_memory_shuffle (ainfo, &ainfo->rfd, &ainfo->rfd_end, rfd_out, sz)) - return FALSE; - - copied = 0; - - /* Look through the FDR's to see which ones we are going to include - in the final output. We do not want duplicate FDR information - for header files, because ECOFF debugging is often very large. - When we find an FDR with no line information which can be merged, - we look it up in a hash table to ensure that we only include it - once. We keep a table mapping FDR numbers to the final number - they get with the BFD, so that we can refer to it when we write - out the external symbols. */ - for (fdr_ptr = fdr_start, i = 0; - fdr_ptr < fdr_end; - fdr_ptr += fdr_add, i++, rfd_out += external_rfd_size) - { - FDR fdr; - - if (input_debug->fdr != (FDR *) NULL) - fdr = *(FDR *) fdr_ptr; - else - (*input_swap->swap_fdr_in) (input_bfd, fdr_ptr, &fdr); - - /* See if this FDR can be merged with an existing one. */ - if (fdr.cbLine == 0 && fdr.rss != -1 && fdr.fMerge) - { - const char *name; - char *lookup; - struct string_hash_entry *fh; - - /* We look up a string formed from the file name and the - number of symbols and aux entries. Sometimes an include - file will conditionally define a typedef or something - based on the order of include files. Using the number of - symbols and aux entries as a hash reduces the chance that - we will merge symbol information that should not be - merged. */ - name = input_debug->ss + fdr.issBase + fdr.rss; - - lookup = (char *) bfd_malloc ((bfd_size_type) strlen (name) + 20); - if (lookup == NULL) - return FALSE; - sprintf (lookup, "%s %lx %lx", name, (unsigned long) fdr.csym, - (unsigned long) fdr.caux); - - fh = string_hash_lookup (&ainfo->fdr_hash, lookup, TRUE, TRUE); - free (lookup); - if (fh == (struct string_hash_entry *) NULL) - return FALSE; - - if (fh->val != -1) - { - input_debug->ifdmap[i] = fh->val; - (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, rfd_out); - - /* Don't copy this FDR. */ - continue; - } - - fh->val = output_symhdr->ifdMax + copied; - } - - input_debug->ifdmap[i] = output_symhdr->ifdMax + copied; - (*swap_rfd_out) (output_bfd, input_debug->ifdmap + i, rfd_out); - ++copied; - } - - newrfdbase = output_symhdr->crfd; - output_symhdr->crfd += input_symhdr->ifdMax; - - /* Copy over any existing RFD's. RFD's are only created by the - linker, so this will only happen for input files which are the - result of a partial link. */ - rfd_in = (bfd_byte *) input_debug->external_rfd; - rfd_end = rfd_in + input_symhdr->crfd * input_swap->external_rfd_size; - for (; - rfd_in < rfd_end; - rfd_in += input_swap->external_rfd_size) - { - RFDT rfd; - - (*swap_rfd_in) (input_bfd, rfd_in, &rfd); - BFD_ASSERT (rfd >= 0 && rfd < input_symhdr->ifdMax); - rfd = input_debug->ifdmap[rfd]; - (*swap_rfd_out) (output_bfd, &rfd, rfd_out); - rfd_out += external_rfd_size; - } - - oldrfdbase = output_symhdr->crfd; - output_symhdr->crfd += input_symhdr->crfd; - - /* Look through the FDR's and copy over all associated debugging - information. */ - sz = copied * external_fdr_size; - fdr_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); - if (!fdr_out) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - if (!add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, fdr_out, sz)) - return FALSE; - for (fdr_ptr = fdr_start, i = 0; - fdr_ptr < fdr_end; - fdr_ptr += fdr_add, i++) - { - FDR fdr; - bfd_byte *sym_out; - bfd_byte *lraw_src; - bfd_byte *lraw_end; - bfd_boolean fgotfilename; - - if (input_debug->ifdmap[i] < output_symhdr->ifdMax) - { - /* We are not copying this FDR. */ - continue; - } - - if (input_debug->fdr != (FDR *) NULL) - fdr = *(FDR *) fdr_ptr; - else - (*input_swap->swap_fdr_in) (input_bfd, fdr_ptr, &fdr); - - /* FIXME: It is conceivable that this FDR points to the .init or - .fini section, in which case this will not do the right - thing. */ - fdr.adr += section_adjust[scText]; - - /* Swap in the local symbols, adjust their values, and swap them - out again. */ - fgotfilename = FALSE; - sz = fdr.csym * external_sym_size; - sym_out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); - if (!sym_out) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - if (!add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, sym_out, - sz)) - return FALSE; - lraw_src = ((bfd_byte *) input_debug->external_sym - + fdr.isymBase * input_swap->external_sym_size); - lraw_end = lraw_src + fdr.csym * input_swap->external_sym_size; - for (; lraw_src < lraw_end; lraw_src += input_swap->external_sym_size) - { - SYMR internal_sym; - - (*swap_sym_in) (input_bfd, lraw_src, &internal_sym); - - BFD_ASSERT (internal_sym.sc != scCommon - && internal_sym.sc != scSCommon); - - /* Adjust the symbol value if appropriate. */ - switch (internal_sym.st) - { - case stNil: - if (ECOFF_IS_STAB (&internal_sym)) - break; - /* Fall through. */ - case stGlobal: - case stStatic: - case stLabel: - case stProc: - case stStaticProc: - internal_sym.value += section_adjust[internal_sym.sc]; - break; - - default: - break; - } - - /* If we are doing a final link, we hash all the strings in - the local symbol table together. This reduces the amount - of space required by debugging information. We don't do - this when performing a relocatable link because it would - prevent us from easily merging different FDR's. */ - if (! bfd_link_relocatable (info)) - { - bfd_boolean ffilename; - const char *name; - - if (! fgotfilename && internal_sym.iss == fdr.rss) - ffilename = TRUE; - else - ffilename = FALSE; - - /* Hash the name into the string table. */ - name = input_debug->ss + fdr.issBase + internal_sym.iss; - if (*name == '\0') - internal_sym.iss = 0; - else - { - struct string_hash_entry *sh; - - sh = string_hash_lookup (&ainfo->str_hash, name, TRUE, TRUE); - if (sh == (struct string_hash_entry *) NULL) - return FALSE; - if (sh->val == -1) - { - sh->val = output_symhdr->issMax; - output_symhdr->issMax += strlen (name) + 1; - if (ainfo->ss_hash == (struct string_hash_entry *) NULL) - ainfo->ss_hash = sh; - if (ainfo->ss_hash_end - != (struct string_hash_entry *) NULL) - ainfo->ss_hash_end->next = sh; - ainfo->ss_hash_end = sh; - } - internal_sym.iss = sh->val; - } - - if (ffilename) - { - fdr.rss = internal_sym.iss; - fgotfilename = TRUE; - } - } - - (*swap_sym_out) (output_bfd, &internal_sym, sym_out); - sym_out += external_sym_size; - } - - fdr.isymBase = output_symhdr->isymMax; - output_symhdr->isymMax += fdr.csym; - - /* Copy the information that does not need swapping. */ - - /* FIXME: If we are relaxing, we need to adjust the line - numbers. Frankly, forget it. Anybody using stabs debugging - information will not use this line number information, and - stabs are adjusted correctly. */ - if (fdr.cbLine > 0) - { - file_ptr pos = input_symhdr->cbLineOffset + fdr.cbLineOffset; - if (!add_file_shuffle (ainfo, &ainfo->line, &ainfo->line_end, - input_bfd, pos, (unsigned long) fdr.cbLine)) - return FALSE; - fdr.ilineBase = output_symhdr->ilineMax; - fdr.cbLineOffset = output_symhdr->cbLine; - output_symhdr->ilineMax += fdr.cline; - output_symhdr->cbLine += fdr.cbLine; - } - if (fdr.caux > 0) - { - file_ptr pos = (input_symhdr->cbAuxOffset - + fdr.iauxBase * sizeof (union aux_ext)); - if (!add_file_shuffle (ainfo, &ainfo->aux, &ainfo->aux_end, - input_bfd, pos, - fdr.caux * sizeof (union aux_ext))) - return FALSE; - fdr.iauxBase = output_symhdr->iauxMax; - output_symhdr->iauxMax += fdr.caux; - } - if (! bfd_link_relocatable (info)) - { - - /* When we are hashing strings, we lie about the number of - strings attached to each FDR. We need to set cbSs - because some versions of dbx apparently use it to decide - how much of the string table to read in. */ - fdr.issBase = 0; - fdr.cbSs = output_symhdr->issMax; - } - else if (fdr.cbSs > 0) - { - file_ptr pos = input_symhdr->cbSsOffset + fdr.issBase; - if (!add_file_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, - input_bfd, pos, (unsigned long) fdr.cbSs)) - return FALSE; - fdr.issBase = output_symhdr->issMax; - output_symhdr->issMax += fdr.cbSs; - } - - if (output_bfd->xvec->header_byteorder - == input_bfd->xvec->header_byteorder) - { - /* The two BFD's have the same endianness, and we don't have - to adjust the PDR addresses, so simply copying the - information will suffice. */ - BFD_ASSERT (external_pdr_size == input_swap->external_pdr_size); - if (fdr.cpd > 0) - { - file_ptr pos = (input_symhdr->cbPdOffset - + fdr.ipdFirst * external_pdr_size); - unsigned long size = fdr.cpd * external_pdr_size; - if (!add_file_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, - input_bfd, pos, size)) - return FALSE; - } - BFD_ASSERT (external_opt_size == input_swap->external_opt_size); - if (fdr.copt > 0) - { - file_ptr pos = (input_symhdr->cbOptOffset - + fdr.ioptBase * external_opt_size); - unsigned long size = fdr.copt * external_opt_size; - if (!add_file_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, - input_bfd, pos, size)) - return FALSE; - } - } - else - { - bfd_size_type outsz, insz; - bfd_byte *in; - bfd_byte *end; - bfd_byte *out; - - /* The two BFD's have different endianness, so we must swap - everything in and out. This code would always work, but - it would be unnecessarily slow in the normal case. */ - outsz = external_pdr_size; - insz = input_swap->external_pdr_size; - in = ((bfd_byte *) input_debug->external_pdr - + fdr.ipdFirst * insz); - end = in + fdr.cpd * insz; - sz = fdr.cpd * outsz; - out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); - if (!out) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - if (!add_memory_shuffle (ainfo, &ainfo->pdr, &ainfo->pdr_end, out, - sz)) - return FALSE; - for (; in < end; in += insz, out += outsz) - { - PDR pdr; - - (*input_swap->swap_pdr_in) (input_bfd, in, &pdr); - (*output_swap->swap_pdr_out) (output_bfd, &pdr, out); - } - - /* Swap over the optimization information. */ - outsz = external_opt_size; - insz = input_swap->external_opt_size; - in = ((bfd_byte *) input_debug->external_opt - + fdr.ioptBase * insz); - end = in + fdr.copt * insz; - sz = fdr.copt * outsz; - out = (bfd_byte *) objalloc_alloc (ainfo->memory, sz); - if (!out) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - if (!add_memory_shuffle (ainfo, &ainfo->opt, &ainfo->opt_end, out, - sz)) - return FALSE; - for (; in < end; in += insz, out += outsz) - { - OPTR opt; - - (*input_swap->swap_opt_in) (input_bfd, in, &opt); - (*output_swap->swap_opt_out) (output_bfd, &opt, out); - } - } - - fdr.ipdFirst = output_symhdr->ipdMax; - output_symhdr->ipdMax += fdr.cpd; - fdr.ioptBase = output_symhdr->ioptMax; - output_symhdr->ioptMax += fdr.copt; - - if (fdr.crfd <= 0) - { - /* Point this FDR at the table of RFD's we created. */ - fdr.rfdBase = newrfdbase; - fdr.crfd = input_symhdr->ifdMax; - } - else - { - /* Point this FDR at the remapped RFD's. */ - fdr.rfdBase += oldrfdbase; - } - - (*swap_fdr_out) (output_bfd, &fdr, fdr_out); - fdr_out += external_fdr_size; - ++output_symhdr->ifdMax; - } - - return TRUE; -} - -/* Add a string to the debugging information we are accumulating. - Return the offset from the fdr string base. */ - -static long -ecoff_add_string (struct accumulate *ainfo, - struct bfd_link_info *info, - struct ecoff_debug_info *debug, - FDR *fdr, - const char *string) -{ - HDRR *symhdr; - size_t len; - bfd_size_type ret; - - symhdr = &debug->symbolic_header; - len = strlen (string); - if (bfd_link_relocatable (info)) - { - if (!add_memory_shuffle (ainfo, &ainfo->ss, &ainfo->ss_end, - (bfd_byte *) string, len + 1)) - return -1; - ret = symhdr->issMax; - symhdr->issMax += len + 1; - fdr->cbSs += len + 1; - } - else - { - struct string_hash_entry *sh; - - sh = string_hash_lookup (&ainfo->str_hash, string, TRUE, TRUE); - if (sh == (struct string_hash_entry *) NULL) - return -1; - if (sh->val == -1) - { - sh->val = symhdr->issMax; - symhdr->issMax += len + 1; - if (ainfo->ss_hash == (struct string_hash_entry *) NULL) - ainfo->ss_hash = sh; - if (ainfo->ss_hash_end - != (struct string_hash_entry *) NULL) - ainfo->ss_hash_end->next = sh; - ainfo->ss_hash_end = sh; - } - ret = sh->val; - } - - return ret; -} - -/* Add debugging information from a non-ECOFF file. */ - -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 *info) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - void (* const swap_sym_out) (bfd *, const SYMR *, void *) - = output_swap->swap_sym_out; - HDRR *output_symhdr = &output_debug->symbolic_header; - FDR fdr; - asection *sec; - asymbol **symbols; - asymbol **sym_ptr; - asymbol **sym_end; - long symsize; - long symcount; - void * external_fdr; - - memset (&fdr, 0, sizeof fdr); - - sec = bfd_get_section_by_name (input_bfd, ".text"); - if (sec != NULL) - fdr.adr = sec->output_section->vma + sec->output_offset; - else - { - /* FIXME: What about .init or .fini? */ - fdr.adr = 0; - } - - fdr.issBase = output_symhdr->issMax; - fdr.cbSs = 0; - fdr.rss = ecoff_add_string (ainfo, info, output_debug, &fdr, - input_bfd->filename); - if (fdr.rss == -1) - return FALSE; - fdr.isymBase = output_symhdr->isymMax; - - /* Get the local symbols from the input BFD. */ - symsize = bfd_get_symtab_upper_bound (input_bfd); - if (symsize < 0) - return FALSE; - symbols = (asymbol **) bfd_alloc (output_bfd, (bfd_size_type) symsize); - if (symbols == (asymbol **) NULL) - return FALSE; - symcount = bfd_canonicalize_symtab (input_bfd, symbols); - if (symcount < 0) - return FALSE; - sym_end = symbols + symcount; - - /* Handle the local symbols. Any external symbols are handled - separately. */ - fdr.csym = 0; - for (sym_ptr = symbols; sym_ptr != sym_end; sym_ptr++) - { - SYMR internal_sym; - void * external_sym; - - if (((*sym_ptr)->flags & BSF_EXPORT) != 0) - continue; - memset (&internal_sym, 0, sizeof internal_sym); - internal_sym.iss = ecoff_add_string (ainfo, info, output_debug, &fdr, - (*sym_ptr)->name); - - if (internal_sym.iss == -1) - return FALSE; - if (bfd_is_com_section ((*sym_ptr)->section) - || bfd_is_und_section ((*sym_ptr)->section)) - internal_sym.value = (*sym_ptr)->value; - else - internal_sym.value = ((*sym_ptr)->value - + (*sym_ptr)->section->output_offset - + (*sym_ptr)->section->output_section->vma); - internal_sym.st = stNil; - internal_sym.sc = scUndefined; - internal_sym.index = indexNil; - - external_sym = objalloc_alloc (ainfo->memory, - output_swap->external_sym_size); - if (!external_sym) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - (*swap_sym_out) (output_bfd, &internal_sym, external_sym); - add_memory_shuffle (ainfo, &ainfo->sym, &ainfo->sym_end, - (bfd_byte *) external_sym, - (unsigned long) output_swap->external_sym_size); - ++fdr.csym; - ++output_symhdr->isymMax; - } - - bfd_release (output_bfd, symbols); - - /* Leave everything else in the FDR zeroed out. This will cause - the lang field to be langC. The fBigendian field will - indicate little endian format, but it doesn't matter because - it only applies to aux fields and there are none. */ - external_fdr = objalloc_alloc (ainfo->memory, - output_swap->external_fdr_size); - if (!external_fdr) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - (*output_swap->swap_fdr_out) (output_bfd, &fdr, external_fdr); - add_memory_shuffle (ainfo, &ainfo->fdr, &ainfo->fdr_end, - (bfd_byte *) external_fdr, - (unsigned long) output_swap->external_fdr_size); - - ++output_symhdr->ifdMax; - - return TRUE; -} - -/* Set up ECOFF debugging information for the external symbols. - FIXME: This is done using a memory buffer, but it should be - probably be changed to use a shuffle structure. The assembler uses - this interface, so that must be changed to do something else. */ - -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) (asymbol *, EXTR *), - void (*set_index) (asymbol *, bfd_size_type)) -{ - HDRR * const symhdr = &debug->symbolic_header; - asymbol **sym_ptr_ptr; - size_t c; - - sym_ptr_ptr = bfd_get_outsymbols (abfd); - if (sym_ptr_ptr == NULL) - return TRUE; - - for (c = bfd_get_symcount (abfd); c > 0; c--, sym_ptr_ptr++) - { - asymbol *sym_ptr; - EXTR esym; - - sym_ptr = *sym_ptr_ptr; - - /* Get the external symbol information. */ - if (! (*get_extr) (sym_ptr, &esym)) - continue; - - /* If we're producing an executable, move common symbols into - bss. */ - if (! relocatable) - { - if (esym.asym.sc == scCommon) - esym.asym.sc = scBss; - else if (esym.asym.sc == scSCommon) - esym.asym.sc = scSBss; - } - - if (bfd_is_com_section (sym_ptr->section) - || bfd_is_und_section (sym_ptr->section) - || sym_ptr->section->output_section == (asection *) NULL) - { - /* FIXME: gas does not keep the value of a small undefined - symbol in the symbol itself, because of relocation - problems. */ - if (esym.asym.sc != scSUndefined - || esym.asym.value == 0 - || sym_ptr->value != 0) - esym.asym.value = sym_ptr->value; - } - else - esym.asym.value = (sym_ptr->value - + sym_ptr->section->output_offset - + sym_ptr->section->output_section->vma); - - if (set_index) - (*set_index) (sym_ptr, (bfd_size_type) symhdr->iextMax); - - if (! bfd_ecoff_debug_one_external (abfd, debug, swap, - sym_ptr->name, &esym)) - return FALSE; - } - - return TRUE; -} - -/* Add a single external symbol to the debugging information. */ - -bfd_boolean -bfd_ecoff_debug_one_external (bfd *abfd, - struct ecoff_debug_info *debug, - const struct ecoff_debug_swap *swap, - const char *name, - EXTR *esym) -{ - const bfd_size_type external_ext_size = swap->external_ext_size; - void (* const swap_ext_out) (bfd *, const EXTR *, void *) - = swap->swap_ext_out; - HDRR * const symhdr = &debug->symbolic_header; - size_t namelen; - - namelen = strlen (name); - - if ((size_t) (debug->ssext_end - debug->ssext) - < symhdr->issExtMax + namelen + 1) - { - if (! ecoff_add_bytes ((char **) &debug->ssext, - (char **) &debug->ssext_end, - symhdr->issExtMax + namelen + 1)) - return FALSE; - } - if ((size_t) ((char *) debug->external_ext_end - - (char *) debug->external_ext) - < (symhdr->iextMax + 1) * external_ext_size) - { - char *external_ext = (char *) debug->external_ext; - char *external_ext_end = (char *) debug->external_ext_end; - if (! ecoff_add_bytes ((char **) &external_ext, - (char **) &external_ext_end, - (symhdr->iextMax + 1) * (size_t) external_ext_size)) - return FALSE; - debug->external_ext = external_ext; - debug->external_ext_end = external_ext_end; - } - - esym->asym.iss = symhdr->issExtMax; - - (*swap_ext_out) (abfd, esym, - ((char *) debug->external_ext - + symhdr->iextMax * swap->external_ext_size)); - - ++symhdr->iextMax; - - strcpy (debug->ssext + symhdr->issExtMax, name); - symhdr->issExtMax += namelen + 1; - - return TRUE; -} - -/* Align the ECOFF debugging information. */ - -static void -ecoff_align_debug (bfd *abfd ATTRIBUTE_UNUSED, - struct ecoff_debug_info *debug, - const struct ecoff_debug_swap *swap) -{ - HDRR * const symhdr = &debug->symbolic_header; - bfd_size_type debug_align, aux_align, rfd_align; - size_t add; - - /* Adjust the counts so that structures are aligned. */ - debug_align = swap->debug_align; - aux_align = debug_align / sizeof (union aux_ext); - rfd_align = debug_align / swap->external_rfd_size; - - add = debug_align - (symhdr->cbLine & (debug_align - 1)); - if (add != debug_align) - { - if (debug->line != (unsigned char *) NULL) - memset ((debug->line + symhdr->cbLine), 0, add); - symhdr->cbLine += add; - } - - add = debug_align - (symhdr->issMax & (debug_align - 1)); - if (add != debug_align) - { - if (debug->ss != (char *) NULL) - memset ((debug->ss + symhdr->issMax), 0, add); - symhdr->issMax += add; - } - - add = debug_align - (symhdr->issExtMax & (debug_align - 1)); - if (add != debug_align) - { - if (debug->ssext != (char *) NULL) - memset ((debug->ssext + symhdr->issExtMax), 0, add); - symhdr->issExtMax += add; - } - - add = aux_align - (symhdr->iauxMax & (aux_align - 1)); - if (add != aux_align) - { - if (debug->external_aux != (union aux_ext *) NULL) - memset ((debug->external_aux + symhdr->iauxMax), 0, - add * sizeof (union aux_ext)); - symhdr->iauxMax += add; - } - - add = rfd_align - (symhdr->crfd & (rfd_align - 1)); - if (add != rfd_align) - { - if (debug->external_rfd != NULL) - memset (((char *) debug->external_rfd - + symhdr->crfd * swap->external_rfd_size), - 0, (size_t) (add * swap->external_rfd_size)); - symhdr->crfd += add; - } -} - -/* Return the size required by the ECOFF debugging information. */ - -bfd_size_type -bfd_ecoff_debug_size (bfd *abfd, - struct ecoff_debug_info *debug, - const struct ecoff_debug_swap *swap) -{ - bfd_size_type tot; - - ecoff_align_debug (abfd, debug, swap); - tot = swap->external_hdr_size; - -#define ADD(count, size) \ - tot += debug->symbolic_header.count * size - - ADD (cbLine, sizeof (unsigned char)); - ADD (idnMax, swap->external_dnr_size); - ADD (ipdMax, swap->external_pdr_size); - ADD (isymMax, swap->external_sym_size); - ADD (ioptMax, swap->external_opt_size); - ADD (iauxMax, sizeof (union aux_ext)); - ADD (issMax, sizeof (char)); - ADD (issExtMax, sizeof (char)); - ADD (ifdMax, swap->external_fdr_size); - ADD (crfd, swap->external_rfd_size); - ADD (iextMax, swap->external_ext_size); - -#undef ADD - - return tot; -} - -/* Write out the ECOFF symbolic header, given the file position it is - going to be placed at. This assumes that the counts are set - correctly. */ - -static bfd_boolean -ecoff_write_symhdr (bfd *abfd, - struct ecoff_debug_info *debug, - const struct ecoff_debug_swap *swap, - file_ptr where) -{ - HDRR * const symhdr = &debug->symbolic_header; - char *buff = NULL; - - ecoff_align_debug (abfd, debug, swap); - - /* Go to the right location in the file. */ - if (bfd_seek (abfd, where, SEEK_SET) != 0) - return FALSE; - - where += swap->external_hdr_size; - - symhdr->magic = swap->sym_magic; - - /* Fill in the file offsets. */ -#define SET(offset, count, size) \ - if (symhdr->count == 0) \ - symhdr->offset = 0; \ - else \ - { \ - symhdr->offset = where; \ - where += symhdr->count * size; \ - } - - SET (cbLineOffset, cbLine, sizeof (unsigned char)); - SET (cbDnOffset, idnMax, swap->external_dnr_size); - SET (cbPdOffset, ipdMax, swap->external_pdr_size); - SET (cbSymOffset, isymMax, swap->external_sym_size); - SET (cbOptOffset, ioptMax, swap->external_opt_size); - SET (cbAuxOffset, iauxMax, sizeof (union aux_ext)); - SET (cbSsOffset, issMax, sizeof (char)); - SET (cbSsExtOffset, issExtMax, sizeof (char)); - SET (cbFdOffset, ifdMax, swap->external_fdr_size); - SET (cbRfdOffset, crfd, swap->external_rfd_size); - SET (cbExtOffset, iextMax, swap->external_ext_size); -#undef SET - - buff = (char *) bfd_malloc (swap->external_hdr_size); - if (buff == NULL && swap->external_hdr_size != 0) - goto error_return; - - (*swap->swap_hdr_out) (abfd, symhdr, buff); - if (bfd_bwrite (buff, swap->external_hdr_size, abfd) - != swap->external_hdr_size) - goto error_return; - - if (buff != NULL) - free (buff); - return TRUE; - error_return: - if (buff != NULL) - free (buff); - return FALSE; -} - -/* Write out the ECOFF debugging information. This function assumes - that the information (the pointers and counts) in *DEBUG have been - set correctly. WHERE is the position in the file to write the - information to. This function fills in the file offsets in the - symbolic header. */ - -bfd_boolean -bfd_ecoff_write_debug (bfd *abfd, - struct ecoff_debug_info *debug, - const struct ecoff_debug_swap *swap, - file_ptr where) -{ - HDRR * const symhdr = &debug->symbolic_header; - - if (! ecoff_write_symhdr (abfd, debug, swap, where)) - return FALSE; - -#define WRITE(ptr, count, size, offset) \ - BFD_ASSERT (symhdr->offset == 0 \ - || (bfd_vma) bfd_tell (abfd) == symhdr->offset); \ - if (bfd_bwrite (debug->ptr, (bfd_size_type) size * symhdr->count, abfd)\ - != size * symhdr->count) \ - return FALSE; - - WRITE (line, cbLine, sizeof (unsigned char), cbLineOffset); - WRITE (external_dnr, idnMax, swap->external_dnr_size, cbDnOffset); - WRITE (external_pdr, ipdMax, swap->external_pdr_size, cbPdOffset); - WRITE (external_sym, isymMax, swap->external_sym_size, cbSymOffset); - WRITE (external_opt, ioptMax, swap->external_opt_size, cbOptOffset); - WRITE (external_aux, iauxMax, (bfd_size_type) sizeof (union aux_ext), - cbAuxOffset); - WRITE (ss, issMax, sizeof (char), cbSsOffset); - WRITE (ssext, issExtMax, sizeof (char), cbSsExtOffset); - WRITE (external_fdr, ifdMax, swap->external_fdr_size, cbFdOffset); - WRITE (external_rfd, crfd, swap->external_rfd_size, cbRfdOffset); - WRITE (external_ext, iextMax, swap->external_ext_size, cbExtOffset); -#undef WRITE - - return TRUE; -} - -/* Write out a shuffle list. */ - - -static bfd_boolean -ecoff_write_shuffle (bfd *abfd, - const struct ecoff_debug_swap *swap, - struct shuffle *shuffle, - void * space) -{ - struct shuffle *l; - unsigned long total; - - total = 0; - for (l = shuffle; l != (struct shuffle *) NULL; l = l->next) - { - if (! l->filep) - { - if (bfd_bwrite (l->u.memory, (bfd_size_type) l->size, abfd) - != l->size) - return FALSE; - } - else - { - if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 - || bfd_bread (space, (bfd_size_type) l->size, - l->u.file.input_bfd) != l->size - || bfd_bwrite (space, (bfd_size_type) l->size, abfd) != l->size) - return FALSE; - } - total += l->size; - } - - if ((total & (swap->debug_align - 1)) != 0) - { - unsigned int i; - bfd_byte *s; - - i = swap->debug_align - (total & (swap->debug_align - 1)); - s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i); - if (s == NULL && i != 0) - return FALSE; - - if (bfd_bwrite (s, (bfd_size_type) i, abfd) != i) - { - free (s); - return FALSE; - } - free (s); - } - - return TRUE; -} - -/* Write out debugging information using accumulated linker - information. */ - -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) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - void * space = NULL; - bfd_size_type amt; - - if (! ecoff_write_symhdr (abfd, debug, swap, where)) - goto error_return; - - amt = ainfo->largest_file_shuffle; - space = bfd_malloc (amt); - if (space == NULL && ainfo->largest_file_shuffle != 0) - goto error_return; - - if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space) - || ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space) - || ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space) - || ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space) - || ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space)) - goto error_return; - - /* The string table is written out from the hash table if this is a - final link. */ - if (bfd_link_relocatable (info)) - { - BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL); - if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space)) - goto error_return; - } - else - { - unsigned long total; - bfd_byte null; - struct string_hash_entry *sh; - - BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); - null = 0; - if (bfd_bwrite (&null, (bfd_size_type) 1, abfd) != 1) - goto error_return; - total = 1; - BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); - for (sh = ainfo->ss_hash; - sh != (struct string_hash_entry *) NULL; - sh = sh->next) - { - size_t len; - - len = strlen (sh->root.string); - amt = len + 1; - if (bfd_bwrite (sh->root.string, amt, abfd) != amt) - goto error_return; - total += len + 1; - } - - if ((total & (swap->debug_align - 1)) != 0) - { - unsigned int i; - bfd_byte *s; - - i = swap->debug_align - (total & (swap->debug_align - 1)); - s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i); - if (s == NULL && i != 0) - goto error_return; - - if (bfd_bwrite (s, (bfd_size_type) i, abfd) != i) - { - free (s); - goto error_return; - } - free (s); - } - } - - /* The external strings and symbol are not converted over to using - shuffles. FIXME: They probably should be. */ - amt = debug->symbolic_header.issExtMax; - if (bfd_bwrite (debug->ssext, amt, abfd) != amt) - goto error_return; - if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0) - { - unsigned int i; - bfd_byte *s; - - i = (swap->debug_align - - (debug->symbolic_header.issExtMax & (swap->debug_align - 1))); - s = (bfd_byte *) bfd_zmalloc ((bfd_size_type) i); - if (s == NULL && i != 0) - goto error_return; - - if (bfd_bwrite (s, (bfd_size_type) i, abfd) != i) - { - free (s); - goto error_return; - } - free (s); - } - - if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space) - || ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space)) - goto error_return; - - BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0 - || (debug->symbolic_header.cbExtOffset - == (bfd_vma) bfd_tell (abfd))); - - amt = debug->symbolic_header.iextMax * swap->external_ext_size; - if (bfd_bwrite (debug->external_ext, amt, abfd) != amt) - goto error_return; - - if (space != NULL) - free (space); - return TRUE; - - error_return: - if (space != NULL) - free (space); - return FALSE; -} - -/* Handle the find_nearest_line function for both ECOFF and MIPS ELF - files. */ - -/* Compare FDR entries. This is called via qsort. */ - -static int -cmp_fdrtab_entry (const void * leftp, const void * rightp) -{ - const struct ecoff_fdrtab_entry *lp = - (const struct ecoff_fdrtab_entry *) leftp; - const struct ecoff_fdrtab_entry *rp = - (const struct ecoff_fdrtab_entry *) rightp; - - if (lp->base_addr < rp->base_addr) - return -1; - if (lp->base_addr > rp->base_addr) - return 1; - return 0; -} - -/* Each file descriptor (FDR) has a memory address, to simplify - looking up an FDR by address, we build a table covering all FDRs - that have a least one procedure descriptor in them. The final - table will be sorted by address so we can look it up via binary - search. */ - -static bfd_boolean -mk_fdrtab (bfd *abfd, - struct ecoff_debug_info * const debug_info, - const struct ecoff_debug_swap * const debug_swap, - struct ecoff_find_line *line_info) -{ - struct ecoff_fdrtab_entry *tab; - FDR *fdr_ptr; - FDR *fdr_start; - FDR *fdr_end; - bfd_boolean stabs; - long len; - bfd_size_type amt; - - fdr_start = debug_info->fdr; - fdr_end = fdr_start + debug_info->symbolic_header.ifdMax; - - /* First, let's see how long the table needs to be. */ - for (len = 0, fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) - { - if (fdr_ptr->cpd == 0) /* Skip FDRs that have no PDRs. */ - continue; - ++len; - } - - /* Now, create and fill in the table. */ - amt = (bfd_size_type) len * sizeof (struct ecoff_fdrtab_entry); - line_info->fdrtab = (struct ecoff_fdrtab_entry*) bfd_zalloc (abfd, amt); - if (line_info->fdrtab == NULL) - return FALSE; - line_info->fdrtab_len = len; - - tab = line_info->fdrtab; - for (fdr_ptr = fdr_start; fdr_ptr < fdr_end; fdr_ptr++) - { - if (fdr_ptr->cpd == 0) - continue; - - /* Check whether this file has stabs debugging information. In - a file with stabs debugging information, the second local - symbol is named @stabs. */ - stabs = FALSE; - if (fdr_ptr->csym >= 2) - { - char *sym_ptr; - SYMR sym; - - sym_ptr = ((char *) debug_info->external_sym - + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); - (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); - if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, - STABS_SYMBOL) == 0) - stabs = TRUE; - } - - if (!stabs) - { - /* eraxxon: There are at least two problems with this computation: - 1) PDRs do *not* contain offsets but full vma's; and typically the - address of the first PDR is the address of the FDR, which will - make (most) of the results of the original computation 0! - 2) Once in a wacky while, the Compaq compiler generated PDR - addresses do not equal the FDR vma, but they (the PDR address) - are still vma's and not offsets. Cf. comments in - 'lookup_line'. */ - /* The address of the first PDR is the offset of that - procedure relative to the beginning of file FDR. */ - tab->base_addr = fdr_ptr->adr; - } - else - { - /* XXX I don't know about stabs, so this is a guess - (davidm@cs.arizona.edu). */ - tab->base_addr = fdr_ptr->adr; - } - tab->fdr = fdr_ptr; - ++tab; - } - - /* Finally, the table is sorted in increasing memory-address order. - The table is mostly sorted already, but there are cases (e.g., - static functions in include files), where this does not hold. - Use "odump -PFv" to verify... */ - qsort (line_info->fdrtab, (size_t) len, - sizeof (struct ecoff_fdrtab_entry), cmp_fdrtab_entry); - - return TRUE; -} - -/* Return index of first FDR that covers to OFFSET. */ - -static long -fdrtab_lookup (struct ecoff_find_line *line_info, bfd_vma offset) -{ - long low, high, len; - long mid = -1; - struct ecoff_fdrtab_entry *tab; - - len = line_info->fdrtab_len; - if (len == 0) - return -1; - - tab = line_info->fdrtab; - for (low = 0, high = len - 1 ; low != high ;) - { - mid = (high + low) / 2; - if (offset >= tab[mid].base_addr && offset < tab[mid + 1].base_addr) - goto find_min; - - if (tab[mid].base_addr > offset) - high = mid; - else - low = mid + 1; - } - - /* eraxxon: at this point 'offset' is either lower than the lowest entry or - higher than the highest entry. In the former case high = low = mid = 0; - we want to return -1. In the latter case, low = high and mid = low - 1; - we want to return the index of the highest entry. Only in former case - will the following 'catch-all' test be true. */ - ++mid; - - /* Last entry is catch-all for all higher addresses. */ - if (offset < tab[mid].base_addr) - return -1; - - find_min: - - /* eraxxon: There may be multiple FDRs in the table with the - same base_addr; make sure that we are at the first one. */ - while (mid > 0 && tab[mid - 1].base_addr == tab[mid].base_addr) - --mid; - - return mid; -} - -/* Look up a line given an address, storing the information in - LINE_INFO->cache. */ - -static bfd_boolean -lookup_line (bfd *abfd, - struct ecoff_debug_info * const debug_info, - const struct ecoff_debug_swap * const debug_swap, - struct ecoff_find_line *line_info) -{ - struct ecoff_fdrtab_entry *tab; - bfd_vma offset; - bfd_boolean stabs; - FDR *fdr_ptr; - int i; - - /* eraxxon: note that 'offset' is the full vma, not a section offset. */ - offset = line_info->cache.start; - - /* Build FDR table (sorted by object file's base-address) if we - don't have it already. */ - if (line_info->fdrtab == NULL - && !mk_fdrtab (abfd, debug_info, debug_swap, line_info)) - return FALSE; - - tab = line_info->fdrtab; - - /* Find first FDR for address OFFSET. */ - i = fdrtab_lookup (line_info, offset); - if (i < 0) - return FALSE; /* no FDR, no fun... */ - - /* eraxxon: 'fdrtab_lookup' doesn't give what we want, at least for Compaq's - C++ compiler 6.2. Consider three FDRs with starting addresses of x, y, - and z, respectively, such that x < y < z. Assume further that - y < 'offset' < z. It is possible at times that the PDR for 'offset' is - associated with FDR x and *not* with FDR y. Erg!! - - From a binary dump of my C++ test case 'moo' using Compaq's coffobjanl - (output format has been edited for our purposes): - - FDR [2]: (main.C): First instruction: 0x12000207c - PDR [5] for File [2]: LoopTest__Xv <0x1200020a0> (a) - PDR [7] for File [2]: foo__Xv <0x120002168> - FDR [1]: (-1): First instruction: 0x1200020e8 - PDR [3] for File [1]: <0x120001ad0> (b) - FDR [6]: (-1): First instruction: 0x1200026f0 - - (a) In the case of PDR5, the vma is such that the first few instructions - of the procedure can be found. But since the size of this procedure is - 160b, the vma will soon cross into the 'address space' of FDR1 and no - debugging info will be found. How repugnant! - - (b) It is also possible for a PDR to have a *lower* vma than its associated - FDR; see FDR1 and PDR3. Gross! - - Since the FDRs that are causing so much havok (in this case) 1) do not - describe actual files (fdr.rss == -1), and 2) contain only compiler - generated routines, I thought a simple fix would be to exclude them from - the FDR table in 'mk_fdrtab'. But, besides not knowing for certain - whether this would be correct, it creates an additional problem. If we - happen to ask for source file info on a compiler generated (procedure) - symbol -- which is still in the symbol table -- the result can be - information from a real procedure! This is because compiler generated - procedures with vma's higher than the last FDR in the fdr table will be - associated with a PDR from this FDR, specifically the PDR with the - highest vma. This wasn't a problem before, because each procedure had a - PDR. (Yes, this problem could be eliminated if we kept the size of the - last PDR around, but things are already getting ugly). - - Probably, a better solution would be to have a sorted PDR table. Each - PDR would have a pointer to its FDR so file information could still be - obtained. A FDR table could still be constructed if necessary -- since - it only contains pointers, not much extra memory would be used -- but - the PDR table would be searched to locate debugging info. - - There is still at least one remaining issue. Sometimes a FDR can have a - bogus name, but contain PDRs that should belong to another FDR with a - real name. E.g: - - FDR [3]: 0000000120001b50 (/home/.../Array.H~alt~deccxx_5E5A62AD) - PDR [a] for File [3]: 0000000120001b50 - PDR [b] for File [3]: 0000000120001cf0 - PDR [c] for File [3]: 0000000120001dc8 - PDR [d] for File [3]: 0000000120001e40 - PDR [e] for File [3]: 0000000120001eb8 - PDR [f] for File [3]: 0000000120001f4c - FDR [4]: 0000000120001b50 (/home/.../Array.H) - - Here, FDR4 has the correct name, but should (seemingly) contain PDRa-f. - The symbol table for PDR4 does contain symbols for PDRa-f, but so does - the symbol table for FDR3. However the former is different; perhaps this - can be detected easily. (I'm not sure at this point.) This problem only - seems to be associated with files with templates. I am assuming the idea - is that there is a 'fake' FDR (with PDRs) for each differently typed set - of templates that must be generated. Currently, FDR4 is completely - excluded from the FDR table in 'mk_fdrtab' because it contains no PDRs. - - Since I don't have time to prepare a real fix for this right now, be - prepared for 'A Horrible Hack' to force the inspection of all non-stabs - FDRs. It's coming... */ - fdr_ptr = tab[i].fdr; - - /* Check whether this file has stabs debugging information. In a - file with stabs debugging information, the second local symbol is - named @stabs. */ - stabs = FALSE; - if (fdr_ptr->csym >= 2) - { - char *sym_ptr; - SYMR sym; - - sym_ptr = ((char *) debug_info->external_sym - + (fdr_ptr->isymBase + 1) * debug_swap->external_sym_size); - (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); - if (strcmp (debug_info->ss + fdr_ptr->issBase + sym.iss, - STABS_SYMBOL) == 0) - stabs = TRUE; - } - - if (!stabs) - { - bfd_size_type external_pdr_size; - char *pdr_ptr; - char *best_pdr = NULL; - FDR *best_fdr; - bfd_signed_vma best_dist = -1; - PDR pdr; - unsigned char *line_ptr; - unsigned char *line_end; - int lineno; - /* This file uses ECOFF debugging information. Each FDR has a - list of procedure descriptors (PDR). The address in the FDR - is the absolute address of the first procedure. The address - in the first PDR gives the offset of that procedure relative - to the object file's base-address. The addresses in - subsequent PDRs specify each procedure's address relative to - the object file's base-address. To make things more juicy, - whenever the PROF bit in the PDR is set, the real entry point - of the procedure may be 16 bytes below what would normally be - the procedure's entry point. Instead, DEC came up with a - wicked scheme to create profiled libraries "on the fly": - instead of shipping a regular and a profiled version of each - library, they insert 16 bytes of unused space in front of - each procedure and set the "prof" bit in the PDR to indicate - that there is a gap there (this is done automagically by "as" - when option "-pg" is specified). Thus, normally, you link - against such a library and, except for lots of 16 byte gaps - between functions, things will behave as usual. However, - when invoking "ld" with option "-pg", it will fill those gaps - with code that calls mcount(). It then moves the function's - entry point down by 16 bytes, and out pops a binary that has - all functions profiled. - - NOTE: Neither FDRs nor PDRs are strictly sorted in memory - order. For example, when including header-files that - define functions, the FDRs follow behind the including - file, even though their code may have been generated at - a lower address. File coff-alpha.c from libbfd - illustrates this (use "odump -PFv" to look at a file's - FDR/PDR). Similarly, PDRs are sometimes out of order - as well. An example of this is OSF/1 v3.0 libc's - malloc.c. I'm not sure why this happens, but it could - be due to optimizations that reorder a function's - position within an object-file. - - Strategy: - - On the first call to this function, we build a table of FDRs - that is sorted by the base-address of the object-file the FDR - is referring to. Notice that each object-file may contain - code from multiple source files (e.g., due to code defined in - include files). Thus, for any given base-address, there may - be multiple FDRs (but this case is, fortunately, uncommon). - lookup(addr) guarantees to return the first FDR that applies - to address ADDR. Thus, after invoking lookup(), we have a - list of FDRs that may contain the PDR for ADDR. Next, we - walk through the PDRs of these FDRs and locate the one that - is closest to ADDR (i.e., for which the difference between - ADDR and the PDR's entry point is positive and minimal). - Once, the right FDR and PDR are located, we simply walk - through the line-number table to lookup the line-number that - best matches ADDR. Obviously, things could be sped up by - keeping a sorted list of PDRs instead of a sorted list of - FDRs. However, this would increase space requirements - considerably, which is undesirable. */ - external_pdr_size = debug_swap->external_pdr_size; - - /* eraxxon: The Horrible Hack: Because of the problems above, set 'i' - to 0 so we look through all FDRs. - - Because FDR's without any symbols are assumed to be non-stabs, - searching through all FDRs may cause the following code to try to - read stabs FDRs as ECOFF ones. However, I don't think this will - harm anything. */ - i = 0; - - /* Search FDR list starting at tab[i] for the PDR that best matches - OFFSET. Normally, the FDR list is only one entry long. */ - best_fdr = NULL; - do - { - /* eraxxon: 'dist' and 'min_dist' can be negative now - because we iterate over every FDR rather than just ones - with a base address less than or equal to 'offset'. */ - bfd_signed_vma dist = -1, min_dist = -1; - char *pdr_hold; - char *pdr_end; - - fdr_ptr = tab[i].fdr; - - pdr_ptr = ((char *) debug_info->external_pdr - + fdr_ptr->ipdFirst * external_pdr_size); - pdr_end = pdr_ptr + fdr_ptr->cpd * external_pdr_size; - (*debug_swap->swap_pdr_in) (abfd, pdr_ptr, &pdr); - /* Find PDR that is closest to OFFSET. If pdr.prof is set, - the procedure entry-point *may* be 0x10 below pdr.adr. We - simply pretend that pdr.prof *implies* a lower entry-point. - This is safe because it just means that may identify 4 NOPs - in front of the function as belonging to the function. */ - for (pdr_hold = NULL; - pdr_ptr < pdr_end; - (pdr_ptr += external_pdr_size, - (*debug_swap->swap_pdr_in) (abfd, pdr_ptr, &pdr))) - { - if (offset >= (pdr.adr - 0x10 * pdr.prof)) - { - dist = offset - (pdr.adr - 0x10 * pdr.prof); - - /* eraxxon: 'dist' can be negative now. Note that - 'min_dist' can be negative if 'pdr_hold' below is NULL. */ - if (!pdr_hold || (dist >= 0 && dist < min_dist)) - { - min_dist = dist; - pdr_hold = pdr_ptr; - } - } - } - - if (!best_pdr || (min_dist >= 0 && min_dist < best_dist)) - { - best_dist = (bfd_vma) min_dist; - best_fdr = fdr_ptr; - best_pdr = pdr_hold; - } - /* Continue looping until base_addr of next entry is different. */ - } - /* eraxxon: We want to iterate over all FDRs. - See previous comment about 'fdrtab_lookup'. */ - while (++i < line_info->fdrtab_len); - - if (!best_fdr || !best_pdr) - return FALSE; /* Shouldn't happen... */ - - /* Phew, finally we got something that we can hold onto. */ - fdr_ptr = best_fdr; - pdr_ptr = best_pdr; - (*debug_swap->swap_pdr_in) (abfd, pdr_ptr, &pdr); - /* Now we can look for the actual line number. The line numbers - are stored in a very funky format, which I won't try to - describe. The search is bounded by the end of the FDRs line - number entries. */ - line_end = debug_info->line + fdr_ptr->cbLineOffset + fdr_ptr->cbLine; - - /* Make offset relative to procedure entry. */ - offset -= pdr.adr - 0x10 * pdr.prof; - lineno = pdr.lnLow; - line_ptr = debug_info->line + fdr_ptr->cbLineOffset + pdr.cbLineOffset; - while (line_ptr < line_end) - { - int delta; - unsigned int count; - - delta = *line_ptr >> 4; - if (delta >= 0x8) - delta -= 0x10; - count = (*line_ptr & 0xf) + 1; - ++line_ptr; - if (delta == -8) - { - delta = (((line_ptr[0]) & 0xff) << 8) + ((line_ptr[1]) & 0xff); - if (delta >= 0x8000) - delta -= 0x10000; - line_ptr += 2; - } - lineno += delta; - if (offset < count * 4) - { - line_info->cache.stop += count * 4 - offset; - break; - } - offset -= count * 4; - } - - /* If fdr_ptr->rss is -1, then this file does not have full - symbols, at least according to gdb/mipsread.c. */ - if (fdr_ptr->rss == -1) - { - line_info->cache.filename = NULL; - if (pdr.isym == -1) - line_info->cache.functionname = NULL; - else - { - EXTR proc_ext; - - (*debug_swap->swap_ext_in) - (abfd, - ((char *) debug_info->external_ext - + pdr.isym * debug_swap->external_ext_size), - &proc_ext); - line_info->cache.functionname = (debug_info->ssext - + proc_ext.asym.iss); - } - } - else - { - SYMR proc_sym; - - line_info->cache.filename = (debug_info->ss - + fdr_ptr->issBase - + fdr_ptr->rss); - (*debug_swap->swap_sym_in) - (abfd, - ((char *) debug_info->external_sym - + ((fdr_ptr->isymBase + pdr.isym) - * debug_swap->external_sym_size)), - &proc_sym); - line_info->cache.functionname = (debug_info->ss - + fdr_ptr->issBase - + proc_sym.iss); - } - if (lineno == ilineNil) - lineno = 0; - line_info->cache.line_num = lineno; - } - else - { - bfd_size_type external_sym_size; - const char *directory_name; - const char *main_file_name; - const char *current_file_name; - const char *function_name; - const char *line_file_name; - bfd_vma low_func_vma; - bfd_vma low_line_vma; - bfd_boolean past_line; - bfd_boolean past_fn; - char *sym_ptr, *sym_ptr_end; - size_t len, funclen; - char *buffer = NULL; - - /* This file uses stabs debugging information. When gcc is not - optimizing, it will put the line number information before - the function name stabs entry. When gcc is optimizing, it - will put the stabs entry for all the function first, followed - by the line number information. (This appears to happen - because of the two output files used by the -mgpopt switch, - which is implied by -O). This means that we must keep - looking through the symbols until we find both a line number - and a function name which are beyond the address we want. */ - - line_info->cache.filename = NULL; - line_info->cache.functionname = NULL; - line_info->cache.line_num = 0; - - directory_name = NULL; - main_file_name = NULL; - current_file_name = NULL; - function_name = NULL; - line_file_name = NULL; - low_func_vma = 0; - low_line_vma = 0; - past_line = FALSE; - past_fn = FALSE; - - external_sym_size = debug_swap->external_sym_size; - - sym_ptr = ((char *) debug_info->external_sym - + (fdr_ptr->isymBase + 2) * external_sym_size); - sym_ptr_end = sym_ptr + (fdr_ptr->csym - 2) * external_sym_size; - for (; - sym_ptr < sym_ptr_end && (! past_line || ! past_fn); - sym_ptr += external_sym_size) - { - SYMR sym; - - (*debug_swap->swap_sym_in) (abfd, sym_ptr, &sym); - - if (ECOFF_IS_STAB (&sym)) - { - switch (ECOFF_UNMARK_STAB (sym.index)) - { - case N_SO: - main_file_name = current_file_name = - debug_info->ss + fdr_ptr->issBase + sym.iss; - - /* Check the next symbol to see if it is also an - N_SO symbol. */ - if (sym_ptr + external_sym_size < sym_ptr_end) - { - SYMR nextsym; - - (*debug_swap->swap_sym_in) (abfd, - sym_ptr + external_sym_size, - &nextsym); - if (ECOFF_IS_STAB (&nextsym) - && ECOFF_UNMARK_STAB (nextsym.index) == N_SO) - { - directory_name = current_file_name; - main_file_name = current_file_name = - debug_info->ss + fdr_ptr->issBase + nextsym.iss; - sym_ptr += external_sym_size; - } - } - break; - - case N_SOL: - current_file_name = - debug_info->ss + fdr_ptr->issBase + sym.iss; - break; - - case N_FUN: - if (sym.value > offset) - past_fn = TRUE; - else if (sym.value >= low_func_vma) - { - low_func_vma = sym.value; - function_name = - debug_info->ss + fdr_ptr->issBase + sym.iss; - } - break; - } - } - else if (sym.st == stLabel && sym.index != indexNil) - { - if (sym.value > offset) - past_line = TRUE; - else if (sym.value >= low_line_vma) - { - low_line_vma = sym.value; - line_file_name = current_file_name; - line_info->cache.line_num = sym.index; - } - } - } - - if (line_info->cache.line_num != 0) - main_file_name = line_file_name; - - /* We need to remove the stuff after the colon in the function - name. We also need to put the directory name and the file - name together. */ - if (function_name == NULL) - len = funclen = 0; - else - len = funclen = strlen (function_name) + 1; - - if (main_file_name != NULL - && directory_name != NULL - && main_file_name[0] != '/') - len += strlen (directory_name) + strlen (main_file_name) + 1; - - if (len != 0) - { - if (line_info->find_buffer != NULL) - free (line_info->find_buffer); - buffer = (char *) bfd_malloc ((bfd_size_type) len); - if (buffer == NULL) - return FALSE; - line_info->find_buffer = buffer; - } - - if (function_name != NULL) - { - char *colon; - - strcpy (buffer, function_name); - colon = strchr (buffer, ':'); - if (colon != NULL) - *colon = '\0'; - line_info->cache.functionname = buffer; - } - - if (main_file_name != NULL) - { - if (directory_name == NULL || main_file_name[0] == '/') - line_info->cache.filename = main_file_name; - else - { - sprintf (buffer + funclen, "%s%s", directory_name, - main_file_name); - line_info->cache.filename = buffer + funclen; - } - } - } - - return TRUE; -} - -/* Do the work of find_nearest_line. */ - -bfd_boolean -_bfd_ecoff_locate_line (bfd *abfd, - asection *section, - bfd_vma offset, - struct ecoff_debug_info * const debug_info, - const struct ecoff_debug_swap * const debug_swap, - struct ecoff_find_line *line_info, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *retline_ptr) -{ - offset += section->vma; - - if (line_info->cache.sect == NULL - || line_info->cache.sect != section - || offset < line_info->cache.start - || offset >= line_info->cache.stop) - { - line_info->cache.sect = section; - line_info->cache.start = offset; - line_info->cache.stop = offset; - if (! lookup_line (abfd, debug_info, debug_swap, line_info)) - { - line_info->cache.sect = NULL; - return FALSE; - } - } - - *filename_ptr = line_info->cache.filename; - *functionname_ptr = line_info->cache.functionname; - *retline_ptr = line_info->cache.line_num; - - return TRUE; -} - -/* These routines copy symbolic information into a memory buffer. - - FIXME: The whole point of the shuffle code is to avoid storing - everything in memory, since the linker is such a memory hog. This - code makes that effort useless. It is only called by the MIPS ELF - code when generating a shared library, so it is not that big a - deal, but it should be fixed eventually. */ - -/* Collect a shuffle into a memory buffer. */ - -static bfd_boolean -ecoff_collect_shuffle (struct shuffle *l, bfd_byte *buff) -{ - unsigned long total; - - total = 0; - for (; l != (struct shuffle *) NULL; l = l->next) - { - if (! l->filep) - memcpy (buff, l->u.memory, l->size); - else - { - if (bfd_seek (l->u.file.input_bfd, l->u.file.offset, SEEK_SET) != 0 - || (bfd_bread (buff, (bfd_size_type) l->size, l->u.file.input_bfd) - != l->size)) - return FALSE; - } - total += l->size; - buff += l->size; - } - - return TRUE; -} - -/* Copy PDR information into a memory buffer. */ - -bfd_boolean -_bfd_ecoff_get_accumulated_pdr (void * handle, - bfd_byte *buff) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - - return ecoff_collect_shuffle (ainfo->pdr, buff); -} - -/* Copy symbol information into a memory buffer. */ - -bfd_boolean -_bfd_ecoff_get_accumulated_sym (void * handle, bfd_byte *buff) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - - return ecoff_collect_shuffle (ainfo->sym, buff); -} - -/* Copy the string table into a memory buffer. */ - -bfd_boolean -_bfd_ecoff_get_accumulated_ss (void * handle, bfd_byte *buff) -{ - struct accumulate *ainfo = (struct accumulate *) handle; - struct string_hash_entry *sh; - unsigned long total; - - /* The string table is written out from the hash table if this is a - final link. */ - BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL); - *buff++ = '\0'; - total = 1; - BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1); - for (sh = ainfo->ss_hash; - sh != (struct string_hash_entry *) NULL; - sh = sh->next) - { - size_t len; - - len = strlen (sh->root.string); - memcpy (buff, sh->root.string, len + 1); - total += len + 1; - buff += len + 1; - } - - return TRUE; -} diff --git a/sdcc/support/sdbinutils/bfd/ecoffswap.h b/sdcc/support/sdbinutils/bfd/ecoffswap.h deleted file mode 100644 index 35524d1f1..000000000 --- a/sdcc/support/sdbinutils/bfd/ecoffswap.h +++ /dev/null @@ -1,772 +0,0 @@ -/* Generic ECOFF swapping routines, for BFD. - Copyright (C) 1992-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* NOTE: This is a header file, but it contains executable routines. - This is done this way because these routines are substantially - similar, but are not identical, for all ECOFF targets. - - These are routines to swap the ECOFF symbolic information in and - out. The routines are defined statically. You can set breakpoints - on them in gdb by naming the including source file; e.g., - 'coff-mips.c':ecoff_swap_hdr_in. - - Before including this header file, one of ECOFF_32, ECOFF_64, - ECOFF_SIGNED_32 or ECOFF_SIGNED_64 must be defined. These are - checked when swapping information that depends upon the target - size. This code works for 32 bit and 64 bit ECOFF, but may need to - be generalized in the future. - - Some header file which defines the external forms of these - structures must also be included before including this header file. - Currently this is either coff/mips.h or coff/alpha.h. - - If the symbol TEST is defined when this file is compiled, a - comparison is made to ensure that, in fact, the output is - bit-for-bit the same as the input. Of course, this symbol should - only be defined when deliberately testing the code on a machine - with the proper byte sex and such. */ - -#ifdef ECOFF_32 -#define ECOFF_GET_OFF H_GET_32 -#define ECOFF_PUT_OFF H_PUT_32 -#endif -#ifdef ECOFF_64 -#define ECOFF_GET_OFF H_GET_64 -#define ECOFF_PUT_OFF H_PUT_64 -#endif -#ifdef ECOFF_SIGNED_32 -#define ECOFF_GET_OFF H_GET_S32 -#define ECOFF_PUT_OFF H_PUT_S32 -#endif -#ifdef ECOFF_SIGNED_64 -#define ECOFF_GET_OFF H_GET_S64 -#define ECOFF_PUT_OFF H_PUT_S64 -#endif - -/* 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 *); - -/* Prototypes for functions defined in this file. */ - -static void ecoff_swap_hdr_in (bfd *, void *, HDRR *); -static void ecoff_swap_hdr_out (bfd *, const HDRR *, void *); -static void ecoff_swap_fdr_in (bfd *, void *, FDR *); -static void ecoff_swap_fdr_out (bfd *, const FDR *, void *); -static void ecoff_swap_pdr_in (bfd *, void *, PDR *); -static void ecoff_swap_pdr_out (bfd *, const PDR *, void *); -static void ecoff_swap_sym_in (bfd *, void *, SYMR *); -static void ecoff_swap_sym_out (bfd *, const SYMR *, void *); -static void ecoff_swap_ext_in (bfd *, void *, EXTR *); -static void ecoff_swap_ext_out (bfd *, const EXTR *, void *); -static void ecoff_swap_rfd_in (bfd *, void *, RFDT *); -static void ecoff_swap_rfd_out (bfd *, const RFDT *, void *); -static void ecoff_swap_opt_in (bfd *, void *, OPTR *); -static void ecoff_swap_opt_out (bfd *, const OPTR *, void *); -static void ecoff_swap_dnr_in (bfd *, void *, DNR *); -static void ecoff_swap_dnr_out (bfd *, const DNR *, void *); - -/* Swap in the symbolic header. */ - -static void -ecoff_swap_hdr_in (bfd *abfd, void * ext_copy, HDRR *intern) -{ - struct hdr_ext ext[1]; - - *ext = *(struct hdr_ext *) ext_copy; - - intern->magic = H_GET_S16 (abfd, ext->h_magic); - intern->vstamp = H_GET_S16 (abfd, ext->h_vstamp); - intern->ilineMax = H_GET_32 (abfd, ext->h_ilineMax); - intern->cbLine = ECOFF_GET_OFF (abfd, ext->h_cbLine); - intern->cbLineOffset = ECOFF_GET_OFF (abfd, ext->h_cbLineOffset); - intern->idnMax = H_GET_32 (abfd, ext->h_idnMax); - intern->cbDnOffset = ECOFF_GET_OFF (abfd, ext->h_cbDnOffset); - intern->ipdMax = H_GET_32 (abfd, ext->h_ipdMax); - intern->cbPdOffset = ECOFF_GET_OFF (abfd, ext->h_cbPdOffset); - intern->isymMax = H_GET_32 (abfd, ext->h_isymMax); - intern->cbSymOffset = ECOFF_GET_OFF (abfd, ext->h_cbSymOffset); - intern->ioptMax = H_GET_32 (abfd, ext->h_ioptMax); - intern->cbOptOffset = ECOFF_GET_OFF (abfd, ext->h_cbOptOffset); - intern->iauxMax = H_GET_32 (abfd, ext->h_iauxMax); - intern->cbAuxOffset = ECOFF_GET_OFF (abfd, ext->h_cbAuxOffset); - intern->issMax = H_GET_32 (abfd, ext->h_issMax); - intern->cbSsOffset = ECOFF_GET_OFF (abfd, ext->h_cbSsOffset); - intern->issExtMax = H_GET_32 (abfd, ext->h_issExtMax); - intern->cbSsExtOffset = ECOFF_GET_OFF (abfd, ext->h_cbSsExtOffset); - intern->ifdMax = H_GET_32 (abfd, ext->h_ifdMax); - intern->cbFdOffset = ECOFF_GET_OFF (abfd, ext->h_cbFdOffset); - intern->crfd = H_GET_32 (abfd, ext->h_crfd); - intern->cbRfdOffset = ECOFF_GET_OFF (abfd, ext->h_cbRfdOffset); - intern->iextMax = H_GET_32 (abfd, ext->h_iextMax); - intern->cbExtOffset = ECOFF_GET_OFF (abfd, ext->h_cbExtOffset); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out the symbolic header. */ - -static void -ecoff_swap_hdr_out (bfd *abfd, const HDRR *intern_copy, void * ext_ptr) -{ - struct hdr_ext *ext = (struct hdr_ext *) ext_ptr; - HDRR intern[1]; - - *intern = *intern_copy; - - H_PUT_S16 (abfd, intern->magic, ext->h_magic); - H_PUT_S16 (abfd, intern->vstamp, ext->h_vstamp); - H_PUT_32 (abfd, intern->ilineMax, ext->h_ilineMax); - ECOFF_PUT_OFF (abfd, intern->cbLine, ext->h_cbLine); - ECOFF_PUT_OFF (abfd, intern->cbLineOffset, ext->h_cbLineOffset); - H_PUT_32 (abfd, intern->idnMax, ext->h_idnMax); - ECOFF_PUT_OFF (abfd, intern->cbDnOffset, ext->h_cbDnOffset); - H_PUT_32 (abfd, intern->ipdMax, ext->h_ipdMax); - ECOFF_PUT_OFF (abfd, intern->cbPdOffset, ext->h_cbPdOffset); - H_PUT_32 (abfd, intern->isymMax, ext->h_isymMax); - ECOFF_PUT_OFF (abfd, intern->cbSymOffset, ext->h_cbSymOffset); - H_PUT_32 (abfd, intern->ioptMax, ext->h_ioptMax); - ECOFF_PUT_OFF (abfd, intern->cbOptOffset, ext->h_cbOptOffset); - H_PUT_32 (abfd, intern->iauxMax, ext->h_iauxMax); - ECOFF_PUT_OFF (abfd, intern->cbAuxOffset, ext->h_cbAuxOffset); - H_PUT_32 (abfd, intern->issMax, ext->h_issMax); - ECOFF_PUT_OFF (abfd, intern->cbSsOffset, ext->h_cbSsOffset); - H_PUT_32 (abfd, intern->issExtMax, ext->h_issExtMax); - ECOFF_PUT_OFF (abfd, intern->cbSsExtOffset, ext->h_cbSsExtOffset); - H_PUT_32 (abfd, intern->ifdMax, ext->h_ifdMax); - ECOFF_PUT_OFF (abfd, intern->cbFdOffset, ext->h_cbFdOffset); - H_PUT_32 (abfd, intern->crfd, ext->h_crfd); - ECOFF_PUT_OFF (abfd, intern->cbRfdOffset, ext->h_cbRfdOffset); - H_PUT_32 (abfd, intern->iextMax, ext->h_iextMax); - ECOFF_PUT_OFF (abfd, intern->cbExtOffset, ext->h_cbExtOffset); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in the file descriptor record. */ - -static void -ecoff_swap_fdr_in (bfd *abfd, void * ext_copy, FDR *intern) -{ - struct fdr_ext ext[1]; - - *ext = *(struct fdr_ext *) ext_copy; - - intern->adr = ECOFF_GET_OFF (abfd, ext->f_adr); - intern->rss = H_GET_32 (abfd, ext->f_rss); -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - if (intern->rss == (signed long) 0xffffffff) - intern->rss = -1; -#endif - intern->issBase = H_GET_32 (abfd, ext->f_issBase); - intern->cbSs = ECOFF_GET_OFF (abfd, ext->f_cbSs); - intern->isymBase = H_GET_32 (abfd, ext->f_isymBase); - intern->csym = H_GET_32 (abfd, ext->f_csym); - intern->ilineBase = H_GET_32 (abfd, ext->f_ilineBase); - intern->cline = H_GET_32 (abfd, ext->f_cline); - intern->ioptBase = H_GET_32 (abfd, ext->f_ioptBase); - intern->copt = H_GET_32 (abfd, ext->f_copt); -#if defined (ECOFF_32) || defined (ECOFF_SIGNED_32) - intern->ipdFirst = H_GET_16 (abfd, ext->f_ipdFirst); - intern->cpd = H_GET_16 (abfd, ext->f_cpd); -#endif -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - intern->ipdFirst = H_GET_32 (abfd, ext->f_ipdFirst); - intern->cpd = H_GET_32 (abfd, ext->f_cpd); -#endif - intern->iauxBase = H_GET_32 (abfd, ext->f_iauxBase); - intern->caux = H_GET_32 (abfd, ext->f_caux); - intern->rfdBase = H_GET_32 (abfd, ext->f_rfdBase); - intern->crfd = H_GET_32 (abfd, ext->f_crfd); - - /* Now the fun stuff... */ - if (bfd_header_big_endian (abfd)) - { - intern->lang = ((ext->f_bits1[0] & FDR_BITS1_LANG_BIG) - >> FDR_BITS1_LANG_SH_BIG); - intern->fMerge = 0 != (ext->f_bits1[0] & FDR_BITS1_FMERGE_BIG); - intern->fReadin = 0 != (ext->f_bits1[0] & FDR_BITS1_FREADIN_BIG); - intern->fBigendian = 0 != (ext->f_bits1[0] & FDR_BITS1_FBIGENDIAN_BIG); - intern->glevel = ((ext->f_bits2[0] & FDR_BITS2_GLEVEL_BIG) - >> FDR_BITS2_GLEVEL_SH_BIG); - } - else - { - intern->lang = ((ext->f_bits1[0] & FDR_BITS1_LANG_LITTLE) - >> FDR_BITS1_LANG_SH_LITTLE); - intern->fMerge = 0 != (ext->f_bits1[0] & FDR_BITS1_FMERGE_LITTLE); - intern->fReadin = 0 != (ext->f_bits1[0] & FDR_BITS1_FREADIN_LITTLE); - intern->fBigendian = 0 != (ext->f_bits1[0] & FDR_BITS1_FBIGENDIAN_LITTLE); - intern->glevel = ((ext->f_bits2[0] & FDR_BITS2_GLEVEL_LITTLE) - >> FDR_BITS2_GLEVEL_SH_LITTLE); - } - intern->reserved = 0; - - intern->cbLineOffset = ECOFF_GET_OFF (abfd, ext->f_cbLineOffset); - intern->cbLine = ECOFF_GET_OFF (abfd, ext->f_cbLine); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out the file descriptor record. */ - -static void -ecoff_swap_fdr_out (bfd *abfd, const FDR *intern_copy, void * ext_ptr) -{ - struct fdr_ext *ext = (struct fdr_ext *) ext_ptr; - FDR intern[1]; - - /* Make it reasonable to do in-place. */ - *intern = *intern_copy; - - ECOFF_PUT_OFF (abfd, intern->adr, ext->f_adr); - H_PUT_32 (abfd, intern->rss, ext->f_rss); - H_PUT_32 (abfd, intern->issBase, ext->f_issBase); - ECOFF_PUT_OFF (abfd, intern->cbSs, ext->f_cbSs); - H_PUT_32 (abfd, intern->isymBase, ext->f_isymBase); - H_PUT_32 (abfd, intern->csym, ext->f_csym); - H_PUT_32 (abfd, intern->ilineBase, ext->f_ilineBase); - H_PUT_32 (abfd, intern->cline, ext->f_cline); - H_PUT_32 (abfd, intern->ioptBase, ext->f_ioptBase); - H_PUT_32 (abfd, intern->copt, ext->f_copt); -#if defined (ECOFF_32) || defined (ECOFF_SIGNED_32) - H_PUT_16 (abfd, intern->ipdFirst, ext->f_ipdFirst); - H_PUT_16 (abfd, intern->cpd, ext->f_cpd); -#endif -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - H_PUT_32 (abfd, intern->ipdFirst, ext->f_ipdFirst); - H_PUT_32 (abfd, intern->cpd, ext->f_cpd); -#endif - H_PUT_32 (abfd, intern->iauxBase, ext->f_iauxBase); - H_PUT_32 (abfd, intern->caux, ext->f_caux); - H_PUT_32 (abfd, intern->rfdBase, ext->f_rfdBase); - H_PUT_32 (abfd, intern->crfd, ext->f_crfd); - - /* Now the fun stuff... */ - if (bfd_header_big_endian (abfd)) - { - ext->f_bits1[0] = (((intern->lang << FDR_BITS1_LANG_SH_BIG) - & FDR_BITS1_LANG_BIG) - | (intern->fMerge ? FDR_BITS1_FMERGE_BIG : 0) - | (intern->fReadin ? FDR_BITS1_FREADIN_BIG : 0) - | (intern->fBigendian ? FDR_BITS1_FBIGENDIAN_BIG : 0)); - ext->f_bits2[0] = ((intern->glevel << FDR_BITS2_GLEVEL_SH_BIG) - & FDR_BITS2_GLEVEL_BIG); - ext->f_bits2[1] = 0; - ext->f_bits2[2] = 0; - } - else - { - ext->f_bits1[0] = (((intern->lang << FDR_BITS1_LANG_SH_LITTLE) - & FDR_BITS1_LANG_LITTLE) - | (intern->fMerge ? FDR_BITS1_FMERGE_LITTLE : 0) - | (intern->fReadin ? FDR_BITS1_FREADIN_LITTLE : 0) - | (intern->fBigendian ? FDR_BITS1_FBIGENDIAN_LITTLE : 0)); - ext->f_bits2[0] = ((intern->glevel << FDR_BITS2_GLEVEL_SH_LITTLE) - & FDR_BITS2_GLEVEL_LITTLE); - ext->f_bits2[1] = 0; - ext->f_bits2[2] = 0; - } - - ECOFF_PUT_OFF (abfd, intern->cbLineOffset, ext->f_cbLineOffset); - ECOFF_PUT_OFF (abfd, intern->cbLine, ext->f_cbLine); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in the procedure descriptor record. */ - -static void -ecoff_swap_pdr_in (bfd *abfd, void * ext_copy, PDR *intern) -{ - struct pdr_ext ext[1]; - - *ext = *(struct pdr_ext *) ext_copy; - - memset ((void *) intern, 0, sizeof (*intern)); - - intern->adr = ECOFF_GET_OFF (abfd, ext->p_adr); - intern->isym = H_GET_32 (abfd, ext->p_isym); - intern->iline = H_GET_32 (abfd, ext->p_iline); - intern->regmask = H_GET_32 (abfd, ext->p_regmask); - intern->regoffset = H_GET_S32 (abfd, ext->p_regoffset); - intern->iopt = H_GET_S32 (abfd, ext->p_iopt); - intern->fregmask = H_GET_32 (abfd, ext->p_fregmask); - intern->fregoffset = H_GET_S32 (abfd, ext->p_fregoffset); - intern->frameoffset = H_GET_S32 (abfd, ext->p_frameoffset); - intern->framereg = H_GET_16 (abfd, ext->p_framereg); - intern->pcreg = H_GET_16 (abfd, ext->p_pcreg); - intern->lnLow = H_GET_32 (abfd, ext->p_lnLow); - intern->lnHigh = H_GET_32 (abfd, ext->p_lnHigh); - intern->cbLineOffset = ECOFF_GET_OFF (abfd, ext->p_cbLineOffset); - -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - if (intern->isym == (signed long) 0xffffffff) - intern->isym = -1; - if (intern->iline == (signed long) 0xffffffff) - intern->iline = -1; - - intern->gp_prologue = H_GET_8 (abfd, ext->p_gp_prologue); - if (bfd_header_big_endian (abfd)) - { - intern->gp_used = 0 != (ext->p_bits1[0] & PDR_BITS1_GP_USED_BIG); - intern->reg_frame = 0 != (ext->p_bits1[0] & PDR_BITS1_REG_FRAME_BIG); - intern->prof = 0 != (ext->p_bits1[0] & PDR_BITS1_PROF_BIG); - intern->reserved = (((ext->p_bits1[0] & PDR_BITS1_RESERVED_BIG) - << PDR_BITS1_RESERVED_SH_LEFT_BIG) - | ((ext->p_bits2[0] & PDR_BITS2_RESERVED_BIG) - >> PDR_BITS2_RESERVED_SH_BIG)); - } - else - { - intern->gp_used = 0 != (ext->p_bits1[0] & PDR_BITS1_GP_USED_LITTLE); - intern->reg_frame = 0 != (ext->p_bits1[0] & PDR_BITS1_REG_FRAME_LITTLE); - intern->prof = 0 != (ext->p_bits1[0] & PDR_BITS1_PROF_LITTLE); - intern->reserved = (((ext->p_bits1[0] & PDR_BITS1_RESERVED_LITTLE) - >> PDR_BITS1_RESERVED_SH_LITTLE) - | ((ext->p_bits2[0] & PDR_BITS2_RESERVED_LITTLE) - << PDR_BITS2_RESERVED_SH_LEFT_LITTLE)); - } - intern->localoff = H_GET_8 (abfd, ext->p_localoff); -#endif - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out the procedure descriptor record. */ - -static void -ecoff_swap_pdr_out (bfd *abfd, const PDR *intern_copy, void * ext_ptr) -{ - struct pdr_ext *ext = (struct pdr_ext *) ext_ptr; - PDR intern[1]; - - /* Make it reasonable to do in-place. */ - *intern = *intern_copy; - - ECOFF_PUT_OFF (abfd, intern->adr, ext->p_adr); - H_PUT_32 (abfd, intern->isym, ext->p_isym); - H_PUT_32 (abfd, intern->iline, ext->p_iline); - H_PUT_32 (abfd, intern->regmask, ext->p_regmask); - H_PUT_32 (abfd, intern->regoffset, ext->p_regoffset); - H_PUT_32 (abfd, intern->iopt, ext->p_iopt); - H_PUT_32 (abfd, intern->fregmask, ext->p_fregmask); - H_PUT_32 (abfd, intern->fregoffset, ext->p_fregoffset); - H_PUT_32 (abfd, intern->frameoffset, ext->p_frameoffset); - H_PUT_16 (abfd, intern->framereg, ext->p_framereg); - H_PUT_16 (abfd, intern->pcreg, ext->p_pcreg); - H_PUT_32 (abfd, intern->lnLow, ext->p_lnLow); - H_PUT_32 (abfd, intern->lnHigh, ext->p_lnHigh); - ECOFF_PUT_OFF (abfd, intern->cbLineOffset, ext->p_cbLineOffset); - -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - H_PUT_8 (abfd, intern->gp_prologue, ext->p_gp_prologue); - - if (bfd_header_big_endian (abfd)) - { - ext->p_bits1[0] = ((intern->gp_used ? PDR_BITS1_GP_USED_BIG : 0) - | (intern->reg_frame ? PDR_BITS1_REG_FRAME_BIG : 0) - | (intern->prof ? PDR_BITS1_PROF_BIG : 0) - | ((intern->reserved - >> PDR_BITS1_RESERVED_SH_LEFT_BIG) - & PDR_BITS1_RESERVED_BIG)); - ext->p_bits2[0] = ((intern->reserved << PDR_BITS2_RESERVED_SH_BIG) - & PDR_BITS2_RESERVED_BIG); - } - else - { - ext->p_bits1[0] = ((intern->gp_used ? PDR_BITS1_GP_USED_LITTLE : 0) - | (intern->reg_frame ? PDR_BITS1_REG_FRAME_LITTLE : 0) - | (intern->prof ? PDR_BITS1_PROF_LITTLE : 0) - | ((intern->reserved << PDR_BITS1_RESERVED_SH_LITTLE) - & PDR_BITS1_RESERVED_LITTLE)); - ext->p_bits2[0] = ((intern->reserved >> - PDR_BITS2_RESERVED_SH_LEFT_LITTLE) - & PDR_BITS2_RESERVED_LITTLE); - } - H_PUT_8 (abfd, intern->localoff, ext->p_localoff); -#endif - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in a symbol record. */ - -static void -ecoff_swap_sym_in (bfd *abfd, void * ext_copy, SYMR *intern) -{ - struct sym_ext ext[1]; - - *ext = *(struct sym_ext *) ext_copy; - - intern->iss = H_GET_32 (abfd, ext->s_iss); - intern->value = ECOFF_GET_OFF (abfd, ext->s_value); - -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - if (intern->iss == (signed long) 0xffffffff) - intern->iss = -1; -#endif - - /* Now the fun stuff... */ - if (bfd_header_big_endian (abfd)) - { - intern->st = (ext->s_bits1[0] & SYM_BITS1_ST_BIG) - >> SYM_BITS1_ST_SH_BIG; - intern->sc = ((ext->s_bits1[0] & SYM_BITS1_SC_BIG) - << SYM_BITS1_SC_SH_LEFT_BIG) - | ((ext->s_bits2[0] & SYM_BITS2_SC_BIG) - >> SYM_BITS2_SC_SH_BIG); - intern->reserved = 0 != (ext->s_bits2[0] & SYM_BITS2_RESERVED_BIG); - intern->index = ((ext->s_bits2[0] & SYM_BITS2_INDEX_BIG) - << SYM_BITS2_INDEX_SH_LEFT_BIG) - | (ext->s_bits3[0] << SYM_BITS3_INDEX_SH_LEFT_BIG) - | (ext->s_bits4[0] << SYM_BITS4_INDEX_SH_LEFT_BIG); - } - else - { - intern->st = (ext->s_bits1[0] & SYM_BITS1_ST_LITTLE) - >> SYM_BITS1_ST_SH_LITTLE; - intern->sc = ((ext->s_bits1[0] & SYM_BITS1_SC_LITTLE) - >> SYM_BITS1_SC_SH_LITTLE) - | ((ext->s_bits2[0] & SYM_BITS2_SC_LITTLE) - << SYM_BITS2_SC_SH_LEFT_LITTLE); - intern->reserved = 0 != (ext->s_bits2[0] & SYM_BITS2_RESERVED_LITTLE); - intern->index = ((ext->s_bits2[0] & SYM_BITS2_INDEX_LITTLE) - >> SYM_BITS2_INDEX_SH_LITTLE) - | (ext->s_bits3[0] << SYM_BITS3_INDEX_SH_LEFT_LITTLE) - | ((unsigned int) ext->s_bits4[0] - << SYM_BITS4_INDEX_SH_LEFT_LITTLE); - } - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out a symbol record. */ - -static void -ecoff_swap_sym_out (bfd *abfd, const SYMR *intern_copy, void * ext_ptr) -{ - struct sym_ext *ext = (struct sym_ext *) ext_ptr; - SYMR intern[1]; - - /* Make it reasonable to do in-place. */ - *intern = *intern_copy; - - H_PUT_32 (abfd, intern->iss, ext->s_iss); - ECOFF_PUT_OFF (abfd, intern->value, ext->s_value); - - /* Now the fun stuff... */ - if (bfd_header_big_endian (abfd)) - { - ext->s_bits1[0] = (((intern->st << SYM_BITS1_ST_SH_BIG) - & SYM_BITS1_ST_BIG) - | ((intern->sc >> SYM_BITS1_SC_SH_LEFT_BIG) - & SYM_BITS1_SC_BIG)); - ext->s_bits2[0] = (((intern->sc << SYM_BITS2_SC_SH_BIG) - & SYM_BITS2_SC_BIG) - | (intern->reserved ? SYM_BITS2_RESERVED_BIG : 0) - | ((intern->index >> SYM_BITS2_INDEX_SH_LEFT_BIG) - & SYM_BITS2_INDEX_BIG)); - ext->s_bits3[0] = (intern->index >> SYM_BITS3_INDEX_SH_LEFT_BIG) & 0xff; - ext->s_bits4[0] = (intern->index >> SYM_BITS4_INDEX_SH_LEFT_BIG) & 0xff; - } - else - { - ext->s_bits1[0] = (((intern->st << SYM_BITS1_ST_SH_LITTLE) - & SYM_BITS1_ST_LITTLE) - | ((intern->sc << SYM_BITS1_SC_SH_LITTLE) - & SYM_BITS1_SC_LITTLE)); - ext->s_bits2[0] = (((intern->sc >> SYM_BITS2_SC_SH_LEFT_LITTLE) - & SYM_BITS2_SC_LITTLE) - | (intern->reserved ? SYM_BITS2_RESERVED_LITTLE : 0) - | ((intern->index << SYM_BITS2_INDEX_SH_LITTLE) - & SYM_BITS2_INDEX_LITTLE)); - ext->s_bits3[0] = (intern->index >> SYM_BITS3_INDEX_SH_LEFT_LITTLE) & 0xff; - ext->s_bits4[0] = (intern->index >> SYM_BITS4_INDEX_SH_LEFT_LITTLE) & 0xff; - } - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in an external symbol record. */ - -static void -ecoff_swap_ext_in (bfd *abfd, void * ext_copy, EXTR *intern) -{ - struct ext_ext ext[1]; - - *ext = *(struct ext_ext *) ext_copy; - - /* Now the fun stuff... */ - if (bfd_header_big_endian (abfd)) - { - intern->jmptbl = 0 != (ext->es_bits1[0] & EXT_BITS1_JMPTBL_BIG); - intern->cobol_main = 0 != (ext->es_bits1[0] & EXT_BITS1_COBOL_MAIN_BIG); - intern->weakext = 0 != (ext->es_bits1[0] & EXT_BITS1_WEAKEXT_BIG); - } - else - { - intern->jmptbl = 0 != (ext->es_bits1[0] & EXT_BITS1_JMPTBL_LITTLE); - intern->cobol_main = 0 != (ext->es_bits1[0] & EXT_BITS1_COBOL_MAIN_LITTLE); - intern->weakext = 0 != (ext->es_bits1[0] & EXT_BITS1_WEAKEXT_LITTLE); - } - intern->reserved = 0; - -#if defined (ECOFF_32) || defined (ECOFF_SIGNED_32) - intern->ifd = H_GET_S16 (abfd, ext->es_ifd); -#endif -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - intern->ifd = H_GET_S32 (abfd, ext->es_ifd); -#endif - - ecoff_swap_sym_in (abfd, &ext->es_asym, &intern->asym); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out an external symbol record. */ - -static void -ecoff_swap_ext_out (bfd *abfd, const EXTR *intern_copy, void * ext_ptr) -{ - struct ext_ext *ext = (struct ext_ext *) ext_ptr; - EXTR intern[1]; - - /* Make it reasonable to do in-place. */ - *intern = *intern_copy; - - /* Now the fun stuff... */ - if (bfd_header_big_endian (abfd)) - { - ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_BIG : 0) - | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_BIG : 0) - | (intern->weakext ? EXT_BITS1_WEAKEXT_BIG : 0)); - ext->es_bits2[0] = 0; -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - ext->es_bits2[1] = 0; - ext->es_bits2[2] = 0; -#endif - } - else - { - ext->es_bits1[0] = ((intern->jmptbl ? EXT_BITS1_JMPTBL_LITTLE : 0) - | (intern->cobol_main ? EXT_BITS1_COBOL_MAIN_LITTLE : 0) - | (intern->weakext ? EXT_BITS1_WEAKEXT_LITTLE : 0)); - ext->es_bits2[0] = 0; -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - ext->es_bits2[1] = 0; - ext->es_bits2[2] = 0; -#endif - } - -#if defined (ECOFF_32) || defined (ECOFF_SIGNED_32) - H_PUT_S16 (abfd, intern->ifd, ext->es_ifd); -#endif -#if defined (ECOFF_64) || defined (ECOFF_SIGNED_64) - H_PUT_S32 (abfd, intern->ifd, ext->es_ifd); -#endif - - ecoff_swap_sym_out (abfd, &intern->asym, &ext->es_asym); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in a relative file descriptor. */ - -static void -ecoff_swap_rfd_in (bfd *abfd, void * ext_ptr, RFDT *intern) -{ - struct rfd_ext *ext = (struct rfd_ext *) ext_ptr; - - *intern = H_GET_32 (abfd, ext->rfd); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out a relative file descriptor. */ - -static void -ecoff_swap_rfd_out (bfd *abfd, const RFDT *intern, void * ext_ptr) -{ - struct rfd_ext *ext = (struct rfd_ext *) ext_ptr; - - H_PUT_32 (abfd, *intern, ext->rfd); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in an optimization symbol. */ - -static void -ecoff_swap_opt_in (bfd *abfd, void * ext_copy, OPTR * intern) -{ - struct opt_ext ext[1]; - - *ext = *(struct opt_ext *) ext_copy; - - if (bfd_header_big_endian (abfd)) - { - intern->ot = ext->o_bits1[0]; - intern->value = (((unsigned int) ext->o_bits2[0] - << OPT_BITS2_VALUE_SH_LEFT_BIG) - | ((unsigned int) ext->o_bits3[0] - << OPT_BITS2_VALUE_SH_LEFT_BIG) - | ((unsigned int) ext->o_bits4[0] - << OPT_BITS2_VALUE_SH_LEFT_BIG)); - } - else - { - intern->ot = ext->o_bits1[0]; - intern->value = ((ext->o_bits2[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE) - | (ext->o_bits3[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE) - | (ext->o_bits4[0] << OPT_BITS2_VALUE_SH_LEFT_LITTLE)); - } - - _bfd_ecoff_swap_rndx_in (bfd_header_big_endian (abfd), - &ext->o_rndx, &intern->rndx); - - intern->offset = H_GET_32 (abfd, ext->o_offset); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out an optimization symbol. */ - -static void -ecoff_swap_opt_out (bfd *abfd, const OPTR *intern_copy, void * ext_ptr) -{ - struct opt_ext *ext = (struct opt_ext *) ext_ptr; - OPTR intern[1]; - - /* Make it reasonable to do in-place. */ - *intern = *intern_copy; - - if (bfd_header_big_endian (abfd)) - { - ext->o_bits1[0] = intern->ot; - ext->o_bits2[0] = intern->value >> OPT_BITS2_VALUE_SH_LEFT_BIG; - ext->o_bits3[0] = intern->value >> OPT_BITS3_VALUE_SH_LEFT_BIG; - ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_BIG; - } - else - { - ext->o_bits1[0] = intern->ot; - ext->o_bits2[0] = intern->value >> OPT_BITS2_VALUE_SH_LEFT_LITTLE; - ext->o_bits3[0] = intern->value >> OPT_BITS3_VALUE_SH_LEFT_LITTLE; - ext->o_bits4[0] = intern->value >> OPT_BITS4_VALUE_SH_LEFT_LITTLE; - } - - _bfd_ecoff_swap_rndx_out (bfd_header_big_endian (abfd), - &intern->rndx, &ext->o_rndx); - - H_PUT_32 (abfd, intern->value, ext->o_offset); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap in a dense number. */ - -static void -ecoff_swap_dnr_in (bfd *abfd, void * ext_copy, DNR *intern) -{ - struct dnr_ext ext[1]; - - *ext = *(struct dnr_ext *) ext_copy; - - intern->rfd = H_GET_32 (abfd, ext->d_rfd); - intern->index = H_GET_32 (abfd, ext->d_index); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} - -/* Swap out a dense number. */ - -static void -ecoff_swap_dnr_out (bfd *abfd, const DNR *intern_copy, void * ext_ptr) -{ - struct dnr_ext *ext = (struct dnr_ext *) ext_ptr; - DNR intern[1]; - - /* Make it reasonable to do in-place. */ - *intern = *intern_copy; - - H_PUT_32 (abfd, intern->rfd, ext->d_rfd); - H_PUT_32 (abfd, intern->index, ext->d_index); - -#ifdef TEST - if (memcmp ((char *) ext, (char *) intern, sizeof (*intern)) != 0) - abort (); -#endif -} diff --git a/sdcc/support/sdbinutils/bfd/elf-attrs.c b/sdcc/support/sdbinutils/bfd/elf-attrs.c deleted file mode 100644 index 1783f636b..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-attrs.c +++ /dev/null @@ -1,734 +0,0 @@ -/* ELF attributes support (based on ARM EABI attributes). - Copyright (C) 2005-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libiberty.h" -#include "libbfd.h" -#include "elf-bfd.h" - -/* Return the number of bytes needed by I in uleb128 format. */ -static int -uleb128_size (unsigned int i) -{ - int size; - size = 1; - while (i >= 0x80) - { - i >>= 7; - size++; - } - return size; -} - -/* Return TRUE if the attribute has the default value (0/""). */ -static bfd_boolean -is_default_attr (obj_attribute *attr) -{ - if (ATTR_TYPE_HAS_INT_VAL (attr->type) && attr->i != 0) - return FALSE; - if (ATTR_TYPE_HAS_STR_VAL (attr->type) && attr->s && *attr->s) - return FALSE; - if (ATTR_TYPE_HAS_NO_DEFAULT (attr->type)) - return FALSE; - - return TRUE; -} - -/* Return the size of a single attribute. */ -static bfd_vma -obj_attr_size (unsigned int tag, obj_attribute *attr) -{ - bfd_vma size; - - if (is_default_attr (attr)) - return 0; - - size = uleb128_size (tag); - if (ATTR_TYPE_HAS_INT_VAL (attr->type)) - size += uleb128_size (attr->i); - if (ATTR_TYPE_HAS_STR_VAL (attr->type)) - size += strlen ((char *)attr->s) + 1; - return size; -} - -/* Return the vendor name for a given object attributes section. */ -static const char * -vendor_obj_attr_name (bfd *abfd, int vendor) -{ - return (vendor == OBJ_ATTR_PROC - ? get_elf_backend_data (abfd)->obj_attrs_vendor - : "gnu"); -} - -/* Return the size of the object attributes section for VENDOR - (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes - for that vendor to record and the vendor is OBJ_ATTR_GNU. */ -static bfd_vma -vendor_obj_attr_size (bfd *abfd, int vendor) -{ - bfd_vma size; - obj_attribute *attr; - obj_attribute_list *list; - int i; - const char *vendor_name = vendor_obj_attr_name (abfd, vendor); - - if (!vendor_name) - return 0; - - attr = elf_known_obj_attributes (abfd)[vendor]; - size = 0; - for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) - size += obj_attr_size (i, &attr[i]); - - for (list = elf_other_obj_attributes (abfd)[vendor]; - list; - list = list->next) - size += obj_attr_size (list->tag, &list->attr); - - /* NUL 0x1 */ - return ((size || vendor == OBJ_ATTR_PROC) - ? size + 10 + strlen (vendor_name) - : 0); -} - -/* Return the size of the object attributes section. */ -bfd_vma -bfd_elf_obj_attr_size (bfd *abfd) -{ - bfd_vma size; - - size = vendor_obj_attr_size (abfd, OBJ_ATTR_PROC); - size += vendor_obj_attr_size (abfd, OBJ_ATTR_GNU); - - /* 'A' */ - return (size ? size + 1 : 0); -} - -/* Write VAL in uleb128 format to P, returning a pointer to the - following byte. */ -static bfd_byte * -write_uleb128 (bfd_byte *p, unsigned int val) -{ - bfd_byte c; - do - { - c = val & 0x7f; - val >>= 7; - if (val) - c |= 0x80; - *(p++) = c; - } - while (val); - return p; -} - -/* Write attribute ATTR to butter P, and return a pointer to the following - byte. */ -static bfd_byte * -write_obj_attribute (bfd_byte *p, unsigned int tag, obj_attribute *attr) -{ - /* Suppress default entries. */ - if (is_default_attr (attr)) - return p; - - p = write_uleb128 (p, tag); - if (ATTR_TYPE_HAS_INT_VAL (attr->type)) - p = write_uleb128 (p, attr->i); - if (ATTR_TYPE_HAS_STR_VAL (attr->type)) - { - int len; - - len = strlen (attr->s) + 1; - memcpy (p, attr->s, len); - p += len; - } - - return p; -} - -/* Write the contents of the object attributes section (length SIZE) - for VENDOR to CONTENTS. */ -static void -vendor_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size, - int vendor) -{ - bfd_byte *p; - obj_attribute *attr; - obj_attribute_list *list; - int i; - const char *vendor_name = vendor_obj_attr_name (abfd, vendor); - size_t vendor_length = strlen (vendor_name) + 1; - - p = contents; - bfd_put_32 (abfd, size, p); - p += 4; - memcpy (p, vendor_name, vendor_length); - p += vendor_length; - *(p++) = Tag_File; - bfd_put_32 (abfd, size - 4 - vendor_length, p); - p += 4; - - attr = elf_known_obj_attributes (abfd)[vendor]; - for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) - { - unsigned int tag = i; - if (get_elf_backend_data (abfd)->obj_attrs_order) - tag = get_elf_backend_data (abfd)->obj_attrs_order (i); - p = write_obj_attribute (p, tag, &attr[tag]); - } - - for (list = elf_other_obj_attributes (abfd)[vendor]; - list; - list = list->next) - p = write_obj_attribute (p, list->tag, &list->attr); -} - -/* Write the contents of the object attributes section to CONTENTS. */ -void -bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *contents, bfd_vma size) -{ - bfd_byte *p; - int vendor; - bfd_vma my_size; - - p = contents; - *(p++) = 'A'; - my_size = 1; - for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) - { - bfd_vma vendor_size = vendor_obj_attr_size (abfd, vendor); - if (vendor_size) - vendor_set_obj_attr_contents (abfd, p, vendor_size, vendor); - p += vendor_size; - my_size += vendor_size; - } - - if (size != my_size) - abort (); -} - -/* Allocate/find an object attribute. */ -static obj_attribute * -elf_new_obj_attr (bfd *abfd, int vendor, unsigned int tag) -{ - obj_attribute *attr; - obj_attribute_list *list; - obj_attribute_list *p; - obj_attribute_list **lastp; - - - if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) - { - /* Known tags are preallocated. */ - attr = &elf_known_obj_attributes (abfd)[vendor][tag]; - } - else - { - /* Create a new tag. */ - list = (obj_attribute_list *) - bfd_alloc (abfd, sizeof (obj_attribute_list)); - memset (list, 0, sizeof (obj_attribute_list)); - list->tag = tag; - /* Keep the tag list in order. */ - lastp = &elf_other_obj_attributes (abfd)[vendor]; - for (p = *lastp; p; p = p->next) - { - if (tag < p->tag) - break; - lastp = &p->next; - } - list->next = *lastp; - *lastp = list; - attr = &list->attr; - } - - return attr; -} - -/* Return the value of an integer object attribute. */ -int -bfd_elf_get_obj_attr_int (bfd *abfd, int vendor, unsigned int tag) -{ - obj_attribute_list *p; - - if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) - { - /* Known tags are preallocated. */ - return elf_known_obj_attributes (abfd)[vendor][tag].i; - } - else - { - for (p = elf_other_obj_attributes (abfd)[vendor]; - p; - p = p->next) - { - if (tag == p->tag) - return p->attr.i; - if (tag < p->tag) - break; - } - return 0; - } -} - -/* Add an integer object attribute. */ -void -bfd_elf_add_obj_attr_int (bfd *abfd, int vendor, unsigned int tag, unsigned int i) -{ - obj_attribute *attr; - - attr = elf_new_obj_attr (abfd, vendor, tag); - attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); - attr->i = i; -} - -/* Duplicate an object attribute string value. */ -char * -_bfd_elf_attr_strdup (bfd *abfd, const char * s) -{ - char * p; - int len; - - len = strlen (s) + 1; - p = (char *) bfd_alloc (abfd, len); - return (char *) memcpy (p, s, len); -} - -/* Add a string object attribute. */ -void -bfd_elf_add_obj_attr_string (bfd *abfd, int vendor, unsigned int tag, const char *s) -{ - obj_attribute *attr; - - attr = elf_new_obj_attr (abfd, vendor, tag); - attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); - attr->s = _bfd_elf_attr_strdup (abfd, s); -} - -/* Add a int+string object attribute. */ -void -bfd_elf_add_obj_attr_int_string (bfd *abfd, int vendor, - unsigned int tag, - unsigned int i, const char *s) -{ - obj_attribute *attr; - - attr = elf_new_obj_attr (abfd, vendor, tag); - attr->type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); - attr->i = i; - attr->s = _bfd_elf_attr_strdup (abfd, s); -} - -/* Copy the object attributes from IBFD to OBFD. */ -void -_bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) -{ - obj_attribute *in_attr; - obj_attribute *out_attr; - obj_attribute_list *list; - int i; - int vendor; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return; - - for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) - { - in_attr - = &elf_known_obj_attributes (ibfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; - out_attr - = &elf_known_obj_attributes (obfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; - for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) - { - out_attr->type = in_attr->type; - out_attr->i = in_attr->i; - if (in_attr->s && *in_attr->s) - out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s); - in_attr++; - out_attr++; - } - - for (list = elf_other_obj_attributes (ibfd)[vendor]; - list; - list = list->next) - { - in_attr = &list->attr; - switch (in_attr->type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) - { - case ATTR_TYPE_FLAG_INT_VAL: - bfd_elf_add_obj_attr_int (obfd, vendor, list->tag, in_attr->i); - break; - case ATTR_TYPE_FLAG_STR_VAL: - bfd_elf_add_obj_attr_string (obfd, vendor, list->tag, - in_attr->s); - break; - case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: - bfd_elf_add_obj_attr_int_string (obfd, vendor, list->tag, - in_attr->i, in_attr->s); - break; - default: - abort (); - } - } - } -} - -/* Determine whether a GNU object attribute tag takes an integer, a - string or both. */ -static int -gnu_obj_attrs_arg_type (unsigned int tag) -{ - /* Except for Tag_compatibility, for GNU attributes we follow the - same rule ARM ones > 32 follow: odd-numbered tags take strings - and even-numbered tags take integers. In addition, tag & 2 is - nonzero for architecture-independent tags and zero for - architecture-dependent ones. */ - if (tag == Tag_compatibility) - return 3; - else - return (tag & 1) != 0 ? 2 : 1; -} - -/* Determine what arguments an attribute tag takes. */ -int -_bfd_elf_obj_attrs_arg_type (bfd *abfd, int vendor, unsigned int tag) -{ - switch (vendor) - { - case OBJ_ATTR_PROC: - return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag); - break; - case OBJ_ATTR_GNU: - return gnu_obj_attrs_arg_type (tag); - break; - default: - abort (); - } -} - -/* Parse an object attributes section. */ -void -_bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) -{ - bfd_byte *contents; - bfd_byte *p; - bfd_byte *p_end; - bfd_vma len; - const char *std_sec; - - /* PR 17512: file: 2844a11d. */ - if (hdr->sh_size == 0) - return; - contents = (bfd_byte *) bfd_malloc (hdr->sh_size + 1); - if (!contents) - return; - if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0, - hdr->sh_size)) - { - free (contents); - return; - } - /* Ensure that the buffer is NUL terminated. */ - contents[hdr->sh_size] = 0; - p = contents; - p_end = p + hdr->sh_size; - std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; - - if (*(p++) == 'A') - { - len = hdr->sh_size - 1; - - while (len > 0 && p < p_end - 4) - { - unsigned namelen; - bfd_vma section_len; - int vendor; - - section_len = bfd_get_32 (abfd, p); - p += 4; - if (section_len == 0) - break; - if (section_len > len) - section_len = len; - len -= section_len; - if (section_len <= 4) - { - _bfd_error_handler (_("%B: error: attribute section length too small: %ld"), - abfd, section_len); - break; - } - section_len -= 4; - namelen = strnlen ((char *) p, section_len) + 1; - if (namelen == 0 || namelen >= section_len) - break; - section_len -= namelen; - if (std_sec && strcmp ((char *) p, std_sec) == 0) - vendor = OBJ_ATTR_PROC; - else if (strcmp ((char *) p, "gnu") == 0) - vendor = OBJ_ATTR_GNU; - else - { - /* Other vendor section. Ignore it. */ - p += namelen + section_len; - continue; - } - - p += namelen; - while (section_len > 0 && p < p_end) - { - unsigned int tag; - unsigned int n; - unsigned int val; - bfd_vma subsection_len; - bfd_byte *end; - - tag = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, p_end); - p += n; - if (p < p_end - 4) - subsection_len = bfd_get_32 (abfd, p); - else - subsection_len = 0; - p += 4; - if (subsection_len == 0) - break; - if (subsection_len > section_len) - subsection_len = section_len; - section_len -= subsection_len; - subsection_len -= n + 4; - end = p + subsection_len; - /* PR 17512: file: 0e8c0c90. */ - if (end > p_end) - end = p_end; - switch (tag) - { - case Tag_File: - while (p < end) - { - int type; - - tag = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, end); - p += n; - type = _bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); - switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) - { - case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: - val = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, end); - p += n; - bfd_elf_add_obj_attr_int_string (abfd, vendor, tag, - val, (char *) p); - p += strlen ((char *)p) + 1; - break; - case ATTR_TYPE_FLAG_STR_VAL: - bfd_elf_add_obj_attr_string (abfd, vendor, tag, - (char *) p); - p += strlen ((char *)p) + 1; - break; - case ATTR_TYPE_FLAG_INT_VAL: - val = _bfd_safe_read_leb128 (abfd, p, &n, FALSE, end); - p += n; - bfd_elf_add_obj_attr_int (abfd, vendor, tag, val); - break; - default: - abort (); - } - } - break; - case Tag_Section: - case Tag_Symbol: - /* Don't have anywhere convenient to attach these. - Fall through for now. */ - default: - /* Ignore things we don't kow about. */ - p += subsection_len; - subsection_len = 0; - break; - } - } - } - } - free (contents); -} - -/* Merge common object attributes from IBFD into OBFD. Raise an error - if there are conflicting attributes. Any processor-specific - attributes have already been merged. This must be called from the - bfd_elfNN_bfd_merge_private_bfd_data hook for each individual - target, along with any target-specific merging. Because there are - no common attributes other than Tag_compatibility at present, and - non-"gnu" Tag_compatibility is not expected in "gnu" sections, this - is not presently called for targets without their own - attributes. */ - -bfd_boolean -_bfd_elf_merge_object_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - obj_attribute *in_attr; - obj_attribute *out_attr; - int vendor; - - /* The only common attribute is currently Tag_compatibility, - accepted in both processor and "gnu" sections. */ - for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) - { - /* Handle Tag_compatibility. The tags are only compatible if the flags - are identical and, if the flags are '1', the strings are identical. - If the flags are non-zero, then we can only use the string "gnu". */ - in_attr = &elf_known_obj_attributes (ibfd)[vendor][Tag_compatibility]; - out_attr = &elf_known_obj_attributes (obfd)[vendor][Tag_compatibility]; - - if (in_attr->i > 0 && strcmp (in_attr->s, "gnu") != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B: Object has vendor-specific contents that " - "must be processed by the '%s' toolchain"), - ibfd, in_attr->s); - return FALSE; - } - - if (in_attr->i != out_attr->i - || (in_attr->i != 0 && strcmp (in_attr->s, out_attr->s) != 0)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("error: %B: Object tag '%d, %s' is " - "incompatible with tag '%d, %s'"), - ibfd, - in_attr->i, in_attr->s ? in_attr->s : "", - out_attr->i, out_attr->s ? out_attr->s : ""); - return FALSE; - } - } - - return TRUE; -} - -/* Merge an unknown processor-specific attribute TAG, within the range - of known attributes, from IBFD into OBFD; return TRUE if the link - is OK, FALSE if it must fail. */ - -bfd_boolean -_bfd_elf_merge_unknown_attribute_low (bfd *ibfd, bfd *obfd, int tag) -{ - obj_attribute *in_attr; - obj_attribute *out_attr; - bfd *err_bfd = NULL; - bfd_boolean result = TRUE; - - in_attr = elf_known_obj_attributes_proc (ibfd); - out_attr = elf_known_obj_attributes_proc (obfd); - - if (out_attr[tag].i != 0 || out_attr[tag].s != NULL) - err_bfd = obfd; - else if (in_attr[tag].i != 0 || in_attr[tag].s != NULL) - err_bfd = ibfd; - - if (err_bfd != NULL) - result - = get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, tag); - - /* Only pass on attributes that match in both inputs. */ - if (in_attr[tag].i != out_attr[tag].i - || (in_attr[tag].s == NULL) != (out_attr[tag].s == NULL) - || (in_attr[tag].s != NULL && out_attr[tag].s != NULL - && strcmp (in_attr[tag].s, out_attr[tag].s) != 0)) - { - out_attr[tag].i = 0; - out_attr[tag].s = NULL; - } - - return result; -} - -/* Merge the lists of unknown processor-specific attributes, outside - the known range, from IBFD into OBFD; return TRUE if the link is - OK, FALSE if it must fail. */ - -bfd_boolean -_bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd) -{ - obj_attribute_list *in_list; - obj_attribute_list *out_list; - obj_attribute_list **out_listp; - bfd_boolean result = TRUE; - - in_list = elf_other_obj_attributes_proc (ibfd); - out_listp = &elf_other_obj_attributes_proc (obfd); - out_list = *out_listp; - - for (; in_list || out_list; ) - { - bfd *err_bfd = NULL; - unsigned int err_tag = 0; - - /* The tags for each list are in numerical order. */ - /* If the tags are equal, then merge. */ - if (out_list && (!in_list || in_list->tag > out_list->tag)) - { - /* This attribute only exists in obfd. We can't merge, and we don't - know what the tag means, so delete it. */ - err_bfd = obfd; - err_tag = out_list->tag; - *out_listp = out_list->next; - out_list = *out_listp; - } - else if (in_list && (!out_list || in_list->tag < out_list->tag)) - { - /* This attribute only exists in ibfd. We can't merge, and we don't - know what the tag means, so ignore it. */ - err_bfd = ibfd; - err_tag = in_list->tag; - in_list = in_list->next; - } - else /* The tags are equal. */ - { - /* As present, all attributes in the list are unknown, and - therefore can't be merged meaningfully. */ - err_bfd = obfd; - err_tag = out_list->tag; - - /* Only pass on attributes that match in both inputs. */ - if (in_list->attr.i != out_list->attr.i - || (in_list->attr.s == NULL) != (out_list->attr.s == NULL) - || (in_list->attr.s && out_list->attr.s - && strcmp (in_list->attr.s, out_list->attr.s) != 0)) - { - /* No match. Delete the attribute. */ - *out_listp = out_list->next; - out_list = *out_listp; - } - else - { - /* Matched. Keep the attribute and move to the next. */ - out_list = out_list->next; - in_list = in_list->next; - } - } - - if (err_bfd) - result = result - && get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, - err_tag); - } - - return result; -} diff --git a/sdcc/support/sdbinutils/bfd/elf-eh-frame.c b/sdcc/support/sdbinutils/bfd/elf-eh-frame.c deleted file mode 100644 index 95697c4c8..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-eh-frame.c +++ /dev/null @@ -1,2565 +0,0 @@ -/* .eh_frame section optimization. - Copyright (C) 2001-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "dwarf2.h" - -#define EH_FRAME_HDR_SIZE 8 - -struct cie -{ - unsigned int length; - unsigned int hash; - unsigned char version; - unsigned char local_personality; - char augmentation[20]; - bfd_vma code_align; - bfd_signed_vma data_align; - bfd_vma ra_column; - bfd_vma augmentation_size; - union { - struct elf_link_hash_entry *h; - struct { - unsigned int bfd_id; - unsigned int index; - } sym; - unsigned int reloc_index; - } personality; - struct eh_cie_fde *cie_inf; - unsigned char per_encoding; - unsigned char lsda_encoding; - unsigned char fde_encoding; - unsigned char initial_insn_length; - unsigned char can_make_lsda_relative; - unsigned char initial_instructions[50]; -}; - - - -/* 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 one if C1 and C2 CIEs can be merged. */ - -static int -cie_eq (const void *e1, const void *e2) -{ - const struct cie *c1 = (const struct cie *) e1; - const struct cie *c2 = (const struct cie *) e2; - - if (c1->hash == c2->hash - && c1->length == c2->length - && c1->version == c2->version - && c1->local_personality == c2->local_personality - && 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 - && memcmp (&c1->personality, &c2->personality, - sizeof (c1->personality)) == 0 - && (c1->cie_inf->u.cie.u.sec->output_section - == c2->cie_inf->u.cie.u.sec->output_section) - && c1->per_encoding == c2->per_encoding - && c1->lsda_encoding == c2->lsda_encoding - && c1->fde_encoding == c2->fde_encoding - && c1->initial_insn_length == c2->initial_insn_length - && c1->initial_insn_length <= sizeof (c1->initial_instructions) - && memcmp (c1->initial_instructions, - c2->initial_instructions, - c1->initial_insn_length) == 0) - return 1; - - return 0; -} - -static hashval_t -cie_hash (const void *e) -{ - const struct cie *c = (const struct cie *) e; - return c->hash; -} - -static hashval_t -cie_compute_hash (struct cie *c) -{ - hashval_t h = 0; - size_t len; - h = iterative_hash_object (c->length, h); - h = iterative_hash_object (c->version, h); - h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h); - h = iterative_hash_object (c->code_align, h); - h = iterative_hash_object (c->data_align, h); - h = iterative_hash_object (c->ra_column, h); - h = iterative_hash_object (c->augmentation_size, h); - h = iterative_hash_object (c->personality, h); - h = iterative_hash_object (c->cie_inf->u.cie.u.sec->output_section, h); - h = iterative_hash_object (c->per_encoding, h); - h = iterative_hash_object (c->lsda_encoding, h); - h = iterative_hash_object (c->fde_encoding, h); - h = iterative_hash_object (c->initial_insn_length, h); - len = c->initial_insn_length; - if (len > sizeof (c->initial_instructions)) - len = sizeof (c->initial_instructions); - h = iterative_hash (c->initial_instructions, len, h); - c->hash = h; - return h; -} - -/* 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->u.cie.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->add_augmentation_size) - size++; - if (entry->cie && entry->u.cie.add_fde_encoding) - size++; - return size; -} - -/* Return the size that ENTRY will have in the output. */ - -static unsigned int -size_of_output_cie_fde (struct eh_cie_fde *entry) -{ - if (entry->removed) - return 0; - if (entry->size == 4) - return 4; - return (entry->size - + extra_augmentation_string_bytes (entry) - + extra_augmentation_data_bytes (entry)); -} - -/* Return the offset of the FDE or CIE after ENT. */ - -static unsigned int -next_cie_fde_offset (const struct eh_cie_fde *ent, - const struct eh_cie_fde *last, - const asection *sec) -{ - while (++ent < last) - { - if (!ent->removed) - return ent->new_offset; - } - return sec->size; -} - -/* 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 & 0xc0 ? op & 0xc0 : op) - { - case DW_CFA_nop: - case DW_CFA_advance_loc: - case DW_CFA_restore: - case DW_CFA_remember_state: - case DW_CFA_restore_state: - case DW_CFA_GNU_window_save: - /* 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_val_offset: - case DW_CFA_val_offset_sf: - 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: - case DW_CFA_val_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, - unsigned int *set_loc_count) -{ - bfd_byte *last; - - last = buf; - while (buf < end) - if (*buf == DW_CFA_nop) - buf++; - else - { - if (*buf == DW_CFA_set_loc) - ++*set_loc_count; - if (!skip_cfa_op (&buf, end, encoded_ptr_width)) - return 0; - last = buf; - } - return last; -} - -/* Convert absolute encoding ENCODING into PC-relative form. - SIZE is the size of a pointer. */ - -static unsigned char -make_pc_relative (unsigned char encoding, unsigned int ptr_size) -{ - if ((encoding & 0x7f) == DW_EH_PE_absptr) - switch (ptr_size) - { - case 2: - encoding |= DW_EH_PE_sdata2; - break; - case 4: - encoding |= DW_EH_PE_sdata4; - break; - case 8: - encoding |= DW_EH_PE_sdata8; - break; - } - return encoding | DW_EH_PE_pcrel; -} - -/* Examine each .eh_frame_entry section and discard those - those that are marked SEC_EXCLUDE. */ - -static void -bfd_elf_discard_eh_frame_entry (struct eh_frame_hdr_info *hdr_info) -{ - unsigned int i; - for (i = 0; i < hdr_info->array_count; i++) - { - if (hdr_info->u.compact.entries[i]->flags & SEC_EXCLUDE) - { - unsigned int j; - for (j = i + 1; j < hdr_info->array_count; j++) - hdr_info->u.compact.entries[j-1] = hdr_info->u.compact.entries[j]; - - hdr_info->array_count--; - hdr_info->u.compact.entries[hdr_info->array_count] = NULL; - i--; - } - } -} - -/* Add a .eh_frame_entry section. */ - -static void -bfd_elf_record_eh_frame_entry (struct eh_frame_hdr_info *hdr_info, - asection *sec) -{ - if (hdr_info->array_count == hdr_info->u.compact.allocated_entries) - { - if (hdr_info->u.compact.allocated_entries == 0) - { - hdr_info->frame_hdr_is_compact = TRUE; - hdr_info->u.compact.allocated_entries = 2; - hdr_info->u.compact.entries = - bfd_malloc (hdr_info->u.compact.allocated_entries - * sizeof (hdr_info->u.compact.entries[0])); - } - else - { - hdr_info->u.compact.allocated_entries *= 2; - hdr_info->u.compact.entries = - bfd_realloc (hdr_info->u.compact.entries, - hdr_info->u.compact.allocated_entries - * sizeof (hdr_info->u.compact.entries[0])); - } - - BFD_ASSERT (hdr_info->u.compact.entries); - } - - hdr_info->u.compact.entries[hdr_info->array_count++] = sec; -} - -/* Parse a .eh_frame_entry section. Figure out which text section it - references. */ - -bfd_boolean -_bfd_elf_parse_eh_frame_entry (struct bfd_link_info *info, - asection *sec, struct elf_reloc_cookie *cookie) -{ - struct elf_link_hash_table *htab; - struct eh_frame_hdr_info *hdr_info; - unsigned long r_symndx; - asection *text_sec; - - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - - if (sec->size == 0 - || sec->sec_info_type != SEC_INFO_TYPE_NONE) - { - return TRUE; - } - - if (sec->output_section && bfd_is_abs_section (sec->output_section)) - { - /* At least one of the sections is being discarded from the - link, so we should just ignore them. */ - return TRUE; - } - - if (cookie->rel == cookie->relend) - return FALSE; - - /* The first relocation is the function start. */ - r_symndx = cookie->rel->r_info >> cookie->r_sym_shift; - if (r_symndx == STN_UNDEF) - return FALSE; - - text_sec = _bfd_elf_section_for_symbol (cookie, r_symndx, FALSE); - - if (text_sec == NULL) - return FALSE; - - elf_section_eh_frame_entry (text_sec) = sec; - if (text_sec->output_section - && bfd_is_abs_section (text_sec->output_section)) - sec->flags |= SEC_EXCLUDE; - - sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME_ENTRY; - elf_section_data (sec)->sec_info = text_sec; - bfd_elf_record_eh_frame_entry (hdr_info, sec); - return TRUE; -} - -/* Try to parse .eh_frame section SEC, which belongs to ABFD. Store the - information in the section's sec_info field on success. COOKIE - describes the relocations in SEC. */ - -void -_bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, - asection *sec, struct elf_reloc_cookie *cookie) -{ -#define REQUIRE(COND) \ - do \ - if (!(COND)) \ - goto free_no_table; \ - while (0) - - bfd_byte *ehbuf = NULL, *buf, *end; - bfd_byte *last_fde; - struct eh_cie_fde *this_inf; - unsigned int hdr_length, hdr_id; - unsigned int cie_count; - struct cie *cie, *local_cies = NULL; - struct elf_link_hash_table *htab; - struct eh_frame_hdr_info *hdr_info; - struct eh_frame_sec_info *sec_info = NULL; - unsigned int ptr_size; - unsigned int num_cies; - unsigned int num_entries; - elf_gc_mark_hook_fn gc_mark_hook; - - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - - if (sec->size == 0 - || sec->sec_info_type != SEC_INFO_TYPE_NONE) - { - /* This file does not contain .eh_frame information. */ - return; - } - - if (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; - } - - /* Read the frame unwind information from abfd. */ - - REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); - - /* 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); - - /* Go through the section contents and work out how many FDEs and - CIEs there are. */ - buf = ehbuf; - end = ehbuf + sec->size; - num_cies = 0; - num_entries = 0; - while (buf != end) - { - num_entries++; - - /* Read the length of the entry. */ - REQUIRE (skip_bytes (&buf, end, 4)); - hdr_length = bfd_get_32 (abfd, buf - 4); - - /* 64-bit .eh_frame is not supported. */ - REQUIRE (hdr_length != 0xffffffff); - if (hdr_length == 0) - break; - - REQUIRE (skip_bytes (&buf, end, 4)); - hdr_id = bfd_get_32 (abfd, buf - 4); - if (hdr_id == 0) - num_cies++; - - REQUIRE (skip_bytes (&buf, end, hdr_length - 4)); - } - - sec_info = (struct eh_frame_sec_info *) - bfd_zmalloc (sizeof (struct eh_frame_sec_info) - + (num_entries - 1) * sizeof (struct eh_cie_fde)); - REQUIRE (sec_info); - - /* We need to have a "struct cie" for each CIE in this section. */ - if (num_cies) - { - local_cies = (struct cie *) bfd_zmalloc (num_cies * sizeof (*local_cies)); - REQUIRE (local_cies); - } - - /* FIXME: octets_per_byte. */ -#define ENSURE_NO_RELOCS(buf) \ - while (cookie->rel < cookie->relend \ - && (cookie->rel->r_offset \ - < (bfd_size_type) ((buf) - ehbuf))) \ - { \ - REQUIRE (cookie->rel->r_info == 0); \ - cookie->rel++; \ - } - - /* FIXME: octets_per_byte. */ -#define SKIP_RELOCS(buf) \ - while (cookie->rel < cookie->relend \ - && (cookie->rel->r_offset \ - < (bfd_size_type) ((buf) - ehbuf))) \ - cookie->rel++ - - /* FIXME: octets_per_byte. */ -#define GET_RELOC(buf) \ - ((cookie->rel < cookie->relend \ - && (cookie->rel->r_offset \ - == (bfd_size_type) ((buf) - ehbuf))) \ - ? cookie->rel : NULL) - - buf = ehbuf; - cie_count = 0; - gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook; - while ((bfd_size_type) (buf - ehbuf) != sec->size) - { - char *aug; - bfd_byte *start, *insns, *insns_end; - bfd_size_type length; - unsigned int set_loc_count; - - this_inf = sec_info->entry + sec_info->count; - last_fde = buf; - - /* Read the length of the entry. */ - REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); - hdr_length = bfd_get_32 (abfd, buf - 4); - - /* 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; - this_inf->reloc_index = cookie->rel - cookie->rels; - - if (hdr_length == 0) - { - /* A zero-length CIE should only be found at the end of - the section, but allow multiple terminators. */ - while (skip_bytes (&buf, ehbuf + sec->size, 4)) - REQUIRE (bfd_get_32 (abfd, buf - 4) == 0); - REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); - ENSURE_NO_RELOCS (buf); - sec_info->count++; - break; - } - - REQUIRE (skip_bytes (&buf, end, 4)); - hdr_id = bfd_get_32 (abfd, buf - 4); - - if (hdr_id == 0) - { - unsigned int initial_insn_length; - - /* CIE */ - this_inf->cie = 1; - - /* Point CIE to one of the section-local cie structures. */ - cie = local_cies + cie_count++; - - cie->cie_inf = this_inf; - cie->length = hdr_length; - start = buf; - REQUIRE (read_byte (&buf, end, &cie->version)); - - /* Cannot handle unknown versions. */ - REQUIRE (cie->version == 1 - || cie->version == 3 - || cie->version == 4); - REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation)); - - strcpy (cie->augmentation, (char *) buf); - buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; - this_inf->u.cie.aug_str_len = buf - start - 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); - } - if (cie->version >= 4) - { - REQUIRE (buf + 1 < end); - REQUIRE (buf[0] == ptr_size); - REQUIRE (buf[1] == 0); - buf += 2; - } - 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 & 0x70) == DW_EH_PE_aligned) - { - length = -(buf - ehbuf) & (per_width - 1); - REQUIRE (skip_bytes (&buf, end, length)); - if (per_width == 8) - this_inf->u.cie.per_encoding_aligned8 = 1; - } - this_inf->u.cie.personality_offset = buf - start; - ENSURE_NO_RELOCS (buf); - /* Ensure we have a reloc here. */ - REQUIRE (GET_RELOC (buf)); - cie->personality.reloc_index - = cookie->rel - cookie->rels; - /* 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; - } - } - this_inf->u.cie.aug_data_len - = buf - start - 1 - this_inf->u.cie.aug_str_len; - - /* For shared libraries, try to get rid of as many RELATIVE relocs - as possible. */ - if (bfd_link_pic (info) - && (get_elf_backend_data (abfd) - ->elf_backend_can_make_relative_eh_frame - (abfd, info, sec))) - { - if ((cie->fde_encoding & 0x70) == DW_EH_PE_absptr) - this_inf->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 & 0x70) != DW_EH_PE_aligned) - { - if (*cie->augmentation == 0) - this_inf->add_augmentation_size = 1; - this_inf->u.cie.add_fde_encoding = 1; - this_inf->make_relative = 1; - } - - if ((cie->lsda_encoding & 0x70) == DW_EH_PE_absptr) - cie->can_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; - cie->initial_insn_length = initial_insn_length; - memcpy (cie->initial_instructions, buf, - initial_insn_length <= sizeof (cie->initial_instructions) - ? initial_insn_length : sizeof (cie->initial_instructions)); - insns = buf; - buf += initial_insn_length; - ENSURE_NO_RELOCS (buf); - - if (!bfd_link_relocatable (info)) - { - /* Keep info for merging cies. */ - this_inf->u.cie.u.full_cie = cie; - this_inf->u.cie.per_encoding_relative - = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; - } - } - else - { - /* Find the corresponding CIE. */ - unsigned int cie_offset = this_inf->offset + 4 - hdr_id; - for (cie = local_cies; cie < local_cies + cie_count; cie++) - if (cie_offset == cie->cie_inf->offset) - break; - - /* Ensure this FDE references one of the CIEs in this input - section. */ - REQUIRE (cie != local_cies + cie_count); - this_inf->u.fde.cie_inf = cie->cie_inf; - this_inf->make_relative = cie->cie_inf->make_relative; - this_inf->add_augmentation_size - = cie->cie_inf->add_augmentation_size; - - ENSURE_NO_RELOCS (buf); - if ((sec->flags & SEC_LINKER_CREATED) == 0 || cookie->rels != NULL) - { - asection *rsec; - - REQUIRE (GET_RELOC (buf)); - - /* Chain together the FDEs for each section. */ - rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, - cookie, NULL); - /* RSEC will be NULL if FDE was cleared out as it was belonging to - a discarded SHT_GROUP. */ - if (rsec) - { - REQUIRE (rsec->owner == abfd); - this_inf->u.fde.next_for_section = elf_fde_list (rsec); - elf_fde_list (rsec) = this_inf; - } - } - - /* 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_RELOCS (buf - length); - if (!GET_RELOC (buf - length) - && read_value (abfd, buf - length, length, FALSE) == 0) - { - (*info->callbacks->minfo) - /* xgettext:c-format */ - (_("discarding zero address range FDE in %B(%A).\n"), - abfd, sec); - this_inf->u.fde.cie_inf = NULL; - } - - /* Skip the augmentation size, if present. */ - if (cie->augmentation[0] == 'z') - REQUIRE (read_uleb128 (&buf, end, &length)); - 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) - { - SKIP_RELOCS (buf); - if (cie->can_make_lsda_relative && GET_RELOC (buf)) - cie->cie_inf->u.cie.make_lsda_relative = 1; - 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; - - /* For NULL RSEC (cleared FDE belonging to a discarded section) - the relocations are commonly cleared. We do not sanity check if - all these relocations are cleared as (1) relocations to - .gcc_except_table will remain uncleared (they will get dropped - with the drop of this unused FDE) and (2) BFD already safely drops - relocations of any type to .eh_frame by - elf_section_ignore_discarded_relocs. - TODO: The .gcc_except_table entries should be also filtered as - .eh_frame entries; or GCC could rather use COMDAT for them. */ - 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 - include the padding. */ - length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); - set_loc_count = 0; - insns_end = skip_non_nops (insns, end, length, &set_loc_count); - /* If we don't understand the CFA instructions, we can't know - what needs to be adjusted there. */ - if (insns_end == NULL - /* For the time being we don't support DW_CFA_set_loc in - CIE instructions. */ - || (set_loc_count && this_inf->cie)) - goto free_no_table; - this_inf->size -= end - insns_end; - if (insns_end != end && this_inf->cie) - { - cie->initial_insn_length -= end - insns_end; - cie->length -= end - insns_end; - } - if (set_loc_count - && ((cie->fde_encoding & 0x70) == DW_EH_PE_pcrel - || this_inf->make_relative)) - { - unsigned int cnt; - bfd_byte *p; - - this_inf->set_loc = (unsigned int *) - bfd_malloc ((set_loc_count + 1) * sizeof (unsigned int)); - REQUIRE (this_inf->set_loc); - this_inf->set_loc[0] = set_loc_count; - p = insns; - cnt = 0; - while (p < end) - { - if (*p == DW_CFA_set_loc) - this_inf->set_loc[++cnt] = p + 1 - start; - REQUIRE (skip_cfa_op (&p, end, length)); - } - } - - this_inf->removed = 1; - this_inf->fde_encoding = cie->fde_encoding; - this_inf->lsda_encoding = cie->lsda_encoding; - sec_info->count++; - } - BFD_ASSERT (sec_info->count == num_entries); - BFD_ASSERT (cie_count == num_cies); - - elf_section_data (sec)->sec_info = sec_info; - sec->sec_info_type = SEC_INFO_TYPE_EH_FRAME; - if (!bfd_link_relocatable (info)) - { - /* Keep info for merging cies. */ - sec_info->cies = local_cies; - local_cies = NULL; - } - goto success; - - free_no_table: - (*info->callbacks->einfo) - /* xgettext:c-format */ - (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), - abfd, sec); - hdr_info->u.dwarf.table = FALSE; - if (sec_info) - free (sec_info); - success: - if (ehbuf) - free (ehbuf); - if (local_cies) - free (local_cies); -#undef REQUIRE -} - -/* Order eh_frame_hdr entries by the VMA of their text section. */ - -static int -cmp_eh_frame_hdr (const void *a, const void *b) -{ - bfd_vma text_a; - bfd_vma text_b; - asection *sec; - - sec = *(asection *const *)a; - sec = (asection *) elf_section_data (sec)->sec_info; - text_a = sec->output_section->vma + sec->output_offset; - sec = *(asection *const *)b; - sec = (asection *) elf_section_data (sec)->sec_info; - text_b = sec->output_section->vma + sec->output_offset; - - if (text_a < text_b) - return -1; - return text_a > text_b; - -} - -/* Add space for a CANTUNWIND terminator to SEC if the text sections - referenced by it and NEXT are not contiguous, or NEXT is NULL. */ - -static void -add_eh_frame_hdr_terminator (asection *sec, - asection *next) -{ - bfd_vma end; - bfd_vma next_start; - asection *text_sec; - - if (next) - { - /* See if there is a gap (presumably a text section without unwind info) - between these two entries. */ - text_sec = (asection *) elf_section_data (sec)->sec_info; - end = text_sec->output_section->vma + text_sec->output_offset - + text_sec->size; - text_sec = (asection *) elf_section_data (next)->sec_info; - next_start = text_sec->output_section->vma + text_sec->output_offset; - if (end == next_start) - return; - } - - /* Add space for a CANTUNWIND terminator. */ - if (!sec->rawsize) - sec->rawsize = sec->size; - - bfd_set_section_size (sec->owner, sec, sec->size + 8); -} - -/* Finish a pass over all .eh_frame_entry sections. */ - -bfd_boolean -_bfd_elf_end_eh_frame_parsing (struct bfd_link_info *info) -{ - struct eh_frame_hdr_info *hdr_info; - unsigned int i; - - hdr_info = &elf_hash_table (info)->eh_info; - - if (info->eh_frame_hdr_type != COMPACT_EH_HDR - || hdr_info->array_count == 0) - return FALSE; - - bfd_elf_discard_eh_frame_entry (hdr_info); - - qsort (hdr_info->u.compact.entries, hdr_info->array_count, - sizeof (asection *), cmp_eh_frame_hdr); - - for (i = 0; i < hdr_info->array_count - 1; i++) - { - add_eh_frame_hdr_terminator (hdr_info->u.compact.entries[i], - hdr_info->u.compact.entries[i + 1]); - } - - /* Add a CANTUNWIND terminator after the last entry. */ - add_eh_frame_hdr_terminator (hdr_info->u.compact.entries[i], NULL); - return TRUE; -} - -/* Mark all relocations against CIE or FDE ENT, which occurs in - .eh_frame section SEC. COOKIE describes the relocations in SEC; - its "rel" field can be changed freely. */ - -static bfd_boolean -mark_entry (struct bfd_link_info *info, asection *sec, - struct eh_cie_fde *ent, elf_gc_mark_hook_fn gc_mark_hook, - struct elf_reloc_cookie *cookie) -{ - /* FIXME: octets_per_byte. */ - for (cookie->rel = cookie->rels + ent->reloc_index; - cookie->rel < cookie->relend - && cookie->rel->r_offset < ent->offset + ent->size; - cookie->rel++) - if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, cookie)) - return FALSE; - - return TRUE; -} - -/* Mark all the relocations against FDEs that relate to code in input - section SEC. The FDEs belong to .eh_frame section EH_FRAME, whose - relocations are described by COOKIE. */ - -bfd_boolean -_bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec, - asection *eh_frame, elf_gc_mark_hook_fn gc_mark_hook, - struct elf_reloc_cookie *cookie) -{ - struct eh_cie_fde *fde, *cie; - - for (fde = elf_fde_list (sec); fde; fde = fde->u.fde.next_for_section) - { - if (!mark_entry (info, eh_frame, fde, gc_mark_hook, cookie)) - return FALSE; - - /* At this stage, all cie_inf fields point to local CIEs, so we - can use the same cookie to refer to them. */ - cie = fde->u.fde.cie_inf; - if (cie != NULL && !cie->u.cie.gc_mark) - { - cie->u.cie.gc_mark = 1; - if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie)) - return FALSE; - } - } - return TRUE; -} - -/* Input section SEC of ABFD is an .eh_frame section that contains the - CIE described by CIE_INF. Return a version of CIE_INF that is going - to be kept in the output, adding CIE_INF to the output if necessary. - - HDR_INFO is the .eh_frame_hdr information and COOKIE describes the - relocations in REL. */ - -static struct eh_cie_fde * -find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec, - struct eh_frame_hdr_info *hdr_info, - struct elf_reloc_cookie *cookie, - struct eh_cie_fde *cie_inf) -{ - unsigned long r_symndx; - struct cie *cie, *new_cie; - Elf_Internal_Rela *rel; - void **loc; - - /* Use CIE_INF if we have already decided to keep it. */ - if (!cie_inf->removed) - return cie_inf; - - /* If we have merged CIE_INF with another CIE, use that CIE instead. */ - if (cie_inf->u.cie.merged) - return cie_inf->u.cie.u.merged_with; - - cie = cie_inf->u.cie.u.full_cie; - - /* Assume we will need to keep CIE_INF. */ - cie_inf->removed = 0; - cie_inf->u.cie.u.sec = sec; - - /* If we are not merging CIEs, use CIE_INF. */ - if (cie == NULL) - return cie_inf; - - if (cie->per_encoding != DW_EH_PE_omit) - { - bfd_boolean per_binds_local; - - /* Work out the address of personality routine, or at least - enough info that we could calculate the address had we made a - final section layout. The symbol on the reloc is enough, - either the hash for a global, or (bfd id, index) pair for a - local. The assumption here is that no one uses addends on - the reloc. */ - rel = cookie->rels + cie->personality.reloc_index; - memset (&cie->personality, 0, sizeof (cie->personality)); -#ifdef BFD64 - if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) - r_symndx = ELF64_R_SYM (rel->r_info); - else -#endif - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx >= cookie->locsymcount - || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) - { - 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 = h; - per_binds_local = SYMBOL_REFERENCES_LOCAL (info, h); - } - else - { - Elf_Internal_Sym *sym; - asection *sym_sec; - - sym = &cookie->locsyms[r_symndx]; - sym_sec = bfd_section_from_elf_index (abfd, sym->st_shndx); - if (sym_sec == NULL) - return cie_inf; - - if (sym_sec->kept_section != NULL) - sym_sec = sym_sec->kept_section; - if (sym_sec->output_section == NULL) - return cie_inf; - - cie->local_personality = 1; - cie->personality.sym.bfd_id = abfd->id; - cie->personality.sym.index = r_symndx; - per_binds_local = TRUE; - } - - if (per_binds_local - && bfd_link_pic (info) - && (cie->per_encoding & 0x70) == DW_EH_PE_absptr - && (get_elf_backend_data (abfd) - ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) - { - cie_inf->u.cie.make_per_encoding_relative = 1; - cie_inf->u.cie.per_encoding_relative = 1; - } - } - - /* See if we can merge this CIE with an earlier one. */ - cie_compute_hash (cie); - if (hdr_info->u.dwarf.cies == NULL) - { - hdr_info->u.dwarf.cies = htab_try_create (1, cie_hash, cie_eq, free); - if (hdr_info->u.dwarf.cies == NULL) - return cie_inf; - } - loc = htab_find_slot_with_hash (hdr_info->u.dwarf.cies, cie, - cie->hash, INSERT); - if (loc == NULL) - return cie_inf; - - new_cie = (struct cie *) *loc; - if (new_cie == NULL) - { - /* Keep CIE_INF and record it in the hash table. */ - new_cie = (struct cie *) malloc (sizeof (struct cie)); - if (new_cie == NULL) - return cie_inf; - - memcpy (new_cie, cie, sizeof (struct cie)); - *loc = new_cie; - } - else - { - /* Merge CIE_INF with NEW_CIE->CIE_INF. */ - cie_inf->removed = 1; - cie_inf->u.cie.merged = 1; - cie_inf->u.cie.u.merged_with = new_cie->cie_inf; - if (cie_inf->u.cie.make_lsda_relative) - new_cie->cie_inf->u.cie.make_lsda_relative = 1; - } - return new_cie->cie_inf; -} - -/* For a given OFFSET in SEC, return the delta to the new location - after .eh_frame editing. */ - -static bfd_signed_vma -offset_adjust (bfd_vma offset, const asection *sec) -{ - struct eh_frame_sec_info *sec_info - = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; - unsigned int lo, hi, mid; - struct eh_cie_fde *ent = NULL; - bfd_signed_vma delta; - - lo = 0; - hi = sec_info->count; - if (hi == 0) - return 0; - - while (lo < hi) - { - mid = (lo + hi) / 2; - ent = &sec_info->entry[mid]; - if (offset < ent->offset) - hi = mid; - else if (mid + 1 >= hi) - break; - else if (offset >= ent[1].offset) - lo = mid + 1; - else - break; - } - - if (!ent->removed) - delta = (bfd_vma) ent->new_offset - (bfd_vma) ent->offset; - else if (ent->cie && ent->u.cie.merged) - { - struct eh_cie_fde *cie = ent->u.cie.u.merged_with; - delta = ((bfd_vma) cie->new_offset + cie->u.cie.u.sec->output_offset - - (bfd_vma) ent->offset - sec->output_offset); - } - else - { - /* Is putting the symbol on the next entry best for a deleted - CIE/FDE? */ - struct eh_cie_fde *last = sec_info->entry + sec_info->count; - delta = ((bfd_vma) next_cie_fde_offset (ent, last, sec) - - (bfd_vma) ent->offset); - return delta; - } - - /* Account for editing within this CIE/FDE. */ - offset -= ent->offset; - if (ent->cie) - { - unsigned int extra - = ent->add_augmentation_size + ent->u.cie.add_fde_encoding; - if (extra == 0 - || offset <= 9u + ent->u.cie.aug_str_len) - return delta; - delta += extra; - if (offset <= 9u + ent->u.cie.aug_str_len + ent->u.cie.aug_data_len) - return delta; - delta += extra; - } - else - { - unsigned int ptr_size, width, extra = ent->add_augmentation_size; - if (offset <= 12 || extra == 0) - return delta; - ptr_size = (get_elf_backend_data (sec->owner) - ->elf_backend_eh_frame_address_size (sec->owner, sec)); - width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); - if (offset <= 8 + 2 * width) - return delta; - delta += extra; - } - - return delta; -} - -/* Adjust a global symbol defined in .eh_frame, so that it stays - relative to its original CIE/FDE. It is assumed that a symbol - defined at the beginning of a CIE/FDE belongs to that CIE/FDE - rather than marking the end of the previous CIE/FDE. This matters - when a CIE is merged with a previous CIE, since the symbol is - moved to the merged CIE. */ - -bfd_boolean -_bfd_elf_adjust_eh_frame_global_symbol (struct elf_link_hash_entry *h, - void *arg ATTRIBUTE_UNUSED) -{ - asection *sym_sec; - bfd_signed_vma delta; - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - return TRUE; - - sym_sec = h->root.u.def.section; - if (sym_sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME - || elf_section_data (sym_sec)->sec_info == NULL) - return TRUE; - - delta = offset_adjust (h->root.u.def.value, sym_sec); - h->root.u.def.value += delta; - - return TRUE; -} - -/* The same for all local symbols defined in .eh_frame. Returns true - if any symbol was changed. */ - -static int -adjust_eh_frame_local_symbols (const asection *sec, - struct elf_reloc_cookie *cookie) -{ - unsigned int shndx; - Elf_Internal_Sym *sym; - Elf_Internal_Sym *end_sym; - int adjusted = 0; - - shndx = elf_section_data (sec)->this_idx; - end_sym = cookie->locsyms + cookie->locsymcount; - for (sym = cookie->locsyms + 1; sym < end_sym; ++sym) - if (sym->st_info <= ELF_ST_INFO (STB_LOCAL, STT_OBJECT) - && sym->st_shndx == shndx) - { - bfd_signed_vma delta = offset_adjust (sym->st_value, sec); - - if (delta != 0) - { - adjusted = 1; - sym->st_value += delta; - } - } - return adjusted; -} - -/* 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) -{ - struct eh_cie_fde *ent; - struct eh_frame_sec_info *sec_info; - struct eh_frame_hdr_info *hdr_info; - unsigned int ptr_size, offset, eh_alignment; - int changed; - - if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) - return FALSE; - - sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; - if (sec_info == NULL) - return FALSE; - - ptr_size = (get_elf_backend_data (sec->owner) - ->elf_backend_eh_frame_address_size (sec->owner, sec)); - - hdr_info = &elf_hash_table (info)->eh_info; - for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) - if (ent->size == 4) - /* There should only be one zero terminator, on the last input - file supplying .eh_frame (crtend.o). Remove any others. */ - ent->removed = sec->map_head.s != NULL; - else if (!ent->cie && ent->u.fde.cie_inf != NULL) - { - bfd_boolean keep; - if ((sec->flags & SEC_LINKER_CREATED) != 0 && cookie->rels == NULL) - { - unsigned int width - = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); - bfd_vma value - = read_value (abfd, sec->contents + ent->offset + 8 + width, - width, get_DW_EH_PE_signed (ent->fde_encoding)); - keep = value != 0; - } - else - { - cookie->rel = cookie->rels + ent->reloc_index; - /* FIXME: octets_per_byte. */ - BFD_ASSERT (cookie->rel < cookie->relend - && cookie->rel->r_offset == ent->offset + 8); - keep = !(*reloc_symbol_deleted_p) (ent->offset + 8, cookie); - } - if (keep) - { - if (bfd_link_pic (info) - && (((ent->fde_encoding & 0x70) == DW_EH_PE_absptr - && ent->make_relative == 0) - || (ent->fde_encoding & 0x70) == DW_EH_PE_aligned)) - { - static int num_warnings_issued = 0; - - /* 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->u.dwarf.table = FALSE; - if (num_warnings_issued < 10) - { - (*info->callbacks->einfo) - /* xgettext:c-format */ - (_("%P: FDE encoding in %B(%A) prevents .eh_frame_hdr" - " table being created.\n"), abfd, sec); - num_warnings_issued ++; - } - else if (num_warnings_issued == 10) - { - (*info->callbacks->einfo) - (_("%P: Further warnings about FDE encoding preventing .eh_frame_hdr generation dropped.\n")); - num_warnings_issued ++; - } - } - ent->removed = 0; - hdr_info->u.dwarf.fde_count++; - ent->u.fde.cie_inf = find_merged_cie (abfd, info, sec, hdr_info, - cookie, ent->u.fde.cie_inf); - } - } - - if (sec_info->cies) - { - free (sec_info->cies); - sec_info->cies = NULL; - } - - /* It may be that some .eh_frame input section has greater alignment - than other .eh_frame sections. In that case we run the risk of - padding with zeros before that section, which would be seen as a - zero terminator. Alignment padding must be added *inside* the - last FDE instead. For other FDEs we align according to their - encoding, in order to align FDE address range entries naturally. */ - offset = 0; - changed = 0; - for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) - if (!ent->removed) - { - eh_alignment = 4; - if (ent->size == 4) - ; - else if (ent->cie) - { - if (ent->u.cie.per_encoding_aligned8) - eh_alignment = 8; - } - else - { - eh_alignment = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); - if (eh_alignment < 4) - eh_alignment = 4; - } - offset = (offset + eh_alignment - 1) & -eh_alignment; - ent->new_offset = offset; - if (ent->new_offset != ent->offset) - changed = 1; - offset += size_of_output_cie_fde (ent); - } - - eh_alignment = 4; - offset = (offset + eh_alignment - 1) & -eh_alignment; - sec->rawsize = sec->size; - sec->size = offset; - if (sec->size != sec->rawsize) - changed = 1; - - if (changed && adjust_eh_frame_local_symbols (sec, cookie)) - { - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - symtab_hdr->contents = (unsigned char *) cookie->locsyms; - } - return changed; -} - -/* 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; - - if (!hdr_info->frame_hdr_is_compact && hdr_info->u.dwarf.cies != NULL) - { - htab_delete (hdr_info->u.dwarf.cies); - hdr_info->u.dwarf.cies = NULL; - } - - sec = hdr_info->hdr_sec; - if (sec == NULL) - return FALSE; - - if (info->eh_frame_hdr_type == COMPACT_EH_HDR) - { - /* For compact frames we only add the header. The actual table comes - from the .eh_frame_entry sections. */ - sec->size = 8; - } - else - { - sec->size = EH_FRAME_HDR_SIZE; - if (hdr_info->u.dwarf.table) - sec->size += 4 + hdr_info->u.dwarf.fde_count * 8; - } - - elf_eh_frame_hdr (abfd) = sec; - return TRUE; -} - -/* Return true if there is at least one non-empty .eh_frame section in - input files. Can only be called after ld has mapped input to - output sections, and before sections are stripped. */ - -bfd_boolean -_bfd_elf_eh_frame_present (struct bfd_link_info *info) -{ - asection *eh = bfd_get_section_by_name (info->output_bfd, ".eh_frame"); - - if (eh == NULL) - return FALSE; - - /* Count only sections which have at least a single CIE or FDE. - There cannot be any CIE or FDE <= 8 bytes. */ - for (eh = eh->map_head.s; eh != NULL; eh = eh->map_head.s) - if (eh->size > 8) - return TRUE; - - return FALSE; -} - -/* Return true if there is at least one .eh_frame_entry section in - input files. */ - -bfd_boolean -_bfd_elf_eh_frame_entry_present (struct bfd_link_info *info) -{ - asection *o; - bfd *abfd; - - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) - { - for (o = abfd->sections; o; o = o->next) - { - const char *name = bfd_get_section_name (abfd, o); - - if (strcmp (name, ".eh_frame_entry") - && !bfd_is_abs_section (o->output_section)) - return TRUE; - } - } - return FALSE; -} - -/* This function is called from size_dynamic_sections. - It needs to decide whether .eh_frame_hdr should be output or not, - because when the dynamic symbol table has been sized it is too late - to strip sections. */ - -bfd_boolean -_bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab; - struct eh_frame_hdr_info *hdr_info; - struct bfd_link_hash_entry *bh = NULL; - struct elf_link_hash_entry *h; - - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - if (hdr_info->hdr_sec == NULL) - return TRUE; - - if (bfd_is_abs_section (hdr_info->hdr_sec->output_section) - || info->eh_frame_hdr_type == 0 - || (info->eh_frame_hdr_type == DWARF2_EH_HDR - && !_bfd_elf_eh_frame_present (info)) - || (info->eh_frame_hdr_type == COMPACT_EH_HDR - && !_bfd_elf_eh_frame_entry_present (info))) - { - hdr_info->hdr_sec->flags |= SEC_EXCLUDE; - hdr_info->hdr_sec = NULL; - return TRUE; - } - - /* Add a hidden symbol so that systems without access to PHDRs can - find the table. */ - if (! (_bfd_generic_link_add_one_symbol - (info, info->output_bfd, "__GNU_EH_FRAME_HDR", BSF_LOCAL, - hdr_info->hdr_sec, 0, NULL, FALSE, FALSE, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->other = STV_HIDDEN; - get_elf_backend_data - (info->output_bfd)->elf_backend_hide_symbol (info, h, TRUE); - - if (!hdr_info->frame_hdr_is_compact) - hdr_info->u.dwarf.table = TRUE; - return TRUE; -} - -/* 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 ATTRIBUTE_UNUSED, - asection *sec, - bfd_vma offset) -{ - struct eh_frame_sec_info *sec_info; - unsigned int lo, hi, mid; - - if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) - return offset; - sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; - - if (offset >= sec->rawsize) - return offset - sec->rawsize + sec->size; - - lo = 0; - hi = sec_info->count; - mid = 0; - while (lo < hi) - { - mid = (lo + hi) / 2; - if (offset < sec_info->entry[mid].offset) - hi = mid; - else if (offset - >= sec_info->entry[mid].offset + sec_info->entry[mid].size) - lo = mid + 1; - else - break; - } - - BFD_ASSERT (lo < hi); - - /* FDE or CIE was removed. */ - if (sec_info->entry[mid].removed) - return (bfd_vma) -1; - - /* If converting personality pointers to DW_EH_PE_pcrel, there will be - no need for run-time relocation against the personality field. */ - if (sec_info->entry[mid].cie - && sec_info->entry[mid].u.cie.make_per_encoding_relative - && offset == (sec_info->entry[mid].offset + 8 - + sec_info->entry[mid].u.cie.personality_offset)) - return (bfd_vma) -2; - - /* 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].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].u.fde.cie_inf->u.cie.make_lsda_relative - && offset == (sec_info->entry[mid].offset + 8 - + sec_info->entry[mid].lsda_offset)) - return (bfd_vma) -2; - - /* If converting to DW_EH_PE_pcrel, there will be no need for run-time - relocation against DW_CFA_set_loc's arguments. */ - if (sec_info->entry[mid].set_loc - && sec_info->entry[mid].make_relative - && (offset >= sec_info->entry[mid].offset + 8 - + sec_info->entry[mid].set_loc[1])) - { - unsigned int cnt; - - for (cnt = 1; cnt <= sec_info->entry[mid].set_loc[0]; cnt++) - if (offset == sec_info->entry[mid].offset + 8 - + sec_info->entry[mid].set_loc[cnt]) - return (bfd_vma) -2; - } - - /* 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_entry section. Add CANTUNWIND terminator if needed. - Also check that the contents look sane. */ - -bfd_boolean -_bfd_elf_write_section_eh_frame_entry (bfd *abfd, struct bfd_link_info *info, - asection *sec, bfd_byte *contents) -{ - const struct elf_backend_data *bed; - bfd_byte cantunwind[8]; - bfd_vma addr; - bfd_vma last_addr; - bfd_vma offset; - asection *text_sec = (asection *) elf_section_data (sec)->sec_info; - - if (!sec->rawsize) - sec->rawsize = sec->size; - - BFD_ASSERT (sec->sec_info_type == SEC_INFO_TYPE_EH_FRAME_ENTRY); - - /* Check to make sure that the text section corresponding to this eh_frame_entry - section has not been excluded. In particular, mips16 stub entries will be - excluded outside of the normal process. */ - if (sec->flags & SEC_EXCLUDE - || text_sec->flags & SEC_EXCLUDE) - return TRUE; - - if (!bfd_set_section_contents (abfd, sec->output_section, contents, - sec->output_offset, sec->rawsize)) - return FALSE; - - last_addr = bfd_get_signed_32 (abfd, contents); - /* Check that all the entries are in order. */ - for (offset = 8; offset < sec->rawsize; offset += 8) - { - addr = bfd_get_signed_32 (abfd, contents + offset) + offset; - if (addr <= last_addr) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %A not in order"), sec->owner, sec); - return FALSE; - } - - last_addr = addr; - } - - addr = text_sec->output_section->vma + text_sec->output_offset - + text_sec->size; - addr &= ~1; - addr -= (sec->output_section->vma + sec->output_offset + sec->rawsize); - if (addr & 1) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %A invalid input section size"), - sec->owner, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - if (last_addr >= addr + sec->rawsize) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %A points past end of text section"), - sec->owner, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (sec->size == sec->rawsize) - return TRUE; - - bed = get_elf_backend_data (abfd); - BFD_ASSERT (sec->size == sec->rawsize + 8); - BFD_ASSERT ((addr & 1) == 0); - BFD_ASSERT (bed->cant_unwind_opcode); - - bfd_put_32 (abfd, addr, cantunwind); - bfd_put_32 (abfd, (*bed->cant_unwind_opcode) (info), cantunwind + 4); - return bfd_set_section_contents (abfd, sec->output_section, cantunwind, - sec->output_offset + sec->rawsize, 8); -} - -/* Write out .eh_frame section. This is called with the relocated - contents. */ - -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, *last_ent; - - if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) - /* FIXME: octets_per_byte. */ - 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 = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - - if (hdr_info->u.dwarf.table && hdr_info->u.dwarf.array == NULL) - { - hdr_info->frame_hdr_is_compact = FALSE; - hdr_info->u.dwarf.array = (struct eh_frame_array_ent *) - bfd_malloc (hdr_info->u.dwarf.fde_count - * sizeof (*hdr_info->u.dwarf.array)); - } - if (hdr_info->u.dwarf.array == NULL) - hdr_info = NULL; - - /* The new offsets can be bigger or smaller than the original offsets. - 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, contents + ent->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, contents + ent->offset, ent->size); - - last_ent = sec_info->entry + sec_info->count; - for (ent = sec_info->entry; ent < last_ent; ++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 == last_ent - 1); - continue; - } - - buf = contents + ent->new_offset; - end = buf + ent->size; - new_size = next_cie_fde_offset (ent, last_ent, sec) - ent->new_offset; - - /* 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->u.cie.make_lsda_relative - || ent->u.cie.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->u.cie.make_lsda_relative ? 2 : 0) - | (ent->u.cie.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->u.cie.add_fde_encoding) - { - BFD_ASSERT (action & 1); - *aug++ = 'R'; - *buf++ = make_pc_relative (DW_EH_PE_absptr, ptr_size); - action &= ~1; - } - - while (action) - switch (*aug++) - { - case 'L': - if (action & 2) - { - BFD_ASSERT (*buf == ent->lsda_encoding); - *buf = make_pc_relative (*buf, ptr_size); - action &= ~2; - } - buf++; - break; - case 'P': - if (ent->u.cie.make_per_encoding_relative) - *buf = make_pc_relative (*buf, ptr_size); - 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->u.cie.per_encoding_relative); - if ((per_encoding & 0x70) == 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)); - if (ent->u.cie.make_per_encoding_relative) - val -= (sec->output_section->vma - + sec->output_offset - + (buf - contents)); - else - { - val += (bfd_vma) 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 = make_pc_relative (*buf, ptr_size); - action &= ~1; - } - buf++; - break; - case 'S': - break; - default: - BFD_FAIL (); - } - } - } - else - { - /* FDE */ - bfd_vma value, address; - unsigned int width; - bfd_byte *start; - struct eh_cie_fde *cie; - - /* Skip length. */ - cie = ent->u.fde.cie_inf; - buf += 4; - value = ((ent->new_offset + sec->output_offset + 4) - - (cie->new_offset + cie->u.cie.u.sec->output_offset)); - bfd_put_32 (abfd, value, buf); - if (bfd_link_relocatable (info)) - continue; - 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 & 0x70) - { - case DW_EH_PE_textrel: - BFD_ASSERT (hdr_info == NULL); - break; - case DW_EH_PE_datarel: - { - switch (abfd->arch_info->arch) - { - case bfd_arch_ia64: - BFD_ASSERT (elf_gp (abfd) != 0); - address += elf_gp (abfd); - break; - default: - (*info->callbacks->einfo) - (_("%P: DW_EH_PE_datarel unspecified" - " for this architecture.\n")); - /* Fall thru */ - case bfd_arch_frv: - case bfd_arch_i386: - BFD_ASSERT (htab->hgot != NULL - && ((htab->hgot->root.type - == bfd_link_hash_defined) - || (htab->hgot->root.type - == bfd_link_hash_defweak))); - address - += (htab->hgot->root.u.def.value - + htab->hgot->root.u.def.section->output_offset - + (htab->hgot->root.u.def.section->output_section - ->vma)); - break; - } - } - break; - case DW_EH_PE_pcrel: - value += (bfd_vma) ent->offset - ent->new_offset; - address += (sec->output_section->vma - + sec->output_offset - + ent->offset + 8); - break; - } - if (ent->make_relative) - value -= (sec->output_section->vma - + sec->output_offset - + ent->new_offset + 8); - write_value (abfd, buf, value, width); - } - - start = buf; - - if (hdr_info) - { - /* The address calculation may overflow, giving us a - value greater than 4G on a 32-bit target when - dwarf_vma is 64-bit. */ - if (sizeof (address) > 4 && ptr_size == 4) - address &= 0xffffffff; - hdr_info->u.dwarf.array[hdr_info->array_count].initial_loc - = address; - hdr_info->u.dwarf.array[hdr_info->array_count].range - = read_value (abfd, buf + width, width, FALSE); - hdr_info->u.dwarf.array[hdr_info->array_count++].fde - = (sec->output_section->vma - + sec->output_offset - + ent->new_offset); - } - - if ((ent->lsda_encoding & 0x70) == DW_EH_PE_pcrel - || cie->u.cie.make_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 & 0x70) == DW_EH_PE_pcrel) - value += (bfd_vma) ent->offset - ent->new_offset; - else if (cie->u.cie.make_lsda_relative) - value -= (sec->output_section->vma - + sec->output_offset - + ent->new_offset + 8 + ent->lsda_offset); - write_value (abfd, buf, value, width); - } - } - else if (ent->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; - } - - if (ent->set_loc) - { - /* Adjust DW_CFA_set_loc. */ - unsigned int cnt; - bfd_vma new_offset; - - width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); - new_offset = ent->new_offset + 8 - + extra_augmentation_string_bytes (ent) - + extra_augmentation_data_bytes (ent); - - for (cnt = 1; cnt <= ent->set_loc[0]; cnt++) - { - buf = start + ent->set_loc[cnt]; - - value = read_value (abfd, buf, width, - get_DW_EH_PE_signed (ent->fde_encoding)); - if (!value) - continue; - - if ((ent->fde_encoding & 0x70) == DW_EH_PE_pcrel) - value += (bfd_vma) ent->offset + 8 - new_offset; - if (ent->make_relative) - value -= (sec->output_section->vma - + sec->output_offset - + new_offset + ent->set_loc[cnt]); - write_value (abfd, buf, value, width); - } - } - } - } - - /* FIXME: octets_per_byte. */ - 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 = (const struct eh_frame_array_ent *) a; - const struct eh_frame_array_ent *q = (const struct eh_frame_array_ent *) b; - if (p->initial_loc > q->initial_loc) - return 1; - if (p->initial_loc < q->initial_loc) - return -1; - if (p->range > q->range) - return 1; - if (p->range < q->range) - return -1; - return 0; -} - -/* Reorder .eh_frame_entry sections to match the associated text sections. - This routine is called during the final linking step, just before writing - the contents. At this stage, sections in the eh_frame_hdr_info are already - sorted in order of increasing text section address and so we simply need - to make the .eh_frame_entrys follow that same order. Note that it is - invalid for a linker script to try to force a particular order of - .eh_frame_entry sections. */ - -bfd_boolean -_bfd_elf_fixup_eh_frame_hdr (struct bfd_link_info *info) -{ - asection *sec = NULL; - asection *osec; - struct eh_frame_hdr_info *hdr_info; - unsigned int i; - bfd_vma offset; - struct bfd_link_order *p; - - hdr_info = &elf_hash_table (info)->eh_info; - - if (hdr_info->hdr_sec == NULL - || info->eh_frame_hdr_type != COMPACT_EH_HDR - || hdr_info->array_count == 0) - return TRUE; - - /* Change section output offsets to be in text section order. */ - offset = 8; - osec = hdr_info->u.compact.entries[0]->output_section; - for (i = 0; i < hdr_info->array_count; i++) - { - sec = hdr_info->u.compact.entries[i]; - if (sec->output_section != osec) - { - _bfd_error_handler - (_("Invalid output section for .eh_frame_entry: %A"), - sec->output_section); - return FALSE; - } - sec->output_offset = offset; - offset += sec->size; - } - - - /* Fix the link_order to match. */ - for (p = sec->output_section->map_head.link_order; p != NULL; p = p->next) - { - if (p->type != bfd_indirect_link_order) - abort(); - - p->offset = p->u.indirect.section->output_offset; - if (p->next != NULL) - i--; - } - - if (i != 0) - { - _bfd_error_handler - (_("Invalid contents in %A section"), osec); - return FALSE; - } - - return TRUE; -} - -/* The .eh_frame_hdr format for Compact EH frames: - ubyte version (2) - ubyte eh_ref_enc (DW_EH_PE_* encoding of typinfo references) - uint32_t count (Number of entries in table) - [array from .eh_frame_entry sections] */ - -static bfd_boolean -write_compact_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab; - struct eh_frame_hdr_info *hdr_info; - asection *sec; - const struct elf_backend_data *bed; - bfd_vma count; - bfd_byte contents[8]; - unsigned int i; - - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - sec = hdr_info->hdr_sec; - - if (sec->size != 8) - abort(); - - for (i = 0; i < sizeof (contents); i++) - contents[i] = 0; - - contents[0] = COMPACT_EH_HDR; - bed = get_elf_backend_data (abfd); - - BFD_ASSERT (bed->compact_eh_encoding); - contents[1] = (*bed->compact_eh_encoding) (info); - - count = (sec->output_section->size - 8) / 8; - bfd_put_32 (abfd, count, contents + 4); - return bfd_set_section_contents (abfd, sec->output_section, contents, - (file_ptr) sec->output_offset, sec->size); -} - -/* The .eh_frame_hdr format for DWARF frames: - - ubyte version (currently 1) - ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of - .eh_frame section) - 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). */ - -static bfd_boolean -write_dwarf_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab; - struct eh_frame_hdr_info *hdr_info; - asection *sec; - bfd_boolean retval = TRUE; - - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - sec = hdr_info->hdr_sec; - bfd_byte *contents; - asection *eh_frame_sec; - bfd_size_type size; - bfd_vma encoded_eh_frame; - - size = EH_FRAME_HDR_SIZE; - if (hdr_info->u.dwarf.array - && hdr_info->array_count == hdr_info->u.dwarf.fde_count) - size += 4 + hdr_info->u.dwarf.fde_count * 8; - contents = (bfd_byte *) bfd_malloc (size); - if (contents == NULL) - return FALSE; - - eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); - if (eh_frame_sec == NULL) - { - free (contents); - return FALSE; - } - - memset (contents, 0, EH_FRAME_HDR_SIZE); - /* Version. */ - contents[0] = 1; - /* .eh_frame offset. */ - contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address - (abfd, info, eh_frame_sec, 0, sec, 4, &encoded_eh_frame); - - if (hdr_info->u.dwarf.array - && hdr_info->array_count == hdr_info->u.dwarf.fde_count) - { - /* FDE count encoding. */ - contents[2] = DW_EH_PE_udata4; - /* Search table encoding. */ - contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; - } - else - { - contents[2] = DW_EH_PE_omit; - contents[3] = DW_EH_PE_omit; - } - bfd_put_32 (abfd, encoded_eh_frame, contents + 4); - - if (contents[2] != DW_EH_PE_omit) - { - unsigned int i; - bfd_boolean overlap, overflow; - - bfd_put_32 (abfd, hdr_info->u.dwarf.fde_count, - contents + EH_FRAME_HDR_SIZE); - qsort (hdr_info->u.dwarf.array, hdr_info->u.dwarf.fde_count, - sizeof (*hdr_info->u.dwarf.array), vma_compare); - overlap = FALSE; - overflow = FALSE; - for (i = 0; i < hdr_info->u.dwarf.fde_count; i++) - { - bfd_vma val; - - val = hdr_info->u.dwarf.array[i].initial_loc - - sec->output_section->vma; - val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; - if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 - && (hdr_info->u.dwarf.array[i].initial_loc - != sec->output_section->vma + val)) - overflow = TRUE; - bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 4); - val = hdr_info->u.dwarf.array[i].fde - sec->output_section->vma; - val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; - if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 - && (hdr_info->u.dwarf.array[i].fde - != sec->output_section->vma + val)) - overflow = TRUE; - bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 8); - if (i != 0 - && (hdr_info->u.dwarf.array[i].initial_loc - < (hdr_info->u.dwarf.array[i - 1].initial_loc - + hdr_info->u.dwarf.array[i - 1].range))) - overlap = TRUE; - } - if (overflow) - (*info->callbacks->einfo) (_("%P: .eh_frame_hdr entry overflow.\n")); - if (overlap) - (*info->callbacks->einfo) - (_("%P: .eh_frame_hdr refers to overlapping FDEs.\n")); - if (overflow || overlap) - { - bfd_set_error (bfd_error_bad_value); - retval = FALSE; - } - } - - /* FIXME: octets_per_byte. */ - if (!bfd_set_section_contents (abfd, sec->output_section, contents, - (file_ptr) sec->output_offset, - sec->size)) - retval = FALSE; - free (contents); - - if (hdr_info->u.dwarf.array != NULL) - free (hdr_info->u.dwarf.array); - return retval; -} - -/* 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. */ - -bfd_boolean -_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab; - struct eh_frame_hdr_info *hdr_info; - asection *sec; - - htab = elf_hash_table (info); - hdr_info = &htab->eh_info; - sec = hdr_info->hdr_sec; - - if (info->eh_frame_hdr_type == 0 || sec == NULL) - return TRUE; - - if (info->eh_frame_hdr_type == COMPACT_EH_HDR) - return write_compact_eh_frame_hdr (abfd, info); - else - return write_dwarf_eh_frame_hdr (abfd, info); -} - -/* Return the width of FDE addresses. This is the default implementation. */ - -unsigned int -_bfd_elf_eh_frame_address_size (bfd *abfd, const 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/sdcc/support/sdbinutils/bfd/elf-hppa.h b/sdcc/support/sdbinutils/bfd/elf-hppa.h deleted file mode 100644 index b87ee836e..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-hppa.h +++ /dev/null @@ -1,1225 +0,0 @@ -/* Common code for PA ELF implementations. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define ELF_HOWTO_TABLE_SIZE R_PARISC_UNIMPLEMENTED + 1 - -/* This file is included by multiple PA ELF BFD backends with different - sizes. - - Most of the routines are written to be size independent, but sometimes - external constraints require 32 or 64 bit specific code. We remap - the definitions/functions as necessary here. */ -#if ARCH_SIZE == 64 -#define ELF_R_TYPE(X) ELF64_R_TYPE(X) -#define ELF_R_SYM(X) ELF64_R_SYM(X) -#define elf_hppa_reloc_final_type elf64_hppa_reloc_final_type -#define _bfd_elf_hppa_gen_reloc_type _bfd_elf64_hppa_gen_reloc_type -#define elf_hppa_relocate_section elf64_hppa_relocate_section -#define elf_hppa_final_link elf64_hppa_final_link -#endif -#if ARCH_SIZE == 32 -#define ELF_R_TYPE(X) ELF32_R_TYPE(X) -#define ELF_R_SYM(X) ELF32_R_SYM(X) -#define elf_hppa_reloc_final_type elf32_hppa_reloc_final_type -#define _bfd_elf_hppa_gen_reloc_type _bfd_elf32_hppa_gen_reloc_type -#define elf_hppa_relocate_section elf32_hppa_relocate_section -#define elf_hppa_final_link elf32_hppa_final_link -#endif - -/* ELF/PA relocation howto entries. */ - -static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] = -{ - { R_PARISC_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_NONE", FALSE, 0, 0, FALSE }, - - /* The values in DIR32 are to placate the check in - _bfd_stab_section_find_nearest_line. */ - { R_PARISC_DIR32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR32", FALSE, 0, 0xffffffff, FALSE }, - { R_PARISC_DIR21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR21L", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR17R, 0, 2, 17, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR17R", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR17F, 0, 2, 17, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR17F", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR14R", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR14F", FALSE, 0, 0, FALSE }, - /* 8 */ - { R_PARISC_PCREL12F, 0, 2, 12, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL12F", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL32", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL21L, 0, 2, 21, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL21L", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL17R, 0, 2, 17, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL17R", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL17F, 0, 2, 17, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL17F", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL17C, 0, 2, 17, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL17C", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL14R, 0, 2, 14, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL14R", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL14F, 0, 2, 14, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL14F", FALSE, 0, 0, FALSE }, - /* 16 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DPREL21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DPREL21L", FALSE, 0, 0, FALSE }, - { R_PARISC_DPREL14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DPREL14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_DPREL14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DPREL14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DPREL14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DPREL14R", FALSE, 0, 0, FALSE }, - { R_PARISC_DPREL14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DPREL14F", FALSE, 0, 0, FALSE }, - /* 24 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTREL21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTREL21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTREL14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTREL14R", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTREL14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTREL14F", FALSE, 0, 0, FALSE }, - /* 32 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTIND21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTIND21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTIND14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTIND14R", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTIND14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTIND14F", FALSE, 0, 0, FALSE }, - /* 40 */ - { R_PARISC_SETBASE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_SETBASE", FALSE, 0, 0, FALSE }, - { R_PARISC_SECREL32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_SECREL32", FALSE, 0, 0xffffffff, FALSE }, - { R_PARISC_BASEREL21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL21L", FALSE, 0, 0, FALSE }, - { R_PARISC_BASEREL17R, 0, 2, 17, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL17R", FALSE, 0, 0, FALSE }, - { R_PARISC_BASEREL17F, 0, 2, 17, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL17F", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_BASEREL14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL14R", FALSE, 0, 0, FALSE }, - { R_PARISC_BASEREL14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL14F", FALSE, 0, 0, FALSE }, - /* 48 */ - { R_PARISC_SEGBASE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_SEGBASE", FALSE, 0, 0, FALSE }, - { R_PARISC_SEGREL32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_SEGREL32", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF14R", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF14F", FALSE, 0, 0, FALSE }, - /* 56 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR32", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR14R", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 64 */ - { R_PARISC_FPTR64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_FPTR64", FALSE, 0, 0, FALSE }, - { R_PARISC_PLABEL32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLABEL32", FALSE, 0, 0, FALSE }, - { R_PARISC_PLABEL21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLABEL21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_PLABEL14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLABEL14R", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 72 */ - { R_PARISC_PCREL64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL64", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL22C, 0, 2, 22, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL22C", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL22F, 0, 2, 22, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL22F", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL16F", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_PCREL16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PCREL16DF", FALSE, 0, 0, FALSE }, - /* 80 */ - { R_PARISC_DIR64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR64", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR16F", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_DIR16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DIR16DF", FALSE, 0, 0, FALSE }, - /* 88 */ - { R_PARISC_GPREL64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_GPREL64", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTREL14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTREL14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTREL14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTREL14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_GPREL16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_GPREL16F", FALSE, 0, 0, FALSE }, - { R_PARISC_GPREL16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_GPREL16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_GPREL16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_GPREL16DF", FALSE, 0, 0, FALSE }, - /* 96 */ - { R_PARISC_LTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF64", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTIND14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTIND14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_DLTIND14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_DLTIND14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF16F", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF16DF", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF16DF", FALSE, 0, 0, FALSE }, - /* 104 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_BASEREL14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_BASEREL14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_BASEREL14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 112 */ - { R_PARISC_SEGREL64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_SEGREL64", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF16F", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_PLTOFF16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_PLTOFF16DF", FALSE, 0, 0, FALSE }, - /* 120 */ - { R_PARISC_LTOFF_FPTR64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR16F", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_FPTR16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_FPTR16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 128 */ - { R_PARISC_COPY, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_COPY", FALSE, 0, 0, FALSE }, - { R_PARISC_IPLT, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_IPLT", FALSE, 0, 0, FALSE }, - { R_PARISC_EPLT, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_EPLT", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 136 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 144 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 152 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL32, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_TPREL32", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TPREL21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TPREL14R", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 160 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP21L", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14R", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP14F, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14F", FALSE, 0, 0, FALSE }, - /* 168 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 176 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 184 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 192 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 200 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 208 */ - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - /* 216 */ - { R_PARISC_TPREL64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TPREL64", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL14WR, 0, 2, 14, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_TPREL14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TPREL14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL16F, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TPREL16F", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL16WF, 0, 2, 16, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_TPREL16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_TPREL16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TPREL16DF", FALSE, 0, 0, FALSE }, - /* 224 */ - { R_PARISC_LTOFF_TP64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP64", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_UNIMPLEMENTED, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP14WR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14WR", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP14DR, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP14DR", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP16F, 0, 2, 16, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP16F", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP16WF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP16WF", FALSE, 0, 0, FALSE }, - { R_PARISC_LTOFF_TP16DF, 0, 2, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_LTOFF_TP16DF", FALSE, 0, 0, FALSE }, - /* 232 */ - { R_PARISC_GNU_VTENTRY, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_GNU_VTENTRY", FALSE, 0, 0, FALSE }, - { R_PARISC_GNU_VTINHERIT, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_GNU_VTINHERIT", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_GD21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_GD21L", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_GD14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_GD14R", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_GDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_TLS_GDCALL", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_LDM21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_LDM21L", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_LDM14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_LDM14R", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_LDMCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_PARISC_TLS_LDMCALL", FALSE, 0, 0, FALSE }, - /* 240 */ - { R_PARISC_TLS_LDO21L, 0, 2, 21, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_LDO21L", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_LDO14R, 0, 2, 14, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_LDO14R", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_DTPMOD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_DTPMOD32", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_DTPMOD64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_DTPMOD64", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_DTPOFF32", FALSE, 0, 0, FALSE }, - { R_PARISC_TLS_DTPOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_PARISC_TLS_DTPOFF64", FALSE, 0, 0, FALSE }, -}; - -#define OFFSET_14R_FROM_21L 4 -#define OFFSET_14F_FROM_21L 5 - -/* Return the final relocation type for the given base type, instruction - format, and field selector. */ - -elf_hppa_reloc_type -elf_hppa_reloc_final_type (bfd *abfd, - elf_hppa_reloc_type base_type, - int format, - unsigned int field) -{ - elf_hppa_reloc_type final_type = base_type; - - /* Just a tangle of nested switch statements to deal with the braindamage - that a different field selector means a completely different relocation - for PA ELF. */ - switch (base_type) - { - /* We have been using generic relocation types. However, that may not - really make sense. Anyway, we need to support both R_PARISC_DIR64 - and R_PARISC_DIR32 here. */ - case R_PARISC_DIR32: - case R_PARISC_DIR64: - case R_HPPA_ABS_CALL: - switch (format) - { - case 14: - switch (field) - { - case e_fsel: - final_type = R_PARISC_DIR14F; - break; - case e_rsel: - case e_rrsel: - case e_rdsel: - final_type = R_PARISC_DIR14R; - break; - case e_rtsel: - final_type = R_PARISC_DLTIND14R; - break; - case e_rtpsel: - final_type = R_PARISC_LTOFF_FPTR14DR; - break; - case e_tsel: - final_type = R_PARISC_DLTIND14F; - break; - case e_rpsel: - final_type = R_PARISC_PLABEL14R; - break; - default: - return R_PARISC_NONE; - } - break; - - case 17: - switch (field) - { - case e_fsel: - final_type = R_PARISC_DIR17F; - break; - case e_rsel: - case e_rrsel: - case e_rdsel: - final_type = R_PARISC_DIR17R; - break; - default: - return R_PARISC_NONE; - } - break; - - case 21: - switch (field) - { - case e_lsel: - case e_lrsel: - case e_ldsel: - case e_nlsel: - case e_nlrsel: - final_type = R_PARISC_DIR21L; - break; - case e_ltsel: - final_type = R_PARISC_DLTIND21L; - break; - case e_ltpsel: - final_type = R_PARISC_LTOFF_FPTR21L; - break; - case e_lpsel: - final_type = R_PARISC_PLABEL21L; - break; - default: - return R_PARISC_NONE; - } - break; - - case 32: - switch (field) - { - case e_fsel: - final_type = R_PARISC_DIR32; - /* When in 64bit mode, a 32bit relocation is supposed to - be a section relative relocation. Dwarf2 (for example) - uses 32bit section relative relocations. */ - if (bfd_arch_bits_per_address (abfd) != 32) - final_type = R_PARISC_SECREL32; - break; - case e_psel: - final_type = R_PARISC_PLABEL32; - break; - default: - return R_PARISC_NONE; - } - break; - - case 64: - switch (field) - { - case e_fsel: - final_type = R_PARISC_DIR64; - break; - case e_psel: - final_type = R_PARISC_FPTR64; - break; - default: - return R_PARISC_NONE; - } - break; - - default: - return R_PARISC_NONE; - } - break; - - case R_HPPA_GOTOFF: - switch (format) - { - case 14: - switch (field) - { - case e_rsel: - case e_rrsel: - case e_rdsel: - /* R_PARISC_DLTREL14R for elf64, R_PARISC_DPREL14R for elf32. */ - final_type = base_type + OFFSET_14R_FROM_21L; - break; - case e_fsel: - /* R_PARISC_DLTREL14F for elf64, R_PARISC_DPREL14F for elf32. */ - final_type = base_type + OFFSET_14F_FROM_21L; - break; - default: - return R_PARISC_NONE; - } - break; - - case 21: - switch (field) - { - case e_lsel: - case e_lrsel: - case e_ldsel: - case e_nlsel: - case e_nlrsel: - /* R_PARISC_DLTREL21L for elf64, R_PARISC_DPREL21L for elf32. */ - final_type = base_type; - break; - default: - return R_PARISC_NONE; - } - break; - - case 64: - switch (field) - { - case e_fsel: - final_type = R_PARISC_GPREL64; - break; - default: - return R_PARISC_NONE; - } - break; - - default: - return R_PARISC_NONE; - } - break; - - case R_HPPA_PCREL_CALL: - switch (format) - { - case 12: - switch (field) - { - case e_fsel: - final_type = R_PARISC_PCREL12F; - break; - default: - return R_PARISC_NONE; - } - break; - - case 14: - /* Contrary to appearances, these are not calls of any sort. - Rather, they are loads/stores with a pcrel reloc. */ - switch (field) - { - case e_rsel: - case e_rrsel: - case e_rdsel: - final_type = R_PARISC_PCREL14R; - break; - case e_fsel: - if (bfd_get_mach (abfd) < 25) - final_type = R_PARISC_PCREL14F; - else - final_type = R_PARISC_PCREL16F; - break; - default: - return R_PARISC_NONE; - } - break; - - case 17: - switch (field) - { - case e_rsel: - case e_rrsel: - case e_rdsel: - final_type = R_PARISC_PCREL17R; - break; - case e_fsel: - final_type = R_PARISC_PCREL17F; - break; - default: - return R_PARISC_NONE; - } - break; - - case 21: - switch (field) - { - case e_lsel: - case e_lrsel: - case e_ldsel: - case e_nlsel: - case e_nlrsel: - final_type = R_PARISC_PCREL21L; - break; - default: - return R_PARISC_NONE; - } - break; - - case 22: - switch (field) - { - case e_fsel: - final_type = R_PARISC_PCREL22F; - break; - default: - return R_PARISC_NONE; - } - break; - - case 32: - switch (field) - { - case e_fsel: - final_type = R_PARISC_PCREL32; - break; - default: - return R_PARISC_NONE; - } - break; - - case 64: - switch (field) - { - case e_fsel: - final_type = R_PARISC_PCREL64; - break; - default: - return R_PARISC_NONE; - } - break; - - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_TLS_GD21L: - switch (field) - { - case e_ltsel: - case e_lrsel: - final_type = R_PARISC_TLS_GD21L; - break; - case e_rtsel: - case e_rrsel: - final_type = R_PARISC_TLS_GD14R; - break; - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_TLS_LDM21L: - switch (field) - { - case e_ltsel: - case e_lrsel: - final_type = R_PARISC_TLS_LDM21L; - break; - case e_rtsel: - case e_rrsel: - final_type = R_PARISC_TLS_LDM14R; - break; - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_TLS_LDO21L: - switch (field) - { - case e_lrsel: - final_type = R_PARISC_TLS_LDO21L; - break; - case e_rrsel: - final_type = R_PARISC_TLS_LDO14R; - break; - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_TLS_IE21L: - switch (field) - { - case e_ltsel: - case e_lrsel: - final_type = R_PARISC_TLS_IE21L; - break; - case e_rtsel: - case e_rrsel: - final_type = R_PARISC_TLS_IE14R; - break; - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_TLS_LE21L: - switch (field) - { - case e_lrsel: - final_type = R_PARISC_TLS_LE21L; - break; - case e_rrsel: - final_type = R_PARISC_TLS_LE14R; - break; - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_SEGREL32: - switch (format) - { - case 32: - switch (field) - { - case e_fsel: - final_type = R_PARISC_SEGREL32; - break; - default: - return R_PARISC_NONE; - } - break; - - case 64: - switch (field) - { - case e_fsel: - final_type = R_PARISC_SEGREL64; - break; - default: - return R_PARISC_NONE; - } - break; - - default: - return R_PARISC_NONE; - } - break; - - case R_PARISC_GNU_VTENTRY: - case R_PARISC_GNU_VTINHERIT: - case R_PARISC_SEGBASE: - /* The defaults are fine for these cases. */ - break; - - default: - return R_PARISC_NONE; - } - - return final_type; -} - -/* Return one (or more) BFD relocations which implement the base - relocation with modifications based on format and field. */ - -elf_hppa_reloc_type ** -_bfd_elf_hppa_gen_reloc_type (bfd *abfd, - elf_hppa_reloc_type base_type, - int format, - unsigned int field, - int ignore ATTRIBUTE_UNUSED, - asymbol *sym ATTRIBUTE_UNUSED) -{ - elf_hppa_reloc_type *finaltype; - elf_hppa_reloc_type **final_types; - bfd_size_type amt = sizeof (elf_hppa_reloc_type *) * 2; - - /* Allocate slots for the BFD relocation. */ - final_types = bfd_alloc (abfd, amt); - if (final_types == NULL) - return NULL; - - /* Allocate space for the relocation itself. */ - amt = sizeof (elf_hppa_reloc_type); - finaltype = bfd_alloc (abfd, amt); - if (finaltype == NULL) - return NULL; - - /* Some reasonable defaults. */ - final_types[0] = finaltype; - final_types[1] = NULL; - - *finaltype = elf_hppa_reloc_final_type (abfd, base_type, format, field); - - return final_types; -} - -/* Translate from an elf into field into a howto relocation pointer. */ - -static void -elf_hppa_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - BFD_ASSERT (ELF_R_TYPE (elf_reloc->r_info) - < (unsigned int) R_PARISC_UNIMPLEMENTED); - bfd_reloc->howto = &elf_hppa_howto_table[ELF_R_TYPE (elf_reloc->r_info)]; -} - -/* Translate from an elf into field into a howto relocation pointer. */ - -static void -elf_hppa_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - BFD_ASSERT (ELF_R_TYPE (elf_reloc->r_info) - < (unsigned int) R_PARISC_UNIMPLEMENTED); - bfd_reloc->howto = &elf_hppa_howto_table[ELF_R_TYPE (elf_reloc->r_info)]; -} - -/* Return the address of the howto table entry to perform the CODE - relocation for an ARCH machine. */ - -static reloc_howto_type * -elf_hppa_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - if ((int) code < (int) R_PARISC_UNIMPLEMENTED) - { - BFD_ASSERT ((int) elf_hppa_howto_table[(int) code].type == (int) code); - return &elf_hppa_howto_table[(int) code]; - } - return NULL; -} - -static reloc_howto_type * -elf_hppa_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf_hppa_howto_table) / sizeof (elf_hppa_howto_table[0]); - i++) - if (elf_hppa_howto_table[i].name != NULL - && strcasecmp (elf_hppa_howto_table[i].name, r_name) == 0) - return &elf_hppa_howto_table[i]; - - return NULL; -} - -/* Return TRUE if SYM represents a local label symbol. */ - -static bfd_boolean -elf_hppa_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - if (name[0] == 'L' && name[1] == '$') - return TRUE; - return _bfd_elf_is_local_label_name (abfd, name); -} - -/* Set the correct type for an ELF section. We do this by the - section name, which is a hack, but ought to work. */ - -static bfd_boolean -elf_hppa_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) -{ - const char *name; - - name = bfd_get_section_name (abfd, sec); - - if (strcmp (name, ".PARISC.unwind") == 0) - { - int indx; - asection *asec; - -#if ARCH_SIZE == 64 - hdr->sh_type = SHT_LOPROC + 1; -#else - hdr->sh_type = 1; -#endif - /* ?!? How are unwinds supposed to work for symbols in arbitrary - sections? Or what if we have multiple .text sections in a single - .o file? HP really messed up on this one. - - Ugh. We can not use elf_section_data (sec)->this_idx at this - point because it is not initialized yet. - - So we (gasp) recompute it here. Hopefully nobody ever changes the - way sections are numbered in elf.c! */ - for (asec = abfd->sections, indx = 1; asec; asec = asec->next, indx++) - { - if (asec->name && strcmp (asec->name, ".text") == 0) - { - hdr->sh_info = indx; - hdr->sh_flags |= SHF_INFO_LINK; - break; - } - } - - /* I have no idea if this is really necessary or what it means. */ - hdr->sh_entsize = 4; - } - return TRUE; -} - -static void -elf_hppa_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - int mach = bfd_get_mach (abfd); - - elf_elfheader (abfd)->e_flags &= ~(EF_PARISC_ARCH | EF_PARISC_TRAPNIL - | EF_PARISC_EXT | EF_PARISC_LSB - | EF_PARISC_WIDE | EF_PARISC_NO_KABP - | EF_PARISC_LAZYSWAP); - - if (mach == 10) - elf_elfheader (abfd)->e_flags |= EFA_PARISC_1_0; - else if (mach == 11) - elf_elfheader (abfd)->e_flags |= EFA_PARISC_1_1; - else if (mach == 20) - elf_elfheader (abfd)->e_flags |= EFA_PARISC_2_0; - else if (mach == 25) - elf_elfheader (abfd)->e_flags |= (EF_PARISC_WIDE - | EFA_PARISC_2_0 - /* The GNU tools have trapped without - option since 1993, so need to take - a step backwards with the ELF - based toolchains. */ - | EF_PARISC_TRAPNIL); -} - -/* Comparison function for qsort to sort unwind section during a - final link. */ - -static int -hppa_unwind_entry_compare (const void *a, const void *b) -{ - const bfd_byte *ap, *bp; - unsigned long av, bv; - - ap = a; - av = (unsigned long) ap[0] << 24; - av |= (unsigned long) ap[1] << 16; - av |= (unsigned long) ap[2] << 8; - av |= (unsigned long) ap[3]; - - bp = b; - bv = (unsigned long) bp[0] << 24; - bv |= (unsigned long) bp[1] << 16; - bv |= (unsigned long) bp[2] << 8; - bv |= (unsigned long) bp[3]; - - return av < bv ? -1 : av > bv ? 1 : 0; -} - -static bfd_boolean -elf_hppa_sort_unwind (bfd *abfd) -{ - asection *s; - - /* Magic section names, but this is much safer than having - relocate_section remember where SEGREL32 relocs occurred. - Consider what happens if someone inept creates a linker script - that puts unwind information in .text. */ - s = bfd_get_section_by_name (abfd, ".PARISC.unwind"); - if (s != NULL) - { - bfd_size_type size; - bfd_byte *contents; - - if (!bfd_malloc_and_get_section (abfd, s, &contents)) - return FALSE; - - size = s->size; - qsort (contents, (size_t) (size / 16), 16, hppa_unwind_entry_compare); - - if (! bfd_set_section_contents (abfd, s, contents, (file_ptr) 0, size)) - return FALSE; - } - - return TRUE; -} - -/* What to do when ld finds relocations against symbols defined in - discarded sections. */ - -static unsigned int -elf_hppa_action_discarded (asection *sec) -{ - /* Ignore relocations in .data.rel.ro.local. This section can contain - PLABEL32 relocations to functions in discarded COMDAT groups. */ - if (strcmp (".data.rel.ro.local", sec->name) == 0) - return 0; - - if (strcmp (".PARISC.unwind", sec->name) == 0) - return 0; - - return _bfd_elf_default_action_discarded (sec); -} diff --git a/sdcc/support/sdbinutils/bfd/elf-ifunc.c b/sdcc/support/sdbinutils/bfd/elf-ifunc.c deleted file mode 100644 index 1fab44013..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-ifunc.c +++ /dev/null @@ -1,357 +0,0 @@ -/* ELF STT_GNU_IFUNC support. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#define ARCH_SIZE 0 -#include "elf-bfd.h" -#include "safe-ctype.h" -#include "libiberty.h" -#include "objalloc.h" - -/* Create sections needed by STT_GNU_IFUNC symbol. */ - -bfd_boolean -_bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags, pltflags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (htab->irelifunc != NULL || htab->iplt != NULL) - return TRUE; - - 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; - - if (bfd_link_pic (info)) - { - /* We need to create .rel[a].ifunc for PIC objects. */ - const char *rel_sec = (bed->rela_plts_and_copies_p - ? ".rela.ifunc" : ".rel.ifunc"); - - s = bfd_make_section_with_flags (abfd, rel_sec, - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->irelifunc = s; - } - else - { - /* We need to create .iplt, .rel[a].iplt, .igot and .igot.plt - for static executables. */ - s = bfd_make_section_with_flags (abfd, ".iplt", pltflags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - htab->iplt = s; - - s = bfd_make_section_with_flags (abfd, - (bed->rela_plts_and_copies_p - ? ".rela.iplt" : ".rel.iplt"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->irelplt = s; - - /* We don't need the .igot section if we have the .igot.plt - section. */ - if (bed->want_got_plt) - s = bfd_make_section_with_flags (abfd, ".igot.plt", flags); - else - s = bfd_make_section_with_flags (abfd, ".igot", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->igotplt = s; - } - - return TRUE; -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs against a STT_GNU_IFUNC symbol definition. */ - -bfd_boolean -_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - struct elf_dyn_relocs **head, - bfd_boolean *readonly_dynrelocs_against_ifunc_p, - unsigned int plt_entry_size, - unsigned int plt_header_size, - unsigned int got_entry_size, - bfd_boolean avoid_plt) -{ - asection *plt, *gotplt, *relplt; - struct elf_dyn_relocs *p; - unsigned int sizeof_reloc; - const struct elf_backend_data *bed; - struct elf_link_hash_table *htab; - bfd_boolean readonly_dynrelocs_against_ifunc; - /* If AVOID_PLT is TRUE, don't use PLT if possible. */ - bfd_boolean use_plt = !avoid_plt || h->plt.refcount > 0; - bfd_boolean need_dynreloc = !use_plt || bfd_link_pic (info); - - /* When a PIC object references a STT_GNU_IFUNC symbol defined - in executable or it isn't referenced via PLT, the address of - the resolved function may be used. But in non-PIC executable, - the address of its .plt slot may be used. Pointer equality may - not work correctly. PIE or non-PLT reference should be used if - pointer equality is required here. */ - if (!need_dynreloc - && (h->dynindx != -1 - || info->export_dynamic) - && h->pointer_equality_needed) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer " - "equality in `%B' can not be used when making an " - "executable; recompile with -fPIE and relink with -pie\n"), - h->root.root.string, - h->root.u.def.section->owner); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - htab = elf_hash_table (info); - - /* When the symbol is marked with regular reference, if PLT isn't used - or we are building a PIC object, we must keep dynamic relocation - if there is non-GOT reference and use PLT if there is PC-relative - reference. */ - if (need_dynreloc && h->ref_regular) - { - bfd_boolean keep = FALSE; - for (p = *head; p != NULL; p = p->next) - if (p->count) - { - h->non_got_ref = 1; - /* Need dynamic relocations for non-GOT reference. */ - keep = TRUE; - if (p->pc_count) - { - /* Must use PLT for PC-relative reference. */ - use_plt = TRUE; - need_dynreloc = bfd_link_pic (info); - break; - } - } - if (keep) - goto keep; - } - - /* Support garbage collection against STT_GNU_IFUNC symbols. */ - if (h->plt.refcount <= 0 && h->got.refcount <= 0) - { - h->got = htab->init_got_offset; - h->plt = htab->init_plt_offset; - *head = NULL; - return TRUE; - } - - /* Return and discard space for dynamic relocations against it if - it is never referenced. */ - if (!h->ref_regular) - { - if (h->plt.refcount > 0 - || h->got.refcount > 0) - abort (); - h->got = htab->init_got_offset; - h->plt = htab->init_plt_offset; - *head = NULL; - return TRUE; - } - -keep: - bed = get_elf_backend_data (info->output_bfd); - if (bed->rela_plts_and_copies_p) - sizeof_reloc = bed->s->sizeof_rela; - else - sizeof_reloc = bed->s->sizeof_rel; - - /* When building a static executable, use .iplt, .igot.plt and - .rel[a].iplt sections for STT_GNU_IFUNC symbols. */ - if (htab->splt != NULL) - { - plt = htab->splt; - gotplt = htab->sgotplt; - relplt = htab->srelplt; - - /* If this is the first .plt entry and PLT is used, make room for - the special first entry. */ - if (plt->size == 0 && use_plt) - plt->size += plt_header_size; - } - else - { - plt = htab->iplt; - gotplt = htab->igotplt; - relplt = htab->irelplt; - } - - if (use_plt) - { - /* Don't update value of STT_GNU_IFUNC symbol to PLT. We need - the original value for R_*_IRELATIVE. */ - h->plt.offset = plt->size; - - /* Make room for this entry in the .plt/.iplt section. */ - plt->size += plt_entry_size; - - /* We also need to make an entry in the .got.plt/.got.iplt section, - which will be placed in the .got section by the linker script. */ - gotplt->size += got_entry_size; - } - - /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt - section for GOTPLT relocation if PLT is used. */ - if (use_plt) - { - relplt->size += sizeof_reloc; - relplt->reloc_count++; - } - - /* We need dynamic relocation for STT_GNU_IFUNC symbol only when - there is a non-GOT reference in a PIC object or PLT isn't used. */ - if (!need_dynreloc || !h->non_got_ref) - *head = NULL; - - readonly_dynrelocs_against_ifunc = FALSE; - - /* Finally, allocate space. */ - p = *head; - if (p != NULL) - { - bfd_size_type count = 0; - do - { - if (!readonly_dynrelocs_against_ifunc) - { - asection *s = p->sec->output_section; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - readonly_dynrelocs_against_ifunc = TRUE; - } - count += p->count; - p = p->next; - } - while (p != NULL); - - /* Dynamic relocations are stored in - 1. .rel[a].ifunc section in PIC object. - 2. .rel[a].got section in dynamic executable. - 3. .rel[a].iplt section in static executable. */ - if (bfd_link_pic (info)) - htab->irelifunc->size += count * sizeof_reloc; - else if (htab->splt != NULL) - htab->srelgot->size += count * sizeof_reloc; - else - { - relplt->size += count * sizeof_reloc; - relplt->reloc_count += count; - } - } - - if (readonly_dynrelocs_against_ifunc_p) - *readonly_dynrelocs_against_ifunc_p = readonly_dynrelocs_against_ifunc; - - /* For STT_GNU_IFUNC symbol, .got.plt has the real function address - and .got has the PLT entry adddress. We will load the GOT entry - with the PLT entry in finish_dynamic_symbol if it is used. For - branch, it uses .got.plt. For symbol value, if PLT is used, - 1. Use .got.plt in a PIC object if it is forced local or not - dynamic. - 2. Use .got.plt in a non-PIC object if pointer equality isn't - needed. - 3. Use .got.plt in PIE. - 4. Use .got.plt if .got isn't used. - 5. Otherwise use .got so that it can be shared among different - objects at run-time. - If PLT isn't used, always use .got for symbol value. - We only need to relocate .got entry in PIC object or in dynamic - executable without PLT. */ - if (use_plt - && (h->got.refcount <= 0 - || (bfd_link_pic (info) - && (h->dynindx == -1 - || h->forced_local)) - || (!bfd_link_pic (info) - && !h->pointer_equality_needed) - || bfd_link_pie (info) - || htab->sgot == NULL)) - { - /* Use .got.plt. */ - h->got.offset = (bfd_vma) -1; - } - else - { - if (!use_plt) - { - /* PLT isn't used. */ - h->plt.offset = (bfd_vma) -1; - } - if (h->got.refcount <= 0) - { - /* GOT isn't need when there are only relocations for static - pointers. */ - h->got.offset = (bfd_vma) -1; - } - else - { - h->got.offset = htab->sgot->size; - htab->sgot->size += got_entry_size; - /* Need to relocate the GOT entry in a PIC object or PLT isn't - used. Otherwise, the GOT entry will be filled with the PLT - entry and dynamic GOT relocation isn't needed. */ - if (need_dynreloc) - { - /* For non-static executable, dynamic GOT relocation is in - .rel[a].got section, but for static executable, it is - in .rel[a].iplt section. */ - if (htab->splt != NULL) - htab->srelgot->size += sizeof_reloc; - else - { - relplt->size += sizeof_reloc; - relplt->reloc_count++; - } - } - } - } - - return TRUE; -} diff --git a/sdcc/support/sdbinutils/bfd/elf-linux-core.h b/sdcc/support/sdbinutils/bfd/elf-linux-core.h deleted file mode 100644 index 0a5d76fe9..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-linux-core.h +++ /dev/null @@ -1,234 +0,0 @@ -/* Definitions for PRPSINFO structures under ELF on GNU/Linux. - Copyright (C) 2013-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef ELF_LINUX_CORE_H -#define ELF_LINUX_CORE_H - -/* External 32-bit structure for PRPSINFO. This structure is - ABI-defined, thus we choose to use char arrays here in order to - avoid dealing with different types in different architectures. - - This is the variant for targets which use a 32-bit data type for - UID and GID, as all modern Linux ports do. Some older ports use - a 16-bit data type instead; see below for the alternative variant. - - This structure will ultimately be written in the corefile's note - section, as the PRPSINFO. */ - -struct elf_external_linux_prpsinfo32_ugid32 - { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - char pr_flag[4]; /* Flags. */ - char pr_uid[4]; - char pr_gid[4]; - char pr_pid[4]; - char pr_ppid[4]; - char pr_pgrp[4]; - char pr_sid[4]; - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ - }; - -/* Helper function to copy an elf_internal_linux_prpsinfo in host - endian to an elf_external_linux_prpsinfo32_ugid32 in target endian. */ - -static inline void -swap_linux_prpsinfo32_ugid32_out - (bfd *obfd, - const struct elf_internal_linux_prpsinfo *from, - struct elf_external_linux_prpsinfo32_ugid32 *to) -{ - bfd_put_8 (obfd, from->pr_state, &to->pr_state); - bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); - bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); - bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); - bfd_put_32 (obfd, from->pr_flag, to->pr_flag); - bfd_put_32 (obfd, from->pr_uid, to->pr_uid); - bfd_put_32 (obfd, from->pr_gid, to->pr_gid); - bfd_put_32 (obfd, from->pr_pid, to->pr_pid); - bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); - bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); - bfd_put_32 (obfd, from->pr_sid, to->pr_sid); - strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); - strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); -} - -/* External 32-bit structure for PRPSINFO. This structure is - ABI-defined, thus we choose to use char arrays here in order to - avoid dealing with different types in different architectures. - - This is the variant for targets which use a 16-bit data type for - UID and GID, as some older Linux ports do. All modern ports use - a 32-bit data type instead; see above for the alternative variant. - - This structure will ultimately be written in the corefile's note - section, as the PRPSINFO. */ - -struct elf_external_linux_prpsinfo32_ugid16 - { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - char pr_flag[4]; /* Flags. */ - char pr_uid[2]; - char pr_gid[2]; - char pr_pid[4]; - char pr_ppid[4]; - char pr_pgrp[4]; - char pr_sid[4]; - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ - }; - -/* Helper function to copy an elf_internal_linux_prpsinfo in host - endian to an elf_external_linux_prpsinfo32_ugid16 in target endian. */ - -static inline void -swap_linux_prpsinfo32_ugid16_out - (bfd *obfd, - const struct elf_internal_linux_prpsinfo *from, - struct elf_external_linux_prpsinfo32_ugid16 *to) -{ - bfd_put_8 (obfd, from->pr_state, &to->pr_state); - bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); - bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); - bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); - bfd_put_32 (obfd, from->pr_flag, to->pr_flag); - bfd_put_16 (obfd, from->pr_uid, to->pr_uid); - bfd_put_16 (obfd, from->pr_gid, to->pr_gid); - bfd_put_32 (obfd, from->pr_pid, to->pr_pid); - bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); - bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); - bfd_put_32 (obfd, from->pr_sid, to->pr_sid); - strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); - strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); -} - -/* External 64-bit structure for PRPSINFO. This structure is - ABI-defined, thus we choose to use char arrays here in order to - avoid dealing with different types in different architectures. - - This is the variant for targets which use a 32-bit data type for - UID and GID, as most Linux ports do. The SH64 port uses a 16-bit - data type instead; see below for the alternative variant. - - This structure will ultimately be written in the corefile's note - section, as the PRPSINFO. */ - -struct elf_external_linux_prpsinfo64_ugid32 - { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - char gap[4]; - char pr_flag[8]; /* Flags. */ - char pr_uid[4]; - char pr_gid[4]; - char pr_pid[4]; - char pr_ppid[4]; - char pr_pgrp[4]; - char pr_sid[4]; - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ - }; - -/* Helper function to copy an elf_internal_linux_prpsinfo in host - endian to an elf_external_linux_prpsinfo64_ugid32 in target endian. */ - -static inline void -swap_linux_prpsinfo64_ugid32_out - (bfd *obfd, - const struct elf_internal_linux_prpsinfo *from, - struct elf_external_linux_prpsinfo64_ugid32 *to) -{ - bfd_put_8 (obfd, from->pr_state, &to->pr_state); - bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); - bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); - bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); - bfd_put_64 (obfd, from->pr_flag, to->pr_flag); - bfd_put_32 (obfd, from->pr_uid, to->pr_uid); - bfd_put_32 (obfd, from->pr_gid, to->pr_gid); - bfd_put_32 (obfd, from->pr_pid, to->pr_pid); - bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); - bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); - bfd_put_32 (obfd, from->pr_sid, to->pr_sid); - strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); - strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); -} - -/* External 64-bit structure for PRPSINFO. This structure is - ABI-defined, thus we choose to use char arrays here in order to - avoid dealing with different types in different architectures. - - This is the variant for the SH64 port which uses a 16-bit data - type for UID and GID. Most Linux ports use a 32-bit data type - instead; see above for the alternative variant. - - This structure will ultimately be written in the corefile's note - section, as the PRPSINFO. */ - -struct elf_external_linux_prpsinfo64_ugid16 - { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - char gap[4]; - char pr_flag[8]; /* Flags. */ - char pr_uid[2]; - char pr_gid[2]; - char pr_pid[4]; - char pr_ppid[4]; - char pr_pgrp[4]; - char pr_sid[4]; - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ - }; - -/* Helper function to copy an elf_internal_linux_prpsinfo in host - endian to an elf_external_linux_prpsinfo64_ugid16 in target endian. */ - -static inline void -swap_linux_prpsinfo64_ugid16_out - (bfd *obfd, - const struct elf_internal_linux_prpsinfo *from, - struct elf_external_linux_prpsinfo64_ugid16 *to) -{ - bfd_put_8 (obfd, from->pr_state, &to->pr_state); - bfd_put_8 (obfd, from->pr_sname, &to->pr_sname); - bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb); - bfd_put_8 (obfd, from->pr_nice, &to->pr_nice); - bfd_put_64 (obfd, from->pr_flag, to->pr_flag); - bfd_put_16 (obfd, from->pr_uid, to->pr_uid); - bfd_put_16 (obfd, from->pr_gid, to->pr_gid); - bfd_put_32 (obfd, from->pr_pid, to->pr_pid); - bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid); - bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp); - bfd_put_32 (obfd, from->pr_sid, to->pr_sid); - strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname)); - strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs)); -} - -#endif diff --git a/sdcc/support/sdbinutils/bfd/elf-m10200.c b/sdcc/support/sdbinutils/bfd/elf-m10200.c deleted file mode 100644 index 82c4ee733..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-m10200.c +++ /dev/null @@ -1,1389 +0,0 @@ -/* Matsushita 10200 specific support for 32-bit ELF - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -static bfd_boolean -mn10200_elf_relax_delete_bytes (bfd *, asection *, bfd_vma, int); -static bfd_boolean -mn10200_elf_symbol_address_p (bfd *, asection *, Elf_Internal_Sym *, bfd_vma); - -enum reloc_type -{ - R_MN10200_NONE = 0, - R_MN10200_32, - R_MN10200_16, - R_MN10200_8, - R_MN10200_24, - R_MN10200_PCREL8, - R_MN10200_PCREL16, - R_MN10200_PCREL24, - R_MN10200_MAX -}; - -static reloc_howto_type elf_mn10200_howto_table[] = -{ - /* Dummy relocation. Does nothing. */ - HOWTO (R_MN10200_NONE, - 0, - 3, - 0, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_MN10200_NONE", - FALSE, - 0, - 0, - FALSE), - /* Standard 32 bit reloc. */ - HOWTO (R_MN10200_32, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_32", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - /* Standard 16 bit reloc. */ - HOWTO (R_MN10200_16, - 0, - 1, - 16, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_16", - FALSE, - 0xffff, - 0xffff, - FALSE), - /* Standard 8 bit reloc. */ - HOWTO (R_MN10200_8, - 0, - 0, - 8, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_8", - FALSE, - 0xff, - 0xff, - FALSE), - /* Standard 24 bit reloc. */ - HOWTO (R_MN10200_24, - 0, - 2, - 24, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_24", - FALSE, - 0xffffff, - 0xffffff, - FALSE), - /* Simple 8 pc-relative reloc. */ - HOWTO (R_MN10200_PCREL8, - 0, - 0, - 8, - TRUE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_PCREL8", - FALSE, - 0xff, - 0xff, - TRUE), - /* Simple 16 pc-relative reloc. */ - HOWTO (R_MN10200_PCREL16, - 0, - 1, - 16, - TRUE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_PCREL16", - FALSE, - 0xffff, - 0xffff, - TRUE), - /* Simple 32bit pc-relative reloc with a 1 byte adjustment - to get the pc-relative offset correct. */ - HOWTO (R_MN10200_PCREL24, - 0, - 2, - 24, - TRUE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10200_PCREL24", - FALSE, - 0xffffff, - 0xffffff, - TRUE), -}; - -struct mn10200_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct mn10200_reloc_map mn10200_reloc_map[] = -{ - { BFD_RELOC_NONE , R_MN10200_NONE , }, - { BFD_RELOC_32 , R_MN10200_32 , }, - { BFD_RELOC_16 , R_MN10200_16 , }, - { BFD_RELOC_8 , R_MN10200_8 , }, - { BFD_RELOC_24 , R_MN10200_24 , }, - { BFD_RELOC_8_PCREL , R_MN10200_PCREL8 , }, - { BFD_RELOC_16_PCREL, R_MN10200_PCREL16, }, - { BFD_RELOC_24_PCREL, R_MN10200_PCREL24, }, -}; - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (mn10200_reloc_map) / sizeof (struct mn10200_reloc_map); - i++) - { - if (mn10200_reloc_map[i].bfd_reloc_val == code) - return &elf_mn10200_howto_table[mn10200_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf_mn10200_howto_table) - / sizeof (elf_mn10200_howto_table[0])); - i++) - if (elf_mn10200_howto_table[i].name != NULL - && strcasecmp (elf_mn10200_howto_table[i].name, r_name) == 0) - return &elf_mn10200_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an MN10200 ELF reloc. */ - -static void -mn10200_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - BFD_ASSERT (r_type < (unsigned int) R_MN10200_MAX); - cache_ptr->howto = &elf_mn10200_howto_table[r_type]; -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -mn10200_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd_byte *contents, - bfd_vma offset, - bfd_vma value, - bfd_vma addend, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sym_sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - unsigned long r_type = howto->type; - bfd_byte *hit_data = contents + offset; - - switch (r_type) - { - - case R_MN10200_NONE: - return bfd_reloc_ok; - - case R_MN10200_32: - value += addend; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10200_16: - value += addend; - - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10200_8: - value += addend; - - if ((long) value > 0x7f || (long) value < -0x80) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10200_24: - value += addend; - - if ((long) value > 0x7fffff || (long) value < -0x800000) - return bfd_reloc_overflow; - - value &= 0xffffff; - value |= (bfd_get_32 (input_bfd, hit_data) & 0xff000000); - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10200_PCREL8: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= (offset + 1); - value += addend; - - if ((long) value > 0xff || (long) value < -0x100) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10200_PCREL16: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= (offset + 2); - value += addend; - - if ((long) value > 0xffff || (long) value < -0x10000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10200_PCREL24: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= (offset + 3); - value += addend; - - if ((long) value > 0xffffff || (long) value < -0x1000000) - return bfd_reloc_overflow; - - value &= 0xffffff; - value |= (bfd_get_32 (input_bfd, hit_data) & 0xff000000); - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - default: - return bfd_reloc_notsupported; - } -} - -/* Relocate an MN10200 ELF section. */ -static bfd_boolean -mn10200_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - howto = elf_mn10200_howto_table + r_type; - - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = mn10200_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char *name; - const char *msg = (const char *) 0; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) (info, name, input_bfd, - input_section, - rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -mn10200_elf_relax_delete_bytes (bfd *abfd, asection *sec, - bfd_vma addr, int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset < toaddr)) - irel->r_offset -= count; - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - isym->st_value -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - { - sym_hash->root.u.def.value -= count; - } - } - - return TRUE; -} - -/* This function handles relaxing for the mn10200. - - There are quite a few relaxing opportunities available on the mn10200: - - * jsr:24 -> jsr:16 2 bytes - - * jmp:24 -> jmp:16 2 bytes - * jmp:16 -> bra:8 1 byte - - * If the previous instruction is a conditional branch - around the jump/bra, we may be able to reverse its condition - and change its target to the jump's target. The jump/bra - can then be deleted. 2 bytes - - * mov abs24 -> mov abs16 2 byte savings - - * Most instructions which accept imm24 can relax to imm16 2 bytes - - Most instructions which accept imm16 can relax to imm8 1 byte - - * Most instructions which accept d24 can relax to d16 2 bytes - - Most instructions which accept d16 can relax to d8 1 byte - - abs24, imm24, d24 all look the same at the reloc level. It - might make the code simpler if we had different relocs for - the various relaxable operand types. - - We don't handle imm16->imm8 or d16->d8 as they're very rare - and somewhat more difficult to support. */ - -static bfd_boolean -mn10200_elf_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_NONE - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_8 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_MAX) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - } - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Try to turn a 24bit pc-relative branch/call into a 16bit pc-relative - branch/call. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_PCREL24) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= (irel->r_offset + 3); - value += irel->r_addend; - - /* See if the value will fit in 16 bits, note the high value is - 0x7fff + 2 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 0x8001 && (long) value > -0x8000) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - if (code != 0xe0 && code != 0xe1) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - if (code == 0xe0) - bfd_put_8 (abfd, 0xfc, contents + irel->r_offset - 2); - else if (code == 0xe1) - bfd_put_8 (abfd, 0xfd, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10200_PCREL16); - - /* The opcode got shorter too, so we have to fix the offset. */ - irel->r_offset -= 1; - - /* Delete two bytes of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 16bit pc-relative branch into a 8bit pc-relative - branch. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_PCREL16) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= (irel->r_offset + 2); - value += irel->r_addend; - - /* See if the value will fit in 8 bits, note the high value is - 0x7f + 1 as the target will be one bytes closer if we are - able to relax. */ - if ((long) value < 0x80 && (long) value > -0x80) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - if (code != 0xfc) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xea, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10200_PCREL8); - - /* Delete one byte of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 1)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to eliminate an unconditional 8 bit pc-relative branch - which immediately follows a conditional 8 bit pc-relative - branch around the unconditional branch. - - original: new: - bCC lab1 bCC' lab2 - bra lab2 - lab1: lab1: - - This happens when the bCC can't reach lab2 at assembly time, - but due to other relaxations it can reach at link time. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_PCREL8) - { - Elf_Internal_Rela *nrel; - bfd_vma value = symval; - unsigned char code; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= (irel->r_offset + 1); - value += irel->r_addend; - - /* Do nothing if this reloc is the last byte in the section. */ - if (irel->r_offset == sec->size) - continue; - - /* See if the next instruction is an unconditional pc-relative - branch, more often than not this test will fail, so we - test it first to speed things up. */ - code = bfd_get_8 (abfd, contents + irel->r_offset + 1); - if (code != 0xea) - continue; - - /* Also make sure the next relocation applies to the next - instruction and that it's a pc-relative 8 bit branch. */ - nrel = irel + 1; - if (nrel == irelend - || irel->r_offset + 2 != nrel->r_offset - || ELF32_R_TYPE (nrel->r_info) != (int) R_MN10200_PCREL8) - continue; - - /* Make sure our destination immediately follows the - unconditional branch. */ - if (symval != (sec->output_section->vma + sec->output_offset - + irel->r_offset + 3)) - continue; - - /* Now make sure we are a conditional branch. This may not - be necessary, but why take the chance. - - Note these checks assume that R_MN10200_PCREL8 relocs - only occur on bCC and bCCx insns. If they occured - elsewhere, we'd need to know the start of this insn - for this check to be accurate. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - if (code != 0xe0 && code != 0xe1 && code != 0xe2 - && code != 0xe3 && code != 0xe4 && code != 0xe5 - && code != 0xe6 && code != 0xe7 && code != 0xe8 - && code != 0xe9 && code != 0xec && code != 0xed - && code != 0xee && code != 0xef && code != 0xfc - && code != 0xfd && code != 0xfe && code != 0xff) - continue; - - /* We also have to be sure there is no symbol/label - at the unconditional branch. */ - if (mn10200_elf_symbol_address_p (abfd, sec, isymbuf, - irel->r_offset + 1)) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Reverse the condition of the first branch. */ - switch (code) - { - case 0xfc: - code = 0xfd; - break; - case 0xfd: - code = 0xfc; - break; - case 0xfe: - code = 0xff; - break; - case 0xff: - code = 0xfe; - break; - case 0xe8: - code = 0xe9; - break; - case 0xe9: - code = 0xe8; - break; - case 0xe0: - code = 0xe2; - break; - case 0xe2: - code = 0xe0; - break; - case 0xe3: - code = 0xe1; - break; - case 0xe1: - code = 0xe3; - break; - case 0xe4: - code = 0xe6; - break; - case 0xe6: - code = 0xe4; - break; - case 0xe7: - code = 0xe5; - break; - case 0xe5: - code = 0xe7; - break; - case 0xec: - code = 0xed; - break; - case 0xed: - code = 0xec; - break; - case 0xee: - code = 0xef; - break; - case 0xef: - code = 0xee; - break; - } - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - /* Set the reloc type and symbol for the first branch - from the second branch. */ - irel->r_info = nrel->r_info; - - /* Make the reloc for the second branch a null reloc. */ - nrel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info), - R_MN10200_NONE); - - /* Delete two bytes of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - - /* Try to turn a 24bit immediate, displacement or absolute address - into a 16bit immediate, displacement or absolute address. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10200_24) - { - bfd_vma value = symval; - - /* See if the value will fit in 16 bits. - We allow any 16bit match here. We prune those we can't - handle below. */ - if ((long) value < 0x7fff && (long) value > -0x8000) - { - unsigned char code; - - /* All insns which have 24bit operands are 5 bytes long, - the first byte will always be 0xf4, but we double check - it just in case. */ - - /* Get the first opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - if (code != 0xf4) - continue; - - /* Get the second opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - switch (code & 0xfc) - { - /* mov imm24,dn -> mov imm16,dn */ - case 0x70: - /* Not safe if the high bit is on as relaxing may - move the value out of high mem and thus not fit - in a signed 16bit value. */ - if (value & 0x8000) - continue; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xf8 + (code & 0x03), - contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10200_16); - - /* The opcode got shorter too, so we have to fix the - offset. */ - irel->r_offset -= 1; - - /* Delete two bytes of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - - /* mov imm24,an -> mov imm16,an - cmp imm24,an -> cmp imm16,an - mov (abs24),dn -> mov (abs16),dn - mov dn,(abs24) -> mov dn,(abs16) - movb dn,(abs24) -> movb dn,(abs16) - movbu (abs24),dn -> movbu (abs16),dn */ - case 0x74: - case 0x7c: - case 0xc0: - case 0x40: - case 0x44: - case 0xc8: - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - if ((code & 0xfc) == 0x74) - code = 0xdc + (code & 0x03); - else if ((code & 0xfc) == 0x7c) - code = 0xec + (code & 0x03); - else if ((code & 0xfc) == 0xc0) - code = 0xc8 + (code & 0x03); - else if ((code & 0xfc) == 0x40) - code = 0xc0 + (code & 0x03); - else if ((code & 0xfc) == 0x44) - code = 0xc4 + (code & 0x03); - else if ((code & 0xfc) == 0xc8) - code = 0xcc + (code & 0x03); - - /* Fix the opcode. */ - bfd_put_8 (abfd, code, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10200_16); - - /* The opcode got shorter too, so we have to fix the - offset. */ - irel->r_offset -= 1; - - /* Delete two bytes of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - - /* cmp imm24,dn -> cmp imm16,dn - mov (abs24),an -> mov (abs16),an - mov an,(abs24) -> mov an,(abs16) - add imm24,dn -> add imm16,dn - add imm24,an -> add imm16,an - sub imm24,dn -> sub imm16,dn - sub imm24,an -> sub imm16,an - And all d24->d16 in memory ops. */ - case 0x78: - case 0xd0: - case 0x50: - case 0x60: - case 0x64: - case 0x68: - case 0x6c: - case 0x80: - case 0xf0: - case 0x00: - case 0x10: - case 0xb0: - case 0x30: - case 0xa0: - case 0x20: - case 0x90: - /* Not safe if the high bit is on as relaxing may - move the value out of high mem and thus not fit - in a signed 16bit value. */ - if (((code & 0xfc) == 0x78 - || (code & 0xfc) == 0x60 - || (code & 0xfc) == 0x64 - || (code & 0xfc) == 0x68 - || (code & 0xfc) == 0x6c - || (code & 0xfc) == 0x80 - || (code & 0xfc) == 0xf0 - || (code & 0xfc) == 0x00 - || (code & 0xfc) == 0x10 - || (code & 0xfc) == 0xb0 - || (code & 0xfc) == 0x30 - || (code & 0xfc) == 0xa0 - || (code & 0xfc) == 0x20 - || (code & 0xfc) == 0x90) - && (value & 0x8000) != 0) - continue; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xf7, contents + irel->r_offset - 2); - - if ((code & 0xfc) == 0x78) - code = 0x48 + (code & 0x03); - else if ((code & 0xfc) == 0xd0) - code = 0x30 + (code & 0x03); - else if ((code & 0xfc) == 0x50) - code = 0x20 + (code & 0x03); - else if ((code & 0xfc) == 0x60) - code = 0x18 + (code & 0x03); - else if ((code & 0xfc) == 0x64) - code = 0x08 + (code & 0x03); - else if ((code & 0xfc) == 0x68) - code = 0x1c + (code & 0x03); - else if ((code & 0xfc) == 0x6c) - code = 0x0c + (code & 0x03); - else if ((code & 0xfc) == 0x80) - code = 0xc0 + (code & 0x07); - else if ((code & 0xfc) == 0xf0) - code = 0xb0 + (code & 0x07); - else if ((code & 0xfc) == 0x00) - code = 0x80 + (code & 0x07); - else if ((code & 0xfc) == 0x10) - code = 0xa0 + (code & 0x07); - else if ((code & 0xfc) == 0xb0) - code = 0x70 + (code & 0x07); - else if ((code & 0xfc) == 0x30) - code = 0x60 + (code & 0x07); - else if ((code & 0xfc) == 0xa0) - code = 0xd0 + (code & 0x07); - else if ((code & 0xfc) == 0x20) - code = 0x90 + (code & 0x07); - else if ((code & 0xfc) == 0x90) - code = 0x50 + (code & 0x07); - - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10200_16); - - /* Delete one bytes of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 1)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - - /* movb (abs24),dn ->movbu (abs16),dn extxb bn */ - case 0xc4: - /* Note that we've changed the reldection contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - bfd_put_8 (abfd, 0xcc + (code & 0x03), - contents + irel->r_offset - 2); - - bfd_put_8 (abfd, 0xb8 + (code & 0x03), - contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10200_16); - - /* The reloc will be applied one byte in front of its - current location. */ - irel->r_offset -= 1; - - /* Delete one bytes of data. */ - if (!mn10200_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 1)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - } - } - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* Return TRUE if a symbol exists at the given address, else return - FALSE. */ -static bfd_boolean -mn10200_elf_symbol_address_p (bfd *abfd, - asection *sec, - Elf_Internal_Sym *isym, - bfd_vma addr) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* Examine all the local symbols. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value == addr) - return TRUE; - } - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == addr) - return TRUE; - } - - return FALSE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses mn10200_elf_relocate_section. */ - -static bfd_byte * -mn10200_elf_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - asection **secpp; - bfd_size_type amt; - - internal_relocs = (_bfd_elf_link_read_relocs - (input_bfd, input_section, NULL, - (Elf_Internal_Rela *) NULL, FALSE)); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = (asection **) bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! mn10200_elf_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - return NULL; -} - -#define TARGET_LITTLE_SYM mn10200_elf32_vec -#define TARGET_LITTLE_NAME "elf32-mn10200" -#define ELF_ARCH bfd_arch_mn10200 -#define ELF_MACHINE_CODE EM_MN10200 -#define ELF_MACHINE_ALT1 EM_CYGNUS_MN10200 -#define ELF_MAXPAGESIZE 0x1000 - -#define elf_backend_rela_normal 1 -#define elf_info_to_howto mn10200_info_to_howto -#define elf_info_to_howto_rel 0 -#define elf_backend_relocate_section mn10200_elf_relocate_section -#define bfd_elf32_bfd_relax_section mn10200_elf_relax_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - mn10200_elf_get_relocated_section_contents - -#define elf_symbol_leading_char '_' - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf-m10300.c b/sdcc/support/sdbinutils/bfd/elf-m10300.c deleted file mode 100644 index a91257edf..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-m10300.c +++ /dev/null @@ -1,5594 +0,0 @@ -/* Matsushita 10300 specific support for 32-bit ELF - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/mn10300.h" -#include "libiberty.h" - -/* The mn10300 linker needs to keep track of the number of relocs that - it decides to copy in check_relocs for each symbol. This is so - that it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ - -struct elf32_mn10300_link_hash_entry -{ - /* The basic elf link hash table entry. */ - struct elf_link_hash_entry root; - - /* For function symbols, the number of times this function is - called directly (ie by name). */ - unsigned int direct_calls; - - /* For function symbols, the size of this function's stack - (if <= 255 bytes). We stuff this into "call" instructions - to this target when it's valid and profitable to do so. - - This does not include stack allocated by movm! */ - unsigned char stack_size; - - /* For function symbols, arguments (if any) for movm instruction - in the prologue. We stuff this value into "call" instructions - to the target when it's valid and profitable to do so. */ - unsigned char movm_args; - - /* For function symbols, the amount of stack space that would be allocated - by the movm instruction. This is redundant with movm_args, but we - add it to the hash table to avoid computing it over and over. */ - unsigned char movm_stack_size; - -/* When set, convert all "call" instructions to this target into "calls" - instructions. */ -#define MN10300_CONVERT_CALL_TO_CALLS 0x1 - -/* Used to mark functions which have had redundant parts of their - prologue deleted. */ -#define MN10300_DELETED_PROLOGUE_BYTES 0x2 - unsigned char flags; - - /* Calculated value. */ - bfd_vma value; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_LD 3 -#define GOT_TLS_IE 4 - /* Used to distinguish GOT entries for TLS types from normal GOT entries. */ - unsigned char tls_type; -}; - -/* We derive a hash table from the main elf linker hash table so - we can store state variables and a secondary hash table without - resorting to global variables. */ -struct elf32_mn10300_link_hash_table -{ - /* The main hash table. */ - struct elf_link_hash_table root; - - /* A hash table for static functions. We could derive a new hash table - instead of using the full elf32_mn10300_link_hash_table if we wanted - to save some memory. */ - struct elf32_mn10300_link_hash_table *static_hash_table; - - /* Random linker state flags. */ -#define MN10300_HASH_ENTRIES_INITIALIZED 0x1 - char flags; - struct - { - bfd_signed_vma refcount; - bfd_vma offset; - char got_allocated; - char rel_emitted; - } tls_ldm_got; -}; - -#define elf_mn10300_hash_entry(ent) ((struct elf32_mn10300_link_hash_entry *)(ent)) - -struct elf_mn10300_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char * local_got_tls_type; -}; - -#define elf_mn10300_tdata(abfd) \ - ((struct elf_mn10300_obj_tdata *) (abfd)->tdata.any) - -#define elf_mn10300_local_got_tls_type(abfd) \ - (elf_mn10300_tdata (abfd)->local_got_tls_type) - -#ifndef streq -#define streq(a, b) (strcmp ((a),(b)) == 0) -#endif - -/* For MN10300 linker hash table. */ - -/* Get the MN10300 ELF linker hash table from a link_info structure. */ - -#define elf32_mn10300_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == MN10300_ELF_DATA ? ((struct elf32_mn10300_link_hash_table *) ((p)->hash)) : NULL) - -#define elf32_mn10300_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -static reloc_howto_type elf_mn10300_howto_table[] = -{ - /* Dummy relocation. Does nothing. */ - HOWTO (R_MN10300_NONE, - 0, - 3, - 0, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_MN10300_NONE", - FALSE, - 0, - 0, - FALSE), - /* Standard 32 bit reloc. */ - HOWTO (R_MN10300_32, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_32", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - /* Standard 16 bit reloc. */ - HOWTO (R_MN10300_16, - 0, - 1, - 16, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_16", - FALSE, - 0xffff, - 0xffff, - FALSE), - /* Standard 8 bit reloc. */ - HOWTO (R_MN10300_8, - 0, - 0, - 8, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_8", - FALSE, - 0xff, - 0xff, - FALSE), - /* Standard 32bit pc-relative reloc. */ - HOWTO (R_MN10300_PCREL32, - 0, - 2, - 32, - TRUE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_PCREL32", - FALSE, - 0xffffffff, - 0xffffffff, - TRUE), - /* Standard 16bit pc-relative reloc. */ - HOWTO (R_MN10300_PCREL16, - 0, - 1, - 16, - TRUE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_PCREL16", - FALSE, - 0xffff, - 0xffff, - TRUE), - /* Standard 8 pc-relative reloc. */ - HOWTO (R_MN10300_PCREL8, - 0, - 0, - 8, - TRUE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_PCREL8", - FALSE, - 0xff, - 0xff, - TRUE), - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_MN10300_GNU_VTINHERIT, /* 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 */ - "R_MN10300_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_MN10300_GNU_VTENTRY, /* 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 */ - "R_MN10300_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Standard 24 bit reloc. */ - HOWTO (R_MN10300_24, - 0, - 2, - 24, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_MN10300_24", - FALSE, - 0xffffff, - 0xffffff, - FALSE), - HOWTO (R_MN10300_GOTPC32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOTPC32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOTPC16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOTPC16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOTOFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOTOFF32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOTOFF24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOTOFF24", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOTOFF16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOTOFF16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_PLT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_PLT32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MN10300_PLT16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_PLT16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOT32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOT24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOT24", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_GOT16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_COPY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_GD", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_LD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_LD", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_LDO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_LDO", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_GOTIE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_GOTIE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_IE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_IE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_LE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_LE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_DTPMOD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_DTPMOD", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_DTPOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_DTPOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_TLS_TPOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_MN10300_TLS_TPOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_SYM_DIFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - NULL, /* special handler. */ - "R_MN10300_SYM_DIFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MN10300_ALIGN, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - NULL, /* special handler. */ - "R_MN10300_ALIGN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -struct mn10300_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct mn10300_reloc_map mn10300_reloc_map[] = -{ - { BFD_RELOC_NONE, R_MN10300_NONE, }, - { BFD_RELOC_32, R_MN10300_32, }, - { BFD_RELOC_16, R_MN10300_16, }, - { BFD_RELOC_8, R_MN10300_8, }, - { BFD_RELOC_32_PCREL, R_MN10300_PCREL32, }, - { BFD_RELOC_16_PCREL, R_MN10300_PCREL16, }, - { BFD_RELOC_8_PCREL, R_MN10300_PCREL8, }, - { BFD_RELOC_24, R_MN10300_24, }, - { BFD_RELOC_VTABLE_INHERIT, R_MN10300_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_MN10300_GNU_VTENTRY }, - { BFD_RELOC_32_GOT_PCREL, R_MN10300_GOTPC32 }, - { BFD_RELOC_16_GOT_PCREL, R_MN10300_GOTPC16 }, - { BFD_RELOC_32_GOTOFF, R_MN10300_GOTOFF32 }, - { BFD_RELOC_MN10300_GOTOFF24, R_MN10300_GOTOFF24 }, - { BFD_RELOC_16_GOTOFF, R_MN10300_GOTOFF16 }, - { BFD_RELOC_32_PLT_PCREL, R_MN10300_PLT32 }, - { BFD_RELOC_16_PLT_PCREL, R_MN10300_PLT16 }, - { BFD_RELOC_MN10300_GOT32, R_MN10300_GOT32 }, - { BFD_RELOC_MN10300_GOT24, R_MN10300_GOT24 }, - { BFD_RELOC_MN10300_GOT16, R_MN10300_GOT16 }, - { BFD_RELOC_MN10300_COPY, R_MN10300_COPY }, - { BFD_RELOC_MN10300_GLOB_DAT, R_MN10300_GLOB_DAT }, - { BFD_RELOC_MN10300_JMP_SLOT, R_MN10300_JMP_SLOT }, - { BFD_RELOC_MN10300_RELATIVE, R_MN10300_RELATIVE }, - { BFD_RELOC_MN10300_TLS_GD, R_MN10300_TLS_GD }, - { BFD_RELOC_MN10300_TLS_LD, R_MN10300_TLS_LD }, - { BFD_RELOC_MN10300_TLS_LDO, R_MN10300_TLS_LDO }, - { BFD_RELOC_MN10300_TLS_GOTIE, R_MN10300_TLS_GOTIE }, - { BFD_RELOC_MN10300_TLS_IE, R_MN10300_TLS_IE }, - { BFD_RELOC_MN10300_TLS_LE, R_MN10300_TLS_LE }, - { BFD_RELOC_MN10300_TLS_DTPMOD, R_MN10300_TLS_DTPMOD }, - { BFD_RELOC_MN10300_TLS_DTPOFF, R_MN10300_TLS_DTPOFF }, - { BFD_RELOC_MN10300_TLS_TPOFF, R_MN10300_TLS_TPOFF }, - { BFD_RELOC_MN10300_SYM_DIFF, R_MN10300_SYM_DIFF }, - { BFD_RELOC_MN10300_ALIGN, R_MN10300_ALIGN } -}; - -/* Create the GOT section. */ - -static bfd_boolean -_bfd_mn10300_elf_create_got_section (bfd * abfd, - struct bfd_link_info * info) -{ - flagword flags; - flagword pltflags; - asection * s; - struct elf_link_hash_entry * h; - const struct elf_backend_data * bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab; - int ptralign; - - /* This function may be called more than once. */ - htab = elf_hash_table (info); - if (htab->sgot != NULL) - return TRUE; - - switch (bed->s->arch_size) - { - case 32: - ptralign = 2; - break; - - case 64: - ptralign = 3; - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - pltflags = flags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - htab->splt = s; - 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_"); - htab->hplt = h; - if (h == NULL) - return FALSE; - } - - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - htab->sgot = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (bed->want_got_plt) - { - s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); - htab->sgotplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - - /* 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_"); - htab->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; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (mn10300_reloc_map); i--;) - if (mn10300_reloc_map[i].bfd_reloc_val == code) - return &elf_mn10300_howto_table[mn10300_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = ARRAY_SIZE (elf_mn10300_howto_table); i--;) - if (elf_mn10300_howto_table[i].name != NULL - && strcasecmp (elf_mn10300_howto_table[i].name, r_name) == 0) - return elf_mn10300_howto_table + i; - - return NULL; -} - -/* Set the howto pointer for an MN10300 ELF reloc. */ - -static void -mn10300_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_MN10300_MAX) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised MN10300 reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_MN10300_NONE; - } - cache_ptr->howto = elf_mn10300_howto_table + r_type; -} - -static int -elf_mn10300_tls_transition (struct bfd_link_info * info, - int r_type, - struct elf_link_hash_entry * h, - asection * sec, - bfd_boolean counting) -{ - bfd_boolean is_local; - - if (r_type == R_MN10300_TLS_GD - && h != NULL - && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_IE) - return R_MN10300_TLS_GOTIE; - - if (bfd_link_pic (info)) - return r_type; - - if (! (sec->flags & SEC_CODE)) - return r_type; - - if (! counting && h != NULL && ! elf_hash_table (info)->dynamic_sections_created) - is_local = TRUE; - else - is_local = SYMBOL_CALLS_LOCAL (info, h); - - /* For the main program, these are the transitions we do. */ - switch (r_type) - { - case R_MN10300_TLS_GD: return is_local ? R_MN10300_TLS_LE : R_MN10300_TLS_GOTIE; - case R_MN10300_TLS_LD: return R_MN10300_NONE; - case R_MN10300_TLS_LDO: return R_MN10300_TLS_LE; - case R_MN10300_TLS_IE: - case R_MN10300_TLS_GOTIE: return is_local ? R_MN10300_TLS_LE : r_type; - } - - return r_type; -} - -/* Return the relocation value for @tpoff relocation - if STT_TLS virtual address is ADDRESS. */ - -static bfd_vma -dtpoff (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 address - htab->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 address - (htab->tls_size + htab->tls_sec->vma); -} - -/* Returns nonzero if there's a R_MN10300_PLT32 reloc that we now need - to skip, after this one. The actual value is the offset between - this reloc and the PLT reloc. */ - -static int -mn10300_do_tls_transition (bfd * input_bfd, - unsigned int r_type, - unsigned int tls_r_type, - bfd_byte * contents, - bfd_vma offset) -{ - bfd_byte *op = contents + offset; - int gotreg = 0; - -#define TLS_PAIR(r1,r2) ((r1) * R_MN10300_MAX + (r2)) - - /* This is common to all GD/LD transitions, so break it out. */ - if (r_type == R_MN10300_TLS_GD - || r_type == R_MN10300_TLS_LD) - { - op -= 2; - /* mov imm,d0. */ - BFD_ASSERT (bfd_get_8 (input_bfd, op) == 0xFC); - BFD_ASSERT (bfd_get_8 (input_bfd, op + 1) == 0xCC); - /* add aN,d0. */ - BFD_ASSERT (bfd_get_8 (input_bfd, op + 6) == 0xF1); - gotreg = (bfd_get_8 (input_bfd, op + 7) & 0x0c) >> 2; - /* Call. */ - BFD_ASSERT (bfd_get_8 (input_bfd, op + 8) == 0xDD); - } - - switch (TLS_PAIR (r_type, tls_r_type)) - { - case TLS_PAIR (R_MN10300_TLS_GD, R_MN10300_TLS_GOTIE): - { - /* Keep track of which register we put GOTptr in. */ - /* mov (_x@indntpoff,a2),a0. */ - memcpy (op, "\xFC\x20\x00\x00\x00\x00", 6); - op[1] |= gotreg; - /* add e2,a0. */ - memcpy (op+6, "\xF9\x78\x28", 3); - /* or 0x00000000, d0 - six byte nop. */ - memcpy (op+9, "\xFC\xE4\x00\x00\x00\x00", 6); - } - return 7; - - case TLS_PAIR (R_MN10300_TLS_GD, R_MN10300_TLS_LE): - { - /* Register is *always* a0. */ - /* mov _x@tpoff,a0. */ - memcpy (op, "\xFC\xDC\x00\x00\x00\x00", 6); - /* add e2,a0. */ - memcpy (op+6, "\xF9\x78\x28", 3); - /* or 0x00000000, d0 - six byte nop. */ - memcpy (op+9, "\xFC\xE4\x00\x00\x00\x00", 6); - } - return 7; - case TLS_PAIR (R_MN10300_TLS_LD, R_MN10300_NONE): - { - /* Register is *always* a0. */ - /* mov e2,a0. */ - memcpy (op, "\xF5\x88", 2); - /* or 0x00000000, d0 - six byte nop. */ - memcpy (op+2, "\xFC\xE4\x00\x00\x00\x00", 6); - /* or 0x00000000, e2 - seven byte nop. */ - memcpy (op+8, "\xFE\x19\x22\x00\x00\x00\x00", 7); - } - return 7; - - case TLS_PAIR (R_MN10300_TLS_LDO, R_MN10300_TLS_LE): - /* No changes needed, just the reloc change. */ - return 0; - - /* These are a little tricky, because we have to detect which - opcode is being used (they're different sizes, with the reloc - at different offsets within the opcode) and convert each - accordingly, copying the operands as needed. The conversions - we do are as follows (IE,GOTIE,LE): - - 1111 1100 1010 01Dn [-- abs32 --] MOV (x@indntpoff),Dn - 1111 1100 0000 DnAm [-- abs32 --] MOV (x@gotntpoff,Am),Dn - 1111 1100 1100 11Dn [-- abs32 --] MOV x@tpoff,Dn - - 1111 1100 1010 00An [-- abs32 --] MOV (x@indntpoff),An - 1111 1100 0010 AnAm [-- abs32 --] MOV (x@gotntpoff,Am),An - 1111 1100 1101 11An [-- abs32 --] MOV x@tpoff,An - - 1111 1110 0000 1110 Rnnn Xxxx [-- abs32 --] MOV (x@indntpoff),Rn - 1111 1110 0000 1010 Rnnn Rmmm [-- abs32 --] MOV (x@indntpoff,Rm),Rn - 1111 1110 0000 1000 Rnnn Xxxx [-- abs32 --] MOV x@tpoff,Rn - - Since the GOT pointer is always $a2, we assume the last - normally won't happen, but let's be paranoid and plan for the - day that GCC optimizes it somewhow. */ - - case TLS_PAIR (R_MN10300_TLS_IE, R_MN10300_TLS_LE): - if (op[-2] == 0xFC) - { - op -= 2; - if ((op[1] & 0xFC) == 0xA4) /* Dn */ - { - op[1] &= 0x03; /* Leaves Dn. */ - op[1] |= 0xCC; - } - else /* An */ - { - op[1] &= 0x03; /* Leaves An. */ - op[1] |= 0xDC; - } - } - else if (op[-3] == 0xFE) - op[-2] = 0x08; - else - abort (); - break; - - case TLS_PAIR (R_MN10300_TLS_GOTIE, R_MN10300_TLS_LE): - if (op[-2] == 0xFC) - { - op -= 2; - if ((op[1] & 0xF0) == 0x00) /* Dn */ - { - op[1] &= 0x0C; /* Leaves Dn. */ - op[1] >>= 2; - op[1] |= 0xCC; - } - else /* An */ - { - op[1] &= 0x0C; /* Leaves An. */ - op[1] >>= 2; - op[1] |= 0xDC; - } - } - else if (op[-3] == 0xFE) - op[-2] = 0x08; - else - abort (); - break; - - default: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Unsupported transition from %s to %s"), - input_bfd, - elf_mn10300_howto_table[r_type].name, - elf_mn10300_howto_table[tls_r_type].name); - break; - } -#undef TLS_PAIR - return 0; -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -mn10300_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf32_mn10300_link_hash_table * htab = elf32_mn10300_hash_table (info); - bfd_boolean sym_diff_reloc_seen; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym * isymbuf = NULL; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd * dynobj; - bfd_vma * local_got_offsets; - asection * sgot; - asection * srelgot; - asection * sreloc; - bfd_boolean result = FALSE; - - sgot = NULL; - srelgot = NULL; - sreloc = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - sym_hashes = elf_sym_hashes (abfd); - - dynobj = elf_hash_table (info)->dynobj; - local_got_offsets = elf_local_got_offsets (abfd); - rel_end = relocs + sec->reloc_count; - sym_diff_reloc_seen = FALSE; - - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - unsigned int r_type; - int tls_type = GOT_NORMAL; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - r_type = ELF32_R_TYPE (rel->r_info); - r_type = elf_mn10300_tls_transition (info, r_type, h, sec, TRUE); - - /* Some relocs require a global offset table. */ - if (dynobj == NULL) - { - switch (r_type) - { - case R_MN10300_GOT32: - case R_MN10300_GOT24: - case R_MN10300_GOT16: - case R_MN10300_GOTOFF32: - case R_MN10300_GOTOFF24: - case R_MN10300_GOTOFF16: - case R_MN10300_GOTPC32: - case R_MN10300_GOTPC16: - case R_MN10300_TLS_GD: - case R_MN10300_TLS_LD: - case R_MN10300_TLS_GOTIE: - case R_MN10300_TLS_IE: - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! _bfd_mn10300_elf_create_got_section (dynobj, info)) - goto fail; - break; - - default: - break; - } - } - - switch (r_type) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_MN10300_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - goto fail; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_MN10300_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - goto fail; - break; - - case R_MN10300_TLS_LD: - htab->tls_ldm_got.refcount ++; - tls_type = GOT_TLS_LD; - - if (htab->tls_ldm_got.got_allocated) - break; - goto create_got; - - case R_MN10300_TLS_IE: - case R_MN10300_TLS_GOTIE: - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - /* Fall through */ - - case R_MN10300_TLS_GD: - case R_MN10300_GOT32: - case R_MN10300_GOT24: - case R_MN10300_GOT16: - create_got: - /* This symbol requires a global offset table entry. */ - - switch (r_type) - { - case R_MN10300_TLS_IE: - case R_MN10300_TLS_GOTIE: tls_type = GOT_TLS_IE; break; - case R_MN10300_TLS_GD: tls_type = GOT_TLS_GD; break; - default: tls_type = GOT_NORMAL; break; - } - - sgot = htab->root.sgot; - srelgot = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srelgot != NULL); - - if (r_type == R_MN10300_TLS_LD) - { - htab->tls_ldm_got.offset = sgot->size; - htab->tls_ldm_got.got_allocated ++; - } - else if (h != NULL) - { - if (elf_mn10300_hash_entry (h)->tls_type != tls_type - && elf_mn10300_hash_entry (h)->tls_type != GOT_UNKNOWN) - { - if (tls_type == GOT_TLS_IE - && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_GD) - /* No change - this is ok. */; - else if (tls_type == GOT_TLS_GD - && elf_mn10300_hash_entry (h)->tls_type == GOT_TLS_IE) - /* Transition GD->IE. */ - tls_type = GOT_TLS_IE; - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %s' accessed both as normal and thread local symbol"), - abfd, h ? h->root.root.string : ""); - } - - elf_mn10300_hash_entry (h)->tls_type = tls_type; - - if (h->got.offset != (bfd_vma) -1) - /* We have already allocated space in the .got. */ - break; - - h->got.offset = sgot->size; - - if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL - /* Make sure this symbol is output as a dynamic symbol. */ - && h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - goto fail; - } - - srelgot->size += sizeof (Elf32_External_Rela); - if (r_type == R_MN10300_TLS_GD) - srelgot->size += sizeof (Elf32_External_Rela); - } - else - { - /* This is a global offset table entry for a local - symbol. */ - if (local_got_offsets == NULL) - { - size_t size; - unsigned int i; - - size = symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (char)); - local_got_offsets = bfd_alloc (abfd, size); - - if (local_got_offsets == NULL) - goto fail; - - elf_local_got_offsets (abfd) = local_got_offsets; - elf_mn10300_local_got_tls_type (abfd) - = (char *) (local_got_offsets + symtab_hdr->sh_info); - - for (i = 0; i < symtab_hdr->sh_info; i++) - local_got_offsets[i] = (bfd_vma) -1; - } - - if (local_got_offsets[r_symndx] != (bfd_vma) -1) - /* We have already allocated space in the .got. */ - break; - - local_got_offsets[r_symndx] = sgot->size; - - if (bfd_link_pic (info)) - { - /* If we are generating a shared object, we need to - output a R_MN10300_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. */ - srelgot->size += sizeof (Elf32_External_Rela); - - if (r_type == R_MN10300_TLS_GD) - /* And a R_MN10300_TLS_DTPOFF reloc as well. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - - elf_mn10300_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - - sgot->size += 4; - if (r_type == R_MN10300_TLS_GD - || r_type == R_MN10300_TLS_LD) - sgot->size += 4; - - goto need_shared_relocs; - - case R_MN10300_PLT32: - case R_MN10300_PLT16: - /* 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; - - if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) - break; - - h->needs_plt = 1; - break; - - case R_MN10300_24: - case R_MN10300_16: - case R_MN10300_8: - case R_MN10300_PCREL32: - case R_MN10300_PCREL16: - case R_MN10300_PCREL8: - if (h != NULL) - h->non_got_ref = 1; - break; - - case R_MN10300_SYM_DIFF: - sym_diff_reloc_seen = TRUE; - break; - - case R_MN10300_32: - if (h != NULL) - h->non_got_ref = 1; - - need_shared_relocs: - /* If we are creating a shared library, then we - need to copy the reloc into the shared library. */ - if (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - /* Do not generate a dynamic reloc for a - reloc associated with a SYM_DIFF operation. */ - && ! sym_diff_reloc_seen) - { - asection * sym_section = NULL; - - /* Find the section containing the - symbol involved in the relocation. */ - if (h == NULL) - { - Elf_Internal_Sym * isym; - - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf) - { - isym = isymbuf + r_symndx; - /* All we care about is whether this local symbol is absolute. */ - if (isym->st_shndx == SHN_ABS) - sym_section = bfd_abs_section_ptr; - } - } - else - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - sym_section = h->root.u.def.section; - } - - /* If the symbol is absolute then the relocation can - be resolved during linking and there is no need for - a dynamic reloc. */ - if (sym_section != bfd_abs_section_ptr) - { - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - if (sreloc == NULL) - goto fail; - } - - sreloc->size += sizeof (Elf32_External_Rela); - } - } - - break; - } - - if (ELF32_R_TYPE (rel->r_info) != R_MN10300_SYM_DIFF) - sym_diff_reloc_seen = FALSE; - } - - result = TRUE; - fail: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - - return result; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -mn10300_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_MN10300_GNU_VTINHERIT: - case R_MN10300_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -mn10300_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd_byte *contents, - bfd_vma offset, - bfd_vma value, - bfd_vma addend, - struct elf_link_hash_entry * h, - unsigned long symndx, - struct bfd_link_info *info, - asection *sym_sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - struct elf32_mn10300_link_hash_table * htab = elf32_mn10300_hash_table (info); - static asection * sym_diff_section; - static bfd_vma sym_diff_value; - bfd_boolean is_sym_diff_reloc; - unsigned long r_type = howto->type; - bfd_byte * hit_data = contents + offset; - bfd * dynobj; - asection * sgot; - asection * splt; - asection * sreloc; - - dynobj = elf_hash_table (info)->dynobj; - sgot = NULL; - splt = NULL; - sreloc = NULL; - - switch (r_type) - { - case R_MN10300_24: - case R_MN10300_16: - case R_MN10300_8: - case R_MN10300_PCREL8: - case R_MN10300_PCREL16: - case R_MN10300_PCREL32: - case R_MN10300_GOTOFF32: - case R_MN10300_GOTOFF24: - case R_MN10300_GOTOFF16: - if (bfd_link_pic (info) - && (input_section->flags & SEC_ALLOC) != 0 - && h != NULL - && ! SYMBOL_REFERENCES_LOCAL (info, h)) - return bfd_reloc_dangerous; - /* Fall through. */ - case R_MN10300_GOT32: - /* Issue 2052223: - Taking the address of a protected function in a shared library - is illegal. Issue an error message here. */ - if (bfd_link_pic (info) - && (input_section->flags & SEC_ALLOC) != 0 - && h != NULL - && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED - && (h->type == STT_FUNC || h->type == STT_GNU_IFUNC) - && ! SYMBOL_REFERENCES_LOCAL (info, h)) - return bfd_reloc_dangerous; - } - - is_sym_diff_reloc = FALSE; - if (sym_diff_section != NULL) - { - BFD_ASSERT (sym_diff_section == input_section); - - switch (r_type) - { - case R_MN10300_32: - case R_MN10300_24: - case R_MN10300_16: - case R_MN10300_8: - value -= sym_diff_value; - /* If we are computing a 32-bit value for the location lists - and the result is 0 then we add one to the value. A zero - value can result because of linker relaxation deleteing - prologue instructions and using a value of 1 (for the begin - and end offsets in the location list entry) results in a - nul entry which does not prevent the following entries from - being parsed. */ - if (r_type == R_MN10300_32 - && value == 0 - && strcmp (input_section->name, ".debug_loc") == 0) - value = 1; - sym_diff_section = NULL; - is_sym_diff_reloc = TRUE; - break; - - default: - sym_diff_section = NULL; - break; - } - } - - switch (r_type) - { - case R_MN10300_SYM_DIFF: - BFD_ASSERT (addend == 0); - /* Cache the input section and value. - The offset is unreliable, since relaxation may - have reduced the following reloc's offset. */ - sym_diff_section = input_section; - sym_diff_value = value; - return bfd_reloc_ok; - - case R_MN10300_ALIGN: - case R_MN10300_NONE: - return bfd_reloc_ok; - - case R_MN10300_32: - if (bfd_link_pic (info) - /* Do not generate relocs when an R_MN10300_32 has been used - with an R_MN10300_SYM_DIFF to compute a difference of two - symbols. */ - && !is_sym_diff_reloc - /* Also, do not generate a reloc when the symbol associated - with the R_MN10300_32 reloc is absolute - there is no - need for a run time computation in this case. */ - && sym_sec != bfd_abs_section_ptr - /* If the section is not going to be allocated at load time - then there is no need to generate relocs for it. */ - && (input_section->flags & SEC_ALLOC) != 0) - { - Elf_Internal_Rela outrel; - bfd_boolean skip, relocate; - - /* When generating a shared object, these relocations are - copied into the output file to be resolved at run - time. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - skip = FALSE; - - outrel.r_offset = _bfd_elf_section_offset (input_bfd, info, - input_section, offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - { - memset (&outrel, 0, sizeof outrel); - relocate = FALSE; - } - else - { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (h == NULL - || SYMBOL_REFERENCES_LOCAL (info, h)) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); - outrel.r_addend = value + addend; - } - else - { - BFD_ASSERT (h->dynindx != -1); - relocate = FALSE; - outrel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_32); - outrel.r_addend = value + addend; - } - } - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - (bfd_byte *) (((Elf32_External_Rela *) sreloc->contents) - + sreloc->reloc_count)); - ++sreloc->reloc_count; - - /* If this reloc is against an external symbol, we do - not want to fiddle with the addend. Otherwise, we - need to include the symbol value so that it becomes - an addend for the dynamic reloc. */ - if (! relocate) - return bfd_reloc_ok; - } - value += addend; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_24: - value += addend; - - if ((long) value > 0x7fffff || (long) value < -0x800000) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value & 0xff, hit_data); - bfd_put_8 (input_bfd, (value >> 8) & 0xff, hit_data + 1); - bfd_put_8 (input_bfd, (value >> 16) & 0xff, hit_data + 2); - return bfd_reloc_ok; - - case R_MN10300_16: - value += addend; - - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_8: - value += addend; - - if ((long) value > 0x7f || (long) value < -0x80) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_PCREL8: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - if ((long) value > 0x7f || (long) value < -0x80) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_PCREL16: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_PCREL32: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_GNU_VTINHERIT: - case R_MN10300_GNU_VTENTRY: - return bfd_reloc_ok; - - case R_MN10300_GOTPC32: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - /* Use global offset table as symbol value. */ - value = htab->root.sgot->output_section->vma; - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_GOTPC16: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - /* Use global offset table as symbol value. */ - value = htab->root.sgot->output_section->vma; - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_GOTOFF32: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - value -= htab->root.sgot->output_section->vma; - value += addend; - - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_GOTOFF24: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - value -= htab->root.sgot->output_section->vma; - value += addend; - - if ((long) value > 0x7fffff || (long) value < -0x800000) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value, hit_data); - bfd_put_8 (input_bfd, (value >> 8) & 0xff, hit_data + 1); - bfd_put_8 (input_bfd, (value >> 16) & 0xff, hit_data + 2); - return bfd_reloc_ok; - - case R_MN10300_GOTOFF16: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - value -= htab->root.sgot->output_section->vma; - value += addend; - - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_PLT32: - if (h != NULL - && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL - && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN - && h->plt.offset != (bfd_vma) -1) - { - if (dynobj == NULL) - return bfd_reloc_dangerous; - - splt = htab->root.splt; - value = (splt->output_section->vma - + splt->output_offset - + h->plt.offset) - value; - } - - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_PLT16: - if (h != NULL - && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL - && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN - && h->plt.offset != (bfd_vma) -1) - { - if (dynobj == NULL) - return bfd_reloc_dangerous; - - splt = htab->root.splt; - value = (splt->output_section->vma - + splt->output_offset - + h->plt.offset) - value; - } - - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_MN10300_TLS_LDO: - value = dtpoff (info, value); - bfd_put_32 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_MN10300_TLS_LE: - value = tpoff (info, value); - bfd_put_32 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_MN10300_TLS_LD: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - sgot = htab->root.sgot; - BFD_ASSERT (sgot != NULL); - value = htab->tls_ldm_got.offset + sgot->output_offset; - bfd_put_32 (input_bfd, value, hit_data); - - if (!htab->tls_ldm_got.rel_emitted) - { - asection *srelgot = htab->root.srelgot; - Elf_Internal_Rela rel; - - BFD_ASSERT (srelgot != NULL); - htab->tls_ldm_got.rel_emitted ++; - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + htab->tls_ldm_got.offset); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + htab->tls_ldm_got.offset); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + htab->tls_ldm_got.offset+4); - rel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPMOD); - rel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, & rel, - (bfd_byte *) ((Elf32_External_Rela *) srelgot->contents - + srelgot->reloc_count)); - ++ srelgot->reloc_count; - } - - return bfd_reloc_ok; - - case R_MN10300_TLS_GOTIE: - value = tpoff (info, value); - /* Fall Through. */ - - case R_MN10300_TLS_GD: - case R_MN10300_TLS_IE: - case R_MN10300_GOT32: - case R_MN10300_GOT24: - case R_MN10300_GOT16: - if (dynobj == NULL) - return bfd_reloc_dangerous; - - sgot = htab->root.sgot; - if (r_type == R_MN10300_TLS_GD) - value = dtpoff (info, value); - - if (h != NULL) - { - bfd_vma off; - - off = h->got.offset; - /* Offsets in the GOT are allocated in check_relocs - which is not called for shared libraries... */ - if (off == (bfd_vma) -1) - off = 0; - - if (sgot->contents != NULL - && (! elf_hash_table (info)->dynamic_sections_created - || SYMBOL_REFERENCES_LOCAL (info, h))) - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. - - 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. */ - bfd_put_32 (output_bfd, value, - sgot->contents + off); - - value = sgot->output_offset + off; - } - else - { - bfd_vma off; - - off = elf_local_got_offsets (input_bfd)[symndx]; - - if (off & 1) - bfd_put_32 (output_bfd, value, sgot->contents + (off & ~ 1)); - else - { - bfd_put_32 (output_bfd, value, sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *srelgot = htab->root.srelgot;; - Elf_Internal_Rela outrel; - - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - switch (r_type) - { - case R_MN10300_TLS_GD: - outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPOFF); - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off + 4); - bfd_elf32_swap_reloca_out (output_bfd, & outrel, - (bfd_byte *) (((Elf32_External_Rela *) - srelgot->contents) - + srelgot->reloc_count)); - ++ srelgot->reloc_count; - outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_DTPMOD); - break; - case R_MN10300_TLS_GOTIE: - case R_MN10300_TLS_IE: - outrel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_TPOFF); - break; - default: - outrel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); - break; - } - - outrel.r_addend = value; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - (bfd_byte *) (((Elf32_External_Rela *) - srelgot->contents) - + srelgot->reloc_count)); - ++ srelgot->reloc_count; - elf_local_got_offsets (input_bfd)[symndx] |= 1; - } - - value = sgot->output_offset + (off & ~(bfd_vma) 1); - } - } - - value += addend; - - if (r_type == R_MN10300_TLS_IE) - { - value += sgot->output_section->vma; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - else if (r_type == R_MN10300_TLS_GOTIE - || r_type == R_MN10300_TLS_GD - || r_type == R_MN10300_TLS_LD) - { - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - else if (r_type == R_MN10300_GOT32) - { - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - else if (r_type == R_MN10300_GOT24) - { - if ((long) value > 0x7fffff || (long) value < -0x800000) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value & 0xff, hit_data); - bfd_put_8 (input_bfd, (value >> 8) & 0xff, hit_data + 1); - bfd_put_8 (input_bfd, (value >> 16) & 0xff, hit_data + 2); - return bfd_reloc_ok; - } - else if (r_type == R_MN10300_GOT16) - { - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - /* Fall through. */ - - default: - return bfd_reloc_notsupported; - } -} - -/* Relocate an MN10300 ELF section. */ - -static bfd_boolean -mn10300_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - Elf_Internal_Rela * trel; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf32_mn10300_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - int tls_r_type; - bfd_boolean unresolved_reloc = FALSE; - bfd_boolean warned, ignored; - struct elf_link_hash_entry * hh; - - relocation = 0; - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - howto = elf_mn10300_howto_table + r_type; - - /* Just skip the vtable gc relocs. */ - if (r_type == R_MN10300_GNU_VTINHERIT - || r_type == R_MN10300_GNU_VTENTRY) - continue; - - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - hh = NULL; - else - { - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - hh, sec, relocation, - unresolved_reloc, warned, ignored); - } - h = elf_mn10300_hash_entry (hh); - - tls_r_type = elf_mn10300_tls_transition (info, r_type, hh, input_section, 0); - if (tls_r_type != r_type) - { - bfd_boolean had_plt; - - had_plt = mn10300_do_tls_transition (input_bfd, r_type, tls_r_type, - contents, rel->r_offset); - r_type = tls_r_type; - howto = elf_mn10300_howto_table + r_type; - - if (had_plt) - for (trel = rel+1; trel < relend; trel++) - if ((ELF32_R_TYPE (trel->r_info) == R_MN10300_PLT32 - || ELF32_R_TYPE (trel->r_info) == R_MN10300_PCREL32) - && rel->r_offset + had_plt == trel->r_offset) - trel->r_info = ELF32_R_INFO (0, R_MN10300_NONE); - } - - 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 - { - if ((h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - && ( r_type == R_MN10300_GOTPC32 - || r_type == R_MN10300_GOTPC16 - || (( r_type == R_MN10300_PLT32 - || r_type == R_MN10300_PLT16) - && ELF_ST_VISIBILITY (h->root.other) != STV_INTERNAL - && ELF_ST_VISIBILITY (h->root.other) != STV_HIDDEN - && h->root.plt.offset != (bfd_vma) -1) - || (( r_type == R_MN10300_GOT32 - || r_type == R_MN10300_GOT24 - || r_type == R_MN10300_TLS_GD - || r_type == R_MN10300_TLS_LD - || r_type == R_MN10300_TLS_GOTIE - || r_type == R_MN10300_TLS_IE - || r_type == R_MN10300_GOT16) - && elf_hash_table (info)->dynamic_sections_created - && !SYMBOL_REFERENCES_LOCAL (info, hh)) - || (r_type == R_MN10300_32 - /* _32 relocs in executables force _COPY relocs, - such that the address of the symbol ends up - being local. */ - && !bfd_link_executable (info) - && !SYMBOL_REFERENCES_LOCAL (info, hh) - && ((input_section->flags & SEC_ALLOC) != 0 - /* DWARF will emit R_MN10300_32 relocations - in its sections against symbols defined - externally in shared libraries. We can't - do anything with them here. */ - || ((input_section->flags & SEC_DEBUGGING) != 0 - && h->root.def_dynamic))))) - /* In these cases, we don't need the relocation - value. We check specially because in some - obscure cases sec->output_section will be NULL. */ - relocation = 0; - - else if (!bfd_link_relocatable (info) && unresolved_reloc - && _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.root.string); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = mn10300_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - (struct elf_link_hash_entry *) h, - r_symndx, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char *name; - const char *msg = NULL; - - if (h != NULL) - name = h->root.root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root.root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - if (r_type == R_MN10300_PCREL32) - msg = _("error: inappropriate relocation type for shared" - " library (did you forget -fpic?)"); - else if (r_type == R_MN10300_GOT32) - /* xgettext:c-format */ - msg = _("%B: taking the address of protected function" - " '%s' cannot be done when making a shared library"); - else - msg = _("internal error: suspicious relocation type used" - " in shared library"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* Fall through. */ - - common_error: - _bfd_error_handler (msg, input_bfd, name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - } - - return TRUE; -} - -/* Finish initializing one hash table entry. */ - -static bfd_boolean -elf32_mn10300_finish_hash_table_entry (struct bfd_hash_entry *gen_entry, - void * in_args) -{ - struct elf32_mn10300_link_hash_entry *entry; - struct bfd_link_info *link_info = (struct bfd_link_info *) in_args; - unsigned int byte_count = 0; - - entry = (struct elf32_mn10300_link_hash_entry *) gen_entry; - - /* If we already know we want to convert "call" to "calls" for calls - to this symbol, then return now. */ - if (entry->flags == MN10300_CONVERT_CALL_TO_CALLS) - return TRUE; - - /* If there are no named calls to this symbol, or there's nothing we - can move from the function itself into the "call" instruction, - then note that all "call" instructions should be converted into - "calls" instructions and return. If a symbol is available for - dynamic symbol resolution (overridable or overriding), avoid - custom calling conventions. */ - if (entry->direct_calls == 0 - || (entry->stack_size == 0 && entry->movm_args == 0) - || (elf_hash_table (link_info)->dynamic_sections_created - && ELF_ST_VISIBILITY (entry->root.other) != STV_INTERNAL - && ELF_ST_VISIBILITY (entry->root.other) != STV_HIDDEN)) - { - /* Make a note that we should convert "call" instructions to "calls" - instructions for calls to this symbol. */ - entry->flags |= MN10300_CONVERT_CALL_TO_CALLS; - return TRUE; - } - - /* We may be able to move some instructions from the function itself into - the "call" instruction. Count how many bytes we might be able to - eliminate in the function itself. */ - - /* A movm instruction is two bytes. */ - if (entry->movm_args) - byte_count += 2; - - /* Count the insn to allocate stack space too. */ - if (entry->stack_size > 0) - { - if (entry->stack_size <= 128) - byte_count += 3; - else - byte_count += 4; - } - - /* If using "call" will result in larger code, then turn all - the associated "call" instructions into "calls" instructions. */ - if (byte_count < entry->direct_calls) - entry->flags |= MN10300_CONVERT_CALL_TO_CALLS; - - /* This routine never fails. */ - return TRUE; -} - -/* Used to count hash table entries. */ - -static bfd_boolean -elf32_mn10300_count_hash_table_entries (struct bfd_hash_entry *gen_entry ATTRIBUTE_UNUSED, - void * in_args) -{ - int *count = (int *) in_args; - - (*count) ++; - return TRUE; -} - -/* Used to enumerate hash table entries into a linear array. */ - -static bfd_boolean -elf32_mn10300_list_hash_table_entries (struct bfd_hash_entry *gen_entry, - void * in_args) -{ - struct bfd_hash_entry ***ptr = (struct bfd_hash_entry ***) in_args; - - **ptr = gen_entry; - (*ptr) ++; - return TRUE; -} - -/* Used to sort the array created by the above. */ - -static int -sort_by_value (const void *va, const void *vb) -{ - struct elf32_mn10300_link_hash_entry *a - = *(struct elf32_mn10300_link_hash_entry **) va; - struct elf32_mn10300_link_hash_entry *b - = *(struct elf32_mn10300_link_hash_entry **) vb; - - return a->value - b->value; -} - -/* Compute the stack size and movm arguments for the function - referred to by HASH at address ADDR in section with - contents CONTENTS, store the information in the hash table. */ - -static void -compute_function_info (bfd *abfd, - struct elf32_mn10300_link_hash_entry *hash, - bfd_vma addr, - unsigned char *contents) -{ - unsigned char byte1, byte2; - /* We only care about a very small subset of the possible prologue - sequences here. Basically we look for: - - movm [d2,d3,a2,a3],sp (optional) - add ,sp (optional, and only for sizes which fit in an unsigned - 8 bit number) - - If we find anything else, we quit. */ - - /* Look for movm [regs],sp. */ - byte1 = bfd_get_8 (abfd, contents + addr); - byte2 = bfd_get_8 (abfd, contents + addr + 1); - - if (byte1 == 0xcf) - { - hash->movm_args = byte2; - addr += 2; - byte1 = bfd_get_8 (abfd, contents + addr); - byte2 = bfd_get_8 (abfd, contents + addr + 1); - } - - /* Now figure out how much stack space will be allocated by the movm - instruction. We need this kept separate from the function's normal - stack space. */ - if (hash->movm_args) - { - /* Space for d2. */ - if (hash->movm_args & 0x80) - hash->movm_stack_size += 4; - - /* Space for d3. */ - if (hash->movm_args & 0x40) - hash->movm_stack_size += 4; - - /* Space for a2. */ - if (hash->movm_args & 0x20) - hash->movm_stack_size += 4; - - /* Space for a3. */ - if (hash->movm_args & 0x10) - hash->movm_stack_size += 4; - - /* "other" space. d0, d1, a0, a1, mdr, lir, lar, 4 byte pad. */ - if (hash->movm_args & 0x08) - hash->movm_stack_size += 8 * 4; - - if (bfd_get_mach (abfd) == bfd_mach_am33 - || bfd_get_mach (abfd) == bfd_mach_am33_2) - { - /* "exother" space. e0, e1, mdrq, mcrh, mcrl, mcvf */ - if (hash->movm_args & 0x1) - hash->movm_stack_size += 6 * 4; - - /* exreg1 space. e4, e5, e6, e7 */ - if (hash->movm_args & 0x2) - hash->movm_stack_size += 4 * 4; - - /* exreg0 space. e2, e3 */ - if (hash->movm_args & 0x4) - hash->movm_stack_size += 2 * 4; - } - } - - /* Now look for the two stack adjustment variants. */ - if (byte1 == 0xf8 && byte2 == 0xfe) - { - int temp = bfd_get_8 (abfd, contents + addr + 2); - temp = ((temp & 0xff) ^ (~0x7f)) + 0x80; - - hash->stack_size = -temp; - } - else if (byte1 == 0xfa && byte2 == 0xfe) - { - int temp = bfd_get_16 (abfd, contents + addr + 2); - temp = ((temp & 0xffff) ^ (~0x7fff)) + 0x8000; - temp = -temp; - - if (temp < 255) - hash->stack_size = temp; - } - - /* If the total stack to be allocated by the call instruction is more - than 255 bytes, then we can't remove the stack adjustment by using - "call" (we might still be able to remove the "movm" instruction. */ - if (hash->stack_size + hash->movm_stack_size > 255) - hash->stack_size = 0; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -mn10300_elf_relax_delete_bytes (bfd *abfd, - asection *sec, - bfd_vma addr, - int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Rela *irelalign; - bfd_vma toaddr; - Elf_Internal_Sym *isym, *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - irelalign = NULL; - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - if (sec->reloc_count > 0) - { - /* If there is an align reloc at the end of the section ignore it. - GAS creates these relocs for reasons of its own, and they just - serve to keep the section artifically inflated. */ - if (ELF32_R_TYPE ((irelend - 1)->r_info) == (int) R_MN10300_ALIGN) - --irelend; - - /* The deletion must stop at the next ALIGN reloc for an alignment - power larger than, or not a multiple of, the number of bytes we - are deleting. */ - for (; irel < irelend; irel++) - { - int alignment = 1 << irel->r_addend; - - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN - && irel->r_offset > addr - && irel->r_offset < toaddr - && (count < alignment - || alignment % count != 0)) - { - irelalign = irel; - toaddr = irel->r_offset; - break; - } - } - } - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - - /* Adjust the section's size if we are shrinking it, or else - pad the bytes between the end of the shrunken region and - the start of the next region with NOP codes. */ - if (irelalign == NULL) - { - sec->size -= count; - /* Include symbols at the end of the section, but - not at the end of a sub-region of the section. */ - toaddr ++; - } - else - { - int i; - -#define NOP_OPCODE 0xcb - - for (i = 0; i < count; i ++) - bfd_put_8 (abfd, (bfd_vma) NOP_OPCODE, contents + toaddr - count + i); - } - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset < toaddr) - || (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN - && irel->r_offset == toaddr)) - irel->r_offset -= count; - } - - /* Adjust the local symbols in the section, reducing their value - by the number of bytes deleted. Note - symbols within the deleted - region are moved to the address of the start of the region, which - actually means that they will address the byte beyond the end of - the region once the deletion has been completed. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - { - if (isym->st_value < addr + count) - isym->st_value = addr; - else - isym->st_value -= count; - } - /* Adjust the function symbol's size as well. */ - else if (isym->st_shndx == sec_shndx - && ELF_ST_TYPE (isym->st_info) == STT_FUNC - && isym->st_value + isym->st_size > addr - && isym->st_value + isym->st_size < toaddr) - isym->st_size -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - { - if (sym_hash->root.u.def.value < addr + count) - sym_hash->root.u.def.value = addr; - else - sym_hash->root.u.def.value -= count; - } - /* Adjust the function symbol's size as well. */ - else if (sym_hash->root.type == bfd_link_hash_defined - && sym_hash->root.u.def.section == sec - && sym_hash->type == STT_FUNC - && sym_hash->root.u.def.value + sym_hash->size > addr - && sym_hash->root.u.def.value + sym_hash->size < toaddr) - sym_hash->size -= count; - } - - /* See if we can move the ALIGN reloc forward. - We have adjusted r_offset for it already. */ - if (irelalign != NULL) - { - bfd_vma alignto, alignaddr; - - if ((int) irelalign->r_addend > 0) - { - /* This is the old address. */ - alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend); - /* This is where the align points to now. */ - alignaddr = BFD_ALIGN (irelalign->r_offset, - 1 << irelalign->r_addend); - if (alignaddr < alignto) - /* Tail recursion. */ - return mn10300_elf_relax_delete_bytes (abfd, sec, alignaddr, - (int) (alignto - alignaddr)); - } - } - - return TRUE; -} - -/* Return TRUE if a symbol exists at the given address, else return - FALSE. */ - -static bfd_boolean -mn10300_elf_symbol_address_p (bfd *abfd, - asection *sec, - Elf_Internal_Sym *isym, - bfd_vma addr) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* Examine all the symbols. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - if (isym->st_shndx == sec_shndx - && isym->st_value == addr) - return TRUE; - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == addr) - return TRUE; - } - - return FALSE; -} - -/* This function handles relaxing for the mn10300. - - There are quite a few relaxing opportunities available on the mn10300: - - * calls:32 -> calls:16 2 bytes - * call:32 -> call:16 2 bytes - - * call:32 -> calls:32 1 byte - * call:16 -> calls:16 1 byte - * These are done anytime using "calls" would result - in smaller code, or when necessary to preserve the - meaning of the program. - - * call:32 varies - * call:16 - * In some circumstances we can move instructions - from a function prologue into a "call" instruction. - This is only done if the resulting code is no larger - than the original code. - - * jmp:32 -> jmp:16 2 bytes - * jmp:16 -> bra:8 1 byte - - * If the previous instruction is a conditional branch - around the jump/bra, we may be able to reverse its condition - and change its target to the jump's target. The jump/bra - can then be deleted. 2 bytes - - * mov abs32 -> mov abs16 1 or 2 bytes - - * Most instructions which accept imm32 can relax to imm16 1 or 2 bytes - - Most instructions which accept imm16 can relax to imm8 1 or 2 bytes - - * Most instructions which accept d32 can relax to d16 1 or 2 bytes - - Most instructions which accept d16 can relax to d8 1 or 2 bytes - - We don't handle imm16->imm8 or d16->d8 as they're very rare - and somewhat more difficult to support. */ - -static bfd_boolean -mn10300_elf_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - struct elf32_mn10300_link_hash_table *hash_table; - asection *section = sec; - bfd_vma align_gap_adjustment; - - if (bfd_link_relocatable (link_info)) - (*link_info->callbacks->einfo) - (_("%P%F: --relax and -r may not be used together\n")); - - /* Assume nothing changes. */ - *again = FALSE; - - /* We need a pointer to the mn10300 specific hash table. */ - hash_table = elf32_mn10300_hash_table (link_info); - if (hash_table == NULL) - return FALSE; - - /* Initialize fields in each hash table entry the first time through. */ - if ((hash_table->flags & MN10300_HASH_ENTRIES_INITIALIZED) == 0) - { - bfd *input_bfd; - - /* Iterate over all the input bfds. */ - for (input_bfd = link_info->input_bfds; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - /* We're going to need all the symbols for each bfd. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Iterate over each section in this bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - struct elf32_mn10300_link_hash_entry *hash; - asection *sym_sec = NULL; - const char *sym_name; - char *new_name; - - /* If there's nothing to do in this section, skip it. */ - if (! ((section->flags & SEC_RELOC) != 0 - && section->reloc_count != 0)) - continue; - if ((section->flags & SEC_ALLOC) == 0) - continue; - - /* Get cached copy of section contents if it exists. */ - if (elf_section_data (section)->this_hdr.contents != NULL) - contents = elf_section_data (section)->this_hdr.contents; - else if (section->size != 0) - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (input_bfd, section, - &contents)) - goto error_return; - } - else - contents = NULL; - - /* If there aren't any relocs, then there's nothing to do. */ - if ((section->flags & SEC_RELOC) != 0 - && section->reloc_count != 0) - { - /* Get a copy of the native relocations. */ - internal_relocs = _bfd_elf_link_read_relocs (input_bfd, section, - NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Now examine each relocation. */ - irel = internal_relocs; - irelend = irel + section->reloc_count; - for (; irel < irelend; irel++) - { - long r_type; - unsigned long r_index; - unsigned char code; - - r_type = ELF32_R_TYPE (irel->r_info); - r_index = ELF32_R_SYM (irel->r_info); - - if (r_type < 0 || r_type >= (int) R_MN10300_MAX) - goto error_return; - - /* We need the name and hash table entry of the target - symbol! */ - hash = NULL; - sym_sec = NULL; - - if (r_index < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - struct elf_link_hash_table *elftab; - bfd_size_type amt; - - isym = isymbuf + r_index; - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec - = bfd_section_from_elf_index (input_bfd, - isym->st_shndx); - - sym_name - = bfd_elf_string_from_elf_section (input_bfd, - (symtab_hdr - ->sh_link), - isym->st_name); - - /* If it isn't a function, then we don't care - about it. */ - if (ELF_ST_TYPE (isym->st_info) != STT_FUNC) - continue; - - /* Tack on an ID so we can uniquely identify this - local symbol in the global hash table. */ - amt = strlen (sym_name) + 10; - new_name = bfd_malloc (amt); - if (new_name == NULL) - goto error_return; - - sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); - sym_name = new_name; - - elftab = &hash_table->static_hash_table->root; - hash = ((struct elf32_mn10300_link_hash_entry *) - elf_link_hash_lookup (elftab, sym_name, - TRUE, TRUE, FALSE)); - free (new_name); - } - else - { - r_index -= symtab_hdr->sh_info; - hash = (struct elf32_mn10300_link_hash_entry *) - elf_sym_hashes (input_bfd)[r_index]; - } - - sym_name = hash->root.root.root.string; - if ((section->flags & SEC_CODE) != 0) - { - /* If this is not a "call" instruction, then we - should convert "call" instructions to "calls" - instructions. */ - code = bfd_get_8 (input_bfd, - contents + irel->r_offset - 1); - if (code != 0xdd && code != 0xcd) - hash->flags |= MN10300_CONVERT_CALL_TO_CALLS; - } - - /* If this is a jump/call, then bump the - direct_calls counter. Else force "call" to - "calls" conversions. */ - if (r_type == R_MN10300_PCREL32 - || r_type == R_MN10300_PLT32 - || r_type == R_MN10300_PLT16 - || r_type == R_MN10300_PCREL16) - hash->direct_calls++; - else - hash->flags |= MN10300_CONVERT_CALL_TO_CALLS; - } - } - - /* Now look at the actual contents to get the stack size, - and a list of what registers were saved in the prologue - (ie movm_args). */ - if ((section->flags & SEC_CODE) != 0) - { - Elf_Internal_Sym *isym, *isymend; - unsigned int sec_shndx; - struct elf_link_hash_entry **hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (input_bfd, - section); - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - hashes = elf_sym_hashes (input_bfd); - end_hashes = hashes + symcount; - - /* Look at each function defined in this section and - update info for that function. */ - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && ELF_ST_TYPE (isym->st_info) == STT_FUNC) - { - struct elf_link_hash_table *elftab; - bfd_size_type amt; - struct elf_link_hash_entry **lhashes = hashes; - - /* Skip a local symbol if it aliases a - global one. */ - for (; lhashes < end_hashes; lhashes++) - { - hash = (struct elf32_mn10300_link_hash_entry *) *lhashes; - if ((hash->root.root.type == bfd_link_hash_defined - || hash->root.root.type == bfd_link_hash_defweak) - && hash->root.root.u.def.section == section - && hash->root.type == STT_FUNC - && hash->root.root.u.def.value == isym->st_value) - break; - } - if (lhashes != end_hashes) - continue; - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec - = bfd_section_from_elf_index (input_bfd, - isym->st_shndx); - - sym_name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, - isym->st_name)); - - /* Tack on an ID so we can uniquely identify this - local symbol in the global hash table. */ - amt = strlen (sym_name) + 10; - new_name = bfd_malloc (amt); - if (new_name == NULL) - goto error_return; - - sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); - sym_name = new_name; - - elftab = &hash_table->static_hash_table->root; - hash = ((struct elf32_mn10300_link_hash_entry *) - elf_link_hash_lookup (elftab, sym_name, - TRUE, TRUE, FALSE)); - free (new_name); - compute_function_info (input_bfd, hash, - isym->st_value, contents); - hash->value = isym->st_value; - } - } - - for (; hashes < end_hashes; hashes++) - { - hash = (struct elf32_mn10300_link_hash_entry *) *hashes; - if ((hash->root.root.type == bfd_link_hash_defined - || hash->root.root.type == bfd_link_hash_defweak) - && hash->root.root.u.def.section == section - && hash->root.type == STT_FUNC) - compute_function_info (input_bfd, hash, - (hash)->root.root.u.def.value, - contents); - } - } - - /* Cache or free any memory we allocated for the relocs. */ - if (internal_relocs != NULL - && elf_section_data (section)->relocs != internal_relocs) - free (internal_relocs); - internal_relocs = NULL; - - /* Cache or free any memory we allocated for the contents. */ - if (contents != NULL - && elf_section_data (section)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (section)->this_hdr.contents = contents; - } - } - contents = NULL; - } - - /* Cache or free any memory we allocated for the symbols. */ - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - isymbuf = NULL; - } - - /* Now iterate on each symbol in the hash table and perform - the final initialization steps on each. */ - elf32_mn10300_link_hash_traverse (hash_table, - elf32_mn10300_finish_hash_table_entry, - link_info); - elf32_mn10300_link_hash_traverse (hash_table->static_hash_table, - elf32_mn10300_finish_hash_table_entry, - link_info); - - { - /* This section of code collects all our local symbols, sorts - them by value, and looks for multiple symbols referring to - the same address. For those symbols, the flags are merged. - At this point, the only flag that can be set is - MN10300_CONVERT_CALL_TO_CALLS, so we simply OR the flags - together. */ - int static_count = 0, i; - struct elf32_mn10300_link_hash_entry **entries; - struct elf32_mn10300_link_hash_entry **ptr; - - elf32_mn10300_link_hash_traverse (hash_table->static_hash_table, - elf32_mn10300_count_hash_table_entries, - &static_count); - - entries = bfd_malloc (static_count * sizeof (* ptr)); - - ptr = entries; - elf32_mn10300_link_hash_traverse (hash_table->static_hash_table, - elf32_mn10300_list_hash_table_entries, - & ptr); - - qsort (entries, static_count, sizeof (entries[0]), sort_by_value); - - for (i = 0; i < static_count - 1; i++) - if (entries[i]->value && entries[i]->value == entries[i+1]->value) - { - int v = entries[i]->flags; - int j; - - for (j = i + 1; j < static_count && entries[j]->value == entries[i]->value; j++) - v |= entries[j]->flags; - - for (j = i; j < static_count && entries[j]->value == entries[i]->value; j++) - entries[j]->flags = v; - - i = j - 1; - } - } - - /* All entries in the hash table are fully initialized. */ - hash_table->flags |= MN10300_HASH_ENTRIES_INITIALIZED; - - /* Now that everything has been initialized, go through each - code section and delete any prologue insns which will be - redundant because their operations will be performed by - a "call" instruction. */ - for (input_bfd = link_info->input_bfds; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - /* We're going to need all the local symbols for each bfd. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Walk over each section in this bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - unsigned int sec_shndx; - Elf_Internal_Sym *isym, *isymend; - struct elf_link_hash_entry **hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - /* Skip non-code sections and empty sections. */ - if ((section->flags & SEC_CODE) == 0 || section->size == 0) - continue; - - if (section->reloc_count != 0) - { - /* Get a copy of the native relocations. */ - internal_relocs = _bfd_elf_link_read_relocs (input_bfd, section, - NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - } - - /* Get cached copy of section contents if it exists. */ - if (elf_section_data (section)->this_hdr.contents != NULL) - contents = elf_section_data (section)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (input_bfd, section, - &contents)) - goto error_return; - } - - sec_shndx = _bfd_elf_section_from_bfd_section (input_bfd, - section); - - /* Now look for any function in this section which needs - insns deleted from its prologue. */ - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf; isym < isymend; isym++) - { - struct elf32_mn10300_link_hash_entry *sym_hash; - asection *sym_sec = NULL; - const char *sym_name; - char *new_name; - struct elf_link_hash_table *elftab; - bfd_size_type amt; - - if (isym->st_shndx != sec_shndx) - continue; - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec - = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - sym_name - = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - isym->st_name); - - /* Tack on an ID so we can uniquely identify this - local symbol in the global hash table. */ - amt = strlen (sym_name) + 10; - new_name = bfd_malloc (amt); - if (new_name == NULL) - goto error_return; - sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); - sym_name = new_name; - - elftab = & hash_table->static_hash_table->root; - sym_hash = (struct elf32_mn10300_link_hash_entry *) - elf_link_hash_lookup (elftab, sym_name, - FALSE, FALSE, FALSE); - - free (new_name); - if (sym_hash == NULL) - continue; - - if (! (sym_hash->flags & MN10300_CONVERT_CALL_TO_CALLS) - && ! (sym_hash->flags & MN10300_DELETED_PROLOGUE_BYTES)) - { - int bytes = 0; - - /* Note that we've changed things. */ - elf_section_data (section)->relocs = internal_relocs; - elf_section_data (section)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Count how many bytes we're going to delete. */ - if (sym_hash->movm_args) - bytes += 2; - - if (sym_hash->stack_size > 0) - { - if (sym_hash->stack_size <= 128) - bytes += 3; - else - bytes += 4; - } - - /* Note that we've deleted prologue bytes for this - function. */ - sym_hash->flags |= MN10300_DELETED_PROLOGUE_BYTES; - - /* Actually delete the bytes. */ - if (!mn10300_elf_relax_delete_bytes (input_bfd, - section, - isym->st_value, - bytes)) - goto error_return; - - /* Something changed. Not strictly necessary, but - may lead to more relaxing opportunities. */ - *again = TRUE; - } - } - - /* Look for any global functions in this section which - need insns deleted from their prologues. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - hashes = elf_sym_hashes (input_bfd); - end_hashes = hashes + symcount; - for (; hashes < end_hashes; hashes++) - { - struct elf32_mn10300_link_hash_entry *sym_hash; - - sym_hash = (struct elf32_mn10300_link_hash_entry *) *hashes; - if ((sym_hash->root.root.type == bfd_link_hash_defined - || sym_hash->root.root.type == bfd_link_hash_defweak) - && sym_hash->root.root.u.def.section == section - && ! (sym_hash->flags & MN10300_CONVERT_CALL_TO_CALLS) - && ! (sym_hash->flags & MN10300_DELETED_PROLOGUE_BYTES)) - { - int bytes = 0; - bfd_vma symval; - struct elf_link_hash_entry **hh; - - /* Note that we've changed things. */ - elf_section_data (section)->relocs = internal_relocs; - elf_section_data (section)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Count how many bytes we're going to delete. */ - if (sym_hash->movm_args) - bytes += 2; - - if (sym_hash->stack_size > 0) - { - if (sym_hash->stack_size <= 128) - bytes += 3; - else - bytes += 4; - } - - /* Note that we've deleted prologue bytes for this - function. */ - sym_hash->flags |= MN10300_DELETED_PROLOGUE_BYTES; - - /* Actually delete the bytes. */ - symval = sym_hash->root.root.u.def.value; - if (!mn10300_elf_relax_delete_bytes (input_bfd, - section, - symval, - bytes)) - goto error_return; - - /* There may be other C++ functions symbols with the same - address. If so then mark these as having had their - prologue bytes deleted as well. */ - for (hh = elf_sym_hashes (input_bfd); hh < end_hashes; hh++) - { - struct elf32_mn10300_link_hash_entry *h; - - h = (struct elf32_mn10300_link_hash_entry *) * hh; - - if (h != sym_hash - && (h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - && h->root.root.u.def.section == section - && ! (h->flags & MN10300_CONVERT_CALL_TO_CALLS) - && h->root.root.u.def.value == symval - && h->root.type == STT_FUNC) - h->flags |= MN10300_DELETED_PROLOGUE_BYTES; - } - - /* Something changed. Not strictly necessary, but - may lead to more relaxing opportunities. */ - *again = TRUE; - } - } - - /* Cache or free any memory we allocated for the relocs. */ - if (internal_relocs != NULL - && elf_section_data (section)->relocs != internal_relocs) - free (internal_relocs); - internal_relocs = NULL; - - /* Cache or free any memory we allocated for the contents. */ - if (contents != NULL - && elf_section_data (section)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (section)->this_hdr.contents = contents; - } - contents = NULL; - } - - /* Cache or free any memory we allocated for the symbols. */ - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - isymbuf = NULL; - } - } - - /* (Re)initialize for the basic instruction shortening/relaxing pass. */ - contents = NULL; - internal_relocs = NULL; - isymbuf = NULL; - /* For error_return. */ - section = sec; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Scan for worst case alignment gap changes. Note that this logic - is not ideal; what we should do is run this scan for every - opcode/address range and adjust accordingly, but that's - expensive. Worst case is that for an alignment of N bytes, we - move by 2*N-N-1 bytes, assuming we have aligns of 1, 2, 4, 8, etc - all before it. Plus, this still doesn't cover cross-section - jumps with section alignment. */ - irelend = internal_relocs + sec->reloc_count; - align_gap_adjustment = 0; - for (irel = internal_relocs; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_ALIGN) - { - bfd_vma adj = 1 << irel->r_addend; - bfd_vma aend = irel->r_offset; - - aend = BFD_ALIGN (aend, 1 << irel->r_addend); - adj = 2 * adj - adj - 1; - - /* Record the biggest adjustmnet. Skip any alignment at the - end of our section. */ - if (align_gap_adjustment < adj - && aend < sec->output_section->vma + sec->output_offset + sec->size) - align_gap_adjustment = adj; - } - } - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - bfd_signed_vma jump_offset; - asection *sym_sec = NULL; - struct elf32_mn10300_link_hash_entry *h = NULL; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_NONE - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_8 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_MAX) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isym; - const char *sym_name; - char *new_name; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - sym_name = bfd_elf_string_from_elf_section (abfd, - symtab_hdr->sh_link, - isym->st_name); - - if ((sym_sec->flags & SEC_MERGE) - && sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE) - { - symval = isym->st_value; - - /* GAS may reduce relocations against symbols in SEC_MERGE - sections to a relocation against the section symbol when - the original addend was zero. When the reloc is against - a section symbol we should include the addend in the - offset passed to _bfd_merged_section_offset, since the - location of interest is the original symbol. On the - other hand, an access to "sym+addend" where "sym" is not - a section symbol should not include the addend; Such an - access is presumed to be an offset from "sym"; The - location of interest is just "sym". */ - if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) - symval += irel->r_addend; - - symval = _bfd_merged_section_offset (abfd, & sym_sec, - elf_section_data (sym_sec)->sec_info, - symval); - - if (ELF_ST_TYPE (isym->st_info) != STT_SECTION) - symval += irel->r_addend; - - symval += sym_sec->output_section->vma - + sym_sec->output_offset - irel->r_addend; - } - else - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - - /* Tack on an ID so we can uniquely identify this - local symbol in the global hash table. */ - new_name = bfd_malloc ((bfd_size_type) strlen (sym_name) + 10); - if (new_name == NULL) - goto error_return; - sprintf (new_name, "%s_%08x", sym_name, sym_sec->id); - sym_name = new_name; - - h = (struct elf32_mn10300_link_hash_entry *) - elf_link_hash_lookup (&hash_table->static_hash_table->root, - sym_name, FALSE, FALSE, FALSE); - free (new_name); - } - else - { - unsigned long indx; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = (struct elf32_mn10300_link_hash_entry *) - (elf_sym_hashes (abfd)[indx]); - BFD_ASSERT (h != NULL); - if (h->root.root.type != bfd_link_hash_defined - && h->root.root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - /* Check for a reference to a discarded symbol and ignore it. */ - if (h->root.root.u.def.section->output_section == NULL) - continue; - - sym_sec = h->root.root.u.def.section->output_section; - - symval = (h->root.root.u.def.value - + h->root.root.u.def.section->output_section->vma - + h->root.root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Try to turn a 32bit pc-relative branch/call into a 16bit pc-relative - branch/call, also deal with "call" -> "calls" conversions and - insertion of prologue data into "call" instructions. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL32 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PLT32) - { - bfd_vma value = symval; - - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PLT32 - && h != NULL - && ELF_ST_VISIBILITY (h->root.other) != STV_INTERNAL - && ELF_ST_VISIBILITY (h->root.other) != STV_HIDDEN - && h->root.plt.offset != (bfd_vma) -1) - { - asection * splt; - - splt = hash_table->root.splt; - value = ((splt->output_section->vma - + splt->output_offset - + h->root.plt.offset) - - (sec->output_section->vma - + sec->output_offset - + irel->r_offset)); - } - - /* If we've got a "call" instruction that needs to be turned - into a "calls" instruction, do so now. It saves a byte. */ - if (h && (h->flags & MN10300_CONVERT_CALL_TO_CALLS)) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* Make sure we're working with a "call" instruction! */ - if (code == 0xdd) - { - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfc, contents + irel->r_offset - 1); - bfd_put_8 (abfd, 0xff, contents + irel->r_offset); - - /* Fix irel->r_offset and irel->r_addend. */ - irel->r_offset += 1; - irel->r_addend += 1; - - /* Delete one byte of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 3, 1)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - else if (h) - { - /* We've got a "call" instruction which needs some data - from target function filled in. */ - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* Insert data from the target function into the "call" - instruction if needed. */ - if (code == 0xdd) - { - bfd_put_8 (abfd, h->movm_args, contents + irel->r_offset + 4); - bfd_put_8 (abfd, h->stack_size + h->movm_stack_size, - contents + irel->r_offset + 5); - } - } - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 16 bits, note the high value is - 0x7fff + 2 as the target will be two bytes closer if we are - able to relax, if it's in the same section. */ - if (sec->output_section == sym_sec->output_section) - jump_offset = 0x8001; - else - jump_offset = 0x7fff; - - /* Account for jumps across alignment boundaries using - align_gap_adjustment. */ - if ((bfd_signed_vma) value < jump_offset - (bfd_signed_vma) align_gap_adjustment - && ((bfd_signed_vma) value > -0x8000 + (bfd_signed_vma) align_gap_adjustment)) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - if (code != 0xdc && code != 0xdd && code != 0xff) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - if (code == 0xdc) - bfd_put_8 (abfd, 0xcc, contents + irel->r_offset - 1); - else if (code == 0xdd) - bfd_put_8 (abfd, 0xcd, contents + irel->r_offset - 1); - else if (code == 0xff) - bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_PLT32) - ? R_MN10300_PLT16 : - R_MN10300_PCREL16); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 16bit pc-relative branch into a 8bit pc-relative - branch. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL16) - { - bfd_vma value = symval; - - /* If we've got a "call" instruction that needs to be turned - into a "calls" instruction, do so now. It saves a byte. */ - if (h && (h->flags & MN10300_CONVERT_CALL_TO_CALLS)) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* Make sure we're working with a "call" instruction! */ - if (code == 0xcd) - { - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 1); - bfd_put_8 (abfd, 0xff, contents + irel->r_offset); - - /* Fix irel->r_offset and irel->r_addend. */ - irel->r_offset += 1; - irel->r_addend += 1; - - /* Delete one byte of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 1)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - else if (h) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* Insert data from the target function into the "call" - instruction if needed. */ - if (code == 0xcd) - { - bfd_put_8 (abfd, h->movm_args, contents + irel->r_offset + 2); - bfd_put_8 (abfd, h->stack_size + h->movm_stack_size, - contents + irel->r_offset + 3); - } - } - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 8 bits, note the high value is - 0x7f + 1 as the target will be one bytes closer if we are - able to relax. */ - if ((long) value < 0x80 && (long) value > -0x80) - { - unsigned char code; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - if (code != 0xcc) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xca, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10300_PCREL8); - - /* Delete one byte of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 1)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to eliminate an unconditional 8 bit pc-relative branch - which immediately follows a conditional 8 bit pc-relative - branch around the unconditional branch. - - original: new: - bCC lab1 bCC' lab2 - bra lab2 - lab1: lab1: - - This happens when the bCC can't reach lab2 at assembly time, - but due to other relaxations it can reach at link time. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_PCREL8) - { - Elf_Internal_Rela *nrel; - bfd_vma value = symval; - unsigned char code; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* Do nothing if this reloc is the last byte in the section. */ - if (irel->r_offset == sec->size) - continue; - - /* See if the next instruction is an unconditional pc-relative - branch, more often than not this test will fail, so we - test it first to speed things up. */ - code = bfd_get_8 (abfd, contents + irel->r_offset + 1); - if (code != 0xca) - continue; - - /* Also make sure the next relocation applies to the next - instruction and that it's a pc-relative 8 bit branch. */ - nrel = irel + 1; - if (nrel == irelend - || irel->r_offset + 2 != nrel->r_offset - || ELF32_R_TYPE (nrel->r_info) != (int) R_MN10300_PCREL8) - continue; - - /* Make sure our destination immediately follows the - unconditional branch. */ - if (symval != (sec->output_section->vma + sec->output_offset - + irel->r_offset + 3)) - continue; - - /* Now make sure we are a conditional branch. This may not - be necessary, but why take the chance. - - Note these checks assume that R_MN10300_PCREL8 relocs - only occur on bCC and bCCx insns. If they occured - elsewhere, we'd need to know the start of this insn - for this check to be accurate. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - if (code != 0xc0 && code != 0xc1 && code != 0xc2 - && code != 0xc3 && code != 0xc4 && code != 0xc5 - && code != 0xc6 && code != 0xc7 && code != 0xc8 - && code != 0xc9 && code != 0xe8 && code != 0xe9 - && code != 0xea && code != 0xeb) - continue; - - /* We also have to be sure there is no symbol/label - at the unconditional branch. */ - if (mn10300_elf_symbol_address_p (abfd, sec, isymbuf, - irel->r_offset + 1)) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Reverse the condition of the first branch. */ - switch (code) - { - case 0xc8: - code = 0xc9; - break; - case 0xc9: - code = 0xc8; - break; - case 0xc0: - code = 0xc2; - break; - case 0xc2: - code = 0xc0; - break; - case 0xc3: - code = 0xc1; - break; - case 0xc1: - code = 0xc3; - break; - case 0xc4: - code = 0xc6; - break; - case 0xc6: - code = 0xc4; - break; - case 0xc7: - code = 0xc5; - break; - case 0xc5: - code = 0xc7; - break; - case 0xe8: - code = 0xe9; - break; - case 0x9d: - code = 0xe8; - break; - case 0xea: - code = 0xeb; - break; - case 0xeb: - code = 0xea; - break; - } - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - /* Set the reloc type and symbol for the first branch - from the second branch. */ - irel->r_info = nrel->r_info; - - /* Make the reloc for the second branch a null reloc. */ - nrel->r_info = ELF32_R_INFO (ELF32_R_SYM (nrel->r_info), - R_MN10300_NONE); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - - /* Try to turn a 24 immediate, displacement or absolute address - into a 8 immediate, displacement or absolute address. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_24) - { - bfd_vma value = symval; - value += irel->r_addend; - - /* See if the value will fit in 8 bits. */ - if ((long) value < 0x7f && (long) value > -0x80) - { - unsigned char code; - - /* AM33 insns which have 24 operands are 6 bytes long and - will have 0xfd as the first byte. */ - - /* Get the first opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 3); - - if (code == 0xfd) - { - /* Get the second opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - /* We can not relax 0x6b, 0x7b, 0x8b, 0x9b as no 24bit - equivalent instructions exists. */ - if (code != 0x6b && code != 0x7b - && code != 0x8b && code != 0x9b - && ((code & 0x0f) == 0x09 || (code & 0x0f) == 0x08 - || (code & 0x0f) == 0x0a || (code & 0x0f) == 0x0b - || (code & 0x0f) == 0x0e)) - { - /* Not safe if the high bit is on as relaxing may - move the value out of high mem and thus not fit - in a signed 8bit value. This is currently over - conservative. */ - if ((value & 0x80) == 0) - { - /* Note that we've changed the relocation contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfb, contents + irel->r_offset - 3); - bfd_put_8 (abfd, code, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MN10300_8); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax - again. Note that this is not required, and it - may be slow. */ - *again = TRUE; - break; - } - } - } - } - } - - /* Try to turn a 32bit immediate, displacement or absolute address - into a 16bit immediate, displacement or absolute address. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_32 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOT32 - || ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTOFF32) - { - bfd_vma value = symval; - - if (ELF32_R_TYPE (irel->r_info) != (int) R_MN10300_32) - { - asection * sgot; - - sgot = hash_table->root.sgot; - if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOT32) - { - value = sgot->output_offset; - - if (h) - value += h->root.got.offset; - else - value += (elf_local_got_offsets - (abfd)[ELF32_R_SYM (irel->r_info)]); - } - else if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTOFF32) - value -= sgot->output_section->vma; - else if (ELF32_R_TYPE (irel->r_info) == (int) R_MN10300_GOTPC32) - value = (sgot->output_section->vma - - (sec->output_section->vma - + sec->output_offset - + irel->r_offset)); - else - abort (); - } - - value += irel->r_addend; - - /* See if the value will fit in 24 bits. - We allow any 16bit match here. We prune those we can't - handle below. */ - if ((long) value < 0x7fffff && (long) value > -0x800000) - { - unsigned char code; - - /* AM33 insns which have 32bit operands are 7 bytes long and - will have 0xfe as the first byte. */ - - /* Get the first opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 3); - - if (code == 0xfe) - { - /* Get the second opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - /* All the am33 32 -> 24 relaxing possibilities. */ - /* We can not relax 0x6b, 0x7b, 0x8b, 0x9b as no 24bit - equivalent instructions exists. */ - if (code != 0x6b && code != 0x7b - && code != 0x8b && code != 0x9b - && (ELF32_R_TYPE (irel->r_info) - != (int) R_MN10300_GOTPC32) - && ((code & 0x0f) == 0x09 || (code & 0x0f) == 0x08 - || (code & 0x0f) == 0x0a || (code & 0x0f) == 0x0b - || (code & 0x0f) == 0x0e)) - { - /* Not safe if the high bit is on as relaxing may - move the value out of high mem and thus not fit - in a signed 16bit value. This is currently over - conservative. */ - if ((value & 0x8000) == 0) - { - /* Note that we've changed the relocation contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfd, contents + irel->r_offset - 3); - bfd_put_8 (abfd, code, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF24 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT24 : - R_MN10300_24); - - /* Delete one byte of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 3, 1)) - goto error_return; - - /* That will change things, so, we should relax - again. Note that this is not required, and it - may be slow. */ - *again = TRUE; - break; - } - } - } - } - - /* See if the value will fit in 16 bits. - We allow any 16bit match here. We prune those we can't - handle below. */ - if ((long) value < 0x7fff && (long) value > -0x8000) - { - unsigned char code; - - /* Most insns which have 32bit operands are 6 bytes long; - exceptions are pcrel insns and bit insns. - - We handle pcrel insns above. We don't bother trying - to handle the bit insns here. - - The first byte of the remaining insns will be 0xfc. */ - - /* Get the first opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - if (code != 0xfc) - continue; - - /* Get the second opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - if ((code & 0xf0) < 0x80) - switch (code & 0xf0) - { - /* mov (d32,am),dn -> mov (d32,am),dn - mov dm,(d32,am) -> mov dn,(d32,am) - mov (d32,am),an -> mov (d32,am),an - mov dm,(d32,am) -> mov dn,(d32,am) - movbu (d32,am),dn -> movbu (d32,am),dn - movbu dm,(d32,am) -> movbu dn,(d32,am) - movhu (d32,am),dn -> movhu (d32,am),dn - movhu dm,(d32,am) -> movhu dn,(d32,am) */ - case 0x00: - case 0x10: - case 0x20: - case 0x30: - case 0x40: - case 0x50: - case 0x60: - case 0x70: - /* Not safe if the high bit is on as relaxing may - move the value out of high mem and thus not fit - in a signed 16bit value. */ - if (code == 0xcc - && (value & 0x8000)) - continue; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2); - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTPC32) - ? R_MN10300_GOTPC16 : - R_MN10300_16); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - } - else if ((code & 0xf0) == 0x80 - || (code & 0xf0) == 0x90) - switch (code & 0xf3) - { - /* mov dn,(abs32) -> mov dn,(abs16) - movbu dn,(abs32) -> movbu dn,(abs16) - movhu dn,(abs32) -> movhu dn,(abs16) */ - case 0x81: - case 0x82: - case 0x83: - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - if ((code & 0xf3) == 0x81) - code = 0x01 + (code & 0x0c); - else if ((code & 0xf3) == 0x82) - code = 0x02 + (code & 0x0c); - else if ((code & 0xf3) == 0x83) - code = 0x03 + (code & 0x0c); - else - abort (); - - /* Fix the opcode. */ - bfd_put_8 (abfd, code, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTPC32) - ? R_MN10300_GOTPC16 : - R_MN10300_16); - - /* The opcode got shorter too, so we have to fix the - addend and offset too! */ - irel->r_offset -= 1; - - /* Delete three bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 3)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - - /* mov am,(abs32) -> mov am,(abs16) - mov am,(d32,sp) -> mov am,(d16,sp) - mov dm,(d32,sp) -> mov dm,(d32,sp) - movbu dm,(d32,sp) -> movbu dm,(d32,sp) - movhu dm,(d32,sp) -> movhu dm,(d32,sp) */ - case 0x80: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - /* sp-based offsets are zero-extended. */ - if (code >= 0x90 && code <= 0x93 - && (long) value < 0) - continue; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2); - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTPC32) - ? R_MN10300_GOTPC16 : - R_MN10300_16); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - } - else if ((code & 0xf0) < 0xf0) - switch (code & 0xfc) - { - /* mov imm32,dn -> mov imm16,dn - mov imm32,an -> mov imm16,an - mov (abs32),dn -> mov (abs16),dn - movbu (abs32),dn -> movbu (abs16),dn - movhu (abs32),dn -> movhu (abs16),dn */ - case 0xcc: - case 0xdc: - case 0xa4: - case 0xa8: - case 0xac: - /* Not safe if the high bit is on as relaxing may - move the value out of high mem and thus not fit - in a signed 16bit value. */ - if (code == 0xcc - && (value & 0x8000)) - continue; - - /* "mov imm16, an" zero-extends the immediate. */ - if ((code & 0xfc) == 0xdc - && (long) value < 0) - continue; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - if ((code & 0xfc) == 0xcc) - code = 0x2c + (code & 0x03); - else if ((code & 0xfc) == 0xdc) - code = 0x24 + (code & 0x03); - else if ((code & 0xfc) == 0xa4) - code = 0x30 + (code & 0x03); - else if ((code & 0xfc) == 0xa8) - code = 0x34 + (code & 0x03); - else if ((code & 0xfc) == 0xac) - code = 0x38 + (code & 0x03); - else - abort (); - - /* Fix the opcode. */ - bfd_put_8 (abfd, code, contents + irel->r_offset - 2); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTPC32) - ? R_MN10300_GOTPC16 : - R_MN10300_16); - - /* The opcode got shorter too, so we have to fix the - addend and offset too! */ - irel->r_offset -= 1; - - /* Delete three bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 3)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - - /* mov (abs32),an -> mov (abs16),an - mov (d32,sp),an -> mov (d16,sp),an - mov (d32,sp),dn -> mov (d16,sp),dn - movbu (d32,sp),dn -> movbu (d16,sp),dn - movhu (d32,sp),dn -> movhu (d16,sp),dn - add imm32,dn -> add imm16,dn - cmp imm32,dn -> cmp imm16,dn - add imm32,an -> add imm16,an - cmp imm32,an -> cmp imm16,an - and imm32,dn -> and imm16,dn - or imm32,dn -> or imm16,dn - xor imm32,dn -> xor imm16,dn - btst imm32,dn -> btst imm16,dn */ - - case 0xa0: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xc0: - case 0xc8: - - case 0xd0: - case 0xd8: - case 0xe0: - case 0xe1: - case 0xe2: - case 0xe3: - /* cmp imm16, an zero-extends the immediate. */ - if (code == 0xdc - && (long) value < 0) - continue; - - /* So do sp-based offsets. */ - if (code >= 0xb0 && code <= 0xb3 - && (long) value < 0) - continue; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2); - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTPC32) - ? R_MN10300_GOTPC16 : - R_MN10300_16); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - } - else if (code == 0xfe) - { - /* add imm32,sp -> add imm16,sp */ - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0xfa, contents + irel->r_offset - 2); - bfd_put_8 (abfd, 0xfe, contents + irel->r_offset - 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOT32) - ? R_MN10300_GOT16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTOFF32) - ? R_MN10300_GOTOFF16 - : (ELF32_R_TYPE (irel->r_info) - == (int) R_MN10300_GOTPC32) - ? R_MN10300_GOTPC16 : - R_MN10300_16); - - /* Delete two bytes of data. */ - if (!mn10300_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - } - } - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (section)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (section)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses mn10300_elf_relocate_section. */ - -static bfd_byte * -mn10300_elf_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - asection **secpp; - Elf_Internal_Sym *isym, *isymend; - bfd_size_type amt; - - internal_relocs = _bfd_elf_link_read_relocs (input_bfd, input_section, - NULL, NULL, FALSE); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! mn10300_elf_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != elf_section_data (input_section)->relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && internal_relocs != elf_section_data (input_section)->relocs) - free (internal_relocs); - return NULL; -} - -/* Assorted hash table functions. */ - -/* Initialize an entry in the link hash table. */ - -/* Create an entry in an MN10300 ELF linker hash table. */ - -static struct bfd_hash_entry * -elf32_mn10300_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf32_mn10300_link_hash_entry *ret = - (struct elf32_mn10300_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = (struct elf32_mn10300_link_hash_entry *) - bfd_hash_allocate (table, sizeof (* ret)); - if (ret == NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = (struct elf32_mn10300_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string); - if (ret != NULL) - { - ret->direct_calls = 0; - ret->stack_size = 0; - ret->movm_args = 0; - ret->movm_stack_size = 0; - ret->flags = 0; - ret->value = 0; - ret->tls_type = GOT_UNKNOWN; - } - - return (struct bfd_hash_entry *) ret; -} - -static void -_bfd_mn10300_copy_indirect_symbol (struct bfd_link_info * info, - struct elf_link_hash_entry * dir, - struct elf_link_hash_entry * ind) -{ - struct elf32_mn10300_link_hash_entry * edir; - struct elf32_mn10300_link_hash_entry * eind; - - edir = elf_mn10300_hash_entry (dir); - eind = elf_mn10300_hash_entry (ind); - - if (ind->root.type == bfd_link_hash_indirect - && dir->got.refcount <= 0) - { - edir->tls_type = eind->tls_type; - eind->tls_type = GOT_UNKNOWN; - } - edir->direct_calls = eind->direct_calls; - edir->stack_size = eind->stack_size; - edir->movm_args = eind->movm_args; - edir->movm_stack_size = eind->movm_stack_size; - edir->flags = eind->flags; - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Destroy an mn10300 ELF linker hash table. */ - -static void -elf32_mn10300_link_hash_table_free (bfd *obfd) -{ - struct elf32_mn10300_link_hash_table *ret - = (struct elf32_mn10300_link_hash_table *) obfd->link.hash; - - obfd->link.hash = &ret->static_hash_table->root.root; - _bfd_elf_link_hash_table_free (obfd); - obfd->is_linker_output = TRUE; - obfd->link.hash = &ret->root.root; - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create an mn10300 ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf32_mn10300_link_hash_table_create (bfd *abfd) -{ - struct elf32_mn10300_link_hash_table *ret; - bfd_size_type amt = sizeof (* ret); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - amt = sizeof (struct elf_link_hash_table); - ret->static_hash_table = bfd_zmalloc (amt); - if (ret->static_hash_table == NULL) - { - free (ret); - return NULL; - } - - if (!_bfd_elf_link_hash_table_init (&ret->static_hash_table->root, abfd, - elf32_mn10300_link_hash_newfunc, - sizeof (struct elf32_mn10300_link_hash_entry), - MN10300_ELF_DATA)) - { - free (ret->static_hash_table); - free (ret); - return NULL; - } - - abfd->is_linker_output = FALSE; - abfd->link.hash = NULL; - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - elf32_mn10300_link_hash_newfunc, - sizeof (struct elf32_mn10300_link_hash_entry), - MN10300_ELF_DATA)) - { - abfd->is_linker_output = TRUE; - abfd->link.hash = &ret->static_hash_table->root.root; - _bfd_elf_link_hash_table_free (abfd); - free (ret); - return NULL; - } - ret->root.root.hash_table_free = elf32_mn10300_link_hash_table_free; - - ret->tls_ldm_got.offset = -1; - - return & ret->root.root; -} - -static unsigned long -elf_mn10300_mach (flagword flags) -{ - switch (flags & EF_MN10300_MACH) - { - case E_MN10300_MACH_MN10300: - default: - return bfd_mach_mn10300; - - case E_MN10300_MACH_AM33: - return bfd_mach_am33; - - case E_MN10300_MACH_AM33_2: - return bfd_mach_am33_2; - } -} - -/* The final processing done just before writing out a MN10300 ELF object - file. This gets the MN10300 architecture right based on the machine - number. */ - -static void -_bfd_mn10300_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_mn10300: - val = E_MN10300_MACH_MN10300; - break; - - case bfd_mach_am33: - val = E_MN10300_MACH_AM33; - break; - - case bfd_mach_am33_2: - val = E_MN10300_MACH_AM33_2; - break; - } - - elf_elfheader (abfd)->e_flags &= ~ (EF_MN10300_MACH); - elf_elfheader (abfd)->e_flags |= val; -} - -static bfd_boolean -_bfd_mn10300_elf_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_mn10300, - elf_mn10300_mach (elf_elfheader (abfd)->e_flags)); - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -_bfd_mn10300_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_mach (obfd) < bfd_get_mach (ibfd)) - { - if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd))) - return FALSE; - } - - return TRUE; -} - -#define PLT0_ENTRY_SIZE 15 -#define PLT_ENTRY_SIZE 20 -#define PIC_PLT_ENTRY_SIZE 24 - -static const bfd_byte elf_mn10300_plt0_entry[PLT0_ENTRY_SIZE] = -{ - 0xfc, 0xa0, 0, 0, 0, 0, /* mov (.got+8),a0 */ - 0xfe, 0xe, 0x10, 0, 0, 0, 0, /* mov (.got+4),r1 */ - 0xf0, 0xf4, /* jmp (a0) */ -}; - -static const bfd_byte elf_mn10300_plt_entry[PLT_ENTRY_SIZE] = -{ - 0xfc, 0xa0, 0, 0, 0, 0, /* mov (nameN@GOT + .got),a0 */ - 0xf0, 0xf4, /* jmp (a0) */ - 0xfe, 8, 0, 0, 0, 0, 0, /* mov reloc-table-address,r0 */ - 0xdc, 0, 0, 0, 0, /* jmp .plt0 */ -}; - -static const bfd_byte elf_mn10300_pic_plt_entry[PIC_PLT_ENTRY_SIZE] = -{ - 0xfc, 0x22, 0, 0, 0, 0, /* mov (nameN@GOT,a2),a0 */ - 0xf0, 0xf4, /* jmp (a0) */ - 0xfe, 8, 0, 0, 0, 0, 0, /* mov reloc-table-address,r0 */ - 0xf8, 0x22, 8, /* mov (8,a2),a0 */ - 0xfb, 0xa, 0x1a, 4, /* mov (4,a2),r1 */ - 0xf0, 0xf4, /* jmp (a0) */ -}; - -/* Return size of the first PLT entry. */ -#define elf_mn10300_sizeof_plt0(info) \ - (bfd_link_pic (info) ? PIC_PLT_ENTRY_SIZE : PLT0_ENTRY_SIZE) - -/* Return size of a PLT entry. */ -#define elf_mn10300_sizeof_plt(info) \ - (bfd_link_pic (info) ? PIC_PLT_ENTRY_SIZE : PLT_ENTRY_SIZE) - -/* Return offset of the PLT0 address in an absolute PLT entry. */ -#define elf_mn10300_plt_plt0_offset(info) 16 - -/* Return offset of the linker in PLT0 entry. */ -#define elf_mn10300_plt0_linker_offset(info) 2 - -/* Return offset of the GOT id in PLT0 entry. */ -#define elf_mn10300_plt0_gotid_offset(info) 9 - -/* Return offset of the temporary in PLT entry. */ -#define elf_mn10300_plt_temp_offset(info) 8 - -/* Return offset of the symbol in PLT entry. */ -#define elf_mn10300_plt_symbol_offset(info) 2 - -/* Return offset of the relocation in PLT entry. */ -#define elf_mn10300_plt_reloc_offset(info) 11 - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -_bfd_mn10300_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags; - asection * s; - const struct elf_backend_data * bed = get_elf_backend_data (abfd); - struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); - int ptralign = 0; - - switch (bed->s->arch_size) - { - case 32: - ptralign = 2; - break; - - case 64: - ptralign = 3; - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.plt" : ".rel.plt"), - flags | SEC_READONLY); - htab->root.srelplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (! _bfd_mn10300_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_anyway_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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - 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 -_bfd_mn10300_elf_adjust_dynamic_symbol (struct bfd_link_info * info, - struct elf_link_hash_entry * h) -{ - struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); - bfd * dynobj; - asection * s; - - dynobj = htab->root.dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (! bfd_link_pic (info) - && !h->def_dynamic - && !h->ref_dynamic) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a REL32 - reloc instead. */ - BFD_ASSERT (h->needs_plt); - return TRUE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->root.splt; - BFD_ASSERT (s != NULL); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += elf_mn10300_sizeof_plt0 (info); - - /* 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 (! bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = s->size; - } - - h->plt.offset = s->size; - - /* Make room for this entry. */ - s->size += elf_mn10300_sizeof_plt (info); - - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - s = htab->root.sgotplt; - BFD_ASSERT (s != NULL); - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - s = htab->root.srelplt; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - - return TRUE; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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; - - /* 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. */ - - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - /* We must generate a R_MN10300_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection * srel; - - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -_bfd_mn10300_elf_size_dynamic_sections (bfd * output_bfd, - struct bfd_link_info * info) -{ - struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); - bfd * dynobj; - asection * s; - bfd_boolean plt; - bfd_boolean relocs; - bfd_boolean reltext; - - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = htab->root.sgot; - if (s != NULL) - s->size = 0; - } - - if (htab->tls_ldm_got.refcount > 0) - { - s = htab->root.srelgot; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char * name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (streq (name, ".plt")) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - asection * target; - - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (! streq (name, ".rela.plt")) - { - const char * outname; - - relocs = TRUE; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL - entry. The entries in the .rela.plt section - really apply to the .got section, which we - created ourselves and so know is not readonly. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 5); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = 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 if (! CONST_STRNEQ (name, ".got") - && ! streq (name, ".dynbss")) - /* 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_MN10300_NONE reloc - instead of garbage. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in _bfd_mn10300_elf_finish_dynamic_sections, - but we must add the entries now so that we get the correct - size for the .dynamic section. The DT_DEBUG entry is filled - in by the dynamic linker and used by the debugger. */ - if (! bfd_link_pic (info)) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - } - - if (reltext) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0)) - return FALSE; - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -_bfd_mn10300_elf_finish_dynamic_symbol (bfd * output_bfd, - struct bfd_link_info * info, - struct elf_link_hash_entry * h, - Elf_Internal_Sym * sym) -{ - struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); - bfd * dynobj; - - dynobj = htab->root.dynobj; - - if (h->plt.offset != (bfd_vma) -1) - { - asection * splt; - asection * sgot; - asection * srel; - bfd_vma plt_index; - bfd_vma got_offset; - Elf_Internal_Rela rel; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srel = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = ((h->plt.offset - elf_mn10300_sizeof_plt0 (info)) - / elf_mn10300_sizeof_plt (info)); - - /* 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 (! bfd_link_pic (info)) - { - memcpy (splt->contents + h->plt.offset, elf_mn10300_plt_entry, - elf_mn10300_sizeof_plt (info)); - bfd_put_32 (output_bfd, - (sgot->output_section->vma - + sgot->output_offset - + got_offset), - (splt->contents + h->plt.offset - + elf_mn10300_plt_symbol_offset (info))); - - bfd_put_32 (output_bfd, - (1 - h->plt.offset - elf_mn10300_plt_plt0_offset (info)), - (splt->contents + h->plt.offset - + elf_mn10300_plt_plt0_offset (info))); - } - else - { - memcpy (splt->contents + h->plt.offset, elf_mn10300_pic_plt_entry, - elf_mn10300_sizeof_plt (info)); - - bfd_put_32 (output_bfd, got_offset, - (splt->contents + h->plt.offset - + elf_mn10300_plt_symbol_offset (info))); - } - - bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela), - (splt->contents + h->plt.offset - + elf_mn10300_plt_reloc_offset (info))); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + elf_mn10300_plt_temp_offset (info)), - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_JMP_SLOT); - rel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rel, - (bfd_byte *) ((Elf32_External_Rela *) srel->contents - + plt_index)); - - if (!h->def_regular) - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - - if (h->got.offset != (bfd_vma) -1) - { - asection * sgot; - asection * srel; - Elf_Internal_Rela rel; - - /* This symbol has an entry in the global offset table. Set it up. */ - sgot = htab->root.sgot; - srel = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srel != NULL); - - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset & ~1)); - - switch (elf_mn10300_hash_entry (h)->tls_type) - { - case GOT_TLS_GD: - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset + 4); - rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_DTPMOD); - rel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, & rel, - (bfd_byte *) ((Elf32_External_Rela *) srel->contents - + srel->reloc_count)); - ++ srel->reloc_count; - rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_DTPOFF); - rel.r_offset += 4; - rel.r_addend = 0; - break; - - case GOT_TLS_IE: - /* We originally stored the addend in the GOT, but at this - point, we want to move it to the reloc instead as that's - where the dynamic linker wants it. */ - rel.r_addend = bfd_get_32 (output_bfd, sgot->contents + h->got.offset); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - if (h->dynindx == -1) - rel.r_info = ELF32_R_INFO (0, R_MN10300_TLS_TPOFF); - else - rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_TLS_TPOFF); - break; - - default: - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic || h->dynindx == -1) - && h->def_regular) - { - rel.r_info = ELF32_R_INFO (0, R_MN10300_RELATIVE); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_MN10300_GLOB_DAT); - rel.r_addend = 0; - } - } - - if (ELF32_R_TYPE (rel.r_info) != R_MN10300_NONE) - { - bfd_elf32_swap_reloca_out (output_bfd, &rel, - (bfd_byte *) ((Elf32_External_Rela *) srel->contents - + srel->reloc_count)); - ++ srel->reloc_count; - } - } - - if (h->needs_copy) - { - asection * s; - Elf_Internal_Rela rel; - - /* This symbol needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - 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_MN10300_COPY); - rel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, & rel, - (bfd_byte *) ((Elf32_External_Rela *) s->contents - + s->reloc_count)); - ++ s->reloc_count; - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -_bfd_mn10300_elf_finish_dynamic_sections (bfd * output_bfd, - struct bfd_link_info * info) -{ - bfd * dynobj; - asection * sgot; - asection * sdyn; - struct elf32_mn10300_link_hash_table *htab = elf32_mn10300_hash_table (info); - - dynobj = htab->root.dynobj; - sgot = htab->root.sgotplt; - BFD_ASSERT (sgot != NULL); - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection * splt; - Elf32_External_Dyn * dyncon; - Elf32_External_Dyn * dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection * s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = htab->root.sgot; - goto get_vma; - - case DT_JMPREL: - s = htab->root.srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; - if (splt && splt->size > 0) - { - if (bfd_link_pic (info)) - { - memcpy (splt->contents, elf_mn10300_pic_plt_entry, - elf_mn10300_sizeof_plt (info)); - } - else - { - memcpy (splt->contents, elf_mn10300_plt0_entry, PLT0_ENTRY_SIZE); - bfd_put_32 (output_bfd, - sgot->output_section->vma + sgot->output_offset + 4, - splt->contents + elf_mn10300_plt0_gotid_offset (info)); - bfd_put_32 (output_bfd, - sgot->output_section->vma + sgot->output_offset + 8, - splt->contents + elf_mn10300_plt0_linker_offset (info)); - } - - /* UnixWare sets the entsize of .plt to 4, although that doesn't - really seem like the right value. */ - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; - - /* UnixWare sets the entsize of .plt to 4, but this is incorrect - as it means that the size of the PLT0 section (15 bytes) is not - a multiple of the sh_entsize. Some ELF tools flag this as an - error. We could pad PLT0 to 16 bytes, but that would introduce - compatibilty issues with previous toolchains, so instead we - just set the entry size to 1. */ - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 1; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -/* Classify relocation types, such that combreloc can sort them - properly. */ - -static enum elf_reloc_type_class -_bfd_mn10300_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_MN10300_RELATIVE: return reloc_class_relative; - case R_MN10300_JMP_SLOT: return reloc_class_plt; - case R_MN10300_COPY: return reloc_class_copy; - default: return reloc_class_normal; - } -} - -/* Allocate space for an MN10300 extension to the bfd elf data structure. */ - -static bfd_boolean -mn10300_elf_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_mn10300_obj_tdata), - MN10300_ELF_DATA); -} - -#define bfd_elf32_mkobject mn10300_elf_mkobject - -#ifndef ELF_ARCH -#define TARGET_LITTLE_SYM mn10300_elf32_vec -#define TARGET_LITTLE_NAME "elf32-mn10300" -#define ELF_ARCH bfd_arch_mn10300 -#define ELF_TARGET_ID MN10300_ELF_DATA -#define ELF_MACHINE_CODE EM_MN10300 -#define ELF_MACHINE_ALT1 EM_CYGNUS_MN10300 -#define ELF_MAXPAGESIZE 0x1000 -#endif - -#define elf_info_to_howto mn10300_info_to_howto -#define elf_info_to_howto_rel 0 -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 -#define elf_backend_check_relocs mn10300_elf_check_relocs -#define elf_backend_gc_mark_hook mn10300_elf_gc_mark_hook -#define elf_backend_relocate_section mn10300_elf_relocate_section -#define bfd_elf32_bfd_relax_section mn10300_elf_relax_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - mn10300_elf_get_relocated_section_contents -#define bfd_elf32_bfd_link_hash_table_create \ - elf32_mn10300_link_hash_table_create - -#ifndef elf_symbol_leading_char -#define elf_symbol_leading_char '_' -#endif - -/* So we can set bits in e_flags. */ -#define elf_backend_final_write_processing \ - _bfd_mn10300_elf_final_write_processing -#define elf_backend_object_p _bfd_mn10300_elf_object_p - -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_mn10300_elf_merge_private_bfd_data - -#define elf_backend_can_gc_sections 1 -#define elf_backend_create_dynamic_sections \ - _bfd_mn10300_elf_create_dynamic_sections -#define elf_backend_adjust_dynamic_symbol \ - _bfd_mn10300_elf_adjust_dynamic_symbol -#define elf_backend_size_dynamic_sections \ - _bfd_mn10300_elf_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_finish_dynamic_symbol \ - _bfd_mn10300_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_mn10300_elf_finish_dynamic_sections -#define elf_backend_copy_indirect_symbol \ - _bfd_mn10300_copy_indirect_symbol -#define elf_backend_reloc_type_class \ - _bfd_mn10300_elf_reloc_type_class - -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf-nacl.c b/sdcc/support/sdbinutils/bfd/elf-nacl.c deleted file mode 100644 index 5f446b424..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-nacl.c +++ /dev/null @@ -1,353 +0,0 @@ -/* Native Client support for ELF - Copyright (C) 2012-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf-nacl.h" -#include "elf/common.h" -#include "elf/internal.h" - -static bfd_boolean -segment_executable (struct elf_segment_map *seg) -{ - if (seg->p_flags_valid) - return (seg->p_flags & PF_X) != 0; - else - { - /* The p_flags value has not been computed yet, - so we have to look through the sections. */ - unsigned int i; - for (i = 0; i < seg->count; ++i) - if (seg->sections[i]->flags & SEC_CODE) - return TRUE; - } - return FALSE; -} - -/* Determine if this segment is eligible to receive the file and program - headers. It must be read-only and non-executable. - Its first section must start far enough past the page boundary to - allow space for the headers. */ -static bfd_boolean -segment_eligible_for_headers (struct elf_segment_map *seg, - bfd_vma minpagesize, bfd_vma sizeof_headers) -{ - unsigned int i; - if (seg->count == 0 || seg->sections[0]->lma % minpagesize < sizeof_headers) - return FALSE; - for (i = 0; i < seg->count; ++i) - { - if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY) - return FALSE; - } - return TRUE; -} - - -/* We permute the segment_map to get BFD to do the file layout we want: - The first non-executable PT_LOAD segment appears first in the file - and contains the ELF file header and phdrs. */ -bfd_boolean -nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) -{ - const struct elf_backend_data *const bed = get_elf_backend_data (abfd); - struct elf_segment_map **m = &elf_seg_map (abfd); - struct elf_segment_map **first_load = NULL; - struct elf_segment_map **last_load = NULL; - bfd_boolean moved_headers = FALSE; - int sizeof_headers; - - if (info != NULL && info->user_phdrs) - /* The linker script used PHDRS explicitly, so don't change what the - user asked for. */ - return TRUE; - - if (info != NULL) - /* We're doing linking, so evalute SIZEOF_HEADERS as in a linker script. */ - sizeof_headers = bfd_sizeof_headers (abfd, info); - else - { - /* We're not doing linking, so this is objcopy or suchlike. - We just need to collect the size of the existing headers. */ - struct elf_segment_map *seg; - sizeof_headers = bed->s->sizeof_ehdr; - for (seg = *m; seg != NULL; seg = seg->next) - sizeof_headers += bed->s->sizeof_phdr; - } - - while (*m != NULL) - { - struct elf_segment_map *seg = *m; - - if (seg->p_type == PT_LOAD) - { - bfd_boolean executable = segment_executable (seg); - - if (executable - && seg->count > 0 - && seg->sections[0]->vma % bed->minpagesize == 0) - { - asection *lastsec = seg->sections[seg->count - 1]; - bfd_vma end = lastsec->vma + lastsec->size; - if (end % bed->minpagesize != 0) - { - /* This is an executable segment that starts on a page - boundary but does not end on a page boundary. Fill - it out to a whole page with code fill (the tail of - the segment will not be within any section). Thus - the entire code segment can be mapped from the file - as whole pages and that mapping will contain only - valid instructions. - - To accomplish this, we must fake out the code in - assign_file_positions_for_load_sections (elf.c) so - that it advances past the rest of the final page, - rather than trying to put the next (unaligned, or - unallocated) section. We do this by appending a - dummy section record to this element in the segment - map. No such output section ever actually exists, - but this gets the layout logic to advance the file - positions past this partial page. Since we are - lying to BFD like this, nothing will ever know to - write the section contents. So we do that by hand - after the fact, in nacl_final_write_processing, below. */ - - struct elf_segment_map *newseg; - asection *sec; - struct bfd_elf_section_data *secdata; - - BFD_ASSERT (!seg->p_size_valid); - - secdata = bfd_zalloc (abfd, sizeof *secdata); - if (secdata == NULL) - return FALSE; - - sec = bfd_zalloc (abfd, sizeof *sec); - if (sec == NULL) - return FALSE; - - /* Fill in only the fields that actually affect the logic - in assign_file_positions_for_load_sections. */ - sec->vma = end; - sec->lma = lastsec->lma + lastsec->size; - sec->size = bed->minpagesize - (end % bed->minpagesize); - sec->flags = (SEC_ALLOC | SEC_LOAD - | SEC_READONLY | SEC_CODE | SEC_LINKER_CREATED); - sec->used_by_bfd = secdata; - - secdata->this_hdr.sh_type = SHT_PROGBITS; - secdata->this_hdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; - secdata->this_hdr.sh_addr = sec->vma; - secdata->this_hdr.sh_size = sec->size; - - newseg = bfd_alloc (abfd, - sizeof *newseg + ((seg->count + 1) - * sizeof (asection *))); - if (newseg == NULL) - return FALSE; - memcpy (newseg, seg, - sizeof *newseg + (seg->count * sizeof (asection *))); - newseg->sections[newseg->count++] = sec; - *m = seg = newseg; - } - } - - /* First, we're just finding the earliest PT_LOAD. - By the normal rules, this will be the lowest-addressed one. - We only have anything interesting to do if it's executable. */ - last_load = m; - if (first_load == NULL) - { - if (!executable) - goto next; - first_load = m; - } - /* Now that we've noted the first PT_LOAD, we're looking for - the first non-executable PT_LOAD with a nonempty p_filesz. */ - else if (!moved_headers - && segment_eligible_for_headers (seg, bed->minpagesize, - sizeof_headers)) - { - /* This is the one we were looking for! - - First, clear the flags on previous segments that - say they include the file header and phdrs. */ - struct elf_segment_map *prevseg; - for (prevseg = *first_load; - prevseg != seg; - prevseg = prevseg->next) - if (prevseg->p_type == PT_LOAD) - { - prevseg->includes_filehdr = 0; - prevseg->includes_phdrs = 0; - } - - /* This segment will include those headers instead. */ - seg->includes_filehdr = 1; - seg->includes_phdrs = 1; - - moved_headers = TRUE; - } - } - - next: - m = &seg->next; - } - - if (first_load != last_load && moved_headers) - { - /* Now swap the first and last PT_LOAD segments' - positions in segment_map. */ - struct elf_segment_map *first = *first_load; - struct elf_segment_map *last = *last_load; - *first_load = first->next; - first->next = last->next; - last->next = first; - } - - return TRUE; -} - -/* After nacl_modify_segment_map has done its work, the file layout has - been done as we wanted. But the PT_LOAD phdrs are no longer in the - proper order for the ELF rule that they must appear in ascending address - order. So find the two segments we swapped before, and swap them back. */ -bfd_boolean -nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_segment_map **m = &elf_seg_map (abfd); - Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; - Elf_Internal_Phdr *p = phdr; - - if (info != NULL && info->user_phdrs) - /* The linker script used PHDRS explicitly, so don't change what the - user asked for. */ - return TRUE; - - /* Find the PT_LOAD that contains the headers (should be the first). */ - while (*m != NULL) - { - if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr) - break; - - m = &(*m)->next; - ++p; - } - - if (*m != NULL) - { - struct elf_segment_map **first_load_seg = m; - Elf_Internal_Phdr *first_load_phdr = p; - struct elf_segment_map **next_load_seg = NULL; - Elf_Internal_Phdr *next_load_phdr = NULL; - - /* Now move past that first one and find the PT_LOAD that should be - before it by address order. */ - - m = &(*m)->next; - ++p; - - while (*m != NULL) - { - if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) - { - next_load_seg = m; - next_load_phdr = p; - break; - } - - m = &(*m)->next; - ++p; - } - - /* Swap their positions in the segment_map back to how they used to be. - The phdrs have already been set up by now, so we have to slide up - the earlier ones to insert the one that should be first. */ - if (next_load_seg != NULL) - { - Elf_Internal_Phdr move_phdr; - struct elf_segment_map *first_seg = *first_load_seg; - struct elf_segment_map *next_seg = *next_load_seg; - struct elf_segment_map *first_next = first_seg->next; - struct elf_segment_map *next_next = next_seg->next; - - if (next_load_seg == &first_seg->next) - { - *first_load_seg = next_seg; - next_seg->next = first_seg; - first_seg->next = next_next; - } - else - { - *first_load_seg = first_next; - *next_load_seg = next_next; - - first_seg->next = *next_load_seg; - *next_load_seg = first_seg; - - next_seg->next = *first_load_seg; - *first_load_seg = next_seg; - } - - move_phdr = *next_load_phdr; - memmove (first_load_phdr + 1, first_load_phdr, - (next_load_phdr - first_load_phdr) * sizeof move_phdr); - *first_load_phdr = move_phdr; - } - } - - return TRUE; -} - -void -nacl_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) -{ - struct elf_segment_map *seg; - for (seg = elf_seg_map (abfd); seg != NULL; seg = seg->next) - if (seg->p_type == PT_LOAD - && seg->count > 1 - && seg->sections[seg->count - 1]->owner == NULL) - { - /* This is a fake section added in nacl_modify_segment_map, above. - It's not a real BFD section, so nothing wrote its contents. - Now write out its contents. */ - - asection *sec = seg->sections[seg->count - 1]; - char *fill; - - BFD_ASSERT (sec->flags & SEC_LINKER_CREATED); - BFD_ASSERT (sec->flags & SEC_CODE); - BFD_ASSERT (sec->size > 0); - - fill = abfd->arch_info->fill (sec->size, bfd_big_endian (abfd), TRUE); - - if (fill == NULL - || bfd_seek (abfd, sec->filepos, SEEK_SET) != 0 - || bfd_bwrite (fill, sec->size, abfd) != sec->size) - { - /* We don't have a proper way to report an error here. So - instead fudge things so that elf_write_shdrs_and_ehdr will - fail. */ - elf_elfheader (abfd)->e_shoff = (file_ptr) -1; - } - - free (fill); - } -} diff --git a/sdcc/support/sdbinutils/bfd/elf-nacl.h b/sdcc/support/sdbinutils/bfd/elf-nacl.h deleted file mode 100644 index 8ca061831..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-nacl.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Native Client support for ELF - Copyright (C) 2012-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include "bfd.h" - -bfd_boolean nacl_modify_segment_map (bfd *, struct bfd_link_info *); -bfd_boolean nacl_modify_program_headers (bfd *, struct bfd_link_info *); -void nacl_final_write_processing (bfd *, bfd_boolean linker); diff --git a/sdcc/support/sdbinutils/bfd/elf-properties.c b/sdcc/support/sdbinutils/bfd/elf-properties.c deleted file mode 100644 index 2549dd0e7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-properties.c +++ /dev/null @@ -1,510 +0,0 @@ -/* ELF program property support. - Copyright (C) 2017-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* GNU program property draft is at: - - https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf - */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -/* Get a property, allocate a new one if needed. */ - -elf_property * -_bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz) -{ - elf_property_list *p, **lastp; - - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - { - /* Never should happen. */ - abort (); - } - - /* Keep the property list in order of type. */ - lastp = &elf_properties (abfd); - for (p = *lastp; p; p = p->next) - { - /* Reuse the existing entry. */ - if (type == p->property.pr_type) - { - if (datasz > p->property.pr_datasz) - { - /* This can happen when mixing 32-bit and 64-bit objects. */ - p->property.pr_datasz = datasz; - } - return &p->property; - } - else if (type < p->property.pr_type) - break; - lastp = &p->next; - } - p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p)); - if (p == NULL) - { - _bfd_error_handler (_("%B: out of memory in _bfd_elf_get_property"), - abfd); - _exit (EXIT_FAILURE); - } - memset (p, 0, sizeof (*p)); - p->property.pr_type = type; - p->property.pr_datasz = datasz; - p->next = *lastp; - *lastp = p; - return &p->property; -} - -/* Parse GNU properties. */ - -bfd_boolean -_bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; - bfd_byte *ptr = (bfd_byte *) note->descdata; - bfd_byte *ptr_end = ptr + note->descsz; - - if (note->descsz < 8 || (note->descsz % align_size) != 0) - { -bad_size: - _bfd_error_handler - (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"), - abfd, note->type, note->descsz); - return FALSE; - } - - while (ptr != ptr_end) - { - unsigned int type; - unsigned int datasz; - elf_property *prop; - - if ((size_t) (ptr_end - ptr) < 8) - goto bad_size; - - type = bfd_h_get_32 (abfd, ptr); - datasz = bfd_h_get_32 (abfd, ptr + 4); - ptr += 8; - - if (datasz > (size_t) (ptr_end - ptr)) - { - _bfd_error_handler - (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x"), - abfd, note->type, type, datasz); - /* Clear all properties. */ - elf_properties (abfd) = NULL; - return FALSE; - } - - if (type >= GNU_PROPERTY_LOPROC) - { - if (bed->elf_machine_code == EM_NONE) - { - /* Ignore processor-specific properties with generic ELF - target vector. They should be handled by the matching - ELF target vector. */ - goto next; - } - else if (type < GNU_PROPERTY_LOUSER - && bed->parse_gnu_properties) - { - enum elf_property_kind kind - = bed->parse_gnu_properties (abfd, type, ptr, datasz); - if (kind == property_corrupt) - { - /* Clear all properties. */ - elf_properties (abfd) = NULL; - return FALSE; - } - else if (kind != property_ignored) - goto next; - } - } - else - { - switch (type) - { - case GNU_PROPERTY_STACK_SIZE: - if (datasz != align_size) - { - _bfd_error_handler - (_("warning: %B: corrupt stack size: 0x%x"), - abfd, datasz); - /* Clear all properties. */ - elf_properties (abfd) = NULL; - return FALSE; - } - prop = _bfd_elf_get_property (abfd, type, datasz); - if (datasz == 8) - prop->u.number = bfd_h_get_64 (abfd, ptr); - else - prop->u.number = bfd_h_get_32 (abfd, ptr); - prop->pr_kind = property_number; - goto next; - - case GNU_PROPERTY_NO_COPY_ON_PROTECTED: - if (datasz != 0) - { - _bfd_error_handler - (_("warning: %B: corrupt no copy on protected size: 0x%x"), - abfd, datasz); - /* Clear all properties. */ - elf_properties (abfd) = NULL; - return FALSE; - } - prop = _bfd_elf_get_property (abfd, type, datasz); - elf_has_no_copy_on_protected (abfd) = TRUE; - prop->pr_kind = property_number; - goto next; - - default: - break; - } - } - - _bfd_error_handler - (_("warning: %B: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"), - abfd, note->type, type); - -next: - ptr += (datasz + (align_size - 1)) & ~ (align_size - 1); - } - - return TRUE; -} - -/* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE - if APROP is updated. Otherwise, return TRUE if BPROP should be merged - with ABFD. */ - -static bfd_boolean -elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, - elf_property *aprop, elf_property *bprop) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; - - if (bed->merge_gnu_properties != NULL - && pr_type >= GNU_PROPERTY_LOPROC - && pr_type < GNU_PROPERTY_LOUSER) - return bed->merge_gnu_properties (info, abfd, aprop, bprop); - - switch (pr_type) - { - case GNU_PROPERTY_STACK_SIZE: - if (aprop != NULL && bprop != NULL) - { - if (bprop->u.number > aprop->u.number) - { - aprop->u.number = bprop->u.number; - return TRUE; - } - break; - } - /* FALLTHROUGH */ - - case GNU_PROPERTY_NO_COPY_ON_PROTECTED: - /* Return TRUE if APROP is NULL to indicate that BPROP should - be added to ABFD. */ - return aprop == NULL; - - default: - /* Never should happen. */ - abort (); - } - - return FALSE; -} - -/* Return the property of TYPE on *LISTP and remove it from *LISTP. - Return NULL if not found. */ - -static elf_property * -elf_find_and_remove_property (elf_property_list **listp, - unsigned int type) -{ - elf_property_list *list; - - for (list = *listp; list; list = list->next) - { - if (type == list->property.pr_type) - { - /* Remove this property. */ - *listp = list->next; - return &list->property; - } - else if (type < list->property.pr_type) - break; - listp = &list->next; - } - - return NULL; -} - -/* Merge GNU property list *LISTP with ABFD. */ - -static void -elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *abfd, - elf_property_list **listp) -{ - elf_property_list *p, **lastp; - elf_property *pr; - - /* Merge each GNU property in ABFD with the one on *LISTP. */ - lastp = &elf_properties (abfd); - for (p = *lastp; p; p = p->next) - { - pr = elf_find_and_remove_property (listp, p->property.pr_type); - /* Pass NULL to elf_merge_gnu_properties for the property which - isn't on *LISTP. */ - elf_merge_gnu_properties (info, abfd, &p->property, pr); - if (p->property.pr_kind == property_remove) - { - /* Remove this property. */ - *lastp = p->next; - continue; - } - lastp = &p->next; - } - - /* Merge the remaining properties on *LISTP with ABFD. */ - for (p = *listp; p != NULL; p = p->next) - if (elf_merge_gnu_properties (info, abfd, NULL, &p->property)) - { - if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED) - elf_has_no_copy_on_protected (abfd) = TRUE; - - pr = _bfd_elf_get_property (abfd, p->property.pr_type, - p->property.pr_datasz); - /* It must be a new property. */ - if (pr->pr_kind != property_unknown) - abort (); - /* Add a new property. */ - *pr = p->property; - } -} - -/* Set up GNU properties. Return the first relocatable ELF input with - GNU properties if found. Otherwise, return NULL. */ - -bfd * -_bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) -{ - bfd *abfd, *first_pbfd = NULL; - elf_property_list *list; - asection *sec; - bfd_boolean has_properties = FALSE; - const struct elf_backend_data *bed - = get_elf_backend_data (info->output_bfd); - unsigned int elfclass = bed->s->elfclass; - int elf_machine_code = bed->elf_machine_code; - - /* Find the first relocatable ELF input with GNU properties. */ - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && (abfd->flags & DYNAMIC) == 0 - && elf_properties (abfd) != NULL) - { - has_properties = TRUE; - - /* Ignore GNU properties from ELF objects with different machine - code or class. Also skip objects without a GNU_PROPERTY note - section. */ - if ((elf_machine_code - == get_elf_backend_data (abfd)->elf_machine_code) - && (elfclass - == get_elf_backend_data (abfd)->s->elfclass) - && bfd_get_section_by_name (abfd, - NOTE_GNU_PROPERTY_SECTION_NAME) != NULL - ) - { - /* Keep .note.gnu.property section in FIRST_PBFD. */ - first_pbfd = abfd; - break; - } - } - - /* Do nothing if there is no .note.gnu.property section. */ - if (!has_properties) - return NULL; - - /* Merge .note.gnu.property sections. */ - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) - if (abfd != first_pbfd && (abfd->flags & DYNAMIC) == 0) - { - elf_property_list *null_ptr = NULL; - elf_property_list **listp = &null_ptr; - - /* Merge .note.gnu.property section in relocatable ELF input. */ - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) - { - list = elf_properties (abfd); - - /* Ignore GNU properties from ELF objects with different - machine code. */ - if (list != NULL - && (elf_machine_code - == get_elf_backend_data (abfd)->elf_machine_code)) - listp = &elf_properties (abfd); - } - else - list = NULL; - - /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL - when all properties are from ELF objects with different - machine code or class. */ - if (first_pbfd != NULL) - elf_merge_gnu_property_list (info, first_pbfd, listp); - - if (list != NULL) - { - /* Discard the .note.gnu.property section in this bfd. */ - sec = bfd_get_section_by_name (abfd, - NOTE_GNU_PROPERTY_SECTION_NAME); - if (sec != NULL) - sec->output_section = bfd_abs_section_ptr; - } - } - - /* Rewrite .note.gnu.property section so that GNU properties are - always sorted by type even if input GNU properties aren't sorted. */ - if (first_pbfd != NULL) - { - unsigned int size; - unsigned int descsz; - bfd_byte *contents; - Elf_External_Note *e_note; - unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; - - sec = bfd_get_section_by_name (first_pbfd, - NOTE_GNU_PROPERTY_SECTION_NAME); - BFD_ASSERT (sec != NULL); - - /* Update stack size in .note.gnu.property with -z stack-size=N - if N > 0. */ - if (info->stacksize > 0) - { - elf_property *p; - bfd_vma stacksize = info->stacksize; - - p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, - align_size); - if (p->pr_kind == property_unknown) - { - /* Create GNU_PROPERTY_STACK_SIZE. */ - p->u.number = stacksize; - p->pr_kind = property_number; - } - else if (stacksize > p->u.number) - p->u.number = stacksize; - } - else if (elf_properties (first_pbfd) == NULL) - { - /* Discard .note.gnu.property section if all properties have - been removed. */ - sec->output_section = bfd_abs_section_ptr; - return NULL; - } - - /* Compute the section size. */ - descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); - descsz = (descsz + 3) & -(unsigned int) 4; - size = descsz; - for (list = elf_properties (first_pbfd); - list != NULL; - list = list->next) - { - /* There are 4 byte type + 4 byte datasz for each property. */ - size += 4 + 4 + list->property.pr_datasz; - /* Align each property. */ - size = (size + (align_size - 1)) & ~(align_size - 1); - } - - /* Update .note.gnu.property section now. */ - sec->size = size; - contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); - - e_note = (Elf_External_Note *) contents; - bfd_h_put_32 (first_pbfd, sizeof "GNU", &e_note->namesz); - bfd_h_put_32 (first_pbfd, size - descsz, &e_note->descsz); - bfd_h_put_32 (first_pbfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type); - memcpy (e_note->name, "GNU", sizeof "GNU"); - - size = descsz; - for (list = elf_properties (first_pbfd); - list != NULL; - list = list->next) - { - /* There are 4 byte type + 4 byte datasz for each property. */ - bfd_h_put_32 (first_pbfd, list->property.pr_type, - contents + size); - bfd_h_put_32 (first_pbfd, list->property.pr_datasz, - contents + size + 4); - size += 4 + 4; - - /* Write out property value. */ - switch (list->property.pr_kind) - { - case property_number: - switch (list->property.pr_datasz) - { - default: - /* Never should happen. */ - abort (); - - case 0: - break; - - case 4: - bfd_h_put_32 (first_pbfd, list->property.u.number, - contents + size); - break; - - case 8: - bfd_h_put_64 (first_pbfd, list->property.u.number, - contents + size); - break; - } - break; - - default: - /* Never should happen. */ - abort (); - } - size += list->property.pr_datasz; - - /* Align each property. */ - size = (size + (align_size - 1)) & ~ (align_size - 1); - } - - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - - /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data - symbol is defined in the shared object. */ - if (elf_has_no_copy_on_protected (first_pbfd)) - info->extern_protected_data = FALSE; - } - - return first_pbfd; -} diff --git a/sdcc/support/sdbinutils/bfd/elf-s390-common.c b/sdcc/support/sdbinutils/bfd/elf-s390-common.c deleted file mode 100644 index 4aa666622..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-s390-common.c +++ /dev/null @@ -1,317 +0,0 @@ -/* IBM S/390-specific support for ELF 32 and 64 bit functions - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Andreas Krebbel. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - - -/* Return TRUE if H is an IFUNC symbol. Simply checking for the - symbol type might not be enough since it might get changed to - STT_FUNC for pointer equality reasons. */ -static inline bfd_boolean -s390_is_ifunc_symbol_p (struct elf_link_hash_entry *h) -{ - struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h; - return h->type == STT_GNU_IFUNC || eh->ifunc_resolver_address != 0; -} - -/* Create sections needed by STT_GNU_IFUNC symbol. */ - -static bfd_boolean -s390_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (htab->iplt != NULL) - return TRUE; - - flags = bed->dynamic_sec_flags; - - if (bfd_link_pic (info)) - { - s = bfd_make_section_with_flags (abfd, ".rela.ifunc", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->irelifunc = s; - } - - /* Create .iplt, .rel[a].iplt, and .igot.plt. */ - s = bfd_make_section_with_flags (abfd, ".iplt", - flags | SEC_CODE | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - htab->iplt = s; - - s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->irelplt = s; - - s = bfd_make_section_with_flags (abfd, ".igot.plt", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->igotplt = s; - - return TRUE; -} - - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs against a STT_GNU_IFUNC symbol definition. */ - -static bfd_boolean -s390_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - struct elf_link_hash_table *htab; - struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h; - struct elf_dyn_relocs **head = &eh->dyn_relocs; - - htab = elf_hash_table (info); - eh->ifunc_resolver_address = h->root.u.def.value; - eh->ifunc_resolver_section = h->root.u.def.section; - - /* Support garbage collection against STT_GNU_IFUNC symbols. */ - if (h->plt.refcount <= 0 && h->got.refcount <= 0) - { - /* When building shared library, we need to handle the case - where it is marked with regular reference, but not non-GOT - reference. It may happen if we didn't see STT_GNU_IFUNC - symbol at the time when checking relocations. */ - if (bfd_link_pic (info) - && !h->non_got_ref - && h->ref_regular) - for (p = *head; p != NULL; p = p->next) - if (p->count) - { - h->non_got_ref = 1; - goto keep; - } - - h->got = htab->init_got_offset; - h->plt = htab->init_plt_offset; - *head = NULL; - return TRUE; - } - - /* Return and discard space for dynamic relocations against it if - it is never referenced in a non-shared object. */ - if (!h->ref_regular) - { - if (h->plt.refcount > 0 - || h->got.refcount > 0) - abort (); - h->got = htab->init_got_offset; - h->plt = htab->init_plt_offset; - *head = NULL; - return TRUE; - } - -keep: - /* Without checking h->plt.refcount here we allocate a PLT slot. - When setting plt.refcount in check_relocs it might not have been - known that this will be an IFUNC symol. */ - h->plt.offset = htab->iplt->size; - h->needs_plt = 1; - htab->iplt->size += PLT_ENTRY_SIZE; - htab->igotplt->size += GOT_ENTRY_SIZE; - htab->irelplt->size += RELA_ENTRY_SIZE; - htab->irelplt->reloc_count++; - - /* In order to make pointer equality work with IFUNC symbols defined - in a non-PIE executable and referenced in a shared lib, we turn - the symbol into a STT_FUNC symbol and make the symbol value to - point to the IPLT slot. That way the referencing shared lib will - always get the PLT slot address when resolving the respective - R_390_GLOB_DAT/R_390_64 relocs on that symbol. */ - if (bfd_link_pde (info) - && h->def_regular - && h->ref_dynamic) - { - h->root.u.def.section = htab->iplt; - h->root.u.def.value = h->plt.offset; - h->size = PLT_ENTRY_SIZE; - h->type = STT_FUNC; - } - - if (!bfd_link_pic (info)) - *head = NULL; - - /* Finally, allocate space. */ - p = *head; - if (p != NULL) - { - bfd_size_type count = 0; - do - { - count += p->count; - p = p->next; - } - while (p != NULL); - htab->irelifunc->size += count * RELA_ENTRY_SIZE; - } - - /* Decide whether the got.iplt slot can be used. This has to be - avoided if the values in the GOT slots could differ for pointer - equality reasons. */ - if (h->got.refcount <= 0 - || (bfd_link_pic (info) - && (h->dynindx == -1 || h->forced_local)) - || bfd_link_pie (info) - || htab->sgot == NULL) - { - /* Use .got.iplt. */ - h->got.offset = (bfd_vma) -1; - } - else - { - h->got.offset = htab->sgot->size; - htab->sgot->size += GOT_ENTRY_SIZE; - if (bfd_link_pic (info)) - htab->srelgot->size += RELA_ENTRY_SIZE; - } - - return TRUE; -} - -static bfd_boolean -elf_s390_allocate_local_syminfo (bfd *abfd, Elf_Internal_Shdr *symtab_hdr) -{ - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= (sizeof (bfd_signed_vma) /* local got */ - + sizeof (struct plt_entry) /* local plt */ - + sizeof(char)); /* local tls type */ - elf_local_got_refcounts (abfd) = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); - if (elf_local_got_refcounts (abfd) == NULL) - return FALSE; - elf_s390_local_plt (abfd) - = (struct plt_entry*)(elf_local_got_refcounts (abfd) - + symtab_hdr->sh_info); - elf_s390_local_got_tls_type (abfd) - = (char *) (elf_s390_local_plt (abfd) + symtab_hdr->sh_info); - - return TRUE; -} - -/* Pick ELFOSABI_GNU if IFUNC symbols are used. */ - -static bfd_boolean -elf_s390_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp ATTRIBUTE_UNUSED, - bfd_vma *valp ATTRIBUTE_UNUSED) -{ - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - return TRUE; -} - -/* Whether to sort relocs output by ld -r or ld --emit-relocs, by - r_offset. Don't do so for code sections. We want to keep ordering - of GDCALL / PLT32DBL for TLS optimizations as is. On the other - hand, elf-eh-frame.c processing requires .eh_frame relocs to be - sorted. */ - -static bfd_boolean -elf_s390_elf_sort_relocs_p (asection *sec) -{ - return (sec->flags & SEC_CODE) == 0; -} - -/* Merge object attributes from IBFD into OBFD. Raise an error if - there are conflicting attributes. */ -static bfd_boolean -elf_s390_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - obj_attribute *in_attr, *in_attrs; - obj_attribute *out_attr, *out_attrs; - - if (!elf_known_obj_attributes_proc (obfd)[0].i) - { - /* This is the first object. Copy the attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - /* Use the Tag_null value to indicate the attributes have been - initialized. */ - elf_known_obj_attributes_proc (obfd)[0].i = 1; - - return TRUE; - } - - in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; - out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; - - /* Check for conflicting Tag_GNU_S390_ABI_Vector attributes and - merge non-conflicting ones. */ - in_attr = &in_attrs[Tag_GNU_S390_ABI_Vector]; - out_attr = &out_attrs[Tag_GNU_S390_ABI_Vector]; - - if (in_attr->i > 2) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses unknown vector ABI %d"), ibfd, - in_attr->i); - else if (out_attr->i > 2) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses unknown vector ABI %d"), obfd, - out_attr->i); - else if (in_attr->i != out_attr->i) - { - out_attr->type = ATTR_TYPE_FLAG_INT_VAL; - - if (in_attr->i && out_attr->i) - { - const char abi_str[3][9] = { "none", "software", "hardware" }; - - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses vector %s ABI, %B uses %s ABI"), - ibfd, abi_str[in_attr->i], obfd, abi_str[out_attr->i]); - } - if (in_attr->i > out_attr->i) - out_attr->i = in_attr->i; - } - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - _bfd_elf_merge_object_attributes (ibfd, info); - - return TRUE; -} diff --git a/sdcc/support/sdbinutils/bfd/elf-s390.h b/sdcc/support/sdbinutils/bfd/elf-s390.h deleted file mode 100644 index 1bcb2bffa..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-s390.h +++ /dev/null @@ -1,29 +0,0 @@ -/* S/390-specific support for ELF. - Copyright (C) 2017-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* Used to pass info between ld and bfd. */ -struct s390_elf_params -{ - /* Tell the kernel to allocate 4k page tables. */ - int pgste; -}; - -bfd_boolean bfd_elf_s390_set_options (struct bfd_link_info *info, - struct s390_elf_params *params); diff --git a/sdcc/support/sdbinutils/bfd/elf-strtab.c b/sdcc/support/sdbinutils/bfd/elf-strtab.c deleted file mode 100644 index 3905a150c..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-strtab.c +++ /dev/null @@ -1,446 +0,0 @@ -/* ELF strtab with GC and suffix merging support. - Copyright (C) 2001-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "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. */ - size_t size; - /* Number of array entries alloced. */ - size_t 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 = (struct bfd_hash_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 = (struct elf_strtab_hash *) 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 = ((struct elf_strtab_hash_entry **) - bfd_malloc (table->alloced * amt)); - if (table->array == NULL) - { - free (table); - return NULL; - } - - table->array[0] = NULL; - - return table; -} - -/* Free a strtab. */ - -void -_bfd_elf_strtab_free (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. */ - -size_t -_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 (size_t) -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 = (struct elf_strtab_hash_entry **) - bfd_realloc_or_free (tab->array, tab->alloced * amt); - if (tab->array == NULL) - return (size_t) -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, size_t idx) -{ - if (idx == 0 || idx == (size_t) -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, size_t idx) -{ - if (idx == 0 || idx == (size_t) -1) - return; - BFD_ASSERT (tab->sec_size == 0); - BFD_ASSERT (idx < tab->size); - BFD_ASSERT (tab->array[idx]->refcount > 0); - --tab->array[idx]->refcount; -} - -unsigned int -_bfd_elf_strtab_refcount (struct elf_strtab_hash *tab, size_t idx) -{ - return tab->array[idx]->refcount; -} - -void -_bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab) -{ - size_t idx; - - for (idx = 1; idx < tab->size; idx++) - tab->array[idx]->refcount = 0; -} - -/* Save strtab refcounts prior to adding --as-needed library. */ - -struct strtab_save -{ - size_t size; - unsigned int refcount[1]; -}; - -void * -_bfd_elf_strtab_save (struct elf_strtab_hash *tab) -{ - struct strtab_save *save; - size_t idx, size; - - size = sizeof (*save) + (tab->size - 1) * sizeof (save->refcount[0]); - save = bfd_malloc (size); - if (save == NULL) - return save; - - save->size = tab->size; - for (idx = 1; idx < tab->size; idx++) - save->refcount[idx] = tab->array[idx]->refcount; - return save; -} - -/* Restore strtab refcounts on finding --as-needed library not needed. */ - -void -_bfd_elf_strtab_restore (struct elf_strtab_hash *tab, void *buf) -{ - size_t idx, curr_size = tab->size; - struct strtab_save *save = (struct strtab_save *) buf; - - BFD_ASSERT (tab->sec_size == 0); - BFD_ASSERT (save->size <= curr_size); - tab->size = save->size; - for (idx = 1; idx < save->size; ++idx) - tab->array[idx]->refcount = save->refcount[idx]; - - for (; idx < curr_size; ++idx) - { - /* We don't remove entries from the hash table, just set their - REFCOUNT to zero. Setting LEN zero will result in the size - growing if the entry is added again. See _bfd_elf_strtab_add. */ - tab->array[idx]->refcount = 0; - tab->array[idx]->len = 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, size_t 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; - size_t 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 amt, sec_size; - size_t size, i; - - /* Sort the strings by suffix and length. */ - amt = tab->size; - amt *= sizeof (struct elf_strtab_hash_entry *); - array = (struct elf_strtab_hash_entry **) 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. */ - sec_size = 1; - for (i = 1; i < tab->size; ++i) - { - e = tab->array[i]; - if (e->refcount && e->len > 0) - { - e->u.index = sec_size; - sec_size += e->len; - } - } - - tab->sec_size = sec_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/sdcc/support/sdbinutils/bfd/elf-vxworks.c b/sdcc/support/sdbinutils/bfd/elf-vxworks.c deleted file mode 100644 index 32b08e4bd..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-vxworks.c +++ /dev/null @@ -1,299 +0,0 @@ -/* VxWorks support for ELF - Copyright (C) 2005-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* This file provides routines used by all VxWorks targets. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf-vxworks.h" -#include "elf/vxworks.h" - -/* Return true if symbol NAME, as defined by ABFD, is one of the special - __GOTT_BASE__ or __GOTT_INDEX__ symbols. */ - -static bfd_boolean -elf_vxworks_gott_symbol_p (bfd *abfd, const char *name) -{ - char leading; - - leading = bfd_get_symbol_leading_char (abfd); - if (leading) - { - if (*name != leading) - return FALSE; - name++; - } - return (strcmp (name, "__GOTT_BASE__") == 0 - || strcmp (name, "__GOTT_INDEX__") == 0); -} - -/* Tweak magic VxWorks symbols as they are loaded. */ -bfd_boolean -elf_vxworks_add_symbol_hook (bfd *abfd, - 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 ((bfd_link_pic (info) || abfd->flags & DYNAMIC) - && elf_vxworks_gott_symbol_p (abfd, *namep)) - { - 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 (!bfd_link_pic (info)) - { - s = bfd_make_section_anyway_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. */ -int -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) -{ - /* Reverse the effects of the hack in elf_vxworks_add_symbol_hook. */ - if (h - && h->root.type == bfd_link_hash_undefweak - && elf_vxworks_gott_symbol_p (h->root.u.undef.abfd, name)) - sym->st_info = ELF_ST_INFO (STB_GLOBAL, ELF_ST_TYPE (sym->st_info)); - - return 1; -} - -/* Copy relocations into the output file. Fixes up relocations against 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; - int j; - - bed = get_elf_backend_data (output_bfd); - - if (output_bfd->flags & (DYNAMIC|EXEC_P)) - { - Elf_Internal_Rela *irela; - Elf_Internal_Rela *irelaend; - struct elf_link_hash_entry **hash_ptr; - - for (irela = internal_relocs, - irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) - * bed->s->int_rels_per_ext_rel), - hash_ptr = rel_hash; - irela < irelaend; - irela += bed->s->int_rels_per_ext_rel, - hash_ptr++) - { - if (*hash_ptr - && (*hash_ptr)->def_dynamic - && !(*hash_ptr)->def_regular - && ((*hash_ptr)->root.type == bfd_link_hash_defined - || (*hash_ptr)->root.type == bfd_link_hash_defweak) - && (*hash_ptr)->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 = (*hash_ptr)->root.u.def.section; - int this_idx = sec->output_section->target_index; - - irela[j].r_info - = ELF32_R_INFO (this_idx, ELF32_R_TYPE (irela[j].r_info)); - irela[j].r_addend += (*hash_ptr)->root.u.def.value; - irela[j].r_addend += sec->output_offset; - } - /* Stop the generic routine adjusting this entry. */ - *hash_ptr = NULL; - } - } - } - 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_onesymtab (abfd); - sec = bfd_get_section_by_name (abfd, ".plt"); - if (sec) - d->this_hdr.sh_info = elf_section_data (sec)->this_idx; -} - -/* Add the dynamic entries required by VxWorks. These point to the - tls sections. */ - -bfd_boolean -elf_vxworks_add_dynamic_entries (bfd *output_bfd, struct bfd_link_info *info) -{ - if (bfd_get_section_by_name (output_bfd, ".tls_data")) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_START, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_SIZE, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_DATA_ALIGN, 0)) - return FALSE; - } - if (bfd_get_section_by_name (output_bfd, ".tls_vars")) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_START, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_VX_WRS_TLS_VARS_SIZE, 0)) - return FALSE; - } - return TRUE; -} - -/* If *DYN is one of the VxWorks-specific dynamic entries, then fill - in the value now and return TRUE. Otherwise return FALSE. */ - -bfd_boolean -elf_vxworks_finish_dynamic_entry (bfd *output_bfd, Elf_Internal_Dyn *dyn) -{ - asection *sec; - - switch (dyn->d_tag) - { - default: - return FALSE; - - case DT_VX_WRS_TLS_DATA_START: - sec = bfd_get_section_by_name (output_bfd, ".tls_data"); - dyn->d_un.d_ptr = sec->vma; - break; - - case DT_VX_WRS_TLS_DATA_SIZE: - sec = bfd_get_section_by_name (output_bfd, ".tls_data"); - dyn->d_un.d_val = sec->size; - break; - - case DT_VX_WRS_TLS_DATA_ALIGN: - sec = bfd_get_section_by_name (output_bfd, ".tls_data"); - dyn->d_un.d_val - = (bfd_size_type)1 << bfd_get_section_alignment (output_bfd, - sec); - break; - - case DT_VX_WRS_TLS_VARS_START: - sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); - dyn->d_un.d_ptr = sec->vma; - break; - - case DT_VX_WRS_TLS_VARS_SIZE: - sec = bfd_get_section_by_name (output_bfd, ".tls_vars"); - dyn->d_un.d_val = sec->size; - break; - } - return TRUE; -} - - diff --git a/sdcc/support/sdbinutils/bfd/elf-vxworks.h b/sdcc/support/sdbinutils/bfd/elf-vxworks.h deleted file mode 100644 index 72a19e469..000000000 --- a/sdcc/support/sdbinutils/bfd/elf-vxworks.h +++ /dev/null @@ -1,36 +0,0 @@ -/* VxWorks support for ELF - Copyright (C) 2005-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#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 **); -bfd_boolean elf_vxworks_add_dynamic_entries (bfd *, struct bfd_link_info *); -bfd_boolean elf_vxworks_finish_dynamic_entry (bfd *, Elf_Internal_Dyn *); - diff --git a/sdcc/support/sdbinutils/bfd/elf32-am33lin.c b/sdcc/support/sdbinutils/bfd/elf32-am33lin.c deleted file mode 100644 index d1438a22f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-am33lin.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Matsushita AM33/2.0 support for 32-bit GNU/Linux ELF - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "elf-bfd.h" -#include "elf/mn10300.h" - -#define elf_symbol_leading_char 0 - -#define TARGET_LITTLE_SYM am33_elf32_linux_vec -#define TARGET_LITTLE_NAME "elf32-am33lin" -#define ELF_ARCH bfd_arch_mn10300 -#define ELF_MACHINE_CODE EM_MN10300 -#define ELF_MACHINE_ALT1 EM_CYGNUS_MN10300 -#define ELF_MAXPAGESIZE 0x1000 - -/* Rename global functions. */ -#define _bfd_mn10300_elf_merge_private_bfd_data _bfd_am33_elf_merge_private_bfd_data -#define _bfd_mn10300_elf_object_p _bfd_am33_elf_object_p -#define _bfd_mn10300_elf_final_write_processing _bfd_am33_elf_final_write_processing - -/* Support for core dump NOTE sections. */ -static bfd_boolean -elf32_am33lin_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 184: - case 188: /* Linux/am33 */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 112; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", size, - note->descpos + offset); -} - -static bfd_boolean -elf32_am33lin_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/am33 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; -} - -#define elf_backend_grok_prstatus elf32_am33lin_grok_prstatus -#define elf_backend_grok_psinfo elf32_am33lin_grok_psinfo - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf-m10300.c" diff --git a/sdcc/support/sdbinutils/bfd/elf32-arc.c b/sdcc/support/sdbinutils/bfd/elf32-arc.c deleted file mode 100644 index 5921cc252..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-arc.c +++ /dev/null @@ -1,2962 +0,0 @@ -/* ARC-specific support for 32-bit ELF - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Contributed by Cupertino Miranda (cmiranda@synopsys.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/arc.h" -#include "libiberty.h" -#include "opcode/arc-func.h" -#include "opcode/arc.h" -#include "arc-plt.h" - -#define FEATURE_LIST_NAME bfd_feature_list -#define CONFLICT_LIST bfd_conflict_list -#include "opcode/arc-attrs.h" - -/* #define ARC_ENABLE_DEBUG 1 */ -#ifdef ARC_ENABLE_DEBUG -static const char * -name_for_global_symbol (struct elf_link_hash_entry *h) -{ - static char *local_str = "(local)"; - if (h == NULL) - return local_str; - return h->root.root.string; -} -#define ARC_DEBUG(fmt, args...) fprintf (stderr, fmt, ##args) -#else -#define ARC_DEBUG(...) -#endif - - -#define ADD_RELA(BFD, SECTION, OFFSET, SYM_IDX, TYPE, ADDEND) \ - { \ - struct elf_link_hash_table *_htab = elf_hash_table (info); \ - Elf_Internal_Rela _rel; \ - bfd_byte * _loc; \ - \ - if (_htab->dynamic_sections_created == TRUE) \ - { \ - BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \ - _loc = _htab->srel##SECTION->contents \ - + ((_htab->srel##SECTION->reloc_count) \ - * sizeof (Elf32_External_Rela)); \ - _htab->srel##SECTION->reloc_count++; \ - _rel.r_addend = ADDEND; \ - _rel.r_offset = (_htab->s##SECTION)->output_section->vma \ - + (_htab->s##SECTION)->output_offset + OFFSET; \ - BFD_ASSERT ((long) SYM_IDX != -1); \ - _rel.r_info = ELF32_R_INFO (SYM_IDX, TYPE); \ - bfd_elf32_swap_reloca_out (BFD, &_rel, _loc); \ - } \ - } - - -/* The default symbols representing the init and fini dyn values. - TODO: Check what is the relation of those strings with arclinux.em - and DT_INIT. */ -#define INIT_SYM_STRING "_init" -#define FINI_SYM_STRING "_fini" - -char * init_str = INIT_SYM_STRING; -char * fini_str = FINI_SYM_STRING; - -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - case VALUE: \ - return "R_" #TYPE; \ - break; - -static ATTRIBUTE_UNUSED const char * -reloc_type_to_name (unsigned int type) -{ - switch (type) - { - #include "elf/arc-reloc.def" - - default: - return "UNKNOWN"; - break; - } -} -#undef ARC_RELOC_HOWTO - -/* Try to minimize the amount of space occupied by relocation tables - on the ROM (not that the ROM won't be swamped by other ELF overhead). */ - -#define USE_REL 1 - -static ATTRIBUTE_UNUSED bfd_boolean -is_reloc_PC_relative (reloc_howto_type *howto) -{ - return (strstr (howto->name, "PC") != NULL) ? TRUE : FALSE; -} - -static bfd_boolean -is_reloc_SDA_relative (reloc_howto_type *howto) -{ - return (strstr (howto->name, "SDA") != NULL) ? TRUE : FALSE; -} - -static bfd_boolean -is_reloc_for_GOT (reloc_howto_type * howto) -{ - if (strstr (howto->name, "TLS") != NULL) - return FALSE; - return (strstr (howto->name, "GOT") != NULL) ? TRUE : FALSE; -} - -static bfd_boolean -is_reloc_for_PLT (reloc_howto_type * howto) -{ - return (strstr (howto->name, "PLT") != NULL) ? TRUE : FALSE; -} - -static bfd_boolean -is_reloc_for_TLS (reloc_howto_type *howto) -{ - return (strstr (howto->name, "TLS") != NULL) ? TRUE : FALSE; -} - -struct arc_relocation_data -{ - bfd_signed_vma reloc_offset; - bfd_signed_vma reloc_addend; - bfd_signed_vma got_offset_value; - - bfd_signed_vma sym_value; - asection * sym_section; - - reloc_howto_type *howto; - - asection * input_section; - - bfd_signed_vma sdata_begin_symbol_vma; - bfd_boolean sdata_begin_symbol_vma_set; - bfd_signed_vma got_symbol_vma; - - bfd_boolean should_relocate; - - const char * symbol_name; -}; - -/* Should be included at this location due to static declarations - * defined before this point. */ -#include "arc-got.h" - -#define arc_bfd_get_8(A,B,C) bfd_get_8(A,B) -#define arc_bfd_get_16(A,B,C) bfd_get_16(A,B) -#define arc_bfd_get_32(A,B,C) bfd_get_32(A,B) -#define arc_bfd_put_8(A,B,C,D) bfd_put_8(A,B,C) -#define arc_bfd_put_16(A,B,C,D) bfd_put_16(A,B,C) -#define arc_bfd_put_32(A,B,C,D) bfd_put_32(A,B,C) - - -static bfd_reloc_status_type -arc_elf_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol_in, - void *data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char ** error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - { - reloc_entry->address += input_section->output_offset; - - /* In case of relocateable link and if the reloc is against a - section symbol, the addend needs to be adjusted according to - where the section symbol winds up in the output section. */ - if ((symbol_in->flags & BSF_SECTION_SYM) && symbol_in->section) - reloc_entry->addend += symbol_in->section->output_offset; - - return bfd_reloc_ok; - } - - return bfd_reloc_continue; -} - - -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - TYPE = VALUE, -enum howto_list -{ -#include "elf/arc-reloc.def" - HOWTO_LIST_LAST -}; -#undef ARC_RELOC_HOWTO - -#define ARC_RELOC_HOWTO(TYPE, VALUE, RSIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - [TYPE] = HOWTO (R_##TYPE, 0, RSIZE, BITSIZE, FALSE, 0, \ - complain_overflow_##OVERFLOW, arc_elf_reloc, \ - "R_" #TYPE, FALSE, 0, 0, FALSE), - -static struct reloc_howto_struct elf_arc_howto_table[] = -{ -#include "elf/arc-reloc.def" -/* Example of what is generated by the preprocessor. Currently kept as an - example. - HOWTO (R_ARC_NONE, // Type. - 0, // Rightshift. - 2, // Size (0 = byte, 1 = short, 2 = long). - 32, // Bitsize. - FALSE, // PC_relative. - 0, // Bitpos. - complain_overflow_bitfield, // Complain_on_overflow. - bfd_elf_generic_reloc, // Special_function. - "R_ARC_NONE", // Name. - TRUE, // Partial_inplace. - 0, // Src_mask. - 0, // Dst_mask. - FALSE), // PCrel_offset. -*/ -}; -#undef ARC_RELOC_HOWTO - -static void arc_elf_howto_init (void) -{ -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - elf_arc_howto_table[TYPE].pc_relative = \ - (strstr (#FORMULA, " P ") != NULL || strstr (#FORMULA, " PDATA ") != NULL); \ - elf_arc_howto_table[TYPE].dst_mask = RELOC_FUNCTION(0, ~0); \ - /* Only 32 bit data relocations should be marked as ME. */ \ - if (strstr (#FORMULA, " ME ") != NULL) \ - { \ - BFD_ASSERT (SIZE == 2); \ - } - -#include "elf/arc-reloc.def" - -} -#undef ARC_RELOC_HOWTO - - -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - [TYPE] = VALUE, -const int howto_table_lookup[] = -{ -#include "elf/arc-reloc.def" -}; -#undef ARC_RELOC_HOWTO - -static reloc_howto_type * -arc_elf_howto (unsigned int r_type) -{ - if (elf_arc_howto_table[R_ARC_32].dst_mask == 0) - arc_elf_howto_init (); - return &elf_arc_howto_table[r_type]; -} - -/* Map BFD reloc types to ARC ELF reloc types. */ - -struct arc_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -/* ARC ELF linker hash entry. */ -struct elf_arc_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; -}; - -/* ARC ELF linker hash table. */ -struct elf_arc_link_hash_table -{ - struct elf_link_hash_table elf; -}; - -static struct bfd_hash_entry * -elf_arc_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 = (struct bfd_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_arc_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_arc_link_hash_entry *eh; - - eh = (struct elf_arc_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - } - - return entry; -} - -/* Destroy an ARC ELF linker hash table. */ -static void -elf_arc_link_hash_table_free (bfd *obfd) -{ - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create an ARC ELF linker hash table. */ - -static struct bfd_link_hash_table * -arc_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_arc_link_hash_table *ret; - - ret = (struct elf_arc_link_hash_table *) bfd_zmalloc (sizeof (*ret)); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - elf_arc_link_hash_newfunc, - sizeof (struct elf_arc_link_hash_entry), - ARC_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->elf.init_got_refcount.refcount = 0; - ret->elf.init_got_refcount.glist = NULL; - ret->elf.init_got_offset.offset = 0; - ret->elf.init_got_offset.glist = NULL; - - ret->elf.root.hash_table_free = elf_arc_link_hash_table_free; - - return &ret->elf.root; -} - -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - { BFD_RELOC_##TYPE, R_##TYPE }, -static const struct arc_reloc_map arc_reloc_map[] = -{ -#include "elf/arc-reloc.def" - - {BFD_RELOC_NONE, R_ARC_NONE}, - {BFD_RELOC_8, R_ARC_8}, - {BFD_RELOC_16, R_ARC_16}, - {BFD_RELOC_24, R_ARC_24}, - {BFD_RELOC_32, R_ARC_32}, -}; -#undef ARC_RELOC_HOWTO - -typedef ATTRIBUTE_UNUSED bfd_vma (*replace_func) (unsigned, int ATTRIBUTE_UNUSED); - -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - case TYPE: \ - func = (void *) RELOC_FUNCTION; \ - break; -static replace_func -get_replace_function (bfd *abfd, unsigned int r_type) -{ - void *func = NULL; - - switch (r_type) - { - #include "elf/arc-reloc.def" - } - - if (func == replace_bits24 && bfd_big_endian (abfd)) - return (replace_func) replace_bits24_be; - - return (replace_func) func; -} -#undef ARC_RELOC_HOWTO - -static reloc_howto_type * -arc_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (arc_reloc_map); i--;) - { - if (arc_reloc_map[i].bfd_reloc_val == code) - return arc_elf_howto (arc_reloc_map[i].elf_reloc_val); - } - - return NULL; -} - -/* Function to set the ELF flag bits. */ -static bfd_boolean -arc_elf_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Print private flags. */ -static bfd_boolean -arc_elf_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (unsigned long) flags); - - switch (flags & EF_ARC_MACH_MSK) - { - case EF_ARC_CPU_ARCV2HS : fprintf (file, " -mcpu=ARCv2HS"); break; - case EF_ARC_CPU_ARCV2EM : fprintf (file, " -mcpu=ARCv2EM"); break; - case E_ARC_MACH_ARC600 : fprintf (file, " -mcpu=ARC600"); break; - case E_ARC_MACH_ARC601 : fprintf (file, " -mcpu=ARC601"); break; - case E_ARC_MACH_ARC700 : fprintf (file, " -mcpu=ARC700"); break; - default: - fprintf (file, "-mcpu=unknown"); - break; - } - - switch (flags & EF_ARC_OSABI_MSK) - { - case E_ARC_OSABI_ORIG : fprintf (file, " (ABI:legacy)"); break; - case E_ARC_OSABI_V2 : fprintf (file, " (ABI:v2)"); break; - case E_ARC_OSABI_V3 : fprintf (file, " (ABI:v3)"); break; - case E_ARC_OSABI_V4 : fprintf (file, " (ABI:v4)"); break; - default: - fprintf (file, " (ABI:unknown)"); - break; - } - - fputc ('\n', file); - return TRUE; -} - -/* Copy backend specific data from one object module to another. */ - -static bfd_boolean -arc_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - BFD_ASSERT (!elf_flags_init (obfd) - || elf_elfheader (obfd)->e_flags == elf_elfheader (ibfd)->e_flags); - - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - elf_flags_init (obfd) = TRUE; - - /* Copy object attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - return _bfd_elf_copy_private_bfd_data (ibfd, obfd); -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd * abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf_arc_howto_table); i++) - if (elf_arc_howto_table[i].name != NULL - && strcasecmp (elf_arc_howto_table[i].name, r_name) == 0) - return arc_elf_howto (i); - - return NULL; -} - -/* Set the howto pointer for an ARC ELF reloc. */ - -static void -arc_info_to_howto_rel (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - BFD_ASSERT (r_type < (unsigned int) R_ARC_max); - cache_ptr->howto = arc_elf_howto (r_type); -} - -/* Extract CPU features from an NTBS. */ - -static unsigned -arc_extract_features (const char *p) -{ - unsigned i, r = 0; - - if (!p) - return 0; - - for (i = 0; i < ARRAY_SIZE (bfd_feature_list); i++) - { - char *t = strstr (p, bfd_feature_list[i].attr); - unsigned l = strlen (bfd_feature_list[i].attr); - if ((t != NULL) - && (t[l] == ',' - || t[l] == '\0')) - r |= bfd_feature_list[i].feature; - } - - return r; -} - -/* Concatenate two strings. s1 can be NULL but not - s2. */ - -static char * -arc_stralloc (char * s1, const char * s2) -{ - char *p; - - /* Only s1 can be null. */ - BFD_ASSERT (s2); - - p = s1 ? concat (s1, ",", s2, NULL) : (char *)s2; - - return p; -} - -/* Merge ARC object attributes from IBFD into OBFD. Raise an error if - there are conflicting attributes. */ - -static bfd_boolean -arc_elf_merge_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - obj_attribute *in_attr; - obj_attribute *out_attr; - int i; - bfd_boolean result = TRUE; - const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section; - char *tagname = NULL; - - /* Skip the linker stubs file. This preserves previous behavior - of accepting unknown attributes in the first input file - but - is that a bug? */ - if (ibfd->flags & BFD_LINKER_CREATED) - return TRUE; - - /* Skip any input that hasn't attribute section. - This enables to link object files without attribute section with - any others. */ - if (bfd_get_section_by_name (ibfd, sec_name) == NULL) - return TRUE; - - if (!elf_known_obj_attributes_proc (obfd)[0].i) - { - /* This is the first object. Copy the attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - out_attr = elf_known_obj_attributes_proc (obfd); - - /* Use the Tag_null value to indicate the attributes have been - initialized. */ - out_attr[0].i = 1; - - return TRUE; - } - - in_attr = elf_known_obj_attributes_proc (ibfd); - out_attr = elf_known_obj_attributes_proc (obfd); - - for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) - { - /* Merge this attribute with existing attributes. */ - switch (i) - { - case Tag_ARC_PCS_config: - if (out_attr[i].i == 0) - out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i) - { - const char *tagval[] = { "Absent", "Bare-metal/mwdt", - "Bare-metal/newlib", "Linux/uclibc", - "Linux/glibc" }; - BFD_ASSERT (in_attr[i].i < 5); - BFD_ASSERT (out_attr[i].i < 5); - /* It's sometimes ok to mix different configs, so this is only - a warning. */ - _bfd_error_handler - (_("Warning: %B: Conflicting platform configuration " - "%s with %s.\n"), ibfd, - tagval[in_attr[i].i], - tagval[out_attr[i].i]); - } - break; - - case Tag_ARC_CPU_base: - if (out_attr[i].i == 0) - out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i - && ((out_attr[i].i + in_attr[i].i) < 6)) - { - const char *tagval[] = { "Absent", "ARC6xx", "ARC7xx", - "ARCEM", "ARCHS" }; - BFD_ASSERT (in_attr[i].i < 5); - BFD_ASSERT (out_attr[i].i < 5); - /* We cannot mix code for different CPUs. */ - _bfd_error_handler - (_("error: %B: unable to merge CPU base attributes " - "%s with %s.\n"), - obfd, - tagval[in_attr[i].i], - tagval[out_attr[i].i]); - result = FALSE; - break; - } - else - { - /* The CPUs may be different, check if we can still mix - the objects against the output choosen CPU. */ - unsigned in_feature = 0; - unsigned out_feature = 0; - char *p1 = in_attr[Tag_ARC_ISA_config].s; - char *p2 = out_attr[Tag_ARC_ISA_config].s; - unsigned j; - unsigned cpu_out; - unsigned opcode_map[] = {0, ARC_OPCODE_ARC600, ARC_OPCODE_ARC700, - ARC_OPCODE_ARCv2EM, ARC_OPCODE_ARCv2HS}; - - BFD_ASSERT (in_attr[i].i < (sizeof (opcode_map) - / sizeof (unsigned))); - BFD_ASSERT (out_attr[i].i < (sizeof (opcode_map) - / sizeof (unsigned))); - cpu_out = opcode_map[out_attr[i].i]; - - in_feature = arc_extract_features (p1); - out_feature = arc_extract_features (p2); - - /* First, check if a feature is compatible with the - output object chosen CPU. */ - for (j = 0; j < ARRAY_SIZE (bfd_feature_list); j++) - if (((in_feature | out_feature) & bfd_feature_list[j].feature) - && (!(cpu_out & bfd_feature_list[j].cpus))) - { - _bfd_error_handler - (_("error: %B: unable to merge ISA extension attributes " - "%s.\n"), - obfd, bfd_feature_list[j].name); - result = FALSE; - break; - } - /* Second, if we have compatible features with the - chosen CPU, check if they are compatible among - them. */ - for (j = 0; j < ARRAY_SIZE (bfd_conflict_list); j++) - if (((in_feature | out_feature) & bfd_conflict_list[j]) - == bfd_conflict_list[j]) - { - unsigned k; - for (k = 0; k < ARRAY_SIZE (bfd_feature_list); k++) - { - if (in_feature & bfd_feature_list[k].feature - & bfd_conflict_list[j]) - p1 = (char *) bfd_feature_list[k].name; - if (out_feature & bfd_feature_list[k].feature - & bfd_conflict_list[j]) - p2 = (char *) bfd_feature_list[k].name; - } - _bfd_error_handler - (_("error: %B: conflicting ISA extension attributes " - "%s with %s.\n"), - obfd, p1, p2); - result = FALSE; - break; - } - /* Everithing is alright. */ - out_feature |= in_feature; - p1 = NULL; - for (j = 0; j < ARRAY_SIZE (bfd_feature_list); j++) - if (out_feature & bfd_feature_list[j].feature) - p1 = arc_stralloc (p1, bfd_feature_list[j].attr); - if (p1) - out_attr[Tag_ARC_ISA_config].s = - _bfd_elf_attr_strdup (obfd, p1); - } - /* Fall through. */ - case Tag_ARC_CPU_variation: - case Tag_ARC_ISA_mpy_option: - case Tag_ARC_ABI_osver: - /* Use the largest value specified. */ - if (in_attr[i].i > out_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_ARC_CPU_name: - break; - - case Tag_ARC_ABI_rf16: - if (out_attr[i].i == 0) - out_attr[i].i = in_attr[i].i; - else if (out_attr[i].i != in_attr[i].i) - { - /* We cannot mix code with rf16 and without. */ - _bfd_error_handler - (_("error: %B: cannot mix rf16 with full register set %B.\n"), - obfd, ibfd); - result = FALSE; - } - break; - - case Tag_ARC_ABI_pic: - tagname = "PIC"; - /* fall through */ - case Tag_ARC_ABI_sda: - if (!tagname) - tagname = "SDA"; - /* fall through */ - case Tag_ARC_ABI_tls: - { - const char *tagval[] = { "Absent", "MWDT", "GNU" }; - - if (!tagname) - tagname = "TLS"; - - BFD_ASSERT (in_attr[i].i < 3); - BFD_ASSERT (out_attr[i].i < 3); - if (out_attr[i].i != 0 && in_attr[i].i != 0 - && out_attr[i].i != in_attr[i].i) - { - _bfd_error_handler - (_("error: %B: conflicting attributes %s: %s with %s.\n"), - obfd, tagname, - tagval[in_attr[i].i], - tagval[out_attr[i].i]); - result = FALSE; - } - tagname = NULL; - break; - } - - case Tag_ARC_ABI_double_size: - tagname = "Double size"; - /* fall through */ - case Tag_ARC_ABI_enumsize: - if (!tagname) - tagname = "Enum size"; - /* fall through */ - case Tag_ARC_ABI_exceptions: - if (!tagname) - tagname = "ABI exceptions"; - - if (out_attr[i].i != 0 && in_attr[i].i != 0 - && out_attr[i].i != in_attr[i].i) - { - _bfd_error_handler - (_("error: %B: conflicting attributes %s.\n"), - obfd, tagname); - result = FALSE; - } - break; - - case Tag_ARC_ISA_apex: - break; /* Do nothing for APEX attributes. */ - - case Tag_ARC_ISA_config: - /* It is handled in Tag_ARC_CPU_base. */ - break; - - default: - result - = result && _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i); - } - - /* If out_attr was copied from in_attr then it won't have a type yet. */ - if (in_attr[i].type && !out_attr[i].type) - out_attr[i].type = in_attr[i].type; - } - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - if (!_bfd_elf_merge_object_attributes (ibfd, info)) - return FALSE; - - /* Check for any attributes not known on ARC. */ - result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd); - - return result; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -arc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - unsigned short mach_ibfd; - static unsigned short mach_obfd = EM_NONE; - flagword out_flags; - flagword in_flags; - asection *sec; - - /* Check if we have the same endianess. */ - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - /* Collect ELF flags. */ - in_flags = elf_elfheader (ibfd)->e_flags & EF_ARC_MACH_MSK; - out_flags = elf_elfheader (obfd)->e_flags & EF_ARC_MACH_MSK; - - if (!elf_flags_init (obfd)) /* First call, no flags set. */ - { - elf_flags_init (obfd) = TRUE; - out_flags = in_flags; - } - - if (!arc_elf_merge_attributes (ibfd, info)) - return FALSE; - - /* Check to see if the input BFD actually contains any sections. Do - not short-circuit dynamic objects; their section list may be - emptied by elf_link_add_object_symbols. */ - if (!(ibfd->flags & DYNAMIC)) - { - bfd_boolean null_input_bfd = TRUE; - bfd_boolean only_data_sections = TRUE; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - if ((bfd_get_section_flags (ibfd, sec) - & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) - == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) - only_data_sections = FALSE; - - null_input_bfd = FALSE; - } - - if (null_input_bfd || only_data_sections) - return TRUE; - } - - /* Complain about various flag/architecture mismatches. */ - mach_ibfd = elf_elfheader (ibfd)->e_machine; - if (mach_obfd == EM_NONE) - { - mach_obfd = mach_ibfd; - } - else - { - if (mach_ibfd != mach_obfd) - { - /* xgettext:c-format */ - _bfd_error_handler (_("ERROR: Attempting to link %B " - "with a binary %B of different architecture"), - ibfd, obfd); - return FALSE; - } - else if ((in_flags != out_flags) - /* If we have object attributes, then we already - checked the objects compatibility, skip it. */ - && !bfd_elf_get_obj_attr_int (ibfd, OBJ_ATTR_PROC, - Tag_ARC_CPU_base)) - { - /* Warn if different flags. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields than " - "previous modules (%#x)"), - ibfd, in_flags, out_flags); - if (in_flags && out_flags) - return FALSE; - /* MWDT doesnt set the eflags hence make sure we choose the - eflags set by gcc. */ - in_flags = in_flags > out_flags ? in_flags : out_flags; - } - else - { - /* Everything is correct; don't change the output flags. */ - in_flags = out_flags; - } - } - - /* Update the flags. */ - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_mach (obfd) < bfd_get_mach (ibfd)) - { - return bfd_set_arch_mach (obfd, bfd_arch_arc, bfd_get_mach (ibfd)); - } - - return TRUE; -} - -/* Return a best guess for the machine number based on the attributes. */ - -static unsigned int -bfd_arc_get_mach_from_attributes (bfd * abfd) -{ - int arch = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, Tag_ARC_CPU_base); - unsigned e_machine = elf_elfheader (abfd)->e_machine; - - switch (arch) - { - case TAG_CPU_ARC6xx: - return bfd_mach_arc_arc600; - case TAG_CPU_ARC7xx: - return bfd_mach_arc_arc700; - case TAG_CPU_ARCEM: - case TAG_CPU_ARCHS: - return bfd_mach_arc_arcv2; - default: - break; - } - return (e_machine == EM_ARC_COMPACT) - ? bfd_mach_arc_arc700 : bfd_mach_arc_arcv2; -} - -/* Set the right machine number for an ARC ELF file. */ -static bfd_boolean -arc_elf_object_p (bfd * abfd) -{ - /* Make sure this is initialised, or you'll have the potential of passing - garbage---or misleading values---into the call to - bfd_default_set_arch_mach (). */ - unsigned int mach = bfd_mach_arc_arc700; - unsigned long arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH_MSK; - unsigned e_machine = elf_elfheader (abfd)->e_machine; - - if (e_machine == EM_ARC_COMPACT || e_machine == EM_ARC_COMPACT2) - { - switch (arch) - { - case E_ARC_MACH_ARC600: - mach = bfd_mach_arc_arc600; - break; - case E_ARC_MACH_ARC601: - mach = bfd_mach_arc_arc601; - break; - case E_ARC_MACH_ARC700: - mach = bfd_mach_arc_arc700; - break; - case EF_ARC_CPU_ARCV2HS: - case EF_ARC_CPU_ARCV2EM: - mach = bfd_mach_arc_arcv2; - break; - default: - mach = bfd_arc_get_mach_from_attributes (abfd); - break; - } - } - else - { - if (e_machine == EM_ARC) - { - _bfd_error_handler - (_("Error: The ARC4 architecture is no longer supported.\n")); - return FALSE; - } - else - { - _bfd_error_handler - (_("Warning: unset or old architecture flags. \n" - " Use default machine.\n")); - } - } - - return bfd_default_set_arch_mach (abfd, bfd_arch_arc, mach); -} - -/* The final processing done just before writing out an ARC ELF object file. - This gets the ARC architecture right based on the machine number. */ - -static void -arc_elf_final_write_processing (bfd * abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long emf; - int osver = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, - Tag_ARC_ABI_osver); - flagword e_flags = elf_elfheader (abfd)->e_flags & ~EF_ARC_OSABI_MSK; - - switch (bfd_get_mach (abfd)) - { - case bfd_mach_arc_arc600: - emf = EM_ARC_COMPACT; - break; - case bfd_mach_arc_arc601: - emf = EM_ARC_COMPACT; - break; - case bfd_mach_arc_arc700: - emf = EM_ARC_COMPACT; - break; - case bfd_mach_arc_arcv2: - emf = EM_ARC_COMPACT2; - break; - default: - return; - } - - elf_elfheader (abfd)->e_machine = emf; - - /* Record whatever is the current syscall ABI version. */ - if (osver) - e_flags |= ((osver & 0x0f) << 8); - else - e_flags |= E_ARC_OSABI_V3; - - elf_elfheader (abfd)->e_flags |= e_flags; -} - -#ifdef ARC_ENABLE_DEBUG -#define DEBUG_ARC_RELOC(A) debug_arc_reloc (A) - -static void -debug_arc_reloc (struct arc_relocation_data reloc_data) -{ - ARC_DEBUG ("Reloc type=%s, should_relocate = %s\n", - reloc_data.howto->name, - reloc_data.should_relocate ? "true" : "false"); - ARC_DEBUG (" offset = 0x%x, addend = 0x%x\n", - (unsigned int) reloc_data.reloc_offset, - (unsigned int) reloc_data.reloc_addend); - ARC_DEBUG (" Symbol:\n"); - ARC_DEBUG (" value = 0x%08x\n", - (unsigned int) reloc_data.sym_value); - if (reloc_data.sym_section != NULL) - { - ARC_DEBUG (" Symbol Section:\n"); - ARC_DEBUG (" section name = %s, output_offset 0x%08x", - reloc_data.sym_section->name, - (unsigned int) reloc_data.sym_section->output_offset); - if (reloc_data.sym_section->output_section != NULL) - ARC_DEBUG (", output_section->vma = 0x%08x", - ((unsigned int) reloc_data.sym_section->output_section->vma)); - ARC_DEBUG ("\n"); - if (reloc_data.sym_section->owner && reloc_data.sym_section->owner->filename) - ARC_DEBUG (" file: %s\n", reloc_data.sym_section->owner->filename); - } - else - { - ARC_DEBUG (" symbol section is NULL\n"); - } - - ARC_DEBUG (" Input_section:\n"); - if (reloc_data.input_section != NULL) - { - ARC_DEBUG (" section name = %s, output_offset 0x%08x, output_section->vma = 0x%08x\n", - reloc_data.input_section->name, - (unsigned int) reloc_data.input_section->output_offset, - (unsigned int) reloc_data.input_section->output_section->vma); - ARC_DEBUG (" changed_address = 0x%08x\n", - (unsigned int) (reloc_data.input_section->output_section->vma - + reloc_data.input_section->output_offset - + reloc_data.reloc_offset)); - ARC_DEBUG (" file: %s\n", reloc_data.input_section->owner->filename); - } - else - { - ARC_DEBUG (" input section is NULL\n"); - } -} -#else -#define DEBUG_ARC_RELOC(A) -#endif /* ARC_ENABLE_DEBUG */ - -static bfd_vma -middle_endian_convert (bfd_vma insn, bfd_boolean do_it) -{ - if (do_it) - { - insn - = ((insn & 0xffff0000) >> 16) - | ((insn & 0xffff) << 16); - } - return insn; -} - -/* This function is called for relocations that are otherwise marked as NOT - requiring overflow checks. In here we perform non-standard checks of - the relocation value. */ - -static inline bfd_reloc_status_type -arc_special_overflow_checks (const struct arc_relocation_data reloc_data, - bfd_signed_vma relocation, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - switch (reloc_data.howto->type) - { - case R_ARC_NPS_CMEM16: - if (((relocation >> 16) & 0xffff) != NPS_CMEM_HIGH_VALUE) - { - if (reloc_data.reloc_addend == 0) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): CMEM relocation to `%s' is invalid, " - "16 MSB should be %#x (value is %#Lx)"), - reloc_data.input_section->owner, - reloc_data.input_section, - reloc_data.reloc_offset, - reloc_data.symbol_name, - NPS_CMEM_HIGH_VALUE, - relocation); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): CMEM relocation to `%s+%#Lx' is invalid, " - "16 MSB should be %#x (value is %#Lx)"), - reloc_data.input_section->owner, - reloc_data.input_section, - reloc_data.reloc_offset, - reloc_data.symbol_name, - reloc_data.reloc_addend, - NPS_CMEM_HIGH_VALUE, - relocation); - return bfd_reloc_overflow; - } - break; - - default: - break; - } - - return bfd_reloc_ok; -} - -#define ME(reloc) (reloc) - -#define IS_ME(FORMULA,BFD) ((strstr (FORMULA, "ME") != NULL) \ - && (!bfd_big_endian (BFD))) - -#define S ((bfd_signed_vma) (reloc_data.sym_value \ - + (reloc_data.sym_section->output_section != NULL ? \ - (reloc_data.sym_section->output_offset \ - + reloc_data.sym_section->output_section->vma) : 0))) -#define L ((bfd_signed_vma) (reloc_data.sym_value \ - + (reloc_data.sym_section->output_section != NULL ? \ - (reloc_data.sym_section->output_offset \ - + reloc_data.sym_section->output_section->vma) : 0))) -#define A (reloc_data.reloc_addend) -#define B (0) -#define G (reloc_data.got_offset_value) -#define GOT (reloc_data.got_symbol_vma) -#define GOT_BEGIN (htab->sgot->output_section->vma) - -#define MES (0) - /* P: relative offset to PCL The offset should be to the - current location aligned to 32 bits. */ -#define P ((bfd_signed_vma) ( \ - ( \ - (reloc_data.input_section->output_section != NULL ? \ - reloc_data.input_section->output_section->vma : 0) \ - + reloc_data.input_section->output_offset \ - + (reloc_data.reloc_offset - (bitsize >= 32 ? 4 : 0))) \ - & ~0x3)) -#define PDATA ((bfd_signed_vma) ( \ - (reloc_data.input_section->output_section->vma \ - + reloc_data.input_section->output_offset \ - + (reloc_data.reloc_offset)))) -#define SECTSTART (bfd_signed_vma) (reloc_data.sym_section->output_section->vma \ - + reloc_data.sym_section->output_offset) -#define JLI (bfd_signed_vma) (reloc_data.sym_section->output_section->vma) -#define _SDA_BASE_ (bfd_signed_vma) (reloc_data.sdata_begin_symbol_vma) -#define TLS_REL (bfd_signed_vma) \ - ((elf_hash_table (info))->tls_sec->output_section->vma) -#define TLS_TBSS (8) - -#define none (0) - -#ifdef ARC_ENABLE_DEBUG -#define PRINT_DEBUG_RELOC_INFO_BEFORE(FORMULA, TYPE) \ - do \ - { \ - asection *sym_section = reloc_data.sym_section; \ - asection *input_section = reloc_data.input_section; \ - ARC_DEBUG ("RELOC_TYPE = " TYPE "\n"); \ - ARC_DEBUG ("FORMULA = " FORMULA "\n"); \ - ARC_DEBUG ("S = %#lx\n", S); \ - ARC_DEBUG ("A = %#lx\n", A); \ - ARC_DEBUG ("L = %lx\n", L); \ - if (sym_section->output_section != NULL) \ - ARC_DEBUG ("symbol_section->vma = %#lx\n", \ - sym_section->output_section->vma \ - + sym_section->output_offset); \ - else \ - ARC_DEBUG ("symbol_section->vma = NULL\n"); \ - if (input_section->output_section != NULL) \ - ARC_DEBUG ("symbol_section->vma = %#lx\n", \ - input_section->output_section->vma \ - + input_section->output_offset); \ - else \ - ARC_DEBUG ("symbol_section->vma = NULL\n"); \ - ARC_DEBUG ("PCL = %#lx\n", P); \ - ARC_DEBUG ("P = %#lx\n", P); \ - ARC_DEBUG ("G = %#lx\n", G); \ - ARC_DEBUG ("SDA_OFFSET = %#lx\n", _SDA_BASE_); \ - ARC_DEBUG ("SDA_SET = %d\n", reloc_data.sdata_begin_symbol_vma_set); \ - ARC_DEBUG ("GOT_OFFSET = %#lx\n", GOT); \ - ARC_DEBUG ("relocation = %#08lx\n", relocation); \ - ARC_DEBUG ("before = %#08x\n", (unsigned) insn); \ - ARC_DEBUG ("data = %08x (%u) (%d)\n", (unsigned) relocation, \ - (unsigned) relocation, (int) relocation); \ - } \ - while (0) - -#define PRINT_DEBUG_RELOC_INFO_AFTER \ - do \ - { \ - ARC_DEBUG ("after = 0x%08x\n", (unsigned int) insn); \ - } \ - while (0) - -#else - -#define PRINT_DEBUG_RELOC_INFO_BEFORE(...) -#define PRINT_DEBUG_RELOC_INFO_AFTER - -#endif /* ARC_ENABLE_DEBUG */ - -#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \ - case R_##TYPE: \ - { \ - bfd_signed_vma bitsize ATTRIBUTE_UNUSED = BITSIZE; \ - relocation = FORMULA ; \ - PRINT_DEBUG_RELOC_INFO_BEFORE (#FORMULA, #TYPE); \ - insn = middle_endian_convert (insn, IS_ME (#FORMULA, abfd)); \ - insn = (* get_replace_function (abfd, TYPE)) (insn, relocation); \ - insn = middle_endian_convert (insn, IS_ME (#FORMULA, abfd)); \ - PRINT_DEBUG_RELOC_INFO_AFTER; \ - } \ - break; - -static bfd_reloc_status_type -arc_do_relocation (bfd_byte * contents, - struct arc_relocation_data reloc_data, - struct bfd_link_info *info) -{ - bfd_signed_vma relocation = 0; - bfd_vma insn; - bfd_vma orig_insn ATTRIBUTE_UNUSED; - bfd * abfd = reloc_data.input_section->owner; - struct elf_link_hash_table *htab ATTRIBUTE_UNUSED = elf_hash_table (info); - bfd_reloc_status_type flag; - - if (!reloc_data.should_relocate) - return bfd_reloc_ok; - - switch (reloc_data.howto->size) - { - case 2: - insn = arc_bfd_get_32 (abfd, - contents + reloc_data.reloc_offset, - reloc_data.input_section); - break; - case 1: - insn = arc_bfd_get_16 (abfd, - contents + reloc_data.reloc_offset, - reloc_data.input_section); - break; - case 0: - insn = arc_bfd_get_8 (abfd, - contents + reloc_data.reloc_offset, - reloc_data.input_section); - break; - default: - insn = 0; - BFD_ASSERT (0); - break; - } - - orig_insn = insn; - - switch (reloc_data.howto->type) - { -#include "elf/arc-reloc.def" - - default: - BFD_ASSERT (0); - break; - } - - /* Check for relocation overflow. */ - if (reloc_data.howto->complain_on_overflow != complain_overflow_dont) - flag = bfd_check_overflow (reloc_data.howto->complain_on_overflow, - reloc_data.howto->bitsize, - reloc_data.howto->rightshift, - bfd_arch_bits_per_address (abfd), - relocation); - else - flag = arc_special_overflow_checks (reloc_data, relocation, info); - - if (flag != bfd_reloc_ok) - { - ARC_DEBUG ("Relocation overflows !\n"); - DEBUG_ARC_RELOC (reloc_data); - ARC_DEBUG ("Relocation value = signed -> %d, unsigned -> %u" - ", hex -> (0x%08x)\n", - (int) relocation, (unsigned) relocation, (int) relocation); - - return flag; - } - - /* Write updated instruction back to memory. */ - switch (reloc_data.howto->size) - { - case 2: - arc_bfd_put_32 (abfd, insn, - contents + reloc_data.reloc_offset, - reloc_data.input_section); - break; - case 1: - arc_bfd_put_16 (abfd, insn, - contents + reloc_data.reloc_offset, - reloc_data.input_section); - break; - case 0: - arc_bfd_put_8 (abfd, insn, - contents + reloc_data.reloc_offset, - reloc_data.input_section); - break; - default: - ARC_DEBUG ("size = %d\n", reloc_data.howto->size); - BFD_ASSERT (0); - break; - } - - return bfd_reloc_ok; -} -#undef S -#undef A -#undef B -#undef G -#undef GOT -#undef L -#undef MES -#undef P -#undef SECTSTAR -#undef SECTSTART -#undef JLI -#undef _SDA_BASE_ -#undef none - -#undef ARC_RELOC_HOWTO - - -/* Relocate an arc ELF section. - Function : elf_arc_relocate_section - Brief : Relocate an arc section, by handling all the relocations - appearing in that section. - Args : output_bfd : The bfd being written to. - info : Link information. - input_bfd : The input bfd. - input_section : The section being relocated. - contents : contents of the section being relocated. - relocs : List of relocations in the section. - local_syms : is a pointer to the swapped in local symbols. - local_section : is an array giving the section in the input file - corresponding to the st_shndx field of each - local symbol. */ -static bfd_boolean -elf_arc_relocate_section (bfd * output_bfd, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * wrel; - Elf_Internal_Rela * relend; - struct elf_link_hash_table * htab = elf_hash_table (info); - - symtab_hdr = &((elf_tdata (input_bfd))->symtab_hdr); - sym_hashes = elf_sym_hashes (input_bfd); - - rel = wrel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; wrel++, rel++) - { - enum elf_arc_reloc_type r_type; - reloc_howto_type * howto; - unsigned long r_symndx; - struct elf_link_hash_entry * h; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h2; - const char * msg; - bfd_boolean unresolved_reloc = FALSE; - - struct arc_relocation_data reloc_data = - { - .reloc_offset = 0, - .reloc_addend = 0, - .got_offset_value = 0, - .sym_value = 0, - .sym_section = NULL, - .howto = NULL, - .input_section = NULL, - .sdata_begin_symbol_vma = 0, - .sdata_begin_symbol_vma_set = FALSE, - .got_symbol_vma = 0, - .should_relocate = FALSE - }; - - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type >= (int) R_ARC_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - howto = arc_elf_howto (r_type); - - r_symndx = ELF32_R_SYM (rel->r_info); - - /* If we are generating another .o file and the symbol in not - local, skip this relocation. */ - if (bfd_link_relocatable (info)) - { - /* This is a relocateable 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. */ - - /* Checks if this is a local symbol and thus the reloc - might (will??) be against a section symbol. */ - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - sec = local_sections[r_symndx]; - - /* For RELA relocs. Just adjust the addend - value in the relocation entry. */ - rel->r_addend += sec->output_offset + sym->st_value; - - ARC_DEBUG ("local symbols reloc (section=%d %s) seen in %s\n", - (int) r_symndx, local_sections[r_symndx]->name, - __PRETTY_FUNCTION__); - } - } - } - - h2 = elf_link_hash_lookup (elf_hash_table (info), "__SDATA_BEGIN__", - FALSE, FALSE, TRUE); - - if (!reloc_data.sdata_begin_symbol_vma_set - && h2 != NULL && h2->root.type != bfd_link_hash_undefined - && h2->root.u.def.section->output_section != NULL) - /* TODO: Verify this condition. */ - { - reloc_data.sdata_begin_symbol_vma = - (h2->root.u.def.value - + h2->root.u.def.section->output_section->vma); - reloc_data.sdata_begin_symbol_vma_set = TRUE; - } - - reloc_data.input_section = input_section; - reloc_data.howto = howto; - reloc_data.reloc_offset = rel->r_offset; - reloc_data.reloc_addend = rel->r_addend; - - /* This is a final link. */ - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) /* A local symbol. */ - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - } - else - { - bfd_boolean warned, ignored; - bfd_vma relocation ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - /* TODO: This code is repeated from below. We should - clean it and remove duplications. - Sec is used check for discarded sections. - Need to redesign code below. */ - - /* Get the symbol's entry in the symtab. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - /* If we have encountered a definition for this symbol. */ - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - reloc_data.sym_value = h->root.u.def.value; - sec = h->root.u.def.section; - } - } - - /* Clean relocs for symbols in discarded sections. */ - if (sec != NULL && discarded_section (sec)) - { - _bfd_clear_contents (howto, input_bfd, input_section, - contents + rel->r_offset); - rel->r_offset = rel->r_offset; - rel->r_info = 0; - rel->r_addend = 0; - - /* For ld -r, remove relocations in debug sections against - sections defined in discarded sections. Not done for - eh_frame editing code expects to be present. */ - if (bfd_link_relocatable (info) - && (input_section->flags & SEC_DEBUGGING)) - wrel--; - - continue; - } - - if (bfd_link_relocatable (info)) - { - if (wrel != rel) - *wrel = *rel; - continue; - } - - if (r_symndx < symtab_hdr->sh_info) /* A local symbol. */ - { - reloc_data.sym_value = sym->st_value; - reloc_data.sym_section = sec; - reloc_data.symbol_name = - bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - - /* Mergeable section handling. */ - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - asection *msec; - msec = sec; - rel->r_addend = _bfd_elf_rel_local_sym (output_bfd, sym, - &msec, rel->r_addend); - rel->r_addend -= (sec->output_section->vma - + sec->output_offset - + sym->st_value); - rel->r_addend += msec->output_section->vma + msec->output_offset; - - reloc_data.reloc_addend = rel->r_addend; - } - - BFD_ASSERT (htab->sgot != NULL || !is_reloc_for_GOT (howto)); - if (htab->sgot != NULL) - reloc_data.got_symbol_vma = htab->sgot->output_section->vma - + htab->sgot->output_offset; - - reloc_data.should_relocate = TRUE; - } - else /* Global symbol. */ - { - /* FIXME: We should use the RELOC_FOR_GLOBAL_SYMBOL macro - (defined in elf-bfd.h) here. */ - - /* Get the symbol's entry in the symtab. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - { - struct elf_link_hash_entry *h_old = h; - h = (struct elf_link_hash_entry *) h->root.u.i.link; - if (h->got.glist == 0 && h_old->got.glist != h->got.glist) - h->got.glist = h_old->got.glist; - } - - /* TODO: Need to validate what was the intention. */ - /* BFD_ASSERT ((h->dynindx == -1) || (h->forced_local != 0)); */ - reloc_data.symbol_name = h->root.root.string; - - /* If we have encountered a definition for this symbol. */ - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - reloc_data.sym_value = h->root.u.def.value; - reloc_data.sym_section = h->root.u.def.section; - - reloc_data.should_relocate = TRUE; - - if (is_reloc_for_GOT (howto) && !bfd_link_pic (info)) - { - /* TODO: Change it to use arc_do_relocation with - ARC_32 reloc. Try to use ADD_RELA macro. */ - bfd_vma relocation = - reloc_data.sym_value + reloc_data.reloc_addend - + (reloc_data.sym_section->output_section != NULL ? - (reloc_data.sym_section->output_offset - + reloc_data.sym_section->output_section->vma) - : 0); - - BFD_ASSERT (h->got.glist); - bfd_vma got_offset = h->got.glist->offset; - bfd_put_32 (output_bfd, relocation, - htab->sgot->contents + got_offset); - } - if (is_reloc_for_PLT (howto) && h->plt.offset != (bfd_vma) -1) - { - /* TODO: This is repeated up here. */ - reloc_data.sym_value = h->plt.offset; - reloc_data.sym_section = htab->splt; - } - } - else if (h->root.type == bfd_link_hash_undefweak) - { - /* Is weak symbol and has no definition. */ - if (is_reloc_for_GOT (howto)) - { - reloc_data.sym_value = h->root.u.def.value; - reloc_data.sym_section = htab->sgot; - reloc_data.should_relocate = TRUE; - } - else if (is_reloc_for_PLT (howto) - && h->plt.offset != (bfd_vma) -1) - { - /* TODO: This is repeated up here. */ - reloc_data.sym_value = h->plt.offset; - reloc_data.sym_section = htab->splt; - reloc_data.should_relocate = TRUE; - } - else - continue; - } - else - { - if (is_reloc_for_GOT (howto)) - { - reloc_data.sym_value = h->root.u.def.value; - reloc_data.sym_section = htab->sgot; - - reloc_data.should_relocate = TRUE; - } - else if (is_reloc_for_PLT (howto)) - { - /* Fail if it is linking for PIE and the symbol is - undefined. */ - if (bfd_link_executable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_offset, TRUE); - reloc_data.sym_value = h->plt.offset; - reloc_data.sym_section = htab->splt; - - reloc_data.should_relocate = TRUE; - } - else if (!bfd_link_pic (info) || bfd_link_executable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, - rel->r_offset, TRUE); - } - - BFD_ASSERT (htab->sgot != NULL || !is_reloc_for_GOT (howto)); - if (htab->sgot != NULL) - reloc_data.got_symbol_vma = htab->sgot->output_section->vma - + htab->sgot->output_offset; - } - - if ((is_reloc_for_GOT (howto) - || is_reloc_for_TLS (howto))) - { - reloc_data.should_relocate = TRUE; - - struct got_entry **list - = get_got_entry_list_for_symbol (output_bfd, r_symndx, h); - - reloc_data.got_offset_value - = relocate_fix_got_relocs_for_got_info (list, - tls_type_for_reloc (howto), - info, - output_bfd, - r_symndx, - local_syms, - local_sections, - h, - &reloc_data); - - if (h == NULL) - { - create_got_dynrelocs_for_single_entry ( - got_entry_for_type (list, - arc_got_entry_type_for_reloc (howto)), - output_bfd, info, NULL); - } - } - - -#define IS_ARC_PCREL_TYPE(TYPE) \ - ( (TYPE == R_ARC_PC32) \ - || (TYPE == R_ARC_32_PCREL)) - - switch (r_type) - { - case R_ARC_32: - case R_ARC_32_ME: - case R_ARC_PC32: - case R_ARC_32_PCREL: - if (bfd_link_pic (info) - && (!IS_ARC_PCREL_TYPE (r_type) - || (h != NULL - && h->dynindx != -1 - && !h->def_regular - && (!info->symbolic || !h->def_regular)))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip = FALSE; - bfd_boolean relocate = FALSE; - asection *sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, - /*RELA*/ TRUE); - - BFD_ASSERT (sreloc != NULL); - - outrel.r_offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - - outrel.r_addend = rel->r_addend; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - { - memset (&outrel, 0, sizeof outrel); - relocate = FALSE; - } - else if (h != NULL - && h->dynindx != -1 - && (IS_ARC_PCREL_TYPE (r_type) - || !(bfd_link_executable (info) - || SYMBOLIC_BIND (info, h)) - || ! h->def_regular)) - { - BFD_ASSERT (h != NULL); - if ((input_section->flags & SEC_ALLOC) != 0) - relocate = FALSE; - else - relocate = TRUE; - - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - } - else - { - /* Handle local symbols, they either do not have a - global hash table entry (h == NULL), or are - forced local due to a version script - (h->forced_local), or the third condition is - legacy, it appears to say something like, for - links where we are pre-binding the symbols, or - there's not an entry for this symbol in the - dynamic symbol table, and it's a regular symbol - not defined in a shared object, then treat the - symbol as local, resolve it now. */ - relocate = TRUE; - /* outrel.r_addend = 0; */ - outrel.r_info = ELF32_R_INFO (0, R_ARC_RELATIVE); - } - - BFD_ASSERT (sreloc->contents != 0); - - loc = sreloc->contents; - loc += sreloc->reloc_count * sizeof (Elf32_External_Rela); - sreloc->reloc_count += 1; - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - if (!relocate) - continue; - } - break; - default: - break; - } - - if (is_reloc_SDA_relative (howto) - && !reloc_data.sdata_begin_symbol_vma_set) - { - _bfd_error_handler - ("Error: Linker symbol __SDATA_BEGIN__ not found"); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - DEBUG_ARC_RELOC (reloc_data); - - /* Make sure we have with a dynamic linker. In case of GOT and PLT - the sym_section should point to .got or .plt respectively. */ - if ((is_reloc_for_GOT (howto) || is_reloc_for_PLT (howto)) - && reloc_data.sym_section == NULL) - { - _bfd_error_handler - (_("GOT and PLT relocations cannot be fixed with a non dynamic linker.")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - msg = NULL; - switch (arc_do_relocation (contents, reloc_data, info)) - { - case bfd_reloc_ok: - continue; /* The reloc processing loop. */ - - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), reloc_data.symbol_name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, reloc_data.symbol_name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_other: - /* xgettext:c-format */ - msg = _("%B(%A): warning: unaligned access to symbol '%s' in the small data area"); - break; - - case bfd_reloc_outofrange: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: dangerous relocation"); - break; - - default: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: unknown error"); - break; - } - - if (msg) - _bfd_error_handler (msg, input_bfd, input_section, reloc_data.symbol_name); - return FALSE; - } - - return TRUE; -} - -#define elf_arc_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == ARC_ELF_DATA ? ((struct elf_arc_link_hash_table *) ((p)->hash)) : NULL) - -static bfd_boolean -elf_arc_check_relocs (bfd * abfd, - struct bfd_link_info * info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - bfd * dynobj; - asection * sreloc = NULL; - struct elf_link_hash_table * htab = elf_hash_table (info); - - if (bfd_link_relocatable (info)) - return TRUE; - - if (htab->dynobj == NULL) - htab->dynobj = abfd; - - dynobj = (elf_hash_table (info))->dynobj; - symtab_hdr = &((elf_tdata (abfd))->symtab_hdr); - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - enum elf_arc_reloc_type r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type >= (int) R_ARC_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - howto = arc_elf_howto (r_type); - - /* Load symbol information. */ - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) /* Is a local symbol. */ - h = NULL; - else /* Global one. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - switch (r_type) - { - case R_ARC_32: - case R_ARC_32_ME: - /* During shared library creation, these relocs should not - appear in a shared library (as memory will be read only - and the dynamic linker can not resolve these. However - the error should not occur for e.g. debugging or - non-readonly sections. */ - if (h != NULL - && (bfd_link_dll (info) && !bfd_link_pie (info)) - && (sec->flags & SEC_ALLOC) != 0 - && (sec->flags & SEC_READONLY) != 0 - && ((sec->flags & SEC_CODE) != 0 - || (sec->flags & SEC_DEBUGGING) != 0)) - { - const char *name; - if (h) - name = h->root.root.string; - else - /* bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); */ - name = "UNKNOWN"; - _bfd_error_handler - /* xgettext:c-format */ - (_("\ -%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), - abfd, - arc_elf_howto (r_type)->name, - name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* In some cases we are not setting the 'non_got_ref' - flag, even though the relocations don't require a GOT - access. We should extend the testing in this area to - ensure that no significant cases are being missed. */ - if (h) - h->non_got_ref = 1; - /* FALLTHROUGH */ - case R_ARC_PC32: - case R_ARC_32_PCREL: - if ((bfd_link_pic (info)) - && ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL) - || (h != NULL - && (!info->symbolic || !h->def_regular)))) - { - if (sreloc == NULL) - { - if (info->dynamic - && ! htab->dynamic_sections_created - && ! _bfd_elf_link_create_dynamic_sections (abfd, info)) - return FALSE; - sreloc = _bfd_elf_make_dynamic_reloc_section (sec, dynobj, - 2, abfd, - /*rela*/ - TRUE); - - if (sreloc == NULL) - return FALSE; - } - sreloc->size += sizeof (Elf32_External_Rela); - - } - default: - break; - } - - if (is_reloc_for_PLT (howto)) - { - if (h == NULL) - continue; - else - h->needs_plt = 1; - } - - /* Add info to the symbol got_entry_list. */ - if (is_reloc_for_GOT (howto) - || is_reloc_for_TLS (howto)) - { - if (! _bfd_elf_create_got_section (dynobj, info)) - return FALSE; - - arc_fill_got_info_for_reloc ( - arc_got_entry_type_for_reloc (howto), - get_got_entry_list_for_symbol (abfd, r_symndx, h), - info, - h); - } - } - - return TRUE; -} - -#define ELF_DYNAMIC_INTERPRETER "/sbin/ld-uClibc.so" - -static struct plt_version_t * -arc_get_plt_version (struct bfd_link_info *info) -{ - int i; - - for (i = 0; i < 1; i++) - { - ARC_DEBUG ("%d: size1 = %d, size2 = %d\n", i, - (int) plt_versions[i].entry_size, - (int) plt_versions[i].elem_size); - } - - if (bfd_get_mach (info->output_bfd) == bfd_mach_arc_arcv2) - { - if (bfd_link_pic (info)) - return &(plt_versions[ELF_ARCV2_PIC]); - else - return &(plt_versions[ELF_ARCV2_ABS]); - } - else - { - if (bfd_link_pic (info)) - return &(plt_versions[ELF_ARC_PIC]); - else - return &(plt_versions[ELF_ARC_ABS]); - } -} - -static bfd_vma -add_symbol_to_plt (struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - bfd_vma ret; - - struct plt_version_t *plt_data = arc_get_plt_version (info); - - /* If this is the first .plt entry, make room for the special first - entry. */ - if (htab->splt->size == 0) - htab->splt->size += plt_data->entry_size; - - ret = htab->splt->size; - - htab->splt->size += plt_data->elem_size; - ARC_DEBUG ("PLT_SIZE = %d\n", (int) htab->splt->size); - - htab->sgotplt->size += 4; - htab->srelplt->size += sizeof (Elf32_External_Rela); - - return ret; -} - -#define PLT_DO_RELOCS_FOR_ENTRY(ABFD, DS, RELOCS) \ - plt_do_relocs_for_symbol (ABFD, DS, RELOCS, 0, 0) - -static void -plt_do_relocs_for_symbol (bfd *abfd, - struct elf_link_hash_table *htab, - const struct plt_reloc *reloc, - bfd_vma plt_offset, - bfd_vma symbol_got_offset) -{ - while (SYM_ONLY (reloc->symbol) != LAST_RELOC) - { - bfd_vma relocation = 0; - - switch (SYM_ONLY (reloc->symbol)) - { - case SGOT: - relocation - = htab->sgotplt->output_section->vma - + htab->sgotplt->output_offset + symbol_got_offset; - break; - } - relocation += reloc->addend; - - if (IS_RELATIVE (reloc->symbol)) - { - bfd_vma reloc_offset = reloc->offset; - reloc_offset -= (IS_INSN_32 (reloc->symbol)) ? 4 : 0; - reloc_offset -= (IS_INSN_24 (reloc->symbol)) ? 2 : 0; - - relocation -= htab->splt->output_section->vma - + htab->splt->output_offset - + plt_offset + reloc_offset; - } - - /* TODO: being ME is not a property of the relocation but of the - section of which is applying the relocation. */ - if (IS_MIDDLE_ENDIAN (reloc->symbol) && !bfd_big_endian (abfd)) - { - relocation - = ((relocation & 0xffff0000) >> 16) - | ((relocation & 0xffff) << 16); - } - - switch (reloc->size) - { - case 32: - bfd_put_32 (htab->splt->output_section->owner, - relocation, - htab->splt->contents + plt_offset + reloc->offset); - break; - } - - reloc = &(reloc[1]); /* Jump to next relocation. */ - } -} - -static void -relocate_plt_for_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct plt_version_t *plt_data = arc_get_plt_version (info); - struct elf_link_hash_table *htab = elf_hash_table (info); - - bfd_vma plt_index = (h->plt.offset - plt_data->entry_size) - / plt_data->elem_size; - bfd_vma got_offset = (plt_index + 3) * 4; - - ARC_DEBUG ("arc_info: PLT_OFFSET = %#lx, PLT_ENTRY_VMA = %#lx, \ -GOT_ENTRY_OFFSET = %#lx, GOT_ENTRY_VMA = %#lx, for symbol %s\n", - (long) h->plt.offset, - (long) (htab->splt->output_section->vma - + htab->splt->output_offset - + h->plt.offset), - (long) got_offset, - (long) (htab->sgotplt->output_section->vma - + htab->sgotplt->output_offset - + got_offset), - h->root.root.string); - - { - bfd_vma i = 0; - uint16_t *ptr = (uint16_t *) plt_data->elem; - - for (i = 0; i < plt_data->elem_size/2; i++) - { - uint16_t data = ptr[i]; - bfd_put_16 (output_bfd, - (bfd_vma) data, - htab->splt->contents + h->plt.offset + (i*2)); - } - } - - plt_do_relocs_for_symbol (output_bfd, htab, - plt_data->elem_relocs, - h->plt.offset, - got_offset); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (bfd_vma) (htab->splt->output_section->vma - + htab->splt->output_offset), - htab->sgotplt->contents + got_offset); - - /* TODO: Fill in the entry in the .rela.plt section. */ - { - Elf_Internal_Rela rel; - bfd_byte *loc; - - rel.r_offset = (htab->sgotplt->output_section->vma - + htab->sgotplt->output_offset - + got_offset); - rel.r_addend = 0; - - BFD_ASSERT (h->dynindx != -1); - rel.r_info = ELF32_R_INFO (h->dynindx, R_ARC_JMP_SLOT); - - loc = htab->srelplt->contents; - loc += plt_index * sizeof (Elf32_External_Rela); /* relA */ - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } -} - -static void -relocate_plt_for_entry (bfd *abfd, - struct bfd_link_info *info) -{ - struct plt_version_t *plt_data = arc_get_plt_version (info); - struct elf_link_hash_table *htab = elf_hash_table (info); - - { - bfd_vma i = 0; - uint16_t *ptr = (uint16_t *) plt_data->entry; - for (i = 0; i < plt_data->entry_size/2; i++) - { - uint16_t data = ptr[i]; - bfd_put_16 (abfd, - (bfd_vma) data, - htab->splt->contents + (i*2)); - } - } - PLT_DO_RELOCS_FOR_ENTRY (abfd, htab, plt_data->entry_relocs); -} - -/* Desc : 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_arc_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - asection *s; - bfd *dynobj = (elf_hash_table (info))->dynobj; - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (h->type == STT_FUNC - || h->type == STT_GNU_IFUNC - || h->needs_plt == 1) - { - if (!bfd_link_pic (info) && !h->def_dynamic && !h->ref_dynamic) - { - /* 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. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a PC32 - reloc instead. */ - BFD_ASSERT (h->needs_plt); - return TRUE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1 && !h->forced_local - && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - if (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - bfd_vma loc = add_symbol_to_plt (info); - - if (bfd_link_executable (info) && !h->def_regular) - { - h->root.u.def.section = htab->splt; - h->root.u.def.value = loc; - } - h->plt.offset = loc; - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - return TRUE; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (!bfd_link_executable (info)) - return TRUE; - - /* If there are no non-GOT references, we do not need a copy - relocation. */ - 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; - } - - /* 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. */ - - if (htab == NULL) - return FALSE; - - /* We must generate a R_ARC_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - struct elf_arc_link_hash_table *arc_htab = elf_arc_hash_table (info); - - BFD_ASSERT (arc_htab->elf.srelbss != NULL); - arc_htab->elf.srelbss->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - /* TODO: Move this also to arc_hash_table. */ - s = bfd_get_section_by_name (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Function : elf_arc_finish_dynamic_symbol - Brief : Finish up dynamic symbol handling. We set the - contents of various dynamic sections here. - Args : output_bfd : - info : - h : - sym : - Returns : True/False as the return status. */ - -static bfd_boolean -elf_arc_finish_dynamic_symbol (bfd * output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym * sym) -{ - if (h->plt.offset != (bfd_vma) -1) - { - relocate_plt_for_symbol (output_bfd, info, h); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - - /* This function traverses list of GOT entries and - create respective dynamic relocs. */ - /* TODO: Make function to get list and not access the list directly. */ - /* TODO: Move function to relocate_section create this relocs eagerly. */ - create_got_dynrelocs_for_got_info (&h->got.glist, - output_bfd, - info, - h); - - if (h->needs_copy) - { - struct elf_arc_link_hash_table *arc_htab = elf_arc_hash_table (info); - - if (h->dynindx == -1 - || (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - || arc_htab->elf.srelbss == NULL) - abort (); - - bfd_vma rel_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - bfd_byte * loc = arc_htab->elf.srelbss->contents - + (arc_htab->elf.srelbss->reloc_count * sizeof (Elf32_External_Rela)); - arc_htab->elf.srelbss->reloc_count++; - - Elf_Internal_Rela rel; - rel.r_addend = 0; - rel.r_offset = rel_offset; - - BFD_ASSERT (h->dynindx != -1); - rel.r_info = ELF32_R_INFO (h->dynindx, R_ARC_COPY); - - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || strcmp (h->root.root.string, "__DYNAMIC") == 0 - || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -#define GET_SYMBOL_OR_SECTION(TAG, SYMBOL, SECTION) \ - case TAG: \ - if (SYMBOL != NULL) \ - h = elf_link_hash_lookup (elf_hash_table (info), \ - SYMBOL, FALSE, FALSE, TRUE); \ - else if (SECTION != NULL) \ - s = bfd_get_linker_section (dynobj, SECTION); \ - break; - -/* Function : elf_arc_finish_dynamic_sections - Brief : Finish up the dynamic sections handling. - Args : output_bfd : - info : - h : - sym : - Returns : True/False as the return status. */ - -static bfd_boolean -elf_arc_finish_dynamic_sections (bfd * output_bfd, - struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - bfd *dynobj = (elf_hash_table (info))->dynobj; - asection *sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (sdyn) - { - Elf32_External_Dyn *dyncon, *dynconend; - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend - = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn internal_dyn; - bfd_boolean do_it = FALSE; - - struct elf_link_hash_entry *h = NULL; - asection *s = NULL; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &internal_dyn); - - switch (internal_dyn.d_tag) - { - GET_SYMBOL_OR_SECTION (DT_INIT, info->init_function, NULL) - GET_SYMBOL_OR_SECTION (DT_FINI, info->fini_function, NULL) - GET_SYMBOL_OR_SECTION (DT_PLTGOT, NULL, ".plt") - GET_SYMBOL_OR_SECTION (DT_JMPREL, NULL, ".rela.plt") - GET_SYMBOL_OR_SECTION (DT_PLTRELSZ, NULL, ".rela.plt") - GET_SYMBOL_OR_SECTION (DT_VERSYM, NULL, ".gnu.version") - GET_SYMBOL_OR_SECTION (DT_VERDEF, NULL, ".gnu.version_d") - GET_SYMBOL_OR_SECTION (DT_VERNEED, NULL, ".gnu.version_r") - default: - break; - } - - /* In case the dynamic symbols should be updated with a symbol. */ - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - asection *asec_ptr; - - internal_dyn.d_un.d_val = h->root.u.def.value; - asec_ptr = h->root.u.def.section; - if (asec_ptr->output_section != NULL) - { - internal_dyn.d_un.d_val += - (asec_ptr->output_section->vma - + asec_ptr->output_offset); - } - else - { - /* The symbol is imported from another shared - library and does not apply to this one. */ - internal_dyn.d_un.d_val = 0; - } - do_it = TRUE; - } - else if (s != NULL) /* With a section information. */ - { - switch (internal_dyn.d_tag) - { - case DT_PLTGOT: - case DT_JMPREL: - case DT_VERSYM: - case DT_VERDEF: - case DT_VERNEED: - internal_dyn.d_un.d_ptr = (s->output_section->vma - + s->output_offset); - do_it = TRUE; - break; - - case DT_PLTRELSZ: - internal_dyn.d_un.d_val = s->size; - do_it = TRUE; - break; - - default: - break; - } - } - - if (do_it) - bfd_elf32_swap_dyn_out (output_bfd, &internal_dyn, dyncon); - } - - if (htab->splt->size > 0) - { - relocate_plt_for_entry (output_bfd, info); - } - - /* TODO: Validate this. */ - if (htab->srelplt->output_section != bfd_abs_section_ptr) - elf_section_data (htab->srelplt->output_section) - ->this_hdr.sh_entsize = 12; - } - - /* Fill in the first three entries in the global offset table. */ - if (htab->sgot) - { - struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (elf_hash_table (info), "_GLOBAL_OFFSET_TABLE_", - FALSE, FALSE, TRUE); - - if (h != NULL && h->root.type != bfd_link_hash_undefined - && h->root.u.def.section != NULL) - { - asection *sec = h->root.u.def.section; - - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, - sec->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sec->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sec->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sec->contents + 8); - } - } - - return TRUE; -} - -#define ADD_DYNAMIC_SYMBOL(NAME, TAG) \ - h = elf_link_hash_lookup (elf_hash_table (info), \ - NAME, FALSE, FALSE, FALSE); \ - if ((h != NULL && (h->ref_regular || h->def_regular))) \ - if (! _bfd_elf_add_dynamic_entry (info, TAG, 0)) \ - return FALSE; - -/* Set the sizes of the dynamic sections. */ -static bfd_boolean -elf_arc_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean relocs_exist = FALSE; - bfd_boolean reltext_exist = FALSE; - struct elf_link_hash_table *htab = elf_hash_table (info); - - dynobj = htab->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->dynamic_sections_created) - { - struct elf_link_hash_entry *h; - - /* Set the contents of the .interp section to the - interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_section_by_name (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof (ELF_DYNAMIC_INTERPRETER); - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - - /* Add some entries to the .dynamic section. We fill in some of - the values later, in elf_bfd_final_link, but we must add the - entries now so that we know the final size of the .dynamic - section. Checking if the .init section is present. We also - create DT_INIT and DT_FINI entries if the init_str has been - changed by the user. */ - ADD_DYNAMIC_SYMBOL (info->init_function, DT_INIT); - ADD_DYNAMIC_SYMBOL (info->fini_function, DT_FINI); - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - if (htab->srelgot != NULL) - htab->srelgot->size = 0; - } - - 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. */ - } - else if (strncmp (s->name, ".rela", 5) == 0) - { - if (s->size != 0 && s != htab->srelplt) - { - if (!reltext_exist) - { - const char *name = s->name + 5; - bfd *ibfd; - for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) - if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour - && ibfd->flags & DYNAMIC) - { - asection *target = bfd_get_section_by_name (ibfd, name); - if (target != NULL - && elf_section_data (target)->sreloc == s - && ((target->output_section->flags - & (SEC_READONLY | SEC_ALLOC)) - == (SEC_READONLY | SEC_ALLOC))) - { - reltext_exist = TRUE; - break; - } - } - } - relocs_exist = 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) - { - s->flags |= SEC_EXCLUDE; - continue; - } - - if ((s->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (htab->dynamic_sections_created) - { - /* TODO: Check if this is needed. */ - if (!bfd_link_pic (info)) - if (!_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0)) - return FALSE; - - if (htab->splt && (htab->splt->flags & SEC_EXCLUDE) == 0) - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) - return FALSE; - - if (relocs_exist) - if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - - if (reltext_exist) - if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0)) - return FALSE; - } - - return TRUE; -} - - -/* Classify dynamic relocs such that -z combreloc can reorder and combine - them. */ -static enum elf_reloc_type_class -elf32_arc_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_ARC_RELATIVE: - return reloc_class_relative; - case R_ARC_JMP_SLOT: - return reloc_class_plt; - case R_ARC_COPY: - return reloc_class_copy; - /* TODO: Needed in future to support ifunc. */ - /* - case R_ARC_IRELATIVE: - return reloc_class_ifunc; - */ - default: - return reloc_class_normal; - } -} - -const struct elf_size_info arc_elf32_size_info = -{ - sizeof (Elf32_External_Ehdr), - sizeof (Elf32_External_Phdr), - sizeof (Elf32_External_Shdr), - sizeof (Elf32_External_Rel), - sizeof (Elf32_External_Rela), - sizeof (Elf32_External_Sym), - sizeof (Elf32_External_Dyn), - sizeof (Elf_External_Note), - 4, - 1, - 32, 2, - ELFCLASS32, EV_CURRENT, - bfd_elf32_write_out_phdrs, - bfd_elf32_write_shdrs_and_ehdr, - bfd_elf32_checksum_contents, - bfd_elf32_write_relocs, - bfd_elf32_swap_symbol_in, - bfd_elf32_swap_symbol_out, - bfd_elf32_slurp_reloc_table, - bfd_elf32_slurp_symbol_table, - bfd_elf32_swap_dyn_in, - bfd_elf32_swap_dyn_out, - bfd_elf32_swap_reloc_in, - bfd_elf32_swap_reloc_out, - bfd_elf32_swap_reloca_in, - bfd_elf32_swap_reloca_out -}; - -#define elf_backend_size_info arc_elf32_size_info - -/* Hook called by the linker routine which adds symbols from an object - file. */ - -static bfd_boolean -elf_arc_add_symbol_hook (bfd * abfd, - struct bfd_link_info * info, - Elf_Internal_Sym * sym, - const char ** namep ATTRIBUTE_UNUSED, - flagword * flagsp ATTRIBUTE_UNUSED, - asection ** secp ATTRIBUTE_UNUSED, - bfd_vma * valp ATTRIBUTE_UNUSED) -{ - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - return TRUE; -} - -/* GDB expects general purpose registers to be in section .reg. However Linux - kernel doesn't create this section and instead writes registers to NOTE - section. It is up to the binutils to create a pseudo-section .reg from the - contents of NOTE. Also BFD will read pid and signal number from NOTE. This - function relies on offsets inside elf_prstatus structure in Linux to be - stable. */ - -static bfd_boolean -elf32_arc_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 236: /* sizeof (struct elf_prstatus) on Linux/arc. */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - /* pr_regs */ - offset = 72; - size = (40 * 4); /* There are 40 registers in user_regs_struct. */ - break; - } - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", size, - note->descpos + offset); -} - -/* Determine whether an object attribute tag takes an integer, a - string or both. */ - -static int -elf32_arc_obj_attrs_arg_type (int tag) -{ - if (tag == Tag_ARC_CPU_name - || tag == Tag_ARC_ISA_config - || tag == Tag_ARC_ISA_apex) - return ATTR_TYPE_FLAG_STR_VAL; - else if (tag < (Tag_ARC_ISA_mpy_option + 1)) - return ATTR_TYPE_FLAG_INT_VAL; - else - return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; -} - -/* Attribute numbers >=14 can be safely ignored. */ - -static bfd_boolean -elf32_arc_obj_attrs_handle_unknown (bfd *abfd, int tag) -{ - if ((tag & 127) < (Tag_ARC_ISA_mpy_option + 1)) - { - _bfd_error_handler - (_("%B: Unknown mandatory ARC object attribute %d."), - abfd, tag); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - _bfd_error_handler - (_("Warning: %B: Unknown ARC object attribute %d."), - abfd, tag); - return TRUE; - } -} - -/* Handle an ARC specific section when reading an object file. This is - called when bfd_section_from_shdr finds a section with an unknown - type. */ - -static bfd_boolean -elf32_arc_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr * hdr, - const char *name, - int shindex) -{ - switch (hdr->sh_type) - { - case SHT_ARC_ATTRIBUTES: - break; - - default: - return FALSE; - } - - if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - return TRUE; -} - -#define TARGET_LITTLE_SYM arc_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlearc" -#define TARGET_BIG_SYM arc_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bigarc" -#define ELF_ARCH bfd_arch_arc -#define ELF_TARGET_ID ARC_ELF_DATA -#define ELF_MACHINE_CODE EM_ARC_COMPACT -#define ELF_MACHINE_ALT1 EM_ARC_COMPACT2 -#define ELF_MAXPAGESIZE 0x2000 - -#define bfd_elf32_bfd_link_hash_table_create arc_elf_link_hash_table_create - -#define bfd_elf32_bfd_merge_private_bfd_data arc_elf_merge_private_bfd_data -#define bfd_elf32_bfd_reloc_type_lookup arc_elf32_bfd_reloc_type_lookup -#define bfd_elf32_bfd_set_private_flags arc_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data arc_elf_print_private_bfd_data -#define bfd_elf32_bfd_copy_private_bfd_data arc_elf_copy_private_bfd_data - -#define elf_info_to_howto_rel arc_info_to_howto_rel -#define elf_backend_object_p arc_elf_object_p -#define elf_backend_final_write_processing arc_elf_final_write_processing - -#define elf_backend_relocate_section elf_arc_relocate_section -#define elf_backend_check_relocs elf_arc_check_relocs -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections - -#define elf_backend_reloc_type_class elf32_arc_reloc_type_class - -#define elf_backend_adjust_dynamic_symbol elf_arc_adjust_dynamic_symbol -#define elf_backend_finish_dynamic_symbol elf_arc_finish_dynamic_symbol - -#define elf_backend_finish_dynamic_sections elf_arc_finish_dynamic_sections -#define elf_backend_size_dynamic_sections elf_arc_size_dynamic_sections -#define elf_backend_add_symbol_hook elf_arc_add_symbol_hook - -#define elf_backend_can_gc_sections 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_rela_plts_and_copies_p 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_may_use_rel_p 0 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_default_use_rela_p 1 - -#define elf_backend_grok_prstatus elf32_arc_grok_prstatus - -#define elf_backend_default_execstack 0 - -#undef elf_backend_obj_attrs_vendor -#define elf_backend_obj_attrs_vendor "ARC" -#undef elf_backend_obj_attrs_section -#define elf_backend_obj_attrs_section ".ARC.attributes" -#undef elf_backend_obj_attrs_arg_type -#define elf_backend_obj_attrs_arg_type elf32_arc_obj_attrs_arg_type -#undef elf_backend_obj_attrs_section_type -#define elf_backend_obj_attrs_section_type SHT_ARC_ATTRIBUTES -#define elf_backend_obj_attrs_handle_unknown elf32_arc_obj_attrs_handle_unknown - -#define elf_backend_section_from_shdr elf32_arc_section_from_shdr - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-arm.c b/sdcc/support/sdbinutils/bfd/elf32-arm.c deleted file mode 100644 index 0b250cea2..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-arm.c +++ /dev/null @@ -1,19827 +0,0 @@ -/* 32-bit ELF support for ARM - Copyright (C) 1998-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include - -#include "bfd.h" -#include "bfd_stdint.h" -#include "libiberty.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf-nacl.h" -#include "elf-vxworks.h" -#include "elf/arm.h" - -/* Return the relocation section associated with NAME. HTAB is the - bfd's elf32_arm_link_hash_entry. */ -#define RELOC_SECTION(HTAB, NAME) \ - ((HTAB)->use_rel ? ".rel" NAME : ".rela" NAME) - -/* Return size of a relocation entry. HTAB is the bfd's - elf32_arm_link_hash_entry. */ -#define RELOC_SIZE(HTAB) \ - ((HTAB)->use_rel \ - ? sizeof (Elf32_External_Rel) \ - : sizeof (Elf32_External_Rela)) - -/* Return function to swap relocations in. HTAB is the bfd's - elf32_arm_link_hash_entry. */ -#define SWAP_RELOC_IN(HTAB) \ - ((HTAB)->use_rel \ - ? bfd_elf32_swap_reloc_in \ - : bfd_elf32_swap_reloca_in) - -/* Return function to swap relocations out. HTAB is the bfd's - elf32_arm_link_hash_entry. */ -#define SWAP_RELOC_OUT(HTAB) \ - ((HTAB)->use_rel \ - ? bfd_elf32_swap_reloc_out \ - : bfd_elf32_swap_reloca_out) - -#define elf_info_to_howto 0 -#define elf_info_to_howto_rel elf32_arm_info_to_howto - -#define ARM_ELF_ABI_VERSION 0 -#define ARM_ELF_OS_ABI_VERSION ELFOSABI_ARM - -/* The Adjusted Place, as defined by AAELF. */ -#define Pa(X) ((X) & 0xfffffffc) - -static bfd_boolean elf32_arm_write_section (bfd *output_bfd, - struct bfd_link_info *link_info, - asection *sec, - bfd_byte *contents); - -/* Note: code such as elf32_arm_reloc_type_lookup expect to use e.g. - R_ARM_PC24 as an index into this, and find the R_ARM_PC24 HOWTO - in that slot. */ - -static reloc_howto_type elf32_arm_howto_table_1[] = -{ - /* No relocation. */ - HOWTO (R_ARM_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_PC24, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_PC24", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32 bit absolute */ - HOWTO (R_ARM_ABS32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ABS32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* standard 32bit pc-relative reloc */ - HOWTO (R_ARM_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_REL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit absolute - R_ARM_LDR_PC_G0 in AAELF */ - HOWTO (R_ARM_LDR_PC_G0, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_PC_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit absolute */ - HOWTO (R_ARM_ABS16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 12 bit absolute */ - HOWTO (R_ARM_ABS12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ABS12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_ABS5, /* type */ - 6, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_ABS5", /* name */ - FALSE, /* partial_inplace */ - 0x000007e0, /* src_mask */ - 0x000007e0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 8 bit absolute */ - HOWTO (R_ARM_ABS8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ABS8", /* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_SBREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_SBREL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_CALL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_CALL", /* name */ - FALSE, /* partial_inplace */ - 0x07ff2fff, /* src_mask */ - 0x07ff2fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_PC8, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_PC8", /* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_BREL_ADJ, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_BREL_ADJ", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_DESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_DESC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_SWI8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_SWI8", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* BLX instruction for the ARM. */ - HOWTO (R_ARM_XPC25, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_XPC25", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* BLX instruction for the Thumb. */ - HOWTO (R_ARM_THM_XPC22, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_XPC22", /* name */ - FALSE, /* partial_inplace */ - 0x07ff2fff, /* src_mask */ - 0x07ff2fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Dynamic TLS relocations. */ - - HOWTO (R_ARM_TLS_DTPMOD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_DTPMOD32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_DTPOFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_DTPOFF32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_TPOFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_TPOFF32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relocs used in ARM Linux */ - - HOWTO (R_ARM_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_COPY", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GLOB_DAT", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_JUMP_SLOT", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_RELATIVE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_GOTOFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOTOFF32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_GOTPC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOTPC", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_GOT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOT32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_PLT32, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_PLT32", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_CALL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_CALL", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_JUMP24, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_JUMP24", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_JUMP24, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_JUMP24", /* name */ - FALSE, /* partial_inplace */ - 0x07ff2fff, /* src_mask */ - 0x07ff2fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_BASE_ABS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_BASE_ABS", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PCREL7_0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PCREL_7_0", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PCREL15_8, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PCREL_15_8",/* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PCREL23_15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PCREL_23_15",/* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDR_SBREL_11_0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_SBREL_11_0",/* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SBREL_19_12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 12, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SBREL_19_12",/* name */ - FALSE, /* partial_inplace */ - 0x000ff000, /* src_mask */ - 0x000ff000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SBREL_27_20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 20, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SBREL_27_20",/* name */ - FALSE, /* partial_inplace */ - 0x0ff00000, /* src_mask */ - 0x0ff00000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TARGET1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TARGET1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_ROSEGREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ROSEGREL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_V4BX, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_V4BX", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TARGET2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TARGET2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_PREL31, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 31, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_PREL31", /* name */ - FALSE, /* partial_inplace */ - 0x7fffffff, /* src_mask */ - 0x7fffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_MOVW_ABS_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVW_ABS_NC", /* name */ - FALSE, /* partial_inplace */ - 0x000f0fff, /* src_mask */ - 0x000f0fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_MOVT_ABS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVT_ABS", /* name */ - FALSE, /* partial_inplace */ - 0x000f0fff, /* src_mask */ - 0x000f0fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_MOVW_PREL_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVW_PREL_NC", /* name */ - FALSE, /* partial_inplace */ - 0x000f0fff, /* src_mask */ - 0x000f0fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_MOVT_PREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVT_PREL", /* name */ - FALSE, /* partial_inplace */ - 0x000f0fff, /* src_mask */ - 0x000f0fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVW_ABS_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVW_ABS_NC",/* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVT_ABS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVT_ABS", /* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVW_PREL_NC,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVW_PREL_NC",/* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVT_PREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVT_PREL", /* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_JUMP19, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_JUMP19", /* name */ - FALSE, /* partial_inplace */ - 0x043f2fff, /* src_mask */ - 0x043f2fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_JUMP6, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_JUMP6", /* name */ - FALSE, /* partial_inplace */ - 0x02f8, /* src_mask */ - 0x02f8, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* These are declared as 13-bit signed relocations because we can - address -4095 .. 4095(base) by altering ADDW to SUBW or vice - versa. */ - HOWTO (R_ARM_THM_ALU_PREL_11_0,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_ALU_PREL_11_0",/* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_PC12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_PC12", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ABS32_NOI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ABS32_NOI", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_REL32_NOI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_REL32_NOI", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Group relocations. */ - - HOWTO (R_ARM_ALU_PC_G0_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PC_G0_NC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PC_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PC_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PC_G1_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PC_G1_NC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PC_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PC_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_PC_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_PC_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDR_PC_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_PC_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDR_PC_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_PC_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDRS_PC_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDRS_PC_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDRS_PC_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDRS_PC_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDRS_PC_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDRS_PC_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDC_PC_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDC_PC_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDC_PC_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDC_PC_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDC_PC_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDC_PC_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SB_G0_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SB_G0_NC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SB_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SB_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SB_G1_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SB_G1_NC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SB_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SB_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_ALU_SB_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_ALU_SB_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDR_SB_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_SB_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDR_SB_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_SB_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDR_SB_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDR_SB_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDRS_SB_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDRS_SB_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDRS_SB_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDRS_SB_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDRS_SB_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDRS_SB_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDC_SB_G0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDC_SB_G0", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDC_SB_G1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDC_SB_G1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_LDC_SB_G2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_LDC_SB_G2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* End of group relocations. */ - - HOWTO (R_ARM_MOVW_BREL_NC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVW_BREL_NC", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_MOVT_BREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVT_BREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_MOVW_BREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_MOVW_BREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVW_BREL_NC,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVW_BREL_NC",/* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVT_BREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVT_BREL", /* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_MOVW_BREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_MOVW_BREL", /* name */ - FALSE, /* partial_inplace */ - 0x040f70ff, /* src_mask */ - 0x040f70ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_GOTDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - NULL, /* special_function */ - "R_ARM_TLS_GOTDESC", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_CALL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_CALL", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_DESCSEQ, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_DESCSEQ", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_TLS_CALL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_TLS_CALL", /* name */ - FALSE, /* partial_inplace */ - 0x07ff07ff, /* src_mask */ - 0x07ff07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_PLT32_ABS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_PLT32_ABS", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_GOT_ABS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOT_ABS", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_GOT_PREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOT_PREL", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_GOT_BREL12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOT_BREL12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_GOTOFF12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_GOTOFF12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_ARM_GOTRELAX), /* reserved for future GOT-load optimizations */ - - /* GNU extension to record C++ vtable member usage */ - HOWTO (R_ARM_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_ARM_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_ARM_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_ARM_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_JUMP11, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_JUMP11", /* name */ - FALSE, /* partial_inplace */ - 0x000007ff, /* src_mask */ - 0x000007ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_ARM_THM_JUMP8, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_JUMP8", /* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* TLS relocations */ - HOWTO (R_ARM_TLS_GD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - NULL, /* special_function */ - "R_ARM_TLS_GD32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_LDM32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_LDM32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_LDO32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_LDO32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_IE32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - NULL, /* special_function */ - "R_ARM_TLS_IE32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_LE32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - NULL, /* special_function */ - "R_ARM_TLS_LE32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_LDO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_LDO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_LE12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_LE12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_TLS_IE12GP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_TLS_IE12GP", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 112-127 private relocations. */ - EMPTY_HOWTO (112), - EMPTY_HOWTO (113), - EMPTY_HOWTO (114), - EMPTY_HOWTO (115), - EMPTY_HOWTO (116), - EMPTY_HOWTO (117), - EMPTY_HOWTO (118), - EMPTY_HOWTO (119), - EMPTY_HOWTO (120), - EMPTY_HOWTO (121), - EMPTY_HOWTO (122), - EMPTY_HOWTO (123), - EMPTY_HOWTO (124), - EMPTY_HOWTO (125), - EMPTY_HOWTO (126), - EMPTY_HOWTO (127), - - /* R_ARM_ME_TOO, obsolete. */ - EMPTY_HOWTO (128), - - HOWTO (R_ARM_THM_TLS_DESCSEQ, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_THM_TLS_DESCSEQ",/* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - HOWTO (R_ARM_THM_ALU_ABS_G0_NC,/* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield,/* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_ARM_THM_ALU_ABS_G0_NC",/* name. */ - FALSE, /* partial_inplace. */ - 0x00000000, /* src_mask. */ - 0x00000000, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - HOWTO (R_ARM_THM_ALU_ABS_G1_NC,/* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield,/* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_ARM_THM_ALU_ABS_G1_NC",/* name. */ - FALSE, /* partial_inplace. */ - 0x00000000, /* src_mask. */ - 0x00000000, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - HOWTO (R_ARM_THM_ALU_ABS_G2_NC,/* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield,/* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_ARM_THM_ALU_ABS_G2_NC",/* name. */ - FALSE, /* partial_inplace. */ - 0x00000000, /* src_mask. */ - 0x00000000, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - HOWTO (R_ARM_THM_ALU_ABS_G3_NC,/* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield,/* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_ARM_THM_ALU_ABS_G3_NC",/* name. */ - FALSE, /* partial_inplace. */ - 0x00000000, /* src_mask. */ - 0x00000000, /* dst_mask. */ - FALSE), /* pcrel_offset. */ -}; - -/* 160 onwards: */ -static reloc_howto_type elf32_arm_howto_table_2[1] = -{ - HOWTO (R_ARM_IRELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_IRELATIVE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -/* 249-255 extended, currently unused, relocations: */ -static reloc_howto_type elf32_arm_howto_table_3[4] = -{ - HOWTO (R_ARM_RREL32, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_RREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_RABS32, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_RABS32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_RPC24, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_RPC24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_ARM_RBASE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_ARM_RBASE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -static reloc_howto_type * -elf32_arm_howto_from_type (unsigned int r_type) -{ - if (r_type < ARRAY_SIZE (elf32_arm_howto_table_1)) - return &elf32_arm_howto_table_1[r_type]; - - if (r_type == R_ARM_IRELATIVE) - return &elf32_arm_howto_table_2[r_type - R_ARM_IRELATIVE]; - - if (r_type >= R_ARM_RREL32 - && r_type < R_ARM_RREL32 + ARRAY_SIZE (elf32_arm_howto_table_3)) - return &elf32_arm_howto_table_3[r_type - R_ARM_RREL32]; - - return NULL; -} - -static void -elf32_arm_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * bfd_reloc, - Elf_Internal_Rela * elf_reloc) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (elf_reloc->r_info); - bfd_reloc->howto = elf32_arm_howto_from_type (r_type); -} - -struct elf32_arm_reloc_map - { - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; - }; - -/* All entries in this list must also be present in elf32_arm_howto_table. */ -static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] = - { - {BFD_RELOC_NONE, R_ARM_NONE}, - {BFD_RELOC_ARM_PCREL_BRANCH, R_ARM_PC24}, - {BFD_RELOC_ARM_PCREL_CALL, R_ARM_CALL}, - {BFD_RELOC_ARM_PCREL_JUMP, R_ARM_JUMP24}, - {BFD_RELOC_ARM_PCREL_BLX, R_ARM_XPC25}, - {BFD_RELOC_THUMB_PCREL_BLX, R_ARM_THM_XPC22}, - {BFD_RELOC_32, R_ARM_ABS32}, - {BFD_RELOC_32_PCREL, R_ARM_REL32}, - {BFD_RELOC_8, R_ARM_ABS8}, - {BFD_RELOC_16, R_ARM_ABS16}, - {BFD_RELOC_ARM_OFFSET_IMM, R_ARM_ABS12}, - {BFD_RELOC_ARM_THUMB_OFFSET, R_ARM_THM_ABS5}, - {BFD_RELOC_THUMB_PCREL_BRANCH25, R_ARM_THM_JUMP24}, - {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_CALL}, - {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_JUMP11}, - {BFD_RELOC_THUMB_PCREL_BRANCH20, R_ARM_THM_JUMP19}, - {BFD_RELOC_THUMB_PCREL_BRANCH9, R_ARM_THM_JUMP8}, - {BFD_RELOC_THUMB_PCREL_BRANCH7, R_ARM_THM_JUMP6}, - {BFD_RELOC_ARM_GLOB_DAT, R_ARM_GLOB_DAT}, - {BFD_RELOC_ARM_JUMP_SLOT, R_ARM_JUMP_SLOT}, - {BFD_RELOC_ARM_RELATIVE, R_ARM_RELATIVE}, - {BFD_RELOC_ARM_GOTOFF, R_ARM_GOTOFF32}, - {BFD_RELOC_ARM_GOTPC, R_ARM_GOTPC}, - {BFD_RELOC_ARM_GOT_PREL, R_ARM_GOT_PREL}, - {BFD_RELOC_ARM_GOT32, R_ARM_GOT32}, - {BFD_RELOC_ARM_PLT32, R_ARM_PLT32}, - {BFD_RELOC_ARM_TARGET1, R_ARM_TARGET1}, - {BFD_RELOC_ARM_ROSEGREL32, R_ARM_ROSEGREL32}, - {BFD_RELOC_ARM_SBREL32, R_ARM_SBREL32}, - {BFD_RELOC_ARM_PREL31, R_ARM_PREL31}, - {BFD_RELOC_ARM_TARGET2, R_ARM_TARGET2}, - {BFD_RELOC_ARM_PLT32, R_ARM_PLT32}, - {BFD_RELOC_ARM_TLS_GOTDESC, R_ARM_TLS_GOTDESC}, - {BFD_RELOC_ARM_TLS_CALL, R_ARM_TLS_CALL}, - {BFD_RELOC_ARM_THM_TLS_CALL, R_ARM_THM_TLS_CALL}, - {BFD_RELOC_ARM_TLS_DESCSEQ, R_ARM_TLS_DESCSEQ}, - {BFD_RELOC_ARM_THM_TLS_DESCSEQ, R_ARM_THM_TLS_DESCSEQ}, - {BFD_RELOC_ARM_TLS_DESC, R_ARM_TLS_DESC}, - {BFD_RELOC_ARM_TLS_GD32, R_ARM_TLS_GD32}, - {BFD_RELOC_ARM_TLS_LDO32, R_ARM_TLS_LDO32}, - {BFD_RELOC_ARM_TLS_LDM32, R_ARM_TLS_LDM32}, - {BFD_RELOC_ARM_TLS_DTPMOD32, R_ARM_TLS_DTPMOD32}, - {BFD_RELOC_ARM_TLS_DTPOFF32, R_ARM_TLS_DTPOFF32}, - {BFD_RELOC_ARM_TLS_TPOFF32, R_ARM_TLS_TPOFF32}, - {BFD_RELOC_ARM_TLS_IE32, R_ARM_TLS_IE32}, - {BFD_RELOC_ARM_TLS_LE32, R_ARM_TLS_LE32}, - {BFD_RELOC_ARM_IRELATIVE, R_ARM_IRELATIVE}, - {BFD_RELOC_VTABLE_INHERIT, R_ARM_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_ARM_GNU_VTENTRY}, - {BFD_RELOC_ARM_MOVW, R_ARM_MOVW_ABS_NC}, - {BFD_RELOC_ARM_MOVT, R_ARM_MOVT_ABS}, - {BFD_RELOC_ARM_MOVW_PCREL, R_ARM_MOVW_PREL_NC}, - {BFD_RELOC_ARM_MOVT_PCREL, R_ARM_MOVT_PREL}, - {BFD_RELOC_ARM_THUMB_MOVW, R_ARM_THM_MOVW_ABS_NC}, - {BFD_RELOC_ARM_THUMB_MOVT, R_ARM_THM_MOVT_ABS}, - {BFD_RELOC_ARM_THUMB_MOVW_PCREL, R_ARM_THM_MOVW_PREL_NC}, - {BFD_RELOC_ARM_THUMB_MOVT_PCREL, R_ARM_THM_MOVT_PREL}, - {BFD_RELOC_ARM_ALU_PC_G0_NC, R_ARM_ALU_PC_G0_NC}, - {BFD_RELOC_ARM_ALU_PC_G0, R_ARM_ALU_PC_G0}, - {BFD_RELOC_ARM_ALU_PC_G1_NC, R_ARM_ALU_PC_G1_NC}, - {BFD_RELOC_ARM_ALU_PC_G1, R_ARM_ALU_PC_G1}, - {BFD_RELOC_ARM_ALU_PC_G2, R_ARM_ALU_PC_G2}, - {BFD_RELOC_ARM_LDR_PC_G0, R_ARM_LDR_PC_G0}, - {BFD_RELOC_ARM_LDR_PC_G1, R_ARM_LDR_PC_G1}, - {BFD_RELOC_ARM_LDR_PC_G2, R_ARM_LDR_PC_G2}, - {BFD_RELOC_ARM_LDRS_PC_G0, R_ARM_LDRS_PC_G0}, - {BFD_RELOC_ARM_LDRS_PC_G1, R_ARM_LDRS_PC_G1}, - {BFD_RELOC_ARM_LDRS_PC_G2, R_ARM_LDRS_PC_G2}, - {BFD_RELOC_ARM_LDC_PC_G0, R_ARM_LDC_PC_G0}, - {BFD_RELOC_ARM_LDC_PC_G1, R_ARM_LDC_PC_G1}, - {BFD_RELOC_ARM_LDC_PC_G2, R_ARM_LDC_PC_G2}, - {BFD_RELOC_ARM_ALU_SB_G0_NC, R_ARM_ALU_SB_G0_NC}, - {BFD_RELOC_ARM_ALU_SB_G0, R_ARM_ALU_SB_G0}, - {BFD_RELOC_ARM_ALU_SB_G1_NC, R_ARM_ALU_SB_G1_NC}, - {BFD_RELOC_ARM_ALU_SB_G1, R_ARM_ALU_SB_G1}, - {BFD_RELOC_ARM_ALU_SB_G2, R_ARM_ALU_SB_G2}, - {BFD_RELOC_ARM_LDR_SB_G0, R_ARM_LDR_SB_G0}, - {BFD_RELOC_ARM_LDR_SB_G1, R_ARM_LDR_SB_G1}, - {BFD_RELOC_ARM_LDR_SB_G2, R_ARM_LDR_SB_G2}, - {BFD_RELOC_ARM_LDRS_SB_G0, R_ARM_LDRS_SB_G0}, - {BFD_RELOC_ARM_LDRS_SB_G1, R_ARM_LDRS_SB_G1}, - {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2}, - {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0}, - {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1}, - {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}, - {BFD_RELOC_ARM_V4BX, R_ARM_V4BX}, - {BFD_RELOC_ARM_THUMB_ALU_ABS_G3_NC, R_ARM_THM_ALU_ABS_G3_NC}, - {BFD_RELOC_ARM_THUMB_ALU_ABS_G2_NC, R_ARM_THM_ALU_ABS_G2_NC}, - {BFD_RELOC_ARM_THUMB_ALU_ABS_G1_NC, R_ARM_THM_ALU_ABS_G1_NC}, - {BFD_RELOC_ARM_THUMB_ALU_ABS_G0_NC, R_ARM_THM_ALU_ABS_G0_NC} - }; - -static reloc_howto_type * -elf32_arm_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_arm_reloc_map); i ++) - if (elf32_arm_reloc_map[i].bfd_reloc_val == code) - return elf32_arm_howto_from_type (elf32_arm_reloc_map[i].elf_reloc_val); - - return NULL; -} - -static reloc_howto_type * -elf32_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_arm_howto_table_1); i++) - if (elf32_arm_howto_table_1[i].name != NULL - && strcasecmp (elf32_arm_howto_table_1[i].name, r_name) == 0) - return &elf32_arm_howto_table_1[i]; - - for (i = 0; i < ARRAY_SIZE (elf32_arm_howto_table_2); i++) - if (elf32_arm_howto_table_2[i].name != NULL - && strcasecmp (elf32_arm_howto_table_2[i].name, r_name) == 0) - return &elf32_arm_howto_table_2[i]; - - for (i = 0; i < ARRAY_SIZE (elf32_arm_howto_table_3); i++) - if (elf32_arm_howto_table_3[i].name != NULL - && strcasecmp (elf32_arm_howto_table_3[i].name, r_name) == 0) - return &elf32_arm_howto_table_3[i]; - - return NULL; -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 148: /* Linux/ARM 32-bit. */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 72; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/ARM elf_prpsinfo. */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 12); - 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; -} - -static char * -elf32_arm_nabi_write_core_note (bfd *abfd, char *buf, int *bufsiz, - int note_type, ...) -{ - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - { - char data[124]; - va_list ap; - - va_start (ap, note_type); - memset (data, 0, sizeof (data)); - strncpy (data + 28, va_arg (ap, const char *), 16); - strncpy (data + 44, va_arg (ap, const char *), 80); - va_end (ap); - - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - - case NT_PRSTATUS: - { - char data[148]; - va_list ap; - long pid; - int cursig; - const void *greg; - - va_start (ap, note_type); - memset (data, 0, sizeof (data)); - pid = va_arg (ap, long); - bfd_put_32 (abfd, pid, data + 24); - cursig = va_arg (ap, int); - bfd_put_16 (abfd, cursig, data + 12); - greg = va_arg (ap, const void *); - memcpy (data + 72, greg, 72); - va_end (ap); - - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - } -} - -#define TARGET_LITTLE_SYM arm_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlearm" -#define TARGET_BIG_SYM arm_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bigarm" - -#define elf_backend_grok_prstatus elf32_arm_nabi_grok_prstatus -#define elf_backend_grok_psinfo elf32_arm_nabi_grok_psinfo -#define elf_backend_write_core_note elf32_arm_nabi_write_core_note - -typedef unsigned long int insn32; -typedef unsigned short int insn16; - -/* In lieu of proper flags, assume all EABIv4 or later objects are - interworkable. */ -#define INTERWORK_FLAG(abfd) \ - (EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) >= EF_ARM_EABI_VER4 \ - || (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK) \ - || ((abfd)->flags & BFD_LINKER_CREATED)) - -/* The linker script knows the section names for placement. - The entry_names are used to do simple name mangling on the stubs. - Given a function name, and its type, the stub can be found. The - name can be changed. The only requirement is the %s be present. */ -#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t" -#define THUMB2ARM_GLUE_ENTRY_NAME "__%s_from_thumb" - -#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7" -#define ARM2THUMB_GLUE_ENTRY_NAME "__%s_from_arm" - -#define VFP11_ERRATUM_VENEER_SECTION_NAME ".vfp11_veneer" -#define VFP11_ERRATUM_VENEER_ENTRY_NAME "__vfp11_veneer_%x" - -#define STM32L4XX_ERRATUM_VENEER_SECTION_NAME ".text.stm32l4xx_veneer" -#define STM32L4XX_ERRATUM_VENEER_ENTRY_NAME "__stm32l4xx_veneer_%x" - -#define ARM_BX_GLUE_SECTION_NAME ".v4_bx" -#define ARM_BX_GLUE_ENTRY_NAME "__bx_r%d" - -#define STUB_ENTRY_NAME "__%s_veneer" - -#define CMSE_PREFIX "__acle_se_" - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -static const unsigned long tls_trampoline [] = -{ - 0xe08e0000, /* add r0, lr, r0 */ - 0xe5901004, /* ldr r1, [r0,#4] */ - 0xe12fff11, /* bx r1 */ -}; - -static const unsigned long dl_tlsdesc_lazy_trampoline [] = -{ - 0xe52d2004, /* push {r2} */ - 0xe59f200c, /* ldr r2, [pc, #3f - . - 8] */ - 0xe59f100c, /* ldr r1, [pc, #4f - . - 8] */ - 0xe79f2002, /* 1: ldr r2, [pc, r2] */ - 0xe081100f, /* 2: add r1, pc */ - 0xe12fff12, /* bx r2 */ - 0x00000014, /* 3: .word _GLOBAL_OFFSET_TABLE_ - 1b - 8 - + dl_tlsdesc_lazy_resolver(GOT) */ - 0x00000018, /* 4: .word _GLOBAL_OFFSET_TABLE_ - 2b - 8 */ -}; - -#ifdef FOUR_WORD_PLT - -/* The first entry in a procedure linkage table looks like - this. It is set up so that any shared library function that is - called before the relocation has been set up calls the dynamic - linker first. */ -static const bfd_vma elf32_arm_plt0_entry [] = -{ - 0xe52de004, /* str lr, [sp, #-4]! */ - 0xe59fe010, /* ldr lr, [pc, #16] */ - 0xe08fe00e, /* add lr, pc, lr */ - 0xe5bef008, /* ldr pc, [lr, #8]! */ -}; - -/* Subsequent entries in a procedure linkage table look like - this. */ -static const bfd_vma elf32_arm_plt_entry [] = -{ - 0xe28fc600, /* add ip, pc, #NN */ - 0xe28cca00, /* add ip, ip, #NN */ - 0xe5bcf000, /* ldr pc, [ip, #NN]! */ - 0x00000000, /* unused */ -}; - -#else /* not FOUR_WORD_PLT */ - -/* The first entry in a procedure linkage table looks like - this. It is set up so that any shared library function that is - called before the relocation has been set up calls the dynamic - linker first. */ -static const bfd_vma elf32_arm_plt0_entry [] = -{ - 0xe52de004, /* str lr, [sp, #-4]! */ - 0xe59fe004, /* ldr lr, [pc, #4] */ - 0xe08fe00e, /* add lr, pc, lr */ - 0xe5bef008, /* ldr pc, [lr, #8]! */ - 0x00000000, /* &GOT[0] - . */ -}; - -/* By default subsequent entries in a procedure linkage table look like - this. Offsets that don't fit into 28 bits will cause link error. */ -static const bfd_vma elf32_arm_plt_entry_short [] = -{ - 0xe28fc600, /* add ip, pc, #0xNN00000 */ - 0xe28cca00, /* add ip, ip, #0xNN000 */ - 0xe5bcf000, /* ldr pc, [ip, #0xNNN]! */ -}; - -/* When explicitly asked, we'll use this "long" entry format - which can cope with arbitrary displacements. */ -static const bfd_vma elf32_arm_plt_entry_long [] = -{ - 0xe28fc200, /* add ip, pc, #0xN0000000 */ - 0xe28cc600, /* add ip, ip, #0xNN00000 */ - 0xe28cca00, /* add ip, ip, #0xNN000 */ - 0xe5bcf000, /* ldr pc, [ip, #0xNNN]! */ -}; - -static bfd_boolean elf32_arm_use_long_plt_entry = FALSE; - -#endif /* not FOUR_WORD_PLT */ - -/* The first entry in a procedure linkage table looks like this. - It is set up so that any shared library function that is called before the - relocation has been set up calls the dynamic linker first. */ -static const bfd_vma elf32_thumb2_plt0_entry [] = -{ - /* NOTE: As this is a mixture of 16-bit and 32-bit instructions, - an instruction maybe encoded to one or two array elements. */ - 0xf8dfb500, /* push {lr} */ - 0x44fee008, /* ldr.w lr, [pc, #8] */ - /* add lr, pc */ - 0xff08f85e, /* ldr.w pc, [lr, #8]! */ - 0x00000000, /* &GOT[0] - . */ -}; - -/* Subsequent entries in a procedure linkage table for thumb only target - look like this. */ -static const bfd_vma elf32_thumb2_plt_entry [] = -{ - /* NOTE: As this is a mixture of 16-bit and 32-bit instructions, - an instruction maybe encoded to one or two array elements. */ - 0x0c00f240, /* movw ip, #0xNNNN */ - 0x0c00f2c0, /* movt ip, #0xNNNN */ - 0xf8dc44fc, /* add ip, pc */ - 0xbf00f000 /* ldr.w pc, [ip] */ - /* nop */ -}; - -/* The format of the first entry in the procedure linkage table - for a VxWorks executable. */ -static const bfd_vma elf32_arm_vxworks_exec_plt0_entry[] = -{ - 0xe52dc008, /* str ip,[sp,#-8]! */ - 0xe59fc000, /* ldr ip,[pc] */ - 0xe59cf008, /* ldr pc,[ip,#8] */ - 0x00000000, /* .long _GLOBAL_OFFSET_TABLE_ */ -}; - -/* The format of subsequent entries in a VxWorks executable. */ -static const bfd_vma elf32_arm_vxworks_exec_plt_entry[] = -{ - 0xe59fc000, /* ldr ip,[pc] */ - 0xe59cf000, /* ldr pc,[ip] */ - 0x00000000, /* .long @got */ - 0xe59fc000, /* ldr ip,[pc] */ - 0xea000000, /* b _PLT */ - 0x00000000, /* .long @pltindex*sizeof(Elf32_Rela) */ -}; - -/* The format of entries in a VxWorks shared library. */ -static const bfd_vma elf32_arm_vxworks_shared_plt_entry[] = -{ - 0xe59fc000, /* ldr ip,[pc] */ - 0xe79cf009, /* ldr pc,[ip,r9] */ - 0x00000000, /* .long @got */ - 0xe59fc000, /* ldr ip,[pc] */ - 0xe599f008, /* ldr pc,[r9,#8] */ - 0x00000000, /* .long @pltindex*sizeof(Elf32_Rela) */ -}; - -/* An initial stub used if the PLT entry is referenced from Thumb code. */ -#define PLT_THUMB_STUB_SIZE 4 -static const bfd_vma elf32_arm_plt_thumb_stub [] = -{ - 0x4778, /* bx pc */ - 0x46c0 /* nop */ -}; - -/* The entries in a PLT when using a DLL-based target with multiple - address spaces. */ -static const bfd_vma elf32_arm_symbian_plt_entry [] = -{ - 0xe51ff004, /* ldr pc, [pc, #-4] */ - 0x00000000, /* dcd R_ARM_GLOB_DAT(X) */ -}; - -/* The first entry in a procedure linkage table looks like - this. It is set up so that any shared library function that is - called before the relocation has been set up calls the dynamic - linker first. */ -static const bfd_vma elf32_arm_nacl_plt0_entry [] = -{ - /* First bundle: */ - 0xe300c000, /* movw ip, #:lower16:&GOT[2]-.+8 */ - 0xe340c000, /* movt ip, #:upper16:&GOT[2]-.+8 */ - 0xe08cc00f, /* add ip, ip, pc */ - 0xe52dc008, /* str ip, [sp, #-8]! */ - /* Second bundle: */ - 0xe3ccc103, /* bic ip, ip, #0xc0000000 */ - 0xe59cc000, /* ldr ip, [ip] */ - 0xe3ccc13f, /* bic ip, ip, #0xc000000f */ - 0xe12fff1c, /* bx ip */ - /* Third bundle: */ - 0xe320f000, /* nop */ - 0xe320f000, /* nop */ - 0xe320f000, /* nop */ - /* .Lplt_tail: */ - 0xe50dc004, /* str ip, [sp, #-4] */ - /* Fourth bundle: */ - 0xe3ccc103, /* bic ip, ip, #0xc0000000 */ - 0xe59cc000, /* ldr ip, [ip] */ - 0xe3ccc13f, /* bic ip, ip, #0xc000000f */ - 0xe12fff1c, /* bx ip */ -}; -#define ARM_NACL_PLT_TAIL_OFFSET (11 * 4) - -/* Subsequent entries in a procedure linkage table look like this. */ -static const bfd_vma elf32_arm_nacl_plt_entry [] = -{ - 0xe300c000, /* movw ip, #:lower16:&GOT[n]-.+8 */ - 0xe340c000, /* movt ip, #:upper16:&GOT[n]-.+8 */ - 0xe08cc00f, /* add ip, ip, pc */ - 0xea000000, /* b .Lplt_tail */ -}; - -#define ARM_MAX_FWD_BRANCH_OFFSET ((((1 << 23) - 1) << 2) + 8) -#define ARM_MAX_BWD_BRANCH_OFFSET ((-((1 << 23) << 2)) + 8) -#define THM_MAX_FWD_BRANCH_OFFSET ((1 << 22) -2 + 4) -#define THM_MAX_BWD_BRANCH_OFFSET (-(1 << 22) + 4) -#define THM2_MAX_FWD_BRANCH_OFFSET (((1 << 24) - 2) + 4) -#define THM2_MAX_BWD_BRANCH_OFFSET (-(1 << 24) + 4) -#define THM2_MAX_FWD_COND_BRANCH_OFFSET (((1 << 20) -2) + 4) -#define THM2_MAX_BWD_COND_BRANCH_OFFSET (-(1 << 20) + 4) - -enum stub_insn_type -{ - THUMB16_TYPE = 1, - THUMB32_TYPE, - ARM_TYPE, - DATA_TYPE -}; - -#define THUMB16_INSN(X) {(X), THUMB16_TYPE, R_ARM_NONE, 0} -/* A bit of a hack. A Thumb conditional branch, in which the proper condition - is inserted in arm_build_one_stub(). */ -#define THUMB16_BCOND_INSN(X) {(X), THUMB16_TYPE, R_ARM_NONE, 1} -#define THUMB32_INSN(X) {(X), THUMB32_TYPE, R_ARM_NONE, 0} -#define THUMB32_MOVT(X) {(X), THUMB32_TYPE, R_ARM_THM_MOVT_ABS, 0} -#define THUMB32_MOVW(X) {(X), THUMB32_TYPE, R_ARM_THM_MOVW_ABS_NC, 0} -#define THUMB32_B_INSN(X, Z) {(X), THUMB32_TYPE, R_ARM_THM_JUMP24, (Z)} -#define ARM_INSN(X) {(X), ARM_TYPE, R_ARM_NONE, 0} -#define ARM_REL_INSN(X, Z) {(X), ARM_TYPE, R_ARM_JUMP24, (Z)} -#define DATA_WORD(X,Y,Z) {(X), DATA_TYPE, (Y), (Z)} - -typedef struct -{ - bfd_vma data; - enum stub_insn_type type; - unsigned int r_type; - int reloc_addend; -} insn_sequence; - -/* Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx - to reach the stub if necessary. */ -static const insn_sequence elf32_arm_stub_long_branch_any_any[] = -{ - ARM_INSN (0xe51ff004), /* ldr pc, [pc, #-4] */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ -}; - -/* V4T Arm -> Thumb long branch stub. Used on V4T where blx is not - available. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb[] = -{ - ARM_INSN (0xe59fc000), /* ldr ip, [pc, #0] */ - ARM_INSN (0xe12fff1c), /* bx ip */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ -}; - -/* Thumb -> Thumb long branch stub. Used on M-profile architectures. */ -static const insn_sequence elf32_arm_stub_long_branch_thumb_only[] = -{ - THUMB16_INSN (0xb401), /* push {r0} */ - THUMB16_INSN (0x4802), /* ldr r0, [pc, #8] */ - THUMB16_INSN (0x4684), /* mov ip, r0 */ - THUMB16_INSN (0xbc01), /* pop {r0} */ - THUMB16_INSN (0x4760), /* bx ip */ - THUMB16_INSN (0xbf00), /* nop */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ -}; - -/* Thumb -> Thumb long branch stub in thumb2 encoding. Used on armv7. */ -static const insn_sequence elf32_arm_stub_long_branch_thumb2_only[] = -{ - THUMB32_INSN (0xf85ff000), /* ldr.w pc, [pc, #-0] */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(x) */ -}; - -/* Thumb -> Thumb long branch stub. Used for PureCode sections on Thumb2 - M-profile architectures. */ -static const insn_sequence elf32_arm_stub_long_branch_thumb2_only_pure[] = -{ - THUMB32_MOVW (0xf2400c00), /* mov.w ip, R_ARM_MOVW_ABS_NC */ - THUMB32_MOVT (0xf2c00c00), /* movt ip, R_ARM_MOVT_ABS << 16 */ - THUMB16_INSN (0x4760), /* bx ip */ -}; - -/* V4T Thumb -> Thumb long branch stub. Using the stack is not - allowed. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb[] = -{ - THUMB16_INSN (0x4778), /* bx pc */ - THUMB16_INSN (0x46c0), /* nop */ - ARM_INSN (0xe59fc000), /* ldr ip, [pc, #0] */ - ARM_INSN (0xe12fff1c), /* bx ip */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ -}; - -/* V4T Thumb -> ARM long branch stub. Used on V4T where blx is not - available. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm[] = -{ - THUMB16_INSN (0x4778), /* bx pc */ - THUMB16_INSN (0x46c0), /* nop */ - ARM_INSN (0xe51ff004), /* ldr pc, [pc, #-4] */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ -}; - -/* V4T Thumb -> ARM short branch stub. Shorter variant of the above - one, when the destination is close enough. */ -static const insn_sequence elf32_arm_stub_short_branch_v4t_thumb_arm[] = -{ - THUMB16_INSN (0x4778), /* bx pc */ - THUMB16_INSN (0x46c0), /* nop */ - ARM_REL_INSN (0xea000000, -8), /* b (X-8) */ -}; - -/* ARM/Thumb -> ARM long branch stub, PIC. On V5T and above, use - blx to reach the stub if necessary. */ -static const insn_sequence elf32_arm_stub_long_branch_any_arm_pic[] = -{ - ARM_INSN (0xe59fc000), /* ldr ip, [pc] */ - ARM_INSN (0xe08ff00c), /* add pc, pc, ip */ - DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ -}; - -/* ARM/Thumb -> Thumb long branch stub, PIC. On V5T and above, use - blx to reach the stub if necessary. We can not add into pc; - it is not guaranteed to mode switch (different in ARMv6 and - ARMv7). */ -static const insn_sequence elf32_arm_stub_long_branch_any_thumb_pic[] = -{ - ARM_INSN (0xe59fc004), /* ldr ip, [pc, #4] */ - ARM_INSN (0xe08fc00c), /* add ip, pc, ip */ - ARM_INSN (0xe12fff1c), /* bx ip */ - DATA_WORD (0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ -}; - -/* V4T ARM -> ARM long branch stub, PIC. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] = -{ - ARM_INSN (0xe59fc004), /* ldr ip, [pc, #4] */ - ARM_INSN (0xe08fc00c), /* add ip, pc, ip */ - ARM_INSN (0xe12fff1c), /* bx ip */ - DATA_WORD (0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ -}; - -/* V4T Thumb -> ARM long branch stub, PIC. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] = -{ - THUMB16_INSN (0x4778), /* bx pc */ - THUMB16_INSN (0x46c0), /* nop */ - ARM_INSN (0xe59fc000), /* ldr ip, [pc, #0] */ - ARM_INSN (0xe08cf00f), /* add pc, ip, pc */ - DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ -}; - -/* Thumb -> Thumb long branch stub, PIC. Used on M-profile - architectures. */ -static const insn_sequence elf32_arm_stub_long_branch_thumb_only_pic[] = -{ - THUMB16_INSN (0xb401), /* push {r0} */ - THUMB16_INSN (0x4802), /* ldr r0, [pc, #8] */ - THUMB16_INSN (0x46fc), /* mov ip, pc */ - THUMB16_INSN (0x4484), /* add ip, r0 */ - THUMB16_INSN (0xbc01), /* pop {r0} */ - THUMB16_INSN (0x4760), /* bx ip */ - DATA_WORD (0, R_ARM_REL32, 4), /* dcd R_ARM_REL32(X) */ -}; - -/* V4T Thumb -> Thumb long branch stub, PIC. Using the stack is not - allowed. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] = -{ - THUMB16_INSN (0x4778), /* bx pc */ - THUMB16_INSN (0x46c0), /* nop */ - ARM_INSN (0xe59fc004), /* ldr ip, [pc, #4] */ - ARM_INSN (0xe08fc00c), /* add ip, pc, ip */ - ARM_INSN (0xe12fff1c), /* bx ip */ - DATA_WORD (0, R_ARM_REL32, 0), /* dcd R_ARM_REL32(X) */ -}; - -/* Thumb2/ARM -> TLS trampoline. Lowest common denominator, which is a - long PIC stub. We can use r1 as a scratch -- and cannot use ip. */ -static const insn_sequence elf32_arm_stub_long_branch_any_tls_pic[] = -{ - ARM_INSN (0xe59f1000), /* ldr r1, [pc] */ - ARM_INSN (0xe08ff001), /* add pc, pc, r1 */ - DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X-4) */ -}; - -/* V4T Thumb -> TLS trampoline. lowest common denominator, which is a - long PIC stub. We can use r1 as a scratch -- and cannot use ip. */ -static const insn_sequence elf32_arm_stub_long_branch_v4t_thumb_tls_pic[] = -{ - THUMB16_INSN (0x4778), /* bx pc */ - THUMB16_INSN (0x46c0), /* nop */ - ARM_INSN (0xe59f1000), /* ldr r1, [pc, #0] */ - ARM_INSN (0xe081f00f), /* add pc, r1, pc */ - DATA_WORD (0, R_ARM_REL32, -4), /* dcd R_ARM_REL32(X) */ -}; - -/* NaCl ARM -> ARM long branch stub. */ -static const insn_sequence elf32_arm_stub_long_branch_arm_nacl[] = -{ - ARM_INSN (0xe59fc00c), /* ldr ip, [pc, #12] */ - ARM_INSN (0xe3ccc13f), /* bic ip, ip, #0xc000000f */ - ARM_INSN (0xe12fff1c), /* bx ip */ - ARM_INSN (0xe320f000), /* nop */ - ARM_INSN (0xe125be70), /* bkpt 0x5be0 */ - DATA_WORD (0, R_ARM_ABS32, 0), /* dcd R_ARM_ABS32(X) */ - DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */ - DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */ -}; - -/* NaCl ARM -> ARM long branch stub, PIC. */ -static const insn_sequence elf32_arm_stub_long_branch_arm_nacl_pic[] = -{ - ARM_INSN (0xe59fc00c), /* ldr ip, [pc, #12] */ - ARM_INSN (0xe08cc00f), /* add ip, ip, pc */ - ARM_INSN (0xe3ccc13f), /* bic ip, ip, #0xc000000f */ - ARM_INSN (0xe12fff1c), /* bx ip */ - ARM_INSN (0xe125be70), /* bkpt 0x5be0 */ - DATA_WORD (0, R_ARM_REL32, 8), /* dcd R_ARM_REL32(X+8) */ - DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */ - DATA_WORD (0, R_ARM_NONE, 0), /* .word 0 */ -}; - -/* Stub used for transition to secure state (aka SG veneer). */ -static const insn_sequence elf32_arm_stub_cmse_branch_thumb_only[] = -{ - THUMB32_INSN (0xe97fe97f), /* sg. */ - THUMB32_B_INSN (0xf000b800, -4), /* b.w original_branch_dest. */ -}; - - -/* Cortex-A8 erratum-workaround stubs. */ - -/* Stub used for conditional branches (which may be beyond +/-1MB away, so we - can't use a conditional branch to reach this stub). */ - -static const insn_sequence elf32_arm_stub_a8_veneer_b_cond[] = -{ - THUMB16_BCOND_INSN (0xd001), /* b.n true. */ - THUMB32_B_INSN (0xf000b800, -4), /* b.w insn_after_original_branch. */ - THUMB32_B_INSN (0xf000b800, -4) /* true: b.w original_branch_dest. */ -}; - -/* Stub used for b.w and bl.w instructions. */ - -static const insn_sequence elf32_arm_stub_a8_veneer_b[] = -{ - THUMB32_B_INSN (0xf000b800, -4) /* b.w original_branch_dest. */ -}; - -static const insn_sequence elf32_arm_stub_a8_veneer_bl[] = -{ - THUMB32_B_INSN (0xf000b800, -4) /* b.w original_branch_dest. */ -}; - -/* Stub used for Thumb-2 blx.w instructions. We modified the original blx.w - instruction (which switches to ARM mode) to point to this stub. Jump to the - real destination using an ARM-mode branch. */ - -static const insn_sequence elf32_arm_stub_a8_veneer_blx[] = -{ - ARM_REL_INSN (0xea000000, -8) /* b original_branch_dest. */ -}; - -/* For each section group there can be a specially created linker section - to hold the stubs for that group. The name of the stub section is based - upon the name of another section within that group with the suffix below - applied. - - PR 13049: STUB_SUFFIX used to be ".stub", but this allowed the user to - create what appeared to be a linker stub section when it actually - contained user code/data. For example, consider this fragment: - - const char * stubborn_problems[] = { "np" }; - - If this is compiled with "-fPIC -fdata-sections" then gcc produces a - section called: - - .data.rel.local.stubborn_problems - - This then causes problems in arm32_arm_build_stubs() as it triggers: - - // Ignore non-stub sections. - if (!strstr (stub_sec->name, STUB_SUFFIX)) - continue; - - And so the section would be ignored instead of being processed. Hence - the change in definition of STUB_SUFFIX to a name that cannot be a valid - C identifier. */ -#define STUB_SUFFIX ".__stub" - -/* One entry per long/short branch stub defined above. */ -#define DEF_STUBS \ - DEF_STUB(long_branch_any_any) \ - DEF_STUB(long_branch_v4t_arm_thumb) \ - DEF_STUB(long_branch_thumb_only) \ - DEF_STUB(long_branch_v4t_thumb_thumb) \ - DEF_STUB(long_branch_v4t_thumb_arm) \ - DEF_STUB(short_branch_v4t_thumb_arm) \ - DEF_STUB(long_branch_any_arm_pic) \ - DEF_STUB(long_branch_any_thumb_pic) \ - DEF_STUB(long_branch_v4t_thumb_thumb_pic) \ - DEF_STUB(long_branch_v4t_arm_thumb_pic) \ - DEF_STUB(long_branch_v4t_thumb_arm_pic) \ - DEF_STUB(long_branch_thumb_only_pic) \ - DEF_STUB(long_branch_any_tls_pic) \ - DEF_STUB(long_branch_v4t_thumb_tls_pic) \ - DEF_STUB(long_branch_arm_nacl) \ - DEF_STUB(long_branch_arm_nacl_pic) \ - DEF_STUB(cmse_branch_thumb_only) \ - DEF_STUB(a8_veneer_b_cond) \ - DEF_STUB(a8_veneer_b) \ - DEF_STUB(a8_veneer_bl) \ - DEF_STUB(a8_veneer_blx) \ - DEF_STUB(long_branch_thumb2_only) \ - DEF_STUB(long_branch_thumb2_only_pure) - -#define DEF_STUB(x) arm_stub_##x, -enum elf32_arm_stub_type -{ - arm_stub_none, - DEF_STUBS - max_stub_type -}; -#undef DEF_STUB - -/* Note the first a8_veneer type. */ -const unsigned arm_stub_a8_veneer_lwm = arm_stub_a8_veneer_b_cond; - -typedef struct -{ - const insn_sequence* template_sequence; - int template_size; -} stub_def; - -#define DEF_STUB(x) {elf32_arm_stub_##x, ARRAY_SIZE(elf32_arm_stub_##x)}, -static const stub_def stub_definitions[] = -{ - {NULL, 0}, - DEF_STUBS -}; - -struct elf32_arm_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump). */ - bfd_vma target_value; - asection *target_section; - - /* Same as above but for the source of the branch to the stub. Used for - Cortex-A8 erratum workaround to patch it to branch to the stub. As - such, source section does not need to be recorded since Cortex-A8 erratum - workaround stubs are only generated when both source and target are in the - same section. */ - bfd_vma source_value; - - /* The instruction which caused this stub to be generated (only valid for - Cortex-A8 erratum workaround stubs at present). */ - unsigned long orig_insn; - - /* The stub type. */ - enum elf32_arm_stub_type stub_type; - /* Its encoding size in bytes. */ - int stub_size; - /* Its template. */ - const insn_sequence *stub_template; - /* The size of the template (number of entries). */ - int stub_template_size; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf32_arm_link_hash_entry *h; - - /* Type of branch. */ - enum arm_st_branch_type branch_type; - - /* Where this stub is being called from, or, in the case of combined - stub sections, the first input section in the group. */ - asection *id_sec; - - /* The name for the local symbol at the start of this stub. The - stub name in the hash table has to be unique; this does not, so - it can be friendlier. */ - char *output_name; -}; - -/* Used to build a map of a section. This is required for mixed-endian - code/data. */ - -typedef struct elf32_elf_section_map -{ - bfd_vma vma; - char type; -} -elf32_arm_section_map; - -/* Information about a VFP11 erratum veneer, or a branch to such a veneer. */ - -typedef enum -{ - VFP11_ERRATUM_BRANCH_TO_ARM_VENEER, - VFP11_ERRATUM_BRANCH_TO_THUMB_VENEER, - VFP11_ERRATUM_ARM_VENEER, - VFP11_ERRATUM_THUMB_VENEER -} -elf32_vfp11_erratum_type; - -typedef struct elf32_vfp11_erratum_list -{ - struct elf32_vfp11_erratum_list *next; - bfd_vma vma; - union - { - struct - { - struct elf32_vfp11_erratum_list *veneer; - unsigned int vfp_insn; - } b; - struct - { - struct elf32_vfp11_erratum_list *branch; - unsigned int id; - } v; - } u; - elf32_vfp11_erratum_type type; -} -elf32_vfp11_erratum_list; - -/* Information about a STM32L4XX erratum veneer, or a branch to such a - veneer. */ -typedef enum -{ - STM32L4XX_ERRATUM_BRANCH_TO_VENEER, - STM32L4XX_ERRATUM_VENEER -} -elf32_stm32l4xx_erratum_type; - -typedef struct elf32_stm32l4xx_erratum_list -{ - struct elf32_stm32l4xx_erratum_list *next; - bfd_vma vma; - union - { - struct - { - struct elf32_stm32l4xx_erratum_list *veneer; - unsigned int insn; - } b; - struct - { - struct elf32_stm32l4xx_erratum_list *branch; - unsigned int id; - } v; - } u; - elf32_stm32l4xx_erratum_type type; -} -elf32_stm32l4xx_erratum_list; - -typedef enum -{ - DELETE_EXIDX_ENTRY, - INSERT_EXIDX_CANTUNWIND_AT_END -} -arm_unwind_edit_type; - -/* A (sorted) list of edits to apply to an unwind table. */ -typedef struct arm_unwind_table_edit -{ - arm_unwind_edit_type type; - /* Note: we sometimes want to insert an unwind entry corresponding to a - section different from the one we're currently writing out, so record the - (text) section this edit relates to here. */ - asection *linked_section; - unsigned int index; - struct arm_unwind_table_edit *next; -} -arm_unwind_table_edit; - -typedef struct _arm_elf_section_data -{ - /* Information about mapping symbols. */ - struct bfd_elf_section_data elf; - unsigned int mapcount; - unsigned int mapsize; - elf32_arm_section_map *map; - /* Information about CPU errata. */ - unsigned int erratumcount; - elf32_vfp11_erratum_list *erratumlist; - unsigned int stm32l4xx_erratumcount; - elf32_stm32l4xx_erratum_list *stm32l4xx_erratumlist; - unsigned int additional_reloc_count; - /* Information about unwind tables. */ - union - { - /* Unwind info attached to a text section. */ - struct - { - asection *arm_exidx_sec; - } text; - - /* Unwind info attached to an .ARM.exidx section. */ - struct - { - arm_unwind_table_edit *unwind_edit_list; - arm_unwind_table_edit *unwind_edit_tail; - } exidx; - } u; -} -_arm_elf_section_data; - -#define elf32_arm_section_data(sec) \ - ((_arm_elf_section_data *) elf_section_data (sec)) - -/* A fix which might be required for Cortex-A8 Thumb-2 branch/TLB erratum. - These fixes are subject to a relaxation procedure (in elf32_arm_size_stubs), - so may be created multiple times: we use an array of these entries whilst - relaxing which we can refresh easily, then create stubs for each potentially - erratum-triggering instruction once we've settled on a solution. */ - -struct a8_erratum_fix -{ - bfd *input_bfd; - asection *section; - bfd_vma offset; - bfd_vma target_offset; - unsigned long orig_insn; - char *stub_name; - enum elf32_arm_stub_type stub_type; - enum arm_st_branch_type branch_type; -}; - -/* A table of relocs applied to branches which might trigger Cortex-A8 - erratum. */ - -struct a8_erratum_reloc -{ - bfd_vma from; - bfd_vma destination; - struct elf32_arm_link_hash_entry *hash; - const char *sym_name; - unsigned int r_type; - enum arm_st_branch_type branch_type; - bfd_boolean non_a8_stub; -}; - -/* The size of the thread control block. */ -#define TCB_SIZE 8 - -/* ARM-specific information about a PLT entry, over and above the usual - gotplt_union. */ -struct arm_plt_info -{ - /* We reference count Thumb references to a PLT entry separately, - so that we can emit the Thumb trampoline only if needed. */ - bfd_signed_vma thumb_refcount; - - /* Some references from Thumb code may be eliminated by BL->BLX - conversion, so record them separately. */ - bfd_signed_vma maybe_thumb_refcount; - - /* How many of the recorded PLT accesses were from non-call relocations. - This information is useful when deciding whether anything takes the - address of an STT_GNU_IFUNC PLT. A value of 0 means that all - non-call references to the function should resolve directly to the - real runtime target. */ - unsigned int noncall_refcount; - - /* Since PLT entries have variable size if the Thumb prologue is - used, we need to record the index into .got.plt instead of - recomputing it from the PLT offset. */ - bfd_signed_vma got_offset; -}; - -/* Information about an .iplt entry for a local STT_GNU_IFUNC symbol. */ -struct arm_local_iplt_info -{ - /* The information that is usually found in the generic ELF part of - the hash table entry. */ - union gotplt_union root; - - /* The information that is usually found in the ARM-specific part of - the hash table entry. */ - struct arm_plt_info arm; - - /* A list of all potential dynamic relocations against this symbol. */ - struct elf_dyn_relocs *dyn_relocs; -}; - -struct elf_arm_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; - - /* Information for local symbols that need entries in .iplt. */ - struct arm_local_iplt_info **local_iplt; - - /* Zero to warn when linking objects with incompatible enum sizes. */ - int no_enum_size_warning; - - /* Zero to warn when linking objects with incompatible wchar_t sizes. */ - int no_wchar_size_warning; -}; - -#define elf_arm_tdata(bfd) \ - ((struct elf_arm_obj_tdata *) (bfd)->tdata.any) - -#define elf32_arm_local_got_tls_type(bfd) \ - (elf_arm_tdata (bfd)->local_got_tls_type) - -#define elf32_arm_local_tlsdesc_gotent(bfd) \ - (elf_arm_tdata (bfd)->local_tlsdesc_gotent) - -#define elf32_arm_local_iplt(bfd) \ - (elf_arm_tdata (bfd)->local_iplt) - -#define is_arm_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == ARM_ELF_DATA) - -static bfd_boolean -elf32_arm_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_arm_obj_tdata), - ARM_ELF_DATA); -} - -#define elf32_arm_hash_entry(ent) ((struct elf32_arm_link_hash_entry *)(ent)) - -/* Arm ELF linker hash entry. */ -struct elf32_arm_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* ARM-specific PLT information. */ - struct arm_plt_info plt; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_IE 4 -#define GOT_TLS_GDESC 8 -#define GOT_TLS_GD_ANY_P(type) ((type & GOT_TLS_GD) || (type & GOT_TLS_GDESC)) - unsigned int tls_type : 8; - - /* True if the symbol's PLT entry is in .iplt rather than .plt. */ - unsigned int is_iplt : 1; - - unsigned int unused : 23; - - /* Offset of the GOTPLT entry reserved for the TLS descriptor, - starting at the end of the jump table. */ - bfd_vma tlsdesc_got; - - /* The symbol marking the real symbol location for exported thumb - symbols with Arm stubs. */ - struct elf_link_hash_entry *export_glue; - - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct elf32_arm_stub_hash_entry *stub_cache; -}; - -/* Traverse an arm ELF linker hash table. */ -#define elf32_arm_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* Get the ARM elf linker hash table from a link_info structure. */ -#define elf32_arm_hash_table(info) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \ - == ARM_ELF_DATA ? ((struct elf32_arm_link_hash_table *) ((info)->hash)) : NULL) - -#define arm_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_arm_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -/* Array to keep track of which stub sections have been created, and - information on stub grouping. */ -struct map_stub -{ - /* This is the section to which stubs in the group will be - attached. */ - asection *link_sec; - /* The stub section. */ - asection *stub_sec; -}; - -#define elf32_arm_compute_jump_table_size(htab) \ - ((htab)->next_tls_desc_index * 4) - -/* ARM ELF linker hash table. */ -struct elf32_arm_link_hash_table -{ - /* The main hash table. */ - struct elf_link_hash_table root; - - /* The size in bytes of the section containing the Thumb-to-ARM glue. */ - bfd_size_type thumb_glue_size; - - /* The size in bytes of the section containing the ARM-to-Thumb glue. */ - bfd_size_type arm_glue_size; - - /* The size in bytes of section containing the ARMv4 BX veneers. */ - bfd_size_type bx_glue_size; - - /* Offsets of ARMv4 BX veneers. Bit1 set if present, and Bit0 set when - veneer has been populated. */ - bfd_vma bx_glue_offset[15]; - - /* The size in bytes of the section containing glue for VFP11 erratum - veneers. */ - bfd_size_type vfp11_erratum_glue_size; - - /* The size in bytes of the section containing glue for STM32L4XX erratum - veneers. */ - bfd_size_type stm32l4xx_erratum_glue_size; - - /* A table of fix locations for Cortex-A8 Thumb-2 branch/TLB erratum. This - holds Cortex-A8 erratum fix locations between elf32_arm_size_stubs() and - elf32_arm_write_section(). */ - struct a8_erratum_fix *a8_erratum_fixes; - unsigned int num_a8_erratum_fixes; - - /* An arbitrary input BFD chosen to hold the glue sections. */ - bfd * bfd_of_glue_owner; - - /* Nonzero to output a BE8 image. */ - int byteswap_code; - - /* Zero if R_ARM_TARGET1 means R_ARM_ABS32. - Nonzero if R_ARM_TARGET1 means R_ARM_REL32. */ - int target1_is_rel; - - /* The relocation to use for R_ARM_TARGET2 relocations. */ - int target2_reloc; - - /* 0 = Ignore R_ARM_V4BX. - 1 = Convert BX to MOV PC. - 2 = Generate v4 interworing stubs. */ - int fix_v4bx; - - /* Whether we should fix the Cortex-A8 Thumb-2 branch/TLB erratum. */ - int fix_cortex_a8; - - /* Whether we should fix the ARM1176 BLX immediate issue. */ - int fix_arm1176; - - /* Nonzero if the ARM/Thumb BLX instructions are available for use. */ - int use_blx; - - /* What sort of code sequences we should look for which may trigger the - VFP11 denorm erratum. */ - bfd_arm_vfp11_fix vfp11_fix; - - /* Global counter for the number of fixes we have emitted. */ - int num_vfp11_fixes; - - /* What sort of code sequences we should look for which may trigger the - STM32L4XX erratum. */ - bfd_arm_stm32l4xx_fix stm32l4xx_fix; - - /* Global counter for the number of fixes we have emitted. */ - int num_stm32l4xx_fixes; - - /* Nonzero to force PIC branch veneers. */ - int pic_veneer; - - /* The number of bytes in the initial entry in the PLT. */ - bfd_size_type plt_header_size; - - /* The number of bytes in the subsequent PLT etries. */ - bfd_size_type plt_entry_size; - - /* True if the target system is VxWorks. */ - int vxworks_p; - - /* True if the target system is Symbian OS. */ - int symbian_p; - - /* True if the target system is Native Client. */ - int nacl_p; - - /* True if the target uses REL relocations. */ - int use_rel; - - /* Nonzero if import library must be a secure gateway import library - as per ARMv8-M Security Extensions. */ - int cmse_implib; - - /* The import library whose symbols' address must remain stable in - the import library generated. */ - bfd *in_implib_bfd; - - /* The index of the next unused R_ARM_TLS_DESC slot in .rel.plt. */ - bfd_vma next_tls_desc_index; - - /* How many R_ARM_TLS_DESC relocations were generated so far. */ - bfd_vma num_tls_desc; - - /* The (unloaded but important) VxWorks .rela.plt.unloaded section. */ - asection *srelplt2; - - /* 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 dt_tlsdesc_plt; - - /* The offset into sgot of the GOT entry used by the PLT entry - above. */ - bfd_vma dt_tlsdesc_got; - - /* Offset in .plt section of tls_arm_trampoline. */ - bfd_vma tls_trampoline; - - /* Data for R_ARM_TLS_LDM32 relocations. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* For convenience in allocate_dynrelocs. */ - bfd * obfd; - - /* 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; - - /* The stub hash table. */ - struct bfd_hash_table stub_hash_table; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *, asection *, - unsigned int); - void (*layout_sections_again) (void); - - /* Array to keep track of which stub sections have been created, and - information on stub grouping. */ - struct map_stub *stub_group; - - /* Input stub section holding secure gateway veneers. */ - asection *cmse_stub_sec; - - /* Offset in cmse_stub_sec where new SG veneers (not in input import library) - start to be allocated. */ - bfd_vma new_cmse_stub_offset; - - /* Number of elements in stub_group. */ - unsigned int top_id; - - /* Assorted information used by elf32_arm_size_stubs. */ - unsigned int bfd_count; - unsigned int top_index; - asection **input_list; -}; - -static inline int -ctz (unsigned int mask) -{ -#if GCC_VERSION >= 3004 - return __builtin_ctz (mask); -#else - unsigned int i; - - for (i = 0; i < 8 * sizeof (mask); i++) - { - if (mask & 0x1) - break; - mask = (mask >> 1); - } - return i; -#endif -} - -static inline int -elf32_arm_popcount (unsigned int mask) -{ -#if GCC_VERSION >= 3004 - return __builtin_popcount (mask); -#else - unsigned int i; - int sum = 0; - - for (i = 0; i < 8 * sizeof (mask); i++) - { - if (mask & 0x1) - sum++; - mask = (mask >> 1); - } - return sum; -#endif -} - -/* Create an entry in an ARM ELF linker hash table. */ - -static struct bfd_hash_entry * -elf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry, - struct bfd_hash_table * table, - const char * string) -{ - struct elf32_arm_link_hash_entry * ret = - (struct elf32_arm_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = (struct elf32_arm_link_hash_entry *) - bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry)); - if (ret == NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf32_arm_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != NULL) - { - ret->dyn_relocs = NULL; - ret->tls_type = GOT_UNKNOWN; - ret->tlsdesc_got = (bfd_vma) -1; - ret->plt.thumb_refcount = 0; - ret->plt.maybe_thumb_refcount = 0; - ret->plt.noncall_refcount = 0; - ret->plt.got_offset = -1; - ret->is_iplt = FALSE; - ret->export_glue = NULL; - - ret->stub_cache = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Ensure that we have allocated bookkeeping structures for ABFD's local - symbols. */ - -static bfd_boolean -elf32_arm_allocate_local_sym_info (bfd *abfd) -{ - if (elf_local_got_refcounts (abfd) == NULL) - { - bfd_size_type num_syms; - bfd_size_type size; - char *data; - - num_syms = elf_tdata (abfd)->symtab_hdr.sh_info; - size = num_syms * (sizeof (bfd_signed_vma) - + sizeof (struct arm_local_iplt_info *) - + sizeof (bfd_vma) - + sizeof (char)); - data = bfd_zalloc (abfd, size); - if (data == NULL) - return FALSE; - - elf_local_got_refcounts (abfd) = (bfd_signed_vma *) data; - data += num_syms * sizeof (bfd_signed_vma); - - elf32_arm_local_iplt (abfd) = (struct arm_local_iplt_info **) data; - data += num_syms * sizeof (struct arm_local_iplt_info *); - - elf32_arm_local_tlsdesc_gotent (abfd) = (bfd_vma *) data; - data += num_syms * sizeof (bfd_vma); - - elf32_arm_local_got_tls_type (abfd) = data; - } - return TRUE; -} - -/* Return the .iplt information for local symbol R_SYMNDX, which belongs - to input bfd ABFD. Create the information if it doesn't already exist. - Return null if an allocation fails. */ - -static struct arm_local_iplt_info * -elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx) -{ - struct arm_local_iplt_info **ptr; - - if (!elf32_arm_allocate_local_sym_info (abfd)) - return NULL; - - BFD_ASSERT (r_symndx < elf_tdata (abfd)->symtab_hdr.sh_info); - ptr = &elf32_arm_local_iplt (abfd)[r_symndx]; - if (*ptr == NULL) - *ptr = bfd_zalloc (abfd, sizeof (**ptr)); - return *ptr; -} - -/* Try to obtain PLT information for the symbol with index R_SYMNDX - in ABFD's symbol table. If the symbol is global, H points to its - hash table entry, otherwise H is null. - - Return true if the symbol does have PLT information. When returning - true, point *ROOT_PLT at the target-independent reference count/offset - union and *ARM_PLT at the ARM-specific information. */ - -static bfd_boolean -elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals, - struct elf32_arm_link_hash_entry *h, - unsigned long r_symndx, union gotplt_union **root_plt, - struct arm_plt_info **arm_plt) -{ - struct arm_local_iplt_info *local_iplt; - - if (globals->root.splt == NULL && globals->root.iplt == NULL) - return FALSE; - - if (h != NULL) - { - *root_plt = &h->root.plt; - *arm_plt = &h->plt; - return TRUE; - } - - if (elf32_arm_local_iplt (abfd) == NULL) - return FALSE; - - local_iplt = elf32_arm_local_iplt (abfd)[r_symndx]; - if (local_iplt == NULL) - return FALSE; - - *root_plt = &local_iplt->root; - *arm_plt = &local_iplt->arm; - return TRUE; -} - -/* Return true if the PLT described by ARM_PLT requires a Thumb stub - before it. */ - -static bfd_boolean -elf32_arm_plt_needs_thumb_stub_p (struct bfd_link_info *info, - struct arm_plt_info *arm_plt) -{ - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - return (arm_plt->thumb_refcount != 0 - || (!htab->use_blx && arm_plt->maybe_thumb_refcount != 0)); -} - -/* Return a pointer to the head of the dynamic reloc list that should - be used for local symbol ISYM, which is symbol number R_SYMNDX in - ABFD's symbol table. Return null if an error occurs. */ - -static struct elf_dyn_relocs ** -elf32_arm_get_local_dynreloc_list (bfd *abfd, unsigned long r_symndx, - Elf_Internal_Sym *isym) -{ - if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - struct arm_local_iplt_info *local_iplt; - - local_iplt = elf32_arm_create_local_iplt (abfd, r_symndx); - if (local_iplt == NULL) - return NULL; - return &local_iplt->dyn_relocs; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - asection *s; - void *vpp; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - abort (); - - vpp = &elf_section_data (s)->local_dynrel; - return (struct elf_dyn_relocs **) vpp; - } -} - -/* Initialize an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_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 elf32_arm_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf32_arm_stub_hash_entry *eh; - - /* Initialize the local fields. */ - eh = (struct elf32_arm_stub_hash_entry *) entry; - eh->stub_sec = NULL; - eh->stub_offset = (bfd_vma) -1; - eh->source_value = 0; - eh->target_value = 0; - eh->target_section = NULL; - eh->orig_insn = 0; - eh->stub_type = arm_stub_none; - eh->stub_size = 0; - eh->stub_template = NULL; - eh->stub_template_size = -1; - eh->h = NULL; - eh->id_sec = NULL; - eh->output_name = NULL; - } - - return entry; -} - -/* Create .got, .gotplt, and .rel(a).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 elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - /* BPABI objects never have a GOT, or associated sections. */ - if (htab->symbian_p) - return TRUE; - - if (! _bfd_elf_create_got_section (dynobj, info)) - return FALSE; - - return TRUE; -} - -/* Create the .iplt, .rel(a).iplt and .igot.plt sections. */ - -static bfd_boolean -create_ifunc_sections (struct bfd_link_info *info) -{ - struct elf32_arm_link_hash_table *htab; - const struct elf_backend_data *bed; - bfd *dynobj; - asection *s; - flagword flags; - - htab = elf32_arm_hash_table (info); - dynobj = htab->root.dynobj; - bed = get_elf_backend_data (dynobj); - flags = bed->dynamic_sec_flags; - - if (htab->root.iplt == NULL) - { - s = bfd_make_section_anyway_with_flags (dynobj, ".iplt", - flags | SEC_READONLY | SEC_CODE); - if (s == NULL - || !bfd_set_section_alignment (dynobj, s, bed->plt_alignment)) - return FALSE; - htab->root.iplt = s; - } - - if (htab->root.irelplt == NULL) - { - s = bfd_make_section_anyway_with_flags (dynobj, - RELOC_SECTION (htab, ".iplt"), - flags | SEC_READONLY); - if (s == NULL - || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) - return FALSE; - htab->root.irelplt = s; - } - - if (htab->root.igotplt == NULL) - { - s = bfd_make_section_anyway_with_flags (dynobj, ".igot.plt", flags); - if (s == NULL - || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) - return FALSE; - htab->root.igotplt = s; - } - return TRUE; -} - -/* Determine if we're dealing with a Thumb only architecture. */ - -static bfd_boolean -using_thumb_only (struct elf32_arm_link_hash_table *globals) -{ - int arch; - int profile = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch_profile); - - if (profile) - return profile == 'M'; - - arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch); - - /* Force return logic to be reviewed for each new architecture. */ - BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN); - - if (arch == TAG_CPU_ARCH_V6_M - || arch == TAG_CPU_ARCH_V6S_M - || arch == TAG_CPU_ARCH_V7E_M - || arch == TAG_CPU_ARCH_V8M_BASE - || arch == TAG_CPU_ARCH_V8M_MAIN) - return TRUE; - - return FALSE; -} - -/* Determine if we're dealing with a Thumb-2 object. */ - -static bfd_boolean -using_thumb2 (struct elf32_arm_link_hash_table *globals) -{ - int arch; - int thumb_isa = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_THUMB_ISA_use); - - if (thumb_isa) - return thumb_isa == 2; - - arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch); - - /* Force return logic to be reviewed for each new architecture. */ - BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN); - - return (arch == TAG_CPU_ARCH_V6T2 - || arch == TAG_CPU_ARCH_V7 - || arch == TAG_CPU_ARCH_V7E_M - || arch == TAG_CPU_ARCH_V8 - || arch == TAG_CPU_ARCH_V8R - || arch == TAG_CPU_ARCH_V8M_MAIN); -} - -/* Determine whether Thumb-2 BL instruction is available. */ - -static bfd_boolean -using_thumb2_bl (struct elf32_arm_link_hash_table *globals) -{ - int arch = - bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch); - - /* Force return logic to be reviewed for each new architecture. */ - BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN); - - /* Architecture was introduced after ARMv6T2 (eg. ARMv6-M). */ - return (arch == TAG_CPU_ARCH_V6T2 - || arch >= TAG_CPU_ARCH_V7); -} - -/* Create .plt, .rel(a).plt, .got, .got.plt, .rel(a).got, .dynbss, and - .rel(a).bss sections in DYNOBJ, and set up shortcuts to them in our - hash table. */ - -static bfd_boolean -elf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - if (!htab->root.sgot && !create_got_section (dynobj, info)) - return FALSE; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - if (htab->vxworks_p) - { - if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) - return FALSE; - - if (bfd_link_pic (info)) - { - htab->plt_header_size = 0; - htab->plt_entry_size - = 4 * ARRAY_SIZE (elf32_arm_vxworks_shared_plt_entry); - } - else - { - htab->plt_header_size - = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt0_entry); - htab->plt_entry_size - = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt_entry); - } - - if (elf_elfheader (dynobj)) - elf_elfheader (dynobj)->e_ident[EI_CLASS] = ELFCLASS32; - } - else - { - /* PR ld/16017 - Test for thumb only architectures. Note - we cannot just call - using_thumb_only() as the attributes in the output bfd have not been - initialised at this point, so instead we use the input bfd. */ - bfd * saved_obfd = htab->obfd; - - htab->obfd = dynobj; - if (using_thumb_only (htab)) - { - htab->plt_header_size = 4 * ARRAY_SIZE (elf32_thumb2_plt0_entry); - htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_thumb2_plt_entry); - } - htab->obfd = saved_obfd; - } - - if (!htab->root.splt - || !htab->root.srelplt - || !htab->root.sdynbss - || (!bfd_link_pic (info) && !htab->root.srelbss)) - abort (); - - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf32_arm_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf32_arm_link_hash_entry *edir, *eind; - - edir = (struct elf32_arm_link_hash_entry *) dir; - eind = (struct elf32_arm_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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) - { - /* Copy over PLT info. */ - edir->plt.thumb_refcount += eind->plt.thumb_refcount; - eind->plt.thumb_refcount = 0; - edir->plt.maybe_thumb_refcount += eind->plt.maybe_thumb_refcount; - eind->plt.maybe_thumb_refcount = 0; - edir->plt.noncall_refcount += eind->plt.noncall_refcount; - eind->plt.noncall_refcount = 0; - - /* We should only allocate a function to .iplt once the final - symbol information is known. */ - BFD_ASSERT (!eind->is_iplt); - - if (dir->got.refcount <= 0) - { - edir->tls_type = eind->tls_type; - eind->tls_type = GOT_UNKNOWN; - } - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Destroy an ARM elf linker hash table. */ - -static void -elf32_arm_link_hash_table_free (bfd *obfd) -{ - struct elf32_arm_link_hash_table *ret - = (struct elf32_arm_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (&ret->stub_hash_table); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create an ARM elf linker hash table. */ - -static struct bfd_link_hash_table * -elf32_arm_link_hash_table_create (bfd *abfd) -{ - struct elf32_arm_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf32_arm_link_hash_table); - - ret = (struct elf32_arm_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (& ret->root, abfd, - elf32_arm_link_hash_newfunc, - sizeof (struct elf32_arm_link_hash_entry), - ARM_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; - ret->stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_NONE; -#ifdef FOUR_WORD_PLT - ret->plt_header_size = 16; - ret->plt_entry_size = 16; -#else - ret->plt_header_size = 20; - ret->plt_entry_size = elf32_arm_use_long_plt_entry ? 16 : 12; -#endif - ret->use_rel = 1; - ret->obfd = abfd; - - if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc, - sizeof (struct elf32_arm_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - ret->root.root.hash_table_free = elf32_arm_link_hash_table_free; - - return &ret->root.root; -} - -/* Determine what kind of NOPs are available. */ - -static bfd_boolean -arch_has_arm_nop (struct elf32_arm_link_hash_table *globals) -{ - const int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch); - - /* Force return logic to be reviewed for each new architecture. */ - BFD_ASSERT (arch <= TAG_CPU_ARCH_V8M_MAIN); - - return (arch == TAG_CPU_ARCH_V6T2 - || arch == TAG_CPU_ARCH_V6K - || arch == TAG_CPU_ARCH_V7 - || arch == TAG_CPU_ARCH_V8 - || arch == TAG_CPU_ARCH_V8R); -} - -static bfd_boolean -arm_stub_is_thumb (enum elf32_arm_stub_type stub_type) -{ - switch (stub_type) - { - case arm_stub_long_branch_thumb_only: - case arm_stub_long_branch_thumb2_only: - case arm_stub_long_branch_thumb2_only_pure: - case arm_stub_long_branch_v4t_thumb_arm: - case arm_stub_short_branch_v4t_thumb_arm: - case arm_stub_long_branch_v4t_thumb_arm_pic: - case arm_stub_long_branch_v4t_thumb_tls_pic: - case arm_stub_long_branch_thumb_only_pic: - case arm_stub_cmse_branch_thumb_only: - return TRUE; - case arm_stub_none: - BFD_FAIL (); - return FALSE; - break; - default: - return FALSE; - } -} - -/* Determine the type of stub needed, if any, for a call. */ - -static enum elf32_arm_stub_type -arm_type_of_stub (struct bfd_link_info *info, - asection *input_sec, - const Elf_Internal_Rela *rel, - unsigned char st_type, - enum arm_st_branch_type *actual_branch_type, - struct elf32_arm_link_hash_entry *hash, - bfd_vma destination, - asection *sym_sec, - bfd *input_bfd, - const char *name) -{ - bfd_vma location; - bfd_signed_vma branch_offset; - unsigned int r_type; - struct elf32_arm_link_hash_table * globals; - bfd_boolean thumb2, thumb2_bl, thumb_only; - enum elf32_arm_stub_type stub_type = arm_stub_none; - int use_plt = 0; - enum arm_st_branch_type branch_type = *actual_branch_type; - union gotplt_union *root_plt; - struct arm_plt_info *arm_plt; - int arch; - int thumb2_movw; - - if (branch_type == ST_BRANCH_LONG) - return stub_type; - - globals = elf32_arm_hash_table (info); - if (globals == NULL) - return stub_type; - - thumb_only = using_thumb_only (globals); - thumb2 = using_thumb2 (globals); - thumb2_bl = using_thumb2_bl (globals); - - arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, Tag_CPU_arch); - - /* True for architectures that implement the thumb2 movw instruction. */ - thumb2_movw = thumb2 || (arch == TAG_CPU_ARCH_V8M_BASE); - - /* Determine where the call point is. */ - location = (input_sec->output_offset - + input_sec->output_section->vma - + rel->r_offset); - - r_type = ELF32_R_TYPE (rel->r_info); - - /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we - are considering a function call relocation. */ - if (thumb_only && (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24 - || r_type == R_ARM_THM_JUMP19) - && branch_type == ST_BRANCH_TO_ARM) - branch_type = ST_BRANCH_TO_THUMB; - - /* For TLS call relocs, it is the caller's responsibility to provide - the address of the appropriate trampoline. */ - if (r_type != R_ARM_TLS_CALL - && r_type != R_ARM_THM_TLS_CALL - && elf32_arm_get_plt_info (input_bfd, globals, hash, - ELF32_R_SYM (rel->r_info), &root_plt, - &arm_plt) - && root_plt->offset != (bfd_vma) -1) - { - asection *splt; - - if (hash == NULL || hash->is_iplt) - splt = globals->root.iplt; - else - splt = globals->root.splt; - if (splt != NULL) - { - use_plt = 1; - - /* Note when dealing with PLT entries: the main PLT stub is in - ARM mode, so if the branch is in Thumb mode, another - Thumb->ARM stub will be inserted later just before the ARM - PLT stub. If a long branch stub is needed, we'll add a - Thumb->Arm one and branch directly to the ARM PLT entry. - Here, we have to check if a pre-PLT Thumb->ARM stub - is needed and if it will be close enough. */ - - destination = (splt->output_section->vma - + splt->output_offset - + root_plt->offset); - st_type = STT_FUNC; - - /* Thumb branch/call to PLT: it can become a branch to ARM - or to Thumb. We must perform the same checks and - corrections as in elf32_arm_final_link_relocate. */ - if ((r_type == R_ARM_THM_CALL) - || (r_type == R_ARM_THM_JUMP24)) - { - if (globals->use_blx - && r_type == R_ARM_THM_CALL - && !thumb_only) - { - /* If the Thumb BLX instruction is available, convert - the BL to a BLX instruction to call the ARM-mode - PLT entry. */ - branch_type = ST_BRANCH_TO_ARM; - } - else - { - if (!thumb_only) - /* Target the Thumb stub before the ARM PLT entry. */ - destination -= PLT_THUMB_STUB_SIZE; - branch_type = ST_BRANCH_TO_THUMB; - } - } - else - { - branch_type = ST_BRANCH_TO_ARM; - } - } - } - /* Calls to STT_GNU_IFUNC symbols should go through a PLT. */ - BFD_ASSERT (st_type != STT_GNU_IFUNC); - - branch_offset = (bfd_signed_vma)(destination - location); - - if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24 - || r_type == R_ARM_THM_TLS_CALL || r_type == R_ARM_THM_JUMP19) - { - /* Handle cases where: - - this call goes too far (different Thumb/Thumb2 max - distance) - - it's a Thumb->Arm call and blx is not available, or it's a - Thumb->Arm branch (not bl). A stub is needed in this case, - but only if this call is not through a PLT entry. Indeed, - PLT stubs handle mode switching already. */ - if ((!thumb2_bl - && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET - || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) - || (thumb2_bl - && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET - || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) - || (thumb2 - && (branch_offset > THM2_MAX_FWD_COND_BRANCH_OFFSET - || (branch_offset < THM2_MAX_BWD_COND_BRANCH_OFFSET)) - && (r_type == R_ARM_THM_JUMP19)) - || (branch_type == ST_BRANCH_TO_ARM - && (((r_type == R_ARM_THM_CALL - || r_type == R_ARM_THM_TLS_CALL) && !globals->use_blx) - || (r_type == R_ARM_THM_JUMP24) - || (r_type == R_ARM_THM_JUMP19)) - && !use_plt)) - { - /* If we need to insert a Thumb-Thumb long branch stub to a - PLT, use one that branches directly to the ARM PLT - stub. If we pretended we'd use the pre-PLT Thumb->ARM - stub, undo this now. */ - if ((branch_type == ST_BRANCH_TO_THUMB) && use_plt && !thumb_only) - { - branch_type = ST_BRANCH_TO_ARM; - branch_offset += PLT_THUMB_STUB_SIZE; - } - - if (branch_type == ST_BRANCH_TO_THUMB) - { - /* Thumb to thumb. */ - if (!thumb_only) - { - if (input_sec->flags & SEC_ELF_PURECODE) - _bfd_error_handler - (_("%B(%A): warning: long branch veneers used in" - " section with SHF_ARM_PURECODE section" - " attribute is only supported for M-profile" - " targets that implement the movw instruction."), - input_bfd, input_sec); - - stub_type = (bfd_link_pic (info) | globals->pic_veneer) - /* PIC stubs. */ - ? ((globals->use_blx - && (r_type == R_ARM_THM_CALL)) - /* V5T and above. Stub starts with ARM code, so - we must be able to switch mode before - reaching it, which is only possible for 'bl' - (ie R_ARM_THM_CALL relocation). */ - ? arm_stub_long_branch_any_thumb_pic - /* On V4T, use Thumb code only. */ - : arm_stub_long_branch_v4t_thumb_thumb_pic) - - /* non-PIC stubs. */ - : ((globals->use_blx - && (r_type == R_ARM_THM_CALL)) - /* V5T and above. */ - ? arm_stub_long_branch_any_any - /* V4T. */ - : arm_stub_long_branch_v4t_thumb_thumb); - } - else - { - if (thumb2_movw && (input_sec->flags & SEC_ELF_PURECODE)) - stub_type = arm_stub_long_branch_thumb2_only_pure; - else - { - if (input_sec->flags & SEC_ELF_PURECODE) - _bfd_error_handler - (_("%B(%A): warning: long branch veneers used in" - " section with SHF_ARM_PURECODE section" - " attribute is only supported for M-profile" - " targets that implement the movw instruction."), - input_bfd, input_sec); - - stub_type = (bfd_link_pic (info) | globals->pic_veneer) - /* PIC stub. */ - ? arm_stub_long_branch_thumb_only_pic - /* non-PIC stub. */ - : (thumb2 ? arm_stub_long_branch_thumb2_only - : arm_stub_long_branch_thumb_only); - } - } - } - else - { - if (input_sec->flags & SEC_ELF_PURECODE) - _bfd_error_handler - (_("%B(%A): warning: long branch veneers used in" - " section with SHF_ARM_PURECODE section" - " attribute is only supported" " for M-profile" - " targets that implement the movw instruction."), - input_bfd, input_sec); - - /* Thumb to arm. */ - if (sym_sec != NULL - && sym_sec->owner != NULL - && !INTERWORK_FLAG (sym_sec->owner)) - { - _bfd_error_handler - (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: Thumb call to ARM"), - sym_sec->owner, name, input_bfd); - } - - stub_type = - (bfd_link_pic (info) | globals->pic_veneer) - /* PIC stubs. */ - ? (r_type == R_ARM_THM_TLS_CALL - /* TLS PIC stubs. */ - ? (globals->use_blx ? arm_stub_long_branch_any_tls_pic - : arm_stub_long_branch_v4t_thumb_tls_pic) - : ((globals->use_blx && r_type == R_ARM_THM_CALL) - /* V5T PIC and above. */ - ? arm_stub_long_branch_any_arm_pic - /* V4T PIC stub. */ - : arm_stub_long_branch_v4t_thumb_arm_pic)) - - /* non-PIC stubs. */ - : ((globals->use_blx && r_type == R_ARM_THM_CALL) - /* V5T and above. */ - ? arm_stub_long_branch_any_any - /* V4T. */ - : arm_stub_long_branch_v4t_thumb_arm); - - /* Handle v4t short branches. */ - if ((stub_type == arm_stub_long_branch_v4t_thumb_arm) - && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) - && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) - stub_type = arm_stub_short_branch_v4t_thumb_arm; - } - } - } - else if (r_type == R_ARM_CALL - || r_type == R_ARM_JUMP24 - || r_type == R_ARM_PLT32 - || r_type == R_ARM_TLS_CALL) - { - if (input_sec->flags & SEC_ELF_PURECODE) - _bfd_error_handler - (_("%B(%A): warning: long branch veneers used in" - " section with SHF_ARM_PURECODE section" - " attribute is only supported for M-profile" - " targets that implement the movw instruction."), - input_bfd, input_sec); - if (branch_type == ST_BRANCH_TO_THUMB) - { - /* Arm to thumb. */ - - if (sym_sec != NULL - && sym_sec->owner != NULL - && !INTERWORK_FLAG (sym_sec->owner)) - { - _bfd_error_handler - (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: ARM call to Thumb"), - sym_sec->owner, name, input_bfd); - } - - /* We have an extra 2-bytes reach because of - the mode change (bit 24 (H) of BLX encoding). */ - if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) - || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) - || (r_type == R_ARM_CALL && !globals->use_blx) - || (r_type == R_ARM_JUMP24) - || (r_type == R_ARM_PLT32)) - { - stub_type = (bfd_link_pic (info) | globals->pic_veneer) - /* PIC stubs. */ - ? ((globals->use_blx) - /* V5T and above. */ - ? arm_stub_long_branch_any_thumb_pic - /* V4T stub. */ - : arm_stub_long_branch_v4t_arm_thumb_pic) - - /* non-PIC stubs. */ - : ((globals->use_blx) - /* V5T and above. */ - ? arm_stub_long_branch_any_any - /* V4T. */ - : arm_stub_long_branch_v4t_arm_thumb); - } - } - else - { - /* Arm to arm. */ - if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET - || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) - { - stub_type = - (bfd_link_pic (info) | globals->pic_veneer) - /* PIC stubs. */ - ? (r_type == R_ARM_TLS_CALL - /* TLS PIC Stub. */ - ? arm_stub_long_branch_any_tls_pic - : (globals->nacl_p - ? arm_stub_long_branch_arm_nacl_pic - : arm_stub_long_branch_any_arm_pic)) - /* non-PIC stubs. */ - : (globals->nacl_p - ? arm_stub_long_branch_arm_nacl - : arm_stub_long_branch_any_any); - } - } - } - - /* If a stub is needed, record the actual destination type. */ - if (stub_type != arm_stub_none) - *actual_branch_type = branch_type; - - return stub_type; -} - -/* Build a name for an entry in the stub hash table. */ - -static char * -elf32_arm_stub_name (const asection *input_section, - const asection *sym_sec, - const struct elf32_arm_link_hash_entry *hash, - const Elf_Internal_Rela *rel, - enum elf32_arm_stub_type stub_type) -{ - char *stub_name; - bfd_size_type len; - - if (hash) - { - len = 8 + 1 + strlen (hash->root.root.root.string) + 1 + 8 + 1 + 2 + 1; - stub_name = (char *) bfd_malloc (len); - if (stub_name != NULL) - sprintf (stub_name, "%08x_%s+%x_%d", - input_section->id & 0xffffffff, - hash->root.root.root.string, - (int) rel->r_addend & 0xffffffff, - (int) stub_type); - } - else - { - len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 2 + 1; - stub_name = (char *) bfd_malloc (len); - if (stub_name != NULL) - sprintf (stub_name, "%08x_%x:%x+%x_%d", - input_section->id & 0xffffffff, - sym_sec->id & 0xffffffff, - ELF32_R_TYPE (rel->r_info) == R_ARM_TLS_CALL - || ELF32_R_TYPE (rel->r_info) == R_ARM_THM_TLS_CALL - ? 0 : (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, - (int) rel->r_addend & 0xffffffff, - (int) stub_type); - } - - return stub_name; -} - -/* Look up an entry in the stub hash. Stub entries are cached because - creating the stub name takes a bit of time. */ - -static struct elf32_arm_stub_hash_entry * -elf32_arm_get_stub_entry (const asection *input_section, - const asection *sym_sec, - struct elf_link_hash_entry *hash, - const Elf_Internal_Rela *rel, - struct elf32_arm_link_hash_table *htab, - enum elf32_arm_stub_type stub_type) -{ - struct elf32_arm_stub_hash_entry *stub_entry; - struct elf32_arm_link_hash_entry *h = (struct elf32_arm_link_hash_entry *) hash; - const asection *id_sec; - - if ((input_section->flags & SEC_CODE) == 0) - return NULL; - - /* If this input section is part of a group of sections sharing one - stub section, then use the id of the first section in the group. - Stub names need to include a section id, as there may well be - more than one stub used to reach say, printf, and we need to - distinguish between them. */ - BFD_ASSERT (input_section->id <= htab->top_id); - id_sec = htab->stub_group[input_section->id].link_sec; - - if (h != NULL && h->stub_cache != NULL - && h->stub_cache->h == h - && h->stub_cache->id_sec == id_sec - && h->stub_cache->stub_type == stub_type) - { - stub_entry = h->stub_cache; - } - else - { - char *stub_name; - - stub_name = elf32_arm_stub_name (id_sec, sym_sec, h, rel, stub_type); - if (stub_name == NULL) - return NULL; - - stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, - stub_name, FALSE, FALSE); - if (h != NULL) - h->stub_cache = stub_entry; - - free (stub_name); - } - - return stub_entry; -} - -/* Whether veneers of type STUB_TYPE require to be in a dedicated output - section. */ - -static bfd_boolean -arm_dedicated_stub_output_section_required (enum elf32_arm_stub_type stub_type) -{ - if (stub_type >= max_stub_type) - abort (); /* Should be unreachable. */ - - switch (stub_type) - { - case arm_stub_cmse_branch_thumb_only: - return TRUE; - - default: - return FALSE; - } - - abort (); /* Should be unreachable. */ -} - -/* Required alignment (as a power of 2) for the dedicated section holding - veneers of type STUB_TYPE, or 0 if veneers of this type are interspersed - with input sections. */ - -static int -arm_dedicated_stub_output_section_required_alignment - (enum elf32_arm_stub_type stub_type) -{ - if (stub_type >= max_stub_type) - abort (); /* Should be unreachable. */ - - switch (stub_type) - { - /* Vectors of Secure Gateway veneers must be aligned on 32byte - boundary. */ - case arm_stub_cmse_branch_thumb_only: - return 5; - - default: - BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type)); - return 0; - } - - abort (); /* Should be unreachable. */ -} - -/* Name of the dedicated output section to put veneers of type STUB_TYPE, or - NULL if veneers of this type are interspersed with input sections. */ - -static const char * -arm_dedicated_stub_output_section_name (enum elf32_arm_stub_type stub_type) -{ - if (stub_type >= max_stub_type) - abort (); /* Should be unreachable. */ - - switch (stub_type) - { - case arm_stub_cmse_branch_thumb_only: - return ".gnu.sgstubs"; - - default: - BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type)); - return NULL; - } - - abort (); /* Should be unreachable. */ -} - -/* If veneers of type STUB_TYPE should go in a dedicated output section, - returns the address of the hash table field in HTAB holding a pointer to the - corresponding input section. Otherwise, returns NULL. */ - -static asection ** -arm_dedicated_stub_input_section_ptr (struct elf32_arm_link_hash_table *htab, - enum elf32_arm_stub_type stub_type) -{ - if (stub_type >= max_stub_type) - abort (); /* Should be unreachable. */ - - switch (stub_type) - { - case arm_stub_cmse_branch_thumb_only: - return &htab->cmse_stub_sec; - - default: - BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type)); - return NULL; - } - - abort (); /* Should be unreachable. */ -} - -/* Find or create a stub section to contain a stub of type STUB_TYPE. SECTION - is the section that branch into veneer and can be NULL if stub should go in - a dedicated output section. Returns a pointer to the stub section, and the - section to which the stub section will be attached (in *LINK_SEC_P). - LINK_SEC_P may be NULL. */ - -static asection * -elf32_arm_create_or_find_stub_sec (asection **link_sec_p, asection *section, - struct elf32_arm_link_hash_table *htab, - enum elf32_arm_stub_type stub_type) -{ - asection *link_sec, *out_sec, **stub_sec_p; - const char *stub_sec_prefix; - bfd_boolean dedicated_output_section = - arm_dedicated_stub_output_section_required (stub_type); - int align; - - if (dedicated_output_section) - { - bfd *output_bfd = htab->obfd; - const char *out_sec_name = - arm_dedicated_stub_output_section_name (stub_type); - link_sec = NULL; - stub_sec_p = arm_dedicated_stub_input_section_ptr (htab, stub_type); - stub_sec_prefix = out_sec_name; - align = arm_dedicated_stub_output_section_required_alignment (stub_type); - out_sec = bfd_get_section_by_name (output_bfd, out_sec_name); - if (out_sec == NULL) - { - _bfd_error_handler (_("No address assigned to the veneers output " - "section %s"), out_sec_name); - return NULL; - } - } - else - { - BFD_ASSERT (section->id <= htab->top_id); - link_sec = htab->stub_group[section->id].link_sec; - BFD_ASSERT (link_sec != NULL); - stub_sec_p = &htab->stub_group[section->id].stub_sec; - if (*stub_sec_p == NULL) - stub_sec_p = &htab->stub_group[link_sec->id].stub_sec; - stub_sec_prefix = link_sec->name; - out_sec = link_sec->output_section; - align = htab->nacl_p ? 4 : 3; - } - - if (*stub_sec_p == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (stub_sec_prefix); - len = namelen + sizeof (STUB_SUFFIX); - s_name = (char *) bfd_alloc (htab->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, stub_sec_prefix, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - *stub_sec_p = (*htab->add_stub_section) (s_name, out_sec, link_sec, - align); - if (*stub_sec_p == NULL) - return NULL; - - out_sec->flags |= SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE - | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY - | SEC_KEEP; - } - - if (!dedicated_output_section) - htab->stub_group[section->id].stub_sec = *stub_sec_p; - - if (link_sec_p) - *link_sec_p = link_sec; - - return *stub_sec_p; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ - -static struct elf32_arm_stub_hash_entry * -elf32_arm_add_stub (const char *stub_name, asection *section, - struct elf32_arm_link_hash_table *htab, - enum elf32_arm_stub_type stub_type) -{ - asection *link_sec; - asection *stub_sec; - struct elf32_arm_stub_hash_entry *stub_entry; - - stub_sec = elf32_arm_create_or_find_stub_sec (&link_sec, section, htab, - stub_type); - if (stub_sec == NULL) - return NULL; - - /* Enter this entry into the linker stub hash table. */ - stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, - TRUE, FALSE); - if (stub_entry == NULL) - { - if (section == NULL) - section = stub_sec; - _bfd_error_handler (_("%B: cannot create stub entry %s"), - section->owner, stub_name); - return NULL; - } - - stub_entry->stub_sec = stub_sec; - stub_entry->stub_offset = (bfd_vma) -1; - stub_entry->id_sec = link_sec; - - return stub_entry; -} - -/* Store an Arm insn into an output section not processed by - elf32_arm_write_section. */ - -static void -put_arm_insn (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, bfd_vma val, void * ptr) -{ - if (htab->byteswap_code != bfd_little_endian (output_bfd)) - bfd_putl32 (val, ptr); - else - bfd_putb32 (val, ptr); -} - -/* Store a 16-bit Thumb insn into an output section not processed by - elf32_arm_write_section. */ - -static void -put_thumb_insn (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, bfd_vma val, void * ptr) -{ - if (htab->byteswap_code != bfd_little_endian (output_bfd)) - bfd_putl16 (val, ptr); - else - bfd_putb16 (val, ptr); -} - -/* Store a Thumb2 insn into an output section not processed by - elf32_arm_write_section. */ - -static void -put_thumb2_insn (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, bfd_vma val, bfd_byte * ptr) -{ - /* T2 instructions are 16-bit streamed. */ - if (htab->byteswap_code != bfd_little_endian (output_bfd)) - { - bfd_putl16 ((val >> 16) & 0xffff, ptr); - bfd_putl16 ((val & 0xffff), ptr + 2); - } - else - { - bfd_putb16 ((val >> 16) & 0xffff, ptr); - bfd_putb16 ((val & 0xffff), ptr + 2); - } -} - -/* If it's possible to change R_TYPE to a more efficient access - model, return the new reloc type. */ - -static unsigned -elf32_arm_tls_transition (struct bfd_link_info *info, int r_type, - struct elf_link_hash_entry *h) -{ - int is_local = (h == NULL); - - if (bfd_link_pic (info) - || (h && h->root.type == bfd_link_hash_undefweak)) - return r_type; - - /* We do not support relaxations for Old TLS models. */ - switch (r_type) - { - case R_ARM_TLS_GOTDESC: - case R_ARM_TLS_CALL: - case R_ARM_THM_TLS_CALL: - case R_ARM_TLS_DESCSEQ: - case R_ARM_THM_TLS_DESCSEQ: - return is_local ? R_ARM_TLS_LE32 : R_ARM_TLS_IE32; - } - - return r_type; -} - -static bfd_reloc_status_type elf32_arm_final_link_relocate - (reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, bfd_vma, struct bfd_link_info *, asection *, - const char *, unsigned char, enum arm_st_branch_type, - struct elf_link_hash_entry *, bfd_boolean *, char **); - -static unsigned int -arm_stub_required_alignment (enum elf32_arm_stub_type stub_type) -{ - switch (stub_type) - { - case arm_stub_a8_veneer_b_cond: - case arm_stub_a8_veneer_b: - case arm_stub_a8_veneer_bl: - return 2; - - case arm_stub_long_branch_any_any: - case arm_stub_long_branch_v4t_arm_thumb: - case arm_stub_long_branch_thumb_only: - case arm_stub_long_branch_thumb2_only: - case arm_stub_long_branch_thumb2_only_pure: - case arm_stub_long_branch_v4t_thumb_thumb: - case arm_stub_long_branch_v4t_thumb_arm: - case arm_stub_short_branch_v4t_thumb_arm: - case arm_stub_long_branch_any_arm_pic: - case arm_stub_long_branch_any_thumb_pic: - case arm_stub_long_branch_v4t_thumb_thumb_pic: - case arm_stub_long_branch_v4t_arm_thumb_pic: - case arm_stub_long_branch_v4t_thumb_arm_pic: - case arm_stub_long_branch_thumb_only_pic: - case arm_stub_long_branch_any_tls_pic: - case arm_stub_long_branch_v4t_thumb_tls_pic: - case arm_stub_cmse_branch_thumb_only: - case arm_stub_a8_veneer_blx: - return 4; - - case arm_stub_long_branch_arm_nacl: - case arm_stub_long_branch_arm_nacl_pic: - return 16; - - default: - abort (); /* Should be unreachable. */ - } -} - -/* Returns whether stubs of type STUB_TYPE take over the symbol they are - veneering (TRUE) or have their own symbol (FALSE). */ - -static bfd_boolean -arm_stub_sym_claimed (enum elf32_arm_stub_type stub_type) -{ - if (stub_type >= max_stub_type) - abort (); /* Should be unreachable. */ - - switch (stub_type) - { - case arm_stub_cmse_branch_thumb_only: - return TRUE; - - default: - return FALSE; - } - - abort (); /* Should be unreachable. */ -} - -/* Returns the padding needed for the dedicated section used stubs of type - STUB_TYPE. */ - -static int -arm_dedicated_stub_section_padding (enum elf32_arm_stub_type stub_type) -{ - if (stub_type >= max_stub_type) - abort (); /* Should be unreachable. */ - - switch (stub_type) - { - case arm_stub_cmse_branch_thumb_only: - return 32; - - default: - return 0; - } - - abort (); /* Should be unreachable. */ -} - -/* If veneers of type STUB_TYPE should go in a dedicated output section, - returns the address of the hash table field in HTAB holding the offset at - which new veneers should be layed out in the stub section. */ - -static bfd_vma* -arm_new_stubs_start_offset_ptr (struct elf32_arm_link_hash_table *htab, - enum elf32_arm_stub_type stub_type) -{ - switch (stub_type) - { - case arm_stub_cmse_branch_thumb_only: - return &htab->new_cmse_stub_offset; - - default: - BFD_ASSERT (!arm_dedicated_stub_output_section_required (stub_type)); - return NULL; - } -} - -static bfd_boolean -arm_build_one_stub (struct bfd_hash_entry *gen_entry, - void * in_arg) -{ -#define MAXRELOCS 3 - bfd_boolean removed_sg_veneer; - struct elf32_arm_stub_hash_entry *stub_entry; - struct elf32_arm_link_hash_table *globals; - struct bfd_link_info *info; - asection *stub_sec; - bfd *stub_bfd; - bfd_byte *loc; - bfd_vma sym_value; - int template_size; - int size; - const insn_sequence *template_sequence; - int i; - int stub_reloc_idx[MAXRELOCS] = {-1, -1}; - int stub_reloc_offset[MAXRELOCS] = {0, 0}; - int nrelocs = 0; - int just_allocated = 0; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - info = (struct bfd_link_info *) in_arg; - - globals = elf32_arm_hash_table (info); - if (globals == NULL) - return FALSE; - - stub_sec = stub_entry->stub_sec; - - if ((globals->fix_cortex_a8 < 0) - != (arm_stub_required_alignment (stub_entry->stub_type) == 2)) - /* We have to do less-strictly-aligned fixes last. */ - return TRUE; - - /* Assign a slot at the end of section if none assigned yet. */ - if (stub_entry->stub_offset == (bfd_vma) -1) - { - stub_entry->stub_offset = stub_sec->size; - just_allocated = 1; - } - loc = stub_sec->contents + stub_entry->stub_offset; - - stub_bfd = stub_sec->owner; - - /* This is the address of the stub destination. */ - sym_value = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - - template_sequence = stub_entry->stub_template; - template_size = stub_entry->stub_template_size; - - size = 0; - for (i = 0; i < template_size; i++) - { - switch (template_sequence[i].type) - { - case THUMB16_TYPE: - { - bfd_vma data = (bfd_vma) template_sequence[i].data; - if (template_sequence[i].reloc_addend != 0) - { - /* We've borrowed the reloc_addend field to mean we should - insert a condition code into this (Thumb-1 branch) - instruction. See THUMB16_BCOND_INSN. */ - BFD_ASSERT ((data & 0xff00) == 0xd000); - data |= ((stub_entry->orig_insn >> 22) & 0xf) << 8; - } - bfd_put_16 (stub_bfd, data, loc + size); - size += 2; - } - break; - - case THUMB32_TYPE: - bfd_put_16 (stub_bfd, - (template_sequence[i].data >> 16) & 0xffff, - loc + size); - bfd_put_16 (stub_bfd, template_sequence[i].data & 0xffff, - loc + size + 2); - if (template_sequence[i].r_type != R_ARM_NONE) - { - stub_reloc_idx[nrelocs] = i; - stub_reloc_offset[nrelocs++] = size; - } - size += 4; - break; - - case ARM_TYPE: - bfd_put_32 (stub_bfd, template_sequence[i].data, - loc + size); - /* Handle cases where the target is encoded within the - instruction. */ - if (template_sequence[i].r_type == R_ARM_JUMP24) - { - stub_reloc_idx[nrelocs] = i; - stub_reloc_offset[nrelocs++] = size; - } - size += 4; - break; - - case DATA_TYPE: - bfd_put_32 (stub_bfd, template_sequence[i].data, loc + size); - stub_reloc_idx[nrelocs] = i; - stub_reloc_offset[nrelocs++] = size; - size += 4; - break; - - default: - BFD_FAIL (); - return FALSE; - } - } - - if (just_allocated) - stub_sec->size += size; - - /* Stub size has already been computed in arm_size_one_stub. Check - consistency. */ - BFD_ASSERT (size == stub_entry->stub_size); - - /* Destination is Thumb. Force bit 0 to 1 to reflect this. */ - if (stub_entry->branch_type == ST_BRANCH_TO_THUMB) - sym_value |= 1; - - /* Assume non empty slots have at least one and at most MAXRELOCS entries - to relocate in each stub. */ - removed_sg_veneer = - (size == 0 && stub_entry->stub_type == arm_stub_cmse_branch_thumb_only); - BFD_ASSERT (removed_sg_veneer || (nrelocs != 0 && nrelocs <= MAXRELOCS)); - - for (i = 0; i < nrelocs; i++) - { - Elf_Internal_Rela rel; - bfd_boolean unresolved_reloc; - char *error_message; - bfd_vma points_to = - sym_value + template_sequence[stub_reloc_idx[i]].reloc_addend; - - rel.r_offset = stub_entry->stub_offset + stub_reloc_offset[i]; - rel.r_info = ELF32_R_INFO (0, - template_sequence[stub_reloc_idx[i]].r_type); - rel.r_addend = 0; - - if (stub_entry->stub_type == arm_stub_a8_veneer_b_cond && i == 0) - /* The first relocation in the elf32_arm_stub_a8_veneer_b_cond[] - template should refer back to the instruction after the original - branch. We use target_section as Cortex-A8 erratum workaround stubs - are only generated when both source and target are in the same - section. */ - points_to = stub_entry->target_section->output_section->vma - + stub_entry->target_section->output_offset - + stub_entry->source_value; - - elf32_arm_final_link_relocate (elf32_arm_howto_from_type - (template_sequence[stub_reloc_idx[i]].r_type), - stub_bfd, info->output_bfd, stub_sec, stub_sec->contents, &rel, - points_to, info, stub_entry->target_section, "", STT_FUNC, - stub_entry->branch_type, - (struct elf_link_hash_entry *) stub_entry->h, &unresolved_reloc, - &error_message); - } - - return TRUE; -#undef MAXRELOCS -} - -/* Calculate the template, template size and instruction size for a stub. - Return value is the instruction size. */ - -static unsigned int -find_stub_size_and_template (enum elf32_arm_stub_type stub_type, - const insn_sequence **stub_template, - int *stub_template_size) -{ - const insn_sequence *template_sequence = NULL; - int template_size = 0, i; - unsigned int size; - - template_sequence = stub_definitions[stub_type].template_sequence; - if (stub_template) - *stub_template = template_sequence; - - template_size = stub_definitions[stub_type].template_size; - if (stub_template_size) - *stub_template_size = template_size; - - size = 0; - for (i = 0; i < template_size; i++) - { - switch (template_sequence[i].type) - { - case THUMB16_TYPE: - size += 2; - break; - - case ARM_TYPE: - case THUMB32_TYPE: - case DATA_TYPE: - size += 4; - break; - - default: - BFD_FAIL (); - return 0; - } - } - - return size; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ - -static bfd_boolean -arm_size_one_stub (struct bfd_hash_entry *gen_entry, - void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_arm_stub_hash_entry *stub_entry; - const insn_sequence *template_sequence; - int template_size, size; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - - BFD_ASSERT((stub_entry->stub_type > arm_stub_none) - && stub_entry->stub_type < ARRAY_SIZE(stub_definitions)); - - size = find_stub_size_and_template (stub_entry->stub_type, &template_sequence, - &template_size); - - /* Initialized to -1. Null size indicates an empty slot full of zeros. */ - if (stub_entry->stub_template_size) - { - stub_entry->stub_size = size; - stub_entry->stub_template = template_sequence; - stub_entry->stub_template_size = template_size; - } - - /* Already accounted for. */ - if (stub_entry->stub_offset != (bfd_vma) -1) - return TRUE; - - size = (size + 7) & ~7; - stub_entry->stub_sec->size += size; - - return TRUE; -} - -/* External entry points for sizing and building linker stubs. */ - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ - -int -elf32_arm_setup_section_lists (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - bfd_size_type amt; - struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); - - if (htab == NULL) - return 0; - if (! is_elf_hash_table (htab)) - return 0; - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - if (top_id < section->id) - top_id = section->id; - } - } - htab->bfd_count = bfd_count; - - amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = (struct map_stub *) bfd_zmalloc (amt); - if (htab->stub_group == NULL) - return -1; - htab->top_id = top_id; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - _bfd_strip_section_from_output doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = (asection **) bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - { - if ((section->flags & SEC_CODE) != 0) - input_list[section->index] = NULL; - } - - return 1; -} - -/* The linker repeatedly calls this function for each input section, - in the order that input sections are linked into output sections. - Build lists of input sections to determine groupings between which - we may insert linker stubs. */ - -void -elf32_arm_next_input_section (struct bfd_link_info *info, - asection *isec) -{ - struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); - - if (htab == NULL) - return; - - if (isec->output_section->index <= htab->top_index) - { - asection **list = htab->input_list + isec->output_section->index; - - if (*list != bfd_abs_section_ptr && (isec->flags & SEC_CODE) != 0) - { - /* Steal the link_sec pointer for our list. */ -#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) - /* This happens to make the list in reverse order, - which we reverse later. */ - PREV_SEC (isec) = *list; - *list = isec; - } - } -} - -/* See whether we can group stub sections together. Grouping stub - sections may result in fewer stubs. More importantly, we need to - put all .init* and .fini* stubs at the end of the .init or - .fini output sections respectively, because glibc splits the - _init and _fini functions into multiple parts. Putting a stub in - the middle of a function is not a good idea. */ - -static void -group_sections (struct elf32_arm_link_hash_table *htab, - bfd_size_type stub_group_size, - bfd_boolean stubs_always_after_branch) -{ - asection **list = htab->input_list; - - do - { - asection *tail = *list; - asection *head; - - if (tail == bfd_abs_section_ptr) - continue; - - /* Reverse the list: we must avoid placing stubs at the - beginning of the section because the beginning of the text - section may be required for an interrupt vector in bare metal - code. */ -#define NEXT_SEC PREV_SEC - head = NULL; - while (tail != NULL) - { - /* Pop from tail. */ - asection *item = tail; - tail = PREV_SEC (item); - - /* Push on head. */ - NEXT_SEC (item) = head; - head = item; - } - - while (head != NULL) - { - asection *curr; - asection *next; - bfd_vma stub_group_start = head->output_offset; - bfd_vma end_of_next; - - curr = head; - while (NEXT_SEC (curr) != NULL) - { - next = NEXT_SEC (curr); - end_of_next = next->output_offset + next->size; - if (end_of_next - stub_group_start >= stub_group_size) - /* End of NEXT is too far from start, so stop. */ - break; - /* Add NEXT to the group. */ - curr = next; - } - - /* OK, the size from the start to the start of CURR is less - than stub_group_size and thus can be handled by one stub - section. (Or the head section is itself larger than - stub_group_size, in which case we may be toast.) - We should really be keeping track of the total size of - stubs added here, as stubs contribute to the final output - section size. */ - do - { - next = NEXT_SEC (head); - /* Set up this stub group. */ - htab->stub_group[head->id].link_sec = curr; - } - while (head != curr && (head = next) != NULL); - - /* But wait, there's more! Input sections up to stub_group_size - bytes after the stub section can be handled by it too. */ - if (!stubs_always_after_branch) - { - stub_group_start = curr->output_offset + curr->size; - - while (next != NULL) - { - end_of_next = next->output_offset + next->size; - if (end_of_next - stub_group_start >= stub_group_size) - /* End of NEXT is too far from stubs, so stop. */ - break; - /* Add NEXT to the stub group. */ - head = next; - next = NEXT_SEC (head); - htab->stub_group[head->id].link_sec = curr; - } - } - head = next; - } - } - while (list++ != htab->input_list + htab->top_index); - - free (htab->input_list); -#undef PREV_SEC -#undef NEXT_SEC -} - -/* Comparison function for sorting/searching relocations relating to Cortex-A8 - erratum fix. */ - -static int -a8_reloc_compare (const void *a, const void *b) -{ - const struct a8_erratum_reloc *ra = (const struct a8_erratum_reloc *) a; - const struct a8_erratum_reloc *rb = (const struct a8_erratum_reloc *) b; - - if (ra->from < rb->from) - return -1; - else if (ra->from > rb->from) - return 1; - else - return 0; -} - -static struct elf_link_hash_entry *find_thumb_glue (struct bfd_link_info *, - const char *, char **); - -/* Helper function to scan code for sequences which might trigger the Cortex-A8 - branch/TLB erratum. Fill in the table described by A8_FIXES_P, - NUM_A8_FIXES_P, A8_FIX_TABLE_SIZE_P. Returns true if an error occurs, false - otherwise. */ - -static bfd_boolean -cortex_a8_erratum_scan (bfd *input_bfd, - struct bfd_link_info *info, - struct a8_erratum_fix **a8_fixes_p, - unsigned int *num_a8_fixes_p, - unsigned int *a8_fix_table_size_p, - struct a8_erratum_reloc *a8_relocs, - unsigned int num_a8_relocs, - unsigned prev_num_a8_fixes, - bfd_boolean *stub_changed_p) -{ - asection *section; - struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); - struct a8_erratum_fix *a8_fixes = *a8_fixes_p; - unsigned int num_a8_fixes = *num_a8_fixes_p; - unsigned int a8_fix_table_size = *a8_fix_table_size_p; - - if (htab == NULL) - return FALSE; - - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - bfd_byte *contents = NULL; - struct _arm_elf_section_data *sec_data; - unsigned int span; - bfd_vma base_vma; - - if (elf_section_type (section) != SHT_PROGBITS - || (elf_section_flags (section) & SHF_EXECINSTR) == 0 - || (section->flags & SEC_EXCLUDE) != 0 - || (section->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - || (section->output_section == bfd_abs_section_ptr)) - continue; - - base_vma = section->output_section->vma + section->output_offset; - - if (elf_section_data (section)->this_hdr.contents != NULL) - contents = elf_section_data (section)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (input_bfd, section, &contents)) - return TRUE; - - sec_data = elf32_arm_section_data (section); - - for (span = 0; span < sec_data->mapcount; span++) - { - unsigned int span_start = sec_data->map[span].vma; - unsigned int span_end = (span == sec_data->mapcount - 1) - ? section->size : sec_data->map[span + 1].vma; - unsigned int i; - char span_type = sec_data->map[span].type; - bfd_boolean last_was_32bit = FALSE, last_was_branch = FALSE; - - if (span_type != 't') - continue; - - /* Span is entirely within a single 4KB region: skip scanning. */ - if (((base_vma + span_start) & ~0xfff) - == ((base_vma + span_end) & ~0xfff)) - continue; - - /* Scan for 32-bit Thumb-2 branches which span two 4K regions, where: - - * The opcode is BLX.W, BL.W, B.W, Bcc.W - * The branch target is in the same 4KB region as the - first half of the branch. - * The instruction before the branch is a 32-bit - length non-branch instruction. */ - for (i = span_start; i < span_end;) - { - unsigned int insn = bfd_getl16 (&contents[i]); - bfd_boolean insn_32bit = FALSE, is_blx = FALSE, is_b = FALSE; - bfd_boolean is_bl = FALSE, is_bcc = FALSE, is_32bit_branch; - - if ((insn & 0xe000) == 0xe000 && (insn & 0x1800) != 0x0000) - insn_32bit = TRUE; - - if (insn_32bit) - { - /* Load the rest of the insn (in manual-friendly order). */ - insn = (insn << 16) | bfd_getl16 (&contents[i + 2]); - - /* Encoding T4: B.W. */ - is_b = (insn & 0xf800d000) == 0xf0009000; - /* Encoding T1: BL.W. */ - is_bl = (insn & 0xf800d000) == 0xf000d000; - /* Encoding T2: BLX.W. */ - is_blx = (insn & 0xf800d000) == 0xf000c000; - /* Encoding T3: B.W (not permitted in IT block). */ - is_bcc = (insn & 0xf800d000) == 0xf0008000 - && (insn & 0x07f00000) != 0x03800000; - } - - is_32bit_branch = is_b || is_bl || is_blx || is_bcc; - - if (((base_vma + i) & 0xfff) == 0xffe - && insn_32bit - && is_32bit_branch - && last_was_32bit - && ! last_was_branch) - { - bfd_signed_vma offset = 0; - bfd_boolean force_target_arm = FALSE; - bfd_boolean force_target_thumb = FALSE; - bfd_vma target; - enum elf32_arm_stub_type stub_type = arm_stub_none; - struct a8_erratum_reloc key, *found; - bfd_boolean use_plt = FALSE; - - key.from = base_vma + i; - found = (struct a8_erratum_reloc *) - bsearch (&key, a8_relocs, num_a8_relocs, - sizeof (struct a8_erratum_reloc), - &a8_reloc_compare); - - if (found) - { - char *error_message = NULL; - struct elf_link_hash_entry *entry; - - /* We don't care about the error returned from this - function, only if there is glue or not. */ - entry = find_thumb_glue (info, found->sym_name, - &error_message); - - if (entry) - found->non_a8_stub = TRUE; - - /* Keep a simpler condition, for the sake of clarity. */ - if (htab->root.splt != NULL && found->hash != NULL - && found->hash->root.plt.offset != (bfd_vma) -1) - use_plt = TRUE; - - if (found->r_type == R_ARM_THM_CALL) - { - if (found->branch_type == ST_BRANCH_TO_ARM - || use_plt) - force_target_arm = TRUE; - else - force_target_thumb = TRUE; - } - } - - /* Check if we have an offending branch instruction. */ - - if (found && found->non_a8_stub) - /* We've already made a stub for this instruction, e.g. - it's a long branch or a Thumb->ARM stub. Assume that - stub will suffice to work around the A8 erratum (see - setting of always_after_branch above). */ - ; - else if (is_bcc) - { - offset = (insn & 0x7ff) << 1; - offset |= (insn & 0x3f0000) >> 4; - offset |= (insn & 0x2000) ? 0x40000 : 0; - offset |= (insn & 0x800) ? 0x80000 : 0; - offset |= (insn & 0x4000000) ? 0x100000 : 0; - if (offset & 0x100000) - offset |= ~ ((bfd_signed_vma) 0xfffff); - stub_type = arm_stub_a8_veneer_b_cond; - } - else if (is_b || is_bl || is_blx) - { - int s = (insn & 0x4000000) != 0; - int j1 = (insn & 0x2000) != 0; - int j2 = (insn & 0x800) != 0; - int i1 = !(j1 ^ s); - int i2 = !(j2 ^ s); - - offset = (insn & 0x7ff) << 1; - offset |= (insn & 0x3ff0000) >> 4; - offset |= i2 << 22; - offset |= i1 << 23; - offset |= s << 24; - if (offset & 0x1000000) - offset |= ~ ((bfd_signed_vma) 0xffffff); - - if (is_blx) - offset &= ~ ((bfd_signed_vma) 3); - - stub_type = is_blx ? arm_stub_a8_veneer_blx : - is_bl ? arm_stub_a8_veneer_bl : arm_stub_a8_veneer_b; - } - - if (stub_type != arm_stub_none) - { - bfd_vma pc_for_insn = base_vma + i + 4; - - /* The original instruction is a BL, but the target is - an ARM instruction. If we were not making a stub, - the BL would have been converted to a BLX. Use the - BLX stub instead in that case. */ - if (htab->use_blx && force_target_arm - && stub_type == arm_stub_a8_veneer_bl) - { - stub_type = arm_stub_a8_veneer_blx; - is_blx = TRUE; - is_bl = FALSE; - } - /* Conversely, if the original instruction was - BLX but the target is Thumb mode, use the BL - stub. */ - else if (force_target_thumb - && stub_type == arm_stub_a8_veneer_blx) - { - stub_type = arm_stub_a8_veneer_bl; - is_blx = FALSE; - is_bl = TRUE; - } - - if (is_blx) - pc_for_insn &= ~ ((bfd_vma) 3); - - /* If we found a relocation, use the proper destination, - not the offset in the (unrelocated) instruction. - Note this is always done if we switched the stub type - above. */ - if (found) - offset = - (bfd_signed_vma) (found->destination - pc_for_insn); - - /* If the stub will use a Thumb-mode branch to a - PLT target, redirect it to the preceding Thumb - entry point. */ - if (stub_type != arm_stub_a8_veneer_blx && use_plt) - offset -= PLT_THUMB_STUB_SIZE; - - target = pc_for_insn + offset; - - /* The BLX stub is ARM-mode code. Adjust the offset to - take the different PC value (+8 instead of +4) into - account. */ - if (stub_type == arm_stub_a8_veneer_blx) - offset += 4; - - if (((base_vma + i) & ~0xfff) == (target & ~0xfff)) - { - char *stub_name = NULL; - - if (num_a8_fixes == a8_fix_table_size) - { - a8_fix_table_size *= 2; - a8_fixes = (struct a8_erratum_fix *) - bfd_realloc (a8_fixes, - sizeof (struct a8_erratum_fix) - * a8_fix_table_size); - } - - if (num_a8_fixes < prev_num_a8_fixes) - { - /* If we're doing a subsequent scan, - check if we've found the same fix as - before, and try and reuse the stub - name. */ - stub_name = a8_fixes[num_a8_fixes].stub_name; - if ((a8_fixes[num_a8_fixes].section != section) - || (a8_fixes[num_a8_fixes].offset != i)) - { - free (stub_name); - stub_name = NULL; - *stub_changed_p = TRUE; - } - } - - if (!stub_name) - { - stub_name = (char *) bfd_malloc (8 + 1 + 8 + 1); - if (stub_name != NULL) - sprintf (stub_name, "%x:%x", section->id, i); - } - - a8_fixes[num_a8_fixes].input_bfd = input_bfd; - a8_fixes[num_a8_fixes].section = section; - a8_fixes[num_a8_fixes].offset = i; - a8_fixes[num_a8_fixes].target_offset = - target - base_vma; - a8_fixes[num_a8_fixes].orig_insn = insn; - a8_fixes[num_a8_fixes].stub_name = stub_name; - a8_fixes[num_a8_fixes].stub_type = stub_type; - a8_fixes[num_a8_fixes].branch_type = - is_blx ? ST_BRANCH_TO_ARM : ST_BRANCH_TO_THUMB; - - num_a8_fixes++; - } - } - } - - i += insn_32bit ? 4 : 2; - last_was_32bit = insn_32bit; - last_was_branch = is_32bit_branch; - } - } - - if (elf_section_data (section)->this_hdr.contents == NULL) - free (contents); - } - - *a8_fixes_p = a8_fixes; - *num_a8_fixes_p = num_a8_fixes; - *a8_fix_table_size_p = a8_fix_table_size; - - return FALSE; -} - -/* Create or update a stub entry depending on whether the stub can already be - found in HTAB. The stub is identified by: - - its type STUB_TYPE - - its source branch (note that several can share the same stub) whose - section and relocation (if any) are given by SECTION and IRELA - respectively - - its target symbol whose input section, hash, name, value and branch type - are given in SYM_SEC, HASH, SYM_NAME, SYM_VALUE and BRANCH_TYPE - respectively - - If found, the value of the stub's target symbol is updated from SYM_VALUE - and *NEW_STUB is set to FALSE. Otherwise, *NEW_STUB is set to - TRUE and the stub entry is initialized. - - Returns the stub that was created or updated, or NULL if an error - occurred. */ - -static struct elf32_arm_stub_hash_entry * -elf32_arm_create_stub (struct elf32_arm_link_hash_table *htab, - enum elf32_arm_stub_type stub_type, asection *section, - Elf_Internal_Rela *irela, asection *sym_sec, - struct elf32_arm_link_hash_entry *hash, char *sym_name, - bfd_vma sym_value, enum arm_st_branch_type branch_type, - bfd_boolean *new_stub) -{ - const asection *id_sec; - char *stub_name; - struct elf32_arm_stub_hash_entry *stub_entry; - unsigned int r_type; - bfd_boolean sym_claimed = arm_stub_sym_claimed (stub_type); - - BFD_ASSERT (stub_type != arm_stub_none); - *new_stub = FALSE; - - if (sym_claimed) - stub_name = sym_name; - else - { - BFD_ASSERT (irela); - BFD_ASSERT (section); - BFD_ASSERT (section->id <= htab->top_id); - - /* Support for grouping stub sections. */ - id_sec = htab->stub_group[section->id].link_sec; - - /* Get the name of this stub. */ - stub_name = elf32_arm_stub_name (id_sec, sym_sec, hash, irela, - stub_type); - if (!stub_name) - return NULL; - } - - stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, - FALSE); - /* The proper stub has already been created, just update its value. */ - if (stub_entry != NULL) - { - if (!sym_claimed) - free (stub_name); - stub_entry->target_value = sym_value; - return stub_entry; - } - - stub_entry = elf32_arm_add_stub (stub_name, section, htab, stub_type); - if (stub_entry == NULL) - { - if (!sym_claimed) - free (stub_name); - return NULL; - } - - stub_entry->target_value = sym_value; - stub_entry->target_section = sym_sec; - stub_entry->stub_type = stub_type; - stub_entry->h = hash; - stub_entry->branch_type = branch_type; - - if (sym_claimed) - stub_entry->output_name = sym_name; - else - { - if (sym_name == NULL) - sym_name = "unnamed"; - stub_entry->output_name = (char *) - bfd_alloc (htab->stub_bfd, sizeof (THUMB2ARM_GLUE_ENTRY_NAME) - + strlen (sym_name)); - if (stub_entry->output_name == NULL) - { - free (stub_name); - return NULL; - } - - /* For historical reasons, use the existing names for ARM-to-Thumb and - Thumb-to-ARM stubs. */ - r_type = ELF32_R_TYPE (irela->r_info); - if ((r_type == (unsigned int) R_ARM_THM_CALL - || r_type == (unsigned int) R_ARM_THM_JUMP24 - || r_type == (unsigned int) R_ARM_THM_JUMP19) - && branch_type == ST_BRANCH_TO_ARM) - sprintf (stub_entry->output_name, THUMB2ARM_GLUE_ENTRY_NAME, sym_name); - else if ((r_type == (unsigned int) R_ARM_CALL - || r_type == (unsigned int) R_ARM_JUMP24) - && branch_type == ST_BRANCH_TO_THUMB) - sprintf (stub_entry->output_name, ARM2THUMB_GLUE_ENTRY_NAME, sym_name); - else - sprintf (stub_entry->output_name, STUB_ENTRY_NAME, sym_name); - } - - *new_stub = TRUE; - return stub_entry; -} - -/* Scan symbols in INPUT_BFD to identify secure entry functions needing a - gateway veneer to transition from non secure to secure state and create them - accordingly. - - "ARMv8-M Security Extensions: Requirements on Development Tools" document - defines the conditions that govern Secure Gateway veneer creation for a - given symbol as follows: - - it has function type - - it has non local binding - - a symbol named __acle_se_ (called special symbol) exists with the - same type, binding and value as (called normal symbol). - An entry function can handle secure state transition itself in which case - its special symbol would have a different value from the normal symbol. - - OUT_ATTR gives the output attributes, SYM_HASHES the symbol index to hash - entry mapping while HTAB gives the name to hash entry mapping. - *CMSE_STUB_CREATED is increased by the number of secure gateway veneer - created. - - The return value gives whether a stub failed to be allocated. */ - -static bfd_boolean -cmse_scan (bfd *input_bfd, struct elf32_arm_link_hash_table *htab, - obj_attribute *out_attr, struct elf_link_hash_entry **sym_hashes, - int *cmse_stub_created) -{ - const struct elf_backend_data *bed; - Elf_Internal_Shdr *symtab_hdr; - unsigned i, j, sym_count, ext_start; - Elf_Internal_Sym *cmse_sym, *local_syms; - struct elf32_arm_link_hash_entry *hash, *cmse_hash = NULL; - enum arm_st_branch_type branch_type; - char *sym_name, *lsym_name; - bfd_vma sym_value; - asection *section; - struct elf32_arm_stub_hash_entry *stub_entry; - bfd_boolean is_v8m, new_stub, cmse_invalid, ret = TRUE; - - bed = get_elf_backend_data (input_bfd); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym; - ext_start = symtab_hdr->sh_info; - is_v8m = (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE - && out_attr[Tag_CPU_arch_profile].i == 'M'); - - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, NULL, NULL, - NULL); - if (symtab_hdr->sh_info && local_syms == NULL) - return FALSE; - - /* Scan symbols. */ - for (i = 0; i < sym_count; i++) - { - cmse_invalid = FALSE; - - if (i < ext_start) - { - cmse_sym = &local_syms[i]; - /* Not a special symbol. */ - if (!ARM_GET_SYM_CMSE_SPCL (cmse_sym->st_target_internal)) - continue; - sym_name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - cmse_sym->st_name); - /* Special symbol with local binding. */ - cmse_invalid = TRUE; - } - else - { - cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]); - sym_name = (char *) cmse_hash->root.root.root.string; - - /* Not a special symbol. */ - if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal)) - continue; - - /* Special symbol has incorrect binding or type. */ - if ((cmse_hash->root.root.type != bfd_link_hash_defined - && cmse_hash->root.root.type != bfd_link_hash_defweak) - || cmse_hash->root.type != STT_FUNC) - cmse_invalid = TRUE; - } - - if (!is_v8m) - { - _bfd_error_handler (_("%B: Special symbol `%s' only allowed for " - "ARMv8-M architecture or later."), - input_bfd, sym_name); - is_v8m = TRUE; /* Avoid multiple warning. */ - ret = FALSE; - } - - if (cmse_invalid) - { - _bfd_error_handler (_("%B: invalid special symbol `%s'."), - input_bfd, sym_name); - _bfd_error_handler (_("It must be a global or weak function " - "symbol.")); - ret = FALSE; - if (i < ext_start) - continue; - } - - sym_name += strlen (CMSE_PREFIX); - hash = (struct elf32_arm_link_hash_entry *) - elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE); - - /* No associated normal symbol or it is neither global nor weak. */ - if (!hash - || (hash->root.root.type != bfd_link_hash_defined - && hash->root.root.type != bfd_link_hash_defweak) - || hash->root.type != STT_FUNC) - { - /* Initialize here to avoid warning about use of possibly - uninitialized variable. */ - j = 0; - - if (!hash) - { - /* Searching for a normal symbol with local binding. */ - for (; j < ext_start; j++) - { - lsym_name = - bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - local_syms[j].st_name); - if (!strcmp (sym_name, lsym_name)) - break; - } - } - - if (hash || j < ext_start) - { - _bfd_error_handler - (_("%B: invalid standard symbol `%s'."), input_bfd, sym_name); - _bfd_error_handler - (_("It must be a global or weak function symbol.")); - } - else - _bfd_error_handler - (_("%B: absent standard symbol `%s'."), input_bfd, sym_name); - ret = FALSE; - if (!hash) - continue; - } - - sym_value = hash->root.root.u.def.value; - section = hash->root.root.u.def.section; - - if (cmse_hash->root.root.u.def.section != section) - { - _bfd_error_handler - (_("%B: `%s' and its special symbol are in different sections."), - input_bfd, sym_name); - ret = FALSE; - } - if (cmse_hash->root.root.u.def.value != sym_value) - continue; /* Ignore: could be an entry function starting with SG. */ - - /* If this section is a link-once section that will be discarded, then - don't create any stubs. */ - if (section->output_section == NULL) - { - _bfd_error_handler - (_("%B: entry function `%s' not output."), input_bfd, sym_name); - continue; - } - - if (hash->root.size == 0) - { - _bfd_error_handler - (_("%B: entry function `%s' is empty."), input_bfd, sym_name); - ret = FALSE; - } - - if (!ret) - continue; - branch_type = ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal); - stub_entry - = elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only, - NULL, NULL, section, hash, sym_name, - sym_value, branch_type, &new_stub); - - if (stub_entry == NULL) - ret = FALSE; - else - { - BFD_ASSERT (new_stub); - (*cmse_stub_created)++; - } - } - - if (!symtab_hdr->contents) - free (local_syms); - return ret; -} - -/* Return TRUE iff a symbol identified by its linker HASH entry is a secure - code entry function, ie can be called from non secure code without using a - veneer. */ - -static bfd_boolean -cmse_entry_fct_p (struct elf32_arm_link_hash_entry *hash) -{ - bfd_byte contents[4]; - uint32_t first_insn; - asection *section; - file_ptr offset; - bfd *abfd; - - /* Defined symbol of function type. */ - if (hash->root.root.type != bfd_link_hash_defined - && hash->root.root.type != bfd_link_hash_defweak) - return FALSE; - if (hash->root.type != STT_FUNC) - return FALSE; - - /* Read first instruction. */ - section = hash->root.root.u.def.section; - abfd = section->owner; - offset = hash->root.root.u.def.value - section->vma; - if (!bfd_get_section_contents (abfd, section, contents, offset, - sizeof (contents))) - return FALSE; - - first_insn = bfd_get_32 (abfd, contents); - - /* Starts by SG instruction. */ - return first_insn == 0xe97fe97f; -} - -/* Output the name (in symbol table) of the veneer GEN_ENTRY if it is a new - secure gateway veneers (ie. the veneers was not in the input import library) - and there is no output import library (GEN_INFO->out_implib_bfd is NULL. */ - -static bfd_boolean -arm_list_new_cmse_stub (struct bfd_hash_entry *gen_entry, void *gen_info) -{ - struct elf32_arm_stub_hash_entry *stub_entry; - struct bfd_link_info *info; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - info = (struct bfd_link_info *) gen_info; - - if (info->out_implib_bfd) - return TRUE; - - if (stub_entry->stub_type != arm_stub_cmse_branch_thumb_only) - return TRUE; - - if (stub_entry->stub_offset == (bfd_vma) -1) - _bfd_error_handler (" %s", stub_entry->output_name); - - return TRUE; -} - -/* Set offset of each secure gateway veneers so that its address remain - identical to the one in the input import library referred by - HTAB->in_implib_bfd. A warning is issued for veneers that disappeared - (present in input import library but absent from the executable being - linked) or if new veneers appeared and there is no output import library - (INFO->out_implib_bfd is NULL and *CMSE_STUB_CREATED is bigger than the - number of secure gateway veneers found in the input import library. - - The function returns whether an error occurred. If no error occurred, - *CMSE_STUB_CREATED gives the number of SG veneers created by both cmse_scan - and this function and HTAB->new_cmse_stub_offset is set to the biggest - veneer observed set for new veneers to be layed out after. */ - -static bfd_boolean -set_cmse_veneer_addr_from_implib (struct bfd_link_info *info, - struct elf32_arm_link_hash_table *htab, - int *cmse_stub_created) -{ - long symsize; - char *sym_name; - flagword flags; - long i, symcount; - bfd *in_implib_bfd; - asection *stub_out_sec; - bfd_boolean ret = TRUE; - Elf_Internal_Sym *intsym; - const char *out_sec_name; - bfd_size_type cmse_stub_size; - asymbol **sympp = NULL, *sym; - struct elf32_arm_link_hash_entry *hash; - const insn_sequence *cmse_stub_template; - struct elf32_arm_stub_hash_entry *stub_entry; - int cmse_stub_template_size, new_cmse_stubs_created = *cmse_stub_created; - bfd_vma veneer_value, stub_offset, next_cmse_stub_offset; - bfd_vma cmse_stub_array_start = (bfd_vma) -1, cmse_stub_sec_vma = 0; - - /* No input secure gateway import library. */ - if (!htab->in_implib_bfd) - return TRUE; - - in_implib_bfd = htab->in_implib_bfd; - if (!htab->cmse_implib) - { - _bfd_error_handler (_("%B: --in-implib only supported for Secure " - "Gateway import libraries."), in_implib_bfd); - return FALSE; - } - - /* Get symbol table size. */ - symsize = bfd_get_symtab_upper_bound (in_implib_bfd); - if (symsize < 0) - return FALSE; - - /* Read in the input secure gateway import library's symbol table. */ - sympp = (asymbol **) xmalloc (symsize); - symcount = bfd_canonicalize_symtab (in_implib_bfd, sympp); - if (symcount < 0) - { - ret = FALSE; - goto free_sym_buf; - } - - htab->new_cmse_stub_offset = 0; - cmse_stub_size = - find_stub_size_and_template (arm_stub_cmse_branch_thumb_only, - &cmse_stub_template, - &cmse_stub_template_size); - out_sec_name = - arm_dedicated_stub_output_section_name (arm_stub_cmse_branch_thumb_only); - stub_out_sec = - bfd_get_section_by_name (htab->obfd, out_sec_name); - if (stub_out_sec != NULL) - cmse_stub_sec_vma = stub_out_sec->vma; - - /* Set addresses of veneers mentionned in input secure gateway import - library's symbol table. */ - for (i = 0; i < symcount; i++) - { - sym = sympp[i]; - flags = sym->flags; - sym_name = (char *) bfd_asymbol_name (sym); - intsym = &((elf_symbol_type *) sym)->internal_elf_sym; - - if (sym->section != bfd_abs_section_ptr - || !(flags & (BSF_GLOBAL | BSF_WEAK)) - || (flags & BSF_FUNCTION) != BSF_FUNCTION - || (ARM_GET_SYM_BRANCH_TYPE (intsym->st_target_internal) - != ST_BRANCH_TO_THUMB)) - { - _bfd_error_handler (_("%B: invalid import library entry: `%s'."), - in_implib_bfd, sym_name); - _bfd_error_handler (_("Symbol should be absolute, global and " - "refer to Thumb functions.")); - ret = FALSE; - continue; - } - - veneer_value = bfd_asymbol_value (sym); - stub_offset = veneer_value - cmse_stub_sec_vma; - stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, sym_name, - FALSE, FALSE); - hash = (struct elf32_arm_link_hash_entry *) - elf_link_hash_lookup (&(htab)->root, sym_name, FALSE, FALSE, TRUE); - - /* Stub entry should have been created by cmse_scan or the symbol be of - a secure function callable from non secure code. */ - if (!stub_entry && !hash) - { - bfd_boolean new_stub; - - _bfd_error_handler - (_("Entry function `%s' disappeared from secure code."), sym_name); - hash = (struct elf32_arm_link_hash_entry *) - elf_link_hash_lookup (&(htab)->root, sym_name, TRUE, TRUE, TRUE); - stub_entry - = elf32_arm_create_stub (htab, arm_stub_cmse_branch_thumb_only, - NULL, NULL, bfd_abs_section_ptr, hash, - sym_name, veneer_value, - ST_BRANCH_TO_THUMB, &new_stub); - if (stub_entry == NULL) - ret = FALSE; - else - { - BFD_ASSERT (new_stub); - new_cmse_stubs_created++; - (*cmse_stub_created)++; - } - stub_entry->stub_template_size = stub_entry->stub_size = 0; - stub_entry->stub_offset = stub_offset; - } - /* Symbol found is not callable from non secure code. */ - else if (!stub_entry) - { - if (!cmse_entry_fct_p (hash)) - { - _bfd_error_handler (_("`%s' refers to a non entry function."), - sym_name); - ret = FALSE; - } - continue; - } - else - { - /* Only stubs for SG veneers should have been created. */ - BFD_ASSERT (stub_entry->stub_type == arm_stub_cmse_branch_thumb_only); - - /* Check visibility hasn't changed. */ - if (!!(flags & BSF_GLOBAL) - != (hash->root.root.type == bfd_link_hash_defined)) - _bfd_error_handler - (_("%B: visibility of symbol `%s' has changed."), in_implib_bfd, - sym_name); - - stub_entry->stub_offset = stub_offset; - } - - /* Size should match that of a SG veneer. */ - if (intsym->st_size != cmse_stub_size) - { - _bfd_error_handler (_("%B: incorrect size for symbol `%s'."), - in_implib_bfd, sym_name); - ret = FALSE; - } - - /* Previous veneer address is before current SG veneer section. */ - if (veneer_value < cmse_stub_sec_vma) - { - /* Avoid offset underflow. */ - if (stub_entry) - stub_entry->stub_offset = 0; - stub_offset = 0; - ret = FALSE; - } - - /* Complain if stub offset not a multiple of stub size. */ - if (stub_offset % cmse_stub_size) - { - _bfd_error_handler - (_("Offset of veneer for entry function `%s' not a multiple of " - "its size."), sym_name); - ret = FALSE; - } - - if (!ret) - continue; - - new_cmse_stubs_created--; - if (veneer_value < cmse_stub_array_start) - cmse_stub_array_start = veneer_value; - next_cmse_stub_offset = stub_offset + ((cmse_stub_size + 7) & ~7); - if (next_cmse_stub_offset > htab->new_cmse_stub_offset) - htab->new_cmse_stub_offset = next_cmse_stub_offset; - } - - if (!info->out_implib_bfd && new_cmse_stubs_created != 0) - { - BFD_ASSERT (new_cmse_stubs_created > 0); - _bfd_error_handler - (_("new entry function(s) introduced but no output import library " - "specified:")); - bfd_hash_traverse (&htab->stub_hash_table, arm_list_new_cmse_stub, info); - } - - if (cmse_stub_array_start != cmse_stub_sec_vma) - { - _bfd_error_handler - (_("Start address of `%s' is different from previous link."), - out_sec_name); - ret = FALSE; - } - -free_sym_buf: - free (sympp); - return ret; -} - -/* Determine and set the size of the stub section for a final link. - - The basic idea here is to examine all the relocations looking for - PC-relative calls to a target that is unreachable with a "bl" - instruction. */ - -bfd_boolean -elf32_arm_size_stubs (bfd *output_bfd, - bfd *stub_bfd, - struct bfd_link_info *info, - bfd_signed_vma group_size, - asection * (*add_stub_section) (const char *, asection *, - asection *, - unsigned int), - void (*layout_sections_again) (void)) -{ - bfd_boolean ret = TRUE; - obj_attribute *out_attr; - int cmse_stub_created = 0; - bfd_size_type stub_group_size; - bfd_boolean m_profile, stubs_always_after_branch, first_veneer_scan = TRUE; - struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); - struct a8_erratum_fix *a8_fixes = NULL; - unsigned int num_a8_fixes = 0, a8_fix_table_size = 10; - struct a8_erratum_reloc *a8_relocs = NULL; - unsigned int num_a8_relocs = 0, a8_reloc_table_size = 10, i; - - if (htab == NULL) - return FALSE; - - if (htab->fix_cortex_a8) - { - a8_fixes = (struct a8_erratum_fix *) - bfd_zmalloc (sizeof (struct a8_erratum_fix) * a8_fix_table_size); - a8_relocs = (struct a8_erratum_reloc *) - bfd_zmalloc (sizeof (struct a8_erratum_reloc) * a8_reloc_table_size); - } - - /* Propagate mach to stub bfd, because it may not have been - finalized when we created stub_bfd. */ - bfd_set_arch_mach (stub_bfd, bfd_get_arch (output_bfd), - bfd_get_mach (output_bfd)); - - /* Stash our params away. */ - htab->stub_bfd = stub_bfd; - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; - stubs_always_after_branch = group_size < 0; - - out_attr = elf_known_obj_attributes_proc (output_bfd); - m_profile = out_attr[Tag_CPU_arch_profile].i == 'M'; - - /* The Cortex-A8 erratum fix depends on stubs not being in the same 4K page - as the first half of a 32-bit branch straddling two 4K pages. This is a - crude way of enforcing that. */ - if (htab->fix_cortex_a8) - stubs_always_after_branch = 1; - - if (group_size < 0) - stub_group_size = -group_size; - else - stub_group_size = group_size; - - if (stub_group_size == 1) - { - /* Default values. */ - /* Thumb branch range is +-4MB has to be used as the default - maximum size (a given section can contain both ARM and Thumb - code, so the worst case has to be taken into account). - - This value is 24K less than that, which allows for 2025 - 12-byte stubs. If we exceed that, then we will fail to link. - The user will have to relink with an explicit group size - option. */ - stub_group_size = 4170000; - } - - group_sections (htab, stub_group_size, stubs_always_after_branch); - - /* If we're applying the cortex A8 fix, we need to determine the - program header size now, because we cannot change it later -- - that could alter section placements. Notice the A8 erratum fix - ends up requiring the section addresses to remain unchanged - modulo the page size. That's something we cannot represent - inside BFD, and we don't want to force the section alignment to - be the page size. */ - if (htab->fix_cortex_a8) - (*htab->layout_sections_again) (); - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - asection *stub_sec; - enum elf32_arm_stub_type stub_type; - bfd_boolean stub_changed = FALSE; - unsigned prev_num_a8_fixes = num_a8_fixes; - - num_a8_fixes = 0; - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms = NULL; - - if (!is_arm_elf (input_bfd)) - continue; - - num_a8_relocs = 0; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* Limit scan of symbols to object file whose profile is - Microcontroller to not hinder performance in the general case. */ - if (m_profile && first_veneer_scan) - { - struct elf_link_hash_entry **sym_hashes; - - sym_hashes = elf_sym_hashes (input_bfd); - if (!cmse_scan (input_bfd, htab, out_attr, sym_hashes, - &cmse_stub_created)) - goto error_ret_free_local; - - if (cmse_stub_created != 0) - stub_changed = TRUE; - } - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0 - || (section->flags & SEC_CODE) == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, - NULL, info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - asection *sym_sec; - bfd_vma sym_value; - bfd_vma destination; - struct elf32_arm_link_hash_entry *hash; - const char *sym_name; - unsigned char st_type; - enum arm_st_branch_type branch_type; - bfd_boolean created_stub = FALSE; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - if (r_type >= (unsigned int) R_ARM_max) - { - bfd_set_error (bfd_error_bad_value); - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - /* Fall through. */ - error_ret_free_local: - if (local_syms != NULL - && (symtab_hdr->contents - != (unsigned char *) local_syms)) - free (local_syms); - return FALSE; - } - - hash = NULL; - if (r_indx >= symtab_hdr->sh_info) - hash = elf32_arm_hash_entry - (elf_sym_hashes (input_bfd) - [r_indx - symtab_hdr->sh_info]); - - /* Only look for stubs on branch instructions, or - non-relaxed TLSCALL */ - if ((r_type != (unsigned int) R_ARM_CALL) - && (r_type != (unsigned int) R_ARM_THM_CALL) - && (r_type != (unsigned int) R_ARM_JUMP24) - && (r_type != (unsigned int) R_ARM_THM_JUMP19) - && (r_type != (unsigned int) R_ARM_THM_XPC22) - && (r_type != (unsigned int) R_ARM_THM_JUMP24) - && (r_type != (unsigned int) R_ARM_PLT32) - && !((r_type == (unsigned int) R_ARM_TLS_CALL - || r_type == (unsigned int) R_ARM_THM_TLS_CALL) - && r_type == elf32_arm_tls_transition - (info, r_type, &hash->root) - && ((hash ? hash->tls_type - : (elf32_arm_local_got_tls_type - (input_bfd)[r_indx])) - & GOT_TLS_GDESC) != 0)) - continue; - - /* Now determine the call target, its name, value, - section. */ - sym_sec = NULL; - sym_value = 0; - destination = 0; - sym_name = NULL; - - if (r_type == (unsigned int) R_ARM_TLS_CALL - || r_type == (unsigned int) R_ARM_THM_TLS_CALL) - { - /* A non-relaxed TLS call. The target is the - plt-resident trampoline and nothing to do - with the symbol. */ - BFD_ASSERT (htab->tls_trampoline > 0); - sym_sec = htab->root.splt; - sym_value = htab->tls_trampoline; - hash = 0; - st_type = STT_FUNC; - branch_type = ST_BRANCH_TO_ARM; - } - else if (!hash) - { - /* It's a local symbol. */ - Elf_Internal_Sym *sym; - - if (local_syms == NULL) - { - local_syms - = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - local_syms - = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (local_syms == NULL) - goto error_ret_free_internal; - } - - sym = local_syms + r_indx; - if (sym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (sym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (sym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = - bfd_section_from_elf_index (input_bfd, sym->st_shndx); - - if (!sym_sec) - /* This is an undefined symbol. It can never - be resolved. */ - continue; - - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - sym_value = sym->st_value; - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - st_type = ELF_ST_TYPE (sym->st_info); - branch_type = - ARM_GET_SYM_BRANCH_TYPE (sym->st_target_internal); - sym_name - = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - } - else - { - /* It's an external symbol. */ - while (hash->root.root.type == bfd_link_hash_indirect - || hash->root.root.type == bfd_link_hash_warning) - hash = ((struct elf32_arm_link_hash_entry *) - hash->root.root.u.i.link); - - if (hash->root.root.type == bfd_link_hash_defined - || hash->root.root.type == bfd_link_hash_defweak) - { - sym_sec = hash->root.root.u.def.section; - sym_value = hash->root.root.u.def.value; - - struct elf32_arm_link_hash_table *globals = - elf32_arm_hash_table (info); - - /* For a destination in a shared library, - use the PLT stub as target address to - decide whether a branch stub is - needed. */ - if (globals != NULL - && globals->root.splt != NULL - && hash != NULL - && hash->root.plt.offset != (bfd_vma) -1) - { - sym_sec = globals->root.splt; - sym_value = hash->root.plt.offset; - if (sym_sec->output_section != NULL) - destination = (sym_value - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - else if (sym_sec->output_section != NULL) - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - else if ((hash->root.root.type == bfd_link_hash_undefined) - || (hash->root.root.type == bfd_link_hash_undefweak)) - { - /* For a shared library, use the PLT stub as - target address to decide whether a long - branch stub is needed. - For absolute code, they cannot be handled. */ - struct elf32_arm_link_hash_table *globals = - elf32_arm_hash_table (info); - - if (globals != NULL - && globals->root.splt != NULL - && hash != NULL - && hash->root.plt.offset != (bfd_vma) -1) - { - sym_sec = globals->root.splt; - sym_value = hash->root.plt.offset; - if (sym_sec->output_section != NULL) - destination = (sym_value - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - else - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - st_type = hash->root.type; - branch_type = - ARM_GET_SYM_BRANCH_TYPE (hash->root.target_internal); - sym_name = hash->root.root.root.string; - } - - do - { - bfd_boolean new_stub; - struct elf32_arm_stub_hash_entry *stub_entry; - - /* Determine what (if any) linker stub is needed. */ - stub_type = arm_type_of_stub (info, section, irela, - st_type, &branch_type, - hash, destination, sym_sec, - input_bfd, sym_name); - if (stub_type == arm_stub_none) - break; - - /* We've either created a stub for this reloc already, - or we are about to. */ - stub_entry = - elf32_arm_create_stub (htab, stub_type, section, irela, - sym_sec, hash, - (char *) sym_name, sym_value, - branch_type, &new_stub); - - created_stub = stub_entry != NULL; - if (!created_stub) - goto error_ret_free_internal; - else if (!new_stub) - break; - else - stub_changed = TRUE; - } - while (0); - - /* Look for relocations which might trigger Cortex-A8 - erratum. */ - if (htab->fix_cortex_a8 - && (r_type == (unsigned int) R_ARM_THM_JUMP24 - || r_type == (unsigned int) R_ARM_THM_JUMP19 - || r_type == (unsigned int) R_ARM_THM_CALL - || r_type == (unsigned int) R_ARM_THM_XPC22)) - { - bfd_vma from = section->output_section->vma - + section->output_offset - + irela->r_offset; - - if ((from & 0xfff) == 0xffe) - { - /* Found a candidate. Note we haven't checked the - destination is within 4K here: if we do so (and - don't create an entry in a8_relocs) we can't tell - that a branch should have been relocated when - scanning later. */ - if (num_a8_relocs == a8_reloc_table_size) - { - a8_reloc_table_size *= 2; - a8_relocs = (struct a8_erratum_reloc *) - bfd_realloc (a8_relocs, - sizeof (struct a8_erratum_reloc) - * a8_reloc_table_size); - } - - a8_relocs[num_a8_relocs].from = from; - a8_relocs[num_a8_relocs].destination = destination; - a8_relocs[num_a8_relocs].r_type = r_type; - a8_relocs[num_a8_relocs].branch_type = branch_type; - a8_relocs[num_a8_relocs].sym_name = sym_name; - a8_relocs[num_a8_relocs].non_a8_stub = created_stub; - a8_relocs[num_a8_relocs].hash = hash; - - num_a8_relocs++; - } - } - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - - if (htab->fix_cortex_a8) - { - /* Sort relocs which might apply to Cortex-A8 erratum. */ - qsort (a8_relocs, num_a8_relocs, - sizeof (struct a8_erratum_reloc), - &a8_reloc_compare); - - /* Scan for branches which might trigger Cortex-A8 erratum. */ - if (cortex_a8_erratum_scan (input_bfd, info, &a8_fixes, - &num_a8_fixes, &a8_fix_table_size, - a8_relocs, num_a8_relocs, - prev_num_a8_fixes, &stub_changed) - != 0) - goto error_ret_free_local; - } - - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - { - if (!info->keep_memory) - free (local_syms); - else - symtab_hdr->contents = (unsigned char *) local_syms; - } - } - - if (first_veneer_scan - && !set_cmse_veneer_addr_from_implib (info, htab, - &cmse_stub_created)) - ret = FALSE; - - if (prev_num_a8_fixes != num_a8_fixes) - stub_changed = TRUE; - - if (!stub_changed) - break; - - /* OK, we've added some stubs. Find out the new size of the - stub sections. */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - /* Ignore non-stub sections. */ - if (!strstr (stub_sec->name, STUB_SUFFIX)) - continue; - - stub_sec->size = 0; - } - - /* Add new SG veneers after those already in the input import - library. */ - for (stub_type = arm_stub_none + 1; stub_type < max_stub_type; - stub_type++) - { - bfd_vma *start_offset_p; - asection **stub_sec_p; - - start_offset_p = arm_new_stubs_start_offset_ptr (htab, stub_type); - stub_sec_p = arm_dedicated_stub_input_section_ptr (htab, stub_type); - if (start_offset_p == NULL) - continue; - - BFD_ASSERT (stub_sec_p != NULL); - if (*stub_sec_p != NULL) - (*stub_sec_p)->size = *start_offset_p; - } - - /* Compute stub section size, considering padding. */ - bfd_hash_traverse (&htab->stub_hash_table, arm_size_one_stub, htab); - for (stub_type = arm_stub_none + 1; stub_type < max_stub_type; - stub_type++) - { - int size, padding; - asection **stub_sec_p; - - padding = arm_dedicated_stub_section_padding (stub_type); - stub_sec_p = arm_dedicated_stub_input_section_ptr (htab, stub_type); - /* Skip if no stub input section or no stub section padding - required. */ - if ((stub_sec_p != NULL && *stub_sec_p == NULL) || padding == 0) - continue; - /* Stub section padding required but no dedicated section. */ - BFD_ASSERT (stub_sec_p); - - size = (*stub_sec_p)->size; - size = (size + padding - 1) & ~(padding - 1); - (*stub_sec_p)->size = size; - } - - /* Add Cortex-A8 erratum veneers to stub section sizes too. */ - if (htab->fix_cortex_a8) - for (i = 0; i < num_a8_fixes; i++) - { - stub_sec = elf32_arm_create_or_find_stub_sec (NULL, - a8_fixes[i].section, htab, a8_fixes[i].stub_type); - - if (stub_sec == NULL) - return FALSE; - - stub_sec->size - += find_stub_size_and_template (a8_fixes[i].stub_type, NULL, - NULL); - } - - - /* Ask the linker to do its stuff. */ - (*htab->layout_sections_again) (); - first_veneer_scan = FALSE; - } - - /* Add stubs for Cortex-A8 erratum fixes now. */ - if (htab->fix_cortex_a8) - { - for (i = 0; i < num_a8_fixes; i++) - { - struct elf32_arm_stub_hash_entry *stub_entry; - char *stub_name = a8_fixes[i].stub_name; - asection *section = a8_fixes[i].section; - unsigned int section_id = a8_fixes[i].section->id; - asection *link_sec = htab->stub_group[section_id].link_sec; - asection *stub_sec = htab->stub_group[section_id].stub_sec; - const insn_sequence *template_sequence; - int template_size, size = 0; - - stub_entry = arm_stub_hash_lookup (&htab->stub_hash_table, stub_name, - TRUE, FALSE); - if (stub_entry == NULL) - { - _bfd_error_handler (_("%B: cannot create stub entry %s"), - section->owner, stub_name); - return FALSE; - } - - stub_entry->stub_sec = stub_sec; - stub_entry->stub_offset = (bfd_vma) -1; - stub_entry->id_sec = link_sec; - stub_entry->stub_type = a8_fixes[i].stub_type; - stub_entry->source_value = a8_fixes[i].offset; - stub_entry->target_section = a8_fixes[i].section; - stub_entry->target_value = a8_fixes[i].target_offset; - stub_entry->orig_insn = a8_fixes[i].orig_insn; - stub_entry->branch_type = a8_fixes[i].branch_type; - - size = find_stub_size_and_template (a8_fixes[i].stub_type, - &template_sequence, - &template_size); - - stub_entry->stub_size = size; - stub_entry->stub_template = template_sequence; - stub_entry->stub_template_size = template_size; - } - - /* Stash the Cortex-A8 erratum fix array for use later in - elf32_arm_write_section(). */ - htab->a8_erratum_fixes = a8_fixes; - htab->num_a8_erratum_fixes = num_a8_fixes; - } - else - { - htab->a8_erratum_fixes = NULL; - htab->num_a8_erratum_fixes = 0; - } - return ret; -} - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. We also set up the .plt entries for statically linked PIC - functions here. This function is called via arm_elf_finish in the - linker. */ - -bfd_boolean -elf32_arm_build_stubs (struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - enum elf32_arm_stub_type stub_type; - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - bfd_size_type size; - - /* Ignore non-stub sections. */ - if (!strstr (stub_sec->name, STUB_SUFFIX)) - continue; - - /* Allocate memory to hold the linker stubs. Zeroing the stub sections - must at least be done for stub section requiring padding and for SG - veneers to ensure that a non secure code branching to a removed SG - veneer causes an error. */ - size = stub_sec->size; - stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size); - if (stub_sec->contents == NULL && size != 0) - return FALSE; - - stub_sec->size = 0; - } - - /* Add new SG veneers after those already in the input import library. */ - for (stub_type = arm_stub_none + 1; stub_type < max_stub_type; stub_type++) - { - bfd_vma *start_offset_p; - asection **stub_sec_p; - - start_offset_p = arm_new_stubs_start_offset_ptr (htab, stub_type); - stub_sec_p = arm_dedicated_stub_input_section_ptr (htab, stub_type); - if (start_offset_p == NULL) - continue; - - BFD_ASSERT (stub_sec_p != NULL); - if (*stub_sec_p != NULL) - (*stub_sec_p)->size = *start_offset_p; - } - - /* Build the stubs as directed by the stub hash table. */ - table = &htab->stub_hash_table; - bfd_hash_traverse (table, arm_build_one_stub, info); - if (htab->fix_cortex_a8) - { - /* Place the cortex a8 stubs last. */ - htab->fix_cortex_a8 = -1; - bfd_hash_traverse (table, arm_build_one_stub, info); - } - - return TRUE; -} - -/* Locate the Thumb encoded calling stub for NAME. */ - -static struct elf_link_hash_entry * -find_thumb_glue (struct bfd_link_info *link_info, - const char *name, - char **error_message) -{ - char *tmp_name; - struct elf_link_hash_entry *hash; - struct elf32_arm_link_hash_table *hash_table; - - /* We need a pointer to the armelf specific hash table. */ - hash_table = elf32_arm_hash_table (link_info); - if (hash_table == NULL) - return NULL; - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) - + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name); - - hash = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); - - if (hash == NULL - && asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"), - tmp_name, name) == -1) - *error_message = (char *) bfd_errmsg (bfd_error_system_call); - - free (tmp_name); - - return hash; -} - -/* Locate the ARM encoded calling stub for NAME. */ - -static struct elf_link_hash_entry * -find_arm_glue (struct bfd_link_info *link_info, - const char *name, - char **error_message) -{ - char *tmp_name; - struct elf_link_hash_entry *myh; - struct elf32_arm_link_hash_table *hash_table; - - /* We need a pointer to the elfarm specific hash table. */ - hash_table = elf32_arm_hash_table (link_info); - if (hash_table == NULL) - return NULL; - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) - + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); - - myh = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL - && asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"), - tmp_name, name) == -1) - *error_message = (char *) bfd_errmsg (bfd_error_system_call); - - free (tmp_name); - - return myh; -} - -/* ARM->Thumb glue (static images): - - .arm - __func_from_arm: - ldr r12, __func_addr - bx r12 - __func_addr: - .word func @ behave as if you saw a ARM_32 reloc. - - (v5t static images) - .arm - __func_from_arm: - ldr pc, __func_addr - __func_addr: - .word func @ behave as if you saw a ARM_32 reloc. - - (relocatable images) - .arm - __func_from_arm: - ldr r12, __func_offset - add r12, r12, pc - bx r12 - __func_offset: - .word func - . */ - -#define ARM2THUMB_STATIC_GLUE_SIZE 12 -static const insn32 a2t1_ldr_insn = 0xe59fc000; -static const insn32 a2t2_bx_r12_insn = 0xe12fff1c; -static const insn32 a2t3_func_addr_insn = 0x00000001; - -#define ARM2THUMB_V5_STATIC_GLUE_SIZE 8 -static const insn32 a2t1v5_ldr_insn = 0xe51ff004; -static const insn32 a2t2v5_func_addr_insn = 0x00000001; - -#define ARM2THUMB_PIC_GLUE_SIZE 16 -static const insn32 a2t1p_ldr_insn = 0xe59fc004; -static const insn32 a2t2p_add_pc_insn = 0xe08cc00f; -static const insn32 a2t3p_bx_r12_insn = 0xe12fff1c; - -/* Thumb->ARM: Thumb->(non-interworking aware) ARM - - .thumb .thumb - .align 2 .align 2 - __func_from_thumb: __func_from_thumb: - bx pc push {r6, lr} - nop ldr r6, __func_addr - .arm mov lr, pc - b func bx r6 - .arm - ;; back_to_thumb - ldmia r13! {r6, lr} - bx lr - __func_addr: - .word func */ - -#define THUMB2ARM_GLUE_SIZE 8 -static const insn16 t2a1_bx_pc_insn = 0x4778; -static const insn16 t2a2_noop_insn = 0x46c0; -static const insn32 t2a3_b_insn = 0xea000000; - -#define VFP11_ERRATUM_VENEER_SIZE 8 -#define STM32L4XX_ERRATUM_LDM_VENEER_SIZE 16 -#define STM32L4XX_ERRATUM_VLDM_VENEER_SIZE 24 - -#define ARM_BX_VENEER_SIZE 12 -static const insn32 armbx1_tst_insn = 0xe3100001; -static const insn32 armbx2_moveq_insn = 0x01a0f000; -static const insn32 armbx3_bx_insn = 0xe12fff10; - -#ifndef ELFARM_NABI_C_INCLUDED -static void -arm_allocate_glue_section_space (bfd * abfd, bfd_size_type size, const char * name) -{ - asection * s; - bfd_byte * contents; - - if (size == 0) - { - /* Do not include empty glue sections in the output. */ - if (abfd != NULL) - { - s = bfd_get_linker_section (abfd, name); - if (s != NULL) - s->flags |= SEC_EXCLUDE; - } - return; - } - - BFD_ASSERT (abfd != NULL); - - s = bfd_get_linker_section (abfd, name); - BFD_ASSERT (s != NULL); - - contents = (bfd_byte *) bfd_alloc (abfd, size); - - BFD_ASSERT (s->size == size); - s->contents = contents; -} - -bfd_boolean -bfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info) -{ - struct elf32_arm_link_hash_table * globals; - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - - arm_allocate_glue_section_space (globals->bfd_of_glue_owner, - globals->arm_glue_size, - ARM2THUMB_GLUE_SECTION_NAME); - - arm_allocate_glue_section_space (globals->bfd_of_glue_owner, - globals->thumb_glue_size, - THUMB2ARM_GLUE_SECTION_NAME); - - arm_allocate_glue_section_space (globals->bfd_of_glue_owner, - globals->vfp11_erratum_glue_size, - VFP11_ERRATUM_VENEER_SECTION_NAME); - - arm_allocate_glue_section_space (globals->bfd_of_glue_owner, - globals->stm32l4xx_erratum_glue_size, - STM32L4XX_ERRATUM_VENEER_SECTION_NAME); - - arm_allocate_glue_section_space (globals->bfd_of_glue_owner, - globals->bx_glue_size, - ARM_BX_GLUE_SECTION_NAME); - - return TRUE; -} - -/* Allocate space and symbols for calling a Thumb function from Arm mode. - returns the symbol identifying the stub. */ - -static struct elf_link_hash_entry * -record_arm_to_thumb_glue (struct bfd_link_info * link_info, - struct elf_link_hash_entry * h) -{ - const char * name = h->root.root.string; - asection * s; - char * tmp_name; - struct elf_link_hash_entry * myh; - struct bfd_link_hash_entry * bh; - struct elf32_arm_link_hash_table * globals; - bfd_vma val; - bfd_size_type size; - - globals = elf32_arm_hash_table (link_info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_linker_section - (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen (name) - + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name); - - myh = elf_link_hash_lookup - (&(globals)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh != NULL) - { - /* We've already seen this guy. */ - free (tmp_name); - return myh; - } - - /* The only trick here is using hash_table->arm_glue_size as the value. - Even though the section isn't allocated yet, this is where we will be - putting it. The +1 on the value marks that the stub has not been - output yet - not that it is a Thumb function. */ - bh = NULL; - val = globals->arm_glue_size + 1; - _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner, - tmp_name, BSF_GLOBAL, s, val, - NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - - free (tmp_name); - - if (bfd_link_pic (link_info) - || globals->root.is_relocatable_executable - || globals->pic_veneer) - size = ARM2THUMB_PIC_GLUE_SIZE; - else if (globals->use_blx) - size = ARM2THUMB_V5_STATIC_GLUE_SIZE; - else - size = ARM2THUMB_STATIC_GLUE_SIZE; - - s->size += size; - globals->arm_glue_size += size; - - return myh; -} - -/* Allocate space for ARMv4 BX veneers. */ - -static void -record_arm_bx_glue (struct bfd_link_info * link_info, int reg) -{ - asection * s; - struct elf32_arm_link_hash_table *globals; - char *tmp_name; - struct elf_link_hash_entry *myh; - struct bfd_link_hash_entry *bh; - bfd_vma val; - - /* BX PC does not need a veneer. */ - if (reg == 15) - return; - - globals = elf32_arm_hash_table (link_info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - /* Check if this veneer has already been allocated. */ - if (globals->bx_glue_offset[reg]) - return; - - s = bfd_get_linker_section - (globals->bfd_of_glue_owner, ARM_BX_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - /* Add symbol for veneer. */ - tmp_name = (char *) - bfd_malloc ((bfd_size_type) strlen (ARM_BX_GLUE_ENTRY_NAME) + 1); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, ARM_BX_GLUE_ENTRY_NAME, reg); - - myh = elf_link_hash_lookup - (&(globals)->root, tmp_name, FALSE, FALSE, FALSE); - - BFD_ASSERT (myh == NULL); - - bh = NULL; - val = globals->bx_glue_size; - _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner, - tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val, - NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - - s->size += ARM_BX_VENEER_SIZE; - globals->bx_glue_offset[reg] = globals->bx_glue_size | 2; - globals->bx_glue_size += ARM_BX_VENEER_SIZE; -} - - -/* Add an entry to the code/data map for section SEC. */ - -static void -elf32_arm_section_map_add (asection *sec, char type, bfd_vma vma) -{ - struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec); - unsigned int newidx; - - if (sec_data->map == NULL) - { - sec_data->map = (elf32_arm_section_map *) - bfd_malloc (sizeof (elf32_arm_section_map)); - sec_data->mapcount = 0; - sec_data->mapsize = 1; - } - - newidx = sec_data->mapcount++; - - if (sec_data->mapcount > sec_data->mapsize) - { - sec_data->mapsize *= 2; - sec_data->map = (elf32_arm_section_map *) - bfd_realloc_or_free (sec_data->map, sec_data->mapsize - * sizeof (elf32_arm_section_map)); - } - - if (sec_data->map) - { - sec_data->map[newidx].vma = vma; - sec_data->map[newidx].type = type; - } -} - - -/* Record information about a VFP11 denorm-erratum veneer. Only ARM-mode - veneers are handled for now. */ - -static bfd_vma -record_vfp11_erratum_veneer (struct bfd_link_info *link_info, - elf32_vfp11_erratum_list *branch, - bfd *branch_bfd, - asection *branch_sec, - unsigned int offset) -{ - asection *s; - struct elf32_arm_link_hash_table *hash_table; - char *tmp_name; - struct elf_link_hash_entry *myh; - struct bfd_link_hash_entry *bh; - bfd_vma val; - struct _arm_elf_section_data *sec_data; - elf32_vfp11_erratum_list *newerr; - - hash_table = elf32_arm_hash_table (link_info); - BFD_ASSERT (hash_table != NULL); - BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL); - - s = bfd_get_linker_section - (hash_table->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME); - - sec_data = elf32_arm_section_data (s); - - BFD_ASSERT (s != NULL); - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen - (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME, - hash_table->num_vfp11_fixes); - - myh = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE); - - BFD_ASSERT (myh == NULL); - - bh = NULL; - val = hash_table->vfp11_erratum_glue_size; - _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, - tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val, - NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - - /* Link veneer back to calling location. */ - sec_data->erratumcount += 1; - newerr = (elf32_vfp11_erratum_list *) - bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); - - newerr->type = VFP11_ERRATUM_ARM_VENEER; - newerr->vma = -1; - newerr->u.v.branch = branch; - newerr->u.v.id = hash_table->num_vfp11_fixes; - branch->u.b.veneer = newerr; - - newerr->next = sec_data->erratumlist; - sec_data->erratumlist = newerr; - - /* A symbol for the return from the veneer. */ - sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME "_r", - hash_table->num_vfp11_fixes); - - myh = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE); - - if (myh != NULL) - abort (); - - bh = NULL; - val = offset + 4; - _bfd_generic_link_add_one_symbol (link_info, branch_bfd, tmp_name, BSF_LOCAL, - branch_sec, val, NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - - free (tmp_name); - - /* Generate a mapping symbol for the veneer section, and explicitly add an - entry for that symbol to the code/data map for the section. */ - if (hash_table->vfp11_erratum_glue_size == 0) - { - bh = NULL; - /* FIXME: Creates an ARM symbol. Thumb mode will need attention if it - ever requires this erratum fix. */ - _bfd_generic_link_add_one_symbol (link_info, - hash_table->bfd_of_glue_owner, "$a", - BSF_LOCAL, s, 0, NULL, - TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); - myh->forced_local = 1; - - /* The elf32_arm_init_maps function only cares about symbols from input - BFDs. We must make a note of this generated mapping symbol - ourselves so that code byteswapping works properly in - elf32_arm_write_section. */ - elf32_arm_section_map_add (s, 'a', 0); - } - - s->size += VFP11_ERRATUM_VENEER_SIZE; - hash_table->vfp11_erratum_glue_size += VFP11_ERRATUM_VENEER_SIZE; - hash_table->num_vfp11_fixes++; - - /* The offset of the veneer. */ - return val; -} - -/* Record information about a STM32L4XX STM erratum veneer. Only THUMB-mode - veneers need to be handled because used only in Cortex-M. */ - -static bfd_vma -record_stm32l4xx_erratum_veneer (struct bfd_link_info *link_info, - elf32_stm32l4xx_erratum_list *branch, - bfd *branch_bfd, - asection *branch_sec, - unsigned int offset, - bfd_size_type veneer_size) -{ - asection *s; - struct elf32_arm_link_hash_table *hash_table; - char *tmp_name; - struct elf_link_hash_entry *myh; - struct bfd_link_hash_entry *bh; - bfd_vma val; - struct _arm_elf_section_data *sec_data; - elf32_stm32l4xx_erratum_list *newerr; - - hash_table = elf32_arm_hash_table (link_info); - BFD_ASSERT (hash_table != NULL); - BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL); - - s = bfd_get_linker_section - (hash_table->bfd_of_glue_owner, STM32L4XX_ERRATUM_VENEER_SECTION_NAME); - - BFD_ASSERT (s != NULL); - - sec_data = elf32_arm_section_data (s); - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen - (STM32L4XX_ERRATUM_VENEER_ENTRY_NAME) + 10); - - BFD_ASSERT (tmp_name); - - sprintf (tmp_name, STM32L4XX_ERRATUM_VENEER_ENTRY_NAME, - hash_table->num_stm32l4xx_fixes); - - myh = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE); - - BFD_ASSERT (myh == NULL); - - bh = NULL; - val = hash_table->stm32l4xx_erratum_glue_size; - _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner, - tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val, - NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - - /* Link veneer back to calling location. */ - sec_data->stm32l4xx_erratumcount += 1; - newerr = (elf32_stm32l4xx_erratum_list *) - bfd_zmalloc (sizeof (elf32_stm32l4xx_erratum_list)); - - newerr->type = STM32L4XX_ERRATUM_VENEER; - newerr->vma = -1; - newerr->u.v.branch = branch; - newerr->u.v.id = hash_table->num_stm32l4xx_fixes; - branch->u.b.veneer = newerr; - - newerr->next = sec_data->stm32l4xx_erratumlist; - sec_data->stm32l4xx_erratumlist = newerr; - - /* A symbol for the return from the veneer. */ - sprintf (tmp_name, STM32L4XX_ERRATUM_VENEER_ENTRY_NAME "_r", - hash_table->num_stm32l4xx_fixes); - - myh = elf_link_hash_lookup - (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE); - - if (myh != NULL) - abort (); - - bh = NULL; - val = offset + 4; - _bfd_generic_link_add_one_symbol (link_info, branch_bfd, tmp_name, BSF_LOCAL, - branch_sec, val, NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - - free (tmp_name); - - /* Generate a mapping symbol for the veneer section, and explicitly add an - entry for that symbol to the code/data map for the section. */ - if (hash_table->stm32l4xx_erratum_glue_size == 0) - { - bh = NULL; - /* Creates a THUMB symbol since there is no other choice. */ - _bfd_generic_link_add_one_symbol (link_info, - hash_table->bfd_of_glue_owner, "$t", - BSF_LOCAL, s, 0, NULL, - TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); - myh->forced_local = 1; - - /* The elf32_arm_init_maps function only cares about symbols from input - BFDs. We must make a note of this generated mapping symbol - ourselves so that code byteswapping works properly in - elf32_arm_write_section. */ - elf32_arm_section_map_add (s, 't', 0); - } - - s->size += veneer_size; - hash_table->stm32l4xx_erratum_glue_size += veneer_size; - hash_table->num_stm32l4xx_fixes++; - - /* The offset of the veneer. */ - return val; -} - -#define ARM_GLUE_SECTION_FLAGS \ - (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE \ - | SEC_READONLY | SEC_LINKER_CREATED) - -/* Create a fake section for use by the ARM backend of the linker. */ - -static bfd_boolean -arm_make_glue_section (bfd * abfd, const char * name) -{ - asection * sec; - - sec = bfd_get_linker_section (abfd, name); - if (sec != NULL) - /* Already made. */ - return TRUE; - - sec = bfd_make_section_anyway_with_flags (abfd, name, ARM_GLUE_SECTION_FLAGS); - - if (sec == NULL - || !bfd_set_section_alignment (abfd, sec, 2)) - return FALSE; - - /* Set the gc mark to prevent the section from being removed by garbage - collection, despite the fact that no relocs refer to this section. */ - sec->gc_mark = 1; - - return TRUE; -} - -/* Set size of .plt entries. This function is called from the - linker scripts in ld/emultempl/{armelf}.em. */ - -void -bfd_elf32_arm_use_long_plt (void) -{ - elf32_arm_use_long_plt_entry = TRUE; -} - -/* Add the glue sections to ABFD. This function is called from the - linker scripts in ld/emultempl/{armelf}.em. */ - -bfd_boolean -bfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd, - struct bfd_link_info *info) -{ - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info); - bfd_boolean dostm32l4xx = globals - && globals->stm32l4xx_fix != BFD_ARM_STM32L4XX_FIX_NONE; - bfd_boolean addglue; - - /* If we are only performing a partial - link do not bother adding the glue. */ - if (bfd_link_relocatable (info)) - return TRUE; - - addglue = arm_make_glue_section (abfd, ARM2THUMB_GLUE_SECTION_NAME) - && arm_make_glue_section (abfd, THUMB2ARM_GLUE_SECTION_NAME) - && arm_make_glue_section (abfd, VFP11_ERRATUM_VENEER_SECTION_NAME) - && arm_make_glue_section (abfd, ARM_BX_GLUE_SECTION_NAME); - - if (!dostm32l4xx) - return addglue; - - return addglue - && arm_make_glue_section (abfd, STM32L4XX_ERRATUM_VENEER_SECTION_NAME); -} - -/* Mark output sections of veneers needing a dedicated one with SEC_KEEP. This - ensures they are not marked for deletion by - strip_excluded_output_sections () when veneers are going to be created - later. Not doing so would trigger assert on empty section size in - lang_size_sections_1 (). */ - -void -bfd_elf32_arm_keep_private_stub_output_sections (struct bfd_link_info *info) -{ - enum elf32_arm_stub_type stub_type; - - /* If we are only performing a partial - link do not bother adding the glue. */ - if (bfd_link_relocatable (info)) - return; - - for (stub_type = arm_stub_none + 1; stub_type < max_stub_type; stub_type++) - { - asection *out_sec; - const char *out_sec_name; - - if (!arm_dedicated_stub_output_section_required (stub_type)) - continue; - - out_sec_name = arm_dedicated_stub_output_section_name (stub_type); - out_sec = bfd_get_section_by_name (info->output_bfd, out_sec_name); - if (out_sec != NULL) - out_sec->flags |= SEC_KEEP; - } -} - -/* Select a BFD to be used to hold the sections used by the glue code. - This function is called from the linker scripts in ld/emultempl/ - {armelf/pe}.em. */ - -bfd_boolean -bfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info) -{ - struct elf32_arm_link_hash_table *globals; - - /* If we are only performing a partial link - do not bother getting a bfd to hold the glue. */ - if (bfd_link_relocatable (info)) - return TRUE; - - /* Make sure we don't attach the glue sections to a dynamic object. */ - BFD_ASSERT (!(abfd->flags & DYNAMIC)); - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - - if (globals->bfd_of_glue_owner != NULL) - return TRUE; - - /* Save the bfd for later use. */ - globals->bfd_of_glue_owner = abfd; - - return TRUE; -} - -static void -check_use_blx (struct elf32_arm_link_hash_table *globals) -{ - int cpu_arch; - - cpu_arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC, - Tag_CPU_arch); - - if (globals->fix_arm1176) - { - if (cpu_arch == TAG_CPU_ARCH_V6T2 || cpu_arch > TAG_CPU_ARCH_V6K) - globals->use_blx = 1; - } - else - { - if (cpu_arch > TAG_CPU_ARCH_V4T) - globals->use_blx = 1; - } -} - -bfd_boolean -bfd_elf32_arm_process_before_allocation (bfd *abfd, - struct bfd_link_info *link_info) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - - asection *sec; - struct elf32_arm_link_hash_table *globals; - - /* If we are only performing a partial link do not bother - to construct any glue. */ - if (bfd_link_relocatable (link_info)) - return TRUE; - - /* Here we have a bfd that is to be included on the link. We have a - hook to do reloc rummaging, before section sizes are nailed down. */ - globals = elf32_arm_hash_table (link_info); - BFD_ASSERT (globals != NULL); - - check_use_blx (globals); - - if (globals->byteswap_code && !bfd_big_endian (abfd)) - { - _bfd_error_handler (_("%B: BE8 images only valid in big-endian mode."), - abfd); - return FALSE; - } - - /* PR 5398: If we have not decided to include any loadable sections in - the output then we will not have a glue owner bfd. This is OK, it - just means that there is nothing else for us to do here. */ - if (globals->bfd_of_glue_owner == NULL) - return TRUE; - - /* Rummage around all the relocs and map the glue vectors. */ - sec = abfd->sections; - - if (sec == NULL) - return TRUE; - - for (; sec != NULL; sec = sec->next) - { - if (sec->reloc_count == 0) - continue; - - if ((sec->flags & SEC_EXCLUDE) != 0) - continue; - - symtab_hdr = & elf_symtab_hdr (abfd); - - /* Load the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, FALSE); - - if (internal_relocs == NULL) - goto error_return; - - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - long r_type; - unsigned long r_index; - - struct elf_link_hash_entry *h; - - r_type = ELF32_R_TYPE (irel->r_info); - r_index = ELF32_R_SYM (irel->r_info); - - /* These are the only relocation types we care about. */ - if ( r_type != R_ARM_PC24 - && (r_type != R_ARM_V4BX || globals->fix_v4bx < 2)) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - if (r_type == R_ARM_V4BX) - { - int reg; - - reg = bfd_get_32 (abfd, contents + irel->r_offset) & 0xf; - record_arm_bx_glue (link_info, reg); - continue; - } - - /* If the relocation is not against a symbol it cannot concern us. */ - h = NULL; - - /* We don't care about local symbols. */ - if (r_index < symtab_hdr->sh_info) - continue; - - /* This is an external symbol. */ - r_index -= symtab_hdr->sh_info; - h = (struct elf_link_hash_entry *) - elf_sym_hashes (abfd)[r_index]; - - /* If the relocation is against a static symbol it must be within - the current section and so cannot be a cross ARM/Thumb relocation. */ - if (h == NULL) - continue; - - /* If the call will go through a PLT entry then we do not need - glue. */ - if (globals->root.splt != NULL && h->plt.offset != (bfd_vma) -1) - continue; - - switch (r_type) - { - case R_ARM_PC24: - /* This one is a call from arm code. We need to look up - the target of the call. If it is a thumb target, we - insert glue. */ - if (ARM_GET_SYM_BRANCH_TYPE (h->target_internal) - == ST_BRANCH_TO_THUMB) - record_arm_to_thumb_glue (link_info, h); - break; - - default: - abort (); - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - contents = NULL; - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - internal_relocs = NULL; - } - - return TRUE; - -error_return: - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} -#endif - - -/* Initialise maps of ARM/Thumb/data for input BFDs. */ - -void -bfd_elf32_arm_init_maps (bfd *abfd) -{ - Elf_Internal_Sym *isymbuf; - Elf_Internal_Shdr *hdr; - unsigned int i, localsyms; - - /* PR 7093: Make sure that we are dealing with an arm elf binary. */ - if (! is_arm_elf (abfd)) - return; - - if ((abfd->flags & DYNAMIC) != 0) - return; - - hdr = & elf_symtab_hdr (abfd); - localsyms = hdr->sh_info; - - /* Obtain a buffer full of symbols for this BFD. The hdr->sh_info field - should contain the number of local symbols, which should come before any - global symbols. Mapping symbols are always local. */ - isymbuf = bfd_elf_get_elf_syms (abfd, hdr, localsyms, 0, NULL, NULL, - NULL); - - /* No internal symbols read? Skip this BFD. */ - if (isymbuf == NULL) - return; - - for (i = 0; i < localsyms; i++) - { - Elf_Internal_Sym *isym = &isymbuf[i]; - asection *sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - const char *name; - - if (sec != NULL - && ELF_ST_BIND (isym->st_info) == STB_LOCAL) - { - name = bfd_elf_string_from_elf_section (abfd, - hdr->sh_link, isym->st_name); - - if (bfd_is_arm_special_symbol_name (name, - BFD_ARM_SPECIAL_SYM_TYPE_MAP)) - elf32_arm_section_map_add (sec, name[1], isym->st_value); - } - } -} - - -/* Auto-select enabling of Cortex-A8 erratum fix if the user didn't explicitly - say what they wanted. */ - -void -bfd_elf32_arm_set_cortex_a8_fix (bfd *obfd, struct bfd_link_info *link_info) -{ - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd); - - if (globals == NULL) - return; - - if (globals->fix_cortex_a8 == -1) - { - /* Turn on Cortex-A8 erratum workaround for ARMv7-A. */ - if (out_attr[Tag_CPU_arch].i == TAG_CPU_ARCH_V7 - && (out_attr[Tag_CPU_arch_profile].i == 'A' - || out_attr[Tag_CPU_arch_profile].i == 0)) - globals->fix_cortex_a8 = 1; - else - globals->fix_cortex_a8 = 0; - } -} - - -void -bfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info) -{ - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd); - - if (globals == NULL) - return; - /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix. */ - if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7) - { - switch (globals->vfp11_fix) - { - case BFD_ARM_VFP11_FIX_DEFAULT: - case BFD_ARM_VFP11_FIX_NONE: - globals->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; - break; - - default: - /* Give a warning, but do as the user requests anyway. */ - _bfd_error_handler (_("%B: warning: selected VFP11 erratum " - "workaround is not necessary for target architecture"), obfd); - } - } - else if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_DEFAULT) - /* For earlier architectures, we might need the workaround, but do not - enable it by default. If users is running with broken hardware, they - must enable the erratum fix explicitly. */ - globals->vfp11_fix = BFD_ARM_VFP11_FIX_NONE; -} - -void -bfd_elf32_arm_set_stm32l4xx_fix (bfd *obfd, struct bfd_link_info *link_info) -{ - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd); - - if (globals == NULL) - return; - - /* We assume only Cortex-M4 may require the fix. */ - if (out_attr[Tag_CPU_arch].i != TAG_CPU_ARCH_V7E_M - || out_attr[Tag_CPU_arch_profile].i != 'M') - { - if (globals->stm32l4xx_fix != BFD_ARM_STM32L4XX_FIX_NONE) - /* Give a warning, but do as the user requests anyway. */ - _bfd_error_handler - (_("%B: warning: selected STM32L4XX erratum " - "workaround is not necessary for target architecture"), obfd); - } -} - -enum bfd_arm_vfp11_pipe -{ - VFP11_FMAC, - VFP11_LS, - VFP11_DS, - VFP11_BAD -}; - -/* Return a VFP register number. This is encoded as RX:X for single-precision - registers, or X:RX for double-precision registers, where RX is the group of - four bits in the instruction encoding and X is the single extension bit. - RX and X fields are specified using their lowest (starting) bit. The return - value is: - - 0...31: single-precision registers s0...s31 - 32...63: double-precision registers d0...d31. - - Although X should be zero for VFP11 (encoding d0...d15 only), we might - encounter VFP3 instructions, so we allow the full range for DP registers. */ - -static unsigned int -bfd_arm_vfp11_regno (unsigned int insn, bfd_boolean is_double, unsigned int rx, - unsigned int x) -{ - if (is_double) - return (((insn >> rx) & 0xf) | (((insn >> x) & 1) << 4)) + 32; - else - return (((insn >> rx) & 0xf) << 1) | ((insn >> x) & 1); -} - -/* Set bits in *WMASK according to a register number REG as encoded by - bfd_arm_vfp11_regno(). Ignore d16-d31. */ - -static void -bfd_arm_vfp11_write_mask (unsigned int *wmask, unsigned int reg) -{ - if (reg < 32) - *wmask |= 1 << reg; - else if (reg < 48) - *wmask |= 3 << ((reg - 32) * 2); -} - -/* Return TRUE if WMASK overwrites anything in REGS. */ - -static bfd_boolean -bfd_arm_vfp11_antidependency (unsigned int wmask, int *regs, int numregs) -{ - int i; - - for (i = 0; i < numregs; i++) - { - unsigned int reg = regs[i]; - - if (reg < 32 && (wmask & (1 << reg)) != 0) - return TRUE; - - reg -= 32; - - if (reg >= 16) - continue; - - if ((wmask & (3 << (reg * 2))) != 0) - return TRUE; - } - - return FALSE; -} - -/* In this function, we're interested in two things: finding input registers - for VFP data-processing instructions, and finding the set of registers which - arbitrary VFP instructions may write to. We use a 32-bit unsigned int to - hold the written set, so FLDM etc. are easy to deal with (we're only - interested in 32 SP registers or 16 dp registers, due to the VFP version - implemented by the chip in question). DP registers are marked by setting - both SP registers in the write mask). */ - -static enum bfd_arm_vfp11_pipe -bfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs, - int *numregs) -{ - enum bfd_arm_vfp11_pipe vpipe = VFP11_BAD; - bfd_boolean is_double = ((insn & 0xf00) == 0xb00) ? 1 : 0; - - if ((insn & 0x0f000e10) == 0x0e000a00) /* A data-processing insn. */ - { - unsigned int pqrs; - unsigned int fd = bfd_arm_vfp11_regno (insn, is_double, 12, 22); - unsigned int fm = bfd_arm_vfp11_regno (insn, is_double, 0, 5); - - pqrs = ((insn & 0x00800000) >> 20) - | ((insn & 0x00300000) >> 19) - | ((insn & 0x00000040) >> 6); - - switch (pqrs) - { - case 0: /* fmac[sd]. */ - case 1: /* fnmac[sd]. */ - case 2: /* fmsc[sd]. */ - case 3: /* fnmsc[sd]. */ - vpipe = VFP11_FMAC; - bfd_arm_vfp11_write_mask (destmask, fd); - regs[0] = fd; - regs[1] = bfd_arm_vfp11_regno (insn, is_double, 16, 7); /* Fn. */ - regs[2] = fm; - *numregs = 3; - break; - - case 4: /* fmul[sd]. */ - case 5: /* fnmul[sd]. */ - case 6: /* fadd[sd]. */ - case 7: /* fsub[sd]. */ - vpipe = VFP11_FMAC; - goto vfp_binop; - - case 8: /* fdiv[sd]. */ - vpipe = VFP11_DS; - vfp_binop: - bfd_arm_vfp11_write_mask (destmask, fd); - regs[0] = bfd_arm_vfp11_regno (insn, is_double, 16, 7); /* Fn. */ - regs[1] = fm; - *numregs = 2; - break; - - case 15: /* extended opcode. */ - { - unsigned int extn = ((insn >> 15) & 0x1e) - | ((insn >> 7) & 1); - - switch (extn) - { - case 0: /* fcpy[sd]. */ - case 1: /* fabs[sd]. */ - case 2: /* fneg[sd]. */ - case 8: /* fcmp[sd]. */ - case 9: /* fcmpe[sd]. */ - case 10: /* fcmpz[sd]. */ - case 11: /* fcmpez[sd]. */ - case 16: /* fuito[sd]. */ - case 17: /* fsito[sd]. */ - case 24: /* ftoui[sd]. */ - case 25: /* ftouiz[sd]. */ - case 26: /* ftosi[sd]. */ - case 27: /* ftosiz[sd]. */ - /* These instructions will not bounce due to underflow. */ - *numregs = 0; - vpipe = VFP11_FMAC; - break; - - case 3: /* fsqrt[sd]. */ - /* fsqrt cannot underflow, but it can (perhaps) overwrite - registers to cause the erratum in previous instructions. */ - bfd_arm_vfp11_write_mask (destmask, fd); - vpipe = VFP11_DS; - break; - - case 15: /* fcvt{ds,sd}. */ - { - int rnum = 0; - - bfd_arm_vfp11_write_mask (destmask, fd); - - /* Only FCVTSD can underflow. */ - if ((insn & 0x100) != 0) - regs[rnum++] = fm; - - *numregs = rnum; - - vpipe = VFP11_FMAC; - } - break; - - default: - return VFP11_BAD; - } - } - break; - - default: - return VFP11_BAD; - } - } - /* Two-register transfer. */ - else if ((insn & 0x0fe00ed0) == 0x0c400a10) - { - unsigned int fm = bfd_arm_vfp11_regno (insn, is_double, 0, 5); - - if ((insn & 0x100000) == 0) - { - if (is_double) - bfd_arm_vfp11_write_mask (destmask, fm); - else - { - bfd_arm_vfp11_write_mask (destmask, fm); - bfd_arm_vfp11_write_mask (destmask, fm + 1); - } - } - - vpipe = VFP11_LS; - } - else if ((insn & 0x0e100e00) == 0x0c100a00) /* A load insn. */ - { - int fd = bfd_arm_vfp11_regno (insn, is_double, 12, 22); - unsigned int puw = ((insn >> 21) & 0x1) | (((insn >> 23) & 3) << 1); - - switch (puw) - { - case 0: /* Two-reg transfer. We should catch these above. */ - abort (); - - case 2: /* fldm[sdx]. */ - case 3: - case 5: - { - unsigned int i, offset = insn & 0xff; - - if (is_double) - offset >>= 1; - - for (i = fd; i < fd + offset; i++) - bfd_arm_vfp11_write_mask (destmask, i); - } - break; - - case 4: /* fld[sd]. */ - case 6: - bfd_arm_vfp11_write_mask (destmask, fd); - break; - - default: - return VFP11_BAD; - } - - vpipe = VFP11_LS; - } - /* Single-register transfer. Note L==0. */ - else if ((insn & 0x0f100e10) == 0x0e000a10) - { - unsigned int opcode = (insn >> 21) & 7; - unsigned int fn = bfd_arm_vfp11_regno (insn, is_double, 16, 7); - - switch (opcode) - { - case 0: /* fmsr/fmdlr. */ - case 1: /* fmdhr. */ - /* Mark fmdhr and fmdlr as writing to the whole of the DP - destination register. I don't know if this is exactly right, - but it is the conservative choice. */ - bfd_arm_vfp11_write_mask (destmask, fn); - break; - - case 7: /* fmxr. */ - break; - } - - vpipe = VFP11_LS; - } - - return vpipe; -} - - -static int elf32_arm_compare_mapping (const void * a, const void * b); - - -/* Look for potentially-troublesome code sequences which might trigger the - VFP11 denormal/antidependency erratum. See, e.g., the ARM1136 errata sheet - (available from ARM) for details of the erratum. A short version is - described in ld.texinfo. */ - -bfd_boolean -bfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info) -{ - asection *sec; - bfd_byte *contents = NULL; - int state = 0; - int regs[3], numregs = 0; - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - int use_vector = (globals->vfp11_fix == BFD_ARM_VFP11_FIX_VECTOR); - - if (globals == NULL) - return FALSE; - - /* We use a simple FSM to match troublesome VFP11 instruction sequences. - The states transition as follows: - - 0 -> 1 (vector) or 0 -> 2 (scalar) - A VFP FMAC-pipeline instruction has been seen. Fill - regs[0]..regs[numregs-1] with its input operands. Remember this - instruction in 'first_fmac'. - - 1 -> 2 - Any instruction, except for a VFP instruction which overwrites - regs[*]. - - 1 -> 3 [ -> 0 ] or - 2 -> 3 [ -> 0 ] - A VFP instruction has been seen which overwrites any of regs[*]. - We must make a veneer! Reset state to 0 before examining next - instruction. - - 2 -> 0 - If we fail to match anything in state 2, reset to state 0 and reset - the instruction pointer to the instruction after 'first_fmac'. - - If the VFP11 vector mode is in use, there must be at least two unrelated - instructions between anti-dependent VFP11 instructions to properly avoid - triggering the erratum, hence the use of the extra state 1. */ - - /* If we are only performing a partial link do not bother - to construct any glue. */ - if (bfd_link_relocatable (link_info)) - return TRUE; - - /* Skip if this bfd does not correspond to an ELF image. */ - if (! is_arm_elf (abfd)) - return TRUE; - - /* We should have chosen a fix type by the time we get here. */ - BFD_ASSERT (globals->vfp11_fix != BFD_ARM_VFP11_FIX_DEFAULT); - - if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE) - return TRUE; - - /* Skip this BFD if it corresponds to an executable or dynamic object. */ - if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) - return TRUE; - - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - unsigned int i, span, first_fmac = 0, veneer_of_insn = 0; - struct _arm_elf_section_data *sec_data; - - /* If we don't have executable progbits, we're not interested in this - section. Also skip if section is to be excluded. */ - if (elf_section_type (sec) != SHT_PROGBITS - || (elf_section_flags (sec) & SHF_EXECINSTR) == 0 - || (sec->flags & SEC_EXCLUDE) != 0 - || sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS - || sec->output_section == bfd_abs_section_ptr - || strcmp (sec->name, VFP11_ERRATUM_VENEER_SECTION_NAME) == 0) - continue; - - sec_data = elf32_arm_section_data (sec); - - if (sec_data->mapcount == 0) - continue; - - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - - qsort (sec_data->map, sec_data->mapcount, sizeof (elf32_arm_section_map), - elf32_arm_compare_mapping); - - for (span = 0; span < sec_data->mapcount; span++) - { - unsigned int span_start = sec_data->map[span].vma; - unsigned int span_end = (span == sec_data->mapcount - 1) - ? sec->size : sec_data->map[span + 1].vma; - char span_type = sec_data->map[span].type; - - /* FIXME: Only ARM mode is supported at present. We may need to - support Thumb-2 mode also at some point. */ - if (span_type != 'a') - continue; - - for (i = span_start; i < span_end;) - { - unsigned int next_i = i + 4; - unsigned int insn = bfd_big_endian (abfd) - ? (contents[i] << 24) - | (contents[i + 1] << 16) - | (contents[i + 2] << 8) - | contents[i + 3] - : (contents[i + 3] << 24) - | (contents[i + 2] << 16) - | (contents[i + 1] << 8) - | contents[i]; - unsigned int writemask = 0; - enum bfd_arm_vfp11_pipe vpipe; - - switch (state) - { - case 0: - vpipe = bfd_arm_vfp11_insn_decode (insn, &writemask, regs, - &numregs); - /* I'm assuming the VFP11 erratum can trigger with denorm - operands on either the FMAC or the DS pipeline. This might - lead to slightly overenthusiastic veneer insertion. */ - if (vpipe == VFP11_FMAC || vpipe == VFP11_DS) - { - state = use_vector ? 1 : 2; - first_fmac = i; - veneer_of_insn = insn; - } - break; - - case 1: - { - int other_regs[3], other_numregs; - vpipe = bfd_arm_vfp11_insn_decode (insn, &writemask, - other_regs, - &other_numregs); - if (vpipe != VFP11_BAD - && bfd_arm_vfp11_antidependency (writemask, regs, - numregs)) - state = 3; - else - state = 2; - } - break; - - case 2: - { - int other_regs[3], other_numregs; - vpipe = bfd_arm_vfp11_insn_decode (insn, &writemask, - other_regs, - &other_numregs); - if (vpipe != VFP11_BAD - && bfd_arm_vfp11_antidependency (writemask, regs, - numregs)) - state = 3; - else - { - state = 0; - next_i = first_fmac + 4; - } - } - break; - - case 3: - abort (); /* Should be unreachable. */ - } - - if (state == 3) - { - elf32_vfp11_erratum_list *newerr =(elf32_vfp11_erratum_list *) - bfd_zmalloc (sizeof (elf32_vfp11_erratum_list)); - - elf32_arm_section_data (sec)->erratumcount += 1; - - newerr->u.b.vfp_insn = veneer_of_insn; - - switch (span_type) - { - case 'a': - newerr->type = VFP11_ERRATUM_BRANCH_TO_ARM_VENEER; - break; - - default: - abort (); - } - - record_vfp11_erratum_veneer (link_info, newerr, abfd, sec, - first_fmac); - - newerr->vma = -1; - - newerr->next = sec_data->erratumlist; - sec_data->erratumlist = newerr; - - state = 0; - } - - i = next_i; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - contents = NULL; - } - - return TRUE; - -error_return: - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - - return FALSE; -} - -/* Find virtual-memory addresses for VFP11 erratum veneers and return locations - after sections have been laid out, using specially-named symbols. */ - -void -bfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd, - struct bfd_link_info *link_info) -{ - asection *sec; - struct elf32_arm_link_hash_table *globals; - char *tmp_name; - - if (bfd_link_relocatable (link_info)) - return; - - /* Skip if this bfd does not correspond to an ELF image. */ - if (! is_arm_elf (abfd)) - return; - - globals = elf32_arm_hash_table (link_info); - if (globals == NULL) - return; - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen - (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10); - - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec); - elf32_vfp11_erratum_list *errnode = sec_data->erratumlist; - - for (; errnode != NULL; errnode = errnode->next) - { - struct elf_link_hash_entry *myh; - bfd_vma vma; - - switch (errnode->type) - { - case VFP11_ERRATUM_BRANCH_TO_ARM_VENEER: - case VFP11_ERRATUM_BRANCH_TO_THUMB_VENEER: - /* Find veneer symbol. */ - sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME, - errnode->u.b.veneer->u.v.id); - - myh = elf_link_hash_lookup - (&(globals)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL) - _bfd_error_handler (_("%B: unable to find VFP11 veneer " - "`%s'"), abfd, tmp_name); - - vma = myh->root.u.def.section->output_section->vma - + myh->root.u.def.section->output_offset - + myh->root.u.def.value; - - errnode->u.b.veneer->vma = vma; - break; - - case VFP11_ERRATUM_ARM_VENEER: - case VFP11_ERRATUM_THUMB_VENEER: - /* Find return location. */ - sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME "_r", - errnode->u.v.id); - - myh = elf_link_hash_lookup - (&(globals)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL) - _bfd_error_handler (_("%B: unable to find VFP11 veneer " - "`%s'"), abfd, tmp_name); - - vma = myh->root.u.def.section->output_section->vma - + myh->root.u.def.section->output_offset - + myh->root.u.def.value; - - errnode->u.v.branch->vma = vma; - break; - - default: - abort (); - } - } - } - - free (tmp_name); -} - -/* Find virtual-memory addresses for STM32L4XX erratum veneers and - return locations after sections have been laid out, using - specially-named symbols. */ - -void -bfd_elf32_arm_stm32l4xx_fix_veneer_locations (bfd *abfd, - struct bfd_link_info *link_info) -{ - asection *sec; - struct elf32_arm_link_hash_table *globals; - char *tmp_name; - - if (bfd_link_relocatable (link_info)) - return; - - /* Skip if this bfd does not correspond to an ELF image. */ - if (! is_arm_elf (abfd)) - return; - - globals = elf32_arm_hash_table (link_info); - if (globals == NULL) - return; - - tmp_name = (char *) bfd_malloc ((bfd_size_type) strlen - (STM32L4XX_ERRATUM_VENEER_ENTRY_NAME) + 10); - - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec); - elf32_stm32l4xx_erratum_list *errnode = sec_data->stm32l4xx_erratumlist; - - for (; errnode != NULL; errnode = errnode->next) - { - struct elf_link_hash_entry *myh; - bfd_vma vma; - - switch (errnode->type) - { - case STM32L4XX_ERRATUM_BRANCH_TO_VENEER: - /* Find veneer symbol. */ - sprintf (tmp_name, STM32L4XX_ERRATUM_VENEER_ENTRY_NAME, - errnode->u.b.veneer->u.v.id); - - myh = elf_link_hash_lookup - (&(globals)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL) - _bfd_error_handler (_("%B: unable to find STM32L4XX veneer " - "`%s'"), abfd, tmp_name); - - vma = myh->root.u.def.section->output_section->vma - + myh->root.u.def.section->output_offset - + myh->root.u.def.value; - - errnode->u.b.veneer->vma = vma; - break; - - case STM32L4XX_ERRATUM_VENEER: - /* Find return location. */ - sprintf (tmp_name, STM32L4XX_ERRATUM_VENEER_ENTRY_NAME "_r", - errnode->u.v.id); - - myh = elf_link_hash_lookup - (&(globals)->root, tmp_name, FALSE, FALSE, TRUE); - - if (myh == NULL) - _bfd_error_handler (_("%B: unable to find STM32L4XX veneer " - "`%s'"), abfd, tmp_name); - - vma = myh->root.u.def.section->output_section->vma - + myh->root.u.def.section->output_offset - + myh->root.u.def.value; - - errnode->u.v.branch->vma = vma; - break; - - default: - abort (); - } - } - } - - free (tmp_name); -} - -static inline bfd_boolean -is_thumb2_ldmia (const insn32 insn) -{ - /* Encoding T2: LDM.W {!}, - 1110 - 1000 - 10W1 - rrrr - PM (0) l - llll - llll - llll. */ - return (insn & 0xffd02000) == 0xe8900000; -} - -static inline bfd_boolean -is_thumb2_ldmdb (const insn32 insn) -{ - /* Encoding T1: LDMDB {!}, - 1110 - 1001 - 00W1 - rrrr - PM (0) l - llll - llll - llll. */ - return (insn & 0xffd02000) == 0xe9100000; -} - -static inline bfd_boolean -is_thumb2_vldm (const insn32 insn) -{ - /* A6.5 Extension register load or store instruction - A7.7.229 - We look for SP 32-bit and DP 64-bit registers. - Encoding T1 VLDM{mode} {!}, - is consecutive 64-bit registers - 1110 - 110P - UDW1 - rrrr - vvvv - 1011 - iiii - iiii - Encoding T2 VLDM{mode} {!}, - is consecutive 32-bit registers - 1110 - 110P - UDW1 - rrrr - vvvv - 1010 - iiii - iiii - if P==0 && U==1 && W==1 && Rn=1101 VPOP - if PUW=010 || PUW=011 || PUW=101 VLDM. */ - return - (((insn & 0xfe100f00) == 0xec100b00) || - ((insn & 0xfe100f00) == 0xec100a00)) - && /* (IA without !). */ - (((((insn << 7) >> 28) & 0xd) == 0x4) - /* (IA with !), includes VPOP (when reg number is SP). */ - || ((((insn << 7) >> 28) & 0xd) == 0x5) - /* (DB with !). */ - || ((((insn << 7) >> 28) & 0xd) == 0x9)); -} - -/* STM STM32L4XX erratum : This function assumes that it receives an LDM or - VLDM opcode and: - - computes the number and the mode of memory accesses - - decides if the replacement should be done: - . replaces only if > 8-word accesses - . or (testing purposes only) replaces all accesses. */ - -static bfd_boolean -stm32l4xx_need_create_replacing_stub (const insn32 insn, - bfd_arm_stm32l4xx_fix stm32l4xx_fix) -{ - int nb_words = 0; - - /* The field encoding the register list is the same for both LDMIA - and LDMDB encodings. */ - if (is_thumb2_ldmia (insn) || is_thumb2_ldmdb (insn)) - nb_words = elf32_arm_popcount (insn & 0x0000ffff); - else if (is_thumb2_vldm (insn)) - nb_words = (insn & 0xff); - - /* DEFAULT mode accounts for the real bug condition situation, - ALL mode inserts stubs for each LDM/VLDM instruction (testing). */ - return - (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_DEFAULT) ? nb_words > 8 : - (stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_ALL) ? TRUE : FALSE; -} - -/* Look for potentially-troublesome code sequences which might trigger - the STM STM32L4XX erratum. */ - -bfd_boolean -bfd_elf32_arm_stm32l4xx_erratum_scan (bfd *abfd, - struct bfd_link_info *link_info) -{ - asection *sec; - bfd_byte *contents = NULL; - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - - if (globals == NULL) - return FALSE; - - /* If we are only performing a partial link do not bother - to construct any glue. */ - if (bfd_link_relocatable (link_info)) - return TRUE; - - /* Skip if this bfd does not correspond to an ELF image. */ - if (! is_arm_elf (abfd)) - return TRUE; - - if (globals->stm32l4xx_fix == BFD_ARM_STM32L4XX_FIX_NONE) - return TRUE; - - /* Skip this BFD if it corresponds to an executable or dynamic object. */ - if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) - return TRUE; - - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - unsigned int i, span; - struct _arm_elf_section_data *sec_data; - - /* If we don't have executable progbits, we're not interested in this - section. Also skip if section is to be excluded. */ - if (elf_section_type (sec) != SHT_PROGBITS - || (elf_section_flags (sec) & SHF_EXECINSTR) == 0 - || (sec->flags & SEC_EXCLUDE) != 0 - || sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS - || sec->output_section == bfd_abs_section_ptr - || strcmp (sec->name, STM32L4XX_ERRATUM_VENEER_SECTION_NAME) == 0) - continue; - - sec_data = elf32_arm_section_data (sec); - - if (sec_data->mapcount == 0) - continue; - - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - - qsort (sec_data->map, sec_data->mapcount, sizeof (elf32_arm_section_map), - elf32_arm_compare_mapping); - - for (span = 0; span < sec_data->mapcount; span++) - { - unsigned int span_start = sec_data->map[span].vma; - unsigned int span_end = (span == sec_data->mapcount - 1) - ? sec->size : sec_data->map[span + 1].vma; - char span_type = sec_data->map[span].type; - int itblock_current_pos = 0; - - /* Only Thumb2 mode need be supported with this CM4 specific - code, we should not encounter any arm mode eg span_type - != 'a'. */ - if (span_type != 't') - continue; - - for (i = span_start; i < span_end;) - { - unsigned int insn = bfd_get_16 (abfd, &contents[i]); - bfd_boolean insn_32bit = FALSE; - bfd_boolean is_ldm = FALSE; - bfd_boolean is_vldm = FALSE; - bfd_boolean is_not_last_in_it_block = FALSE; - - /* The first 16-bits of all 32-bit thumb2 instructions start - with opcode[15..13]=0b111 and the encoded op1 can be anything - except opcode[12..11]!=0b00. - See 32-bit Thumb instruction encoding. */ - if ((insn & 0xe000) == 0xe000 && (insn & 0x1800) != 0x0000) - insn_32bit = TRUE; - - /* Compute the predicate that tells if the instruction - is concerned by the IT block - - Creates an error if there is a ldm that is not - last in the IT block thus cannot be replaced - - Otherwise we can create a branch at the end of the - IT block, it will be controlled naturally by IT - with the proper pseudo-predicate - - So the only interesting predicate is the one that - tells that we are not on the last item of an IT - block. */ - if (itblock_current_pos != 0) - is_not_last_in_it_block = !!--itblock_current_pos; - - if (insn_32bit) - { - /* Load the rest of the insn (in manual-friendly order). */ - insn = (insn << 16) | bfd_get_16 (abfd, &contents[i + 2]); - is_ldm = is_thumb2_ldmia (insn) || is_thumb2_ldmdb (insn); - is_vldm = is_thumb2_vldm (insn); - - /* Veneers are created for (v)ldm depending on - option flags and memory accesses conditions; but - if the instruction is not the last instruction of - an IT block, we cannot create a jump there, so we - bail out. */ - if ((is_ldm || is_vldm) - && stm32l4xx_need_create_replacing_stub - (insn, globals->stm32l4xx_fix)) - { - if (is_not_last_in_it_block) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#x): error: multiple load detected" - " in non-last IT block instruction :" - " STM32L4XX veneer cannot be generated.\n" - "Use gcc option -mrestrict-it to generate" - " only one instruction per IT block.\n"), - abfd, sec, i); - } - else - { - elf32_stm32l4xx_erratum_list *newerr = - (elf32_stm32l4xx_erratum_list *) - bfd_zmalloc - (sizeof (elf32_stm32l4xx_erratum_list)); - - elf32_arm_section_data (sec) - ->stm32l4xx_erratumcount += 1; - newerr->u.b.insn = insn; - /* We create only thumb branches. */ - newerr->type = - STM32L4XX_ERRATUM_BRANCH_TO_VENEER; - record_stm32l4xx_erratum_veneer - (link_info, newerr, abfd, sec, - i, - is_ldm ? - STM32L4XX_ERRATUM_LDM_VENEER_SIZE: - STM32L4XX_ERRATUM_VLDM_VENEER_SIZE); - newerr->vma = -1; - newerr->next = sec_data->stm32l4xx_erratumlist; - sec_data->stm32l4xx_erratumlist = newerr; - } - } - } - else - { - /* A7.7.37 IT p208 - IT blocks are only encoded in T1 - Encoding T1: IT{x{y{z}}} - 1 0 1 1 - 1 1 1 1 - firstcond - mask - if mask = '0000' then see 'related encodings' - We don't deal with UNPREDICTABLE, just ignore these. - There can be no nested IT blocks so an IT block - is naturally a new one for which it is worth - computing its size. */ - bfd_boolean is_newitblock = ((insn & 0xff00) == 0xbf00) - && ((insn & 0x000f) != 0x0000); - /* If we have a new IT block we compute its size. */ - if (is_newitblock) - { - /* Compute the number of instructions controlled - by the IT block, it will be used to decide - whether we are inside an IT block or not. */ - unsigned int mask = insn & 0x000f; - itblock_current_pos = 4 - ctz (mask); - } - } - - i += insn_32bit ? 4 : 2; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - contents = NULL; - } - - return TRUE; - -error_return: - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - - return FALSE; -} - -/* Set target relocation values needed during linking. */ - -void -bfd_elf32_arm_set_target_params (struct bfd *output_bfd, - struct bfd_link_info *link_info, - struct elf32_arm_params *params) -{ - struct elf32_arm_link_hash_table *globals; - - globals = elf32_arm_hash_table (link_info); - if (globals == NULL) - return; - - globals->target1_is_rel = params->target1_is_rel; - if (strcmp (params->target2_type, "rel") == 0) - globals->target2_reloc = R_ARM_REL32; - else if (strcmp (params->target2_type, "abs") == 0) - globals->target2_reloc = R_ARM_ABS32; - else if (strcmp (params->target2_type, "got-rel") == 0) - globals->target2_reloc = R_ARM_GOT_PREL; - else - { - _bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."), - params->target2_type); - } - globals->fix_v4bx = params->fix_v4bx; - globals->use_blx |= params->use_blx; - globals->vfp11_fix = params->vfp11_denorm_fix; - globals->stm32l4xx_fix = params->stm32l4xx_fix; - globals->pic_veneer = params->pic_veneer; - globals->fix_cortex_a8 = params->fix_cortex_a8; - globals->fix_arm1176 = params->fix_arm1176; - globals->cmse_implib = params->cmse_implib; - globals->in_implib_bfd = params->in_implib_bfd; - - BFD_ASSERT (is_arm_elf (output_bfd)); - elf_arm_tdata (output_bfd)->no_enum_size_warning - = params->no_enum_size_warning; - elf_arm_tdata (output_bfd)->no_wchar_size_warning - = params->no_wchar_size_warning; -} - -/* Replace the target offset of a Thumb bl or b.w instruction. */ - -static void -insert_thumb_branch (bfd *abfd, long int offset, bfd_byte *insn) -{ - bfd_vma upper; - bfd_vma lower; - int reloc_sign; - - BFD_ASSERT ((offset & 1) == 0); - - upper = bfd_get_16 (abfd, insn); - lower = bfd_get_16 (abfd, insn + 2); - reloc_sign = (offset < 0) ? 1 : 0; - upper = (upper & ~(bfd_vma) 0x7ff) - | ((offset >> 12) & 0x3ff) - | (reloc_sign << 10); - lower = (lower & ~(bfd_vma) 0x2fff) - | (((!((offset >> 23) & 1)) ^ reloc_sign) << 13) - | (((!((offset >> 22) & 1)) ^ reloc_sign) << 11) - | ((offset >> 1) & 0x7ff); - bfd_put_16 (abfd, upper, insn); - bfd_put_16 (abfd, lower, insn + 2); -} - -/* Thumb code calling an ARM function. */ - -static int -elf32_thumb_to_arm_stub (struct bfd_link_info * info, - const char * name, - bfd * input_bfd, - bfd * output_bfd, - asection * input_section, - bfd_byte * hit_data, - asection * sym_sec, - bfd_vma offset, - bfd_signed_vma addend, - bfd_vma val, - char **error_message) -{ - asection * s = 0; - bfd_vma my_offset; - long int ret_offset; - struct elf_link_hash_entry * myh; - struct elf32_arm_link_hash_table * globals; - - myh = find_thumb_glue (info, name, error_message); - if (myh == NULL) - return FALSE; - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - my_offset = myh->root.u.def.value; - - s = bfd_get_linker_section (globals->bfd_of_glue_owner, - THUMB2ARM_GLUE_SECTION_NAME); - - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->contents != NULL); - BFD_ASSERT (s->output_section != NULL); - - if ((my_offset & 0x01) == 0x01) - { - if (sym_sec != NULL - && sym_sec->owner != NULL - && !INTERWORK_FLAG (sym_sec->owner)) - { - _bfd_error_handler - (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: Thumb call to ARM"), - sym_sec->owner, name, input_bfd); - - return FALSE; - } - - --my_offset; - myh->root.u.def.value = my_offset; - - put_thumb_insn (globals, output_bfd, (bfd_vma) t2a1_bx_pc_insn, - s->contents + my_offset); - - put_thumb_insn (globals, output_bfd, (bfd_vma) t2a2_noop_insn, - s->contents + my_offset + 2); - - ret_offset = - /* Address of destination of the stub. */ - ((bfd_signed_vma) val) - - ((bfd_signed_vma) - /* Offset from the start of the current section - to the start of the stubs. */ - (s->output_offset - /* Offset of the start of this stub from the start of the stubs. */ - + my_offset - /* Address of the start of the current section. */ - + s->output_section->vma) - /* The branch instruction is 4 bytes into the stub. */ - + 4 - /* ARM branches work from the pc of the instruction + 8. */ - + 8); - - put_arm_insn (globals, output_bfd, - (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF), - s->contents + my_offset + 4); - } - - BFD_ASSERT (my_offset <= globals->thumb_glue_size); - - /* Now go back and fix up the original BL insn to point to here. */ - ret_offset = - /* Address of where the stub is located. */ - (s->output_section->vma + s->output_offset + my_offset) - /* Address of where the BL is located. */ - - (input_section->output_section->vma + input_section->output_offset - + offset) - /* Addend in the relocation. */ - - addend - /* Biassing for PC-relative addressing. */ - - 8; - - insert_thumb_branch (input_bfd, ret_offset, hit_data - input_section->vma); - - return TRUE; -} - -/* Populate an Arm to Thumb stub. Returns the stub symbol. */ - -static struct elf_link_hash_entry * -elf32_arm_create_thumb_stub (struct bfd_link_info * info, - const char * name, - bfd * input_bfd, - bfd * output_bfd, - asection * sym_sec, - bfd_vma val, - asection * s, - char ** error_message) -{ - bfd_vma my_offset; - long int ret_offset; - struct elf_link_hash_entry * myh; - struct elf32_arm_link_hash_table * globals; - - myh = find_arm_glue (info, name, error_message); - if (myh == NULL) - return NULL; - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - my_offset = myh->root.u.def.value; - - if ((my_offset & 0x01) == 0x01) - { - if (sym_sec != NULL - && sym_sec->owner != NULL - && !INTERWORK_FLAG (sym_sec->owner)) - { - _bfd_error_handler - (_("%B(%s): warning: interworking not enabled.\n" - " first occurrence: %B: arm call to thumb"), - sym_sec->owner, name, input_bfd); - } - - --my_offset; - myh->root.u.def.value = my_offset; - - if (bfd_link_pic (info) - || globals->root.is_relocatable_executable - || globals->pic_veneer) - { - /* For relocatable objects we can't use absolute addresses, - so construct the address from a relative offset. */ - /* TODO: If the offset is small it's probably worth - constructing the address with adds. */ - put_arm_insn (globals, output_bfd, (bfd_vma) a2t1p_ldr_insn, - s->contents + my_offset); - put_arm_insn (globals, output_bfd, (bfd_vma) a2t2p_add_pc_insn, - s->contents + my_offset + 4); - put_arm_insn (globals, output_bfd, (bfd_vma) a2t3p_bx_r12_insn, - s->contents + my_offset + 8); - /* Adjust the offset by 4 for the position of the add, - and 8 for the pipeline offset. */ - ret_offset = (val - (s->output_offset - + s->output_section->vma - + my_offset + 12)) - | 1; - bfd_put_32 (output_bfd, ret_offset, - s->contents + my_offset + 12); - } - else if (globals->use_blx) - { - put_arm_insn (globals, output_bfd, (bfd_vma) a2t1v5_ldr_insn, - s->contents + my_offset); - - /* It's a thumb address. Add the low order bit. */ - bfd_put_32 (output_bfd, val | a2t2v5_func_addr_insn, - s->contents + my_offset + 4); - } - else - { - put_arm_insn (globals, output_bfd, (bfd_vma) a2t1_ldr_insn, - s->contents + my_offset); - - put_arm_insn (globals, output_bfd, (bfd_vma) a2t2_bx_r12_insn, - s->contents + my_offset + 4); - - /* It's a thumb address. Add the low order bit. */ - bfd_put_32 (output_bfd, val | a2t3_func_addr_insn, - s->contents + my_offset + 8); - - my_offset += 12; - } - } - - BFD_ASSERT (my_offset <= globals->arm_glue_size); - - return myh; -} - -/* Arm code calling a Thumb function. */ - -static int -elf32_arm_to_thumb_stub (struct bfd_link_info * info, - const char * name, - bfd * input_bfd, - bfd * output_bfd, - asection * input_section, - bfd_byte * hit_data, - asection * sym_sec, - bfd_vma offset, - bfd_signed_vma addend, - bfd_vma val, - char **error_message) -{ - unsigned long int tmp; - bfd_vma my_offset; - asection * s; - long int ret_offset; - struct elf_link_hash_entry * myh; - struct elf32_arm_link_hash_table * globals; - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_linker_section (globals->bfd_of_glue_owner, - ARM2THUMB_GLUE_SECTION_NAME); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->contents != NULL); - BFD_ASSERT (s->output_section != NULL); - - myh = elf32_arm_create_thumb_stub (info, name, input_bfd, output_bfd, - sym_sec, val, s, error_message); - if (!myh) - return FALSE; - - my_offset = myh->root.u.def.value; - tmp = bfd_get_32 (input_bfd, hit_data); - tmp = tmp & 0xFF000000; - - /* Somehow these are both 4 too far, so subtract 8. */ - ret_offset = (s->output_offset - + my_offset - + s->output_section->vma - - (input_section->output_offset - + input_section->output_section->vma - + offset + addend) - - 8); - - tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF); - - bfd_put_32 (output_bfd, (bfd_vma) tmp, hit_data - input_section->vma); - - return TRUE; -} - -/* Populate Arm stub for an exported Thumb function. */ - -static bfd_boolean -elf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info * info = (struct bfd_link_info *) inf; - asection * s; - struct elf_link_hash_entry * myh; - struct elf32_arm_link_hash_entry *eh; - struct elf32_arm_link_hash_table * globals; - asection *sec; - bfd_vma val; - char *error_message; - - eh = elf32_arm_hash_entry (h); - /* Allocate stubs for exported Thumb functions on v4t. */ - if (eh->export_glue == NULL) - return TRUE; - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_linker_section (globals->bfd_of_glue_owner, - ARM2THUMB_GLUE_SECTION_NAME); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->contents != NULL); - BFD_ASSERT (s->output_section != NULL); - - sec = eh->export_glue->root.u.def.section; - - BFD_ASSERT (sec->output_section != NULL); - - val = eh->export_glue->root.u.def.value + sec->output_offset - + sec->output_section->vma; - - myh = elf32_arm_create_thumb_stub (info, h->root.root.string, - h->root.u.def.section->owner, - globals->obfd, sec, val, s, - &error_message); - BFD_ASSERT (myh); - return TRUE; -} - -/* Populate ARMv4 BX veneers. Returns the absolute adress of the veneer. */ - -static bfd_vma -elf32_arm_bx_glue (struct bfd_link_info * info, int reg) -{ - bfd_byte *p; - bfd_vma glue_addr; - asection *s; - struct elf32_arm_link_hash_table *globals; - - globals = elf32_arm_hash_table (info); - BFD_ASSERT (globals != NULL); - BFD_ASSERT (globals->bfd_of_glue_owner != NULL); - - s = bfd_get_linker_section (globals->bfd_of_glue_owner, - ARM_BX_GLUE_SECTION_NAME); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->contents != NULL); - BFD_ASSERT (s->output_section != NULL); - - BFD_ASSERT (globals->bx_glue_offset[reg] & 2); - - glue_addr = globals->bx_glue_offset[reg] & ~(bfd_vma)3; - - if ((globals->bx_glue_offset[reg] & 1) == 0) - { - p = s->contents + glue_addr; - bfd_put_32 (globals->obfd, armbx1_tst_insn + (reg << 16), p); - bfd_put_32 (globals->obfd, armbx2_moveq_insn + reg, p + 4); - bfd_put_32 (globals->obfd, armbx3_bx_insn + reg, p + 8); - globals->bx_glue_offset[reg] |= 1; - } - - return glue_addr + s->output_section->vma + s->output_offset; -} - -/* Generate Arm stubs for exported Thumb symbols. */ -static void -elf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *link_info) -{ - struct elf32_arm_link_hash_table * globals; - - if (link_info == NULL) - /* Ignore this if we are not called by the ELF backend linker. */ - return; - - globals = elf32_arm_hash_table (link_info); - if (globals == NULL) - return; - - /* If blx is available then exported Thumb symbols are OK and there is - nothing to do. */ - if (globals->use_blx) - return; - - elf_link_hash_traverse (&globals->root, elf32_arm_to_thumb_export_stub, - link_info); -} - -/* Reserve space for COUNT dynamic relocations in relocation selection - SRELOC. */ - -static void -elf32_arm_allocate_dynrelocs (struct bfd_link_info *info, asection *sreloc, - bfd_size_type count) -{ - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - BFD_ASSERT (htab->root.dynamic_sections_created); - if (sreloc == NULL) - abort (); - sreloc->size += RELOC_SIZE (htab) * count; -} - -/* Reserve space for COUNT R_ARM_IRELATIVE relocations. If the link is - dynamic, the relocations should go in SRELOC, otherwise they should - go in the special .rel.iplt section. */ - -static void -elf32_arm_allocate_irelocs (struct bfd_link_info *info, asection *sreloc, - bfd_size_type count) -{ - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (!htab->root.dynamic_sections_created) - htab->root.irelplt->size += RELOC_SIZE (htab) * count; - else - { - BFD_ASSERT (sreloc != NULL); - sreloc->size += RELOC_SIZE (htab) * count; - } -} - -/* Add relocation REL to the end of relocation section SRELOC. */ - -static void -elf32_arm_add_dynreloc (bfd *output_bfd, struct bfd_link_info *info, - asection *sreloc, Elf_Internal_Rela *rel) -{ - bfd_byte *loc; - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (!htab->root.dynamic_sections_created - && ELF32_R_TYPE (rel->r_info) == R_ARM_IRELATIVE) - sreloc = htab->root.irelplt; - if (sreloc == NULL) - abort (); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * RELOC_SIZE (htab); - if (sreloc->reloc_count * RELOC_SIZE (htab) > sreloc->size) - abort (); - SWAP_RELOC_OUT (htab) (output_bfd, rel, loc); -} - -/* Allocate room for a PLT entry described by ROOT_PLT and ARM_PLT. - IS_IPLT_ENTRY says whether the entry belongs to .iplt rather than - to .plt. */ - -static void -elf32_arm_allocate_plt_entry (struct bfd_link_info *info, - bfd_boolean is_iplt_entry, - union gotplt_union *root_plt, - struct arm_plt_info *arm_plt) -{ - struct elf32_arm_link_hash_table *htab; - asection *splt; - asection *sgotplt; - - htab = elf32_arm_hash_table (info); - - if (is_iplt_entry) - { - splt = htab->root.iplt; - sgotplt = htab->root.igotplt; - - /* NaCl uses a special first entry in .iplt too. */ - if (htab->nacl_p && splt->size == 0) - splt->size += htab->plt_header_size; - - /* Allocate room for an R_ARM_IRELATIVE relocation in .rel.iplt. */ - elf32_arm_allocate_irelocs (info, htab->root.irelplt, 1); - } - else - { - splt = htab->root.splt; - sgotplt = htab->root.sgotplt; - - /* Allocate room for an R_JUMP_SLOT relocation in .rel.plt. */ - elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (splt->size == 0) - splt->size += htab->plt_header_size; - - htab->next_tls_desc_index++; - } - - /* Allocate the PLT entry itself, including any leading Thumb stub. */ - if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt)) - splt->size += PLT_THUMB_STUB_SIZE; - root_plt->offset = splt->size; - splt->size += htab->plt_entry_size; - - if (!htab->symbian_p) - { - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - if (is_iplt_entry) - arm_plt->got_offset = sgotplt->size; - else - arm_plt->got_offset = sgotplt->size - 8 * htab->num_tls_desc; - sgotplt->size += 4; - } -} - -static bfd_vma -arm_movw_immediate (bfd_vma value) -{ - return (value & 0x00000fff) | ((value & 0x0000f000) << 4); -} - -static bfd_vma -arm_movt_immediate (bfd_vma value) -{ - return ((value & 0x0fff0000) >> 16) | ((value & 0xf0000000) >> 12); -} - -/* Fill in a PLT entry and its associated GOT slot. If DYNINDX == -1, - the entry lives in .iplt and resolves to (*SYM_VALUE)(). - Otherwise, DYNINDX is the index of the symbol in the dynamic - symbol table and SYM_VALUE is undefined. - - ROOT_PLT points to the offset of the PLT entry from the start of its - section (.iplt or .plt). ARM_PLT points to the symbol's ARM-specific - bookkeeping information. - - Returns FALSE if there was a problem. */ - -static bfd_boolean -elf32_arm_populate_plt_entry (bfd *output_bfd, struct bfd_link_info *info, - union gotplt_union *root_plt, - struct arm_plt_info *arm_plt, - int dynindx, bfd_vma sym_value) -{ - struct elf32_arm_link_hash_table *htab; - asection *sgot; - asection *splt; - asection *srel; - bfd_byte *loc; - bfd_vma plt_index; - Elf_Internal_Rela rel; - bfd_vma plt_header_size; - bfd_vma got_header_size; - - htab = elf32_arm_hash_table (info); - - /* Pick the appropriate sections and sizes. */ - if (dynindx == -1) - { - splt = htab->root.iplt; - sgot = htab->root.igotplt; - srel = htab->root.irelplt; - - /* There are no reserved entries in .igot.plt, and no special - first entry in .iplt. */ - got_header_size = 0; - plt_header_size = 0; - } - else - { - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srel = htab->root.srelplt; - - got_header_size = get_elf_backend_data (output_bfd)->got_header_size; - plt_header_size = htab->plt_header_size; - } - BFD_ASSERT (splt != NULL && srel != NULL); - - /* Fill in the entry in the procedure linkage table. */ - if (htab->symbian_p) - { - BFD_ASSERT (dynindx >= 0); - put_arm_insn (htab, output_bfd, - elf32_arm_symbian_plt_entry[0], - splt->contents + root_plt->offset); - bfd_put_32 (output_bfd, - elf32_arm_symbian_plt_entry[1], - splt->contents + root_plt->offset + 4); - - /* Fill in the entry in the .rel.plt section. */ - rel.r_offset = (splt->output_section->vma - + splt->output_offset - + root_plt->offset + 4); - rel.r_info = ELF32_R_INFO (dynindx, R_ARM_GLOB_DAT); - - /* 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 = ((root_plt->offset - plt_header_size) - / htab->plt_entry_size); - } - else - { - bfd_vma got_offset, got_address, plt_address; - bfd_vma got_displacement, initial_got_entry; - bfd_byte * ptr; - - BFD_ASSERT (sgot != NULL); - - /* Get the offset into the .(i)got.plt table of the entry that - corresponds to this function. */ - got_offset = (arm_plt->got_offset & -2); - - /* 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. - After the reserved .got.plt entries, all symbols appear in - the same order as in .plt. */ - plt_index = (got_offset - got_header_size) / 4; - - /* Calculate the address of the GOT entry. */ - got_address = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - - /* ...and the address of the PLT entry. */ - plt_address = (splt->output_section->vma - + splt->output_offset - + root_plt->offset); - - ptr = splt->contents + root_plt->offset; - if (htab->vxworks_p && bfd_link_pic (info)) - { - unsigned int i; - bfd_vma val; - - for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) - { - val = elf32_arm_vxworks_shared_plt_entry[i]; - if (i == 2) - val |= got_address - sgot->output_section->vma; - if (i == 5) - val |= plt_index * RELOC_SIZE (htab); - if (i == 2 || i == 5) - bfd_put_32 (output_bfd, val, ptr); - else - put_arm_insn (htab, output_bfd, val, ptr); - } - } - else if (htab->vxworks_p) - { - unsigned int i; - bfd_vma val; - - for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4) - { - val = elf32_arm_vxworks_exec_plt_entry[i]; - if (i == 2) - val |= got_address; - if (i == 4) - val |= 0xffffff & -((root_plt->offset + i * 4 + 8) >> 2); - if (i == 5) - val |= plt_index * RELOC_SIZE (htab); - if (i == 2 || i == 5) - bfd_put_32 (output_bfd, val, ptr); - else - put_arm_insn (htab, output_bfd, val, ptr); - } - - loc = (htab->srelplt2->contents - + (plt_index * 2 + 1) * RELOC_SIZE (htab)); - - /* Create the .rela.plt.unloaded R_ARM_ABS32 relocation - referencing the GOT for this PLT entry. */ - rel.r_offset = plt_address + 8; - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32); - rel.r_addend = got_offset; - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); - loc += RELOC_SIZE (htab); - - /* Create the R_ARM_ABS32 relocation referencing the - beginning of the PLT for this GOT entry. */ - rel.r_offset = got_address; - rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32); - rel.r_addend = 0; - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); - } - else if (htab->nacl_p) - { - /* Calculate the displacement between the PLT slot and the - common tail that's part of the special initial PLT slot. */ - int32_t tail_displacement - = ((splt->output_section->vma + splt->output_offset - + ARM_NACL_PLT_TAIL_OFFSET) - - (plt_address + htab->plt_entry_size + 4)); - BFD_ASSERT ((tail_displacement & 3) == 0); - tail_displacement >>= 2; - - BFD_ASSERT ((tail_displacement & 0xff000000) == 0 - || (-tail_displacement & 0xff000000) == 0); - - /* Calculate the displacement between the PLT slot and the entry - in the GOT. The offset accounts for the value produced by - adding to pc in the penultimate instruction of the PLT stub. */ - got_displacement = (got_address - - (plt_address + htab->plt_entry_size)); - - /* NaCl does not support interworking at all. */ - BFD_ASSERT (!elf32_arm_plt_needs_thumb_stub_p (info, arm_plt)); - - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt_entry[0] - | arm_movw_immediate (got_displacement), - ptr + 0); - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt_entry[1] - | arm_movt_immediate (got_displacement), - ptr + 4); - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt_entry[2], - ptr + 8); - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt_entry[3] - | (tail_displacement & 0x00ffffff), - ptr + 12); - } - else if (using_thumb_only (htab)) - { - /* PR ld/16017: Generate thumb only PLT entries. */ - if (!using_thumb2 (htab)) - { - /* FIXME: We ought to be able to generate thumb-1 PLT - instructions... */ - _bfd_error_handler (_("%B: Warning: thumb-1 mode PLT generation not currently supported"), - output_bfd); - return FALSE; - } - - /* Calculate the displacement between the PLT slot and the entry in - the GOT. The 12-byte offset accounts for the value produced by - adding to pc in the 3rd instruction of the PLT stub. */ - got_displacement = got_address - (plt_address + 12); - - /* As we are using 32 bit instructions we have to use 'put_arm_insn' - instead of 'put_thumb_insn'. */ - put_arm_insn (htab, output_bfd, - elf32_thumb2_plt_entry[0] - | ((got_displacement & 0x000000ff) << 16) - | ((got_displacement & 0x00000700) << 20) - | ((got_displacement & 0x00000800) >> 1) - | ((got_displacement & 0x0000f000) >> 12), - ptr + 0); - put_arm_insn (htab, output_bfd, - elf32_thumb2_plt_entry[1] - | ((got_displacement & 0x00ff0000) ) - | ((got_displacement & 0x07000000) << 4) - | ((got_displacement & 0x08000000) >> 17) - | ((got_displacement & 0xf0000000) >> 28), - ptr + 4); - put_arm_insn (htab, output_bfd, - elf32_thumb2_plt_entry[2], - ptr + 8); - put_arm_insn (htab, output_bfd, - elf32_thumb2_plt_entry[3], - ptr + 12); - } - else - { - /* Calculate the displacement between the PLT slot and the - entry in the GOT. The eight-byte offset accounts for the - value produced by adding to pc in the first instruction - of the PLT stub. */ - got_displacement = got_address - (plt_address + 8); - - if (elf32_arm_plt_needs_thumb_stub_p (info, arm_plt)) - { - put_thumb_insn (htab, output_bfd, - elf32_arm_plt_thumb_stub[0], ptr - 4); - put_thumb_insn (htab, output_bfd, - elf32_arm_plt_thumb_stub[1], ptr - 2); - } - - if (!elf32_arm_use_long_plt_entry) - { - BFD_ASSERT ((got_displacement & 0xf0000000) == 0); - - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_short[0] - | ((got_displacement & 0x0ff00000) >> 20), - ptr + 0); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_short[1] - | ((got_displacement & 0x000ff000) >> 12), - ptr+ 4); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_short[2] - | (got_displacement & 0x00000fff), - ptr + 8); -#ifdef FOUR_WORD_PLT - bfd_put_32 (output_bfd, elf32_arm_plt_entry_short[3], ptr + 12); -#endif - } - else - { - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_long[0] - | ((got_displacement & 0xf0000000) >> 28), - ptr + 0); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_long[1] - | ((got_displacement & 0x0ff00000) >> 20), - ptr + 4); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_long[2] - | ((got_displacement & 0x000ff000) >> 12), - ptr+ 8); - put_arm_insn (htab, output_bfd, - elf32_arm_plt_entry_long[3] - | (got_displacement & 0x00000fff), - ptr + 12); - } - } - - /* Fill in the entry in the .rel(a).(i)plt section. */ - rel.r_offset = got_address; - rel.r_addend = 0; - if (dynindx == -1) - { - /* .igot.plt entries use IRELATIVE relocations against SYM_VALUE. - The dynamic linker or static executable then calls SYM_VALUE - to determine the correct run-time value of the .igot.plt entry. */ - rel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE); - initial_got_entry = sym_value; - } - else - { - rel.r_info = ELF32_R_INFO (dynindx, R_ARM_JUMP_SLOT); - initial_got_entry = (splt->output_section->vma - + splt->output_offset); - } - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, initial_got_entry, - sgot->contents + got_offset); - } - - if (dynindx == -1) - elf32_arm_add_dynreloc (output_bfd, info, srel, &rel); - else - { - loc = srel->contents + plt_index * RELOC_SIZE (htab); - SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc); - } - - return TRUE; -} - -/* Some relocations map to different relocations depending on the - target. Return the real relocation. */ - -static int -arm_real_reloc_type (struct elf32_arm_link_hash_table * globals, - int r_type) -{ - switch (r_type) - { - case R_ARM_TARGET1: - if (globals->target1_is_rel) - return R_ARM_REL32; - else - return R_ARM_ABS32; - - case R_ARM_TARGET2: - return globals->target2_reloc; - - default: - return r_type; - } -} - -/* 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); - bfd_vma base; - - /* If tls_sec is NULL, we should have signalled an error already. */ - if (htab->tls_sec == NULL) - return 0; - base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power); - return address - htab->tls_sec->vma + base; -} - -/* Perform an R_ARM_ABS12 relocation on the field pointed to by DATA. - VALUE is the relocation value. */ - -static bfd_reloc_status_type -elf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value) -{ - if (value > 0xfff) - return bfd_reloc_overflow; - - value |= bfd_get_32 (abfd, data) & 0xfffff000; - bfd_put_32 (abfd, value, data); - return bfd_reloc_ok; -} - -/* Handle TLS relaxations. Relaxing is possible for symbols that use - R_ARM_GOTDESC, R_ARM_{,THM_}TLS_CALL or - R_ARM_{,THM_}TLS_DESCSEQ relocations, during a static link. - - Return bfd_reloc_ok if we're done, bfd_reloc_continue if the caller - is to then call final_link_relocate. Return other values in the - case of error. - - FIXME:When --emit-relocs is in effect, we'll emit relocs describing - the pre-relaxed code. It would be nice if the relocs were updated - to match the optimization. */ - -static bfd_reloc_status_type -elf32_arm_tls_relax (struct elf32_arm_link_hash_table *globals, - bfd *input_bfd, asection *input_sec, bfd_byte *contents, - Elf_Internal_Rela *rel, unsigned long is_local) -{ - unsigned long insn; - - switch (ELF32_R_TYPE (rel->r_info)) - { - default: - return bfd_reloc_notsupported; - - case R_ARM_TLS_GOTDESC: - if (is_local) - insn = 0; - else - { - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if (insn & 1) - insn -= 5; /* THUMB */ - else - insn -= 8; /* ARM */ - } - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - return bfd_reloc_continue; - - case R_ARM_THM_TLS_DESCSEQ: - /* Thumb insn. */ - insn = bfd_get_16 (input_bfd, contents + rel->r_offset); - if ((insn & 0xff78) == 0x4478) /* add rx, pc */ - { - if (is_local) - /* nop */ - bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset); - } - else if ((insn & 0xffc0) == 0x6840) /* ldr rx,[ry,#4] */ - { - if (is_local) - /* nop */ - bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset); - else - /* ldr rx,[ry] */ - bfd_put_16 (input_bfd, insn & 0xf83f, contents + rel->r_offset); - } - else if ((insn & 0xff87) == 0x4780) /* blx rx */ - { - if (is_local) - /* nop */ - bfd_put_16 (input_bfd, 0x46c0, contents + rel->r_offset); - else - /* mov r0, rx */ - bfd_put_16 (input_bfd, 0x4600 | (insn & 0x78), - contents + rel->r_offset); - } - else - { - if ((insn & 0xf000) == 0xf000 || (insn & 0xf800) == 0xe800) - /* It's a 32 bit instruction, fetch the rest of it for - error generation. */ - insn = (insn << 16) - | bfd_get_16 (input_bfd, contents + rel->r_offset + 2); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unexpected Thumb instruction '%#lx' in TLS trampoline"), - input_bfd, input_sec, rel->r_offset, insn); - return bfd_reloc_notsupported; - } - break; - - case R_ARM_TLS_DESCSEQ: - /* arm insn. */ - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if ((insn & 0xffff0ff0) == 0xe08f0000) /* add rx,pc,ry */ - { - if (is_local) - /* mov rx, ry */ - bfd_put_32 (input_bfd, 0xe1a00000 | (insn & 0xffff), - contents + rel->r_offset); - } - else if ((insn & 0xfff00fff) == 0xe5900004) /* ldr rx,[ry,#4]*/ - { - if (is_local) - /* nop */ - bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset); - else - /* ldr rx,[ry] */ - bfd_put_32 (input_bfd, insn & 0xfffff000, - contents + rel->r_offset); - } - else if ((insn & 0xfffffff0) == 0xe12fff30) /* blx rx */ - { - if (is_local) - /* nop */ - bfd_put_32 (input_bfd, 0xe1a00000, contents + rel->r_offset); - else - /* mov r0, rx */ - bfd_put_32 (input_bfd, 0xe1a00000 | (insn & 0xf), - contents + rel->r_offset); - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unexpected ARM instruction '%#lx' in TLS trampoline"), - input_bfd, input_sec, rel->r_offset, insn); - return bfd_reloc_notsupported; - } - break; - - case R_ARM_TLS_CALL: - /* GD->IE relaxation, turn the instruction into 'nop' or - 'ldr r0, [pc,r0]' */ - insn = is_local ? 0xe1a00000 : 0xe79f0000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - break; - - case R_ARM_THM_TLS_CALL: - /* GD->IE relaxation. */ - if (!is_local) - /* add r0,pc; ldr r0, [r0] */ - insn = 0x44786800; - else if (using_thumb2 (globals)) - /* nop.w */ - insn = 0xf3af8000; - else - /* nop; nop */ - insn = 0xbf00bf00; - - bfd_put_16 (input_bfd, insn >> 16, contents + rel->r_offset); - bfd_put_16 (input_bfd, insn & 0xffff, contents + rel->r_offset + 2); - break; - } - return bfd_reloc_ok; -} - -/* For a given value of n, calculate the value of G_n as required to - deal with group relocations. We return it in the form of an - encoded constant-and-rotation, together with the final residual. If n is - specified as less than zero, then final_residual is filled with the - input value and no further action is performed. */ - -static bfd_vma -calculate_group_reloc_mask (bfd_vma value, int n, bfd_vma *final_residual) -{ - int current_n; - bfd_vma g_n; - bfd_vma encoded_g_n = 0; - bfd_vma residual = value; /* Also known as Y_n. */ - - for (current_n = 0; current_n <= n; current_n++) - { - int shift; - - /* Calculate which part of the value to mask. */ - if (residual == 0) - shift = 0; - else - { - int msb; - - /* Determine the most significant bit in the residual and - align the resulting value to a 2-bit boundary. */ - for (msb = 30; msb >= 0; msb -= 2) - if (residual & (3 << msb)) - break; - - /* The desired shift is now (msb - 6), or zero, whichever - is the greater. */ - shift = msb - 6; - if (shift < 0) - shift = 0; - } - - /* Calculate g_n in 32-bit as well as encoded constant+rotation form. */ - g_n = residual & (0xff << shift); - encoded_g_n = (g_n >> shift) - | ((g_n <= 0xff ? 0 : (32 - shift) / 2) << 8); - - /* Calculate the residual for the next time around. */ - residual &= ~g_n; - } - - *final_residual = residual; - - return encoded_g_n; -} - -/* Given an ARM instruction, determine whether it is an ADD or a SUB. - Returns 1 if it is an ADD, -1 if it is a SUB, and 0 otherwise. */ - -static int -identify_add_or_sub (bfd_vma insn) -{ - int opcode = insn & 0x1e00000; - - if (opcode == 1 << 23) /* ADD */ - return 1; - - if (opcode == 1 << 22) /* SUB */ - return -1; - - return 0; -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -elf32_arm_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - bfd * output_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma value, - struct bfd_link_info * info, - asection * sym_sec, - const char * sym_name, - unsigned char st_type, - enum arm_st_branch_type branch_type, - struct elf_link_hash_entry * h, - bfd_boolean * unresolved_reloc_p, - char ** error_message) -{ - unsigned long r_type = howto->type; - unsigned long r_symndx; - bfd_byte * hit_data = contents + rel->r_offset; - bfd_vma * local_got_offsets; - bfd_vma * local_tlsdesc_gotents; - asection * sgot; - asection * splt; - asection * sreloc = NULL; - asection * srelgot; - bfd_vma addend; - bfd_signed_vma signed_addend; - unsigned char dynreloc_st_type; - bfd_vma dynreloc_value; - struct elf32_arm_link_hash_table * globals; - struct elf32_arm_link_hash_entry *eh; - union gotplt_union *root_plt; - struct arm_plt_info *arm_plt; - bfd_vma plt_offset; - bfd_vma gotplt_offset; - bfd_boolean has_iplt_entry; - bfd_boolean resolved_to_zero; - - globals = elf32_arm_hash_table (info); - if (globals == NULL) - return bfd_reloc_notsupported; - - BFD_ASSERT (is_arm_elf (input_bfd)); - BFD_ASSERT (howto != NULL); - - /* Some relocation types map to different relocations depending on the - target. We pick the right one here. */ - r_type = arm_real_reloc_type (globals, r_type); - - /* It is possible to have linker relaxations on some TLS access - models. Update our information here. */ - r_type = elf32_arm_tls_transition (info, r_type, h); - - if (r_type != howto->type) - howto = elf32_arm_howto_from_type (r_type); - - eh = (struct elf32_arm_link_hash_entry *) h; - sgot = globals->root.sgot; - local_got_offsets = elf_local_got_offsets (input_bfd); - local_tlsdesc_gotents = elf32_arm_local_tlsdesc_gotent (input_bfd); - - if (globals->root.dynamic_sections_created) - srelgot = globals->root.srelgot; - else - srelgot = NULL; - - r_symndx = ELF32_R_SYM (rel->r_info); - - if (globals->use_rel) - { - addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask; - - if (addend & ((howto->src_mask + 1) >> 1)) - { - signed_addend = -1; - signed_addend &= ~ howto->src_mask; - signed_addend |= addend; - } - else - signed_addend = addend; - } - else - addend = signed_addend = rel->r_addend; - - /* ST_BRANCH_TO_ARM is nonsense to thumb-only targets when we - are resolving a function call relocation. */ - if (using_thumb_only (globals) - && (r_type == R_ARM_THM_CALL - || r_type == R_ARM_THM_JUMP24) - && branch_type == ST_BRANCH_TO_ARM) - branch_type = ST_BRANCH_TO_THUMB; - - /* Record the symbol information that should be used in dynamic - relocations. */ - dynreloc_st_type = st_type; - dynreloc_value = value; - if (branch_type == ST_BRANCH_TO_THUMB) - dynreloc_value |= 1; - - /* Find out whether the symbol has a PLT. Set ST_VALUE, BRANCH_TYPE and - VALUE appropriately for relocations that we resolve at link time. */ - has_iplt_entry = FALSE; - if (elf32_arm_get_plt_info (input_bfd, globals, eh, r_symndx, &root_plt, - &arm_plt) - && root_plt->offset != (bfd_vma) -1) - { - plt_offset = root_plt->offset; - gotplt_offset = arm_plt->got_offset; - - if (h == NULL || eh->is_iplt) - { - has_iplt_entry = TRUE; - splt = globals->root.iplt; - - /* Populate .iplt entries here, because not all of them will - be seen by finish_dynamic_symbol. The lower bit is set if - we have already populated the entry. */ - if (plt_offset & 1) - plt_offset--; - else - { - if (elf32_arm_populate_plt_entry (output_bfd, info, root_plt, arm_plt, - -1, dynreloc_value)) - root_plt->offset |= 1; - else - return bfd_reloc_notsupported; - } - - /* Static relocations always resolve to the .iplt entry. */ - st_type = STT_FUNC; - value = (splt->output_section->vma - + splt->output_offset - + plt_offset); - branch_type = ST_BRANCH_TO_ARM; - - /* If there are non-call relocations that resolve to the .iplt - entry, then all dynamic ones must too. */ - if (arm_plt->noncall_refcount != 0) - { - dynreloc_st_type = st_type; - dynreloc_value = value; - } - } - else - /* We populate the .plt entry in finish_dynamic_symbol. */ - splt = globals->root.splt; - } - else - { - splt = NULL; - plt_offset = (bfd_vma) -1; - gotplt_offset = (bfd_vma) -1; - } - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch (r_type) - { - case R_ARM_NONE: - /* We don't need to find a value for this symbol. It's just a - marker. */ - *unresolved_reloc_p = FALSE; - return bfd_reloc_ok; - - case R_ARM_ABS12: - if (!globals->vxworks_p) - return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend); - /* Fall through. */ - - case R_ARM_PC24: - case R_ARM_ABS32: - case R_ARM_ABS32_NOI: - case R_ARM_REL32: - case R_ARM_REL32_NOI: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_XPC25: - case R_ARM_PREL31: - case R_ARM_PLT32: - /* Handle relocations which should use the PLT entry. ABS32/REL32 - will use the symbol's value, which may point to a PLT entry, but we - don't need to handle that here. If we created a PLT entry, all - branches in this object should go to it, except if the PLT is too - far away, in which case a long branch stub should be inserted. */ - if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32 - && r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI - && r_type != R_ARM_CALL - && r_type != R_ARM_JUMP24 - && r_type != R_ARM_PLT32) - && plt_offset != (bfd_vma) -1) - { - /* If we've created a .plt section, and assigned a PLT entry - to this function, it must either be a STT_GNU_IFUNC reference - or not be known to bind locally. In other cases, we should - have cleared the PLT entry by now. */ - BFD_ASSERT (has_iplt_entry || !SYMBOL_CALLS_LOCAL (info, h)); - - value = (splt->output_section->vma - + splt->output_offset - + plt_offset); - *unresolved_reloc_p = FALSE; - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - } - - /* When generating a shared object or relocatable executable, these - relocations are copied into the output file to be resolved at - run time. */ - if ((bfd_link_pic (info) - || globals->root.is_relocatable_executable) - && (input_section->flags & SEC_ALLOC) - && !(globals->vxworks_p - && strcmp (input_section->output_section->name, - ".tls_vars") == 0) - && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI) - || !SYMBOL_CALLS_LOCAL (info, h)) - && !(input_bfd == globals->stub_bfd - && strstr (input_section->name, STUB_SUFFIX)) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && r_type != R_ARM_PC24 - && r_type != R_ARM_CALL - && r_type != R_ARM_JUMP24 - && r_type != R_ARM_PREL31 - && r_type != R_ARM_PLT32) - { - Elf_Internal_Rela outrel; - bfd_boolean skip, relocate; - - if ((r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI) - && !h->def_regular) - { - char *v = _("shared object"); - - if (bfd_link_executable (info)) - v = _("PIE executable"); - - _bfd_error_handler - (_("%B: relocation %s against external or undefined symbol `%s'" - " can not be used when making a %s; recompile with -fPIC"), input_bfd, - elf32_arm_howto_table_1[r_type].name, h->root.root.string, v); - return bfd_reloc_notsupported; - } - - *unresolved_reloc_p = FALSE; - - if (sreloc == NULL && globals->root.dynamic_sections_created) - { - sreloc = _bfd_elf_get_dynamic_reloc_section (input_bfd, input_section, - ! globals->use_rel); - - if (sreloc == NULL) - return bfd_reloc_notsupported; - } - - skip = FALSE; - relocate = FALSE; - - outrel.r_addend = addend; - 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 - && (!bfd_link_pic (info) - || !(bfd_link_pie (info) - || SYMBOLIC_BIND (info, h)) - || !h->def_regular)) - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - else - { - int symbol; - - /* This symbol is local, or marked to become local. */ - BFD_ASSERT (r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI); - if (globals->symbian_p) - { - asection *osec; - - /* On Symbian OS, the data segment and text segement - can be relocated independently. Therefore, we - must indicate the segment to which this - relocation is relative. The BPABI allows us to - use any symbol in the right segment; we just use - the section symbol as it is convenient. (We - cannot use the symbol given by "h" directly as it - will not appear in the dynamic symbol table.) - - Note that the dynamic linker ignores the section - symbol value, so we don't subtract osec->vma - from the emitted reloc addend. */ - if (sym_sec) - osec = sym_sec->output_section; - else - osec = input_section->output_section; - symbol = elf_section_data (osec)->dynindx; - if (symbol == 0) - { - struct elf_link_hash_table *htab = elf_hash_table (info); - - if ((osec->flags & SEC_READONLY) == 0 - && htab->data_index_section != NULL) - osec = htab->data_index_section; - else - osec = htab->text_index_section; - symbol = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (symbol != 0); - } - else - /* On SVR4-ish systems, the dynamic loader cannot - relocate the text and data segments independently, - so the symbol does not matter. */ - symbol = 0; - if (dynreloc_st_type == STT_GNU_IFUNC) - /* We have an STT_GNU_IFUNC symbol that doesn't resolve - to the .iplt entry. Instead, every non-call reference - must use an R_ARM_IRELATIVE relocation to obtain the - correct run-time address. */ - outrel.r_info = ELF32_R_INFO (symbol, R_ARM_IRELATIVE); - else - outrel.r_info = ELF32_R_INFO (symbol, R_ARM_RELATIVE); - if (globals->use_rel) - relocate = TRUE; - else - outrel.r_addend += dynreloc_value; - } - - elf32_arm_add_dynreloc (output_bfd, info, sreloc, &outrel); - - /* 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) - return bfd_reloc_ok; - - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - dynreloc_value, (bfd_vma) 0); - } - else switch (r_type) - { - case R_ARM_ABS12: - return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend); - - case R_ARM_XPC25: /* Arm BLX instruction. */ - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PC24: /* Arm B/BL instruction. */ - case R_ARM_PLT32: - { - struct elf32_arm_stub_hash_entry *stub_entry = NULL; - - if (r_type == R_ARM_XPC25) - { - /* Check for Arm calling Arm function. */ - /* FIXME: Should we translate the instruction into a BL - instruction instead ? */ - if (branch_type != ST_BRANCH_TO_THUMB) - _bfd_error_handler - (_("\%B: Warning: Arm BLX instruction targets Arm function '%s'."), - input_bfd, - h ? h->root.root.string : "(local)"); - } - else if (r_type == R_ARM_PC24) - { - /* Check for Arm calling Thumb function. */ - if (branch_type == ST_BRANCH_TO_THUMB) - { - if (elf32_arm_to_thumb_stub (info, sym_name, input_bfd, - output_bfd, input_section, - hit_data, sym_sec, rel->r_offset, - signed_addend, value, - error_message)) - return bfd_reloc_ok; - else - return bfd_reloc_dangerous; - } - } - - /* Check if a stub has to be inserted because the - destination is too far or we are changing mode. */ - if ( r_type == R_ARM_CALL - || r_type == R_ARM_JUMP24 - || r_type == R_ARM_PLT32) - { - enum elf32_arm_stub_type stub_type = arm_stub_none; - struct elf32_arm_link_hash_entry *hash; - - hash = (struct elf32_arm_link_hash_entry *) h; - stub_type = arm_type_of_stub (info, input_section, rel, - st_type, &branch_type, - hash, value, sym_sec, - input_bfd, sym_name); - - if (stub_type != arm_stub_none) - { - /* The target is out of reach, so redirect the - branch to the local stub for this function. */ - stub_entry = elf32_arm_get_stub_entry (input_section, - sym_sec, h, - rel, globals, - stub_type); - { - if (stub_entry != NULL) - value = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); - - if (plt_offset != (bfd_vma) -1) - *unresolved_reloc_p = FALSE; - } - } - else - { - /* If the call goes through a PLT entry, make sure to - check distance to the right destination address. */ - if (plt_offset != (bfd_vma) -1) - { - value = (splt->output_section->vma - + splt->output_offset - + plt_offset); - *unresolved_reloc_p = FALSE; - /* The PLT entry is in ARM mode, regardless of the - target function. */ - branch_type = ST_BRANCH_TO_ARM; - } - } - } - - /* The ARM ELF ABI says that this reloc is computed as: S - P + A - where: - S is the address of the symbol in the relocation. - P is address of the instruction being relocated. - A is the addend (extracted from the instruction) in bytes. - - S is held in 'value'. - P is the base address of the section containing the - instruction plus the offset of the reloc into that - section, ie: - (input_section->output_section->vma + - input_section->output_offset + - rel->r_offset). - A is the addend, converted into bytes, ie: - (signed_addend * 4) - - Note: None of these operations have knowledge of the pipeline - size of the processor, thus it is up to the assembler to - encode this information into the addend. */ - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= rel->r_offset; - if (globals->use_rel) - value += (signed_addend << howto->size); - else - /* RELA addends do not have to be adjusted by howto->size. */ - value += signed_addend; - - signed_addend = value; - signed_addend >>= howto->rightshift; - - /* A branch to an undefined weak symbol is turned into a jump to - the next instruction unless a PLT entry will be created. - Do the same for local undefined symbols (but not for STN_UNDEF). - The jump to the next instruction is optimized as a NOP depending - on the architecture. */ - if (h ? (h->root.type == bfd_link_hash_undefweak - && plt_offset == (bfd_vma) -1) - : r_symndx != STN_UNDEF && bfd_is_und_section (sym_sec)) - { - value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000); - - if (arch_has_arm_nop (globals)) - value |= 0x0320f000; - else - value |= 0x01a00000; /* Using pre-UAL nop: mov r0, r0. */ - } - else - { - /* Perform a signed range check. */ - if ( signed_addend > ((bfd_signed_vma) (howto->dst_mask >> 1)) - || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1))) - return bfd_reloc_overflow; - - addend = (value & 2); - - value = (signed_addend & howto->dst_mask) - | (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask)); - - if (r_type == R_ARM_CALL) - { - /* Set the H bit in the BLX instruction. */ - if (branch_type == ST_BRANCH_TO_THUMB) - { - if (addend) - value |= (1 << 24); - else - value &= ~(bfd_vma)(1 << 24); - } - - /* Select the correct instruction (BL or BLX). */ - /* Only if we are not handling a BL to a stub. In this - case, mode switching is performed by the stub. */ - if (branch_type == ST_BRANCH_TO_THUMB && !stub_entry) - value |= (1 << 28); - else if (stub_entry || branch_type != ST_BRANCH_UNKNOWN) - { - value &= ~(bfd_vma)(1 << 28); - value |= (1 << 24); - } - } - } - } - break; - - case R_ARM_ABS32: - value += addend; - if (branch_type == ST_BRANCH_TO_THUMB) - value |= 1; - break; - - case R_ARM_ABS32_NOI: - value += addend; - break; - - case R_ARM_REL32: - value += addend; - if (branch_type == ST_BRANCH_TO_THUMB) - value |= 1; - value -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - break; - - case R_ARM_REL32_NOI: - value += addend; - value -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - break; - - case R_ARM_PREL31: - value -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - value += signed_addend; - if (! h || h->root.type != bfd_link_hash_undefweak) - { - /* Check for overflow. */ - if ((value ^ (value >> 1)) & (1 << 30)) - return bfd_reloc_overflow; - } - value &= 0x7fffffff; - value |= (bfd_get_32 (input_bfd, hit_data) & 0x80000000); - if (branch_type == ST_BRANCH_TO_THUMB) - value |= 1; - break; - } - - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_ARM_ABS8: - /* PR 16202: Refectch the addend using the correct size. */ - if (globals->use_rel) - addend = bfd_get_8 (input_bfd, hit_data); - value += addend; - - /* There is no way to tell whether the user intended to use a signed or - unsigned addend. When checking for overflow we accept either, - as specified by the AAELF. */ - if ((long) value > 0xff || (long) value < -0x80) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_ARM_ABS16: - /* PR 16202: Refectch the addend using the correct size. */ - if (globals->use_rel) - addend = bfd_get_16 (input_bfd, hit_data); - value += addend; - - /* See comment for R_ARM_ABS8. */ - if ((long) value > 0xffff || (long) value < -0x8000) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_ARM_THM_ABS5: - /* Support ldr and str instructions for the thumb. */ - if (globals->use_rel) - { - /* Need to refetch addend. */ - addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask; - /* ??? Need to determine shift amount from operand size. */ - addend >>= howto->rightshift; - } - value += addend; - - /* ??? Isn't value unsigned? */ - if ((long) value > 0x1f || (long) value < -0x10) - return bfd_reloc_overflow; - - /* ??? Value needs to be properly shifted into place first. */ - value |= bfd_get_16 (input_bfd, hit_data) & 0xf83f; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_ARM_THM_ALU_PREL_11_0: - /* Corresponds to: addw.w reg, pc, #offset (and similarly for subw). */ - { - bfd_vma insn; - bfd_signed_vma relocation; - - insn = (bfd_get_16 (input_bfd, hit_data) << 16) - | bfd_get_16 (input_bfd, hit_data + 2); - - if (globals->use_rel) - { - signed_addend = (insn & 0xff) | ((insn & 0x7000) >> 4) - | ((insn & (1 << 26)) >> 15); - if (insn & 0xf00000) - signed_addend = -signed_addend; - } - - relocation = value + signed_addend; - relocation -= Pa (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - /* PR 21523: Use an absolute value. The user of this reloc will - have already selected an ADD or SUB insn appropriately. */ - value = labs (relocation); - - if (value >= 0x1000) - return bfd_reloc_overflow; - - /* Destination is Thumb. Force bit 0 to 1 to reflect this. */ - if (branch_type == ST_BRANCH_TO_THUMB) - value |= 1; - - insn = (insn & 0xfb0f8f00) | (value & 0xff) - | ((value & 0x700) << 4) - | ((value & 0x800) << 15); - if (relocation < 0) - insn |= 0xa00000; - - bfd_put_16 (input_bfd, insn >> 16, hit_data); - bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2); - - return bfd_reloc_ok; - } - - case R_ARM_THM_PC8: - /* PR 10073: This reloc is not generated by the GNU toolchain, - but it is supported for compatibility with third party libraries - generated by other compilers, specifically the ARM/IAR. */ - { - bfd_vma insn; - bfd_signed_vma relocation; - - insn = bfd_get_16 (input_bfd, hit_data); - - if (globals->use_rel) - addend = ((((insn & 0x00ff) << 2) + 4) & 0x3ff) -4; - - relocation = value + addend; - relocation -= Pa (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - value = relocation; - - /* We do not check for overflow of this reloc. Although strictly - speaking this is incorrect, it appears to be necessary in order - to work with IAR generated relocs. Since GCC and GAS do not - generate R_ARM_THM_PC8 relocs, the lack of a check should not be - a problem for them. */ - value &= 0x3fc; - - insn = (insn & 0xff00) | (value >> 2); - - bfd_put_16 (input_bfd, insn, hit_data); - - return bfd_reloc_ok; - } - - case R_ARM_THM_PC12: - /* Corresponds to: ldr.w reg, [pc, #offset]. */ - { - bfd_vma insn; - bfd_signed_vma relocation; - - insn = (bfd_get_16 (input_bfd, hit_data) << 16) - | bfd_get_16 (input_bfd, hit_data + 2); - - if (globals->use_rel) - { - signed_addend = insn & 0xfff; - if (!(insn & (1 << 23))) - signed_addend = -signed_addend; - } - - relocation = value + signed_addend; - relocation -= Pa (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - value = relocation; - - if (value >= 0x1000) - return bfd_reloc_overflow; - - insn = (insn & 0xff7ff000) | value; - if (relocation >= 0) - insn |= (1 << 23); - - bfd_put_16 (input_bfd, insn >> 16, hit_data); - bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2); - - return bfd_reloc_ok; - } - - case R_ARM_THM_XPC22: - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - /* Thumb BL (branch long instruction). */ - { - bfd_vma relocation; - bfd_vma reloc_sign; - bfd_boolean overflow = FALSE; - bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); - bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); - bfd_signed_vma reloc_signed_max; - bfd_signed_vma reloc_signed_min; - bfd_vma check; - bfd_signed_vma signed_check; - int bitsize; - const int thumb2 = using_thumb2 (globals); - const int thumb2_bl = using_thumb2_bl (globals); - - /* A branch to an undefined weak symbol is turned into a jump to - the next instruction unless a PLT entry will be created. - The jump to the next instruction is optimized as a NOP.W for - Thumb-2 enabled architectures. */ - if (h && h->root.type == bfd_link_hash_undefweak - && plt_offset == (bfd_vma) -1) - { - if (thumb2) - { - bfd_put_16 (input_bfd, 0xf3af, hit_data); - bfd_put_16 (input_bfd, 0x8000, hit_data + 2); - } - else - { - bfd_put_16 (input_bfd, 0xe000, hit_data); - bfd_put_16 (input_bfd, 0xbf00, hit_data + 2); - } - return bfd_reloc_ok; - } - - /* Fetch the addend. We use the Thumb-2 encoding (backwards compatible - with Thumb-1) involving the J1 and J2 bits. */ - if (globals->use_rel) - { - bfd_vma s = (upper_insn & (1 << 10)) >> 10; - bfd_vma upper = upper_insn & 0x3ff; - bfd_vma lower = lower_insn & 0x7ff; - bfd_vma j1 = (lower_insn & (1 << 13)) >> 13; - bfd_vma j2 = (lower_insn & (1 << 11)) >> 11; - bfd_vma i1 = j1 ^ s ? 0 : 1; - bfd_vma i2 = j2 ^ s ? 0 : 1; - - addend = (i1 << 23) | (i2 << 22) | (upper << 12) | (lower << 1); - /* Sign extend. */ - addend = (addend | ((s ? 0 : 1) << 24)) - (1 << 24); - - signed_addend = addend; - } - - if (r_type == R_ARM_THM_XPC22) - { - /* Check for Thumb to Thumb call. */ - /* FIXME: Should we translate the instruction into a BL - instruction instead ? */ - if (branch_type == ST_BRANCH_TO_THUMB) - _bfd_error_handler - (_("%B: Warning: Thumb BLX instruction targets thumb function '%s'."), - input_bfd, - h ? h->root.root.string : "(local)"); - } - else - { - /* If it is not a call to Thumb, assume call to Arm. - If it is a call relative to a section name, then it is not a - function call at all, but rather a long jump. Calls through - the PLT do not require stubs. */ - if (branch_type == ST_BRANCH_TO_ARM && plt_offset == (bfd_vma) -1) - { - if (globals->use_blx && r_type == R_ARM_THM_CALL) - { - /* Convert BL to BLX. */ - lower_insn = (lower_insn & ~0x1000) | 0x0800; - } - else if (( r_type != R_ARM_THM_CALL) - && (r_type != R_ARM_THM_JUMP24)) - { - if (elf32_thumb_to_arm_stub - (info, sym_name, input_bfd, output_bfd, input_section, - hit_data, sym_sec, rel->r_offset, signed_addend, value, - error_message)) - return bfd_reloc_ok; - else - return bfd_reloc_dangerous; - } - } - else if (branch_type == ST_BRANCH_TO_THUMB - && globals->use_blx - && r_type == R_ARM_THM_CALL) - { - /* Make sure this is a BL. */ - lower_insn |= 0x1800; - } - } - - enum elf32_arm_stub_type stub_type = arm_stub_none; - if (r_type == R_ARM_THM_CALL || r_type == R_ARM_THM_JUMP24) - { - /* Check if a stub has to be inserted because the destination - is too far. */ - struct elf32_arm_stub_hash_entry *stub_entry; - struct elf32_arm_link_hash_entry *hash; - - hash = (struct elf32_arm_link_hash_entry *) h; - - stub_type = arm_type_of_stub (info, input_section, rel, - st_type, &branch_type, - hash, value, sym_sec, - input_bfd, sym_name); - - if (stub_type != arm_stub_none) - { - /* The target is out of reach or we are changing modes, so - redirect the branch to the local stub for this - function. */ - stub_entry = elf32_arm_get_stub_entry (input_section, - sym_sec, h, - rel, globals, - stub_type); - if (stub_entry != NULL) - { - value = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); - - if (plt_offset != (bfd_vma) -1) - *unresolved_reloc_p = FALSE; - } - - /* If this call becomes a call to Arm, force BLX. */ - if (globals->use_blx && (r_type == R_ARM_THM_CALL)) - { - if ((stub_entry - && !arm_stub_is_thumb (stub_entry->stub_type)) - || branch_type != ST_BRANCH_TO_THUMB) - lower_insn = (lower_insn & ~0x1000) | 0x0800; - } - } - } - - /* Handle calls via the PLT. */ - if (stub_type == arm_stub_none && plt_offset != (bfd_vma) -1) - { - value = (splt->output_section->vma - + splt->output_offset - + plt_offset); - - if (globals->use_blx - && r_type == R_ARM_THM_CALL - && ! using_thumb_only (globals)) - { - /* If the Thumb BLX instruction is available, convert - the BL to a BLX instruction to call the ARM-mode - PLT entry. */ - lower_insn = (lower_insn & ~0x1000) | 0x0800; - branch_type = ST_BRANCH_TO_ARM; - } - else - { - if (! using_thumb_only (globals)) - /* Target the Thumb stub before the ARM PLT entry. */ - value -= PLT_THUMB_STUB_SIZE; - branch_type = ST_BRANCH_TO_THUMB; - } - *unresolved_reloc_p = FALSE; - } - - relocation = value + signed_addend; - - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - check = relocation >> howto->rightshift; - - /* If this is a signed value, the rightshift just dropped - leading 1 bits (assuming twos complement). */ - if ((bfd_signed_vma) relocation >= 0) - signed_check = check; - else - signed_check = check | ~((bfd_vma) -1 >> howto->rightshift); - - /* Calculate the permissable maximum and minimum values for - this relocation according to whether we're relocating for - Thumb-2 or not. */ - bitsize = howto->bitsize; - if (!thumb2_bl) - bitsize -= 2; - reloc_signed_max = (1 << (bitsize - 1)) - 1; - reloc_signed_min = ~reloc_signed_max; - - /* Assumes two's complement. */ - if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) - overflow = TRUE; - - if ((lower_insn & 0x5000) == 0x4000) - /* For a BLX instruction, make sure that the relocation is rounded up - to a word boundary. This follows the semantics of the instruction - which specifies that bit 1 of the target address will come from bit - 1 of the base address. */ - relocation = (relocation + 2) & ~ 3; - - /* Put RELOCATION back into the insn. Assumes two's complement. - We use the Thumb-2 encoding, which is safe even if dealing with - a Thumb-1 instruction by virtue of our overflow check above. */ - reloc_sign = (signed_check < 0) ? 1 : 0; - upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) - | ((relocation >> 12) & 0x3ff) - | (reloc_sign << 10); - lower_insn = (lower_insn & ~(bfd_vma) 0x2fff) - | (((!((relocation >> 23) & 1)) ^ reloc_sign) << 13) - | (((!((relocation >> 22) & 1)) ^ reloc_sign) << 11) - | ((relocation >> 1) & 0x7ff); - - /* Put the relocated value back in the object file: */ - bfd_put_16 (input_bfd, upper_insn, hit_data); - bfd_put_16 (input_bfd, lower_insn, hit_data + 2); - - return (overflow ? bfd_reloc_overflow : bfd_reloc_ok); - } - break; - - case R_ARM_THM_JUMP19: - /* Thumb32 conditional branch instruction. */ - { - bfd_vma relocation; - bfd_boolean overflow = FALSE; - bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data); - bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2); - bfd_signed_vma reloc_signed_max = 0xffffe; - bfd_signed_vma reloc_signed_min = -0x100000; - bfd_signed_vma signed_check; - enum elf32_arm_stub_type stub_type = arm_stub_none; - struct elf32_arm_stub_hash_entry *stub_entry; - struct elf32_arm_link_hash_entry *hash; - - /* Need to refetch the addend, reconstruct the top three bits, - and squish the two 11 bit pieces together. */ - if (globals->use_rel) - { - bfd_vma S = (upper_insn & 0x0400) >> 10; - bfd_vma upper = (upper_insn & 0x003f); - bfd_vma J1 = (lower_insn & 0x2000) >> 13; - bfd_vma J2 = (lower_insn & 0x0800) >> 11; - bfd_vma lower = (lower_insn & 0x07ff); - - upper |= J1 << 6; - upper |= J2 << 7; - upper |= (!S) << 8; - upper -= 0x0100; /* Sign extend. */ - - addend = (upper << 12) | (lower << 1); - signed_addend = addend; - } - - /* Handle calls via the PLT. */ - if (plt_offset != (bfd_vma) -1) - { - value = (splt->output_section->vma - + splt->output_offset - + plt_offset); - /* Target the Thumb stub before the ARM PLT entry. */ - value -= PLT_THUMB_STUB_SIZE; - *unresolved_reloc_p = FALSE; - } - - hash = (struct elf32_arm_link_hash_entry *)h; - - stub_type = arm_type_of_stub (info, input_section, rel, - st_type, &branch_type, - hash, value, sym_sec, - input_bfd, sym_name); - if (stub_type != arm_stub_none) - { - stub_entry = elf32_arm_get_stub_entry (input_section, - sym_sec, h, - rel, globals, - stub_type); - if (stub_entry != NULL) - { - value = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); - } - } - - relocation = value + signed_addend; - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - signed_check = (bfd_signed_vma) relocation; - - if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) - overflow = TRUE; - - /* Put RELOCATION back into the insn. */ - { - bfd_vma S = (relocation & 0x00100000) >> 20; - bfd_vma J2 = (relocation & 0x00080000) >> 19; - bfd_vma J1 = (relocation & 0x00040000) >> 18; - bfd_vma hi = (relocation & 0x0003f000) >> 12; - bfd_vma lo = (relocation & 0x00000ffe) >> 1; - - upper_insn = (upper_insn & 0xfbc0) | (S << 10) | hi; - lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo; - } - - /* Put the relocated value back in the object file: */ - bfd_put_16 (input_bfd, upper_insn, hit_data); - bfd_put_16 (input_bfd, lower_insn, hit_data + 2); - - return (overflow ? bfd_reloc_overflow : bfd_reloc_ok); - } - - case R_ARM_THM_JUMP11: - case R_ARM_THM_JUMP8: - case R_ARM_THM_JUMP6: - /* Thumb B (branch) instruction). */ - { - bfd_signed_vma relocation; - bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1; - bfd_signed_vma reloc_signed_min = ~ reloc_signed_max; - bfd_signed_vma signed_check; - - /* CZB cannot jump backward. */ - if (r_type == R_ARM_THM_JUMP6) - reloc_signed_min = 0; - - if (globals->use_rel) - { - /* Need to refetch addend. */ - addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - signed_addend = -1; - signed_addend &= ~ howto->src_mask; - signed_addend |= addend; - } - else - signed_addend = addend; - /* The value in the insn has been right shifted. We need to - undo this, so that we can perform the address calculation - in terms of bytes. */ - signed_addend <<= howto->rightshift; - } - relocation = value + signed_addend; - - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - relocation >>= howto->rightshift; - signed_check = relocation; - - if (r_type == R_ARM_THM_JUMP6) - relocation = ((relocation & 0x0020) << 4) | ((relocation & 0x001f) << 3); - else - relocation &= howto->dst_mask; - relocation |= (bfd_get_16 (input_bfd, hit_data) & (~ howto->dst_mask)); - - bfd_put_16 (input_bfd, relocation, hit_data); - - /* Assumes two's complement. */ - if (signed_check > reloc_signed_max || signed_check < reloc_signed_min) - return bfd_reloc_overflow; - - return bfd_reloc_ok; - } - - case R_ARM_ALU_PCREL7_0: - case R_ARM_ALU_PCREL15_8: - case R_ARM_ALU_PCREL23_15: - { - bfd_vma insn; - bfd_vma relocation; - - insn = bfd_get_32 (input_bfd, hit_data); - if (globals->use_rel) - { - /* Extract the addend. */ - addend = (insn & 0xff) << ((insn & 0xf00) >> 7); - signed_addend = addend; - } - relocation = value + signed_addend; - - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - insn = (insn & ~0xfff) - | ((howto->bitpos << 7) & 0xf00) - | ((relocation >> howto->bitpos) & 0xff); - bfd_put_32 (input_bfd, value, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_GNU_VTINHERIT: - case R_ARM_GNU_VTENTRY: - return bfd_reloc_ok; - - case R_ARM_GOTOFF32: - /* Relocation is relative to the start of the - global offset table. */ - - BFD_ASSERT (sgot != NULL); - if (sgot == NULL) - return bfd_reloc_notsupported; - - /* If we are addressing a Thumb function, we need to adjust the - address by one, so that attempts to call the function pointer will - correctly interpret it as Thumb code. */ - if (branch_type == ST_BRANCH_TO_THUMB) - value += 1; - - /* Note that sgot->output_offset is not involved in this - calculation. We always want the start of .got. If we - define _GLOBAL_OFFSET_TABLE in a different way, as is - permitted by the ABI, we might have to change this - calculation. */ - value -= sgot->output_section->vma; - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - - case R_ARM_GOTPC: - /* Use global offset table as symbol value. */ - BFD_ASSERT (sgot != NULL); - - if (sgot == NULL) - return bfd_reloc_notsupported; - - *unresolved_reloc_p = FALSE; - value = sgot->output_section->vma; - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - - case R_ARM_GOT32: - case R_ARM_GOT_PREL: - /* Relocation is to the entry for this symbol in the - global offset table. */ - if (sgot == NULL) - return bfd_reloc_notsupported; - - if (dynreloc_st_type == STT_GNU_IFUNC - && plt_offset != (bfd_vma) -1 - && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, h))) - { - /* We have a relocation against a locally-binding STT_GNU_IFUNC - symbol, and the relocation resolves directly to the runtime - target rather than to the .iplt entry. This means that any - .got entry would be the same value as the .igot.plt entry, - so there's no point creating both. */ - sgot = globals->root.igotplt; - value = sgot->output_offset + gotplt_offset; - } - else if (h != NULL) - { - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - if ((off & 1) != 0) - { - /* We have already processsed one GOT relocation against - this symbol. */ - off &= ~1; - if (globals->root.dynamic_sections_created - && !SYMBOL_REFERENCES_LOCAL (info, h)) - *unresolved_reloc_p = FALSE; - } - else - { - Elf_Internal_Rela outrel; - - if (h->dynindx != -1 && !SYMBOL_REFERENCES_LOCAL (info, h)) - { - /* If the symbol doesn't resolve locally in a static - object, we have an undefined reference. If the - symbol doesn't resolve locally in a dynamic object, - it should be resolved by the dynamic linker. */ - if (globals->root.dynamic_sections_created) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT); - *unresolved_reloc_p = FALSE; - } - else - outrel.r_info = 0; - outrel.r_addend = 0; - } - else - { - if (dynreloc_st_type == STT_GNU_IFUNC) - outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE); - else if (bfd_link_pic (info) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); - else - outrel.r_info = 0; - outrel.r_addend = dynreloc_value; - } - - /* The GOT entry is initialized to zero by default. - See if we should install a different value. */ - if (outrel.r_addend != 0 - && (outrel.r_info == 0 || globals->use_rel)) - { - bfd_put_32 (output_bfd, outrel.r_addend, - sgot->contents + off); - outrel.r_addend = 0; - } - - if (outrel.r_info != 0) - { - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); - } - h->got.offset |= 1; - } - value = sgot->output_offset + off; - } - else - { - bfd_vma off; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use the - least significant bit to record whether we have already - generated the necessary reloc. */ - if ((off & 1) != 0) - off &= ~1; - else - { - if (globals->use_rel) - bfd_put_32 (output_bfd, dynreloc_value, sgot->contents + off); - - if (bfd_link_pic (info) || dynreloc_st_type == STT_GNU_IFUNC) - { - Elf_Internal_Rela outrel; - - outrel.r_addend = addend + dynreloc_value; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - if (dynreloc_st_type == STT_GNU_IFUNC) - outrel.r_info = ELF32_R_INFO (0, R_ARM_IRELATIVE); - else - outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE); - elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); - } - - local_got_offsets[r_symndx] |= 1; - } - - value = sgot->output_offset + off; - } - if (r_type != R_ARM_GOT32) - value += sgot->output_section->vma; - - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - - case R_ARM_TLS_LDO32: - value = value - dtpoff_base (info); - - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - - case R_ARM_TLS_LDM32: - { - bfd_vma off; - - if (sgot == NULL) - abort (); - - off = globals->tls_ldm_got.offset; - - if ((off & 1) != 0) - off &= ~1; - else - { - /* If we don't know the module number, create a relocation - for it. */ - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - - if (srelgot == NULL) - abort (); - - outrel.r_addend = 0; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset + off); - outrel.r_info = ELF32_R_INFO (0, R_ARM_TLS_DTPMOD32); - - if (globals->use_rel) - bfd_put_32 (output_bfd, outrel.r_addend, - sgot->contents + off); - - elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); - } - else - bfd_put_32 (output_bfd, 1, sgot->contents + off); - - globals->tls_ldm_got.offset |= 1; - } - - value = sgot->output_section->vma + sgot->output_offset + off - - (input_section->output_section->vma + input_section->output_offset + rel->r_offset); - - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - } - - case R_ARM_TLS_CALL: - case R_ARM_THM_TLS_CALL: - case R_ARM_TLS_GD32: - case R_ARM_TLS_IE32: - case R_ARM_TLS_GOTDESC: - case R_ARM_TLS_DESCSEQ: - case R_ARM_THM_TLS_DESCSEQ: - { - bfd_vma off, offplt; - int indx = 0; - char tls_type; - - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - bfd_boolean dyn; - dyn = globals->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - { - *unresolved_reloc_p = FALSE; - indx = h->dynindx; - } - off = h->got.offset; - offplt = elf32_arm_hash_entry (h)->tlsdesc_got; - tls_type = ((struct elf32_arm_link_hash_entry *) h)->tls_type; - } - else - { - BFD_ASSERT (local_got_offsets != NULL); - off = local_got_offsets[r_symndx]; - offplt = local_tlsdesc_gotents[r_symndx]; - tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx]; - } - - /* Linker relaxations happens from one of the - R_ARM_{GOTDESC,CALL,DESCSEQ} relocations to IE or LE. */ - if (ELF32_R_TYPE(rel->r_info) != r_type) - tls_type = GOT_TLS_IE; - - BFD_ASSERT (tls_type != GOT_UNKNOWN); - - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_boolean need_relocs = FALSE; - Elf_Internal_Rela outrel; - int cur_off = off; - - /* The GOT entries have not been initialized yet. Do it - now, and emit any relocations. If both an IE GOT and a - GD GOT are necessary, we emit the GD first. */ - - if ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak)) - { - need_relocs = TRUE; - BFD_ASSERT (srelgot != NULL); - } - - if (tls_type & GOT_TLS_GDESC) - { - bfd_byte *loc; - - /* We should have relaxed, unless this is an undefined - weak symbol. */ - BFD_ASSERT ((h && (h->root.type == bfd_link_hash_undefweak)) - || bfd_link_pic (info)); - BFD_ASSERT (globals->sgotplt_jump_table_size + offplt + 8 - <= globals->root.sgotplt->size); - - outrel.r_addend = 0; - outrel.r_offset = (globals->root.sgotplt->output_section->vma - + globals->root.sgotplt->output_offset - + offplt - + globals->sgotplt_jump_table_size); - - outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DESC); - sreloc = globals->root.srelplt; - loc = sreloc->contents; - loc += globals->next_tls_desc_index++ * RELOC_SIZE (globals); - BFD_ASSERT (loc + RELOC_SIZE (globals) - <= sreloc->contents + sreloc->size); - - SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc); - - /* For globals, the first word in the relocation gets - the relocation index and the top bit set, or zero, - if we're binding now. For locals, it gets the - symbol's offset in the tls section. */ - bfd_put_32 (output_bfd, - !h ? value - elf_hash_table (info)->tls_sec->vma - : info->flags & DF_BIND_NOW ? 0 - : 0x80000000 | ELF32_R_SYM (outrel.r_info), - globals->root.sgotplt->contents + offplt - + globals->sgotplt_jump_table_size); - - /* Second word in the relocation is always zero. */ - bfd_put_32 (output_bfd, 0, - globals->root.sgotplt->contents + offplt - + globals->sgotplt_jump_table_size + 4); - } - if (tls_type & GOT_TLS_GD) - { - if (need_relocs) - { - outrel.r_addend = 0; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + cur_off); - outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DTPMOD32); - - if (globals->use_rel) - bfd_put_32 (output_bfd, outrel.r_addend, - sgot->contents + cur_off); - - elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); - - if (indx == 0) - bfd_put_32 (output_bfd, value - dtpoff_base (info), - sgot->contents + cur_off + 4); - else - { - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (indx, - R_ARM_TLS_DTPOFF32); - outrel.r_offset += 4; - - if (globals->use_rel) - bfd_put_32 (output_bfd, outrel.r_addend, - sgot->contents + cur_off + 4); - - elf32_arm_add_dynreloc (output_bfd, info, - srelgot, &outrel); - } - } - else - { - /* If we are not emitting relocations for a - general dynamic reference, then we must be in a - static link or an executable link with the - symbol binding locally. Mark it as belonging - to module 1, the executable. */ - bfd_put_32 (output_bfd, 1, - sgot->contents + cur_off); - bfd_put_32 (output_bfd, value - dtpoff_base (info), - sgot->contents + cur_off + 4); - } - - cur_off += 8; - } - - if (tls_type & GOT_TLS_IE) - { - if (need_relocs) - { - if (indx == 0) - outrel.r_addend = value - dtpoff_base (info); - else - outrel.r_addend = 0; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + cur_off); - outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_TPOFF32); - - if (globals->use_rel) - bfd_put_32 (output_bfd, outrel.r_addend, - sgot->contents + cur_off); - - elf32_arm_add_dynreloc (output_bfd, info, srelgot, &outrel); - } - else - bfd_put_32 (output_bfd, tpoff (info, value), - sgot->contents + cur_off); - cur_off += 4; - } - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32) - off += 8; - else if (tls_type & GOT_TLS_GDESC) - off = offplt; - - if (ELF32_R_TYPE(rel->r_info) == R_ARM_TLS_CALL - || ELF32_R_TYPE(rel->r_info) == R_ARM_THM_TLS_CALL) - { - bfd_signed_vma offset; - /* TLS stubs are arm mode. The original symbol is a - data object, so branch_type is bogus. */ - branch_type = ST_BRANCH_TO_ARM; - enum elf32_arm_stub_type stub_type - = arm_type_of_stub (info, input_section, rel, - st_type, &branch_type, - (struct elf32_arm_link_hash_entry *)h, - globals->tls_trampoline, globals->root.splt, - input_bfd, sym_name); - - if (stub_type != arm_stub_none) - { - struct elf32_arm_stub_hash_entry *stub_entry - = elf32_arm_get_stub_entry - (input_section, globals->root.splt, 0, rel, - globals, stub_type); - offset = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); - } - else - offset = (globals->root.splt->output_section->vma - + globals->root.splt->output_offset - + globals->tls_trampoline); - - if (ELF32_R_TYPE(rel->r_info) == R_ARM_TLS_CALL) - { - unsigned long inst; - - offset -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset + 8); - - inst = offset >> 2; - inst &= 0x00ffffff; - value = inst | (globals->use_blx ? 0xfa000000 : 0xeb000000); - } - else - { - /* Thumb blx encodes the offset in a complicated - fashion. */ - unsigned upper_insn, lower_insn; - unsigned neg; - - offset -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset + 4); - - if (stub_type != arm_stub_none - && arm_stub_is_thumb (stub_type)) - { - lower_insn = 0xd000; - } - else - { - lower_insn = 0xc000; - /* Round up the offset to a word boundary. */ - offset = (offset + 2) & ~2; - } - - neg = offset < 0; - upper_insn = (0xf000 - | ((offset >> 12) & 0x3ff) - | (neg << 10)); - lower_insn |= (((!((offset >> 23) & 1)) ^ neg) << 13) - | (((!((offset >> 22) & 1)) ^ neg) << 11) - | ((offset >> 1) & 0x7ff); - bfd_put_16 (input_bfd, upper_insn, hit_data); - bfd_put_16 (input_bfd, lower_insn, hit_data + 2); - return bfd_reloc_ok; - } - } - /* These relocations needs special care, as besides the fact - they point somewhere in .gotplt, the addend must be - adjusted accordingly depending on the type of instruction - we refer to. */ - else if ((r_type == R_ARM_TLS_GOTDESC) && (tls_type & GOT_TLS_GDESC)) - { - unsigned long data, insn; - unsigned thumb; - - data = bfd_get_32 (input_bfd, hit_data); - thumb = data & 1; - data &= ~1u; - - if (thumb) - { - insn = bfd_get_16 (input_bfd, contents + rel->r_offset - data); - if ((insn & 0xf000) == 0xf000 || (insn & 0xf800) == 0xe800) - insn = (insn << 16) - | bfd_get_16 (input_bfd, - contents + rel->r_offset - data + 2); - if ((insn & 0xf800c000) == 0xf000c000) - /* bl/blx */ - value = -6; - else if ((insn & 0xffffff00) == 0x4400) - /* add */ - value = -5; - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unexpected Thumb instruction '%#lx' referenced by TLS_GOTDESC"), - input_bfd, input_section, rel->r_offset, insn); - return bfd_reloc_notsupported; - } - } - else - { - insn = bfd_get_32 (input_bfd, contents + rel->r_offset - data); - - switch (insn >> 24) - { - case 0xeb: /* bl */ - case 0xfa: /* blx */ - value = -4; - break; - - case 0xe0: /* add */ - value = -8; - break; - - default: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unexpected ARM instruction '%#lx' referenced by TLS_GOTDESC"), - input_bfd, input_section, rel->r_offset, insn); - return bfd_reloc_notsupported; - } - } - - value += ((globals->root.sgotplt->output_section->vma - + globals->root.sgotplt->output_offset + off) - - (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset) - + globals->sgotplt_jump_table_size); - } - else - value = ((globals->root.sgot->output_section->vma - + globals->root.sgot->output_offset + off) - - (input_section->output_section->vma - + input_section->output_offset + rel->r_offset)); - - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - } - - case R_ARM_TLS_LE32: - if (bfd_link_dll (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation not permitted in shared object"), - input_bfd, input_section, rel->r_offset, howto->name); - return bfd_reloc_notsupported; - } - else - value = tpoff (info, value); - - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, - rel->r_addend); - - case R_ARM_V4BX: - if (globals->fix_v4bx) - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - - /* Ensure that we have a BX instruction. */ - BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10); - - if (globals->fix_v4bx == 2 && (insn & 0xf) != 0xf) - { - /* Branch to veneer. */ - bfd_vma glue_addr; - glue_addr = elf32_arm_bx_glue (info, insn & 0xf); - glue_addr -= input_section->output_section->vma - + input_section->output_offset - + rel->r_offset + 8; - insn = (insn & 0xf0000000) | 0x0a000000 - | ((glue_addr >> 2) & 0x00ffffff); - } - else - { - /* Preserve Rm (lowest four bits) and the condition code - (highest four bits). Other bits encode MOV PC,Rm. */ - insn = (insn & 0xf000000f) | 0x01a0f000; - } - - bfd_put_32 (input_bfd, insn, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - case R_ARM_MOVW_PREL_NC: - case R_ARM_MOVT_PREL: - /* Until we properly support segment-base-relative addressing then - we assume the segment base to be zero, as for the group relocations. - Thus R_ARM_MOVW_BREL_NC has the same semantics as R_ARM_MOVW_ABS_NC - and R_ARM_MOVT_BREL has the same semantics as R_ARM_MOVT_ABS. */ - case R_ARM_MOVW_BREL_NC: - case R_ARM_MOVW_BREL: - case R_ARM_MOVT_BREL: - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - - if (globals->use_rel) - { - addend = ((insn >> 4) & 0xf000) | (insn & 0xfff); - signed_addend = (addend ^ 0x8000) - 0x8000; - } - - value += signed_addend; - - if (r_type == R_ARM_MOVW_PREL_NC || r_type == R_ARM_MOVT_PREL) - value -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - - if (r_type == R_ARM_MOVW_BREL && value >= 0x10000) - return bfd_reloc_overflow; - - if (branch_type == ST_BRANCH_TO_THUMB) - value |= 1; - - if (r_type == R_ARM_MOVT_ABS || r_type == R_ARM_MOVT_PREL - || r_type == R_ARM_MOVT_BREL) - value >>= 16; - - insn &= 0xfff0f000; - insn |= value & 0xfff; - insn |= (value & 0xf000) << 4; - bfd_put_32 (input_bfd, insn, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVW_PREL_NC: - case R_ARM_THM_MOVT_PREL: - /* Until we properly support segment-base-relative addressing then - we assume the segment base to be zero, as for the above relocations. - Thus R_ARM_THM_MOVW_BREL_NC has the same semantics as - R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_BREL has the same semantics - as R_ARM_THM_MOVT_ABS. */ - case R_ARM_THM_MOVW_BREL_NC: - case R_ARM_THM_MOVW_BREL: - case R_ARM_THM_MOVT_BREL: - { - bfd_vma insn; - - insn = bfd_get_16 (input_bfd, hit_data) << 16; - insn |= bfd_get_16 (input_bfd, hit_data + 2); - - if (globals->use_rel) - { - addend = ((insn >> 4) & 0xf000) - | ((insn >> 15) & 0x0800) - | ((insn >> 4) & 0x0700) - | (insn & 0x00ff); - signed_addend = (addend ^ 0x8000) - 0x8000; - } - - value += signed_addend; - - if (r_type == R_ARM_THM_MOVW_PREL_NC || r_type == R_ARM_THM_MOVT_PREL) - value -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - - if (r_type == R_ARM_THM_MOVW_BREL && value >= 0x10000) - return bfd_reloc_overflow; - - if (branch_type == ST_BRANCH_TO_THUMB) - value |= 1; - - if (r_type == R_ARM_THM_MOVT_ABS || r_type == R_ARM_THM_MOVT_PREL - || r_type == R_ARM_THM_MOVT_BREL) - value >>= 16; - - insn &= 0xfbf08f00; - insn |= (value & 0xf000) << 4; - insn |= (value & 0x0800) << 15; - insn |= (value & 0x0700) << 4; - insn |= (value & 0x00ff); - - bfd_put_16 (input_bfd, insn >> 16, hit_data); - bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2); - } - return bfd_reloc_ok; - - case R_ARM_ALU_PC_G0_NC: - case R_ARM_ALU_PC_G1_NC: - case R_ARM_ALU_PC_G0: - case R_ARM_ALU_PC_G1: - case R_ARM_ALU_PC_G2: - case R_ARM_ALU_SB_G0_NC: - case R_ARM_ALU_SB_G1_NC: - case R_ARM_ALU_SB_G0: - case R_ARM_ALU_SB_G1: - case R_ARM_ALU_SB_G2: - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - bfd_vma pc = input_section->output_section->vma - + input_section->output_offset + rel->r_offset; - /* sb is the origin of the *segment* containing the symbol. */ - bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0; - bfd_vma residual; - bfd_vma g_n; - bfd_signed_vma signed_value; - int group = 0; - - /* Determine which group of bits to select. */ - switch (r_type) - { - case R_ARM_ALU_PC_G0_NC: - case R_ARM_ALU_PC_G0: - case R_ARM_ALU_SB_G0_NC: - case R_ARM_ALU_SB_G0: - group = 0; - break; - - case R_ARM_ALU_PC_G1_NC: - case R_ARM_ALU_PC_G1: - case R_ARM_ALU_SB_G1_NC: - case R_ARM_ALU_SB_G1: - group = 1; - break; - - case R_ARM_ALU_PC_G2: - case R_ARM_ALU_SB_G2: - group = 2; - break; - - default: - abort (); - } - - /* If REL, extract the addend from the insn. If RELA, it will - have already been fetched for us. */ - if (globals->use_rel) - { - int negative; - bfd_vma constant = insn & 0xff; - bfd_vma rotation = (insn & 0xf00) >> 8; - - if (rotation == 0) - signed_addend = constant; - else - { - /* Compensate for the fact that in the instruction, the - rotation is stored in multiples of 2 bits. */ - rotation *= 2; - - /* Rotate "constant" right by "rotation" bits. */ - signed_addend = (constant >> rotation) | - (constant << (8 * sizeof (bfd_vma) - rotation)); - } - - /* Determine if the instruction is an ADD or a SUB. - (For REL, this determines the sign of the addend.) */ - negative = identify_add_or_sub (insn); - if (negative == 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): Only ADD or SUB instructions are allowed for ALU group relocations"), - input_bfd, input_section, rel->r_offset); - return bfd_reloc_overflow; - } - - signed_addend *= negative; - } - - /* Compute the value (X) to go in the place. */ - if (r_type == R_ARM_ALU_PC_G0_NC - || r_type == R_ARM_ALU_PC_G1_NC - || r_type == R_ARM_ALU_PC_G0 - || r_type == R_ARM_ALU_PC_G1 - || r_type == R_ARM_ALU_PC_G2) - /* PC relative. */ - signed_value = value - pc + signed_addend; - else - /* Section base relative. */ - signed_value = value - sb + signed_addend; - - /* If the target symbol is a Thumb function, then set the - Thumb bit in the address. */ - if (branch_type == ST_BRANCH_TO_THUMB) - signed_value |= 1; - - /* Calculate the value of the relevant G_n, in encoded - constant-with-rotation format. */ - g_n = calculate_group_reloc_mask (signed_value < 0 ? - signed_value : signed_value, - group, &residual); - - /* Check for overflow if required. */ - if ((r_type == R_ARM_ALU_PC_G0 - || r_type == R_ARM_ALU_PC_G1 - || r_type == R_ARM_ALU_PC_G2 - || r_type == R_ARM_ALU_SB_G0 - || r_type == R_ARM_ALU_SB_G1 - || r_type == R_ARM_ALU_SB_G2) && residual != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): Overflow whilst splitting %#Lx for group relocation %s"), - input_bfd, input_section, rel->r_offset, - signed_value < 0 ? -signed_value : signed_value, howto->name); - return bfd_reloc_overflow; - } - - /* Mask out the value and the ADD/SUB part of the opcode; take care - not to destroy the S bit. */ - insn &= 0xff1ff000; - - /* Set the opcode according to whether the value to go in the - place is negative. */ - if (signed_value < 0) - insn |= 1 << 22; - else - insn |= 1 << 23; - - /* Encode the offset. */ - insn |= g_n; - - bfd_put_32 (input_bfd, insn, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_LDR_PC_G0: - case R_ARM_LDR_PC_G1: - case R_ARM_LDR_PC_G2: - case R_ARM_LDR_SB_G0: - case R_ARM_LDR_SB_G1: - case R_ARM_LDR_SB_G2: - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - bfd_vma pc = input_section->output_section->vma - + input_section->output_offset + rel->r_offset; - /* sb is the origin of the *segment* containing the symbol. */ - bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0; - bfd_vma residual; - bfd_signed_vma signed_value; - int group = 0; - - /* Determine which groups of bits to calculate. */ - switch (r_type) - { - case R_ARM_LDR_PC_G0: - case R_ARM_LDR_SB_G0: - group = 0; - break; - - case R_ARM_LDR_PC_G1: - case R_ARM_LDR_SB_G1: - group = 1; - break; - - case R_ARM_LDR_PC_G2: - case R_ARM_LDR_SB_G2: - group = 2; - break; - - default: - abort (); - } - - /* If REL, extract the addend from the insn. If RELA, it will - have already been fetched for us. */ - if (globals->use_rel) - { - int negative = (insn & (1 << 23)) ? 1 : -1; - signed_addend = negative * (insn & 0xfff); - } - - /* Compute the value (X) to go in the place. */ - if (r_type == R_ARM_LDR_PC_G0 - || r_type == R_ARM_LDR_PC_G1 - || r_type == R_ARM_LDR_PC_G2) - /* PC relative. */ - signed_value = value - pc + signed_addend; - else - /* Section base relative. */ - signed_value = value - sb + signed_addend; - - /* Calculate the value of the relevant G_{n-1} to obtain - the residual at that stage. */ - calculate_group_reloc_mask (signed_value < 0 ? - signed_value : signed_value, - group - 1, &residual); - - /* Check for overflow. */ - if (residual >= 0x1000) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): Overflow whilst splitting %#Lx for group relocation %s"), - input_bfd, input_section, rel->r_offset, - signed_value < 0 ? -signed_value : signed_value, howto->name); - return bfd_reloc_overflow; - } - - /* Mask out the value and U bit. */ - insn &= 0xff7ff000; - - /* Set the U bit if the value to go in the place is non-negative. */ - if (signed_value >= 0) - insn |= 1 << 23; - - /* Encode the offset. */ - insn |= residual; - - bfd_put_32 (input_bfd, insn, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_LDRS_PC_G0: - case R_ARM_LDRS_PC_G1: - case R_ARM_LDRS_PC_G2: - case R_ARM_LDRS_SB_G0: - case R_ARM_LDRS_SB_G1: - case R_ARM_LDRS_SB_G2: - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - bfd_vma pc = input_section->output_section->vma - + input_section->output_offset + rel->r_offset; - /* sb is the origin of the *segment* containing the symbol. */ - bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0; - bfd_vma residual; - bfd_signed_vma signed_value; - int group = 0; - - /* Determine which groups of bits to calculate. */ - switch (r_type) - { - case R_ARM_LDRS_PC_G0: - case R_ARM_LDRS_SB_G0: - group = 0; - break; - - case R_ARM_LDRS_PC_G1: - case R_ARM_LDRS_SB_G1: - group = 1; - break; - - case R_ARM_LDRS_PC_G2: - case R_ARM_LDRS_SB_G2: - group = 2; - break; - - default: - abort (); - } - - /* If REL, extract the addend from the insn. If RELA, it will - have already been fetched for us. */ - if (globals->use_rel) - { - int negative = (insn & (1 << 23)) ? 1 : -1; - signed_addend = negative * (((insn & 0xf00) >> 4) + (insn & 0xf)); - } - - /* Compute the value (X) to go in the place. */ - if (r_type == R_ARM_LDRS_PC_G0 - || r_type == R_ARM_LDRS_PC_G1 - || r_type == R_ARM_LDRS_PC_G2) - /* PC relative. */ - signed_value = value - pc + signed_addend; - else - /* Section base relative. */ - signed_value = value - sb + signed_addend; - - /* Calculate the value of the relevant G_{n-1} to obtain - the residual at that stage. */ - calculate_group_reloc_mask (signed_value < 0 ? - signed_value : signed_value, - group - 1, &residual); - - /* Check for overflow. */ - if (residual >= 0x100) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): Overflow whilst splitting %#Lx for group relocation %s"), - input_bfd, input_section, rel->r_offset, - signed_value < 0 ? -signed_value : signed_value, howto->name); - return bfd_reloc_overflow; - } - - /* Mask out the value and U bit. */ - insn &= 0xff7ff0f0; - - /* Set the U bit if the value to go in the place is non-negative. */ - if (signed_value >= 0) - insn |= 1 << 23; - - /* Encode the offset. */ - insn |= ((residual & 0xf0) << 4) | (residual & 0xf); - - bfd_put_32 (input_bfd, insn, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_LDC_PC_G0: - case R_ARM_LDC_PC_G1: - case R_ARM_LDC_PC_G2: - case R_ARM_LDC_SB_G0: - case R_ARM_LDC_SB_G1: - case R_ARM_LDC_SB_G2: - { - bfd_vma insn = bfd_get_32 (input_bfd, hit_data); - bfd_vma pc = input_section->output_section->vma - + input_section->output_offset + rel->r_offset; - /* sb is the origin of the *segment* containing the symbol. */ - bfd_vma sb = sym_sec ? sym_sec->output_section->vma : 0; - bfd_vma residual; - bfd_signed_vma signed_value; - int group = 0; - - /* Determine which groups of bits to calculate. */ - switch (r_type) - { - case R_ARM_LDC_PC_G0: - case R_ARM_LDC_SB_G0: - group = 0; - break; - - case R_ARM_LDC_PC_G1: - case R_ARM_LDC_SB_G1: - group = 1; - break; - - case R_ARM_LDC_PC_G2: - case R_ARM_LDC_SB_G2: - group = 2; - break; - - default: - abort (); - } - - /* If REL, extract the addend from the insn. If RELA, it will - have already been fetched for us. */ - if (globals->use_rel) - { - int negative = (insn & (1 << 23)) ? 1 : -1; - signed_addend = negative * ((insn & 0xff) << 2); - } - - /* Compute the value (X) to go in the place. */ - if (r_type == R_ARM_LDC_PC_G0 - || r_type == R_ARM_LDC_PC_G1 - || r_type == R_ARM_LDC_PC_G2) - /* PC relative. */ - signed_value = value - pc + signed_addend; - else - /* Section base relative. */ - signed_value = value - sb + signed_addend; - - /* Calculate the value of the relevant G_{n-1} to obtain - the residual at that stage. */ - calculate_group_reloc_mask (signed_value < 0 ? - signed_value : signed_value, - group - 1, &residual); - - /* Check for overflow. (The absolute value to go in the place must be - divisible by four and, after having been divided by four, must - fit in eight bits.) */ - if ((residual & 0x3) != 0 || residual >= 0x400) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): Overflow whilst splitting %#Lx for group relocation %s"), - input_bfd, input_section, rel->r_offset, - signed_value < 0 ? -signed_value : signed_value, howto->name); - return bfd_reloc_overflow; - } - - /* Mask out the value and U bit. */ - insn &= 0xff7fff00; - - /* Set the U bit if the value to go in the place is non-negative. */ - if (signed_value >= 0) - insn |= 1 << 23; - - /* Encode the offset. */ - insn |= residual >> 2; - - bfd_put_32 (input_bfd, insn, hit_data); - } - return bfd_reloc_ok; - - case R_ARM_THM_ALU_ABS_G0_NC: - case R_ARM_THM_ALU_ABS_G1_NC: - case R_ARM_THM_ALU_ABS_G2_NC: - case R_ARM_THM_ALU_ABS_G3_NC: - { - const int shift_array[4] = {0, 8, 16, 24}; - bfd_vma insn = bfd_get_16 (input_bfd, hit_data); - bfd_vma addr = value; - int shift = shift_array[r_type - R_ARM_THM_ALU_ABS_G0_NC]; - - /* Compute address. */ - if (globals->use_rel) - signed_addend = insn & 0xff; - addr += signed_addend; - if (branch_type == ST_BRANCH_TO_THUMB) - addr |= 1; - /* Clean imm8 insn. */ - insn &= 0xff00; - /* And update with correct part of address. */ - insn |= (addr >> shift) & 0xff; - /* Update insn. */ - bfd_put_16 (input_bfd, insn, hit_data); - } - - *unresolved_reloc_p = FALSE; - return bfd_reloc_ok; - - default: - return bfd_reloc_notsupported; - } -} - -/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. */ -static void -arm_add_to_rel (bfd * abfd, - bfd_byte * address, - reloc_howto_type * howto, - bfd_signed_vma increment) -{ - bfd_signed_vma addend; - - if (howto->type == R_ARM_THM_CALL - || howto->type == R_ARM_THM_JUMP24) - { - int upper_insn, lower_insn; - int upper, lower; - - upper_insn = bfd_get_16 (abfd, address); - lower_insn = bfd_get_16 (abfd, address + 2); - upper = upper_insn & 0x7ff; - lower = lower_insn & 0x7ff; - - addend = (upper << 12) | (lower << 1); - addend += increment; - addend >>= 1; - - upper_insn = (upper_insn & 0xf800) | ((addend >> 11) & 0x7ff); - lower_insn = (lower_insn & 0xf800) | (addend & 0x7ff); - - bfd_put_16 (abfd, (bfd_vma) upper_insn, address); - bfd_put_16 (abfd, (bfd_vma) lower_insn, address + 2); - } - else - { - bfd_vma contents; - - contents = bfd_get_32 (abfd, address); - - /* Get the (signed) value from the instruction. */ - addend = contents & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~ howto->src_mask; - addend |= mask; - } - - /* Add in the increment, (which is a byte value). */ - switch (howto->type) - { - default: - addend += increment; - break; - - case R_ARM_PC24: - case R_ARM_PLT32: - case R_ARM_CALL: - case R_ARM_JUMP24: - addend <<= howto->size; - addend += increment; - - /* Should we check for overflow here ? */ - - /* Drop any undesired bits. */ - addend >>= howto->rightshift; - break; - } - - contents = (contents & ~ howto->dst_mask) | (addend & howto->dst_mask); - - bfd_put_32 (abfd, contents, address); - } -} - -#define IS_ARM_TLS_RELOC(R_TYPE) \ - ((R_TYPE) == R_ARM_TLS_GD32 \ - || (R_TYPE) == R_ARM_TLS_LDO32 \ - || (R_TYPE) == R_ARM_TLS_LDM32 \ - || (R_TYPE) == R_ARM_TLS_DTPOFF32 \ - || (R_TYPE) == R_ARM_TLS_DTPMOD32 \ - || (R_TYPE) == R_ARM_TLS_TPOFF32 \ - || (R_TYPE) == R_ARM_TLS_LE32 \ - || (R_TYPE) == R_ARM_TLS_IE32 \ - || IS_ARM_TLS_GNU_RELOC (R_TYPE)) - -/* Specific set of relocations for the gnu tls dialect. */ -#define IS_ARM_TLS_GNU_RELOC(R_TYPE) \ - ((R_TYPE) == R_ARM_TLS_GOTDESC \ - || (R_TYPE) == R_ARM_TLS_CALL \ - || (R_TYPE) == R_ARM_THM_TLS_CALL \ - || (R_TYPE) == R_ARM_TLS_DESCSEQ \ - || (R_TYPE) == R_ARM_THM_TLS_DESCSEQ) - -/* Relocate an ARM ELF section. */ - -static bfd_boolean -elf32_arm_relocate_section (bfd * output_bfd, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - const char *name; - struct elf32_arm_link_hash_table * globals; - - globals = elf32_arm_hash_table (info); - if (globals == NULL) - return FALSE; - - symtab_hdr = & elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - arelent bfd_reloc; - char sym_type; - bfd_boolean unresolved_reloc = FALSE; - char *error_message = NULL; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - r_type = arm_real_reloc_type (globals, r_type); - - if ( r_type == R_ARM_GNU_VTENTRY - || r_type == R_ARM_GNU_VTINHERIT) - continue; - - howto = bfd_reloc.howto = elf32_arm_howto_from_type (r_type); - - if (howto == NULL) - return _bfd_unrecognized_reloc (input_bfd, input_section, r_type); - - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sym_type = ELF32_ST_TYPE (sym->st_info); - sec = local_sections[r_symndx]; - - /* An object file might have a reference to a local - undefined symbol. This is a daft object file, but we - should at least do something about it. V4BX & NONE - relocations do not use the symbol and are explicitly - allowed to use the undefined symbol, so allow those. - Likewise for relocations against STN_UNDEF. */ - if (r_type != R_ARM_V4BX - && r_type != R_ARM_NONE - && r_symndx != STN_UNDEF - && bfd_is_und_section (sec) - && ELF_ST_BIND (sym->st_info) != STB_WEAK) - (*info->callbacks->undefined_symbol) - (info, bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name), - input_bfd, input_section, - rel->r_offset, TRUE); - - if (globals->use_rel) - { - relocation = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - if (!bfd_link_relocatable (info) - && (sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - asection *msec; - bfd_vma addend, value; - - switch (r_type) - { - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - addend = ((value & 0xf0000) >> 4) | (value & 0xfff); - addend = (addend ^ 0x8000) - 0x8000; - break; - - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - value = bfd_get_16 (input_bfd, contents + rel->r_offset) - << 16; - value |= bfd_get_16 (input_bfd, - contents + rel->r_offset + 2); - addend = ((value & 0xf7000) >> 4) | (value & 0xff) - | ((value & 0x04000000) >> 15); - addend = (addend ^ 0x8000) - 0x8000; - break; - - default: - if (howto->rightshift - || (howto->src_mask & (howto->src_mask + 1))) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation against SEC_MERGE section"), - input_bfd, input_section, - rel->r_offset, howto->name); - return FALSE; - } - - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Get the (signed) value from the instruction. */ - addend = value & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~ howto->src_mask; - addend |= mask; - } - break; - } - - msec = sec; - addend = - _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - - relocation; - addend += msec->output_section->vma + msec->output_offset; - - /* Cases here must match those in the preceding - switch statement. */ - switch (r_type) - { - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - value = (value & 0xfff0f000) | ((addend & 0xf000) << 4) - | (addend & 0xfff); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - value = (value & 0xfbf08f00) | ((addend & 0xf700) << 4) - | (addend & 0xff) | ((addend & 0x0800) << 15); - bfd_put_16 (input_bfd, value >> 16, - contents + rel->r_offset); - bfd_put_16 (input_bfd, value, - contents + rel->r_offset + 2); - break; - - default: - value = (value & ~ howto->dst_mask) - | (addend & howto->dst_mask); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - } - } - } - else - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - sym_type = h->type; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - if (globals->use_rel) - arm_add_to_rel (input_bfd, contents + rel->r_offset, - howto, (bfd_signed_vma) sec->output_offset); - else - rel->r_addend += sec->output_offset; - } - continue; - } - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - if (r_symndx != STN_UNDEF - && r_type != R_ARM_NONE - && (h == NULL - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && IS_ARM_TLS_RELOC (r_type) != (sym_type == STT_TLS)) - { - _bfd_error_handler - ((sym_type == STT_TLS - /* xgettext:c-format */ - ? _("%B(%A+%#Lx): %s used with TLS symbol %s") - /* xgettext:c-format */ - : _("%B(%A+%#Lx): %s used with non-TLS symbol %s")), - input_bfd, - input_section, - rel->r_offset, - howto->name, - name); - } - - /* We call elf32_arm_final_link_relocate unless we're completely - done, i.e., the relaxation produced the final output we want, - and we won't let anybody mess with it. Also, we have to do - addend adjustments in case of a R_ARM_TLS_GOTDESC relocation - both in relaxed and non-relaxed cases. */ - if ((elf32_arm_tls_transition (info, r_type, h) != (unsigned)r_type) - || (IS_ARM_TLS_GNU_RELOC (r_type) - && !((h ? elf32_arm_hash_entry (h)->tls_type : - elf32_arm_local_got_tls_type (input_bfd)[r_symndx]) - & GOT_TLS_GDESC))) - { - r = elf32_arm_tls_relax (globals, input_bfd, input_section, - contents, rel, h == NULL); - /* This may have been marked unresolved because it came from - a shared library. But we've just dealt with that. */ - unresolved_reloc = 0; - } - else - r = bfd_reloc_continue; - - if (r == bfd_reloc_continue) - { - unsigned char branch_type = - h ? ARM_GET_SYM_BRANCH_TYPE (h->target_internal) - : ARM_GET_SYM_BRANCH_TYPE (sym->st_target_internal); - - r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd, - input_section, contents, rel, - relocation, info, sec, name, - sym_type, branch_type, h, - &unresolved_reloc, - &error_message); - } - - /* 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - return FALSE; - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - case bfd_reloc_overflow: - /* If the overflowing reloc was to an undefined symbol, - we have already printed one error message and there - is no point complaining again. */ - if (!h || h->root.type != bfd_link_hash_undefined) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - error_message = _("out of range"); - goto common_error; - - case bfd_reloc_notsupported: - error_message = _("unsupported relocation"); - goto common_error; - - case bfd_reloc_dangerous: - /* error_message should already be set. */ - goto common_error; - - default: - error_message = _("unknown error"); - /* Fall through. */ - - common_error: - BFD_ASSERT (error_message != NULL); - (*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* Add a new unwind edit to the list described by HEAD, TAIL. If TINDEX is zero, - adds the edit to the start of the list. (The list must be built in order of - ascending TINDEX: the function's callers are primarily responsible for - maintaining that condition). */ - -static void -add_unwind_table_edit (arm_unwind_table_edit **head, - arm_unwind_table_edit **tail, - arm_unwind_edit_type type, - asection *linked_section, - unsigned int tindex) -{ - arm_unwind_table_edit *new_edit = (arm_unwind_table_edit *) - xmalloc (sizeof (arm_unwind_table_edit)); - - new_edit->type = type; - new_edit->linked_section = linked_section; - new_edit->index = tindex; - - if (tindex > 0) - { - new_edit->next = NULL; - - if (*tail) - (*tail)->next = new_edit; - - (*tail) = new_edit; - - if (!*head) - (*head) = new_edit; - } - else - { - new_edit->next = *head; - - if (!*tail) - *tail = new_edit; - - *head = new_edit; - } -} - -static _arm_elf_section_data *get_arm_elf_section_data (asection *); - -/* Increase the size of EXIDX_SEC by ADJUST bytes. ADJUST mau be negative. */ -static void -adjust_exidx_size(asection *exidx_sec, int adjust) -{ - asection *out_sec; - - if (!exidx_sec->rawsize) - exidx_sec->rawsize = exidx_sec->size; - - bfd_set_section_size (exidx_sec->owner, exidx_sec, exidx_sec->size + adjust); - out_sec = exidx_sec->output_section; - /* Adjust size of output section. */ - bfd_set_section_size (out_sec->owner, out_sec, out_sec->size +adjust); -} - -/* Insert an EXIDX_CANTUNWIND marker at the end of a section. */ -static void -insert_cantunwind_after(asection *text_sec, asection *exidx_sec) -{ - struct _arm_elf_section_data *exidx_arm_data; - - exidx_arm_data = get_arm_elf_section_data (exidx_sec); - add_unwind_table_edit ( - &exidx_arm_data->u.exidx.unwind_edit_list, - &exidx_arm_data->u.exidx.unwind_edit_tail, - INSERT_EXIDX_CANTUNWIND_AT_END, text_sec, UINT_MAX); - - exidx_arm_data->additional_reloc_count++; - - adjust_exidx_size(exidx_sec, 8); -} - -/* Scan .ARM.exidx tables, and create a list describing edits which should be - made to those tables, such that: - - 1. Regions without unwind data are marked with EXIDX_CANTUNWIND entries. - 2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind - codes which have been inlined into the index). - - If MERGE_EXIDX_ENTRIES is false, duplicate entries are not merged. - - The edits are applied when the tables are written - (in elf32_arm_write_section). */ - -bfd_boolean -elf32_arm_fix_exidx_coverage (asection **text_section_order, - unsigned int num_text_sections, - struct bfd_link_info *info, - bfd_boolean merge_exidx_entries) -{ - bfd *inp; - unsigned int last_second_word = 0, i; - asection *last_exidx_sec = NULL; - asection *last_text_sec = NULL; - int last_unwind_type = -1; - - /* Walk over all EXIDX sections, and create backlinks from the corrsponding - text sections. */ - for (inp = info->input_bfds; inp != NULL; inp = inp->link.next) - { - asection *sec; - - for (sec = inp->sections; sec != NULL; sec = sec->next) - { - struct bfd_elf_section_data *elf_sec = elf_section_data (sec); - Elf_Internal_Shdr *hdr = &elf_sec->this_hdr; - - if (!hdr || hdr->sh_type != SHT_ARM_EXIDX) - continue; - - if (elf_sec->linked_to) - { - Elf_Internal_Shdr *linked_hdr - = &elf_section_data (elf_sec->linked_to)->this_hdr; - struct _arm_elf_section_data *linked_sec_arm_data - = get_arm_elf_section_data (linked_hdr->bfd_section); - - if (linked_sec_arm_data == NULL) - continue; - - /* Link this .ARM.exidx section back from the text section it - describes. */ - linked_sec_arm_data->u.text.arm_exidx_sec = sec; - } - } - } - - /* Walk all text sections in order of increasing VMA. Eilminate duplicate - index table entries (EXIDX_CANTUNWIND and inlined unwind opcodes), - and add EXIDX_CANTUNWIND entries for sections with no unwind table data. */ - - for (i = 0; i < num_text_sections; i++) - { - asection *sec = text_section_order[i]; - asection *exidx_sec; - struct _arm_elf_section_data *arm_data = get_arm_elf_section_data (sec); - struct _arm_elf_section_data *exidx_arm_data; - bfd_byte *contents = NULL; - int deleted_exidx_bytes = 0; - bfd_vma j; - arm_unwind_table_edit *unwind_edit_head = NULL; - arm_unwind_table_edit *unwind_edit_tail = NULL; - Elf_Internal_Shdr *hdr; - bfd *ibfd; - - if (arm_data == NULL) - continue; - - exidx_sec = arm_data->u.text.arm_exidx_sec; - if (exidx_sec == NULL) - { - /* Section has no unwind data. */ - if (last_unwind_type == 0 || !last_exidx_sec) - continue; - - /* Ignore zero sized sections. */ - if (sec->size == 0) - continue; - - insert_cantunwind_after(last_text_sec, last_exidx_sec); - last_unwind_type = 0; - continue; - } - - /* Skip /DISCARD/ sections. */ - if (bfd_is_abs_section (exidx_sec->output_section)) - continue; - - hdr = &elf_section_data (exidx_sec)->this_hdr; - if (hdr->sh_type != SHT_ARM_EXIDX) - continue; - - exidx_arm_data = get_arm_elf_section_data (exidx_sec); - if (exidx_arm_data == NULL) - continue; - - ibfd = exidx_sec->owner; - - if (hdr->contents != NULL) - contents = hdr->contents; - else if (! bfd_malloc_and_get_section (ibfd, exidx_sec, &contents)) - /* An error? */ - continue; - - if (last_unwind_type > 0) - { - unsigned int first_word = bfd_get_32 (ibfd, contents); - /* Add cantunwind if first unwind item does not match section - start. */ - if (first_word != sec->vma) - { - insert_cantunwind_after (last_text_sec, last_exidx_sec); - last_unwind_type = 0; - } - } - - for (j = 0; j < hdr->sh_size; j += 8) - { - unsigned int second_word = bfd_get_32 (ibfd, contents + j + 4); - int unwind_type; - int elide = 0; - - /* An EXIDX_CANTUNWIND entry. */ - if (second_word == 1) - { - if (last_unwind_type == 0) - elide = 1; - unwind_type = 0; - } - /* Inlined unwinding data. Merge if equal to previous. */ - else if ((second_word & 0x80000000) != 0) - { - if (merge_exidx_entries - && last_second_word == second_word && last_unwind_type == 1) - elide = 1; - unwind_type = 1; - last_second_word = second_word; - } - /* Normal table entry. In theory we could merge these too, - but duplicate entries are likely to be much less common. */ - else - unwind_type = 2; - - if (elide && !bfd_link_relocatable (info)) - { - add_unwind_table_edit (&unwind_edit_head, &unwind_edit_tail, - DELETE_EXIDX_ENTRY, NULL, j / 8); - - deleted_exidx_bytes += 8; - } - - last_unwind_type = unwind_type; - } - - /* Free contents if we allocated it ourselves. */ - if (contents != hdr->contents) - free (contents); - - /* Record edits to be applied later (in elf32_arm_write_section). */ - exidx_arm_data->u.exidx.unwind_edit_list = unwind_edit_head; - exidx_arm_data->u.exidx.unwind_edit_tail = unwind_edit_tail; - - if (deleted_exidx_bytes > 0) - adjust_exidx_size(exidx_sec, -deleted_exidx_bytes); - - last_exidx_sec = exidx_sec; - last_text_sec = sec; - } - - /* Add terminating CANTUNWIND entry. */ - if (!bfd_link_relocatable (info) && last_exidx_sec - && last_unwind_type != 0) - insert_cantunwind_after(last_text_sec, last_exidx_sec); - - return TRUE; -} - -static bfd_boolean -elf32_arm_output_glue_section (struct bfd_link_info *info, bfd *obfd, - bfd *ibfd, const char *name) -{ - asection *sec, *osec; - - sec = bfd_get_linker_section (ibfd, name); - if (sec == NULL || (sec->flags & SEC_EXCLUDE) != 0) - return TRUE; - - osec = sec->output_section; - if (elf32_arm_write_section (obfd, info, sec, sec->contents)) - return TRUE; - - if (! bfd_set_section_contents (obfd, osec, sec->contents, - sec->output_offset, sec->size)) - return FALSE; - - return TRUE; -} - -static bfd_boolean -elf32_arm_final_link (bfd *abfd, struct bfd_link_info *info) -{ - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info); - asection *sec, *osec; - - if (globals == NULL) - return FALSE; - - /* Invoke the regular ELF backend linker to do all the work. */ - if (!bfd_elf_final_link (abfd, info)) - return FALSE; - - /* Process stub sections (eg BE8 encoding, ...). */ - struct elf32_arm_link_hash_table *htab = elf32_arm_hash_table (info); - unsigned int i; - for (i=0; itop_id; i++) - { - sec = htab->stub_group[i].stub_sec; - /* Only process it once, in its link_sec slot. */ - if (sec && i == htab->stub_group[i].link_sec->id) - { - osec = sec->output_section; - elf32_arm_write_section (abfd, info, sec, sec->contents); - if (! bfd_set_section_contents (abfd, osec, sec->contents, - sec->output_offset, sec->size)) - return FALSE; - } - } - - /* Write out any glue sections now that we have created all the - stubs. */ - if (globals->bfd_of_glue_owner != NULL) - { - if (! elf32_arm_output_glue_section (info, abfd, - globals->bfd_of_glue_owner, - ARM2THUMB_GLUE_SECTION_NAME)) - return FALSE; - - if (! elf32_arm_output_glue_section (info, abfd, - globals->bfd_of_glue_owner, - THUMB2ARM_GLUE_SECTION_NAME)) - return FALSE; - - if (! elf32_arm_output_glue_section (info, abfd, - globals->bfd_of_glue_owner, - VFP11_ERRATUM_VENEER_SECTION_NAME)) - return FALSE; - - if (! elf32_arm_output_glue_section (info, abfd, - globals->bfd_of_glue_owner, - STM32L4XX_ERRATUM_VENEER_SECTION_NAME)) - return FALSE; - - if (! elf32_arm_output_glue_section (info, abfd, - globals->bfd_of_glue_owner, - ARM_BX_GLUE_SECTION_NAME)) - return FALSE; - } - - return TRUE; -} - -/* Return a best guess for the machine number based on the attributes. */ - -static unsigned int -bfd_arm_get_mach_from_attributes (bfd * abfd) -{ - int arch = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, Tag_CPU_arch); - - switch (arch) - { - case TAG_CPU_ARCH_V4: return bfd_mach_arm_4; - case TAG_CPU_ARCH_V4T: return bfd_mach_arm_4T; - case TAG_CPU_ARCH_V5T: return bfd_mach_arm_5T; - - case TAG_CPU_ARCH_V5TE: - { - char * name; - - BFD_ASSERT (Tag_CPU_name < NUM_KNOWN_OBJ_ATTRIBUTES); - name = elf_known_obj_attributes (abfd) [OBJ_ATTR_PROC][Tag_CPU_name].s; - - if (name) - { - if (strcmp (name, "IWMMXT2") == 0) - return bfd_mach_arm_iWMMXt2; - - if (strcmp (name, "IWMMXT") == 0) - return bfd_mach_arm_iWMMXt; - - if (strcmp (name, "XSCALE") == 0) - { - int wmmx; - - BFD_ASSERT (Tag_WMMX_arch < NUM_KNOWN_OBJ_ATTRIBUTES); - wmmx = elf_known_obj_attributes (abfd) [OBJ_ATTR_PROC][Tag_WMMX_arch].i; - switch (wmmx) - { - case 1: return bfd_mach_arm_iWMMXt; - case 2: return bfd_mach_arm_iWMMXt2; - default: return bfd_mach_arm_XScale; - } - } - } - - return bfd_mach_arm_5TE; - } - - default: - return bfd_mach_arm_unknown; - } -} - -/* Set the right machine number. */ - -static bfd_boolean -elf32_arm_object_p (bfd *abfd) -{ - unsigned int mach; - - mach = bfd_arm_get_mach_from_notes (abfd, ARM_NOTE_SECTION); - - if (mach == bfd_mach_arm_unknown) - { - if (elf_elfheader (abfd)->e_flags & EF_ARM_MAVERICK_FLOAT) - mach = bfd_mach_arm_ep9312; - else - mach = bfd_arm_get_mach_from_attributes (abfd); - } - - bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach); - return TRUE; -} - -/* Function to keep ARM specific flags in the ELF header. */ - -static bfd_boolean -elf32_arm_set_private_flags (bfd *abfd, flagword flags) -{ - if (elf_flags_init (abfd) - && elf_elfheader (abfd)->e_flags != flags) - { - if (EF_ARM_EABI_VERSION (flags) == EF_ARM_EABI_UNKNOWN) - { - if (flags & EF_ARM_INTERWORK) - _bfd_error_handler - (_("Warning: Not setting interworking flag of %B since it has already been specified as non-interworking"), - abfd); - else - _bfd_error_handler - (_("Warning: Clearing the interworking flag of %B due to outside request"), - abfd); - } - } - else - { - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - } - - return TRUE; -} - -/* Copy backend specific data from one object module to another. */ - -static bfd_boolean -elf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - flagword in_flags; - flagword out_flags; - - if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd)) - return TRUE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (elf_flags_init (obfd) - && EF_ARM_EABI_VERSION (out_flags) == EF_ARM_EABI_UNKNOWN - && in_flags != out_flags) - { - /* Cannot mix APCS26 and APCS32 code. */ - if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26)) - return FALSE; - - /* Cannot mix float APCS and non-float APCS code. */ - if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT)) - return FALSE; - - /* If the src and dest have different interworking flags - then turn off the interworking bit. */ - if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK)) - { - if (out_flags & EF_ARM_INTERWORK) - _bfd_error_handler - (_("Warning: Clearing the interworking flag of %B because non-interworking code in %B has been linked with it"), - obfd, ibfd); - - in_flags &= ~EF_ARM_INTERWORK; - } - - /* Likewise for PIC, though don't warn for this case. */ - if ((in_flags & EF_ARM_PIC) != (out_flags & EF_ARM_PIC)) - in_flags &= ~EF_ARM_PIC; - } - - elf_elfheader (obfd)->e_flags = in_flags; - elf_flags_init (obfd) = TRUE; - - return _bfd_elf_copy_private_bfd_data (ibfd, obfd); -} - -/* Values for Tag_ABI_PCS_R9_use. */ -enum -{ - AEABI_R9_V6, - AEABI_R9_SB, - AEABI_R9_TLS, - AEABI_R9_unused -}; - -/* Values for Tag_ABI_PCS_RW_data. */ -enum -{ - AEABI_PCS_RW_data_absolute, - AEABI_PCS_RW_data_PCrel, - AEABI_PCS_RW_data_SBrel, - AEABI_PCS_RW_data_unused -}; - -/* Values for Tag_ABI_enum_size. */ -enum -{ - AEABI_enum_unused, - AEABI_enum_short, - AEABI_enum_wide, - AEABI_enum_forced_wide -}; - -/* Determine whether an object attribute tag takes an integer, a - string or both. */ - -static int -elf32_arm_obj_attrs_arg_type (int tag) -{ - if (tag == Tag_compatibility) - return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL; - else if (tag == Tag_nodefaults) - return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_NO_DEFAULT; - else if (tag == Tag_CPU_raw_name || tag == Tag_CPU_name) - return ATTR_TYPE_FLAG_STR_VAL; - else if (tag < 32) - return ATTR_TYPE_FLAG_INT_VAL; - else - return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; -} - -/* The ABI defines that Tag_conformance should be emitted first, and that - Tag_nodefaults should be second (if either is defined). This sets those - two positions, and bumps up the position of all the remaining tags to - compensate. */ -static int -elf32_arm_obj_attrs_order (int num) -{ - if (num == LEAST_KNOWN_OBJ_ATTRIBUTE) - return Tag_conformance; - if (num == LEAST_KNOWN_OBJ_ATTRIBUTE + 1) - return Tag_nodefaults; - if ((num - 2) < Tag_nodefaults) - return num - 2; - if ((num - 1) < Tag_conformance) - return num - 1; - return num; -} - -/* Attribute numbers >=64 (mod 128) can be safely ignored. */ -static bfd_boolean -elf32_arm_obj_attrs_handle_unknown (bfd *abfd, int tag) -{ - if ((tag & 127) < 64) - { - _bfd_error_handler - (_("%B: Unknown mandatory EABI object attribute %d"), - abfd, tag); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - _bfd_error_handler - (_("Warning: %B: Unknown EABI object attribute %d"), - abfd, tag); - return TRUE; - } -} - -/* Read the architecture from the Tag_also_compatible_with attribute, if any. - Returns -1 if no architecture could be read. */ - -static int -get_secondary_compatible_arch (bfd *abfd) -{ - obj_attribute *attr = - &elf_known_obj_attributes_proc (abfd)[Tag_also_compatible_with]; - - /* Note: the tag and its argument below are uleb128 values, though - currently-defined values fit in one byte for each. */ - if (attr->s - && attr->s[0] == Tag_CPU_arch - && (attr->s[1] & 128) != 128 - && attr->s[2] == 0) - return attr->s[1]; - - /* This tag is "safely ignorable", so don't complain if it looks funny. */ - return -1; -} - -/* Set, or unset, the architecture of the Tag_also_compatible_with attribute. - The tag is removed if ARCH is -1. */ - -static void -set_secondary_compatible_arch (bfd *abfd, int arch) -{ - obj_attribute *attr = - &elf_known_obj_attributes_proc (abfd)[Tag_also_compatible_with]; - - if (arch == -1) - { - attr->s = NULL; - return; - } - - /* Note: the tag and its argument below are uleb128 values, though - currently-defined values fit in one byte for each. */ - if (!attr->s) - attr->s = (char *) bfd_alloc (abfd, 3); - attr->s[0] = Tag_CPU_arch; - attr->s[1] = arch; - attr->s[2] = '\0'; -} - -/* Combine two values for Tag_CPU_arch, taking secondary compatibility tags - into account. */ - -static int -tag_cpu_arch_combine (bfd *ibfd, int oldtag, int *secondary_compat_out, - int newtag, int secondary_compat) -{ -#define T(X) TAG_CPU_ARCH_##X - int tagl, tagh, result; - const int v6t2[] = - { - T(V6T2), /* PRE_V4. */ - T(V6T2), /* V4. */ - T(V6T2), /* V4T. */ - T(V6T2), /* V5T. */ - T(V6T2), /* V5TE. */ - T(V6T2), /* V5TEJ. */ - T(V6T2), /* V6. */ - T(V7), /* V6KZ. */ - T(V6T2) /* V6T2. */ - }; - const int v6k[] = - { - T(V6K), /* PRE_V4. */ - T(V6K), /* V4. */ - T(V6K), /* V4T. */ - T(V6K), /* V5T. */ - T(V6K), /* V5TE. */ - T(V6K), /* V5TEJ. */ - T(V6K), /* V6. */ - T(V6KZ), /* V6KZ. */ - T(V7), /* V6T2. */ - T(V6K) /* V6K. */ - }; - const int v7[] = - { - T(V7), /* PRE_V4. */ - T(V7), /* V4. */ - T(V7), /* V4T. */ - T(V7), /* V5T. */ - T(V7), /* V5TE. */ - T(V7), /* V5TEJ. */ - T(V7), /* V6. */ - T(V7), /* V6KZ. */ - T(V7), /* V6T2. */ - T(V7), /* V6K. */ - T(V7) /* V7. */ - }; - const int v6_m[] = - { - -1, /* PRE_V4. */ - -1, /* V4. */ - T(V6K), /* V4T. */ - T(V6K), /* V5T. */ - T(V6K), /* V5TE. */ - T(V6K), /* V5TEJ. */ - T(V6K), /* V6. */ - T(V6KZ), /* V6KZ. */ - T(V7), /* V6T2. */ - T(V6K), /* V6K. */ - T(V7), /* V7. */ - T(V6_M) /* V6_M. */ - }; - const int v6s_m[] = - { - -1, /* PRE_V4. */ - -1, /* V4. */ - T(V6K), /* V4T. */ - T(V6K), /* V5T. */ - T(V6K), /* V5TE. */ - T(V6K), /* V5TEJ. */ - T(V6K), /* V6. */ - T(V6KZ), /* V6KZ. */ - T(V7), /* V6T2. */ - T(V6K), /* V6K. */ - T(V7), /* V7. */ - T(V6S_M), /* V6_M. */ - T(V6S_M) /* V6S_M. */ - }; - const int v7e_m[] = - { - -1, /* PRE_V4. */ - -1, /* V4. */ - T(V7E_M), /* V4T. */ - T(V7E_M), /* V5T. */ - T(V7E_M), /* V5TE. */ - T(V7E_M), /* V5TEJ. */ - T(V7E_M), /* V6. */ - T(V7E_M), /* V6KZ. */ - T(V7E_M), /* V6T2. */ - T(V7E_M), /* V6K. */ - T(V7E_M), /* V7. */ - T(V7E_M), /* V6_M. */ - T(V7E_M), /* V6S_M. */ - T(V7E_M) /* V7E_M. */ - }; - const int v8[] = - { - T(V8), /* PRE_V4. */ - T(V8), /* V4. */ - T(V8), /* V4T. */ - T(V8), /* V5T. */ - T(V8), /* V5TE. */ - T(V8), /* V5TEJ. */ - T(V8), /* V6. */ - T(V8), /* V6KZ. */ - T(V8), /* V6T2. */ - T(V8), /* V6K. */ - T(V8), /* V7. */ - T(V8), /* V6_M. */ - T(V8), /* V6S_M. */ - T(V8), /* V7E_M. */ - T(V8) /* V8. */ - }; - const int v8r[] = - { - T(V8R), /* PRE_V4. */ - T(V8R), /* V4. */ - T(V8R), /* V4T. */ - T(V8R), /* V5T. */ - T(V8R), /* V5TE. */ - T(V8R), /* V5TEJ. */ - T(V8R), /* V6. */ - T(V8R), /* V6KZ. */ - T(V8R), /* V6T2. */ - T(V8R), /* V6K. */ - T(V8R), /* V7. */ - T(V8R), /* V6_M. */ - T(V8R), /* V6S_M. */ - T(V8R), /* V7E_M. */ - T(V8), /* V8. */ - T(V8R), /* V8R. */ - }; - const int v8m_baseline[] = - { - -1, /* PRE_V4. */ - -1, /* V4. */ - -1, /* V4T. */ - -1, /* V5T. */ - -1, /* V5TE. */ - -1, /* V5TEJ. */ - -1, /* V6. */ - -1, /* V6KZ. */ - -1, /* V6T2. */ - -1, /* V6K. */ - -1, /* V7. */ - T(V8M_BASE), /* V6_M. */ - T(V8M_BASE), /* V6S_M. */ - -1, /* V7E_M. */ - -1, /* V8. */ - -1, /* V8R. */ - T(V8M_BASE) /* V8-M BASELINE. */ - }; - const int v8m_mainline[] = - { - -1, /* PRE_V4. */ - -1, /* V4. */ - -1, /* V4T. */ - -1, /* V5T. */ - -1, /* V5TE. */ - -1, /* V5TEJ. */ - -1, /* V6. */ - -1, /* V6KZ. */ - -1, /* V6T2. */ - -1, /* V6K. */ - T(V8M_MAIN), /* V7. */ - T(V8M_MAIN), /* V6_M. */ - T(V8M_MAIN), /* V6S_M. */ - T(V8M_MAIN), /* V7E_M. */ - -1, /* V8. */ - -1, /* V8R. */ - T(V8M_MAIN), /* V8-M BASELINE. */ - T(V8M_MAIN) /* V8-M MAINLINE. */ - }; - const int v4t_plus_v6_m[] = - { - -1, /* PRE_V4. */ - -1, /* V4. */ - T(V4T), /* V4T. */ - T(V5T), /* V5T. */ - T(V5TE), /* V5TE. */ - T(V5TEJ), /* V5TEJ. */ - T(V6), /* V6. */ - T(V6KZ), /* V6KZ. */ - T(V6T2), /* V6T2. */ - T(V6K), /* V6K. */ - T(V7), /* V7. */ - T(V6_M), /* V6_M. */ - T(V6S_M), /* V6S_M. */ - T(V7E_M), /* V7E_M. */ - T(V8), /* V8. */ - -1, /* V8R. */ - T(V8M_BASE), /* V8-M BASELINE. */ - T(V8M_MAIN), /* V8-M MAINLINE. */ - T(V4T_PLUS_V6_M) /* V4T plus V6_M. */ - }; - const int *comb[] = - { - v6t2, - v6k, - v7, - v6_m, - v6s_m, - v7e_m, - v8, - v8r, - v8m_baseline, - v8m_mainline, - /* Pseudo-architecture. */ - v4t_plus_v6_m - }; - - /* Check we've not got a higher architecture than we know about. */ - - if (oldtag > MAX_TAG_CPU_ARCH || newtag > MAX_TAG_CPU_ARCH) - { - _bfd_error_handler (_("error: %B: Unknown CPU architecture"), ibfd); - return -1; - } - - /* Override old tag if we have a Tag_also_compatible_with on the output. */ - - if ((oldtag == T(V6_M) && *secondary_compat_out == T(V4T)) - || (oldtag == T(V4T) && *secondary_compat_out == T(V6_M))) - oldtag = T(V4T_PLUS_V6_M); - - /* And override the new tag if we have a Tag_also_compatible_with on the - input. */ - - if ((newtag == T(V6_M) && secondary_compat == T(V4T)) - || (newtag == T(V4T) && secondary_compat == T(V6_M))) - newtag = T(V4T_PLUS_V6_M); - - tagl = (oldtag < newtag) ? oldtag : newtag; - result = tagh = (oldtag > newtag) ? oldtag : newtag; - - /* Architectures before V6KZ add features monotonically. */ - if (tagh <= TAG_CPU_ARCH_V6KZ) - return result; - - result = comb[tagh - T(V6T2)] ? comb[tagh - T(V6T2)][tagl] : -1; - - /* Use Tag_CPU_arch == V4T and Tag_also_compatible_with (Tag_CPU_arch V6_M) - as the canonical version. */ - if (result == T(V4T_PLUS_V6_M)) - { - result = T(V4T); - *secondary_compat_out = T(V6_M); - } - else - *secondary_compat_out = -1; - - if (result == -1) - { - _bfd_error_handler (_("error: %B: Conflicting CPU architectures %d/%d"), - ibfd, oldtag, newtag); - return -1; - } - - return result; -#undef T -} - -/* Query attributes object to see if integer divide instructions may be - present in an object. */ -static bfd_boolean -elf32_arm_attributes_accept_div (const obj_attribute *attr) -{ - int arch = attr[Tag_CPU_arch].i; - int profile = attr[Tag_CPU_arch_profile].i; - - switch (attr[Tag_DIV_use].i) - { - case 0: - /* Integer divide allowed if instruction contained in archetecture. */ - if (arch == TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M')) - return TRUE; - else if (arch >= TAG_CPU_ARCH_V7E_M) - return TRUE; - else - return FALSE; - - case 1: - /* Integer divide explicitly prohibited. */ - return FALSE; - - default: - /* Unrecognised case - treat as allowing divide everywhere. */ - case 2: - /* Integer divide allowed in ARM state. */ - return TRUE; - } -} - -/* Query attributes object to see if integer divide instructions are - forbidden to be in the object. This is not the inverse of - elf32_arm_attributes_accept_div. */ -static bfd_boolean -elf32_arm_attributes_forbid_div (const obj_attribute *attr) -{ - return attr[Tag_DIV_use].i == 1; -} - -/* Merge EABI object attributes from IBFD into OBFD. Raise an error if there - are conflicting attributes. */ - -static bfd_boolean -elf32_arm_merge_eabi_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - obj_attribute *in_attr; - obj_attribute *out_attr; - /* Some tags have 0 = don't care, 1 = strong requirement, - 2 = weak requirement. */ - static const int order_021[3] = {0, 2, 1}; - int i; - bfd_boolean result = TRUE; - const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section; - - /* Skip the linker stubs file. This preserves previous behavior - of accepting unknown attributes in the first input file - but - is that a bug? */ - if (ibfd->flags & BFD_LINKER_CREATED) - return TRUE; - - /* Skip any input that hasn't attribute section. - This enables to link object files without attribute section with - any others. */ - if (bfd_get_section_by_name (ibfd, sec_name) == NULL) - return TRUE; - - if (!elf_known_obj_attributes_proc (obfd)[0].i) - { - /* This is the first object. Copy the attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - out_attr = elf_known_obj_attributes_proc (obfd); - - /* Use the Tag_null value to indicate the attributes have been - initialized. */ - out_attr[0].i = 1; - - /* We do not output objects with Tag_MPextension_use_legacy - we move - the attribute's value to Tag_MPextension_use. */ - if (out_attr[Tag_MPextension_use_legacy].i != 0) - { - if (out_attr[Tag_MPextension_use].i != 0 - && out_attr[Tag_MPextension_use_legacy].i - != out_attr[Tag_MPextension_use].i) - { - _bfd_error_handler - (_("Error: %B has both the current and legacy " - "Tag_MPextension_use attributes"), ibfd); - result = FALSE; - } - - out_attr[Tag_MPextension_use] = - out_attr[Tag_MPextension_use_legacy]; - out_attr[Tag_MPextension_use_legacy].type = 0; - out_attr[Tag_MPextension_use_legacy].i = 0; - } - - return result; - } - - in_attr = elf_known_obj_attributes_proc (ibfd); - out_attr = elf_known_obj_attributes_proc (obfd); - /* This needs to happen before Tag_ABI_FP_number_model is merged. */ - if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i) - { - /* Ignore mismatches if the object doesn't use floating point or is - floating point ABI independent. */ - if (out_attr[Tag_ABI_FP_number_model].i == AEABI_FP_number_model_none - || (in_attr[Tag_ABI_FP_number_model].i != AEABI_FP_number_model_none - && out_attr[Tag_ABI_VFP_args].i == AEABI_VFP_args_compatible)) - out_attr[Tag_ABI_VFP_args].i = in_attr[Tag_ABI_VFP_args].i; - else if (in_attr[Tag_ABI_FP_number_model].i != AEABI_FP_number_model_none - && in_attr[Tag_ABI_VFP_args].i != AEABI_VFP_args_compatible) - { - _bfd_error_handler - (_("error: %B uses VFP register arguments, %B does not"), - in_attr[Tag_ABI_VFP_args].i ? ibfd : obfd, - in_attr[Tag_ABI_VFP_args].i ? obfd : ibfd); - result = FALSE; - } - } - - for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) - { - /* Merge this attribute with existing attributes. */ - switch (i) - { - case Tag_CPU_raw_name: - case Tag_CPU_name: - /* These are merged after Tag_CPU_arch. */ - break; - - case Tag_ABI_optimization_goals: - case Tag_ABI_FP_optimization_goals: - /* Use the first value seen. */ - break; - - case Tag_CPU_arch: - { - int secondary_compat = -1, secondary_compat_out = -1; - unsigned int saved_out_attr = out_attr[i].i; - int arch_attr; - static const char *name_table[] = - { - /* These aren't real CPU names, but we can't guess - that from the architecture version alone. */ - "Pre v4", - "ARM v4", - "ARM v4T", - "ARM v5T", - "ARM v5TE", - "ARM v5TEJ", - "ARM v6", - "ARM v6KZ", - "ARM v6T2", - "ARM v6K", - "ARM v7", - "ARM v6-M", - "ARM v6S-M", - "ARM v8", - "", - "ARM v8-M.baseline", - "ARM v8-M.mainline", - }; - - /* Merge Tag_CPU_arch and Tag_also_compatible_with. */ - secondary_compat = get_secondary_compatible_arch (ibfd); - secondary_compat_out = get_secondary_compatible_arch (obfd); - arch_attr = tag_cpu_arch_combine (ibfd, out_attr[i].i, - &secondary_compat_out, - in_attr[i].i, - secondary_compat); - - /* Return with error if failed to merge. */ - if (arch_attr == -1) - return FALSE; - - out_attr[i].i = arch_attr; - - set_secondary_compatible_arch (obfd, secondary_compat_out); - - /* Merge Tag_CPU_name and Tag_CPU_raw_name. */ - if (out_attr[i].i == saved_out_attr) - ; /* Leave the names alone. */ - else if (out_attr[i].i == in_attr[i].i) - { - /* The output architecture has been changed to match the - input architecture. Use the input names. */ - out_attr[Tag_CPU_name].s = in_attr[Tag_CPU_name].s - ? _bfd_elf_attr_strdup (obfd, in_attr[Tag_CPU_name].s) - : NULL; - out_attr[Tag_CPU_raw_name].s = in_attr[Tag_CPU_raw_name].s - ? _bfd_elf_attr_strdup (obfd, in_attr[Tag_CPU_raw_name].s) - : NULL; - } - else - { - out_attr[Tag_CPU_name].s = NULL; - out_attr[Tag_CPU_raw_name].s = NULL; - } - - /* If we still don't have a value for Tag_CPU_name, - make one up now. Tag_CPU_raw_name remains blank. */ - if (out_attr[Tag_CPU_name].s == NULL - && out_attr[i].i < ARRAY_SIZE (name_table)) - out_attr[Tag_CPU_name].s = - _bfd_elf_attr_strdup (obfd, name_table[out_attr[i].i]); - } - break; - - case Tag_ARM_ISA_use: - case Tag_THUMB_ISA_use: - case Tag_WMMX_arch: - case Tag_Advanced_SIMD_arch: - /* ??? Do Advanced_SIMD (NEON) and WMMX conflict? */ - case Tag_ABI_FP_rounding: - case Tag_ABI_FP_exceptions: - case Tag_ABI_FP_user_exceptions: - case Tag_ABI_FP_number_model: - case Tag_FP_HP_extension: - case Tag_CPU_unaligned_access: - case Tag_T2EE_use: - case Tag_MPextension_use: - /* Use the largest value specified. */ - if (in_attr[i].i > out_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_ABI_align_preserved: - case Tag_ABI_PCS_RO_data: - /* Use the smallest value specified. */ - if (in_attr[i].i < out_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_ABI_align_needed: - if ((in_attr[i].i > 0 || out_attr[i].i > 0) - && (in_attr[Tag_ABI_align_preserved].i == 0 - || out_attr[Tag_ABI_align_preserved].i == 0)) - { - /* This error message should be enabled once all non-conformant - binaries in the toolchain have had the attributes set - properly. - _bfd_error_handler - (_("error: %B: 8-byte data alignment conflicts with %B"), - obfd, ibfd); - result = FALSE; */ - } - /* Fall through. */ - case Tag_ABI_FP_denormal: - case Tag_ABI_PCS_GOT_use: - /* Use the "greatest" from the sequence 0, 2, 1, or the largest - value if greater than 2 (for future-proofing). */ - if ((in_attr[i].i > 2 && in_attr[i].i > out_attr[i].i) - || (in_attr[i].i <= 2 && out_attr[i].i <= 2 - && order_021[in_attr[i].i] > order_021[out_attr[i].i])) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_Virtualization_use: - /* The virtualization tag effectively stores two bits of - information: the intended use of TrustZone (in bit 0), and the - intended use of Virtualization (in bit 1). */ - if (out_attr[i].i == 0) - out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i != 0 - && in_attr[i].i != out_attr[i].i) - { - if (in_attr[i].i <= 3 && out_attr[i].i <= 3) - out_attr[i].i = 3; - else - { - _bfd_error_handler - (_("error: %B: unable to merge virtualization attributes " - "with %B"), - obfd, ibfd); - result = FALSE; - } - } - break; - - case Tag_CPU_arch_profile: - if (out_attr[i].i != in_attr[i].i) - { - /* 0 will merge with anything. - 'A' and 'S' merge to 'A'. - 'R' and 'S' merge to 'R'. - 'M' and 'A|R|S' is an error. */ - if (out_attr[i].i == 0 - || (out_attr[i].i == 'S' - && (in_attr[i].i == 'A' || in_attr[i].i == 'R'))) - out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i == 0 - || (in_attr[i].i == 'S' - && (out_attr[i].i == 'A' || out_attr[i].i == 'R'))) - ; /* Do nothing. */ - else - { - _bfd_error_handler - (_("error: %B: Conflicting architecture profiles %c/%c"), - ibfd, - in_attr[i].i ? in_attr[i].i : '0', - out_attr[i].i ? out_attr[i].i : '0'); - result = FALSE; - } - } - break; - - case Tag_DSP_extension: - /* No need to change output value if any of: - - pre (<=) ARMv5T input architecture (do not have DSP) - - M input profile not ARMv7E-M and do not have DSP. */ - if (in_attr[Tag_CPU_arch].i <= 3 - || (in_attr[Tag_CPU_arch_profile].i == 'M' - && in_attr[Tag_CPU_arch].i != 13 - && in_attr[i].i == 0)) - ; /* Do nothing. */ - /* Output value should be 0 if DSP part of architecture, ie. - - post (>=) ARMv5te architecture output - - A, R or S profile output or ARMv7E-M output architecture. */ - else if (out_attr[Tag_CPU_arch].i >= 4 - && (out_attr[Tag_CPU_arch_profile].i == 'A' - || out_attr[Tag_CPU_arch_profile].i == 'R' - || out_attr[Tag_CPU_arch_profile].i == 'S' - || out_attr[Tag_CPU_arch].i == 13)) - out_attr[i].i = 0; - /* Otherwise, DSP instructions are added and not part of output - architecture. */ - else - out_attr[i].i = 1; - break; - - case Tag_FP_arch: - { - /* Tag_ABI_HardFP_use is handled along with Tag_FP_arch since - the meaning of Tag_ABI_HardFP_use depends on Tag_FP_arch - when it's 0. It might mean absence of FP hardware if - Tag_FP_arch is zero. */ - -#define VFP_VERSION_COUNT 9 - static const struct - { - int ver; - int regs; - } vfp_versions[VFP_VERSION_COUNT] = - { - {0, 0}, - {1, 16}, - {2, 16}, - {3, 32}, - {3, 16}, - {4, 32}, - {4, 16}, - {8, 32}, - {8, 16} - }; - int ver; - int regs; - int newval; - - /* If the output has no requirement about FP hardware, - follow the requirement of the input. */ - if (out_attr[i].i == 0) - { - /* This assert is still reasonable, we shouldn't - produce the suspicious build attribute - combination (See below for in_attr). */ - BFD_ASSERT (out_attr[Tag_ABI_HardFP_use].i == 0); - out_attr[i].i = in_attr[i].i; - out_attr[Tag_ABI_HardFP_use].i - = in_attr[Tag_ABI_HardFP_use].i; - break; - } - /* If the input has no requirement about FP hardware, do - nothing. */ - else if (in_attr[i].i == 0) - { - /* We used to assert that Tag_ABI_HardFP_use was - zero here, but we should never assert when - consuming an object file that has suspicious - build attributes. The single precision variant - of 'no FP architecture' is still 'no FP - architecture', so we just ignore the tag in this - case. */ - break; - } - - /* Both the input and the output have nonzero Tag_FP_arch. - So Tag_ABI_HardFP_use is implied by Tag_FP_arch when it's zero. */ - - /* If both the input and the output have zero Tag_ABI_HardFP_use, - do nothing. */ - if (in_attr[Tag_ABI_HardFP_use].i == 0 - && out_attr[Tag_ABI_HardFP_use].i == 0) - ; - /* If the input and the output have different Tag_ABI_HardFP_use, - the combination of them is 0 (implied by Tag_FP_arch). */ - else if (in_attr[Tag_ABI_HardFP_use].i - != out_attr[Tag_ABI_HardFP_use].i) - out_attr[Tag_ABI_HardFP_use].i = 0; - - /* Now we can handle Tag_FP_arch. */ - - /* Values of VFP_VERSION_COUNT or more aren't defined, so just - pick the biggest. */ - if (in_attr[i].i >= VFP_VERSION_COUNT - && in_attr[i].i > out_attr[i].i) - { - out_attr[i] = in_attr[i]; - break; - } - /* The output uses the superset of input features - (ISA version) and registers. */ - ver = vfp_versions[in_attr[i].i].ver; - if (ver < vfp_versions[out_attr[i].i].ver) - ver = vfp_versions[out_attr[i].i].ver; - regs = vfp_versions[in_attr[i].i].regs; - if (regs < vfp_versions[out_attr[i].i].regs) - regs = vfp_versions[out_attr[i].i].regs; - /* This assumes all possible supersets are also a valid - options. */ - for (newval = VFP_VERSION_COUNT - 1; newval > 0; newval--) - { - if (regs == vfp_versions[newval].regs - && ver == vfp_versions[newval].ver) - break; - } - out_attr[i].i = newval; - } - break; - case Tag_PCS_config: - if (out_attr[i].i == 0) - out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i != 0 && out_attr[i].i != in_attr[i].i) - { - /* It's sometimes ok to mix different configs, so this is only - a warning. */ - _bfd_error_handler - (_("Warning: %B: Conflicting platform configuration"), ibfd); - } - break; - case Tag_ABI_PCS_R9_use: - if (in_attr[i].i != out_attr[i].i - && out_attr[i].i != AEABI_R9_unused - && in_attr[i].i != AEABI_R9_unused) - { - _bfd_error_handler - (_("error: %B: Conflicting use of R9"), ibfd); - result = FALSE; - } - if (out_attr[i].i == AEABI_R9_unused) - out_attr[i].i = in_attr[i].i; - break; - case Tag_ABI_PCS_RW_data: - if (in_attr[i].i == AEABI_PCS_RW_data_SBrel - && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_SB - && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_unused) - { - _bfd_error_handler - (_("error: %B: SB relative addressing conflicts with use of R9"), - ibfd); - result = FALSE; - } - /* Use the smallest value specified. */ - if (in_attr[i].i < out_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - case Tag_ABI_PCS_wchar_t: - if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i - && !elf_arm_tdata (obfd)->no_wchar_size_warning) - { - _bfd_error_handler - (_("warning: %B uses %u-byte wchar_t yet the output is to use %u-byte wchar_t; use of wchar_t values across objects may fail"), - ibfd, in_attr[i].i, out_attr[i].i); - } - else if (in_attr[i].i && !out_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - case Tag_ABI_enum_size: - if (in_attr[i].i != AEABI_enum_unused) - { - if (out_attr[i].i == AEABI_enum_unused - || out_attr[i].i == AEABI_enum_forced_wide) - { - /* The existing object is compatible with anything. - Use whatever requirements the new object has. */ - out_attr[i].i = in_attr[i].i; - } - else if (in_attr[i].i != AEABI_enum_forced_wide - && out_attr[i].i != in_attr[i].i - && !elf_arm_tdata (obfd)->no_enum_size_warning) - { - static const char *aeabi_enum_names[] = - { "", "variable-size", "32-bit", "" }; - const char *in_name = - in_attr[i].i < ARRAY_SIZE(aeabi_enum_names) - ? aeabi_enum_names[in_attr[i].i] - : ""; - const char *out_name = - out_attr[i].i < ARRAY_SIZE(aeabi_enum_names) - ? aeabi_enum_names[out_attr[i].i] - : ""; - _bfd_error_handler - (_("warning: %B uses %s enums yet the output is to use %s enums; use of enum values across objects may fail"), - ibfd, in_name, out_name); - } - } - break; - case Tag_ABI_VFP_args: - /* Aready done. */ - break; - case Tag_ABI_WMMX_args: - if (in_attr[i].i != out_attr[i].i) - { - _bfd_error_handler - (_("error: %B uses iWMMXt register arguments, %B does not"), - ibfd, obfd); - result = FALSE; - } - break; - case Tag_compatibility: - /* Merged in target-independent code. */ - break; - case Tag_ABI_HardFP_use: - /* This is handled along with Tag_FP_arch. */ - break; - case Tag_ABI_FP_16bit_format: - if (in_attr[i].i != 0 && out_attr[i].i != 0) - { - if (in_attr[i].i != out_attr[i].i) - { - _bfd_error_handler - (_("error: fp16 format mismatch between %B and %B"), - ibfd, obfd); - result = FALSE; - } - } - if (in_attr[i].i != 0) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_DIV_use: - /* A value of zero on input means that the divide instruction may - be used if available in the base architecture as specified via - Tag_CPU_arch and Tag_CPU_arch_profile. A value of 1 means that - the user did not want divide instructions. A value of 2 - explicitly means that divide instructions were allowed in ARM - and Thumb state. */ - if (in_attr[i].i == out_attr[i].i) - /* Do nothing. */ ; - else if (elf32_arm_attributes_forbid_div (in_attr) - && !elf32_arm_attributes_accept_div (out_attr)) - out_attr[i].i = 1; - else if (elf32_arm_attributes_forbid_div (out_attr) - && elf32_arm_attributes_accept_div (in_attr)) - out_attr[i].i = in_attr[i].i; - else if (in_attr[i].i == 2) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_MPextension_use_legacy: - /* We don't output objects with Tag_MPextension_use_legacy - we - move the value to Tag_MPextension_use. */ - if (in_attr[i].i != 0 && in_attr[Tag_MPextension_use].i != 0) - { - if (in_attr[Tag_MPextension_use].i != in_attr[i].i) - { - _bfd_error_handler - (_("%B has both the current and legacy " - "Tag_MPextension_use attributes"), - ibfd); - result = FALSE; - } - } - - if (in_attr[i].i > out_attr[Tag_MPextension_use].i) - out_attr[Tag_MPextension_use] = in_attr[i]; - - break; - - case Tag_nodefaults: - /* This tag is set if it exists, but the value is unused (and is - typically zero). We don't actually need to do anything here - - the merge happens automatically when the type flags are merged - below. */ - break; - case Tag_also_compatible_with: - /* Already done in Tag_CPU_arch. */ - break; - case Tag_conformance: - /* Keep the attribute if it matches. Throw it away otherwise. - No attribute means no claim to conform. */ - if (!in_attr[i].s || !out_attr[i].s - || strcmp (in_attr[i].s, out_attr[i].s) != 0) - out_attr[i].s = NULL; - break; - - default: - result - = result && _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i); - } - - /* If out_attr was copied from in_attr then it won't have a type yet. */ - if (in_attr[i].type && !out_attr[i].type) - out_attr[i].type = in_attr[i].type; - } - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - if (!_bfd_elf_merge_object_attributes (ibfd, info)) - return FALSE; - - /* Check for any attributes not known on ARM. */ - result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd); - - return result; -} - - -/* Return TRUE if the two EABI versions are incompatible. */ - -static bfd_boolean -elf32_arm_versions_compatible (unsigned iver, unsigned over) -{ - /* v4 and v5 are the same spec before and after it was released, - so allow mixing them. */ - if ((iver == EF_ARM_EABI_VER4 && over == EF_ARM_EABI_VER5) - || (iver == EF_ARM_EABI_VER5 && over == EF_ARM_EABI_VER4)) - return TRUE; - - return (iver == over); -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf32_arm_merge_private_bfd_data (bfd *, struct bfd_link_info *); - -/* Display the flags field. */ - -static bfd_boolean -elf32_arm_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - unsigned long flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - /* Ignore init flag - it may not be set, despite the flags field - containing valid data. */ - - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - switch (EF_ARM_EABI_VERSION (flags)) - { - case EF_ARM_EABI_UNKNOWN: - /* The following flag bits are GNU extensions and not part of the - official ARM ELF extended ABI. Hence they are only decoded if - the EABI version is not set. */ - if (flags & EF_ARM_INTERWORK) - fprintf (file, _(" [interworking enabled]")); - - if (flags & EF_ARM_APCS_26) - fprintf (file, " [APCS-26]"); - else - fprintf (file, " [APCS-32]"); - - if (flags & EF_ARM_VFP_FLOAT) - fprintf (file, _(" [VFP float format]")); - else if (flags & EF_ARM_MAVERICK_FLOAT) - fprintf (file, _(" [Maverick float format]")); - else - fprintf (file, _(" [FPA float format]")); - - if (flags & EF_ARM_APCS_FLOAT) - fprintf (file, _(" [floats passed in float registers]")); - - if (flags & EF_ARM_PIC) - fprintf (file, _(" [position independent]")); - - if (flags & EF_ARM_NEW_ABI) - fprintf (file, _(" [new ABI]")); - - if (flags & EF_ARM_OLD_ABI) - fprintf (file, _(" [old ABI]")); - - if (flags & EF_ARM_SOFT_FLOAT) - fprintf (file, _(" [software FP]")); - - flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT - | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI - | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT - | EF_ARM_MAVERICK_FLOAT); - break; - - case EF_ARM_EABI_VER1: - fprintf (file, _(" [Version1 EABI]")); - - if (flags & EF_ARM_SYMSARESORTED) - fprintf (file, _(" [sorted symbol table]")); - else - fprintf (file, _(" [unsorted symbol table]")); - - flags &= ~ EF_ARM_SYMSARESORTED; - break; - - case EF_ARM_EABI_VER2: - fprintf (file, _(" [Version2 EABI]")); - - if (flags & EF_ARM_SYMSARESORTED) - fprintf (file, _(" [sorted symbol table]")); - else - fprintf (file, _(" [unsorted symbol table]")); - - if (flags & EF_ARM_DYNSYMSUSESEGIDX) - fprintf (file, _(" [dynamic symbols use segment index]")); - - if (flags & EF_ARM_MAPSYMSFIRST) - fprintf (file, _(" [mapping symbols precede others]")); - - flags &= ~(EF_ARM_SYMSARESORTED | EF_ARM_DYNSYMSUSESEGIDX - | EF_ARM_MAPSYMSFIRST); - break; - - case EF_ARM_EABI_VER3: - fprintf (file, _(" [Version3 EABI]")); - break; - - case EF_ARM_EABI_VER4: - fprintf (file, _(" [Version4 EABI]")); - goto eabi; - - case EF_ARM_EABI_VER5: - fprintf (file, _(" [Version5 EABI]")); - - if (flags & EF_ARM_ABI_FLOAT_SOFT) - fprintf (file, _(" [soft-float ABI]")); - - if (flags & EF_ARM_ABI_FLOAT_HARD) - fprintf (file, _(" [hard-float ABI]")); - - flags &= ~(EF_ARM_ABI_FLOAT_SOFT | EF_ARM_ABI_FLOAT_HARD); - - eabi: - if (flags & EF_ARM_BE8) - fprintf (file, _(" [BE8]")); - - if (flags & EF_ARM_LE8) - fprintf (file, _(" [LE8]")); - - flags &= ~(EF_ARM_LE8 | EF_ARM_BE8); - break; - - default: - fprintf (file, _(" ")); - break; - } - - flags &= ~ EF_ARM_EABIMASK; - - if (flags & EF_ARM_RELEXEC) - fprintf (file, _(" [relocatable executable]")); - - flags &= ~EF_ARM_RELEXEC; - - if (flags) - fprintf (file, _("")); - - fputc ('\n', file); - - return TRUE; -} - -static int -elf32_arm_get_symbol_type (Elf_Internal_Sym * elf_sym, int type) -{ - switch (ELF_ST_TYPE (elf_sym->st_info)) - { - case STT_ARM_TFUNC: - return ELF_ST_TYPE (elf_sym->st_info); - - case STT_ARM_16BIT: - /* If the symbol is not an object, return the STT_ARM_16BIT flag. - This allows us to distinguish between data used by Thumb instructions - and non-data (which is probably code) inside Thumb regions of an - executable. */ - if (type != STT_OBJECT && type != STT_TLS) - return ELF_ST_TYPE (elf_sym->st_info); - break; - - default: - break; - } - - return type; -} - -static asection * -elf32_arm_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_ARM_GNU_VTINHERIT: - case R_ARM_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. */ - -static bfd_boolean -elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd *dynobj; - asection *sreloc; - struct elf32_arm_link_hash_table *htab; - bfd_boolean call_reloc_p; - bfd_boolean may_become_dynamic_p; - bfd_boolean may_need_local_target_p; - unsigned long nsyms; - - if (bfd_link_relocatable (info)) - return TRUE; - - BFD_ASSERT (is_arm_elf (abfd)); - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - sreloc = NULL; - - /* Create dynamic sections for relocatable executables so that we can - copy relocations. */ - if (htab->root.is_relocatable_executable - && ! htab->root.dynamic_sections_created) - { - if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) - return FALSE; - } - - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - if (!create_ifunc_sections (info)) - return FALSE; - - dynobj = htab->root.dynobj; - - symtab_hdr = & elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - nsyms = NUM_SHDR_ENTRIES (symtab_hdr); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - Elf_Internal_Sym *isym; - struct elf_link_hash_entry *h; - struct elf32_arm_link_hash_entry *eh; - unsigned int r_symndx; - int r_type; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - r_type = arm_real_reloc_type (htab, r_type); - - if (r_symndx >= nsyms - /* PR 9934: It is possible to have relocations that do not - refer to symbols, thus it is also possible to have an - object file containing relocations but no symbol table. */ - && (r_symndx > STN_UNDEF || nsyms > 0)) - { - _bfd_error_handler (_("%B: bad symbol index: %d"), abfd, - r_symndx); - return FALSE; - } - - h = NULL; - isym = NULL; - if (nsyms > 0) - { - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - } - 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; - } - } - - eh = (struct elf32_arm_link_hash_entry *) h; - - call_reloc_p = FALSE; - may_become_dynamic_p = FALSE; - may_need_local_target_p = FALSE; - - /* Could be done earlier, if h were already available. */ - r_type = elf32_arm_tls_transition (info, r_type, h); - switch (r_type) - { - case R_ARM_GOT32: - case R_ARM_GOT_PREL: - case R_ARM_TLS_GD32: - case R_ARM_TLS_IE32: - case R_ARM_TLS_GOTDESC: - case R_ARM_TLS_DESCSEQ: - case R_ARM_THM_TLS_DESCSEQ: - case R_ARM_TLS_CALL: - case R_ARM_THM_TLS_CALL: - /* This symbol requires a global offset table entry. */ - { - int tls_type, old_tls_type; - - switch (r_type) - { - case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break; - - case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break; - - case R_ARM_TLS_GOTDESC: - case R_ARM_TLS_CALL: case R_ARM_THM_TLS_CALL: - case R_ARM_TLS_DESCSEQ: case R_ARM_THM_TLS_DESCSEQ: - tls_type = GOT_TLS_GDESC; break; - - default: tls_type = GOT_NORMAL; break; - } - - if (!bfd_link_executable (info) && (tls_type & GOT_TLS_IE)) - info->flags |= DF_STATIC_TLS; - - if (h != NULL) - { - h->got.refcount++; - old_tls_type = elf32_arm_hash_entry (h)->tls_type; - } - else - { - /* This is a global offset table entry for a local symbol. */ - if (!elf32_arm_allocate_local_sym_info (abfd)) - return FALSE; - elf_local_got_refcounts (abfd)[r_symndx] += 1; - old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx]; - } - - /* If a variable is accessed with both tls methods, two - slots may be created. */ - if (GOT_TLS_GD_ANY_P (old_tls_type) - && GOT_TLS_GD_ANY_P (tls_type)) - tls_type |= old_tls_type; - - /* We will already have issued an error message if there - is a TLS/non-TLS mismatch, based on the symbol - type. So just combine any TLS types needed. */ - if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL - && tls_type != GOT_NORMAL) - tls_type |= old_tls_type; - - /* If the symbol is accessed in both IE and GDESC - method, we're able to relax. Turn off the GDESC flag, - without messing up with any other kind of tls types - that may be involved. */ - if ((tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_GDESC)) - tls_type &= ~GOT_TLS_GDESC; - - if (old_tls_type != tls_type) - { - if (h != NULL) - elf32_arm_hash_entry (h)->tls_type = tls_type; - else - elf32_arm_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - } - /* Fall through. */ - - case R_ARM_TLS_LDM32: - if (r_type == R_ARM_TLS_LDM32) - htab->tls_ldm_got.refcount++; - /* Fall through. */ - - case R_ARM_GOTOFF32: - case R_ARM_GOTPC: - if (htab->root.sgot == NULL - && !create_got_section (htab->root.dynobj, info)) - return FALSE; - break; - - case R_ARM_PC24: - case R_ARM_PLT32: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PREL31: - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - case R_ARM_THM_JUMP19: - call_reloc_p = TRUE; - may_need_local_target_p = TRUE; - break; - - case R_ARM_ABS12: - /* VxWorks uses dynamic R_ARM_ABS12 relocations for - ldr __GOTT_INDEX__ offsets. */ - if (!htab->vxworks_p) - { - may_need_local_target_p = TRUE; - break; - } - else goto jump_over; - - /* Fall through. */ - - case R_ARM_MOVW_ABS_NC: - case R_ARM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - if (bfd_link_pic (info)) - { - _bfd_error_handler - (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), - abfd, elf32_arm_howto_table_1[r_type].name, - (h) ? h->root.root.string : "a local symbol"); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Fall through. */ - case R_ARM_ABS32: - case R_ARM_ABS32_NOI: - jump_over: - if (h != NULL && bfd_link_executable (info)) - { - h->pointer_equality_needed = 1; - } - /* Fall through. */ - case R_ARM_REL32: - case R_ARM_REL32_NOI: - case R_ARM_MOVW_PREL_NC: - case R_ARM_MOVT_PREL: - case R_ARM_THM_MOVW_PREL_NC: - case R_ARM_THM_MOVT_PREL: - - /* Should the interworking branches be listed here? */ - if ((bfd_link_pic (info) || htab->root.is_relocatable_executable) - && (sec->flags & SEC_ALLOC) != 0) - { - if (h == NULL - && elf32_arm_howto_from_type (r_type)->pc_relative) - { - /* In shared libraries and relocatable executables, - we treat local relative references as calls; - see the related SYMBOL_CALLS_LOCAL code in - allocate_dynrelocs. */ - call_reloc_p = TRUE; - may_need_local_target_p = TRUE; - } - else - /* We are creating a shared library or relocatable - executable, and this is a reloc against a global symbol, - or a non-PC-relative reloc against a local symbol. - We may need to copy the reloc into the output. */ - may_become_dynamic_p = TRUE; - } - else - may_need_local_target_p = TRUE; - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_ARM_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_ARM_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - } - - if (h != NULL) - { - if (call_reloc_p) - /* We may need a .plt entry if the function this reloc - refers to is in a different object, regardless of the - symbol's type. We can't tell for sure yet, because - something later might force the symbol local. */ - h->needs_plt = 1; - else if (may_need_local_target_p) - /* 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; - } - - if (may_need_local_target_p - && (h != NULL || ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)) - { - union gotplt_union *root_plt; - struct arm_plt_info *arm_plt; - struct arm_local_iplt_info *local_iplt; - - if (h != NULL) - { - root_plt = &h->plt; - arm_plt = &eh->plt; - } - else - { - local_iplt = elf32_arm_create_local_iplt (abfd, r_symndx); - if (local_iplt == NULL) - return FALSE; - root_plt = &local_iplt->root; - arm_plt = &local_iplt->arm; - } - - /* If the symbol is a function that doesn't bind locally, - this relocation will need a PLT entry. */ - if (root_plt->refcount != -1) - root_plt->refcount += 1; - - if (!call_reloc_p) - arm_plt->noncall_refcount++; - - /* It's too early to use htab->use_blx here, so we have to - record possible blx references separately from - relocs that definitely need a thumb stub. */ - - if (r_type == R_ARM_THM_CALL) - arm_plt->maybe_thumb_refcount += 1; - - if (r_type == R_ARM_THM_JUMP24 - || r_type == R_ARM_THM_JUMP19) - arm_plt->thumb_refcount += 1; - } - - if (may_become_dynamic_p) - { - struct elf_dyn_relocs *p, **head; - - /* Create a reloc section in dynobj. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, ! htab->use_rel); - - if (sreloc == NULL) - return FALSE; - - /* BPABI objects never have dynamic relocations mapped. */ - if (htab->symbian_p) - { - flagword flags; - - flags = bfd_get_section_flags (dynobj, sreloc); - flags &= ~(SEC_LOAD | SEC_ALLOC); - bfd_set_section_flags (dynobj, sreloc, flags); - } - } - - /* If this is a global symbol, count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf32_arm_link_hash_entry *) h)->dyn_relocs; - else - { - head = elf32_arm_get_local_dynreloc_list (abfd, r_symndx, isym); - if (head == NULL) - return FALSE; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - - p = (struct elf_dyn_relocs *) bfd_alloc (htab->root.dynobj, amt); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - if (elf32_arm_howto_from_type (r_type)->pc_relative) - p->pc_count += 1; - p->count += 1; - } - } - - return TRUE; -} - -static void -elf32_arm_update_relocs (asection *o, - struct bfd_elf_section_reloc_data *reldata) -{ - void (*swap_in) (bfd *, const bfd_byte *, Elf_Internal_Rela *); - void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); - const struct elf_backend_data *bed; - _arm_elf_section_data *eado; - struct bfd_link_order *p; - bfd_byte *erela_head, *erela; - Elf_Internal_Rela *irela_head, *irela; - Elf_Internal_Shdr *rel_hdr; - bfd *abfd; - unsigned int count; - - eado = get_arm_elf_section_data (o); - - if (!eado || eado->elf.this_hdr.sh_type != SHT_ARM_EXIDX) - return; - - abfd = o->owner; - bed = get_elf_backend_data (abfd); - rel_hdr = reldata->hdr; - - 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 (); - - erela_head = rel_hdr->contents; - irela_head = (Elf_Internal_Rela *) bfd_zmalloc - ((NUM_SHDR_ENTRIES (rel_hdr) + 1) * sizeof (*irela_head)); - - erela = erela_head; - irela = irela_head; - count = 0; - - for (p = o->map_head.link_order; p; p = p->next) - { - if (p->type == bfd_section_reloc_link_order - || p->type == bfd_symbol_reloc_link_order) - { - (*swap_in) (abfd, erela, irela); - erela += rel_hdr->sh_entsize; - irela++; - count++; - } - else if (p->type == bfd_indirect_link_order) - { - struct bfd_elf_section_reloc_data *input_reldata; - arm_unwind_table_edit *edit_list, *edit_tail; - _arm_elf_section_data *eadi; - bfd_size_type j; - bfd_vma offset; - asection *i; - - i = p->u.indirect.section; - - eadi = get_arm_elf_section_data (i); - edit_list = eadi->u.exidx.unwind_edit_list; - edit_tail = eadi->u.exidx.unwind_edit_tail; - offset = o->vma + i->output_offset; - - if (eadi->elf.rel.hdr && - eadi->elf.rel.hdr->sh_entsize == rel_hdr->sh_entsize) - input_reldata = &eadi->elf.rel; - else if (eadi->elf.rela.hdr && - eadi->elf.rela.hdr->sh_entsize == rel_hdr->sh_entsize) - input_reldata = &eadi->elf.rela; - else - abort (); - - if (edit_list) - { - for (j = 0; j < NUM_SHDR_ENTRIES (input_reldata->hdr); j++) - { - arm_unwind_table_edit *edit_node, *edit_next; - bfd_vma bias; - bfd_vma reloc_index; - - (*swap_in) (abfd, erela, irela); - reloc_index = (irela->r_offset - offset) / 8; - - bias = 0; - edit_node = edit_list; - for (edit_next = edit_list; - edit_next && edit_next->index <= reloc_index; - edit_next = edit_node->next) - { - bias++; - edit_node = edit_next; - } - - if (edit_node->type != DELETE_EXIDX_ENTRY - || edit_node->index != reloc_index) - { - irela->r_offset -= bias * 8; - irela++; - count++; - } - - erela += rel_hdr->sh_entsize; - } - - if (edit_tail->type == INSERT_EXIDX_CANTUNWIND_AT_END) - { - /* New relocation entity. */ - asection *text_sec = edit_tail->linked_section; - asection *text_out = text_sec->output_section; - bfd_vma exidx_offset = offset + i->size - 8; - - irela->r_addend = 0; - irela->r_offset = exidx_offset; - irela->r_info = ELF32_R_INFO - (text_out->target_index, R_ARM_PREL31); - irela++; - count++; - } - } - else - { - for (j = 0; j < NUM_SHDR_ENTRIES (input_reldata->hdr); j++) - { - (*swap_in) (abfd, erela, irela); - erela += rel_hdr->sh_entsize; - irela++; - } - - count += NUM_SHDR_ENTRIES (input_reldata->hdr); - } - } - } - - reldata->count = count; - rel_hdr->sh_size = count * rel_hdr->sh_entsize; - - erela = erela_head; - irela = irela_head; - while (count > 0) - { - (*swap_out) (abfd, irela, erela); - erela += rel_hdr->sh_entsize; - irela++; - count--; - } - - free (irela_head); - - /* Hashes are no longer valid. */ - free (reldata->hashes); - reldata->hashes = NULL; -} - -/* Unwinding tables are not referenced directly. This pass marks them as - required if the corresponding code section is marked. Similarly, ARMv8-M - secure entry functions can only be referenced by SG veneers which are - created after the GC process. They need to be marked in case they reside in - their own section (as would be the case if code was compiled with - -ffunction-sections). */ - -static bfd_boolean -elf32_arm_gc_mark_extra_sections (struct bfd_link_info *info, - elf_gc_mark_hook_fn gc_mark_hook) -{ - bfd *sub; - Elf_Internal_Shdr **elf_shdrp; - asection *cmse_sec; - obj_attribute *out_attr; - Elf_Internal_Shdr *symtab_hdr; - unsigned i, sym_count, ext_start; - const struct elf_backend_data *bed; - struct elf_link_hash_entry **sym_hashes; - struct elf32_arm_link_hash_entry *cmse_hash; - bfd_boolean again, is_v8m, first_bfd_browse = TRUE; - - _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); - - out_attr = elf_known_obj_attributes_proc (info->output_bfd); - is_v8m = out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V8M_BASE - && out_attr[Tag_CPU_arch_profile].i == 'M'; - - /* Marking EH data may cause additional code sections to be marked, - requiring multiple passes. */ - again = TRUE; - while (again) - { - again = FALSE; - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - asection *o; - - if (! is_arm_elf (sub)) - continue; - - elf_shdrp = elf_elfsections (sub); - for (o = sub->sections; o != NULL; o = o->next) - { - Elf_Internal_Shdr *hdr; - - hdr = &elf_section_data (o)->this_hdr; - if (hdr->sh_type == SHT_ARM_EXIDX - && hdr->sh_link - && hdr->sh_link < elf_numsections (sub) - && !o->gc_mark - && elf_shdrp[hdr->sh_link]->bfd_section->gc_mark) - { - again = TRUE; - if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) - return FALSE; - } - } - - /* Mark section holding ARMv8-M secure entry functions. We mark all - of them so no need for a second browsing. */ - if (is_v8m && first_bfd_browse) - { - sym_hashes = elf_sym_hashes (sub); - bed = get_elf_backend_data (sub); - symtab_hdr = &elf_tdata (sub)->symtab_hdr; - sym_count = symtab_hdr->sh_size / bed->s->sizeof_sym; - ext_start = symtab_hdr->sh_info; - - /* Scan symbols. */ - for (i = ext_start; i < sym_count; i++) - { - cmse_hash = elf32_arm_hash_entry (sym_hashes[i - ext_start]); - - /* Assume it is a special symbol. If not, cmse_scan will - warn about it and user can do something about it. */ - if (ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal)) - { - cmse_sec = cmse_hash->root.root.u.def.section; - if (!cmse_sec->gc_mark - && !_bfd_elf_gc_mark (info, cmse_sec, gc_mark_hook)) - return FALSE; - } - } - } - } - first_bfd_browse = FALSE; - } - - return TRUE; -} - -/* Treat mapping symbols as special target symbols. */ - -static bfd_boolean -elf32_arm_is_target_special_symbol (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym) -{ - return bfd_is_arm_special_symbol_name (sym->name, - BFD_ARM_SPECIAL_SYM_TYPE_ANY); -} - -/* This is a copy of elf_find_function() from elf.c except that - ARM mapping symbols are ignored when looking for function names - and STT_ARM_TFUNC is considered to a function type. */ - -static bfd_boolean -arm_elf_find_function (bfd * abfd ATTRIBUTE_UNUSED, - asymbol ** symbols, - asection * section, - bfd_vma offset, - const char ** filename_ptr, - const char ** functionname_ptr) -{ - const char * filename = NULL; - asymbol * func = NULL; - bfd_vma low_func = 0; - asymbol ** p; - - 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: - filename = bfd_asymbol_name (&q->symbol); - break; - case STT_FUNC: - case STT_ARM_TFUNC: - case STT_NOTYPE: - /* Skip mapping symbols. */ - if ((q->symbol.flags & BSF_LOCAL) - && bfd_is_arm_special_symbol_name (q->symbol.name, - BFD_ARM_SPECIAL_SYM_TYPE_ANY)) - continue; - /* Fall through. */ - if (bfd_get_section (&q->symbol) == section - && q->symbol.value >= low_func - && q->symbol.value <= offset) - { - func = (asymbol *) q; - low_func = q->symbol.value; - } - break; - } - } - - if (func == NULL) - return FALSE; - - if (filename_ptr) - *filename_ptr = filename; - if (functionname_ptr) - *functionname_ptr = bfd_asymbol_name (func); - - return TRUE; -} - - -/* Find the nearest line to a particular section and offset, for error - reporting. This code is a duplicate of the code in elf.c, except - that it uses arm_elf_find_function. */ - -static bfd_boolean -elf32_arm_find_nearest_line (bfd * abfd, - asymbol ** symbols, - asection * section, - bfd_vma offset, - const char ** filename_ptr, - const char ** functionname_ptr, - unsigned int * line_ptr, - unsigned int * discriminator_ptr) -{ - bfd_boolean found = FALSE; - - if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, - filename_ptr, functionname_ptr, - line_ptr, discriminator_ptr, - dwarf_debug_sections, 0, - & elf_tdata (abfd)->dwarf2_find_line_info)) - { - if (!*functionname_ptr) - arm_elf_find_function (abfd, symbols, section, offset, - *filename_ptr ? NULL : filename_ptr, - functionname_ptr); - - return TRUE; - } - - /* Skip _bfd_dwarf1_find_nearest_line since no known ARM toolchain - uses DWARF1. */ - - 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 (! arm_elf_find_function (abfd, symbols, section, offset, - filename_ptr, functionname_ptr)) - return FALSE; - - *line_ptr = 0; - return TRUE; -} - -static bfd_boolean -elf32_arm_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; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = elf32_arm_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* 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 -elf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info, - struct elf_link_hash_entry * h) -{ - bfd * dynobj; - asection *s, *srel; - struct elf32_arm_link_hash_entry * eh; - struct elf32_arm_link_hash_table *globals; - - globals = elf32_arm_hash_table (info); - if (globals == NULL) - return FALSE; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->type == STT_GNU_IFUNC - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - eh = (struct elf32_arm_link_hash_entry *) h; - - /* 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->type == STT_GNU_IFUNC || h->needs_plt) - { - /* Calls to STT_GNU_IFUNC symbols always use a PLT, even if the - symbol binds locally. */ - if (h->plt.refcount <= 0 - || (h->type != STT_GNU_IFUNC - && (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 PC24 reloc instead. */ - h->plt.offset = (bfd_vma) -1; - eh->plt.thumb_refcount = 0; - eh->plt.maybe_thumb_refcount = 0; - eh->plt.noncall_refcount = 0; - h->needs_plt = 0; - } - - return TRUE; - } - else - { - /* It's possible that we incorrectly decided a .plt reloc was - needed for an R_ARM_PC24 or similar 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; - eh->plt.thumb_refcount = 0; - eh->plt.maybe_thumb_refcount = 0; - eh->plt.noncall_refcount = 0; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* If there are no non-GOT references, we do not need a copy - relocation. */ - if (!h->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. Relocatable executables - can reference data in shared objects directly, so we don't need to - do anything here. */ - if (bfd_link_pic (info) || globals->root.is_relocatable_executable) - 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. */ - /* If allowed, we must generate a R_ARM_COPY reloc to tell the dynamic - linker to copy the initial value out of the dynamic object and into - the runtime process image. We need to remember the offset into the - .rel(a).bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = globals->root.sdynrelro; - srel = globals->root.sreldynrelro; - } - else - { - s = globals->root.sdynbss; - srel = globals->root.srelbss; - } - if (info->nocopyreloc == 0 - && (h->root.u.def.section->flags & SEC_ALLOC) != 0 - && h->size != 0) - { - elf32_arm_allocate_dynrelocs (info, srel, 1); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs_for_symbol (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info; - struct elf32_arm_link_hash_table *htab; - struct elf32_arm_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - eh = (struct elf32_arm_link_hash_entry *) h; - - info = (struct bfd_link_info *) inf; - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - if ((htab->root.dynamic_sections_created || h->type == STT_GNU_IFUNC) - && 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 - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If the call in the PLT entry binds locally, the associated - GOT entry should use an R_ARM_IRELATIVE relocation instead of - the usual R_ARM_JUMP_SLOT. Put it in the .iplt section rather - than the .plt section. */ - if (h->type == STT_GNU_IFUNC && SYMBOL_CALLS_LOCAL (info, h)) - { - eh->is_iplt = 1; - if (eh->plt.noncall_refcount == 0 - && SYMBOL_REFERENCES_LOCAL (info, h)) - /* All non-call references can be resolved directly. - This means that they can (and in some cases, must) - resolve directly to the run-time target, rather than - to the PLT. That in turns means that any .got entry - would be equal to the .igot.plt entry, so there's - no point having both. */ - h->got.refcount = 0; - } - - if (bfd_link_pic (info) - || eh->is_iplt - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - elf32_arm_allocate_plt_entry (info, eh->is_iplt, &h->plt, &eh->plt); - - /* 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 (! bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = htab->root.splt; - h->root.u.def.value = h->plt.offset; - - /* Make sure the function is not marked as Thumb, in case - it is the target of an ABS32 relocation, which will - point to the PLT entry. */ - ARM_SET_SYM_BRANCH_TYPE (h->target_internal, ST_BRANCH_TO_ARM); - } - - /* VxWorks executables have a second set of relocations for - each PLT entry. They go in a separate relocation section, - which is processed by the kernel loader. */ - if (htab->vxworks_p && !bfd_link_pic (info)) - { - /* There is a relocation for the initial PLT entry: - an R_ARM_32 relocation for _GLOBAL_OFFSET_TABLE_. */ - if (h->plt.offset == htab->plt_header_size) - elf32_arm_allocate_dynrelocs (info, htab->srelplt2, 1); - - /* There are two extra relocations for each subsequent - PLT entry: an R_ARM_32 relocation for the GOT entry, - and an R_ARM_32 relocation for the PLT entry. */ - elf32_arm_allocate_dynrelocs (info, htab->srelplt2, 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 elf32_arm_link_hash_entry *) h; - eh->tlsdesc_got = (bfd_vma) -1; - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = elf32_arm_hash_entry (h)->tls_type; - int indx; - - /* 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 - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (!htab->symbian_p) - { - s = htab->root.sgot; - h->got.offset = s->size; - - if (tls_type == GOT_UNKNOWN) - abort (); - - if (tls_type == GOT_NORMAL) - /* Non-TLS symbols need one GOT slot. */ - s->size += 4; - else - { - if (tls_type & GOT_TLS_GDESC) - { - /* R_ARM_TLS_DESC needs 2 GOT slots. */ - eh->tlsdesc_got - = (htab->root.sgotplt->size - - elf32_arm_compute_jump_table_size (htab)); - htab->root.sgotplt->size += 8; - h->got.offset = (bfd_vma) -2; - /* plt.got_offset needs to know there's a TLS_DESC - reloc in the middle of .got.plt. */ - htab->num_tls_desc++; - } - - if (tls_type & GOT_TLS_GD) - { - /* R_ARM_TLS_GD32 needs 2 consecutive GOT slots. If - the symbol is both GD and GDESC, got.offset may - have been overwritten. */ - h->got.offset = s->size; - s->size += 8; - } - - if (tls_type & GOT_TLS_IE) - /* R_ARM_TLS_IE32 needs one GOT slot. */ - s->size += 4; - } - - dyn = htab->root.dynamic_sections_created; - - indx = 0; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - indx = h->dynindx; - - if (tls_type != GOT_NORMAL - && (bfd_link_pic (info) || indx != 0) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - { - if (tls_type & GOT_TLS_IE) - elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); - - if (tls_type & GOT_TLS_GD) - elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); - - if (tls_type & GOT_TLS_GDESC) - { - elf32_arm_allocate_dynrelocs (info, htab->root.srelplt, 1); - /* GDESC needs a trampoline to jump to. */ - htab->tls_trampoline = -1; - } - - /* Only GD needs it. GDESC just emits one relocation per - 2 entries. */ - if ((tls_type & GOT_TLS_GD) && indx != 0) - elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); - } - else if (indx != -1 && !SYMBOL_REFERENCES_LOCAL (info, h)) - { - if (htab->root.dynamic_sections_created) - /* Reserve room for the GOT entry's R_ARM_GLOB_DAT relocation. */ - elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); - } - else if (h->type == STT_GNU_IFUNC - && eh->plt.noncall_refcount == 0) - /* No non-call references resolve the STT_GNU_IFUNC's PLT entry; - they all resolve dynamically instead. Reserve room for the - GOT entry's R_ARM_IRELATIVE relocation. */ - elf32_arm_allocate_irelocs (info, htab->root.srelgot, 1); - else if (bfd_link_pic (info) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - /* Reserve room for the GOT entry's R_ARM_RELATIVE relocation. */ - elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); - } - } - else - h->got.offset = (bfd_vma) -1; - - /* Allocate stubs for exported Thumb functions on v4t. */ - if (!htab->use_blx && h->dynindx != -1 - && h->def_regular - && ARM_GET_SYM_BRANCH_TYPE (h->target_internal) == ST_BRANCH_TO_THUMB - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - { - struct elf_link_hash_entry * th; - struct bfd_link_hash_entry * bh; - struct elf_link_hash_entry * myh; - char name[1024]; - asection *s; - bh = NULL; - /* Create a new symbol to regist the real location of the function. */ - s = h->root.u.def.section; - sprintf (name, "__real_%s", h->root.root.string); - _bfd_generic_link_add_one_symbol (info, s->owner, - name, BSF_GLOBAL, s, - h->root.u.def.value, - NULL, TRUE, FALSE, &bh); - - myh = (struct elf_link_hash_entry *) bh; - myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - myh->forced_local = 1; - ARM_SET_SYM_BRANCH_TYPE (myh->target_internal, ST_BRANCH_TO_THUMB); - eh->export_glue = myh; - th = record_arm_to_thumb_glue (info, h); - /* Point the symbol at the stub. */ - h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC); - ARM_SET_SYM_BRANCH_TYPE (h->target_internal, ST_BRANCH_TO_ARM); - h->root.u.def.section = th->root.u.def.section; - h->root.u.def.value = th->root.u.def.value & ~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 (bfd_link_pic (info) || htab->root.is_relocatable_executable) - { - /* Relocs that use pc_count are PC-relative forms, which will appear - on something like ".long foo - ." or "movw REG, 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_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; - } - } - - if (htab->vxworks_p) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - if (strcmp (p->sec->output_section->name, ".tls_vars") == 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 - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - 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 (htab->root.is_relocatable_executable && h->dynindx == -1 - && h->root.type == bfd_link_hash_new) - { - /* Output absolute symbols so that we can create relocations - against them. For normal symbols we output a relocation - against the section that contains them. */ - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 && !h->forced_local - && h->root.type == bfd_link_hash_undefweak) - { - 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; - if (h->type == STT_GNU_IFUNC - && eh->plt.noncall_refcount == 0 - && SYMBOL_REFERENCES_LOCAL (info, h)) - elf32_arm_allocate_irelocs (info, sreloc, p->count); - else - elf32_arm_allocate_dynrelocs (info, sreloc, p->count); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -void -bfd_elf32_arm_set_byteswap_code (struct bfd_link_info *info, - int byteswap_code) -{ - struct elf32_arm_link_hash_table *globals; - - globals = elf32_arm_hash_table (info); - if (globals == NULL) - return; - - globals->byteswap_code = byteswap_code; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info) -{ - bfd * dynobj; - asection * s; - bfd_boolean plt; - bfd_boolean relocs; - bfd *ibfd; - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - check_use_blx (htab); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - struct arm_local_iplt_info **local_iplt_ptr, *local_iplt; - char *local_tls_type; - bfd_vma *local_tlsdesc_gotent; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - bfd_boolean is_vxworks = htab->vxworks_p; - unsigned int symndx; - - if (! is_arm_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = (struct elf_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 (is_vxworks - && strcmp (p->sec->output_section->name, - ".tls_vars") == 0) - { - /* Relocations in vxworks .tls_vars sections are - handled specially by the loader. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - elf32_arm_allocate_dynrelocs (info, srel, p->count); - 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_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - local_iplt_ptr = elf32_arm_local_iplt (ibfd); - local_tls_type = elf32_arm_local_got_tls_type (ibfd); - local_tlsdesc_gotent = elf32_arm_local_tlsdesc_gotent (ibfd); - symndx = 0; - s = htab->root.sgot; - srel = htab->root.srelgot; - for (; local_got < end_local_got; - ++local_got, ++local_iplt_ptr, ++local_tls_type, - ++local_tlsdesc_gotent, ++symndx) - { - *local_tlsdesc_gotent = (bfd_vma) -1; - local_iplt = *local_iplt_ptr; - if (local_iplt != NULL) - { - struct elf_dyn_relocs *p; - - if (local_iplt->root.refcount > 0) - { - elf32_arm_allocate_plt_entry (info, TRUE, - &local_iplt->root, - &local_iplt->arm); - if (local_iplt->arm.noncall_refcount == 0) - /* All references to the PLT are calls, so all - non-call references can resolve directly to the - run-time target. This means that the .got entry - would be the same as the .igot.plt entry, so there's - no point creating both. */ - *local_got = 0; - } - else - { - BFD_ASSERT (local_iplt->arm.noncall_refcount == 0); - local_iplt->root.offset = (bfd_vma) -1; - } - - for (p = local_iplt->dyn_relocs; p != NULL; p = p->next) - { - asection *psrel; - - psrel = elf_section_data (p->sec)->sreloc; - if (local_iplt->arm.noncall_refcount == 0) - elf32_arm_allocate_irelocs (info, psrel, p->count); - else - elf32_arm_allocate_dynrelocs (info, psrel, p->count); - } - } - if (*local_got > 0) - { - Elf_Internal_Sym *isym; - - *local_got = s->size; - if (*local_tls_type & GOT_TLS_GD) - /* TLS_GD relocs need an 8-byte structure in the GOT. */ - s->size += 8; - if (*local_tls_type & GOT_TLS_GDESC) - { - *local_tlsdesc_gotent = htab->root.sgotplt->size - - elf32_arm_compute_jump_table_size (htab); - htab->root.sgotplt->size += 8; - *local_got = (bfd_vma) -2; - /* plt.got_offset needs to know there's a TLS_DESC - reloc in the middle of .got.plt. */ - htab->num_tls_desc++; - } - if (*local_tls_type & GOT_TLS_IE) - s->size += 4; - - if (*local_tls_type & GOT_NORMAL) - { - /* If the symbol is both GD and GDESC, *local_got - may have been overwritten. */ - *local_got = s->size; - s->size += 4; - } - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, symndx); - if (isym == NULL) - return FALSE; - - /* If all references to an STT_GNU_IFUNC PLT are calls, - then all non-call references, including this GOT entry, - resolve directly to the run-time target. */ - if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - && (local_iplt == NULL - || local_iplt->arm.noncall_refcount == 0)) - elf32_arm_allocate_irelocs (info, srel, 1); - else if (bfd_link_pic (info) || output_bfd->flags & DYNAMIC) - { - if ((bfd_link_pic (info) && !(*local_tls_type & GOT_TLS_GDESC)) - || *local_tls_type & GOT_TLS_GD) - elf32_arm_allocate_dynrelocs (info, srel, 1); - - if (bfd_link_pic (info) && *local_tls_type & GOT_TLS_GDESC) - { - elf32_arm_allocate_dynrelocs (info, - htab->root.srelplt, 1); - htab->tls_trampoline = -1; - } - } - } - else - *local_got = (bfd_vma) -1; - } - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate two GOT entries and one dynamic relocation (if necessary) - for R_ARM_TLS_LDM32 relocations. */ - htab->tls_ldm_got.offset = htab->root.sgot->size; - htab->root.sgot->size += 8; - if (bfd_link_pic (info)) - elf32_arm_allocate_dynrelocs (info, htab->root.srelgot, 1); - } - 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->root, allocate_dynrelocs_for_symbol, info); - - /* Here we rummage through the found bfds to collect glue information. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - if (! is_arm_elf (ibfd)) - continue; - - /* Initialise mapping tables for code/data. */ - bfd_elf32_arm_init_maps (ibfd); - - if (!bfd_elf32_arm_process_before_allocation (ibfd, info) - || !bfd_elf32_arm_vfp11_erratum_scan (ibfd, info) - || !bfd_elf32_arm_stm32l4xx_erratum_scan (ibfd, info)) - _bfd_error_handler (_("Errors encountered processing file %B"), ibfd); - } - - /* Allocate space for the glue sections now that we've sized them. */ - bfd_elf32_arm_allocate_interworking_sections (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->root.srelplt) - htab->sgotplt_jump_table_size = elf32_arm_compute_jump_table_size(htab); - - if (htab->tls_trampoline) - { - if (htab->root.splt->size == 0) - htab->root.splt->size += htab->plt_header_size; - - htab->tls_trampoline = htab->root.splt->size; - htab->root.splt->size += htab->plt_entry_size; - - /* 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->dt_tlsdesc_got = htab->root.sgot->size; - htab->root.sgot->size += 4; - - htab->dt_tlsdesc_plt = htab->root.splt->size; - htab->root.splt->size += 4 * ARRAY_SIZE (dl_tlsdesc_lazy_trampoline); - } - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char * name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (s == htab->root.splt) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rel")) - { - if (s->size != 0) - { - /* Remember whether there are any reloc sections other - than .rel(a).plt and .rela.plt.unloaded. */ - if (s != htab->root.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 if (s != htab->root.sgot - && s != htab->root.sgotplt - && s != htab->root.iplt - && s != htab->root.igotplt - && s != htab->root.sdynbss - && s != htab->root.sdynrelro) - { - /* 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(a).bss and - .rel(a).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. */ - s->contents = (unsigned char *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf32_arm_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if ( !add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, - htab->use_rel ? DT_REL : DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - - if (htab->dt_tlsdesc_plt - && (!add_dynamic_entry (DT_TLSDESC_PLT,0) - || !add_dynamic_entry (DT_TLSDESC_GOT,0))) - return FALSE; - } - - if (relocs) - { - if (htab->use_rel) - { - if (!add_dynamic_entry (DT_REL, 0) - || !add_dynamic_entry (DT_RELSZ, 0) - || !add_dynamic_entry (DT_RELENT, RELOC_SIZE (htab))) - return FALSE; - } - else - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, RELOC_SIZE (htab))) - return FALSE; - } - } - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - if (htab->vxworks_p - && !elf_vxworks_add_dynamic_entries (output_bfd, info)) - return FALSE; - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Size sections even though they're not dynamic. We use it to setup - _TLS_MODULE_BASE_, if needed. */ - -static bfd_boolean -elf32_arm_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *tls_sec; - - if (bfd_link_relocatable (info)) - return TRUE; - - 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_", TRUE, TRUE, FALSE); - - if (tlsbase) - { - 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->type = STT_TLS; - 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; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf32_arm_finish_dynamic_symbol (bfd * output_bfd, - struct bfd_link_info * info, - struct elf_link_hash_entry * h, - Elf_Internal_Sym * sym) -{ - struct elf32_arm_link_hash_table *htab; - struct elf32_arm_link_hash_entry *eh; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - eh = (struct elf32_arm_link_hash_entry *) h; - - if (h->plt.offset != (bfd_vma) -1) - { - if (!eh->is_iplt) - { - BFD_ASSERT (h->dynindx != -1); - if (! elf32_arm_populate_plt_entry (output_bfd, info, &h->plt, &eh->plt, - h->dynindx, 0)) - return FALSE; - } - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. */ - sym->st_shndx = SHN_UNDEF; - /* If the symbol is weak we need to clear the value. - Otherwise, the PLT entry would provide a definition for - the symbol even if the symbol wasn't defined anywhere, - and so the symbol would never be NULL. 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). */ - if (!h->ref_regular_nonweak || !h->pointer_equality_needed) - sym->st_value = 0; - } - else if (eh->is_iplt && eh->plt.noncall_refcount != 0) - { - /* At least one non-call relocation references this .iplt entry, - so the .iplt entry is the function's canonical address. */ - sym->st_info = ELF_ST_INFO (ELF_ST_BIND (sym->st_info), STT_FUNC); - ARM_SET_SYM_BRANCH_TYPE (sym->st_target_internal, ST_BRANCH_TO_ARM); - sym->st_shndx = (_bfd_elf_section_from_bfd_section - (output_bfd, htab->root.iplt->output_section)); - sym->st_value = (h->plt.offset - + htab->root.iplt->output_section->vma - + htab->root.iplt->output_offset); - } - } - - if (h->needs_copy) - { - asection * s; - Elf_Internal_Rela rel; - - /* This symbol needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - rel.r_addend = 0; - 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_ARM_COPY); - if (h->root.u.def.section == htab->root.sdynrelro) - s = htab->root.sreldynrelro; - else - s = htab->root.srelbss; - elf32_arm_add_dynreloc (output_bfd, info, s, &rel); - } - - /* 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 (h == htab->root.hdynamic - || (!htab->vxworks_p && h == htab->root.hgot)) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -static void -arm_put_trampoline (struct elf32_arm_link_hash_table *htab, bfd *output_bfd, - void *contents, - const unsigned long *template, unsigned count) -{ - unsigned ix; - - for (ix = 0; ix != count; ix++) - { - unsigned long insn = template[ix]; - - /* Emit mov pc,rx if bx is not permitted. */ - if (htab->fix_v4bx == 1 && (insn & 0x0ffffff0) == 0x012fff10) - insn = (insn & 0xf000000f) | 0x01a0f000; - put_arm_insn (htab, output_bfd, insn, (char *)contents + ix*4); - } -} - -/* Install the special first PLT entry for elf32-arm-nacl. Unlike - other variants, NaCl needs this entry in a static executable's - .iplt too. When we're handling that case, GOT_DISPLACEMENT is - zero. For .iplt really only the last bundle is useful, and .iplt - could have a shorter first entry, with each individual PLT entry's - relative branch calculated differently so it targets the last - bundle instead of the instruction before it (labelled .Lplt_tail - above). But it's simpler to keep the size and layout of PLT0 - consistent with the dynamic case, at the cost of some dead code at - the start of .iplt and the one dead store to the stack at the start - of .Lplt_tail. */ -static void -arm_nacl_put_plt0 (struct elf32_arm_link_hash_table *htab, bfd *output_bfd, - asection *plt, bfd_vma got_displacement) -{ - unsigned int i; - - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt0_entry[0] - | arm_movw_immediate (got_displacement), - plt->contents + 0); - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt0_entry[1] - | arm_movt_immediate (got_displacement), - plt->contents + 4); - - for (i = 2; i < ARRAY_SIZE (elf32_arm_nacl_plt0_entry); ++i) - put_arm_insn (htab, output_bfd, - elf32_arm_nacl_plt0_entry[i], - plt->contents + (i * 4)); -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info) -{ - bfd * dynobj; - asection * sgot; - asection * sdyn; - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = elf_hash_table (info)->dynobj; - - sgot = htab->root.sgotplt; - /* A broken linker script might have discarded the dynamic sections. - Catch this here so that we do not seg-fault later on. */ - if (sgot != NULL && bfd_is_abs_section (sgot->output_section)) - return FALSE; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = htab->root.splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - BFD_ASSERT (htab->symbian_p || sgot != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - const char * name; - asection * s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - unsigned int type; - - default: - if (htab->vxworks_p - && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_HASH: - name = ".hash"; - goto get_vma_if_bpabi; - case DT_STRTAB: - name = ".dynstr"; - goto get_vma_if_bpabi; - case DT_SYMTAB: - name = ".dynsym"; - goto get_vma_if_bpabi; - case DT_VERSYM: - name = ".gnu.version"; - goto get_vma_if_bpabi; - case DT_VERDEF: - name = ".gnu.version_d"; - goto get_vma_if_bpabi; - case DT_VERNEED: - name = ".gnu.version_r"; - goto get_vma_if_bpabi; - - case DT_PLTGOT: - name = htab->symbian_p ? ".got" : ".got.plt"; - goto get_vma; - case DT_JMPREL: - name = RELOC_SECTION (htab, ".plt"); - get_vma: - s = bfd_get_linker_section (dynobj, name); - if (s == NULL) - { - _bfd_error_handler - (_("could not find section %s"), name); - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - if (!htab->symbian_p) - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - else - /* In the BPABI, tags in the PT_DYNAMIC section point - at the file offset, not the memory address, for the - convenience of the post linker. */ - dyn.d_un.d_ptr = s->output_section->filepos + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - get_vma_if_bpabi: - if (htab->symbian_p) - goto get_vma; - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - BFD_ASSERT (s != NULL); - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_RELSZ: - case DT_RELASZ: - case DT_REL: - case DT_RELA: - /* In the BPABI, the DT_REL tag must point at the file - offset, not the VMA, of the first relocation - section. So, we use code similar to that in - elflink.c, but do not check for SHF_ALLOC on the - relocation section, since relocation sections are - never allocated under the BPABI. PLT relocs are also - included. */ - if (htab->symbian_p) - { - unsigned int i; - type = ((dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) - ? SHT_REL : SHT_RELA); - dyn.d_un.d_val = 0; - for (i = 1; i < elf_numsections (output_bfd); i++) - { - Elf_Internal_Shdr *hdr - = elf_elfsections (output_bfd)[i]; - if (hdr->sh_type == type) - { - if (dyn.d_tag == DT_RELSZ - || dyn.d_tag == DT_RELASZ) - dyn.d_un.d_val += hdr->sh_size; - else if ((ufile_ptr) hdr->sh_offset - <= dyn.d_un.d_val - 1) - dyn.d_un.d_val = hdr->sh_offset; - } - } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - break; - - case DT_TLSDESC_PLT: - s = htab->root.splt; - dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset - + htab->dt_tlsdesc_plt); - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_TLSDESC_GOT: - s = htab->root.sgot; - dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset - + htab->dt_tlsdesc_got); - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - /* Set the bottom bit of DT_INIT/FINI if the - corresponding function is Thumb. */ - case DT_INIT: - name = info->init_function; - goto get_sym; - case DT_FINI: - name = info->fini_function; - get_sym: - /* If it wasn't set by elf_bfd_final_link - then there is nothing to adjust. */ - if (dyn.d_un.d_val != 0) - { - struct elf_link_hash_entry * eh; - - eh = elf_link_hash_lookup (elf_hash_table (info), name, - FALSE, FALSE, TRUE); - if (eh != NULL - && ARM_GET_SYM_BRANCH_TYPE (eh->target_internal) - == ST_BRANCH_TO_THUMB) - { - dyn.d_un.d_val |= 1; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - if (splt->size > 0 && htab->plt_header_size) - { - const bfd_vma *plt0_entry; - bfd_vma got_address, plt_address, got_displacement; - - /* Calculate the addresses of the GOT and PLT. */ - got_address = sgot->output_section->vma + sgot->output_offset; - plt_address = splt->output_section->vma + splt->output_offset; - - if (htab->vxworks_p) - { - /* The VxWorks GOT is relocated by the dynamic linker. - Therefore, we must emit relocations rather than simply - computing the values now. */ - Elf_Internal_Rela rel; - - plt0_entry = elf32_arm_vxworks_exec_plt0_entry; - put_arm_insn (htab, output_bfd, plt0_entry[0], - splt->contents + 0); - put_arm_insn (htab, output_bfd, plt0_entry[1], - splt->contents + 4); - put_arm_insn (htab, output_bfd, plt0_entry[2], - splt->contents + 8); - bfd_put_32 (output_bfd, got_address, splt->contents + 12); - - /* Generate a relocation for _GLOBAL_OFFSET_TABLE_. */ - rel.r_offset = plt_address + 12; - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32); - rel.r_addend = 0; - SWAP_RELOC_OUT (htab) (output_bfd, &rel, - htab->srelplt2->contents); - } - else if (htab->nacl_p) - arm_nacl_put_plt0 (htab, output_bfd, splt, - got_address + 8 - (plt_address + 16)); - else if (using_thumb_only (htab)) - { - got_displacement = got_address - (plt_address + 12); - - plt0_entry = elf32_thumb2_plt0_entry; - put_arm_insn (htab, output_bfd, plt0_entry[0], - splt->contents + 0); - put_arm_insn (htab, output_bfd, plt0_entry[1], - splt->contents + 4); - put_arm_insn (htab, output_bfd, plt0_entry[2], - splt->contents + 8); - - bfd_put_32 (output_bfd, got_displacement, splt->contents + 12); - } - else - { - got_displacement = got_address - (plt_address + 16); - - plt0_entry = elf32_arm_plt0_entry; - put_arm_insn (htab, output_bfd, plt0_entry[0], - splt->contents + 0); - put_arm_insn (htab, output_bfd, plt0_entry[1], - splt->contents + 4); - put_arm_insn (htab, output_bfd, plt0_entry[2], - splt->contents + 8); - put_arm_insn (htab, output_bfd, plt0_entry[3], - splt->contents + 12); - -#ifdef FOUR_WORD_PLT - /* The displacement value goes in the otherwise-unused - last word of the second entry. */ - bfd_put_32 (output_bfd, got_displacement, splt->contents + 28); -#else - bfd_put_32 (output_bfd, got_displacement, splt->contents + 16); -#endif - } - } - - /* UnixWare sets the entsize of .plt to 4, although that doesn't - really seem like the right value. */ - if (splt->output_section->owner == output_bfd) - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; - - if (htab->dt_tlsdesc_plt) - { - bfd_vma got_address - = sgot->output_section->vma + sgot->output_offset; - bfd_vma gotplt_address = (htab->root.sgot->output_section->vma - + htab->root.sgot->output_offset); - bfd_vma plt_address - = splt->output_section->vma + splt->output_offset; - - arm_put_trampoline (htab, output_bfd, - splt->contents + htab->dt_tlsdesc_plt, - dl_tlsdesc_lazy_trampoline, 6); - - bfd_put_32 (output_bfd, - gotplt_address + htab->dt_tlsdesc_got - - (plt_address + htab->dt_tlsdesc_plt) - - dl_tlsdesc_lazy_trampoline[6], - splt->contents + htab->dt_tlsdesc_plt + 24); - bfd_put_32 (output_bfd, - got_address - (plt_address + htab->dt_tlsdesc_plt) - - dl_tlsdesc_lazy_trampoline[7], - splt->contents + htab->dt_tlsdesc_plt + 24 + 4); - } - - if (htab->tls_trampoline) - { - arm_put_trampoline (htab, output_bfd, - splt->contents + htab->tls_trampoline, - tls_trampoline, 3); -#ifdef FOUR_WORD_PLT - bfd_put_32 (output_bfd, 0x00000000, - splt->contents + htab->tls_trampoline + 12); -#endif - } - - if (htab->vxworks_p - && !bfd_link_pic (info) - && htab->root.splt->size > 0) - { - /* Correct the .rel(a).plt.unloaded relocations. They will have - incorrect symbol indexes. */ - int num_plts; - unsigned char *p; - - num_plts = ((htab->root.splt->size - htab->plt_header_size) - / htab->plt_entry_size); - p = htab->srelplt2->contents + RELOC_SIZE (htab); - - for (; num_plts; num_plts--) - { - Elf_Internal_Rela rel; - - SWAP_RELOC_IN (htab) (output_bfd, p, &rel); - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32); - SWAP_RELOC_OUT (htab) (output_bfd, &rel, p); - p += RELOC_SIZE (htab); - - SWAP_RELOC_IN (htab) (output_bfd, p, &rel); - rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32); - SWAP_RELOC_OUT (htab) (output_bfd, &rel, p); - p += RELOC_SIZE (htab); - } - } - } - - if (htab->nacl_p && htab->root.iplt != NULL && htab->root.iplt->size > 0) - /* NaCl uses a special first entry in .iplt too. */ - arm_nacl_put_plt0 (htab, output_bfd, htab->root.iplt, 0); - - /* Fill in the first three entries in the global offset table. */ - if (sgot) - { - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - return TRUE; -} - -static void -elf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATTRIBUTE_UNUSED) -{ - Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ - struct elf32_arm_link_hash_table *globals; - struct elf_segment_map *m; - - i_ehdrp = elf_elfheader (abfd); - - if (EF_ARM_EABI_VERSION (i_ehdrp->e_flags) == EF_ARM_EABI_UNKNOWN) - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_ARM; - else - _bfd_elf_post_process_headers (abfd, link_info); - i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION; - - if (link_info) - { - globals = elf32_arm_hash_table (link_info); - if (globals != NULL && globals->byteswap_code) - i_ehdrp->e_flags |= EF_ARM_BE8; - } - - if (EF_ARM_EABI_VERSION (i_ehdrp->e_flags) == EF_ARM_EABI_VER5 - && ((i_ehdrp->e_type == ET_DYN) || (i_ehdrp->e_type == ET_EXEC))) - { - int abi = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, Tag_ABI_VFP_args); - if (abi == AEABI_VFP_args_vfp) - i_ehdrp->e_flags |= EF_ARM_ABI_FLOAT_HARD; - else - i_ehdrp->e_flags |= EF_ARM_ABI_FLOAT_SOFT; - } - - /* Scan segment to set p_flags attribute if it contains only sections with - SHF_ARM_PURECODE flag. */ - for (m = elf_seg_map (abfd); m != NULL; m = m->next) - { - unsigned int j; - - if (m->count == 0) - continue; - for (j = 0; j < m->count; j++) - { - if (!(elf_section_flags (m->sections[j]) & SHF_ARM_PURECODE)) - break; - } - if (j == m->count) - { - m->p_flags = PF_X; - m->p_flags_valid = 1; - } - } -} - -static enum elf_reloc_type_class -elf32_arm_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_ARM_RELATIVE: - return reloc_class_relative; - case R_ARM_JUMP_SLOT: - return reloc_class_plt; - case R_ARM_COPY: - return reloc_class_copy; - case R_ARM_IRELATIVE: - return reloc_class_ifunc; - default: - return reloc_class_normal; - } -} - -static void -elf32_arm_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) -{ - bfd_arm_update_notes (abfd, ARM_NOTE_SECTION); -} - -/* Return TRUE if this is an unwinding table entry. */ - -static bfd_boolean -is_arm_elf_unwind_section_name (bfd * abfd ATTRIBUTE_UNUSED, const char * name) -{ - return (CONST_STRNEQ (name, ELF_STRING_ARM_unwind) - || CONST_STRNEQ (name, ELF_STRING_ARM_unwind_once)); -} - - -/* Set the type and flags for an ARM section. We do this by - the section name, which is a hack, but ought to work. */ - -static bfd_boolean -elf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec) -{ - const char * name; - - name = bfd_get_section_name (abfd, sec); - - if (is_arm_elf_unwind_section_name (abfd, name)) - { - hdr->sh_type = SHT_ARM_EXIDX; - hdr->sh_flags |= SHF_LINK_ORDER; - } - - if (sec->flags & SEC_ELF_PURECODE) - hdr->sh_flags |= SHF_ARM_PURECODE; - - return TRUE; -} - -/* Handle an ARM specific section when reading an object file. This is - called when bfd_section_from_shdr finds a section with an unknown - type. */ - -static bfd_boolean -elf32_arm_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr * hdr, - const char *name, - int shindex) -{ - /* There ought to be a place to keep ELF backend specific flags, but - at the moment there isn't one. We just keep track of the - sections by their name, instead. Fortunately, the ABI gives - names for all the ARM specific sections, so we will probably get - away with this. */ - switch (hdr->sh_type) - { - case SHT_ARM_EXIDX: - case SHT_ARM_PREEMPTMAP: - case SHT_ARM_ATTRIBUTES: - break; - - default: - return FALSE; - } - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - return TRUE; -} - -static _arm_elf_section_data * -get_arm_elf_section_data (asection * sec) -{ - if (sec && sec->owner && is_arm_elf (sec->owner)) - return elf32_arm_section_data (sec); - else - return NULL; -} - -typedef struct -{ - void *flaginfo; - struct bfd_link_info *info; - asection *sec; - int sec_shndx; - int (*func) (void *, const char *, Elf_Internal_Sym *, - asection *, struct elf_link_hash_entry *); -} output_arch_syminfo; - -enum map_symbol_type -{ - ARM_MAP_ARM, - ARM_MAP_THUMB, - ARM_MAP_DATA -}; - - -/* Output a single mapping symbol. */ - -static bfd_boolean -elf32_arm_output_map_sym (output_arch_syminfo *osi, - enum map_symbol_type type, - bfd_vma offset) -{ - static const char *names[3] = {"$a", "$t", "$d"}; - Elf_Internal_Sym sym; - - sym.st_value = osi->sec->output_section->vma - + osi->sec->output_offset - + offset; - sym.st_size = 0; - sym.st_other = 0; - sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE); - sym.st_shndx = osi->sec_shndx; - sym.st_target_internal = 0; - elf32_arm_section_map_add (osi->sec, names[type][1], offset); - return osi->func (osi->flaginfo, names[type], &sym, osi->sec, NULL) == 1; -} - -/* Output mapping symbols for the PLT entry described by ROOT_PLT and ARM_PLT. - IS_IPLT_ENTRY_P says whether the PLT is in .iplt rather than .plt. */ - -static bfd_boolean -elf32_arm_output_plt_map_1 (output_arch_syminfo *osi, - bfd_boolean is_iplt_entry_p, - union gotplt_union *root_plt, - struct arm_plt_info *arm_plt) -{ - struct elf32_arm_link_hash_table *htab; - bfd_vma addr, plt_header_size; - - if (root_plt->offset == (bfd_vma) -1) - return TRUE; - - htab = elf32_arm_hash_table (osi->info); - if (htab == NULL) - return FALSE; - - if (is_iplt_entry_p) - { - osi->sec = htab->root.iplt; - plt_header_size = 0; - } - else - { - osi->sec = htab->root.splt; - plt_header_size = htab->plt_header_size; - } - osi->sec_shndx = (_bfd_elf_section_from_bfd_section - (osi->info->output_bfd, osi->sec->output_section)); - - addr = root_plt->offset & -2; - if (htab->symbian_p) - { - if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) - return FALSE; - if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 4)) - return FALSE; - } - else if (htab->vxworks_p) - { - if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) - return FALSE; - if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 8)) - return FALSE; - if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr + 12)) - return FALSE; - if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 20)) - return FALSE; - } - else if (htab->nacl_p) - { - if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) - return FALSE; - } - else if (using_thumb_only (htab)) - { - if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr)) - return FALSE; - } - else - { - bfd_boolean thumb_stub_p; - - thumb_stub_p = elf32_arm_plt_needs_thumb_stub_p (osi->info, arm_plt); - if (thumb_stub_p) - { - if (!elf32_arm_output_map_sym (osi, ARM_MAP_THUMB, addr - 4)) - return FALSE; - } -#ifdef FOUR_WORD_PLT - if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) - return FALSE; - if (!elf32_arm_output_map_sym (osi, ARM_MAP_DATA, addr + 12)) - return FALSE; -#else - /* A three-word PLT with no Thumb thunk contains only Arm code, - so only need to output a mapping symbol for the first PLT entry and - entries with thumb thunks. */ - if (thumb_stub_p || addr == plt_header_size) - { - if (!elf32_arm_output_map_sym (osi, ARM_MAP_ARM, addr)) - return FALSE; - } -#endif - } - - return TRUE; -} - -/* Output mapping symbols for PLT entries associated with H. */ - -static bfd_boolean -elf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf) -{ - output_arch_syminfo *osi = (output_arch_syminfo *) inf; - struct elf32_arm_link_hash_entry *eh; - - 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; - - eh = (struct elf32_arm_link_hash_entry *) h; - return elf32_arm_output_plt_map_1 (osi, SYMBOL_CALLS_LOCAL (osi->info, h), - &h->plt, &eh->plt); -} - -/* Bind a veneered symbol to its veneer identified by its hash entry - STUB_ENTRY. The veneered location thus loose its symbol. */ - -static void -arm_stub_claim_sym (struct elf32_arm_stub_hash_entry *stub_entry) -{ - struct elf32_arm_link_hash_entry *hash = stub_entry->h; - - BFD_ASSERT (hash); - hash->root.root.u.def.section = stub_entry->stub_sec; - hash->root.root.u.def.value = stub_entry->stub_offset; - hash->root.size = stub_entry->stub_size; -} - -/* Output a single local symbol for a generated stub. */ - -static bfd_boolean -elf32_arm_output_stub_sym (output_arch_syminfo *osi, const char *name, - bfd_vma offset, bfd_vma size) -{ - Elf_Internal_Sym sym; - - sym.st_value = osi->sec->output_section->vma - + osi->sec->output_offset - + offset; - sym.st_size = size; - sym.st_other = 0; - sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FUNC); - sym.st_shndx = osi->sec_shndx; - sym.st_target_internal = 0; - return osi->func (osi->flaginfo, name, &sym, osi->sec, NULL) == 1; -} - -static bfd_boolean -arm_map_one_stub (struct bfd_hash_entry * gen_entry, - void * in_arg) -{ - struct elf32_arm_stub_hash_entry *stub_entry; - asection *stub_sec; - bfd_vma addr; - char *stub_name; - output_arch_syminfo *osi; - const insn_sequence *template_sequence; - enum stub_insn_type prev_type; - int size; - int i; - enum map_symbol_type sym_type; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - osi = (output_arch_syminfo *) in_arg; - - stub_sec = stub_entry->stub_sec; - - /* Ensure this stub is attached to the current section being - processed. */ - if (stub_sec != osi->sec) - return TRUE; - - addr = (bfd_vma) stub_entry->stub_offset; - template_sequence = stub_entry->stub_template; - - if (arm_stub_sym_claimed (stub_entry->stub_type)) - arm_stub_claim_sym (stub_entry); - else - { - stub_name = stub_entry->output_name; - switch (template_sequence[0].type) - { - case ARM_TYPE: - if (!elf32_arm_output_stub_sym (osi, stub_name, addr, - stub_entry->stub_size)) - return FALSE; - break; - case THUMB16_TYPE: - case THUMB32_TYPE: - if (!elf32_arm_output_stub_sym (osi, stub_name, addr | 1, - stub_entry->stub_size)) - return FALSE; - break; - default: - BFD_FAIL (); - return 0; - } - } - - prev_type = DATA_TYPE; - size = 0; - for (i = 0; i < stub_entry->stub_template_size; i++) - { - switch (template_sequence[i].type) - { - case ARM_TYPE: - sym_type = ARM_MAP_ARM; - break; - - case THUMB16_TYPE: - case THUMB32_TYPE: - sym_type = ARM_MAP_THUMB; - break; - - case DATA_TYPE: - sym_type = ARM_MAP_DATA; - break; - - default: - BFD_FAIL (); - return FALSE; - } - - if (template_sequence[i].type != prev_type) - { - prev_type = template_sequence[i].type; - if (!elf32_arm_output_map_sym (osi, sym_type, addr + size)) - return FALSE; - } - - switch (template_sequence[i].type) - { - case ARM_TYPE: - case THUMB32_TYPE: - size += 4; - break; - - case THUMB16_TYPE: - size += 2; - break; - - case DATA_TYPE: - size += 4; - break; - - default: - BFD_FAIL (); - return FALSE; - } - } - - return TRUE; -} - -/* Output mapping symbols for linker generated sections, - and for those data-only sections that do not have a - $d. */ - -static bfd_boolean -elf32_arm_output_arch_local_syms (bfd *output_bfd, - struct bfd_link_info *info, - void *flaginfo, - int (*func) (void *, const char *, - Elf_Internal_Sym *, - asection *, - struct elf_link_hash_entry *)) -{ - output_arch_syminfo osi; - struct elf32_arm_link_hash_table *htab; - bfd_vma offset; - bfd_size_type size; - bfd *input_bfd; - - htab = elf32_arm_hash_table (info); - if (htab == NULL) - return FALSE; - - check_use_blx (htab); - - osi.flaginfo = flaginfo; - osi.info = info; - osi.func = func; - - /* Add a $d mapping symbol to data-only sections that - don't have any mapping symbol. This may result in (harmless) redundant - mapping symbols. */ - for (input_bfd = info->input_bfds; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - if ((input_bfd->flags & (BFD_LINKER_CREATED | HAS_SYMS)) == HAS_SYMS) - for (osi.sec = input_bfd->sections; - osi.sec != NULL; - osi.sec = osi.sec->next) - { - if (osi.sec->output_section != NULL - && ((osi.sec->output_section->flags & (SEC_ALLOC | SEC_CODE)) - != 0) - && (osi.sec->flags & (SEC_HAS_CONTENTS | SEC_LINKER_CREATED)) - == SEC_HAS_CONTENTS - && get_arm_elf_section_data (osi.sec) != NULL - && get_arm_elf_section_data (osi.sec)->mapcount == 0 - && osi.sec->size > 0 - && (osi.sec->flags & SEC_EXCLUDE) == 0) - { - osi.sec_shndx = _bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section); - if (osi.sec_shndx != (int)SHN_BAD) - elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 0); - } - } - } - - /* ARM->Thumb glue. */ - if (htab->arm_glue_size > 0) - { - osi.sec = bfd_get_linker_section (htab->bfd_of_glue_owner, - ARM2THUMB_GLUE_SECTION_NAME); - - osi.sec_shndx = _bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section); - if (bfd_link_pic (info) || htab->root.is_relocatable_executable - || htab->pic_veneer) - size = ARM2THUMB_PIC_GLUE_SIZE; - else if (htab->use_blx) - size = ARM2THUMB_V5_STATIC_GLUE_SIZE; - else - size = ARM2THUMB_STATIC_GLUE_SIZE; - - for (offset = 0; offset < htab->arm_glue_size; offset += size) - { - elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, offset); - elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, offset + size - 4); - } - } - - /* Thumb->ARM glue. */ - if (htab->thumb_glue_size > 0) - { - osi.sec = bfd_get_linker_section (htab->bfd_of_glue_owner, - THUMB2ARM_GLUE_SECTION_NAME); - - osi.sec_shndx = _bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section); - size = THUMB2ARM_GLUE_SIZE; - - for (offset = 0; offset < htab->thumb_glue_size; offset += size) - { - elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, offset); - elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, offset + 4); - } - } - - /* ARMv4 BX veneers. */ - if (htab->bx_glue_size > 0) - { - osi.sec = bfd_get_linker_section (htab->bfd_of_glue_owner, - ARM_BX_GLUE_SECTION_NAME); - - osi.sec_shndx = _bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section); - - elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0); - } - - /* Long calls stubs. */ - if (htab->stub_bfd && htab->stub_bfd->sections) - { - asection* stub_sec; - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - /* Ignore non-stub sections. */ - if (!strstr (stub_sec->name, STUB_SUFFIX)) - continue; - - osi.sec = stub_sec; - - osi.sec_shndx = _bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section); - - bfd_hash_traverse (&htab->stub_hash_table, arm_map_one_stub, &osi); - } - } - - /* Finally, output mapping symbols for the PLT. */ - if (htab->root.splt && htab->root.splt->size > 0) - { - osi.sec = htab->root.splt; - osi.sec_shndx = (_bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section)); - - /* Output mapping symbols for the plt header. SymbianOS does not have a - plt header. */ - if (htab->vxworks_p) - { - /* VxWorks shared libraries have no PLT header. */ - if (!bfd_link_pic (info)) - { - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) - return FALSE; - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 12)) - return FALSE; - } - } - else if (htab->nacl_p) - { - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) - return FALSE; - } - else if (using_thumb_only (htab)) - { - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 0)) - return FALSE; - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 12)) - return FALSE; - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_THUMB, 16)) - return FALSE; - } - else if (!htab->symbian_p) - { - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) - return FALSE; -#ifndef FOUR_WORD_PLT - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, 16)) - return FALSE; -#endif - } - } - if (htab->nacl_p && htab->root.iplt && htab->root.iplt->size > 0) - { - /* NaCl uses a special first entry in .iplt too. */ - osi.sec = htab->root.iplt; - osi.sec_shndx = (_bfd_elf_section_from_bfd_section - (output_bfd, osi.sec->output_section)); - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, 0)) - return FALSE; - } - if ((htab->root.splt && htab->root.splt->size > 0) - || (htab->root.iplt && htab->root.iplt->size > 0)) - { - elf_link_hash_traverse (&htab->root, elf32_arm_output_plt_map, &osi); - for (input_bfd = info->input_bfds; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - struct arm_local_iplt_info **local_iplt; - unsigned int i, num_syms; - - local_iplt = elf32_arm_local_iplt (input_bfd); - if (local_iplt != NULL) - { - num_syms = elf_symtab_hdr (input_bfd).sh_info; - for (i = 0; i < num_syms; i++) - if (local_iplt[i] != NULL - && !elf32_arm_output_plt_map_1 (&osi, TRUE, - &local_iplt[i]->root, - &local_iplt[i]->arm)) - return FALSE; - } - } - } - if (htab->dt_tlsdesc_plt != 0) - { - /* Mapping symbols for the lazy tls trampoline. */ - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->dt_tlsdesc_plt)) - return FALSE; - - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, - htab->dt_tlsdesc_plt + 24)) - return FALSE; - } - if (htab->tls_trampoline != 0) - { - /* Mapping symbols for the tls trampoline. */ - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_ARM, htab->tls_trampoline)) - return FALSE; -#ifdef FOUR_WORD_PLT - if (!elf32_arm_output_map_sym (&osi, ARM_MAP_DATA, - htab->tls_trampoline + 12)) - return FALSE; -#endif - } - - return TRUE; -} - -/* Filter normal symbols of CMSE entry functions of ABFD to include in - the import library. All SYMCOUNT symbols of ABFD can be examined - from their pointers in SYMS. Pointers of symbols to keep should be - stored continuously at the beginning of that array. - - Returns the number of symbols to keep. */ - -static unsigned int -elf32_arm_filter_cmse_symbols (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - asymbol **syms, long symcount) -{ - size_t maxnamelen; - char *cmse_name; - long src_count, dst_count = 0; - struct elf32_arm_link_hash_table *htab; - - htab = elf32_arm_hash_table (info); - if (!htab->stub_bfd || !htab->stub_bfd->sections) - symcount = 0; - - maxnamelen = 128; - cmse_name = (char *) bfd_malloc (maxnamelen); - for (src_count = 0; src_count < symcount; src_count++) - { - struct elf32_arm_link_hash_entry *cmse_hash; - asymbol *sym; - flagword flags; - char *name; - size_t namelen; - - sym = syms[src_count]; - flags = sym->flags; - name = (char *) bfd_asymbol_name (sym); - - if ((flags & BSF_FUNCTION) != BSF_FUNCTION) - continue; - if (!(flags & (BSF_GLOBAL | BSF_WEAK))) - continue; - - namelen = strlen (name) + sizeof (CMSE_PREFIX) + 1; - if (namelen > maxnamelen) - { - cmse_name = (char *) - bfd_realloc (cmse_name, namelen); - maxnamelen = namelen; - } - snprintf (cmse_name, maxnamelen, "%s%s", CMSE_PREFIX, name); - cmse_hash = (struct elf32_arm_link_hash_entry *) - elf_link_hash_lookup (&(htab)->root, cmse_name, FALSE, FALSE, TRUE); - - if (!cmse_hash - || (cmse_hash->root.root.type != bfd_link_hash_defined - && cmse_hash->root.root.type != bfd_link_hash_defweak) - || cmse_hash->root.type != STT_FUNC) - continue; - - if (!ARM_GET_SYM_CMSE_SPCL (cmse_hash->root.target_internal)) - continue; - - syms[dst_count++] = sym; - } - free (cmse_name); - - syms[dst_count] = NULL; - - return dst_count; -} - -/* Filter symbols of ABFD to include in the import library. All - SYMCOUNT symbols of ABFD can be examined from their pointers in - SYMS. Pointers of symbols to keep should be stored continuously at - the beginning of that array. - - Returns the number of symbols to keep. */ - -static unsigned int -elf32_arm_filter_implib_symbols (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - asymbol **syms, long symcount) -{ - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (info); - - /* Requirement 8 of "ARM v8-M Security Extensions: Requirements on - Development Tools" (ARM-ECM-0359818) mandates Secure Gateway import - library to be a relocatable object file. */ - BFD_ASSERT (!(bfd_get_file_flags (info->out_implib_bfd) & EXEC_P)); - if (globals->cmse_implib) - return elf32_arm_filter_cmse_symbols (abfd, info, syms, symcount); - else - return _bfd_elf_filter_global_symbols (abfd, info, syms, symcount); -} - -/* Allocate target specific section data. */ - -static bfd_boolean -elf32_arm_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - _arm_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = (_arm_elf_section_data *) bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - - -/* Used to order a list of mapping symbols by address. */ - -static int -elf32_arm_compare_mapping (const void * a, const void * b) -{ - const elf32_arm_section_map *amap = (const elf32_arm_section_map *) a; - const elf32_arm_section_map *bmap = (const elf32_arm_section_map *) b; - - if (amap->vma > bmap->vma) - return 1; - else if (amap->vma < bmap->vma) - return -1; - else if (amap->type > bmap->type) - /* Ensure results do not depend on the host qsort for objects with - multiple mapping symbols at the same address by sorting on type - after vma. */ - return 1; - else if (amap->type < bmap->type) - return -1; - else - return 0; -} - -/* Add OFFSET to lower 31 bits of ADDR, leaving other bits unmodified. */ - -static unsigned long -offset_prel31 (unsigned long addr, bfd_vma offset) -{ - return (addr & ~0x7ffffffful) | ((addr + offset) & 0x7ffffffful); -} - -/* Copy an .ARM.exidx table entry, adding OFFSET to (applied) PREL31 - relocations. */ - -static void -copy_exidx_entry (bfd *output_bfd, bfd_byte *to, bfd_byte *from, bfd_vma offset) -{ - unsigned long first_word = bfd_get_32 (output_bfd, from); - unsigned long second_word = bfd_get_32 (output_bfd, from + 4); - - /* High bit of first word is supposed to be zero. */ - if ((first_word & 0x80000000ul) == 0) - first_word = offset_prel31 (first_word, offset); - - /* If the high bit of the first word is clear, and the bit pattern is not 0x1 - (EXIDX_CANTUNWIND), this is an offset to an .ARM.extab entry. */ - if ((second_word != 0x1) && ((second_word & 0x80000000ul) == 0)) - second_word = offset_prel31 (second_word, offset); - - bfd_put_32 (output_bfd, first_word, to); - bfd_put_32 (output_bfd, second_word, to + 4); -} - -/* Data for make_branch_to_a8_stub(). */ - -struct a8_branch_to_stub_data -{ - asection *writing_section; - bfd_byte *contents; -}; - - -/* Helper to insert branches to Cortex-A8 erratum stubs in the right - places for a particular section. */ - -static bfd_boolean -make_branch_to_a8_stub (struct bfd_hash_entry *gen_entry, - void *in_arg) -{ - struct elf32_arm_stub_hash_entry *stub_entry; - struct a8_branch_to_stub_data *data; - bfd_byte *contents; - unsigned long branch_insn; - bfd_vma veneered_insn_loc, veneer_entry_loc; - bfd_signed_vma branch_offset; - bfd *abfd; - unsigned int loc; - - stub_entry = (struct elf32_arm_stub_hash_entry *) gen_entry; - data = (struct a8_branch_to_stub_data *) in_arg; - - if (stub_entry->target_section != data->writing_section - || stub_entry->stub_type < arm_stub_a8_veneer_lwm) - return TRUE; - - contents = data->contents; - - /* We use target_section as Cortex-A8 erratum workaround stubs are only - generated when both source and target are in the same section. */ - veneered_insn_loc = stub_entry->target_section->output_section->vma - + stub_entry->target_section->output_offset - + stub_entry->source_value; - - veneer_entry_loc = stub_entry->stub_sec->output_section->vma - + stub_entry->stub_sec->output_offset - + stub_entry->stub_offset; - - if (stub_entry->stub_type == arm_stub_a8_veneer_blx) - veneered_insn_loc &= ~3u; - - branch_offset = veneer_entry_loc - veneered_insn_loc - 4; - - abfd = stub_entry->target_section->owner; - loc = stub_entry->source_value; - - /* We attempt to avoid this condition by setting stubs_always_after_branch - in elf32_arm_size_stubs if we've enabled the Cortex-A8 erratum workaround. - This check is just to be on the safe side... */ - if ((veneered_insn_loc & ~0xfff) == (veneer_entry_loc & ~0xfff)) - { - _bfd_error_handler (_("%B: error: Cortex-A8 erratum stub is " - "allocated in unsafe location"), abfd); - return FALSE; - } - - switch (stub_entry->stub_type) - { - case arm_stub_a8_veneer_b: - case arm_stub_a8_veneer_b_cond: - branch_insn = 0xf0009000; - goto jump24; - - case arm_stub_a8_veneer_blx: - branch_insn = 0xf000e800; - goto jump24; - - case arm_stub_a8_veneer_bl: - { - unsigned int i1, j1, i2, j2, s; - - branch_insn = 0xf000d000; - - jump24: - if (branch_offset < -16777216 || branch_offset > 16777214) - { - /* There's not much we can do apart from complain if this - happens. */ - _bfd_error_handler (_("%B: error: Cortex-A8 erratum stub out " - "of range (input file too large)"), abfd); - return FALSE; - } - - /* i1 = not(j1 eor s), so: - not i1 = j1 eor s - j1 = (not i1) eor s. */ - - branch_insn |= (branch_offset >> 1) & 0x7ff; - branch_insn |= ((branch_offset >> 12) & 0x3ff) << 16; - i2 = (branch_offset >> 22) & 1; - i1 = (branch_offset >> 23) & 1; - s = (branch_offset >> 24) & 1; - j1 = (!i1) ^ s; - j2 = (!i2) ^ s; - branch_insn |= j2 << 11; - branch_insn |= j1 << 13; - branch_insn |= s << 26; - } - break; - - default: - BFD_FAIL (); - return FALSE; - } - - bfd_put_16 (abfd, (branch_insn >> 16) & 0xffff, &contents[loc]); - bfd_put_16 (abfd, branch_insn & 0xffff, &contents[loc + 2]); - - return TRUE; -} - -/* Beginning of stm32l4xx work-around. */ - -/* Functions encoding instructions necessary for the emission of the - fix-stm32l4xx-629360. - Encoding is extracted from the - ARM (C) Architecture Reference Manual - ARMv7-A and ARMv7-R edition - ARM DDI 0406C.b (ID072512). */ - -static inline bfd_vma -create_instruction_branch_absolute (int branch_offset) -{ - /* A8.8.18 B (A8-334) - B target_address (Encoding T4). */ - /* 1111 - 0Sii - iiii - iiii - 10J1 - Jiii - iiii - iiii. */ - /* jump offset is: S:I1:I2:imm10:imm11:0. */ - /* with : I1 = NOT (J1 EOR S) I2 = NOT (J2 EOR S). */ - - int s = ((branch_offset & 0x1000000) >> 24); - int j1 = s ^ !((branch_offset & 0x800000) >> 23); - int j2 = s ^ !((branch_offset & 0x400000) >> 22); - - if (branch_offset < -(1 << 24) || branch_offset >= (1 << 24)) - BFD_ASSERT (0 && "Error: branch out of range. Cannot create branch."); - - bfd_vma patched_inst = 0xf0009000 - | s << 26 /* S. */ - | (((unsigned long) (branch_offset) >> 12) & 0x3ff) << 16 /* imm10. */ - | j1 << 13 /* J1. */ - | j2 << 11 /* J2. */ - | (((unsigned long) (branch_offset) >> 1) & 0x7ff); /* imm11. */ - - return patched_inst; -} - -static inline bfd_vma -create_instruction_ldmia (int base_reg, int wback, int reg_mask) -{ - /* A8.8.57 LDM/LDMIA/LDMFD (A8-396) - LDMIA Rn!, {Ra, Rb, Rc, ...} (Encoding T2). */ - bfd_vma patched_inst = 0xe8900000 - | (/*W=*/wback << 21) - | (base_reg << 16) - | (reg_mask & 0x0000ffff); - - return patched_inst; -} - -static inline bfd_vma -create_instruction_ldmdb (int base_reg, int wback, int reg_mask) -{ - /* A8.8.60 LDMDB/LDMEA (A8-402) - LDMDB Rn!, {Ra, Rb, Rc, ...} (Encoding T1). */ - bfd_vma patched_inst = 0xe9100000 - | (/*W=*/wback << 21) - | (base_reg << 16) - | (reg_mask & 0x0000ffff); - - return patched_inst; -} - -static inline bfd_vma -create_instruction_mov (int target_reg, int source_reg) -{ - /* A8.8.103 MOV (register) (A8-486) - MOV Rd, Rm (Encoding T1). */ - bfd_vma patched_inst = 0x4600 - | (target_reg & 0x7) - | ((target_reg & 0x8) >> 3) << 7 - | (source_reg << 3); - - return patched_inst; -} - -static inline bfd_vma -create_instruction_sub (int target_reg, int source_reg, int value) -{ - /* A8.8.221 SUB (immediate) (A8-708) - SUB Rd, Rn, #value (Encoding T3). */ - bfd_vma patched_inst = 0xf1a00000 - | (target_reg << 8) - | (source_reg << 16) - | (/*S=*/0 << 20) - | ((value & 0x800) >> 11) << 26 - | ((value & 0x700) >> 8) << 12 - | (value & 0x0ff); - - return patched_inst; -} - -static inline bfd_vma -create_instruction_vldmia (int base_reg, int is_dp, int wback, int num_words, - int first_reg) -{ - /* A8.8.332 VLDM (A8-922) - VLMD{MODE} Rn{!}, {list} (Encoding T1 or T2). */ - bfd_vma patched_inst = (is_dp ? 0xec900b00 : 0xec900a00) - | (/*W=*/wback << 21) - | (base_reg << 16) - | (num_words & 0x000000ff) - | (((unsigned)first_reg >> 1) & 0x0000000f) << 12 - | (first_reg & 0x00000001) << 22; - - return patched_inst; -} - -static inline bfd_vma -create_instruction_vldmdb (int base_reg, int is_dp, int num_words, - int first_reg) -{ - /* A8.8.332 VLDM (A8-922) - VLMD{MODE} Rn!, {} (Encoding T1 or T2). */ - bfd_vma patched_inst = (is_dp ? 0xed300b00 : 0xed300a00) - | (base_reg << 16) - | (num_words & 0x000000ff) - | (((unsigned)first_reg >>1 ) & 0x0000000f) << 12 - | (first_reg & 0x00000001) << 22; - - return patched_inst; -} - -static inline bfd_vma -create_instruction_udf_w (int value) -{ - /* A8.8.247 UDF (A8-758) - Undefined (Encoding T2). */ - bfd_vma patched_inst = 0xf7f0a000 - | (value & 0x00000fff) - | (value & 0x000f0000) << 16; - - return patched_inst; -} - -static inline bfd_vma -create_instruction_udf (int value) -{ - /* A8.8.247 UDF (A8-758) - Undefined (Encoding T1). */ - bfd_vma patched_inst = 0xde00 - | (value & 0xff); - - return patched_inst; -} - -/* Functions writing an instruction in memory, returning the next - memory position to write to. */ - -static inline bfd_byte * -push_thumb2_insn32 (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, bfd_byte *pt, insn32 insn) -{ - put_thumb2_insn (htab, output_bfd, insn, pt); - return pt + 4; -} - -static inline bfd_byte * -push_thumb2_insn16 (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, bfd_byte *pt, insn32 insn) -{ - put_thumb_insn (htab, output_bfd, insn, pt); - return pt + 2; -} - -/* Function filling up a region in memory with T1 and T2 UDFs taking - care of alignment. */ - -static bfd_byte * -stm32l4xx_fill_stub_udf (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, - const bfd_byte * const base_stub_contents, - bfd_byte * const from_stub_contents, - const bfd_byte * const end_stub_contents) -{ - bfd_byte *current_stub_contents = from_stub_contents; - - /* Fill the remaining of the stub with deterministic contents : UDF - instructions. - Check if realignment is needed on modulo 4 frontier using T1, to - further use T2. */ - if ((current_stub_contents < end_stub_contents) - && !((current_stub_contents - base_stub_contents) % 2) - && ((current_stub_contents - base_stub_contents) % 4)) - current_stub_contents = - push_thumb2_insn16 (htab, output_bfd, current_stub_contents, - create_instruction_udf (0)); - - for (; current_stub_contents < end_stub_contents;) - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_udf_w (0)); - - return current_stub_contents; -} - -/* Functions writing the stream of instructions equivalent to the - derived sequence for ldmia, ldmdb, vldm respectively. */ - -static void -stm32l4xx_create_replacing_stub_ldmia (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, - const insn32 initial_insn, - const bfd_byte *const initial_insn_addr, - bfd_byte *const base_stub_contents) -{ - int wback = (initial_insn & 0x00200000) >> 21; - int ri, rn = (initial_insn & 0x000F0000) >> 16; - int insn_all_registers = initial_insn & 0x0000ffff; - int insn_low_registers, insn_high_registers; - int usable_register_mask; - int nb_registers = elf32_arm_popcount (insn_all_registers); - int restore_pc = (insn_all_registers & (1 << 15)) ? 1 : 0; - int restore_rn = (insn_all_registers & (1 << rn)) ? 1 : 0; - bfd_byte *current_stub_contents = base_stub_contents; - - BFD_ASSERT (is_thumb2_ldmia (initial_insn)); - - /* In BFD_ARM_STM32L4XX_FIX_ALL mode we may have to deal with - smaller than 8 registers load sequences that do not cause the - hardware issue. */ - if (nb_registers <= 8) - { - /* UNTOUCHED : LDMIA Rn{!}, {R-all-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - initial_insn); - - /* B initial_insn_addr+4. */ - if (!restore_pc) - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - - /* Fill the remaining of the stub with deterministic contents. */ - current_stub_contents = - stm32l4xx_fill_stub_udf (htab, output_bfd, - base_stub_contents, current_stub_contents, - base_stub_contents + - STM32L4XX_ERRATUM_LDM_VENEER_SIZE); - - return; - } - - /* - reg_list[13] == 0. */ - BFD_ASSERT ((insn_all_registers & (1 << 13))==0); - - /* - reg_list[14] & reg_list[15] != 1. */ - BFD_ASSERT ((insn_all_registers & 0xC000) != 0xC000); - - /* - if (wback==1) reg_list[rn] == 0. */ - BFD_ASSERT (!wback || !restore_rn); - - /* - nb_registers > 8. */ - BFD_ASSERT (elf32_arm_popcount (insn_all_registers) > 8); - - /* At this point, LDMxx initial insn loads between 9 and 14 registers. */ - - /* In the following algorithm, we split this wide LDM using 2 LDM insns: - - One with the 7 lowest registers (register mask 0x007F) - This LDM will finally contain between 2 and 7 registers - - One with the 7 highest registers (register mask 0xDF80) - This ldm will finally contain between 2 and 7 registers. */ - insn_low_registers = insn_all_registers & 0x007F; - insn_high_registers = insn_all_registers & 0xDF80; - - /* A spare register may be needed during this veneer to temporarily - handle the base register. This register will be restored with the - last LDM operation. - The usable register may be any general purpose register (that - excludes PC, SP, LR : register mask is 0x1FFF). */ - usable_register_mask = 0x1FFF; - - /* Generate the stub function. */ - if (wback) - { - /* LDMIA Rn!, {R-low-register-list} : (Encoding T2). */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (rn, /*wback=*/1, insn_low_registers)); - - /* LDMIA Rn!, {R-high-register-list} : (Encoding T2). */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (rn, /*wback=*/1, insn_high_registers)); - if (!restore_pc) - { - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - } - else /* if (!wback). */ - { - ri = rn; - - /* If Rn is not part of the high-register-list, move it there. */ - if (!(insn_high_registers & (1 << rn))) - { - /* Choose a Ri in the high-register-list that will be restored. */ - ri = ctz (insn_high_registers & usable_register_mask & ~(1 << rn)); - - /* MOV Ri, Rn. */ - current_stub_contents = - push_thumb2_insn16 (htab, output_bfd, current_stub_contents, - create_instruction_mov (ri, rn)); - } - - /* LDMIA Ri!, {R-low-register-list} : (Encoding T2). */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/1, insn_low_registers)); - - /* LDMIA Ri, {R-high-register-list} : (Encoding T2). */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/0, insn_high_registers)); - - if (!restore_pc) - { - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - } - - /* Fill the remaining of the stub with deterministic contents. */ - current_stub_contents = - stm32l4xx_fill_stub_udf (htab, output_bfd, - base_stub_contents, current_stub_contents, - base_stub_contents + - STM32L4XX_ERRATUM_LDM_VENEER_SIZE); -} - -static void -stm32l4xx_create_replacing_stub_ldmdb (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, - const insn32 initial_insn, - const bfd_byte *const initial_insn_addr, - bfd_byte *const base_stub_contents) -{ - int wback = (initial_insn & 0x00200000) >> 21; - int ri, rn = (initial_insn & 0x000f0000) >> 16; - int insn_all_registers = initial_insn & 0x0000ffff; - int insn_low_registers, insn_high_registers; - int usable_register_mask; - int restore_pc = (insn_all_registers & (1 << 15)) ? 1 : 0; - int restore_rn = (insn_all_registers & (1 << rn)) ? 1 : 0; - int nb_registers = elf32_arm_popcount (insn_all_registers); - bfd_byte *current_stub_contents = base_stub_contents; - - BFD_ASSERT (is_thumb2_ldmdb (initial_insn)); - - /* In BFD_ARM_STM32L4XX_FIX_ALL mode we may have to deal with - smaller than 8 registers load sequences that do not cause the - hardware issue. */ - if (nb_registers <= 8) - { - /* UNTOUCHED : LDMIA Rn{!}, {R-all-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - initial_insn); - - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - - /* Fill the remaining of the stub with deterministic contents. */ - current_stub_contents = - stm32l4xx_fill_stub_udf (htab, output_bfd, - base_stub_contents, current_stub_contents, - base_stub_contents + - STM32L4XX_ERRATUM_LDM_VENEER_SIZE); - - return; - } - - /* - reg_list[13] == 0. */ - BFD_ASSERT ((insn_all_registers & (1 << 13)) == 0); - - /* - reg_list[14] & reg_list[15] != 1. */ - BFD_ASSERT ((insn_all_registers & 0xC000) != 0xC000); - - /* - if (wback==1) reg_list[rn] == 0. */ - BFD_ASSERT (!wback || !restore_rn); - - /* - nb_registers > 8. */ - BFD_ASSERT (elf32_arm_popcount (insn_all_registers) > 8); - - /* At this point, LDMxx initial insn loads between 9 and 14 registers. */ - - /* In the following algorithm, we split this wide LDM using 2 LDM insn: - - One with the 7 lowest registers (register mask 0x007F) - This LDM will finally contain between 2 and 7 registers - - One with the 7 highest registers (register mask 0xDF80) - This ldm will finally contain between 2 and 7 registers. */ - insn_low_registers = insn_all_registers & 0x007F; - insn_high_registers = insn_all_registers & 0xDF80; - - /* A spare register may be needed during this veneer to temporarily - handle the base register. This register will be restored with - the last LDM operation. - The usable register may be any general purpose register (that excludes - PC, SP, LR : register mask is 0x1FFF). */ - usable_register_mask = 0x1FFF; - - /* Generate the stub function. */ - if (!wback && !restore_pc && !restore_rn) - { - /* Choose a Ri in the low-register-list that will be restored. */ - ri = ctz (insn_low_registers & usable_register_mask & ~(1 << rn)); - - /* MOV Ri, Rn. */ - current_stub_contents = - push_thumb2_insn16 (htab, output_bfd, current_stub_contents, - create_instruction_mov (ri, rn)); - - /* LDMDB Ri!, {R-high-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmdb - (ri, /*wback=*/1, insn_high_registers)); - - /* LDMDB Ri, {R-low-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmdb - (ri, /*wback=*/0, insn_low_registers)); - - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - else if (wback && !restore_pc && !restore_rn) - { - /* LDMDB Rn!, {R-high-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmdb - (rn, /*wback=*/1, insn_high_registers)); - - /* LDMDB Rn!, {R-low-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmdb - (rn, /*wback=*/1, insn_low_registers)); - - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - else if (!wback && restore_pc && !restore_rn) - { - /* Choose a Ri in the high-register-list that will be restored. */ - ri = ctz (insn_high_registers & usable_register_mask & ~(1 << rn)); - - /* SUB Ri, Rn, #(4*nb_registers). */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_sub (ri, rn, (4 * nb_registers))); - - /* LDMIA Ri!, {R-low-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/1, insn_low_registers)); - - /* LDMIA Ri, {R-high-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/0, insn_high_registers)); - } - else if (wback && restore_pc && !restore_rn) - { - /* Choose a Ri in the high-register-list that will be restored. */ - ri = ctz (insn_high_registers & usable_register_mask & ~(1 << rn)); - - /* SUB Rn, Rn, #(4*nb_registers) */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_sub (rn, rn, (4 * nb_registers))); - - /* MOV Ri, Rn. */ - current_stub_contents = - push_thumb2_insn16 (htab, output_bfd, current_stub_contents, - create_instruction_mov (ri, rn)); - - /* LDMIA Ri!, {R-low-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/1, insn_low_registers)); - - /* LDMIA Ri, {R-high-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/0, insn_high_registers)); - } - else if (!wback && !restore_pc && restore_rn) - { - ri = rn; - if (!(insn_low_registers & (1 << rn))) - { - /* Choose a Ri in the low-register-list that will be restored. */ - ri = ctz (insn_low_registers & usable_register_mask & ~(1 << rn)); - - /* MOV Ri, Rn. */ - current_stub_contents = - push_thumb2_insn16 (htab, output_bfd, current_stub_contents, - create_instruction_mov (ri, rn)); - } - - /* LDMDB Ri!, {R-high-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmdb - (ri, /*wback=*/1, insn_high_registers)); - - /* LDMDB Ri, {R-low-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmdb - (ri, /*wback=*/0, insn_low_registers)); - - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - else if (!wback && restore_pc && restore_rn) - { - ri = rn; - if (!(insn_high_registers & (1 << rn))) - { - /* Choose a Ri in the high-register-list that will be restored. */ - ri = ctz (insn_high_registers & usable_register_mask & ~(1 << rn)); - } - - /* SUB Ri, Rn, #(4*nb_registers). */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_sub (ri, rn, (4 * nb_registers))); - - /* LDMIA Ri!, {R-low-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/1, insn_low_registers)); - - /* LDMIA Ri, {R-high-register-list}. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_ldmia - (ri, /*wback=*/0, insn_high_registers)); - } - else if (wback && restore_rn) - { - /* The assembler should not have accepted to encode this. */ - BFD_ASSERT (0 && "Cannot patch an instruction that has an " - "undefined behavior.\n"); - } - - /* Fill the remaining of the stub with deterministic contents. */ - current_stub_contents = - stm32l4xx_fill_stub_udf (htab, output_bfd, - base_stub_contents, current_stub_contents, - base_stub_contents + - STM32L4XX_ERRATUM_LDM_VENEER_SIZE); - -} - -static void -stm32l4xx_create_replacing_stub_vldm (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, - const insn32 initial_insn, - const bfd_byte *const initial_insn_addr, - bfd_byte *const base_stub_contents) -{ - int num_words = ((unsigned int) initial_insn << 24) >> 24; - bfd_byte *current_stub_contents = base_stub_contents; - - BFD_ASSERT (is_thumb2_vldm (initial_insn)); - - /* In BFD_ARM_STM32L4XX_FIX_ALL mode we may have to deal with - smaller than 8 words load sequences that do not cause the - hardware issue. */ - if (num_words <= 8) - { - /* Untouched instruction. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - initial_insn); - - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - else - { - bfd_boolean is_dp = /* DP encoding. */ - (initial_insn & 0xfe100f00) == 0xec100b00; - bfd_boolean is_ia_nobang = /* (IA without !). */ - (((initial_insn << 7) >> 28) & 0xd) == 0x4; - bfd_boolean is_ia_bang = /* (IA with !) - includes VPOP. */ - (((initial_insn << 7) >> 28) & 0xd) == 0x5; - bfd_boolean is_db_bang = /* (DB with !). */ - (((initial_insn << 7) >> 28) & 0xd) == 0x9; - int base_reg = ((unsigned int) initial_insn << 12) >> 28; - /* d = UInt (Vd:D);. */ - int first_reg = ((((unsigned int) initial_insn << 16) >> 28) << 1) - | (((unsigned int)initial_insn << 9) >> 31); - - /* Compute the number of 8-words chunks needed to split. */ - int chunks = (num_words % 8) ? (num_words / 8 + 1) : (num_words / 8); - int chunk; - - /* The test coverage has been done assuming the following - hypothesis that exactly one of the previous is_ predicates is - true. */ - BFD_ASSERT ( (is_ia_nobang ^ is_ia_bang ^ is_db_bang) - && !(is_ia_nobang & is_ia_bang & is_db_bang)); - - /* We treat the cutting of the words in one pass for all - cases, then we emit the adjustments: - - vldm rx, {...} - -> vldm rx!, {8_words_or_less} for each needed 8_word - -> sub rx, rx, #size (list) - - vldm rx!, {...} - -> vldm rx!, {8_words_or_less} for each needed 8_word - This also handles vpop instruction (when rx is sp) - - vldmd rx!, {...} - -> vldmb rx!, {8_words_or_less} for each needed 8_word. */ - for (chunk = 0; chunk < chunks; ++chunk) - { - bfd_vma new_insn = 0; - - if (is_ia_nobang || is_ia_bang) - { - new_insn = create_instruction_vldmia - (base_reg, - is_dp, - /*wback= . */1, - chunks - (chunk + 1) ? - 8 : num_words - chunk * 8, - first_reg + chunk * 8); - } - else if (is_db_bang) - { - new_insn = create_instruction_vldmdb - (base_reg, - is_dp, - chunks - (chunk + 1) ? - 8 : num_words - chunk * 8, - first_reg + chunk * 8); - } - - if (new_insn) - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - new_insn); - } - - /* Only this case requires the base register compensation - subtract. */ - if (is_ia_nobang) - { - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_sub - (base_reg, base_reg, 4*num_words)); - } - - /* B initial_insn_addr+4. */ - current_stub_contents = - push_thumb2_insn32 (htab, output_bfd, current_stub_contents, - create_instruction_branch_absolute - (initial_insn_addr - current_stub_contents)); - } - - /* Fill the remaining of the stub with deterministic contents. */ - current_stub_contents = - stm32l4xx_fill_stub_udf (htab, output_bfd, - base_stub_contents, current_stub_contents, - base_stub_contents + - STM32L4XX_ERRATUM_VLDM_VENEER_SIZE); -} - -static void -stm32l4xx_create_replacing_stub (struct elf32_arm_link_hash_table * htab, - bfd * output_bfd, - const insn32 wrong_insn, - const bfd_byte *const wrong_insn_addr, - bfd_byte *const stub_contents) -{ - if (is_thumb2_ldmia (wrong_insn)) - stm32l4xx_create_replacing_stub_ldmia (htab, output_bfd, - wrong_insn, wrong_insn_addr, - stub_contents); - else if (is_thumb2_ldmdb (wrong_insn)) - stm32l4xx_create_replacing_stub_ldmdb (htab, output_bfd, - wrong_insn, wrong_insn_addr, - stub_contents); - else if (is_thumb2_vldm (wrong_insn)) - stm32l4xx_create_replacing_stub_vldm (htab, output_bfd, - wrong_insn, wrong_insn_addr, - stub_contents); -} - -/* End of stm32l4xx work-around. */ - - -/* Do code byteswapping. Return FALSE afterwards so that the section is - written out as normal. */ - -static bfd_boolean -elf32_arm_write_section (bfd *output_bfd, - struct bfd_link_info *link_info, - asection *sec, - bfd_byte *contents) -{ - unsigned int mapcount, errcount; - _arm_elf_section_data *arm_data; - struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info); - elf32_arm_section_map *map; - elf32_vfp11_erratum_list *errnode; - elf32_stm32l4xx_erratum_list *stm32l4xx_errnode; - bfd_vma ptr; - bfd_vma end; - bfd_vma offset = sec->output_section->vma + sec->output_offset; - bfd_byte tmp; - unsigned int i; - - if (globals == NULL) - return FALSE; - - /* If this section has not been allocated an _arm_elf_section_data - structure then we cannot record anything. */ - arm_data = get_arm_elf_section_data (sec); - if (arm_data == NULL) - return FALSE; - - mapcount = arm_data->mapcount; - map = arm_data->map; - errcount = arm_data->erratumcount; - - if (errcount != 0) - { - unsigned int endianflip = bfd_big_endian (output_bfd) ? 3 : 0; - - for (errnode = arm_data->erratumlist; errnode != 0; - errnode = errnode->next) - { - bfd_vma target = errnode->vma - offset; - - switch (errnode->type) - { - case VFP11_ERRATUM_BRANCH_TO_ARM_VENEER: - { - bfd_vma branch_to_veneer; - /* Original condition code of instruction, plus bit mask for - ARM B instruction. */ - unsigned int insn = (errnode->u.b.vfp_insn & 0xf0000000) - | 0x0a000000; - - /* The instruction is before the label. */ - target -= 4; - - /* Above offset included in -4 below. */ - branch_to_veneer = errnode->u.b.veneer->vma - - errnode->vma - 4; - - if ((signed) branch_to_veneer < -(1 << 25) - || (signed) branch_to_veneer >= (1 << 25)) - _bfd_error_handler (_("%B: error: VFP11 veneer out of " - "range"), output_bfd); - - insn |= (branch_to_veneer >> 2) & 0xffffff; - contents[endianflip ^ target] = insn & 0xff; - contents[endianflip ^ (target + 1)] = (insn >> 8) & 0xff; - contents[endianflip ^ (target + 2)] = (insn >> 16) & 0xff; - contents[endianflip ^ (target + 3)] = (insn >> 24) & 0xff; - } - break; - - case VFP11_ERRATUM_ARM_VENEER: - { - bfd_vma branch_from_veneer; - unsigned int insn; - - /* Take size of veneer into account. */ - branch_from_veneer = errnode->u.v.branch->vma - - errnode->vma - 12; - - if ((signed) branch_from_veneer < -(1 << 25) - || (signed) branch_from_veneer >= (1 << 25)) - _bfd_error_handler (_("%B: error: VFP11 veneer out of " - "range"), output_bfd); - - /* Original instruction. */ - insn = errnode->u.v.branch->u.b.vfp_insn; - contents[endianflip ^ target] = insn & 0xff; - contents[endianflip ^ (target + 1)] = (insn >> 8) & 0xff; - contents[endianflip ^ (target + 2)] = (insn >> 16) & 0xff; - contents[endianflip ^ (target + 3)] = (insn >> 24) & 0xff; - - /* Branch back to insn after original insn. */ - insn = 0xea000000 | ((branch_from_veneer >> 2) & 0xffffff); - contents[endianflip ^ (target + 4)] = insn & 0xff; - contents[endianflip ^ (target + 5)] = (insn >> 8) & 0xff; - contents[endianflip ^ (target + 6)] = (insn >> 16) & 0xff; - contents[endianflip ^ (target + 7)] = (insn >> 24) & 0xff; - } - break; - - default: - abort (); - } - } - } - - if (arm_data->stm32l4xx_erratumcount != 0) - { - for (stm32l4xx_errnode = arm_data->stm32l4xx_erratumlist; - stm32l4xx_errnode != 0; - stm32l4xx_errnode = stm32l4xx_errnode->next) - { - bfd_vma target = stm32l4xx_errnode->vma - offset; - - switch (stm32l4xx_errnode->type) - { - case STM32L4XX_ERRATUM_BRANCH_TO_VENEER: - { - unsigned int insn; - bfd_vma branch_to_veneer = - stm32l4xx_errnode->u.b.veneer->vma - stm32l4xx_errnode->vma; - - if ((signed) branch_to_veneer < -(1 << 24) - || (signed) branch_to_veneer >= (1 << 24)) - { - bfd_vma out_of_range = - ((signed) branch_to_veneer < -(1 << 24)) ? - - branch_to_veneer - (1 << 24) : - ((signed) branch_to_veneer >= (1 << 24)) ? - branch_to_veneer - (1 << 24) : 0; - - _bfd_error_handler - (_("%B(%#Lx): error: Cannot create STM32L4XX veneer. " - "Jump out of range by %Ld bytes. " - "Cannot encode branch instruction. "), - output_bfd, - stm32l4xx_errnode->vma - 4, - out_of_range); - continue; - } - - insn = create_instruction_branch_absolute - (stm32l4xx_errnode->u.b.veneer->vma - stm32l4xx_errnode->vma); - - /* The instruction is before the label. */ - target -= 4; - - put_thumb2_insn (globals, output_bfd, - (bfd_vma) insn, contents + target); - } - break; - - case STM32L4XX_ERRATUM_VENEER: - { - bfd_byte * veneer; - bfd_byte * veneer_r; - unsigned int insn; - - veneer = contents + target; - veneer_r = veneer - + stm32l4xx_errnode->u.b.veneer->vma - - stm32l4xx_errnode->vma - 4; - - if ((signed) (veneer_r - veneer - - STM32L4XX_ERRATUM_VLDM_VENEER_SIZE > - STM32L4XX_ERRATUM_LDM_VENEER_SIZE ? - STM32L4XX_ERRATUM_VLDM_VENEER_SIZE : - STM32L4XX_ERRATUM_LDM_VENEER_SIZE) < -(1 << 24) - || (signed) (veneer_r - veneer) >= (1 << 24)) - { - _bfd_error_handler (_("%B: error: Cannot create STM32L4XX " - "veneer."), output_bfd); - continue; - } - - /* Original instruction. */ - insn = stm32l4xx_errnode->u.v.branch->u.b.insn; - - stm32l4xx_create_replacing_stub - (globals, output_bfd, insn, (void*)veneer_r, (void*)veneer); - } - break; - - default: - abort (); - } - } - } - - if (arm_data->elf.this_hdr.sh_type == SHT_ARM_EXIDX) - { - arm_unwind_table_edit *edit_node - = arm_data->u.exidx.unwind_edit_list; - /* Now, sec->size is the size of the section we will write. The original - size (before we merged duplicate entries and inserted EXIDX_CANTUNWIND - markers) was sec->rawsize. (This isn't the case if we perform no - edits, then rawsize will be zero and we should use size). */ - bfd_byte *edited_contents = (bfd_byte *) bfd_malloc (sec->size); - unsigned int input_size = sec->rawsize ? sec->rawsize : sec->size; - unsigned int in_index, out_index; - bfd_vma add_to_offsets = 0; - - for (in_index = 0, out_index = 0; in_index * 8 < input_size || edit_node;) - { - if (edit_node) - { - unsigned int edit_index = edit_node->index; - - if (in_index < edit_index && in_index * 8 < input_size) - { - copy_exidx_entry (output_bfd, edited_contents + out_index * 8, - contents + in_index * 8, add_to_offsets); - out_index++; - in_index++; - } - else if (in_index == edit_index - || (in_index * 8 >= input_size - && edit_index == UINT_MAX)) - { - switch (edit_node->type) - { - case DELETE_EXIDX_ENTRY: - in_index++; - add_to_offsets += 8; - break; - - case INSERT_EXIDX_CANTUNWIND_AT_END: - { - asection *text_sec = edit_node->linked_section; - bfd_vma text_offset = text_sec->output_section->vma - + text_sec->output_offset - + text_sec->size; - bfd_vma exidx_offset = offset + out_index * 8; - unsigned long prel31_offset; - - /* Note: this is meant to be equivalent to an - R_ARM_PREL31 relocation. These synthetic - EXIDX_CANTUNWIND markers are not relocated by the - usual BFD method. */ - prel31_offset = (text_offset - exidx_offset) - & 0x7ffffffful; - if (bfd_link_relocatable (link_info)) - { - /* Here relocation for new EXIDX_CANTUNWIND is - created, so there is no need to - adjust offset by hand. */ - prel31_offset = text_sec->output_offset - + text_sec->size; - } - - /* First address we can't unwind. */ - bfd_put_32 (output_bfd, prel31_offset, - &edited_contents[out_index * 8]); - - /* Code for EXIDX_CANTUNWIND. */ - bfd_put_32 (output_bfd, 0x1, - &edited_contents[out_index * 8 + 4]); - - out_index++; - add_to_offsets -= 8; - } - break; - } - - edit_node = edit_node->next; - } - } - else - { - /* No more edits, copy remaining entries verbatim. */ - copy_exidx_entry (output_bfd, edited_contents + out_index * 8, - contents + in_index * 8, add_to_offsets); - out_index++; - in_index++; - } - } - - if (!(sec->flags & SEC_EXCLUDE) && !(sec->flags & SEC_NEVER_LOAD)) - bfd_set_section_contents (output_bfd, sec->output_section, - edited_contents, - (file_ptr) sec->output_offset, sec->size); - - return TRUE; - } - - /* Fix code to point to Cortex-A8 erratum stubs. */ - if (globals->fix_cortex_a8) - { - struct a8_branch_to_stub_data data; - - data.writing_section = sec; - data.contents = contents; - - bfd_hash_traverse (& globals->stub_hash_table, make_branch_to_a8_stub, - & data); - } - - if (mapcount == 0) - return FALSE; - - if (globals->byteswap_code) - { - qsort (map, mapcount, sizeof (* map), elf32_arm_compare_mapping); - - ptr = map[0].vma; - for (i = 0; i < mapcount; i++) - { - if (i == mapcount - 1) - end = sec->size; - else - end = map[i + 1].vma; - - switch (map[i].type) - { - case 'a': - /* Byte swap code words. */ - while (ptr + 3 < end) - { - tmp = contents[ptr]; - contents[ptr] = contents[ptr + 3]; - contents[ptr + 3] = tmp; - tmp = contents[ptr + 1]; - contents[ptr + 1] = contents[ptr + 2]; - contents[ptr + 2] = tmp; - ptr += 4; - } - break; - - case 't': - /* Byte swap code halfwords. */ - while (ptr + 1 < end) - { - tmp = contents[ptr]; - contents[ptr] = contents[ptr + 1]; - contents[ptr + 1] = tmp; - ptr += 2; - } - break; - - case 'd': - /* Leave data alone. */ - break; - } - ptr = end; - } - } - - free (map); - arm_data->mapcount = -1; - arm_data->mapsize = 0; - arm_data->map = NULL; - - return FALSE; -} - -/* Mangle thumb function symbols as we read them in. */ - -static bfd_boolean -elf32_arm_swap_symbol_in (bfd * abfd, - const void *psrc, - const void *pshn, - Elf_Internal_Sym *dst) -{ - Elf_Internal_Shdr *symtab_hdr; - const char *name = NULL; - - if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst)) - return FALSE; - dst->st_target_internal = 0; - - /* New EABI objects mark thumb function symbols by setting the low bit of - the address. */ - if (ELF_ST_TYPE (dst->st_info) == STT_FUNC - || ELF_ST_TYPE (dst->st_info) == STT_GNU_IFUNC) - { - if (dst->st_value & 1) - { - dst->st_value &= ~(bfd_vma) 1; - ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, - ST_BRANCH_TO_THUMB); - } - else - ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_TO_ARM); - } - else if (ELF_ST_TYPE (dst->st_info) == STT_ARM_TFUNC) - { - dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_FUNC); - ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_TO_THUMB); - } - else if (ELF_ST_TYPE (dst->st_info) == STT_SECTION) - ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_LONG); - else - ARM_SET_SYM_BRANCH_TYPE (dst->st_target_internal, ST_BRANCH_UNKNOWN); - - /* Mark CMSE special symbols. */ - symtab_hdr = & elf_symtab_hdr (abfd); - if (symtab_hdr->sh_size) - name = bfd_elf_sym_name (abfd, symtab_hdr, dst, NULL); - if (name && CONST_STRNEQ (name, CMSE_PREFIX)) - ARM_SET_SYM_CMSE_SPCL (dst->st_target_internal); - - return TRUE; -} - - -/* Mangle thumb function symbols as we write them out. */ - -static void -elf32_arm_swap_symbol_out (bfd *abfd, - const Elf_Internal_Sym *src, - void *cdst, - void *shndx) -{ - Elf_Internal_Sym newsym; - - /* We convert STT_ARM_TFUNC symbols into STT_FUNC with the low bit - of the address set, as per the new EABI. We do this unconditionally - because objcopy does not set the elf header flags until after - it writes out the symbol table. */ - if (ARM_GET_SYM_BRANCH_TYPE (src->st_target_internal) == ST_BRANCH_TO_THUMB) - { - newsym = *src; - if (ELF_ST_TYPE (src->st_info) != STT_GNU_IFUNC) - newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC); - if (newsym.st_shndx != SHN_UNDEF) - { - /* Do this only for defined symbols. At link type, the static - linker will simulate the work of dynamic linker of resolving - symbols and will carry over the thumbness of found symbols to - the output symbol table. It's not clear how it happens, but - the thumbness of undefined symbols can well be different at - runtime, and writing '1' for them will be confusing for users - and possibly for dynamic linker itself. - */ - newsym.st_value |= 1; - } - - src = &newsym; - } - bfd_elf32_swap_symbol_out (abfd, src, cdst, shndx); -} - -/* Add the PT_ARM_EXIDX program header. */ - -static bfd_boolean -elf32_arm_modify_segment_map (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - struct elf_segment_map *m; - asection *sec; - - sec = bfd_get_section_by_name (abfd, ".ARM.exidx"); - if (sec != NULL && (sec->flags & SEC_LOAD) != 0) - { - /* If there is already a PT_ARM_EXIDX header, then we do not - want to add another one. This situation arises when running - "strip"; the input binary already has the header. */ - m = elf_seg_map (abfd); - while (m && m->p_type != PT_ARM_EXIDX) - m = m->next; - if (!m) - { - m = (struct elf_segment_map *) - bfd_zalloc (abfd, sizeof (struct elf_segment_map)); - if (m == NULL) - return FALSE; - m->p_type = PT_ARM_EXIDX; - m->count = 1; - m->sections[0] = sec; - - m->next = elf_seg_map (abfd); - elf_seg_map (abfd) = m; - } - } - - return TRUE; -} - -/* We may add a PT_ARM_EXIDX program header. */ - -static int -elf32_arm_additional_program_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - asection *sec; - - sec = bfd_get_section_by_name (abfd, ".ARM.exidx"); - if (sec != NULL && (sec->flags & SEC_LOAD) != 0) - return 1; - else - return 0; -} - -/* Hook called by the linker routine which adds symbols from an object - file. */ - -static bfd_boolean -elf32_arm_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, const char **namep, - flagword *flagsp, asection **secp, bfd_vma *valp) -{ - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - if (elf32_arm_hash_table (info) == NULL) - return FALSE; - - if (elf32_arm_hash_table (info)->vxworks_p - && !elf_vxworks_add_symbol_hook (abfd, info, sym, namep, - flagsp, secp, valp)) - return FALSE; - - return TRUE; -} - -/* We use this to override swap_symbol_in and swap_symbol_out. */ -const struct elf_size_info elf32_arm_size_info = -{ - sizeof (Elf32_External_Ehdr), - sizeof (Elf32_External_Phdr), - sizeof (Elf32_External_Shdr), - sizeof (Elf32_External_Rel), - sizeof (Elf32_External_Rela), - sizeof (Elf32_External_Sym), - sizeof (Elf32_External_Dyn), - sizeof (Elf_External_Note), - 4, - 1, - 32, 2, - ELFCLASS32, EV_CURRENT, - bfd_elf32_write_out_phdrs, - bfd_elf32_write_shdrs_and_ehdr, - bfd_elf32_checksum_contents, - bfd_elf32_write_relocs, - elf32_arm_swap_symbol_in, - elf32_arm_swap_symbol_out, - bfd_elf32_slurp_reloc_table, - bfd_elf32_slurp_symbol_table, - bfd_elf32_swap_dyn_in, - bfd_elf32_swap_dyn_out, - bfd_elf32_swap_reloc_in, - bfd_elf32_swap_reloc_out, - bfd_elf32_swap_reloca_in, - bfd_elf32_swap_reloca_out -}; - -static bfd_vma -read_code32 (const bfd *abfd, const bfd_byte *addr) -{ - /* V7 BE8 code is always little endian. */ - if ((elf_elfheader (abfd)->e_flags & EF_ARM_BE8) != 0) - return bfd_getl32 (addr); - - return bfd_get_32 (abfd, addr); -} - -static bfd_vma -read_code16 (const bfd *abfd, const bfd_byte *addr) -{ - /* V7 BE8 code is always little endian. */ - if ((elf_elfheader (abfd)->e_flags & EF_ARM_BE8) != 0) - return bfd_getl16 (addr); - - return bfd_get_16 (abfd, addr); -} - -/* Return size of plt0 entry starting at ADDR - or (bfd_vma) -1 if size can not be determined. */ - -static bfd_vma -elf32_arm_plt0_size (const bfd *abfd, const bfd_byte *addr) -{ - bfd_vma first_word; - bfd_vma plt0_size; - - first_word = read_code32 (abfd, addr); - - if (first_word == elf32_arm_plt0_entry[0]) - plt0_size = 4 * ARRAY_SIZE (elf32_arm_plt0_entry); - else if (first_word == elf32_thumb2_plt0_entry[0]) - plt0_size = 4 * ARRAY_SIZE (elf32_thumb2_plt0_entry); - else - /* We don't yet handle this PLT format. */ - return (bfd_vma) -1; - - return plt0_size; -} - -/* Return size of plt entry starting at offset OFFSET - of plt section located at address START - or (bfd_vma) -1 if size can not be determined. */ - -static bfd_vma -elf32_arm_plt_size (const bfd *abfd, const bfd_byte *start, bfd_vma offset) -{ - bfd_vma first_insn; - bfd_vma plt_size = 0; - const bfd_byte *addr = start + offset; - - /* PLT entry size if fixed on Thumb-only platforms. */ - if (read_code32 (abfd, start) == elf32_thumb2_plt0_entry[0]) - return 4 * ARRAY_SIZE (elf32_thumb2_plt_entry); - - /* Respect Thumb stub if necessary. */ - if (read_code16 (abfd, addr) == elf32_arm_plt_thumb_stub[0]) - { - plt_size += 2 * ARRAY_SIZE(elf32_arm_plt_thumb_stub); - } - - /* Strip immediate from first add. */ - first_insn = read_code32 (abfd, addr + plt_size) & 0xffffff00; - -#ifdef FOUR_WORD_PLT - if (first_insn == elf32_arm_plt_entry[0]) - plt_size += 4 * ARRAY_SIZE (elf32_arm_plt_entry); -#else - if (first_insn == elf32_arm_plt_entry_long[0]) - plt_size += 4 * ARRAY_SIZE (elf32_arm_plt_entry_long); - else if (first_insn == elf32_arm_plt_entry_short[0]) - plt_size += 4 * ARRAY_SIZE (elf32_arm_plt_entry_short); -#endif - else - /* We don't yet handle this PLT format. */ - return (bfd_vma) -1; - - return plt_size; -} - -/* Implementation is shamelessly borrowed from _bfd_elf_get_synthetic_symtab. */ - -static long -elf32_arm_get_synthetic_symtab (bfd *abfd, - long symcount ATTRIBUTE_UNUSED, - asymbol **syms ATTRIBUTE_UNUSED, - long dynsymcount, - asymbol **dynsyms, - asymbol **ret) -{ - asection *relplt; - asymbol *s; - arelent *p; - long count, i, n; - size_t size; - Elf_Internal_Shdr *hdr; - char *names; - asection *plt; - bfd_vma offset; - bfd_byte *data; - - *ret = NULL; - - if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) - return 0; - - if (dynsymcount <= 0) - return 0; - - relplt = bfd_get_section_by_name (abfd, ".rel.plt"); - 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; - - if (!elf32_arm_size_info.slurp_reloc_table (abfd, relplt, dynsyms, TRUE)) - return -1; - - data = plt->contents; - if (data == NULL) - { - if (!bfd_get_full_section_contents(abfd, (asection *) plt, &data) || data == NULL) - return -1; - bfd_cache_section_contents((asection *) plt, data); - } - - count = relplt->size / hdr->sh_entsize; - size = count * sizeof (asymbol); - p = relplt->relocation; - for (i = 0; i < count; i++, p += elf32_arm_size_info.int_rels_per_ext_rel) - { - size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); - if (p->addend != 0) - size += sizeof ("+0x") - 1 + 8; - } - - s = *ret = (asymbol *) bfd_malloc (size); - if (s == NULL) - return -1; - - offset = elf32_arm_plt0_size (abfd, data); - if (offset == (bfd_vma) -1) - return -1; - - names = (char *) (s + count); - p = relplt->relocation; - n = 0; - for (i = 0; i < count; i++, p += elf32_arm_size_info.int_rels_per_ext_rel) - { - size_t len; - - bfd_vma plt_size = elf32_arm_plt_size (abfd, data, offset); - if (plt_size == (bfd_vma) -1) - break; - - *s = **p->sym_ptr_ptr; - /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since - we are defining a symbol, ensure one of them is set. */ - if ((s->flags & BSF_LOCAL) == 0) - s->flags |= BSF_GLOBAL; - s->flags |= BSF_SYNTHETIC; - s->section = plt; - s->value = offset; - s->name = names; - s->udata.p = NULL; - len = strlen ((*p->sym_ptr_ptr)->name); - memcpy (names, (*p->sym_ptr_ptr)->name, len); - names += len; - if (p->addend != 0) - { - char buf[30], *a; - - memcpy (names, "+0x", sizeof ("+0x") - 1); - names += sizeof ("+0x") - 1; - bfd_sprintf_vma (abfd, buf, p->addend); - for (a = buf; *a == '0'; ++a) - ; - len = strlen (a); - memcpy (names, a, len); - names += len; - } - memcpy (names, "@plt", sizeof ("@plt")); - names += sizeof ("@plt"); - ++s, ++n; - offset += plt_size; - } - - return n; -} - -static bfd_boolean -elf32_arm_section_flags (flagword *flags, const Elf_Internal_Shdr * hdr) -{ - if (hdr->sh_flags & SHF_ARM_PURECODE) - *flags |= SEC_ELF_PURECODE; - return TRUE; -} - -static flagword -elf32_arm_lookup_section_flags (char *flag_name) -{ - if (!strcmp (flag_name, "SHF_ARM_PURECODE")) - return SHF_ARM_PURECODE; - - return SEC_NO_FLAGS; -} - -static unsigned int -elf32_arm_count_additional_relocs (asection *sec) -{ - struct _arm_elf_section_data *arm_data; - arm_data = get_arm_elf_section_data (sec); - - return arm_data == NULL ? 0 : arm_data->additional_reloc_count; -} - -/* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which - has a type >= SHT_LOOS. Returns TRUE if these fields were initialised - FALSE otherwise. ISECTION is the best guess matching section from the - input bfd IBFD, but it might be NULL. */ - -static bfd_boolean -elf32_arm_copy_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED, - bfd *obfd ATTRIBUTE_UNUSED, - const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *osection) -{ - switch (osection->sh_type) - { - case SHT_ARM_EXIDX: - { - Elf_Internal_Shdr **oheaders = elf_elfsections (obfd); - Elf_Internal_Shdr **iheaders = elf_elfsections (ibfd); - unsigned i = 0; - - osection->sh_flags = SHF_ALLOC | SHF_LINK_ORDER; - osection->sh_info = 0; - - /* The sh_link field must be set to the text section associated with - this index section. Unfortunately the ARM EHABI does not specify - exactly how to determine this association. Our caller does try - to match up OSECTION with its corresponding input section however - so that is a good first guess. */ - if (isection != NULL - && osection->bfd_section != NULL - && isection->bfd_section != NULL - && isection->bfd_section->output_section != NULL - && isection->bfd_section->output_section == osection->bfd_section - && iheaders != NULL - && isection->sh_link > 0 - && isection->sh_link < elf_numsections (ibfd) - && iheaders[isection->sh_link]->bfd_section != NULL - && iheaders[isection->sh_link]->bfd_section->output_section != NULL - ) - { - for (i = elf_numsections (obfd); i-- > 0;) - if (oheaders[i]->bfd_section - == iheaders[isection->sh_link]->bfd_section->output_section) - break; - } - - if (i == 0) - { - /* Failing that we have to find a matching section ourselves. If - we had the output section name available we could compare that - with input section names. Unfortunately we don't. So instead - we use a simple heuristic and look for the nearest executable - section before this one. */ - for (i = elf_numsections (obfd); i-- > 0;) - if (oheaders[i] == osection) - break; - if (i == 0) - break; - - while (i-- > 0) - if (oheaders[i]->sh_type == SHT_PROGBITS - && (oheaders[i]->sh_flags & (SHF_ALLOC | SHF_EXECINSTR)) - == (SHF_ALLOC | SHF_EXECINSTR)) - break; - } - - if (i) - { - osection->sh_link = i; - /* If the text section was part of a group - then the index section should be too. */ - if (oheaders[i]->sh_flags & SHF_GROUP) - osection->sh_flags |= SHF_GROUP; - return TRUE; - } - } - break; - - case SHT_ARM_PREEMPTMAP: - osection->sh_flags = SHF_ALLOC; - break; - - case SHT_ARM_ATTRIBUTES: - case SHT_ARM_DEBUGOVERLAY: - case SHT_ARM_OVERLAYSECTION: - default: - break; - } - - return FALSE; -} - -/* Returns TRUE if NAME is an ARM mapping symbol. - Traditionally the symbols $a, $d and $t have been used. - The ARM ELF standard also defines $x (for A64 code). It also allows a - period initiated suffix to be added to the symbol: "$[adtx]\.[:sym_char]+". - Other tools might also produce $b (Thumb BL), $f, $p, $m and $v, but we do - not support them here. $t.x indicates the start of ThumbEE instructions. */ - -static bfd_boolean -is_arm_mapping_symbol (const char * name) -{ - return name != NULL /* Paranoia. */ - && name[0] == '$' /* Note: if objcopy --prefix-symbols has been used then - the mapping symbols could have acquired a prefix. - We do not support this here, since such symbols no - longer conform to the ARM ELF ABI. */ - && (name[1] == 'a' || name[1] == 'd' || name[1] == 't' || name[1] == 'x') - && (name[2] == 0 || name[2] == '.'); - /* FIXME: Strictly speaking the symbol is only a valid mapping symbol if - any characters that follow the period are legal characters for the body - of a symbol's name. For now we just assume that this is the case. */ -} - -/* Make sure that mapping symbols in object files are not removed via the - "strip --strip-unneeded" tool. These symbols are needed in order to - correctly generate interworking veneers, and for byte swapping code - regions. Once an object file has been linked, it is safe to remove the - symbols as they will no longer be needed. */ - -static void -elf32_arm_backend_symbol_processing (bfd *abfd, asymbol *sym) -{ - if (((abfd->flags & (EXEC_P | DYNAMIC)) == 0) - && sym->section != bfd_abs_section_ptr - && is_arm_mapping_symbol (sym->name)) - sym->flags |= BSF_KEEP; -} - -#undef elf_backend_copy_special_section_fields -#define elf_backend_copy_special_section_fields elf32_arm_copy_special_section_fields - -#define ELF_ARCH bfd_arch_arm -#define ELF_TARGET_ID ARM_ELF_DATA -#define ELF_MACHINE_CODE EM_ARM -#ifdef __QNXTARGET__ -#define ELF_MAXPAGESIZE 0x1000 -#else -#define ELF_MAXPAGESIZE 0x10000 -#endif -#define ELF_MINPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 - -#define bfd_elf32_mkobject elf32_arm_mkobject - -#define bfd_elf32_bfd_copy_private_bfd_data elf32_arm_copy_private_bfd_data -#define bfd_elf32_bfd_merge_private_bfd_data elf32_arm_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags elf32_arm_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data elf32_arm_print_private_bfd_data -#define bfd_elf32_bfd_link_hash_table_create elf32_arm_link_hash_table_create -#define bfd_elf32_bfd_reloc_type_lookup elf32_arm_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf32_arm_reloc_name_lookup -#define bfd_elf32_find_nearest_line elf32_arm_find_nearest_line -#define bfd_elf32_find_inliner_info elf32_arm_find_inliner_info -#define bfd_elf32_new_section_hook elf32_arm_new_section_hook -#define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol -#define bfd_elf32_bfd_final_link elf32_arm_final_link -#define bfd_elf32_get_synthetic_symtab elf32_arm_get_synthetic_symtab - -#define elf_backend_get_symbol_type elf32_arm_get_symbol_type -#define elf_backend_gc_mark_hook elf32_arm_gc_mark_hook -#define elf_backend_gc_mark_extra_sections elf32_arm_gc_mark_extra_sections -#define elf_backend_check_relocs elf32_arm_check_relocs -#define elf_backend_update_relocs elf32_arm_update_relocs -#define elf_backend_relocate_section elf32_arm_relocate_section -#define elf_backend_write_section elf32_arm_write_section -#define elf_backend_adjust_dynamic_symbol elf32_arm_adjust_dynamic_symbol -#define elf_backend_create_dynamic_sections elf32_arm_create_dynamic_sections -#define elf_backend_finish_dynamic_symbol elf32_arm_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections elf32_arm_finish_dynamic_sections -#define elf_backend_size_dynamic_sections elf32_arm_size_dynamic_sections -#define elf_backend_always_size_sections elf32_arm_always_size_sections -#define elf_backend_init_index_section _bfd_elf_init_2_index_sections -#define elf_backend_post_process_headers elf32_arm_post_process_headers -#define elf_backend_reloc_type_class elf32_arm_reloc_type_class -#define elf_backend_object_p elf32_arm_object_p -#define elf_backend_fake_sections elf32_arm_fake_sections -#define elf_backend_section_from_shdr elf32_arm_section_from_shdr -#define elf_backend_final_write_processing elf32_arm_final_write_processing -#define elf_backend_copy_indirect_symbol elf32_arm_copy_indirect_symbol -#define elf_backend_size_info elf32_arm_size_info -#define elf_backend_modify_segment_map elf32_arm_modify_segment_map -#define elf_backend_additional_program_headers elf32_arm_additional_program_headers -#define elf_backend_output_arch_local_syms elf32_arm_output_arch_local_syms -#define elf_backend_filter_implib_symbols elf32_arm_filter_implib_symbols -#define elf_backend_begin_write_processing elf32_arm_begin_write_processing -#define elf_backend_add_symbol_hook elf32_arm_add_symbol_hook -#define elf_backend_count_additional_relocs elf32_arm_count_additional_relocs -#define elf_backend_symbol_processing elf32_arm_backend_symbol_processing - -#define elf_backend_can_refcount 1 -#define elf_backend_can_gc_sections 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_want_dynrelro 1 -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 0 -#define elf_backend_default_use_rela_p 0 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_got_header_size 12 -#define elf_backend_extern_protected_data 1 - -#undef elf_backend_obj_attrs_vendor -#define elf_backend_obj_attrs_vendor "aeabi" -#undef elf_backend_obj_attrs_section -#define elf_backend_obj_attrs_section ".ARM.attributes" -#undef elf_backend_obj_attrs_arg_type -#define elf_backend_obj_attrs_arg_type elf32_arm_obj_attrs_arg_type -#undef elf_backend_obj_attrs_section_type -#define elf_backend_obj_attrs_section_type SHT_ARM_ATTRIBUTES -#define elf_backend_obj_attrs_order elf32_arm_obj_attrs_order -#define elf_backend_obj_attrs_handle_unknown elf32_arm_obj_attrs_handle_unknown - -#undef elf_backend_section_flags -#define elf_backend_section_flags elf32_arm_section_flags -#undef elf_backend_lookup_section_flags_hook -#define elf_backend_lookup_section_flags_hook elf32_arm_lookup_section_flags - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" - -/* Native Client targets. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM arm_elf32_nacl_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-littlearm-nacl" -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM arm_elf32_nacl_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-bigarm-nacl" - -/* Like elf32_arm_link_hash_table_create -- but overrides - appropriately for NaCl. */ - -static struct bfd_link_hash_table * -elf32_arm_nacl_link_hash_table_create (bfd *abfd) -{ - struct bfd_link_hash_table *ret; - - ret = elf32_arm_link_hash_table_create (abfd); - if (ret) - { - struct elf32_arm_link_hash_table *htab - = (struct elf32_arm_link_hash_table *) ret; - - htab->nacl_p = 1; - - htab->plt_header_size = 4 * ARRAY_SIZE (elf32_arm_nacl_plt0_entry); - htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_arm_nacl_plt_entry); - } - return ret; -} - -/* Since NaCl doesn't use the ARM-specific unwind format, we don't - really need to use elf32_arm_modify_segment_map. But we do it - anyway just to reduce gratuitous differences with the stock ARM backend. */ - -static bfd_boolean -elf32_arm_nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) -{ - return (elf32_arm_modify_segment_map (abfd, info) - && nacl_modify_segment_map (abfd, info)); -} - -static void -elf32_arm_nacl_final_write_processing (bfd *abfd, bfd_boolean linker) -{ - elf32_arm_final_write_processing (abfd, linker); - nacl_final_write_processing (abfd, linker); -} - -static bfd_vma -elf32_arm_nacl_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma - + 4 * (ARRAY_SIZE (elf32_arm_nacl_plt0_entry) + - i * ARRAY_SIZE (elf32_arm_nacl_plt_entry)); -} - -#undef elf32_bed -#define elf32_bed elf32_arm_nacl_bed -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create \ - elf32_arm_nacl_link_hash_table_create -#undef elf_backend_plt_alignment -#define elf_backend_plt_alignment 4 -#undef elf_backend_modify_segment_map -#define elf_backend_modify_segment_map elf32_arm_nacl_modify_segment_map -#undef elf_backend_modify_program_headers -#define elf_backend_modify_program_headers nacl_modify_program_headers -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing elf32_arm_nacl_final_write_processing -#undef bfd_elf32_get_synthetic_symtab -#undef elf_backend_plt_sym_val -#define elf_backend_plt_sym_val elf32_arm_nacl_plt_sym_val -#undef elf_backend_copy_special_section_fields - -#undef ELF_MINPAGESIZE -#undef ELF_COMMONPAGESIZE - - -#include "elf32-target.h" - -/* Reset to defaults. */ -#undef elf_backend_plt_alignment -#undef elf_backend_modify_segment_map -#define elf_backend_modify_segment_map elf32_arm_modify_segment_map -#undef elf_backend_modify_program_headers -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing elf32_arm_final_write_processing -#undef ELF_MINPAGESIZE -#define ELF_MINPAGESIZE 0x1000 -#undef ELF_COMMONPAGESIZE -#define ELF_COMMONPAGESIZE 0x1000 - - -/* VxWorks Targets. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM arm_elf32_vxworks_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-littlearm-vxworks" -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM arm_elf32_vxworks_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-bigarm-vxworks" - -/* Like elf32_arm_link_hash_table_create -- but overrides - appropriately for VxWorks. */ - -static struct bfd_link_hash_table * -elf32_arm_vxworks_link_hash_table_create (bfd *abfd) -{ - struct bfd_link_hash_table *ret; - - ret = elf32_arm_link_hash_table_create (abfd); - if (ret) - { - struct elf32_arm_link_hash_table *htab - = (struct elf32_arm_link_hash_table *) ret; - htab->use_rel = 0; - htab->vxworks_p = 1; - } - return ret; -} - -static void -elf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) -{ - elf32_arm_final_write_processing (abfd, linker); - elf_vxworks_final_write_processing (abfd, linker); -} - -#undef elf32_bed -#define elf32_bed elf32_arm_vxworks_bed - -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create elf32_arm_vxworks_link_hash_table_create -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing elf32_arm_vxworks_final_write_processing -#undef elf_backend_emit_relocs -#define elf_backend_emit_relocs elf_vxworks_emit_relocs - -#undef elf_backend_may_use_rel_p -#define elf_backend_may_use_rel_p 0 -#undef elf_backend_may_use_rela_p -#define elf_backend_may_use_rela_p 1 -#undef elf_backend_default_use_rela_p -#define elf_backend_default_use_rela_p 1 -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 1 -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x1000 - -#include "elf32-target.h" - - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf32_arm_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - bfd_boolean flags_compatible = TRUE; - asection *sec; - - /* Check if we have the same endianness. */ - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if (! is_arm_elf (ibfd) || ! is_arm_elf (obfd)) - return TRUE; - - if (!elf32_arm_merge_eabi_attributes (ibfd, info)) - return FALSE; - - /* The input BFD must have had its flags initialised. */ - /* The following seems bogus to me -- The flags are initialized in - the assembler but I don't think an elf_flags_init field is - written into the object. */ - /* BFD_ASSERT (elf_flags_init (ibfd)); */ - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - /* In theory there is no reason why we couldn't handle this. However - in practice it isn't even close to working and there is no real - reason to want it. */ - if (EF_ARM_EABI_VERSION (in_flags) >= EF_ARM_EABI_VER4 - && !(ibfd->flags & DYNAMIC) - && (in_flags & EF_ARM_BE8)) - { - _bfd_error_handler (_("error: %B is already in final BE8 format"), - ibfd); - return FALSE; - } - - if (!elf_flags_init (obfd)) - { - /* If the input is the default architecture and had the default - flags then do not bother setting the flags for the output - architecture, instead allow future merges to do this. If no - future merges ever set these flags then they will retain their - uninitialised values, which surprise surprise, correspond - to the default values. */ - if (bfd_get_arch_info (ibfd)->the_default - && elf_elfheader (ibfd)->e_flags == 0) - return TRUE; - - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); - - return TRUE; - } - - /* Determine what should happen if the input ARM architecture - does not match the output ARM architecture. */ - if (! bfd_arm_merge_machines (ibfd, obfd)) - return FALSE; - - /* Identical flags must be compatible. */ - if (in_flags == out_flags) - return TRUE; - - /* Check to see if the input BFD actually contains any sections. If - not, its flags may not have been initialised either, but it - cannot actually cause any incompatiblity. Do not short-circuit - dynamic objects; their section list may be emptied by - elf_link_add_object_symbols. - - Also check to see if there are no code sections in the input. - In this case there is no need to check for code specific flags. - XXX - do we need to worry about floating-point format compatability - in data sections ? */ - if (!(ibfd->flags & DYNAMIC)) - { - bfd_boolean null_input_bfd = TRUE; - bfd_boolean only_data_sections = TRUE; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - /* Ignore synthetic glue sections. */ - if (strcmp (sec->name, ".glue_7") - && strcmp (sec->name, ".glue_7t")) - { - if ((bfd_get_section_flags (ibfd, sec) - & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) - == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) - only_data_sections = FALSE; - - null_input_bfd = FALSE; - break; - } - } - - if (null_input_bfd || only_data_sections) - return TRUE; - } - - /* Complain about various flag mismatches. */ - if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags), - EF_ARM_EABI_VERSION (out_flags))) - { - _bfd_error_handler - (_("error: Source object %B has EABI version %d, but target %B has EABI version %d"), - ibfd, (in_flags & EF_ARM_EABIMASK) >> 24, - obfd, (out_flags & EF_ARM_EABIMASK) >> 24); - return FALSE; - } - - /* Not sure what needs to be checked for EABI versions >= 1. */ - /* VxWorks libraries do not use these flags. */ - if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed - && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed - && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN) - { - if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26)) - { - _bfd_error_handler - (_("error: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"), - ibfd, in_flags & EF_ARM_APCS_26 ? 26 : 32, - obfd, out_flags & EF_ARM_APCS_26 ? 26 : 32); - flags_compatible = FALSE; - } - - if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT)) - { - if (in_flags & EF_ARM_APCS_FLOAT) - _bfd_error_handler - (_("error: %B passes floats in float registers, whereas %B passes them in integer registers"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B passes floats in integer registers, whereas %B passes them in float registers"), - ibfd, obfd); - - flags_compatible = FALSE; - } - - if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT)) - { - if (in_flags & EF_ARM_VFP_FLOAT) - _bfd_error_handler - (_("error: %B uses VFP instructions, whereas %B does not"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B uses FPA instructions, whereas %B does not"), - ibfd, obfd); - - flags_compatible = FALSE; - } - - if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT)) - { - if (in_flags & EF_ARM_MAVERICK_FLOAT) - _bfd_error_handler - (_("error: %B uses Maverick instructions, whereas %B does not"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B does not use Maverick instructions, whereas %B does"), - ibfd, obfd); - - flags_compatible = FALSE; - } - -#ifdef EF_ARM_SOFT_FLOAT - if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT)) - { - /* We can allow interworking between code that is VFP format - layout, and uses either soft float or integer regs for - passing floating point arguments and results. We already - know that the APCS_FLOAT flags match; similarly for VFP - flags. */ - if ((in_flags & EF_ARM_APCS_FLOAT) != 0 - || (in_flags & EF_ARM_VFP_FLOAT) == 0) - { - if (in_flags & EF_ARM_SOFT_FLOAT) - _bfd_error_handler - (_("error: %B uses software FP, whereas %B uses hardware FP"), - ibfd, obfd); - else - _bfd_error_handler - (_("error: %B uses hardware FP, whereas %B uses software FP"), - ibfd, obfd); - - flags_compatible = FALSE; - } - } -#endif - - /* Interworking mismatch is only a warning. */ - if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK)) - { - if (in_flags & EF_ARM_INTERWORK) - { - _bfd_error_handler - (_("Warning: %B supports interworking, whereas %B does not"), - ibfd, obfd); - } - else - { - _bfd_error_handler - (_("Warning: %B does not support interworking, whereas %B does"), - ibfd, obfd); - } - } - } - - return flags_compatible; -} - - -/* Symbian OS Targets. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM arm_elf32_symbian_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-littlearm-symbian" -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM arm_elf32_symbian_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-bigarm-symbian" - -/* Like elf32_arm_link_hash_table_create -- but overrides - appropriately for Symbian OS. */ - -static struct bfd_link_hash_table * -elf32_arm_symbian_link_hash_table_create (bfd *abfd) -{ - struct bfd_link_hash_table *ret; - - ret = elf32_arm_link_hash_table_create (abfd); - if (ret) - { - struct elf32_arm_link_hash_table *htab - = (struct elf32_arm_link_hash_table *)ret; - /* There is no PLT header for Symbian OS. */ - htab->plt_header_size = 0; - /* The PLT entries are each one instruction and one word. */ - htab->plt_entry_size = 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry); - htab->symbian_p = 1; - /* Symbian uses armv5t or above, so use_blx is always true. */ - htab->use_blx = 1; - htab->root.is_relocatable_executable = 1; - } - return ret; -} - -static const struct bfd_elf_special_section -elf32_arm_symbian_special_sections[] = -{ - /* In a BPABI executable, the dynamic linking sections do not go in - the loadable read-only segment. The post-linker may wish to - refer to these sections, but they are not part of the final - program image. */ - { STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, 0 }, - { STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, 0 }, - { STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, 0 }, - { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, 0 }, - { STRING_COMMA_LEN (".hash"), 0, SHT_HASH, 0 }, - /* These sections do not need to be writable as the SymbianOS - postlinker will arrange things so that no dynamic relocation is - required. */ - { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC }, - { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC }, - { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } -}; - -static void -elf32_arm_symbian_begin_write_processing (bfd *abfd, - struct bfd_link_info *link_info) -{ - /* BPABI objects are never loaded directly by an OS kernel; they are - processed by a postlinker first, into an OS-specific format. If - the D_PAGED bit is set on the file, BFD will align segments on - page boundaries, so that an OS can directly map the file. With - BPABI objects, that just results in wasted space. In addition, - because we clear the D_PAGED bit, map_sections_to_segments will - recognize that the program headers should not be mapped into any - loadable segment. */ - abfd->flags &= ~D_PAGED; - elf32_arm_begin_write_processing (abfd, link_info); -} - -static bfd_boolean -elf32_arm_symbian_modify_segment_map (bfd *abfd, - struct bfd_link_info *info) -{ - struct elf_segment_map *m; - asection *dynsec; - - /* BPABI shared libraries and executables should have a PT_DYNAMIC - segment. However, because the .dynamic section is not marked - with SEC_LOAD, the generic ELF code will not create such a - segment. */ - dynsec = bfd_get_section_by_name (abfd, ".dynamic"); - if (dynsec) - { - for (m = elf_seg_map (abfd); m != NULL; m = m->next) - if (m->p_type == PT_DYNAMIC) - break; - - if (m == NULL) - { - m = _bfd_elf_make_dynamic_segment (abfd, dynsec); - m->next = elf_seg_map (abfd); - elf_seg_map (abfd) = m; - } - } - - /* Also call the generic arm routine. */ - return elf32_arm_modify_segment_map (abfd, info); -} - -/* 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 -elf32_arm_symbian_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + 4 * ARRAY_SIZE (elf32_arm_symbian_plt_entry) * i; -} - -#undef elf32_bed -#define elf32_bed elf32_arm_symbian_bed - -/* The dynamic sections are not allocated on SymbianOS; the postlinker - will process them and then discard them. */ -#undef ELF_DYNAMIC_SEC_FLAGS -#define ELF_DYNAMIC_SEC_FLAGS \ - (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED) - -#undef elf_backend_emit_relocs - -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create elf32_arm_symbian_link_hash_table_create -#undef elf_backend_special_sections -#define elf_backend_special_sections elf32_arm_symbian_special_sections -#undef elf_backend_begin_write_processing -#define elf_backend_begin_write_processing elf32_arm_symbian_begin_write_processing -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing elf32_arm_final_write_processing - -#undef elf_backend_modify_segment_map -#define elf_backend_modify_segment_map elf32_arm_symbian_modify_segment_map - -/* There is no .got section for BPABI objects, and hence no header. */ -#undef elf_backend_got_header_size -#define elf_backend_got_header_size 0 - -/* Similarly, there is no .got.plt section. */ -#undef elf_backend_want_got_plt -#define elf_backend_want_got_plt 0 - -#undef elf_backend_plt_sym_val -#define elf_backend_plt_sym_val elf32_arm_symbian_plt_sym_val - -#undef elf_backend_may_use_rel_p -#define elf_backend_may_use_rel_p 1 -#undef elf_backend_may_use_rela_p -#define elf_backend_may_use_rela_p 0 -#undef elf_backend_default_use_rela_p -#define elf_backend_default_use_rela_p 0 -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 0 -#undef elf_backend_dtrel_excludes_plt -#define elf_backend_dtrel_excludes_plt 0 -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x8000 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-avr.c b/sdcc/support/sdbinutils/bfd/elf32-avr.c deleted file mode 100644 index 46e15ec4d..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-avr.c +++ /dev/null @@ -1,4257 +0,0 @@ -/* AVR-specific support for 32-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Denis Chertykov - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/avr.h" -#include "elf32-avr.h" -#include "bfd_stdint.h" - -/* Enable debugging printout at stdout with this variable. */ -static bfd_boolean debug_relax = FALSE; - -/* Enable debugging printout at stdout with this variable. */ -static bfd_boolean debug_stubs = FALSE; - -static bfd_reloc_status_type -bfd_elf_avr_diff_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -/* Hash table initialization and handling. Code is taken from the hppa port - and adapted to the needs of AVR. */ - -/* We use two hash tables to hold information for linking avr objects. - - The first is the elf32_avr_link_hash_table which is derived from the - stanard ELF linker hash table. We use this as a place to attach the other - hash table and some static information. - - The second is the stub hash table which is derived from the base BFD - hash table. The stub hash table holds the information on the linker - stubs. */ - -struct elf32_avr_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry bh_root; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump). */ - bfd_vma target_value; - - /* This way we could mark stubs to be no longer necessary. */ - bfd_boolean is_actually_needed; -}; - -struct elf32_avr_link_hash_table -{ - /* The main hash table. */ - struct elf_link_hash_table etab; - - /* The stub hash table. */ - struct bfd_hash_table bstab; - - bfd_boolean no_stubs; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* The stub section. */ - asection *stub_sec; - - /* Usually 0, unless we are generating code for a bootloader. Will - be initialized by elf32_avr_size_stubs to the vma offset of the - output section associated with the stub section. */ - bfd_vma vector_base; - - /* Assorted information used by elf32_avr_size_stubs. */ - unsigned int bfd_count; - unsigned int top_index; - asection ** input_list; - Elf_Internal_Sym ** all_local_syms; - - /* Tables for mapping vma beyond the 128k boundary to the address of the - corresponding stub. (AMT) - "amt_max_entry_cnt" reflects the number of entries that memory is allocated - for in the "amt_stub_offsets" and "amt_destination_addr" arrays. - "amt_entry_cnt" informs how many of these entries actually contain - useful data. */ - unsigned int amt_entry_cnt; - unsigned int amt_max_entry_cnt; - bfd_vma * amt_stub_offsets; - bfd_vma * amt_destination_addr; -}; - -/* Various hash macros and functions. */ -#define avr_link_hash_table(p) \ - /* PR 3874: Check that we have an AVR style hash table before using it. */\ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == AVR_ELF_DATA ? ((struct elf32_avr_link_hash_table *) ((p)->hash)) : NULL) - -#define avr_stub_hash_entry(ent) \ - ((struct elf32_avr_stub_hash_entry *)(ent)) - -#define avr_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_avr_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -static reloc_howto_type elf_avr_howto_table[] = -{ - HOWTO (R_AVR_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_AVR_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 7 bit PC relative relocation. */ - HOWTO (R_AVR_7_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_7_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 13 bit PC relative relocation. */ - HOWTO (R_AVR_13_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_13_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_AVR_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation for command address - Will be changed when linker stubs are needed. */ - HOWTO (R_AVR_16_PM, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_16_PM", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 16 bit address. - For LDI command. */ - HOWTO (R_AVR_LO8_LDI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LO8_LDI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A high 8 bit absolute relocation of 16 bit address. - For LDI command. */ - HOWTO (R_AVR_HI8_LDI, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HI8_LDI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A high 6 bit absolute relocation of 22 bit address. - For LDI command. As well second most significant 8 bit value of - a 32 bit link-time constant. */ - HOWTO (R_AVR_HH8_LDI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HH8_LDI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A negative low 8 bit absolute relocation of 16 bit address. - For LDI command. */ - HOWTO (R_AVR_LO8_LDI_NEG, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LO8_LDI_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A negative high 8 bit absolute relocation of 16 bit address. - For LDI command. */ - HOWTO (R_AVR_HI8_LDI_NEG, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HI8_LDI_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A negative high 6 bit absolute relocation of 22 bit address. - For LDI command. */ - HOWTO (R_AVR_HH8_LDI_NEG, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HH8_LDI_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will not be changed when linker stubs are needed. */ - HOWTO (R_AVR_LO8_LDI_PM, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LO8_LDI_PM", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will not be changed when linker stubs are needed. */ - HOWTO (R_AVR_HI8_LDI_PM, /* type */ - 9, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HI8_LDI_PM", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will not be changed when linker stubs are needed. */ - HOWTO (R_AVR_HH8_LDI_PM, /* type */ - 17, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HH8_LDI_PM", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will not be changed when linker stubs are needed. */ - HOWTO (R_AVR_LO8_LDI_PM_NEG, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LO8_LDI_PM_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will not be changed when linker stubs are needed. */ - HOWTO (R_AVR_HI8_LDI_PM_NEG, /* type */ - 9, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HI8_LDI_PM_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will not be changed when linker stubs are needed. */ - HOWTO (R_AVR_HH8_LDI_PM_NEG, /* type */ - 17, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HH8_LDI_PM_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Relocation for CALL command in ATmega. */ - HOWTO (R_AVR_CALL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 23, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_CALL", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A 16 bit absolute relocation of 16 bit address. - For LDI command. */ - HOWTO (R_AVR_LDI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LDI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A 6 bit absolute relocation of 6 bit offset. - For ldd/sdd command. */ - HOWTO (R_AVR_6, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_6", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A 6 bit absolute relocation of 6 bit offset. - For sbiw/adiw command. */ - HOWTO (R_AVR_6_ADIW, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_6_ADIW", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Most significant 8 bit value of a 32 bit link-time constant. */ - HOWTO (R_AVR_MS8_LDI, /* type */ - 24, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_MS8_LDI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Negative most significant 8 bit value of a 32 bit link-time constant. */ - HOWTO (R_AVR_MS8_LDI_NEG, /* type */ - 24, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_MS8_LDI_NEG", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will be changed when linker stubs are needed. */ - HOWTO (R_AVR_LO8_LDI_GS, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LO8_LDI_GS", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A low 8 bit absolute relocation of 24 bit program memory address. - For LDI command. Will be changed when linker stubs are needed. */ - HOWTO (R_AVR_HI8_LDI_GS, /* type */ - 9, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_HI8_LDI_GS", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* 8 bit offset. */ - HOWTO (R_AVR_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_8", /* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* lo8-part to use in .byte lo8(sym). */ - HOWTO (R_AVR_8_LO8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_8_LO8", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* hi8-part to use in .byte hi8(sym). */ - HOWTO (R_AVR_8_HI8, /* type */ - 8, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_8_HI8", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* hlo8-part to use in .byte hlo8(sym). */ - HOWTO (R_AVR_8_HLO8, /* type */ - 16, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_8_HLO8", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_AVR_DIFF8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_avr_diff_reloc, /* special_function */ - "R_AVR_DIFF8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_AVR_DIFF16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_avr_diff_reloc,/* special_function */ - "R_AVR_DIFF16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_AVR_DIFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_avr_diff_reloc,/* special_function */ - "R_AVR_DIFF32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* 7 bit immediate for LDS/STS in Tiny core. */ - HOWTO (R_AVR_LDS_STS_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_LDS_STS_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_AVR_PORT6, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_PORT6", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_AVR_PORT5, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_PORT5", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit PC relative relocation. */ - HOWTO (R_AVR_32_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AVR_32_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* Map BFD reloc types to AVR ELF reloc types. */ - -struct avr_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int elf_reloc_val; -}; - -static const struct avr_reloc_map avr_reloc_map[] = -{ - { BFD_RELOC_NONE, R_AVR_NONE }, - { BFD_RELOC_32, R_AVR_32 }, - { BFD_RELOC_AVR_7_PCREL, R_AVR_7_PCREL }, - { BFD_RELOC_AVR_13_PCREL, R_AVR_13_PCREL }, - { BFD_RELOC_16, R_AVR_16 }, - { BFD_RELOC_AVR_16_PM, R_AVR_16_PM }, - { BFD_RELOC_AVR_LO8_LDI, R_AVR_LO8_LDI}, - { BFD_RELOC_AVR_HI8_LDI, R_AVR_HI8_LDI }, - { BFD_RELOC_AVR_HH8_LDI, R_AVR_HH8_LDI }, - { BFD_RELOC_AVR_MS8_LDI, R_AVR_MS8_LDI }, - { BFD_RELOC_AVR_LO8_LDI_NEG, R_AVR_LO8_LDI_NEG }, - { BFD_RELOC_AVR_HI8_LDI_NEG, R_AVR_HI8_LDI_NEG }, - { BFD_RELOC_AVR_HH8_LDI_NEG, R_AVR_HH8_LDI_NEG }, - { BFD_RELOC_AVR_MS8_LDI_NEG, R_AVR_MS8_LDI_NEG }, - { BFD_RELOC_AVR_LO8_LDI_PM, R_AVR_LO8_LDI_PM }, - { BFD_RELOC_AVR_LO8_LDI_GS, R_AVR_LO8_LDI_GS }, - { BFD_RELOC_AVR_HI8_LDI_PM, R_AVR_HI8_LDI_PM }, - { BFD_RELOC_AVR_HI8_LDI_GS, R_AVR_HI8_LDI_GS }, - { BFD_RELOC_AVR_HH8_LDI_PM, R_AVR_HH8_LDI_PM }, - { BFD_RELOC_AVR_LO8_LDI_PM_NEG, R_AVR_LO8_LDI_PM_NEG }, - { BFD_RELOC_AVR_HI8_LDI_PM_NEG, R_AVR_HI8_LDI_PM_NEG }, - { BFD_RELOC_AVR_HH8_LDI_PM_NEG, R_AVR_HH8_LDI_PM_NEG }, - { BFD_RELOC_AVR_CALL, R_AVR_CALL }, - { BFD_RELOC_AVR_LDI, R_AVR_LDI }, - { BFD_RELOC_AVR_6, R_AVR_6 }, - { BFD_RELOC_AVR_6_ADIW, R_AVR_6_ADIW }, - { BFD_RELOC_8, R_AVR_8 }, - { BFD_RELOC_AVR_8_LO, R_AVR_8_LO8 }, - { BFD_RELOC_AVR_8_HI, R_AVR_8_HI8 }, - { BFD_RELOC_AVR_8_HLO, R_AVR_8_HLO8 }, - { BFD_RELOC_AVR_DIFF8, R_AVR_DIFF8 }, - { BFD_RELOC_AVR_DIFF16, R_AVR_DIFF16 }, - { BFD_RELOC_AVR_DIFF32, R_AVR_DIFF32 }, - { BFD_RELOC_AVR_LDS_STS_16, R_AVR_LDS_STS_16}, - { BFD_RELOC_AVR_PORT6, R_AVR_PORT6}, - { BFD_RELOC_AVR_PORT5, R_AVR_PORT5}, - { BFD_RELOC_32_PCREL, R_AVR_32_PCREL} -}; - -/* Meant to be filled one day with the wrap around address for the - specific device. I.e. should get the value 0x4000 for 16k devices, - 0x8000 for 32k devices and so on. - - We initialize it here with a value of 0x1000000 resulting in - that we will never suggest a wrap-around jump during relaxation. - The logic of the source code later on assumes that in - avr_pc_wrap_around one single bit is set. */ -static bfd_vma avr_pc_wrap_around = 0x10000000; - -/* If this variable holds a value different from zero, the linker relaxation - machine will try to optimize call/ret sequences by a single jump - instruction. This option could be switched off by a linker switch. */ -static int avr_replace_call_ret_sequences = 1; - - -/* Per-section relaxation related information for avr. */ - -struct avr_relax_info -{ - /* Track the avr property records that apply to this section. */ - - struct - { - /* Number of records in the list. */ - unsigned count; - - /* How many records worth of space have we allocated. */ - unsigned allocated; - - /* The records, only COUNT records are initialised. */ - struct avr_property_record *items; - } records; -}; - -/* Per section data, specialised for avr. */ - -struct elf_avr_section_data -{ - /* The standard data must appear first. */ - struct bfd_elf_section_data elf; - - /* Relaxation related information. */ - struct avr_relax_info relax_info; -}; - -/* Possibly initialise avr specific data for new section SEC from ABFD. */ - -static bfd_boolean -elf_avr_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - struct elf_avr_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - -/* Return a pointer to the relaxation information for SEC. */ - -static struct avr_relax_info * -get_avr_relax_info (asection *sec) -{ - struct elf_avr_section_data *section_data; - - /* No info available if no section or if it is an output section. */ - if (!sec || sec == sec->output_section) - return NULL; - - section_data = (struct elf_avr_section_data *) elf_section_data (sec); - return §ion_data->relax_info; -} - -/* Initialise the per section relaxation information for SEC. */ - -static void -init_avr_relax_info (asection *sec) -{ - struct avr_relax_info *relax_info = get_avr_relax_info (sec); - - relax_info->records.count = 0; - relax_info->records.allocated = 0; - relax_info->records.items = NULL; -} - -/* Initialize an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_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 elf32_avr_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf32_avr_stub_hash_entry *hsh; - - /* Initialize the local fields. */ - hsh = avr_stub_hash_entry (entry); - hsh->stub_offset = 0; - hsh->target_value = 0; - } - - return entry; -} - -/* This function is just a straight passthrough to the real - function in linker.c. Its prupose is so that its address - can be compared inside the avr_link_hash_table macro. */ - -static struct bfd_hash_entry * -elf32_avr_link_hash_newfunc (struct bfd_hash_entry * entry, - struct bfd_hash_table * table, - const char * string) -{ - return _bfd_elf_link_hash_newfunc (entry, table, string); -} - -/* Free the derived linker hash table. */ - -static void -elf32_avr_link_hash_table_free (bfd *obfd) -{ - struct elf32_avr_link_hash_table *htab - = (struct elf32_avr_link_hash_table *) obfd->link.hash; - - /* Free the address mapping table. */ - if (htab->amt_stub_offsets != NULL) - free (htab->amt_stub_offsets); - if (htab->amt_destination_addr != NULL) - free (htab->amt_destination_addr); - - bfd_hash_table_free (&htab->bstab); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create the derived linker hash table. The AVR ELF port uses the derived - hash table to keep information specific to the AVR ELF linker (without - using static variables). */ - -static struct bfd_link_hash_table * -elf32_avr_link_hash_table_create (bfd *abfd) -{ - struct elf32_avr_link_hash_table *htab; - bfd_size_type amt = sizeof (*htab); - - htab = bfd_zmalloc (amt); - if (htab == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&htab->etab, abfd, - elf32_avr_link_hash_newfunc, - sizeof (struct elf_link_hash_entry), - AVR_ELF_DATA)) - { - free (htab); - return NULL; - } - - /* Init the stub hash table too. */ - if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc, - sizeof (struct elf32_avr_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - htab->etab.root.hash_table_free = elf32_avr_link_hash_table_free; - - return &htab->etab.root; -} - -/* Calculates the effective distance of a pc relative jump/call. */ - -static int -avr_relative_distance_considering_wrap_around (unsigned int distance) -{ - unsigned int wrap_around_mask = avr_pc_wrap_around - 1; - int dist_with_wrap_around = distance & wrap_around_mask; - - if (dist_with_wrap_around > ((int) (avr_pc_wrap_around >> 1))) - dist_with_wrap_around -= avr_pc_wrap_around; - - return dist_with_wrap_around; -} - - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (avr_reloc_map) / sizeof (struct avr_reloc_map); - i++) - if (avr_reloc_map[i].bfd_reloc_val == code) - return &elf_avr_howto_table[avr_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf_avr_howto_table) / sizeof (elf_avr_howto_table[0]); - i++) - if (elf_avr_howto_table[i].name != NULL - && strcasecmp (elf_avr_howto_table[i].name, r_name) == 0) - return &elf_avr_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an AVR ELF reloc. */ - -static void -avr_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_AVR_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid AVR reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_avr_howto_table[r_type]; -} - -static bfd_boolean -avr_stub_is_required_for_16_bit_reloc (bfd_vma relocation) -{ - return (relocation >= 0x020000); -} - -/* Returns the address of the corresponding stub if there is one. - Returns otherwise an address above 0x020000. This function - could also be used, if there is no knowledge on the section where - the destination is found. */ - -static bfd_vma -avr_get_stub_addr (bfd_vma srel, - struct elf32_avr_link_hash_table *htab) -{ - unsigned int sindex; - bfd_vma stub_sec_addr = - (htab->stub_sec->output_section->vma + - htab->stub_sec->output_offset); - - for (sindex = 0; sindex < htab->amt_max_entry_cnt; sindex ++) - if (htab->amt_destination_addr[sindex] == srel) - return htab->amt_stub_offsets[sindex] + stub_sec_addr; - - /* Return an address that could not be reached by 16 bit relocs. */ - return 0x020000; -} - -/* Perform a diff relocation. Nothing to do, as the difference value is already - written into the section's contents. */ - -static bfd_reloc_status_type -bfd_elf_avr_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - return bfd_reloc_ok; -} - - -/* Perform a single relocation. By default we use the standard BFD - routines, but a few relocs, we have to do them ourselves. */ - -static bfd_reloc_status_type -avr_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation, - struct elf32_avr_link_hash_table * htab) -{ - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma x; - bfd_signed_vma srel; - bfd_signed_vma reloc_addr; - bfd_boolean use_stubs = FALSE; - /* Usually is 0, unless we are generating code for a bootloader. */ - bfd_signed_vma base_addr = htab->vector_base; - - /* Absolute addr of the reloc in the final excecutable. */ - reloc_addr = rel->r_offset + input_section->output_section->vma - + input_section->output_offset; - - switch (howto->type) - { - case R_AVR_7_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - if (srel > ((1 << 7) - 1) || (srel < - (1 << 7))) - return bfd_reloc_overflow; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfc07) | (((srel >> 1) << 3) & 0x3f8); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_13_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - - srel = avr_relative_distance_considering_wrap_around (srel); - - /* AVR addresses commands as words. */ - srel >>= 1; - - /* Check for overflow. */ - if (srel < -2048 || srel > 2047) - { - /* Relative distance is too large. */ - - /* Always apply WRAPAROUND for avr2, avr25, and avr4. */ - switch (bfd_get_mach (input_bfd)) - { - case bfd_mach_avr2: - case bfd_mach_avr25: - case bfd_mach_avr4: - break; - - default: - return bfd_reloc_overflow; - } - } - - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf000) | (srel & 0xfff); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_LO8_LDI: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_LDI: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if (((srel > 0) && (srel & 0xffff) > 255) - || ((srel < 0) && ((-srel) & 0xffff) > 128)) - /* Remove offset for data/eeprom section. */ - return bfd_reloc_overflow; - - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_6: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if (((srel & 0xffff) > 63) || (srel < 0)) - /* Remove offset for data/eeprom section. */ - return bfd_reloc_overflow; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xd3f8) | ((srel & 7) | ((srel & (3 << 3)) << 7) - | ((srel & (1 << 5)) << 8)); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_6_ADIW: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if (((srel & 0xffff) > 63) || (srel < 0)) - /* Remove offset for data/eeprom section. */ - return bfd_reloc_overflow; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xff30) | (srel & 0xf) | ((srel & 0x30) << 2); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HI8_LDI: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = (srel >> 8) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HH8_LDI: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = (srel >> 16) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_MS8_LDI: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = (srel >> 24) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_LO8_LDI_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HI8_LDI_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - srel = (srel >> 8) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HH8_LDI_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - srel = (srel >> 16) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_MS8_LDI_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - srel = (srel >> 24) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_LO8_LDI_GS: - use_stubs = (!htab->no_stubs); - /* Fall through. */ - case R_AVR_LO8_LDI_PM: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - - if (use_stubs - && avr_stub_is_required_for_16_bit_reloc (srel - base_addr)) - { - bfd_vma old_srel = srel; - - /* We need to use the address of the stub instead. */ - srel = avr_get_stub_addr (srel, htab); - if (debug_stubs) - printf ("LD: Using jump stub (at 0x%x) with destination 0x%x for " - "reloc at address 0x%x.\n", - (unsigned int) srel, - (unsigned int) old_srel, - (unsigned int) reloc_addr); - - if (avr_stub_is_required_for_16_bit_reloc (srel - base_addr)) - return bfd_reloc_outofrange; - } - - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HI8_LDI_GS: - use_stubs = (!htab->no_stubs); - /* Fall through. */ - case R_AVR_HI8_LDI_PM: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - - if (use_stubs - && avr_stub_is_required_for_16_bit_reloc (srel - base_addr)) - { - bfd_vma old_srel = srel; - - /* We need to use the address of the stub instead. */ - srel = avr_get_stub_addr (srel, htab); - if (debug_stubs) - printf ("LD: Using jump stub (at 0x%x) with destination 0x%x for " - "reloc at address 0x%x.\n", - (unsigned int) srel, - (unsigned int) old_srel, - (unsigned int) reloc_addr); - - if (avr_stub_is_required_for_16_bit_reloc (srel - base_addr)) - return bfd_reloc_outofrange; - } - - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - srel = (srel >> 8) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HH8_LDI_PM: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - srel = (srel >> 16) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_LO8_LDI_PM_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HI8_LDI_PM_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - srel = (srel >> 8) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_HH8_LDI_PM_NEG: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - srel = -srel; - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - srel = (srel >> 16) & 0xff; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0f0) | (srel & 0xf) | ((srel << 4) & 0xf00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_CALL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - x = bfd_get_16 (input_bfd, contents); - x |= ((srel & 0x10000) | ((srel << 3) & 0x1f00000)) >> 16; - bfd_put_16 (input_bfd, x, contents); - bfd_put_16 (input_bfd, (bfd_vma) srel & 0xffff, contents+2); - break; - - case R_AVR_16_PM: - use_stubs = (!htab->no_stubs); - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - - if (use_stubs - && avr_stub_is_required_for_16_bit_reloc (srel - base_addr)) - { - bfd_vma old_srel = srel; - - /* We need to use the address of the stub instead. */ - srel = avr_get_stub_addr (srel,htab); - if (debug_stubs) - printf ("LD: Using jump stub (at 0x%x) with destination 0x%x for " - "reloc at address 0x%x.\n", - (unsigned int) srel, - (unsigned int) old_srel, - (unsigned int) reloc_addr); - - if (avr_stub_is_required_for_16_bit_reloc (srel - base_addr)) - return bfd_reloc_outofrange; - } - - if (srel & 1) - return bfd_reloc_outofrange; - srel = srel >> 1; - bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents); - break; - - case R_AVR_DIFF8: - case R_AVR_DIFF16: - case R_AVR_DIFF32: - /* Nothing to do here, as contents already contains the diff value. */ - r = bfd_reloc_ok; - break; - - case R_AVR_LDS_STS_16: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if ((srel & 0xFFFF) < 0x40 || (srel & 0xFFFF) > 0xbf) - return bfd_reloc_outofrange; - srel = srel & 0x7f; - x = bfd_get_16 (input_bfd, contents); - x |= (srel & 0x0f) | ((srel & 0x30) << 5) | ((srel & 0x40) << 2); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_PORT6: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if ((srel & 0xffff) > 0x3f) - return bfd_reloc_outofrange; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf9f0) | ((srel & 0x30) << 5) | (srel & 0x0f); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_AVR_PORT5: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation + rel->r_addend; - if ((srel & 0xffff) > 0x1f) - return bfd_reloc_outofrange; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xff07) | ((srel & 0x1f) << 3); - bfd_put_16 (input_bfd, x, contents); - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - return r; -} - -/* Relocate an AVR ELF section. */ - -static bfd_boolean -elf32_avr_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - struct elf32_avr_link_hash_table * htab = avr_link_hash_table (info); - - if (htab == NULL) - return FALSE; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - howto = elf_avr_howto_table + r_type; - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = avr_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation, htab); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* The final processing done just before writing out a AVR ELF object - file. This gets the AVR architecture right based on the machine - number. */ - -static void -bfd_elf_avr_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_avr2: - val = E_AVR_MACH_AVR2; - break; - - case bfd_mach_avr1: - val = E_AVR_MACH_AVR1; - break; - - case bfd_mach_avr25: - val = E_AVR_MACH_AVR25; - break; - - case bfd_mach_avr3: - val = E_AVR_MACH_AVR3; - break; - - case bfd_mach_avr31: - val = E_AVR_MACH_AVR31; - break; - - case bfd_mach_avr35: - val = E_AVR_MACH_AVR35; - break; - - case bfd_mach_avr4: - val = E_AVR_MACH_AVR4; - break; - - case bfd_mach_avr5: - val = E_AVR_MACH_AVR5; - break; - - case bfd_mach_avr51: - val = E_AVR_MACH_AVR51; - break; - - case bfd_mach_avr6: - val = E_AVR_MACH_AVR6; - break; - - case bfd_mach_avrxmega1: - val = E_AVR_MACH_XMEGA1; - break; - - case bfd_mach_avrxmega2: - val = E_AVR_MACH_XMEGA2; - break; - - case bfd_mach_avrxmega3: - val = E_AVR_MACH_XMEGA3; - break; - - case bfd_mach_avrxmega4: - val = E_AVR_MACH_XMEGA4; - break; - - case bfd_mach_avrxmega5: - val = E_AVR_MACH_XMEGA5; - break; - - case bfd_mach_avrxmega6: - val = E_AVR_MACH_XMEGA6; - break; - - case bfd_mach_avrxmega7: - val = E_AVR_MACH_XMEGA7; - break; - - case bfd_mach_avrtiny: - val = E_AVR_MACH_AVRTINY; - break; - } - - elf_elfheader (abfd)->e_machine = EM_AVR; - elf_elfheader (abfd)->e_flags &= ~ EF_AVR_MACH; - elf_elfheader (abfd)->e_flags |= val; -} - -/* Set the right machine number. */ - -static bfd_boolean -elf32_avr_object_p (bfd *abfd) -{ - unsigned int e_set = bfd_mach_avr2; - - if (elf_elfheader (abfd)->e_machine == EM_AVR - || elf_elfheader (abfd)->e_machine == EM_AVR_OLD) - { - int e_mach = elf_elfheader (abfd)->e_flags & EF_AVR_MACH; - - switch (e_mach) - { - default: - case E_AVR_MACH_AVR2: - e_set = bfd_mach_avr2; - break; - - case E_AVR_MACH_AVR1: - e_set = bfd_mach_avr1; - break; - - case E_AVR_MACH_AVR25: - e_set = bfd_mach_avr25; - break; - - case E_AVR_MACH_AVR3: - e_set = bfd_mach_avr3; - break; - - case E_AVR_MACH_AVR31: - e_set = bfd_mach_avr31; - break; - - case E_AVR_MACH_AVR35: - e_set = bfd_mach_avr35; - break; - - case E_AVR_MACH_AVR4: - e_set = bfd_mach_avr4; - break; - - case E_AVR_MACH_AVR5: - e_set = bfd_mach_avr5; - break; - - case E_AVR_MACH_AVR51: - e_set = bfd_mach_avr51; - break; - - case E_AVR_MACH_AVR6: - e_set = bfd_mach_avr6; - break; - - case E_AVR_MACH_XMEGA1: - e_set = bfd_mach_avrxmega1; - break; - - case E_AVR_MACH_XMEGA2: - e_set = bfd_mach_avrxmega2; - break; - - case E_AVR_MACH_XMEGA3: - e_set = bfd_mach_avrxmega3; - break; - - case E_AVR_MACH_XMEGA4: - e_set = bfd_mach_avrxmega4; - break; - - case E_AVR_MACH_XMEGA5: - e_set = bfd_mach_avrxmega5; - break; - - case E_AVR_MACH_XMEGA6: - e_set = bfd_mach_avrxmega6; - break; - - case E_AVR_MACH_XMEGA7: - e_set = bfd_mach_avrxmega7; - break; - - case E_AVR_MACH_AVRTINY: - e_set = bfd_mach_avrtiny; - break; - } - } - return bfd_default_set_arch_mach (abfd, bfd_arch_avr, - e_set); -} - -/* Returns whether the relocation type passed is a diff reloc. */ - -static bfd_boolean -elf32_avr_is_diff_reloc (Elf_Internal_Rela *irel) -{ - return (ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF8 - ||ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF16 - || ELF32_R_TYPE (irel->r_info) == R_AVR_DIFF32); -} - -/* Reduce the diff value written in the section by count if the shrinked - insn address happens to fall between the two symbols for which this - diff reloc was emitted. */ - -static void -elf32_avr_adjust_diff_reloc_value (bfd *abfd, - struct bfd_section *isec, - Elf_Internal_Rela *irel, - bfd_vma symval, - bfd_vma shrinked_insn_address, - int count) -{ - unsigned char *reloc_contents = NULL; - unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents; - if (isec_contents == NULL) - { - if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents)) - return; - - elf_section_data (isec)->this_hdr.contents = isec_contents; - } - - reloc_contents = isec_contents + irel->r_offset; - - /* Read value written in object file. */ - bfd_signed_vma x = 0; - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_AVR_DIFF8: - { - x = bfd_get_signed_8 (abfd, reloc_contents); - break; - } - case R_AVR_DIFF16: - { - x = bfd_get_signed_16 (abfd, reloc_contents); - break; - } - case R_AVR_DIFF32: - { - x = bfd_get_signed_32 (abfd, reloc_contents); - break; - } - default: - { - BFD_FAIL(); - } - } - - /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written - into the object file at the reloc offset. sym2's logical value is - symval () + reloc addend. Compute the start and end - addresses and check if the shrinked insn falls between sym1 and sym2. */ - - bfd_vma sym2_address = symval + irel->r_addend; - bfd_vma sym1_address = sym2_address - x; - - /* Don't assume sym2 is bigger than sym1 - the difference - could be negative. Compute start and end addresses, and - use those to see if they span shrinked_insn_address. */ - - bfd_vma start_address = sym1_address < sym2_address - ? sym1_address : sym2_address; - bfd_vma end_address = sym1_address > sym2_address - ? sym1_address : sym2_address; - - - if (shrinked_insn_address >= start_address - && shrinked_insn_address < end_address) - { - /* Reduce the diff value by count bytes and write it back into section - contents. */ - bfd_signed_vma new_diff = x < 0 ? x + count : x - count; - - if (sym2_address > shrinked_insn_address) - irel->r_addend -= count; - - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_AVR_DIFF8: - { - bfd_put_signed_8 (abfd, new_diff, reloc_contents); - break; - } - case R_AVR_DIFF16: - { - bfd_put_signed_16 (abfd, new_diff & 0xFFFF, reloc_contents); - break; - } - case R_AVR_DIFF32: - { - bfd_put_signed_32 (abfd, new_diff & 0xFFFFFFFF, reloc_contents); - break; - } - default: - { - BFD_FAIL(); - } - } - - } -} - -static void -elf32_avr_adjust_reloc_if_spans_insn (bfd *abfd, - asection *isec, - Elf_Internal_Rela *irel, bfd_vma symval, - bfd_vma shrinked_insn_address, - bfd_vma shrink_boundary, - int count) -{ - - if (elf32_avr_is_diff_reloc (irel)) - { - elf32_avr_adjust_diff_reloc_value (abfd, isec, irel, - symval, - shrinked_insn_address, - count); - } - else - { - bfd_vma reloc_value = symval + irel->r_addend; - bfd_boolean addend_within_shrink_boundary = - (reloc_value <= shrink_boundary); - - bfd_boolean reloc_spans_insn = - (symval <= shrinked_insn_address - && reloc_value > shrinked_insn_address - && addend_within_shrink_boundary); - - if (! reloc_spans_insn) - return; - - irel->r_addend -= count; - - if (debug_relax) - printf ("Relocation's addend needed to be fixed \n"); - } -} - -static bfd_boolean -avr_should_move_sym (symvalue symval, - bfd_vma start, - bfd_vma end, - bfd_boolean did_pad) -{ - bfd_boolean sym_within_boundary = - did_pad ? symval < end : symval <= end; - return (symval > start && sym_within_boundary); -} - -static bfd_boolean -avr_should_reduce_sym_size (symvalue symval, - symvalue symend, - bfd_vma start, - bfd_vma end, - bfd_boolean did_pad) -{ - bfd_boolean sym_end_within_boundary = - did_pad ? symend < end : symend <= end; - return (symval <= start && symend > start && sym_end_within_boundary); -} - -static bfd_boolean -avr_should_increase_sym_size (symvalue symval, - symvalue symend, - bfd_vma start, - bfd_vma end, - bfd_boolean did_pad) -{ - return avr_should_move_sym (symval, start, end, did_pad) - && symend >= end && did_pad; -} - -/* Delete some bytes from a section while changing the size of an instruction. - The parameter "addr" denotes the section-relative offset pointing just - behind the shrinked instruction. "addr+count" point at the first - byte just behind the original unshrinked instruction. If delete_shrinks_insn - is FALSE, we are deleting redundant padding bytes from relax_info prop - record handling. In that case, addr is section-relative offset of start - of padding, and count is the number of padding bytes to delete. */ - -static bfd_boolean -elf32_avr_relax_delete_bytes (bfd *abfd, - asection *sec, - bfd_vma addr, - int count, - bfd_boolean delete_shrinks_insn) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymbuf = NULL; - bfd_vma toaddr; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - struct avr_relax_info *relax_info; - struct avr_property_record *prop_record = NULL; - bfd_boolean did_shrink = FALSE; - bfd_boolean did_pad = FALSE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - contents = elf_section_data (sec)->this_hdr.contents; - relax_info = get_avr_relax_info (sec); - - toaddr = sec->size; - - if (relax_info->records.count > 0) - { - /* There should be no property record within the range of deleted - bytes, however, there might be a property record for ADDR, this is - how we handle alignment directives. - Find the next (if any) property record after the deleted bytes. */ - unsigned int i; - - for (i = 0; i < relax_info->records.count; ++i) - { - bfd_vma offset = relax_info->records.items [i].offset; - - BFD_ASSERT (offset <= addr || offset >= (addr + count)); - if (offset >= (addr + count)) - { - prop_record = &relax_info->records.items [i]; - toaddr = offset; - break; - } - } - } - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - if (toaddr - addr - count > 0) - { - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - did_shrink = TRUE; - } - if (prop_record == NULL) - { - sec->size -= count; - did_shrink = TRUE; - } - else - { - /* Use the property record to fill in the bytes we've opened up. */ - int fill = 0; - switch (prop_record->type) - { - case RECORD_ORG_AND_FILL: - fill = prop_record->data.org.fill; - /* Fall through. */ - case RECORD_ORG: - break; - case RECORD_ALIGN_AND_FILL: - fill = prop_record->data.align.fill; - /* Fall through. */ - case RECORD_ALIGN: - prop_record->data.align.preceding_deleted += count; - break; - }; - /* If toaddr == (addr + count), then we didn't delete anything, yet - we fill count bytes backwards from toaddr. This is still ok - we - end up overwriting the bytes we would have deleted. We just need - to remember we didn't delete anything i.e. don't set did_shrink, - so that we don't corrupt reloc offsets or symbol values.*/ - memset (contents + toaddr - count, fill, count); - did_pad = TRUE; - } - - if (!did_shrink) - return TRUE; - - /* Adjust all the reloc addresses. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - bfd_vma old_reloc_address; - - old_reloc_address = (sec->output_section->vma - + sec->output_offset + irel->r_offset); - - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset < toaddr)) - { - if (debug_relax) - printf ("Relocation at address 0x%x needs to be moved.\n" - "Old section offset: 0x%x, New section offset: 0x%x \n", - (unsigned int) old_reloc_address, - (unsigned int) irel->r_offset, - (unsigned int) ((irel->r_offset) - count)); - - irel->r_offset -= count; - } - - } - - /* The reloc's own addresses are now ok. However, we need to readjust - the reloc's addend, i.e. the reloc's value if two conditions are met: - 1.) the reloc is relative to a symbol in this section that - is located in front of the shrinked instruction - 2.) symbol plus addend end up behind the shrinked instruction. - - The most common case where this happens are relocs relative to - the section-start symbol. - - This step needs to be done for all of the sections of the bfd. */ - - { - struct bfd_section *isec; - - for (isec = abfd->sections; isec; isec = isec->next) - { - bfd_vma symval; - bfd_vma shrinked_insn_address; - - if (isec->reloc_count == 0) - continue; - - shrinked_insn_address = (sec->output_section->vma - + sec->output_offset + addr); - if (delete_shrinks_insn) - shrinked_insn_address -= count; - - irel = elf_section_data (isec)->relocs; - /* PR 12161: Read in the relocs for this section if necessary. */ - if (irel == NULL) - irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); - - for (irelend = irel + isec->reloc_count; - irel < irelend; - irel++) - { - /* Read this BFD's local symbols if we haven't done - so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec == sec) - { - /* If there is an alignment boundary, we only need to - adjust addends that end up below the boundary. */ - bfd_vma shrink_boundary = (toaddr - + sec->output_section->vma - + sec->output_offset); - - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - - if (debug_relax) - printf ("Checking if the relocation's " - "addend needs corrections.\n" - "Address of anchor symbol: 0x%x \n" - "Address of relocation target: 0x%x \n" - "Address of relaxed insn: 0x%x \n", - (unsigned int) symval, - (unsigned int) (symval + irel->r_addend), - (unsigned int) shrinked_insn_address); - - elf32_avr_adjust_reloc_if_spans_insn (abfd, isec, irel, - symval, - shrinked_insn_address, - shrink_boundary, - count); - } - /* else...Reference symbol is absolute. No adjustment needed. */ - } - /* else...Reference symbol is extern. No need for adjusting - the addend. */ - } - } - } - - /* Adjust the local symbols defined in this section. */ - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - /* Fix PR 9841, there may be no local symbols. */ - if (isym != NULL) - { - Elf_Internal_Sym *isymend; - - isymend = isym + symtab_hdr->sh_info; - for (; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx) - { - symvalue symval = isym->st_value; - symvalue symend = symval + isym->st_size; - if (avr_should_reduce_sym_size (symval, symend, - addr, toaddr, did_pad)) - { - /* If this assert fires then we have a symbol that ends - part way through an instruction. Does that make - sense? */ - BFD_ASSERT (isym->st_value + isym->st_size >= addr + count); - isym->st_size -= count; - } - else if (avr_should_increase_sym_size (symval, symend, - addr, toaddr, did_pad)) - isym->st_size += count; - - if (avr_should_move_sym (symval, addr, toaddr, did_pad)) - isym->st_value -= count; - } - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - symvalue symval = sym_hash->root.u.def.value; - symvalue symend = symval + sym_hash->size; - - if (avr_should_reduce_sym_size (symval, symend, - addr, toaddr, did_pad)) - { - /* If this assert fires then we have a symbol that ends - part way through an instruction. Does that make - sense? */ - BFD_ASSERT (symend >= addr + count); - sym_hash->size -= count; - } - else if (avr_should_increase_sym_size (symval, symend, - addr, toaddr, did_pad)) - sym_hash->size += count; - - if (avr_should_move_sym (symval, addr, toaddr, did_pad)) - sym_hash->root.u.def.value -= count; - } - } - - return TRUE; -} - -static Elf_Internal_Sym * -retrieve_local_syms (bfd *input_bfd) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf; - size_t locsymcount; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL && locsymcount != 0) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, - NULL, NULL, NULL); - - /* Save the symbols for this input file so they won't be read again. */ - if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents) - symtab_hdr->contents = (unsigned char *) isymbuf; - - return isymbuf; -} - -/* Get the input section for a given symbol index. - If the symbol is: - . a section symbol, return the section; - . a common symbol, return the common section; - . an undefined symbol, return the undefined section; - . an indirect symbol, follow the links; - . an absolute value, return the absolute section. */ - -static asection * -get_elf_r_symndx_section (bfd *abfd, unsigned long r_symndx) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - asection *target_sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isymbuf; - unsigned int section_index; - - isymbuf = retrieve_local_syms (abfd); - section_index = isymbuf[r_symndx].st_shndx; - - if (section_index == SHN_UNDEF) - target_sec = bfd_und_section_ptr; - else if (section_index == SHN_ABS) - target_sec = bfd_abs_section_ptr; - else if (section_index == SHN_COMMON) - target_sec = bfd_com_section_ptr; - else - target_sec = bfd_section_from_elf_index (abfd, section_index); - } - else - { - unsigned long indx = r_symndx - symtab_hdr->sh_info; - struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - target_sec = h->root.u.def.section; - break; - case bfd_link_hash_common: - target_sec = bfd_com_section_ptr; - break; - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - target_sec = bfd_und_section_ptr; - break; - default: /* New indirect warning. */ - target_sec = bfd_und_section_ptr; - break; - } - } - return target_sec; -} - -/* Get the section-relative offset for a symbol number. */ - -static bfd_vma -get_elf_r_symndx_offset (bfd *abfd, unsigned long r_symndx) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - bfd_vma offset = 0; - - if (r_symndx < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isymbuf; - isymbuf = retrieve_local_syms (abfd); - offset = isymbuf[r_symndx].st_value; - } - else - { - unsigned long indx = r_symndx - symtab_hdr->sh_info; - struct elf_link_hash_entry *h = - elf_sym_hashes (abfd)[indx]; - - 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) - offset = h->root.u.def.value; - } - return offset; -} - -/* Iterate over the property records in R_LIST, and copy each record into - the list of records within the relaxation information for the section to - which the record applies. */ - -static void -avr_elf32_assign_records_to_sections (struct avr_property_record_list *r_list) -{ - unsigned int i; - - for (i = 0; i < r_list->record_count; ++i) - { - struct avr_relax_info *relax_info; - - relax_info = get_avr_relax_info (r_list->records [i].section); - BFD_ASSERT (relax_info != NULL); - - if (relax_info->records.count - == relax_info->records.allocated) - { - /* Allocate more space. */ - bfd_size_type size; - - relax_info->records.allocated += 10; - size = (sizeof (struct avr_property_record) - * relax_info->records.allocated); - relax_info->records.items - = bfd_realloc (relax_info->records.items, size); - } - - memcpy (&relax_info->records.items [relax_info->records.count], - &r_list->records [i], - sizeof (struct avr_property_record)); - relax_info->records.count++; - } -} - -/* Compare two STRUCT AVR_PROPERTY_RECORD in AP and BP, used as the - ordering callback from QSORT. */ - -static int -avr_property_record_compare (const void *ap, const void *bp) -{ - const struct avr_property_record *a - = (struct avr_property_record *) ap; - const struct avr_property_record *b - = (struct avr_property_record *) bp; - - if (a->offset != b->offset) - return (a->offset - b->offset); - - if (a->section != b->section) - return (bfd_get_section_vma (a->section->owner, a->section) - - bfd_get_section_vma (b->section->owner, b->section)); - - return (a->type - b->type); -} - -/* Load all of the avr property sections from all of the bfd objects - referenced from LINK_INFO. All of the records within each property - section are assigned to the STRUCT AVR_RELAX_INFO within the section - specific data of the appropriate section. */ - -static void -avr_load_all_property_sections (struct bfd_link_info *link_info) -{ - bfd *abfd; - asection *sec; - - /* Initialize the per-section relaxation info. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - init_avr_relax_info (sec); - } - - /* Load the descriptor tables from .avr.prop sections. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - { - struct avr_property_record_list *r_list; - - r_list = avr_elf32_load_property_records (abfd); - if (r_list != NULL) - avr_elf32_assign_records_to_sections (r_list); - - free (r_list); - } - - /* Now, for every section, ensure that the descriptor list in the - relaxation data is sorted by ascending offset within the section. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - struct avr_relax_info *relax_info = get_avr_relax_info (sec); - if (relax_info && relax_info->records.count > 0) - { - unsigned int i; - - qsort (relax_info->records.items, - relax_info->records.count, - sizeof (struct avr_property_record), - avr_property_record_compare); - - /* For debug purposes, list all the descriptors. */ - for (i = 0; i < relax_info->records.count; ++i) - { - switch (relax_info->records.items [i].type) - { - case RECORD_ORG: - break; - case RECORD_ORG_AND_FILL: - break; - case RECORD_ALIGN: - break; - case RECORD_ALIGN_AND_FILL: - break; - }; - } - } - } -} - -/* This function handles relaxing for the avr. - Many important relaxing opportunities within functions are already - realized by the compiler itself. - Here we try to replace call (4 bytes) -> rcall (2 bytes) - and jump -> rjmp (safes also 2 bytes). - As well we now optimize seqences of - - call/rcall function - - ret - to yield - - jmp/rjmp function - - ret - . In case that within a sequence - - jmp/rjmp label - - ret - the ret could no longer be reached it is optimized away. In order - to check if the ret is no longer needed, it is checked that the ret's address - is not the target of a branch or jump within the same section, it is checked - that there is no skip instruction before the jmp/rjmp and that there - is no local or global label place at the address of the ret. - - We refrain from relaxing within sections ".vectors" and - ".jumptables" in order to maintain the position of the instructions. - There, however, we substitute jmp/call by a sequence rjmp,nop/rcall,nop - if possible. (In future one could possibly use the space of the nop - for the first instruction of the irq service function. - - The .jumptables sections is meant to be used for a future tablejump variant - for the devices with 3-byte program counter where the table itself - contains 4-byte jump instructions whose relative offset must not - be changed. */ - -static bfd_boolean -elf32_avr_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - struct elf32_avr_link_hash_table *htab; - static bfd_boolean relaxation_initialised = FALSE; - - if (!relaxation_initialised) - { - relaxation_initialised = TRUE; - - /* Load entries from the .avr.prop sections. */ - avr_load_all_property_sections (link_info); - } - - /* If 'shrinkable' is FALSE, do not shrink by deleting bytes while - relaxing. Such shrinking can cause issues for the sections such - as .vectors and .jumptables. Instead the unused bytes should be - filled with nop instructions. */ - bfd_boolean shrinkable = TRUE; - - if (!strcmp (sec->name,".vectors") - || !strcmp (sec->name,".jumptables")) - shrinkable = FALSE; - - if (bfd_link_relocatable (link_info)) - (*link_info->callbacks->einfo) - (_("%P%F: --relax and -r may not be used together\n")); - - htab = avr_link_hash_table (link_info); - if (htab == NULL) - return FALSE; - - /* Assume nothing changes. */ - *again = FALSE; - - if ((!htab->no_stubs) && (sec == htab->stub_sec)) - { - /* We are just relaxing the stub section. - Let's calculate the size needed again. */ - bfd_size_type last_estimated_stub_section_size = htab->stub_sec->size; - - if (debug_relax) - printf ("Relaxing the stub section. Size prior to this pass: %i\n", - (int) last_estimated_stub_section_size); - - elf32_avr_size_stubs (htab->stub_sec->output_section->owner, - link_info, FALSE); - - /* Check if the number of trampolines changed. */ - if (last_estimated_stub_section_size != htab->stub_sec->size) - *again = TRUE; - - if (debug_relax) - printf ("Size of stub section after this pass: %i\n", - (int) htab->stub_sec->size); - - return TRUE; - } - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - /* Check if the object file to relax uses internal symbols so that we - could fix up the relocations. */ - if (!(elf_elfheader (abfd)->e_flags & EF_AVR_LINKRELAX_PREPARED)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, NULL, link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through the relocs looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - if ( ELF32_R_TYPE (irel->r_info) != R_AVR_13_PCREL - && ELF32_R_TYPE (irel->r_info) != R_AVR_7_PCREL - && ELF32_R_TYPE (irel->r_info) != R_AVR_CALL) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec) - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - switch (ELF32_R_TYPE (irel->r_info)) - { - /* Try to turn a 22-bit absolute call/jump into an 13-bit - pc-relative rcall/rjmp. */ - case R_AVR_CALL: - { - bfd_vma value = symval + irel->r_addend; - bfd_vma dot, gap; - int distance_short_enough = 0; - - /* Get the address of this instruction. */ - dot = (sec->output_section->vma - + sec->output_offset + irel->r_offset); - - /* Compute the distance from this insn to the branch target. */ - gap = value - dot; - - /* Check if the gap falls in the range that can be accommodated - in 13bits signed (It is 12bits when encoded, as we deal with - word addressing). */ - if (!shrinkable && ((int) gap >= -4096 && (int) gap <= 4095)) - distance_short_enough = 1; - /* If shrinkable, then we can check for a range of distance which - is two bytes farther on both the directions because the call - or jump target will be closer by two bytes after the - relaxation. */ - else if (shrinkable && ((int) gap >= -4094 && (int) gap <= 4097)) - distance_short_enough = 1; - - /* Here we handle the wrap-around case. E.g. for a 16k device - we could use a rjmp to jump from address 0x100 to 0x3d00! - In order to make this work properly, we need to fill the - vaiable avr_pc_wrap_around with the appropriate value. - I.e. 0x4000 for a 16k device. */ - { - /* Shrinking the code size makes the gaps larger in the - case of wrap-arounds. So we use a heuristical safety - margin to avoid that during relax the distance gets - again too large for the short jumps. Let's assume - a typical code-size reduction due to relax for a - 16k device of 600 bytes. So let's use twice the - typical value as safety margin. */ - int rgap; - int safety_margin; - - int assumed_shrink = 600; - if (avr_pc_wrap_around > 0x4000) - assumed_shrink = 900; - - safety_margin = 2 * assumed_shrink; - - rgap = avr_relative_distance_considering_wrap_around (gap); - - if (rgap >= (-4092 + safety_margin) - && rgap <= (4094 - safety_margin)) - distance_short_enough = 1; - } - - if (distance_short_enough) - { - unsigned char code_msb; - unsigned char code_lsb; - - if (debug_relax) - printf ("shrinking jump/call instruction at address 0x%x" - " in section %s\n\n", - (int) dot, sec->name); - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Get the instruction code for relaxing. */ - code_lsb = bfd_get_8 (abfd, contents + irel->r_offset); - code_msb = bfd_get_8 (abfd, contents + irel->r_offset + 1); - - /* Mask out the relocation bits. */ - code_msb &= 0x94; - code_lsb &= 0x0E; - if (code_msb == 0x94 && code_lsb == 0x0E) - { - /* we are changing call -> rcall . */ - bfd_put_8 (abfd, 0x00, contents + irel->r_offset); - bfd_put_8 (abfd, 0xD0, contents + irel->r_offset + 1); - } - else if (code_msb == 0x94 && code_lsb == 0x0C) - { - /* we are changeing jump -> rjmp. */ - bfd_put_8 (abfd, 0x00, contents + irel->r_offset); - bfd_put_8 (abfd, 0xC0, contents + irel->r_offset + 1); - } - else - abort (); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_AVR_13_PCREL); - - /* We should not modify the ordering if 'shrinkable' is - FALSE. */ - if (!shrinkable) - { - /* Let's insert a nop. */ - bfd_put_8 (abfd, 0x00, contents + irel->r_offset + 2); - bfd_put_8 (abfd, 0x00, contents + irel->r_offset + 3); - } - else - { - /* Delete two bytes of data. */ - if (!elf32_avr_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 2, - TRUE)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - } - /* Fall through. */ - - default: - { - unsigned char code_msb; - unsigned char code_lsb; - bfd_vma dot; - - code_msb = bfd_get_8 (abfd, contents + irel->r_offset + 1); - code_lsb = bfd_get_8 (abfd, contents + irel->r_offset + 0); - - /* Get the address of this instruction. */ - dot = (sec->output_section->vma - + sec->output_offset + irel->r_offset); - - /* Here we look for rcall/ret or call/ret sequences that could be - safely replaced by rjmp/ret or jmp/ret. */ - if (((code_msb & 0xf0) == 0xd0) - && avr_replace_call_ret_sequences) - { - /* This insn is a rcall. */ - unsigned char next_insn_msb = 0; - unsigned char next_insn_lsb = 0; - - if (irel->r_offset + 3 < sec->size) - { - next_insn_msb = - bfd_get_8 (abfd, contents + irel->r_offset + 3); - next_insn_lsb = - bfd_get_8 (abfd, contents + irel->r_offset + 2); - } - - if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) - { - /* The next insn is a ret. We now convert the rcall insn - into a rjmp instruction. */ - code_msb &= 0xef; - bfd_put_8 (abfd, code_msb, contents + irel->r_offset + 1); - if (debug_relax) - printf ("converted rcall/ret sequence at address 0x%x" - " into rjmp/ret sequence. Section is %s\n\n", - (int) dot, sec->name); - *again = TRUE; - break; - } - } - else if ((0x94 == (code_msb & 0xfe)) - && (0x0e == (code_lsb & 0x0e)) - && avr_replace_call_ret_sequences) - { - /* This insn is a call. */ - unsigned char next_insn_msb = 0; - unsigned char next_insn_lsb = 0; - - if (irel->r_offset + 5 < sec->size) - { - next_insn_msb = - bfd_get_8 (abfd, contents + irel->r_offset + 5); - next_insn_lsb = - bfd_get_8 (abfd, contents + irel->r_offset + 4); - } - - if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) - { - /* The next insn is a ret. We now convert the call insn - into a jmp instruction. */ - - code_lsb &= 0xfd; - bfd_put_8 (abfd, code_lsb, contents + irel->r_offset); - if (debug_relax) - printf ("converted call/ret sequence at address 0x%x" - " into jmp/ret sequence. Section is %s\n\n", - (int) dot, sec->name); - *again = TRUE; - break; - } - } - else if ((0xc0 == (code_msb & 0xf0)) - || ((0x94 == (code_msb & 0xfe)) - && (0x0c == (code_lsb & 0x0e)))) - { - /* This insn is a rjmp or a jmp. */ - unsigned char next_insn_msb = 0; - unsigned char next_insn_lsb = 0; - int insn_size; - - if (0xc0 == (code_msb & 0xf0)) - insn_size = 2; /* rjmp insn */ - else - insn_size = 4; /* jmp insn */ - - if (irel->r_offset + insn_size + 1 < sec->size) - { - next_insn_msb = - bfd_get_8 (abfd, contents + irel->r_offset - + insn_size + 1); - next_insn_lsb = - bfd_get_8 (abfd, contents + irel->r_offset - + insn_size); - } - - if ((0x95 == next_insn_msb) && (0x08 == next_insn_lsb)) - { - /* The next insn is a ret. We possibly could delete - this ret. First we need to check for preceding - sbis/sbic/sbrs or cpse "skip" instructions. */ - - int there_is_preceding_non_skip_insn = 1; - bfd_vma address_of_ret; - - address_of_ret = dot + insn_size; - - if (debug_relax && (insn_size == 2)) - printf ("found rjmp / ret sequence at address 0x%x\n", - (int) dot); - if (debug_relax && (insn_size == 4)) - printf ("found jmp / ret sequence at address 0x%x\n", - (int) dot); - - /* We have to make sure that there is a preceding insn. */ - if (irel->r_offset >= 2) - { - unsigned char preceding_msb; - unsigned char preceding_lsb; - - preceding_msb = - bfd_get_8 (abfd, contents + irel->r_offset - 1); - preceding_lsb = - bfd_get_8 (abfd, contents + irel->r_offset - 2); - - /* sbic. */ - if (0x99 == preceding_msb) - there_is_preceding_non_skip_insn = 0; - - /* sbis. */ - if (0x9b == preceding_msb) - there_is_preceding_non_skip_insn = 0; - - /* sbrc */ - if ((0xfc == (preceding_msb & 0xfe) - && (0x00 == (preceding_lsb & 0x08)))) - there_is_preceding_non_skip_insn = 0; - - /* sbrs */ - if ((0xfe == (preceding_msb & 0xfe) - && (0x00 == (preceding_lsb & 0x08)))) - there_is_preceding_non_skip_insn = 0; - - /* cpse */ - if (0x10 == (preceding_msb & 0xfc)) - there_is_preceding_non_skip_insn = 0; - - if (there_is_preceding_non_skip_insn == 0) - if (debug_relax) - printf ("preceding skip insn prevents deletion of" - " ret insn at Addy 0x%x in section %s\n", - (int) dot + 2, sec->name); - } - else - { - /* There is no previous instruction. */ - there_is_preceding_non_skip_insn = 0; - } - - if (there_is_preceding_non_skip_insn) - { - /* We now only have to make sure that there is no - local label defined at the address of the ret - instruction and that there is no local relocation - in this section pointing to the ret. */ - - int deleting_ret_is_safe = 1; - unsigned int section_offset_of_ret_insn = - irel->r_offset + insn_size; - Elf_Internal_Sym *isym, *isymend; - unsigned int sec_shndx; - struct bfd_section *isec; - - sec_shndx = - _bfd_elf_section_from_bfd_section (abfd, sec); - - /* Check for local symbols. */ - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - isymend = isym + symtab_hdr->sh_info; - /* PR 6019: There may not be any local symbols. */ - for (; isym != NULL && isym < isymend; isym++) - { - if (isym->st_value == section_offset_of_ret_insn - && isym->st_shndx == sec_shndx) - { - deleting_ret_is_safe = 0; - if (debug_relax) - printf ("local label prevents deletion of ret " - "insn at address 0x%x\n", - (int) dot + insn_size); - } - } - - /* Now check for global symbols. */ - { - int symcount; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - - symcount = (symtab_hdr->sh_size - / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = - *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == - bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == section_offset_of_ret_insn) - { - deleting_ret_is_safe = 0; - if (debug_relax) - printf ("global label prevents deletion of " - "ret insn at address 0x%x\n", - (int) dot + insn_size); - } - } - } - - /* Now we check for relocations pointing to ret. */ - for (isec = abfd->sections; isec && deleting_ret_is_safe; isec = isec->next) - { - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - rel = elf_section_data (isec)->relocs; - if (rel == NULL) - rel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); - - relend = rel + isec->reloc_count; - - for (; rel && rel < relend; rel++) - { - bfd_vma reloc_target = 0; - - /* Read this BFD's local symbols if we haven't - done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) - symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms - (abfd, - symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - break; - } - - /* Get the value of the symbol referred to - by the reloc. */ - if (ELF32_R_SYM (rel->r_info) - < symtab_hdr->sh_info) - { - /* A local symbol. */ - asection *sym_sec; - - isym = isymbuf - + ELF32_R_SYM (rel->r_info); - sym_sec = bfd_section_from_elf_index - (abfd, isym->st_shndx); - symval = isym->st_value; - - /* If the reloc is absolute, it will not - have a symbol or section associated - with it. */ - - if (sym_sec) - { - symval += - sym_sec->output_section->vma - + sym_sec->output_offset; - reloc_target = symval + rel->r_addend; - } - else - { - reloc_target = symval + rel->r_addend; - /* Reference symbol is absolute. */ - } - } - /* else ... reference symbol is extern. */ - - if (address_of_ret == reloc_target) - { - deleting_ret_is_safe = 0; - if (debug_relax) - printf ("ret from " - "rjmp/jmp ret sequence at address" - " 0x%x could not be deleted. ret" - " is target of a relocation.\n", - (int) address_of_ret); - break; - } - } - } - - if (deleting_ret_is_safe) - { - if (debug_relax) - printf ("unreachable ret instruction " - "at address 0x%x deleted.\n", - (int) dot + insn_size); - - /* Delete two bytes of data. */ - if (!elf32_avr_relax_delete_bytes (abfd, sec, - irel->r_offset + insn_size, 2, - TRUE)) - goto error_return; - - /* That will change things, so, we should relax - again. Note that this is not required, and it - may be slow. */ - *again = TRUE; - break; - } - } - } - } - break; - } - } - } - - if (!*again) - { - /* Look through all the property records in this section to see if - there's any alignment records that can be moved. */ - struct avr_relax_info *relax_info; - - relax_info = get_avr_relax_info (sec); - if (relax_info->records.count > 0) - { - unsigned int i; - - for (i = 0; i < relax_info->records.count; ++i) - { - switch (relax_info->records.items [i].type) - { - case RECORD_ORG: - case RECORD_ORG_AND_FILL: - break; - case RECORD_ALIGN: - case RECORD_ALIGN_AND_FILL: - { - struct avr_property_record *record; - unsigned long bytes_to_align; - int count = 0; - - /* Look for alignment directives that have had enough - bytes deleted before them, such that the directive - can be moved backwards and still maintain the - required alignment. */ - record = &relax_info->records.items [i]; - bytes_to_align - = (unsigned long) (1 << record->data.align.bytes); - while (record->data.align.preceding_deleted >= - bytes_to_align) - { - record->data.align.preceding_deleted - -= bytes_to_align; - count += bytes_to_align; - } - - if (count > 0) - { - bfd_vma addr = record->offset; - - /* We can delete COUNT bytes and this alignment - directive will still be correctly aligned. - First move the alignment directive, then delete - the bytes. */ - record->offset -= count; - elf32_avr_relax_delete_bytes (abfd, sec, - addr - count, - count, FALSE); - *again = TRUE; - } - } - break; - } - } - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses elf32_avr_relocate_section. - - For avr it's essentially a cut and paste taken from the H8300 port. - The author of the relaxation support patch for avr had absolutely no - clue what is happening here but found out that this part of the code - seems to be important. */ - -static bfd_byte * -elf32_avr_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - asection **secpp; - Elf_Internal_Sym *isym, *isymend; - bfd_size_type amt; - - internal_relocs = (_bfd_elf_link_read_relocs - (input_bfd, input_section, NULL, NULL, FALSE)); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! elf32_avr_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - return NULL; -} - - -/* Determines the hash entry name for a particular reloc. It consists of - the identifier of the symbol section and the added reloc addend and - symbol offset relative to the section the symbol is attached to. */ - -static char * -avr_stub_name (const asection *symbol_section, - const bfd_vma symbol_offset, - const Elf_Internal_Rela *rela) -{ - char *stub_name; - bfd_size_type len; - - len = 8 + 1 + 8 + 1 + 1; - stub_name = bfd_malloc (len); - - sprintf (stub_name, "%08x+%08x", - symbol_section->id & 0xffffffff, - (unsigned int) ((rela->r_addend & 0xffffffff) + symbol_offset)); - - return stub_name; -} - - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ - -static struct elf32_avr_stub_hash_entry * -avr_add_stub (const char *stub_name, - struct elf32_avr_link_hash_table *htab) -{ - struct elf32_avr_stub_hash_entry *hsh; - - /* Enter this entry into the linker stub hash table. */ - hsh = avr_stub_hash_lookup (&htab->bstab, stub_name, TRUE, FALSE); - - if (hsh == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("cannot create stub entry %s"), stub_name); - return NULL; - } - - hsh->stub_offset = 0; - return hsh; -} - -/* We assume that there is already space allocated for the stub section - contents and that before building the stubs the section size is - initialized to 0. We assume that within the stub hash table entry, - the absolute position of the jmp target has been written in the - target_value field. We write here the offset of the generated jmp insn - relative to the trampoline section start to the stub_offset entry in - the stub hash table entry. */ - -static bfd_boolean -avr_build_one_stub (struct bfd_hash_entry *bh, void *in_arg) -{ - struct elf32_avr_stub_hash_entry *hsh; - struct bfd_link_info *info; - struct elf32_avr_link_hash_table *htab; - bfd *stub_bfd; - bfd_byte *loc; - bfd_vma target; - bfd_vma starget; - - /* Basic opcode */ - bfd_vma jmp_insn = 0x0000940c; - - /* Massage our args to the form they really have. */ - hsh = avr_stub_hash_entry (bh); - - if (!hsh->is_actually_needed) - return TRUE; - - info = (struct bfd_link_info *) in_arg; - - htab = avr_link_hash_table (info); - if (htab == NULL) - return FALSE; - - target = hsh->target_value; - - /* Make a note of the offset within the stubs for this entry. */ - hsh->stub_offset = htab->stub_sec->size; - loc = htab->stub_sec->contents + hsh->stub_offset; - - stub_bfd = htab->stub_sec->owner; - - if (debug_stubs) - printf ("Building one Stub. Address: 0x%x, Offset: 0x%x\n", - (unsigned int) target, - (unsigned int) hsh->stub_offset); - - /* We now have to add the information on the jump target to the bare - opcode bits already set in jmp_insn. */ - - /* Check for the alignment of the address. */ - if (target & 1) - return FALSE; - - starget = target >> 1; - jmp_insn |= ((starget & 0x10000) | ((starget << 3) & 0x1f00000)) >> 16; - bfd_put_16 (stub_bfd, jmp_insn, loc); - bfd_put_16 (stub_bfd, (bfd_vma) starget & 0xffff, loc + 2); - - htab->stub_sec->size += 4; - - /* Now add the entries in the address mapping table if there is still - space left. */ - { - unsigned int nr; - - nr = htab->amt_entry_cnt + 1; - if (nr <= htab->amt_max_entry_cnt) - { - htab->amt_entry_cnt = nr; - - htab->amt_stub_offsets[nr - 1] = hsh->stub_offset; - htab->amt_destination_addr[nr - 1] = target; - } - } - - return TRUE; -} - -static bfd_boolean -avr_mark_stub_not_to_be_necessary (struct bfd_hash_entry *bh, - void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_avr_stub_hash_entry *hsh; - - hsh = avr_stub_hash_entry (bh); - hsh->is_actually_needed = FALSE; - - return TRUE; -} - -static bfd_boolean -avr_size_one_stub (struct bfd_hash_entry *bh, void *in_arg) -{ - struct elf32_avr_stub_hash_entry *hsh; - struct elf32_avr_link_hash_table *htab; - int size; - - /* Massage our args to the form they really have. */ - hsh = avr_stub_hash_entry (bh); - htab = in_arg; - - if (hsh->is_actually_needed) - size = 4; - else - size = 0; - - htab->stub_sec->size += size; - return TRUE; -} - -void -elf32_avr_setup_params (struct bfd_link_info *info, - bfd *avr_stub_bfd, - asection *avr_stub_section, - bfd_boolean no_stubs, - bfd_boolean deb_stubs, - bfd_boolean deb_relax, - bfd_vma pc_wrap_around, - bfd_boolean call_ret_replacement) -{ - struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info); - - if (htab == NULL) - return; - htab->stub_sec = avr_stub_section; - htab->stub_bfd = avr_stub_bfd; - htab->no_stubs = no_stubs; - - debug_relax = deb_relax; - debug_stubs = deb_stubs; - avr_pc_wrap_around = pc_wrap_around; - avr_replace_call_ret_sequences = call_ret_replacement; -} - - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. It also sets - information on the stubs bfd and the stub section in the info - struct. */ - -int -elf32_avr_setup_section_lists (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - bfd_size_type amt; - struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info); - - if (htab == NULL || htab->no_stubs) - return 0; - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - if (top_id < section->id) - top_id = section->id; - } - - htab->bfd_count = bfd_count; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - if (top_index < section->index) - top_index = section->index; - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - if ((section->flags & SEC_CODE) != 0) - input_list[section->index] = NULL; - - return 1; -} - - -/* Read in all local syms for all input bfds, and create hash entries - for export stubs if we are building a multi-subspace shared lib. - Returns -1 on error, 0 otherwise. */ - -static int -get_local_syms (bfd *input_bfd, struct bfd_link_info *info) -{ - unsigned int bfd_indx; - Elf_Internal_Sym *local_syms, **all_local_syms; - struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info); - bfd_size_type amt; - - if (htab == NULL) - return -1; - - /* We want to read in symbol extension records only once. To do this - we need to read in the local symbols in parallel and save them for - later use; so hold pointers to the local symbols in an array. */ - amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count; - all_local_syms = bfd_zmalloc (amt); - htab->all_local_syms = all_local_syms; - if (all_local_syms == NULL) - return -1; - - /* Walk over all the input BFDs, swapping in local symbols. - If we are creating a shared library, create hash entries for the - export stubs. */ - for (bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* We need an array of the local symbols attached to the input bfd. */ - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - { - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - /* Cache them for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - if (local_syms == NULL) - return -1; - - all_local_syms[bfd_indx] = local_syms; - } - - return 0; -} - -#define ADD_DUMMY_STUBS_FOR_DEBUGGING 0 - -bfd_boolean -elf32_avr_size_stubs (bfd *output_bfd, - struct bfd_link_info *info, - bfd_boolean is_prealloc_run) -{ - struct elf32_avr_link_hash_table *htab; - int stub_changed = 0; - - htab = avr_link_hash_table (info); - if (htab == NULL) - return FALSE; - - /* At this point we initialize htab->vector_base - To the start of the text output section. */ - htab->vector_base = htab->stub_sec->output_section->vma; - - if (get_local_syms (info->input_bfds, info)) - { - if (htab->all_local_syms) - goto error_ret_free_local; - return FALSE; - } - - if (ADD_DUMMY_STUBS_FOR_DEBUGGING) - { - struct elf32_avr_stub_hash_entry *test; - - test = avr_add_stub ("Hugo",htab); - test->target_value = 0x123456; - test->stub_offset = 13; - - test = avr_add_stub ("Hugo2",htab); - test->target_value = 0x84210; - test->stub_offset = 14; - } - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - - /* We will have to re-generate the stub hash table each time anything - in memory has changed. */ - - bfd_hash_traverse (&htab->bstab, avr_mark_stub_not_to_be_necessary, htab); - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - local_syms = htab->all_local_syms[bfd_indx]; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - struct elf32_avr_stub_hash_entry *hsh; - asection *sym_sec; - bfd_vma sym_value; - bfd_vma destination; - struct elf_link_hash_entry *hh; - char *stub_name; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - /* Only look for 16 bit GS relocs. No other reloc will need a - stub. */ - if (!((r_type == R_AVR_16_PM) - || (r_type == R_AVR_LO8_LDI_GS) - || (r_type == R_AVR_HI8_LDI_GS))) - continue; - - /* Now determine the call target, its name, value, - section. */ - sym_sec = NULL; - sym_value = 0; - destination = 0; - hh = NULL; - if (r_indx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - Elf_Internal_Sym *sym; - Elf_Internal_Shdr *hdr; - unsigned int shndx; - - sym = local_syms + r_indx; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - sym_value = sym->st_value; - shndx = sym->st_shndx; - if (shndx < elf_numsections (input_bfd)) - { - hdr = elf_elfsections (input_bfd)[shndx]; - sym_sec = hdr->bfd_section; - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - } - else - { - /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hh = elf_sym_hashes (input_bfd)[e_indx]; - - while (hh->root.type == bfd_link_hash_indirect - || hh->root.type == bfd_link_hash_warning) - hh = (struct elf_link_hash_entry *) - (hh->root.u.i.link); - - if (hh->root.type == bfd_link_hash_defined - || hh->root.type == bfd_link_hash_defweak) - { - sym_sec = hh->root.u.def.section; - sym_value = hh->root.u.def.value; - if (sym_sec->output_section != NULL) - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - else if (hh->root.type == bfd_link_hash_undefweak) - { - if (! bfd_link_pic (info)) - continue; - } - else if (hh->root.type == bfd_link_hash_undefined) - { - if (! (info->unresolved_syms_in_objects == RM_IGNORE - && (ELF_ST_VISIBILITY (hh->other) - == STV_DEFAULT))) - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - goto error_ret_free_local; - } - } - - if (! avr_stub_is_required_for_16_bit_reloc - (destination - htab->vector_base)) - { - if (!is_prealloc_run) - /* We are having a reloc that does't need a stub. */ - continue; - - /* We don't right now know if a stub will be needed. - Let's rather be on the safe side. */ - } - - /* Get the name of this stub. */ - stub_name = avr_stub_name (sym_sec, sym_value, irela); - - if (!stub_name) - goto error_ret_free_internal; - - - hsh = avr_stub_hash_lookup (&htab->bstab, - stub_name, - FALSE, FALSE); - if (hsh != NULL) - { - /* The proper stub has already been created. Mark it - to be used and write the possibly changed destination - value. */ - hsh->is_actually_needed = TRUE; - hsh->target_value = destination; - free (stub_name); - continue; - } - - hsh = avr_add_stub (stub_name, htab); - if (hsh == NULL) - { - free (stub_name); - goto error_ret_free_internal; - } - - hsh->is_actually_needed = TRUE; - hsh->target_value = destination; - - if (debug_stubs) - printf ("Adding stub with destination 0x%x to the" - " hash table.\n", (unsigned int) destination); - if (debug_stubs) - printf ("(Pre-Alloc run: %i)\n", is_prealloc_run); - - stub_changed = TRUE; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - } - - /* Re-Calculate the number of needed stubs. */ - htab->stub_sec->size = 0; - bfd_hash_traverse (&htab->bstab, avr_size_one_stub, htab); - - if (!stub_changed) - break; - - stub_changed = FALSE; - } - - free (htab->all_local_syms); - return TRUE; - - error_ret_free_local: - free (htab->all_local_syms); - return FALSE; -} - - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. We also set up the .plt entries for statically linked PIC - functions here. This function is called via hppaelf_finish in the - linker. */ - -bfd_boolean -elf32_avr_build_stubs (struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - struct elf32_avr_link_hash_table *htab; - bfd_size_type total_size = 0; - - htab = avr_link_hash_table (info); - if (htab == NULL) - return FALSE; - - /* In case that there were several stub sections: */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - bfd_size_type size; - - /* Allocate memory to hold the linker stubs. */ - size = stub_sec->size; - total_size += size; - - stub_sec->contents = bfd_zalloc (htab->stub_bfd, size); - if (stub_sec->contents == NULL && size != 0) - return FALSE; - stub_sec->size = 0; - } - - /* Allocate memory for the adress mapping table. */ - htab->amt_entry_cnt = 0; - htab->amt_max_entry_cnt = total_size / 4; - htab->amt_stub_offsets = bfd_malloc (sizeof (bfd_vma) - * htab->amt_max_entry_cnt); - htab->amt_destination_addr = bfd_malloc (sizeof (bfd_vma) - * htab->amt_max_entry_cnt ); - - if (debug_stubs) - printf ("Allocating %i entries in the AMT\n", htab->amt_max_entry_cnt); - - /* Build the stubs as directed by the stub hash table. */ - table = &htab->bstab; - bfd_hash_traverse (table, avr_build_one_stub, info); - - if (debug_stubs) - printf ("Final Stub section Size: %i\n", (int) htab->stub_sec->size); - - return TRUE; -} - -/* Callback used by QSORT to order relocations AP and BP. */ - -static int -internal_reloc_compare (const void *ap, const void *bp) -{ - const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap; - const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp; - - if (a->r_offset != b->r_offset) - return (a->r_offset - b->r_offset); - - /* We don't need to sort on these criteria for correctness, - but enforcing a more strict ordering prevents unstable qsort - from behaving differently with different implementations. - Without the code below we get correct but different results - on Solaris 2.7 and 2.8. We would like to always produce the - same results no matter the host. */ - - if (a->r_info != b->r_info) - return (a->r_info - b->r_info); - - return (a->r_addend - b->r_addend); -} - -/* Return true if ADDRESS is within the vma range of SECTION from ABFD. */ - -static bfd_boolean -avr_is_section_for_address (bfd *abfd, asection *section, bfd_vma address) -{ - bfd_vma vma; - bfd_size_type size; - - vma = bfd_get_section_vma (abfd, section); - if (address < vma) - return FALSE; - - size = section->size; - if (address >= vma + size) - return FALSE; - - return TRUE; -} - -/* Data structure used by AVR_FIND_SECTION_FOR_ADDRESS. */ - -struct avr_find_section_data -{ - /* The address we're looking for. */ - bfd_vma address; - - /* The section we've found. */ - asection *section; -}; - -/* Helper function to locate the section holding a certain virtual memory - address. This is called via bfd_map_over_sections. The DATA is an - instance of STRUCT AVR_FIND_SECTION_DATA, the address field of which - has been set to the address to search for, and the section field has - been set to NULL. If SECTION from ABFD contains ADDRESS then the - section field in DATA will be set to SECTION. As an optimisation, if - the section field is already non-null then this function does not - perform any checks, and just returns. */ - -static void -avr_find_section_for_address (bfd *abfd, - asection *section, void *data) -{ - struct avr_find_section_data *fs_data - = (struct avr_find_section_data *) data; - - /* Return if already found. */ - if (fs_data->section != NULL) - return; - - /* If this section isn't part of the addressable code content, skip it. */ - if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0 - && (bfd_get_section_flags (abfd, section) & SEC_CODE) == 0) - return; - - if (avr_is_section_for_address (abfd, section, fs_data->address)) - fs_data->section = section; -} - -/* Load all of the property records from SEC, a section from ABFD. Return - a STRUCT AVR_PROPERTY_RECORD_LIST containing all the records. The - memory for the returned structure, and all of the records pointed too by - the structure are allocated with a single call to malloc, so, only the - pointer returned needs to be free'd. */ - -static struct avr_property_record_list * -avr_elf32_load_records_from_section (bfd *abfd, asection *sec) -{ - char *contents = NULL, *ptr; - bfd_size_type size, mem_size; - bfd_byte version, flags; - uint16_t record_count, i; - struct avr_property_record_list *r_list = NULL; - Elf_Internal_Rela *internal_relocs = NULL, *rel, *rel_end; - struct avr_find_section_data fs_data; - - fs_data.section = NULL; - - size = bfd_get_section_size (sec); - contents = bfd_malloc (size); - bfd_get_section_contents (abfd, sec, contents, 0, size); - ptr = contents; - - /* Load the relocations for the '.avr.prop' section if there are any, and - sort them. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, NULL, FALSE)); - if (internal_relocs) - qsort (internal_relocs, sec->reloc_count, - sizeof (Elf_Internal_Rela), internal_reloc_compare); - - /* There is a header at the start of the property record section SEC, the - format of this header is: - uint8_t : version number - uint8_t : flags - uint16_t : record counter - */ - - /* Check we have at least got a headers worth of bytes. */ - if (size < AVR_PROPERTY_SECTION_HEADER_SIZE) - goto load_failed; - - version = *((bfd_byte *) ptr); - ptr++; - flags = *((bfd_byte *) ptr); - ptr++; - record_count = *((uint16_t *) ptr); - ptr+=2; - BFD_ASSERT (ptr - contents == AVR_PROPERTY_SECTION_HEADER_SIZE); - - /* Now allocate space for the list structure, and all of the list - elements in a single block. */ - mem_size = sizeof (struct avr_property_record_list) - + sizeof (struct avr_property_record) * record_count; - r_list = bfd_malloc (mem_size); - if (r_list == NULL) - goto load_failed; - - r_list->version = version; - r_list->flags = flags; - r_list->section = sec; - r_list->record_count = record_count; - r_list->records = (struct avr_property_record *) (&r_list [1]); - size -= AVR_PROPERTY_SECTION_HEADER_SIZE; - - /* Check that we understand the version number. There is only one - version number right now, anything else is an error. */ - if (r_list->version != AVR_PROPERTY_RECORDS_VERSION) - goto load_failed; - - rel = internal_relocs; - rel_end = rel + sec->reloc_count; - for (i = 0; i < record_count; ++i) - { - bfd_vma address; - - /* Each entry is a 32-bit address, followed by a single byte type. - After that is the type specific data. We must take care to - ensure that we don't read beyond the end of the section data. */ - if (size < 5) - goto load_failed; - - r_list->records [i].section = NULL; - r_list->records [i].offset = 0; - - if (rel) - { - /* The offset of the address within the .avr.prop section. */ - size_t offset = ptr - contents; - - while (rel < rel_end && rel->r_offset < offset) - ++rel; - - if (rel == rel_end) - rel = NULL; - else if (rel->r_offset == offset) - { - /* Find section and section offset. */ - unsigned long r_symndx; - - asection * rel_sec; - bfd_vma sec_offset; - - r_symndx = ELF32_R_SYM (rel->r_info); - rel_sec = get_elf_r_symndx_section (abfd, r_symndx); - sec_offset = get_elf_r_symndx_offset (abfd, r_symndx) - + rel->r_addend; - - r_list->records [i].section = rel_sec; - r_list->records [i].offset = sec_offset; - } - } - - address = *((uint32_t *) ptr); - ptr += 4; - size -= 4; - - if (r_list->records [i].section == NULL) - { - /* Try to find section and offset from address. */ - if (fs_data.section != NULL - && !avr_is_section_for_address (abfd, fs_data.section, - address)) - fs_data.section = NULL; - - if (fs_data.section == NULL) - { - fs_data.address = address; - bfd_map_over_sections (abfd, avr_find_section_for_address, - &fs_data); - } - - if (fs_data.section == NULL) - { - fprintf (stderr, "Failed to find matching section.\n"); - goto load_failed; - } - - r_list->records [i].section = fs_data.section; - r_list->records [i].offset - = address - bfd_get_section_vma (abfd, fs_data.section); - } - - r_list->records [i].type = *((bfd_byte *) ptr); - ptr += 1; - size -= 1; - - switch (r_list->records [i].type) - { - case RECORD_ORG: - /* Nothing else to load. */ - break; - case RECORD_ORG_AND_FILL: - /* Just a 4-byte fill to load. */ - if (size < 4) - goto load_failed; - r_list->records [i].data.org.fill = *((uint32_t *) ptr); - ptr += 4; - size -= 4; - break; - case RECORD_ALIGN: - /* Just a 4-byte alignment to load. */ - if (size < 4) - goto load_failed; - r_list->records [i].data.align.bytes = *((uint32_t *) ptr); - ptr += 4; - size -= 4; - /* Just initialise PRECEDING_DELETED field, this field is - used during linker relaxation. */ - r_list->records [i].data.align.preceding_deleted = 0; - break; - case RECORD_ALIGN_AND_FILL: - /* A 4-byte alignment, and a 4-byte fill to load. */ - if (size < 8) - goto load_failed; - r_list->records [i].data.align.bytes = *((uint32_t *) ptr); - ptr += 4; - r_list->records [i].data.align.fill = *((uint32_t *) ptr); - ptr += 4; - size -= 8; - /* Just initialise PRECEDING_DELETED field, this field is - used during linker relaxation. */ - r_list->records [i].data.align.preceding_deleted = 0; - break; - default: - goto load_failed; - } - } - - free (contents); - if (elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return r_list; - - load_failed: - if (elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - free (contents); - free (r_list); - return NULL; -} - -/* Load all of the property records from ABFD. See - AVR_ELF32_LOAD_RECORDS_FROM_SECTION for details of the return value. */ - -struct avr_property_record_list * -avr_elf32_load_property_records (bfd *abfd) -{ - asection *sec; - - /* Find the '.avr.prop' section and load the contents into memory. */ - sec = bfd_get_section_by_name (abfd, AVR_PROPERTY_RECORD_SECTION_NAME); - if (sec == NULL) - return NULL; - return avr_elf32_load_records_from_section (abfd, sec); -} - -const char * -avr_elf32_property_record_name (struct avr_property_record *rec) -{ - const char *str; - - switch (rec->type) - { - case RECORD_ORG: - str = "ORG"; - break; - case RECORD_ORG_AND_FILL: - str = "ORG+FILL"; - break; - case RECORD_ALIGN: - str = "ALIGN"; - break; - case RECORD_ALIGN_AND_FILL: - str = "ALIGN+FILL"; - break; - default: - str = "unknown"; - } - - return str; -} - - -#define ELF_ARCH bfd_arch_avr -#define ELF_TARGET_ID AVR_ELF_DATA -#define ELF_MACHINE_CODE EM_AVR -#define ELF_MACHINE_ALT1 EM_AVR_OLD -#define ELF_MAXPAGESIZE 1 - -#define TARGET_LITTLE_SYM avr_elf32_vec -#define TARGET_LITTLE_NAME "elf32-avr" - -#define bfd_elf32_bfd_link_hash_table_create elf32_avr_link_hash_table_create - -#define elf_info_to_howto avr_info_to_howto_rela -#define elf_info_to_howto_rel NULL -#define elf_backend_relocate_section elf32_avr_relocate_section -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 -#define elf_backend_final_write_processing \ - bfd_elf_avr_final_write_processing -#define elf_backend_object_p elf32_avr_object_p - -#define bfd_elf32_bfd_relax_section elf32_avr_relax_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - elf32_avr_get_relocated_section_contents -#define bfd_elf32_new_section_hook elf_avr_new_section_hook - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-avr.h b/sdcc/support/sdbinutils/bfd/elf32-avr.h deleted file mode 100644 index b6c664c90..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-avr.h +++ /dev/null @@ -1,122 +0,0 @@ -/* AVR-specific support for 32-bit ELF. - Copyright (C) 2006-2018 Free Software Foundation, Inc. - - Written by Bjoern Haase - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - - -/* These four functions will be called from the ld back-end. */ - -extern void -elf32_avr_setup_params (struct bfd_link_info *, bfd *, asection *, - bfd_boolean, bfd_boolean, bfd_boolean, - bfd_vma, bfd_boolean); - -extern int -elf32_avr_setup_section_lists (bfd *, struct bfd_link_info *); - -extern bfd_boolean -elf32_avr_size_stubs (bfd *, struct bfd_link_info *, bfd_boolean); - -extern bfd_boolean -elf32_avr_build_stubs (struct bfd_link_info *); - -/* The name of the section into which the property records are stored. */ -#define AVR_PROPERTY_RECORD_SECTION_NAME ".avr.prop" - -/* The current version number for the format of the property records. */ -#define AVR_PROPERTY_RECORDS_VERSION 1 - -/* The size of the header that is written to the property record section - before the property records are written out. */ -#define AVR_PROPERTY_SECTION_HEADER_SIZE 4 - -/* This holds a single property record in memory, the structure of this - data when written out to the ELF section is more compressed. */ - -struct avr_property_record -{ - /* The section and offset for this record. */ - asection *section; - bfd_vma offset; - - /* The type of this record. */ - enum { - RECORD_ORG = 0, - RECORD_ORG_AND_FILL = 1, - RECORD_ALIGN = 2, - RECORD_ALIGN_AND_FILL = 3 - } type; - - /* Type specific data. */ - union - { - /* RECORD_ORG and RECORD_ORG_AND_FILL. */ - struct - { - unsigned long fill; - } org; - - /* RECORD_ALIGN and RECORD_ALIGN_AND_FILL. */ - struct - { - unsigned long bytes; - unsigned long fill; - - /* This field is used during linker relaxation to track the number of - bytes that have been opened up before this alignment directive. - When we have enough bytes available it is possible to move the - re-align this directive backwards while still maintaining the - alignment requirement. */ - unsigned long preceding_deleted; - } align; - } data; -}; - -struct avr_property_record_list -{ - /* The version number tells us the structure of the property record data - within the section. See AVR_PROPERTY_RECORDS_VERSION. */ - bfd_byte version; - - /* The flags field is currently unused. This should be set to 0. */ - bfd_byte flags; - - /* The number of property records. This is stored as a 2-byte value in - the section contents. */ - unsigned long record_count; - - /* The section from which the property records were loaded. This is the - actual section containing the records, not the section(s) to which the - records apply. */ - asection *section; - - /* The actual property records. */ - struct avr_property_record *records; -}; - -/* Load the property records from ABFD, return NULL if there are non - found, otherwise return pointer to dynamically allocated memory. The - memory for the header and all of the records are allocated in a single - block, as such only the header needs to be freed. */ - -extern struct avr_property_record_list *avr_elf32_load_property_records (bfd *abfd); - -/* Return a string that is the name of the property record pointed to by REC. */ -extern const char *avr_elf32_property_record_name (struct avr_property_record *rec); diff --git a/sdcc/support/sdbinutils/bfd/elf32-bfin.c b/sdcc/support/sdbinutils/bfd/elf32-bfin.c deleted file mode 100644 index 478b8d473..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-bfin.c +++ /dev/null @@ -1,5534 +0,0 @@ -/* ADI Blackfin BFD support for 32-bit ELF. - Copyright (C) 2005-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/bfin.h" -#include "dwarf2.h" -#include "hashtab.h" - -/* FUNCTION : bfin_pltpc_reloc - ABSTRACT : TODO : figure out how to handle pltpc relocs. */ -static bfd_reloc_status_type -bfin_pltpc_reloc ( - bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type flag = bfd_reloc_ok; - return flag; -} - - -static bfd_reloc_status_type -bfin_pcrel24_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - bfd_size_type addr = reloc_entry->address; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - asection *output_section; - bfd_boolean relocatable = (output_bfd != NULL); - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && !relocatable) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - output_section = symbol->section->output_section; - - if (relocatable) - output_base = 0; - else - output_base = output_section->vma; - - if (!relocatable || !strcmp (symbol->name, symbol->section->name)) - relocation += output_base + symbol->section->output_offset; - - if (!relocatable && !strcmp (symbol->name, symbol->section->name)) - relocation += reloc_entry->addend; - - relocation -= input_section->output_section->vma + input_section->output_offset; - relocation -= reloc_entry->address; - - if (howto->complain_on_overflow != complain_overflow_dont) - { - bfd_reloc_status_type status; - status = bfd_check_overflow (howto->complain_on_overflow, - howto->bitsize, - howto->rightshift, - bfd_arch_bits_per_address(abfd), - relocation); - if (status != bfd_reloc_ok) - return status; - } - - /* if rightshift is 1 and the number odd, return error. */ - if (howto->rightshift && (relocation & 0x01)) - { - _bfd_error_handler (_("relocation should be even number")); - return bfd_reloc_overflow; - } - - relocation >>= (bfd_vma) howto->rightshift; - /* Shift everything up to where it's going to be used. */ - - relocation <<= (bfd_vma) howto->bitpos; - - if (relocatable) - { - reloc_entry->address += input_section->output_offset; - reloc_entry->addend += symbol->section->output_offset; - } - - { - short x; - - /* We are getting reloc_entry->address 2 byte off from - the start of instruction. Assuming absolute postion - of the reloc data. But, following code had been written assuming - reloc address is starting at begining of instruction. - To compensate that I have increased the value of - relocation by 1 (effectively 2) and used the addr -2 instead of addr. */ - - relocation += 1; - x = bfd_get_16 (abfd, (bfd_byte *) data + addr - 2); - x = (x & 0xff00) | ((relocation >> 16) & 0xff); - bfd_put_16 (abfd, x, (unsigned char *) data + addr - 2); - - x = bfd_get_16 (abfd, (bfd_byte *) data + addr); - x = relocation & 0xFFFF; - bfd_put_16 (abfd, x, (unsigned char *) data + addr ); - } - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -bfin_imm16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation, x; - bfd_size_type reloc_addr = reloc_entry->address; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - asection *output_section; - bfd_boolean relocatable = (output_bfd != NULL); - - /* 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; - - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && !relocatable) - return bfd_reloc_undefined; - - output_section = symbol->section->output_section; - relocation = symbol->value; - - /* Convert input-section-relative symbol value to absolute. */ - if (relocatable) - output_base = 0; - else - output_base = output_section->vma; - - if (!relocatable || !strcmp (symbol->name, symbol->section->name)) - relocation += output_base + symbol->section->output_offset; - - /* Add in supplied addend. */ - relocation += reloc_entry->addend; - - if (relocatable) - { - reloc_entry->address += input_section->output_offset; - reloc_entry->addend += symbol->section->output_offset; - } - else - { - reloc_entry->addend = 0; - } - - if (howto->complain_on_overflow != complain_overflow_dont) - { - bfd_reloc_status_type flag; - flag = bfd_check_overflow (howto->complain_on_overflow, - howto->bitsize, - howto->rightshift, - bfd_arch_bits_per_address(abfd), - relocation); - if (flag != bfd_reloc_ok) - return flag; - } - - /* Here the variable relocation holds the final address of the - symbol we are relocating against, plus any addend. */ - - relocation >>= (bfd_vma) howto->rightshift; - x = relocation; - bfd_put_16 (abfd, x, (unsigned char *) data + reloc_addr); - return bfd_reloc_ok; -} - - -static bfd_reloc_status_type -bfin_byte4_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation, x; - bfd_size_type addr = reloc_entry->address; - bfd_vma output_base = 0; - asection *output_section; - bfd_boolean relocatable = (output_bfd != NULL); - - /* 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; - - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && !relocatable) - return bfd_reloc_undefined; - - output_section = symbol->section->output_section; - relocation = symbol->value; - /* Convert input-section-relative symbol value to absolute. */ - if (relocatable) - output_base = 0; - else - output_base = output_section->vma; - - if ((symbol->name - && symbol->section->name - && !strcmp (symbol->name, symbol->section->name)) - || !relocatable) - { - relocation += output_base + symbol->section->output_offset; - } - - relocation += reloc_entry->addend; - - if (relocatable) - { - /* This output will be relocatable ... like ld -r. */ - reloc_entry->address += input_section->output_offset; - reloc_entry->addend += symbol->section->output_offset; - } - else - { - reloc_entry->addend = 0; - } - - /* Here the variable relocation holds the final address of the - symbol we are relocating against, plus any addend. */ - x = relocation & 0xFFFF0000; - x >>=16; - bfd_put_16 (abfd, x, (unsigned char *) data + addr + 2); - - x = relocation & 0x0000FFFF; - bfd_put_16 (abfd, x, (unsigned char *) data + addr); - return bfd_reloc_ok; -} - -/* bfin_bfd_reloc handles the blackfin arithmetic relocations. - Use this instead of bfd_perform_relocation. */ -static bfd_reloc_status_type -bfin_bfd_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - bfd_size_type addr = reloc_entry->address; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - asection *output_section; - bfd_boolean relocatable = (output_bfd != NULL); - - /* 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; - - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && !relocatable) - return bfd_reloc_undefined; - - /* Get symbol value. (Common symbols are special.) */ - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - output_section = symbol->section->output_section; - - /* Convert input-section-relative symbol value to absolute. */ - if (relocatable) - output_base = 0; - else - output_base = output_section->vma; - - if (!relocatable || !strcmp (symbol->name, symbol->section->name)) - relocation += output_base + symbol->section->output_offset; - - if (!relocatable && !strcmp (symbol->name, symbol->section->name)) - { - /* 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) - { - relocation -= input_section->output_section->vma + input_section->output_offset; - - if (howto->pcrel_offset) - relocation -= reloc_entry->address; - } - - if (relocatable) - { - reloc_entry->address += input_section->output_offset; - reloc_entry->addend += symbol->section->output_offset; - } - - if (howto->complain_on_overflow != complain_overflow_dont) - { - bfd_reloc_status_type status; - - status = bfd_check_overflow (howto->complain_on_overflow, - howto->bitsize, - howto->rightshift, - bfd_arch_bits_per_address(abfd), - relocation); - if (status != bfd_reloc_ok) - return status; - } - - /* If rightshift is 1 and the number odd, return error. */ - if (howto->rightshift && (relocation & 0x01)) - { - _bfd_error_handler (_("relocation should be even number")); - return bfd_reloc_overflow; - } - - relocation >>= (bfd_vma) howto->rightshift; - - /* Shift everything up to where it's going to be used. */ - - relocation <<= (bfd_vma) howto->bitpos; - -#define DOIT(x) \ - x = ( (x & ~howto->dst_mask) | (relocation & howto->dst_mask)) - - /* handle 8 and 16 bit relocations here. */ - switch (howto->size) - { - case 0: - { - char x = bfd_get_8 (abfd, (char *) data + addr); - DOIT (x); - bfd_put_8 (abfd, x, (unsigned char *) data + addr); - } - break; - - case 1: - { - unsigned short x = bfd_get_16 (abfd, (bfd_byte *) data + addr); - DOIT (x); - bfd_put_16 (abfd, (bfd_vma) x, (unsigned char *) data + addr); - } - break; - - default: - return bfd_reloc_other; - } - - return bfd_reloc_ok; -} - -/* HOWTO Table for blackfin. - Blackfin relocations are fairly complicated. - Some of the salient features are - a. Even numbered offsets. A number of (not all) relocations are - even numbered. This means that the rightmost bit is not stored. - Needs to right shift by 1 and check to see if value is not odd - b. A relocation can be an expression. An expression takes on - a variety of relocations arranged in a stack. - As a result, we cannot use the standard generic function as special - function. We will have our own, which is very similar to the standard - generic function except that it understands how to get the value from - the relocation stack. . */ - -#define BFIN_RELOC_MIN 0 -#define BFIN_RELOC_MAX 0x21 -#define BFIN_GNUEXT_RELOC_MIN 0x40 -#define BFIN_GNUEXT_RELOC_MAX 0x43 -#define BFIN_ARELOC_MIN 0xE0 -#define BFIN_ARELOC_MAX 0xF3 - -static reloc_howto_type bfin_howto_table [] = -{ - /* This reloc does nothing. . */ - HOWTO (R_BFIN_UNUSED0, /* type. */ - 0, /* rightshift. */ - 3, /* size (0 = byte, 1 = short, 2 = long). */ - 0, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_BFIN_UNUSED0", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL5M2, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long).. */ - 4, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_PCREL5M2", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x0000000F, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_UNUSED1, /* type. */ - 0, /* rightshift. */ - 3, /* size (0 = byte, 1 = short, 2 = long). */ - 0, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_BFIN_UNUSED1", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL10, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 10, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_PCREL10", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x000003FF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL12_JUMP, /* type. */ - 1, /* rightshift. */ - /* the offset is actually 13 bit - aligned on a word boundary so - only 12 bits have to be used. - Right shift the rightmost bit.. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 12, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_PCREL12_JUMP", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x0FFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_RIMM16, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_imm16_reloc, /* special_function. */ - "R_BFIN_RIMM16", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x0000FFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_LUIMM16, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - bfin_imm16_reloc, /* special_function. */ - "R_BFIN_LUIMM16", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x0000FFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_HUIMM16, /* type. */ - 16, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfin_imm16_reloc, /* special_function. */ - "R_BFIN_HUIMM16", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x0000FFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL12_JUMP_S, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 12, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_PCREL12_JUMP_S", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x00000FFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL24_JUMP_X, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 24, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_pcrel24_reloc, /* special_function. */ - "R_BFIN_PCREL24_JUMP_X", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x00FFFFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL24, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 24, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_pcrel24_reloc, /* special_function. */ - "R_BFIN_PCREL24", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x00FFFFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_UNUSEDB, /* type. */ - 0, /* rightshift. */ - 3, /* size (0 = byte, 1 = short, 2 = long). */ - 0, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_BFIN_UNUSEDB", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_UNUSEDC, /* type. */ - 0, /* rightshift. */ - 3, /* size (0 = byte, 1 = short, 2 = long). */ - 0, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_BFIN_UNUSEDC", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL24_JUMP_L, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 24, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_pcrel24_reloc, /* special_function. */ - "R_BFIN_PCREL24_JUMP_L", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x00FFFFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL24_CALL_X, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 24, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_pcrel24_reloc, /* special_function. */ - "R_BFIN_PCREL24_CALL_X", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x00FFFFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_VAR_EQ_SYMB, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_VAR_EQ_SYMB", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_BYTE_DATA, /* type. */ - 0, /* rightshift. */ - 0, /* size (0 = byte, 1 = short, 2 = long). */ - 8, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_BYTE_DATA", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0xFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_BYTE2_DATA, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_BYTE2_DATA", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0xFFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_BYTE4_DATA, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfin_byte4_reloc, /* special_function. */ - "R_BFIN_BYTE4_DATA", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0xFFFFFFFF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_BFIN_PCREL11, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 10, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfin_bfd_reloc, /* special_function. */ - "R_BFIN_PCREL11", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x000003FF, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - - /* A 18-bit signed operand with the GOT offset for the address of - the symbol. */ - HOWTO (R_BFIN_GOT17M4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_GOT17M4", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_BFIN_GOTHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_GOTHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_BFIN_GOTLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_GOTLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 32-bit address of the canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_GOT17M4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_GOT17M4", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_GOTHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_GOTHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_GOTLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_GOTLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 32-bit address of the canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_VALUE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_VALUE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_GOTOFF17M4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_GOTOFF17M4", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_GOTOFFHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_GOTOFFHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_BFIN_FUNCDESC_GOTOFFLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_FUNCDESC_GOTOFFLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - the symbol. */ - HOWTO (R_BFIN_GOTOFF17M4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_GOTOFF17M4", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_BFIN_GOTOFFHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_GOTOFFHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_BFIN_GOTOFFLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_BFIN_GOTOFFLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static reloc_howto_type bfin_gnuext_howto_table [] = -{ - HOWTO (R_BFIN_PLTPC, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfin_pltpc_reloc, /* special_function. */ - "R_BFIN_PLTPC", /* name. */ - FALSE, /* partial_inplace. */ - 0xffff, /* src_mask. */ - 0xffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_BFIN_GOT, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_BFIN_GOT", /* name. */ - FALSE, /* partial_inplace. */ - 0x7fff, /* src_mask. */ - 0x7fff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - -/* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_BFIN_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_BFIN_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_BFIN_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_BFIN_GNU_VTENTRY", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - FALSE) /* pcrel_offset. */ -}; - -struct bfin_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int bfin_reloc_val; -}; - -static const struct bfin_reloc_map bfin_reloc_map [] = -{ - { BFD_RELOC_NONE, R_BFIN_UNUSED0 }, - { BFD_RELOC_BFIN_5_PCREL, R_BFIN_PCREL5M2 }, - { BFD_RELOC_NONE, R_BFIN_UNUSED1 }, - { BFD_RELOC_BFIN_10_PCREL, R_BFIN_PCREL10 }, - { BFD_RELOC_BFIN_12_PCREL_JUMP, R_BFIN_PCREL12_JUMP }, - { BFD_RELOC_BFIN_16_IMM, R_BFIN_RIMM16 }, - { BFD_RELOC_BFIN_16_LOW, R_BFIN_LUIMM16 }, - { BFD_RELOC_BFIN_16_HIGH, R_BFIN_HUIMM16 }, - { BFD_RELOC_BFIN_12_PCREL_JUMP_S, R_BFIN_PCREL12_JUMP_S }, - { BFD_RELOC_24_PCREL, R_BFIN_PCREL24 }, - { BFD_RELOC_24_PCREL, R_BFIN_PCREL24 }, - { BFD_RELOC_BFIN_24_PCREL_JUMP_L, R_BFIN_PCREL24_JUMP_L }, - { BFD_RELOC_NONE, R_BFIN_UNUSEDB }, - { BFD_RELOC_NONE, R_BFIN_UNUSEDC }, - { BFD_RELOC_BFIN_24_PCREL_CALL_X, R_BFIN_PCREL24_CALL_X }, - { BFD_RELOC_8, R_BFIN_BYTE_DATA }, - { BFD_RELOC_16, R_BFIN_BYTE2_DATA }, - { BFD_RELOC_32, R_BFIN_BYTE4_DATA }, - { BFD_RELOC_BFIN_11_PCREL, R_BFIN_PCREL11 }, - { BFD_RELOC_BFIN_GOT, R_BFIN_GOT }, - { BFD_RELOC_BFIN_PLTPC, R_BFIN_PLTPC }, - - { BFD_RELOC_BFIN_GOT17M4, R_BFIN_GOT17M4 }, - { BFD_RELOC_BFIN_GOTHI, R_BFIN_GOTHI }, - { BFD_RELOC_BFIN_GOTLO, R_BFIN_GOTLO }, - { BFD_RELOC_BFIN_FUNCDESC, R_BFIN_FUNCDESC }, - { BFD_RELOC_BFIN_FUNCDESC_GOT17M4, R_BFIN_FUNCDESC_GOT17M4 }, - { BFD_RELOC_BFIN_FUNCDESC_GOTHI, R_BFIN_FUNCDESC_GOTHI }, - { BFD_RELOC_BFIN_FUNCDESC_GOTLO, R_BFIN_FUNCDESC_GOTLO }, - { BFD_RELOC_BFIN_FUNCDESC_VALUE, R_BFIN_FUNCDESC_VALUE }, - { BFD_RELOC_BFIN_FUNCDESC_GOTOFF17M4, R_BFIN_FUNCDESC_GOTOFF17M4 }, - { BFD_RELOC_BFIN_FUNCDESC_GOTOFFHI, R_BFIN_FUNCDESC_GOTOFFHI }, - { BFD_RELOC_BFIN_FUNCDESC_GOTOFFLO, R_BFIN_FUNCDESC_GOTOFFLO }, - { BFD_RELOC_BFIN_GOTOFF17M4, R_BFIN_GOTOFF17M4 }, - { BFD_RELOC_BFIN_GOTOFFHI, R_BFIN_GOTOFFHI }, - { BFD_RELOC_BFIN_GOTOFFLO, R_BFIN_GOTOFFLO }, - - { BFD_RELOC_VTABLE_INHERIT, R_BFIN_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_BFIN_GNU_VTENTRY }, -}; - - -static void -bfin_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - - if (r_type <= BFIN_RELOC_MAX) - cache_ptr->howto = &bfin_howto_table [r_type]; - - else if (r_type >= BFIN_GNUEXT_RELOC_MIN && r_type <= BFIN_GNUEXT_RELOC_MAX) - cache_ptr->howto = &bfin_gnuext_howto_table [r_type - BFIN_GNUEXT_RELOC_MIN]; - - else - cache_ptr->howto = (reloc_howto_type *) NULL; -} - -/* Given a BFD reloc type, return the howto. */ -static reloc_howto_type * -bfin_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - unsigned int r_type = (unsigned int) -1; - - for (i = sizeof (bfin_reloc_map) / sizeof (bfin_reloc_map[0]); i--;) - if (bfin_reloc_map[i].bfd_reloc_val == code) - r_type = bfin_reloc_map[i].bfin_reloc_val; - - if (r_type <= BFIN_RELOC_MAX) - return &bfin_howto_table [r_type]; - - else if (r_type >= BFIN_GNUEXT_RELOC_MIN && r_type <= BFIN_GNUEXT_RELOC_MAX) - return &bfin_gnuext_howto_table [r_type - BFIN_GNUEXT_RELOC_MIN]; - - return (reloc_howto_type *) NULL; -} - -static reloc_howto_type * -bfin_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (bfin_howto_table) - / sizeof (bfin_howto_table[0])); - i++) - if (bfin_howto_table[i].name != NULL - && strcasecmp (bfin_howto_table[i].name, r_name) == 0) - return &bfin_howto_table[i]; - - for (i = 0; - i < (sizeof (bfin_gnuext_howto_table) - / sizeof (bfin_gnuext_howto_table[0])); - i++) - if (bfin_gnuext_howto_table[i].name != NULL - && strcasecmp (bfin_gnuext_howto_table[i].name, r_name) == 0) - return &bfin_gnuext_howto_table[i]; - - return NULL; -} - -/* Given a bfin relocation type, return the howto. */ -static reloc_howto_type * -bfin_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - unsigned int r_type) -{ - if (r_type <= BFIN_RELOC_MAX) - return &bfin_howto_table [r_type]; - - else if (r_type >= BFIN_GNUEXT_RELOC_MIN && r_type <= BFIN_GNUEXT_RELOC_MAX) - return &bfin_gnuext_howto_table [r_type - BFIN_GNUEXT_RELOC_MIN]; - - return (reloc_howto_type *) NULL; -} - -/* Set by ld emulation if --code-in-l1. */ -bfd_boolean elf32_bfin_code_in_l1 = 0; - -/* Set by ld emulation if --data-in-l1. */ -bfd_boolean elf32_bfin_data_in_l1 = 0; - -static void -elf32_bfin_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - if (elf32_bfin_code_in_l1) - elf_elfheader (abfd)->e_flags |= EF_BFIN_CODE_IN_L1; - if (elf32_bfin_data_in_l1) - elf_elfheader (abfd)->e_flags |= EF_BFIN_DATA_IN_L1; -} - -/* Return TRUE if the name is a local label. - bfin local labels begin with L$. */ -static bfd_boolean -bfin_is_local_label_name (bfd *abfd, const char *label) -{ - if (label[0] == 'L' && label[1] == '$' ) - return TRUE; - - return _bfd_elf_is_local_label_name (abfd, label); -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -bfin_check_relocs (bfd * abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_signed_vma *local_got_refcounts; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - asection *sgot; - asection *srelgot; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - sgot = NULL; - srelgot = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_BFIN_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_BFIN_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_BFIN_GOT: - if (h != NULL - && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) - break; - /* Fall through. */ - - if (dynobj == NULL) - { - /* Create the .got section. */ - elf_hash_table (info)->dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - } - - sgot = elf_hash_table (info)->sgot; - srelgot = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - if (h->got.refcount == 0) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1 && !h->forced_local) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* Allocate space in the .got section. */ - sgot->size += 4; - /* Allocate relocation space. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - h->got.refcount++; - } - else - { - /* This is a global offset table entry for a local symbol. */ - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - if (local_got_refcounts[r_symndx] == 0) - { - sgot->size += 4; - if (bfd_link_pic (info)) - { - /* If we are generating a shared object, we need to - output a R_68K_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - } - local_got_refcounts[r_symndx]++; - } - break; - - default: - break; - } - } - - return TRUE; -} - -static enum elf_reloc_type_class -elf32_bfin_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela * rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - default: - return reloc_class_normal; - } -} - -static bfd_reloc_status_type -bfin_final_link_relocate (Elf_Internal_Rela *rel, reloc_howto_type *howto, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, bfd_vma address, - bfd_vma value, bfd_vma addend) -{ - int r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_BFIN_PCREL24 || r_type == R_BFIN_PCREL24_JUMP_L) - { - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma x; - - if (address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - value += addend; - - /* Perform usual pc-relative correction. */ - value -= input_section->output_section->vma + input_section->output_offset; - value -= address; - - /* We are getting reloc_entry->address 2 byte off from - the start of instruction. Assuming absolute postion - of the reloc data. But, following code had been written assuming - reloc address is starting at begining of instruction. - To compensate that I have increased the value of - relocation by 1 (effectively 2) and used the addr -2 instead of addr. */ - - value += 2; - address -= 2; - - if ((value & 0xFF000000) != 0 - && (value & 0xFF000000) != 0xFF000000) - r = bfd_reloc_overflow; - - value >>= 1; - - x = bfd_get_16 (input_bfd, contents + address); - x = (x & 0xff00) | ((value >> 16) & 0xff); - bfd_put_16 (input_bfd, x, contents + address); - - x = bfd_get_16 (input_bfd, contents + address + 2); - x = value & 0xFFFF; - bfd_put_16 (input_bfd, x, contents + address + 2); - return r; - } - - return _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, value, addend); - -} - -static bfd_boolean -bfin_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) -{ - bfd *dynobj; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - asection *sgot; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - int i = 0; - - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - sgot = NULL; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++, i++) - { - 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 relocation = 0; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - bfd_vma address; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= 243) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (r_type == R_BFIN_GNU_VTENTRY - || r_type == R_BFIN_GNU_VTINHERIT) - continue; - - howto = bfin_reloc_type_lookup (input_bfd, r_type); - if (howto == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - r_symndx = ELF32_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, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - address = rel->r_offset; - - /* Then, process normally. */ - switch (r_type) - { - case R_BFIN_GNU_VTINHERIT: - case R_BFIN_GNU_VTENTRY: - return bfd_reloc_ok; - - case R_BFIN_GOT: - /* Relocation is to the address of the entry for this symbol - in the global offset table. */ - if (h != NULL - && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) - goto do_default; - /* Fall through. */ - /* Relocation is the offset of the entry for this symbol in - the global offset table. */ - - { - bfd_vma off; - - if (dynobj == NULL) - { - /* Create the .got section. */ - elf_hash_table (info)->dynobj = dynobj = output_bfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - } - - sgot = elf_hash_table (info)->sgot; - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) - 1); - dyn = elf_hash_table (info)->dynamic_sections_created; - - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file.. We must initialize - this entry in the global offset table. Since - the offset must always be a multiple of 4, we - use the least significant bit to record whether - we have initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; - } - } - else - unresolved_reloc = FALSE; - } - else - { - BFD_ASSERT (local_got_offsets != NULL); - off = local_got_offsets[r_symndx]; - BFD_ASSERT (off != (bfd_vma) - 1); - - /* 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, sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *s; - Elf_Internal_Rela outrel; - bfd_byte *loc; - - s = elf_hash_table (info)->srelgot; - BFD_ASSERT (s != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset + off); - outrel.r_info = - ELF32_R_INFO (0, R_BFIN_PCREL24); - outrel.r_addend = relocation; - loc = s->contents; - loc += - s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - - local_got_offsets[r_symndx] |= 1; - } - } - - relocation = sgot->output_offset + off; - rel->r_addend = 0; - /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4. */ - relocation /= 4; - } - goto do_default; - - default: - do_default: - r = bfin_final_link_relocate (rel, howto, input_bfd, input_section, - contents, address, - relocation, rel->r_addend); - - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable relocation against symbol `%s'"), - input_bfd, - input_section, rel->r_offset, h->root.root.string); - return FALSE; - } - - 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) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), - input_bfd, input_section, rel->r_offset, name, (int) r); - return FALSE; - } - } - } - - return TRUE; -} - -static asection * -bfin_gc_mark_hook (asection * sec, - struct bfd_link_info *info, - Elf_Internal_Rela * rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym * sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_BFIN_GNU_VTINHERIT: - case R_BFIN_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -extern const bfd_target bfin_elf32_fdpic_vec; -#define IS_FDPIC(bfd) ((bfd)->xvec == &bfin_elf32_fdpic_vec) - -/* An extension of the elf hash table data structure, - containing some additional Blackfin-specific data. */ -struct bfinfdpic_elf_link_hash_table -{ - struct elf_link_hash_table elf; - - /* A pointer to the .rofixup section. */ - asection *sgotfixup; - /* GOT base offset. */ - bfd_vma got0; - /* Location of the first non-lazy PLT entry, i.e., the number of - bytes taken by lazy PLT entries. */ - bfd_vma plt0; - /* A hash table holding information about which symbols were - referenced with which PIC-related relocations. */ - struct htab *relocs_info; - /* Summary reloc information collected by - _bfinfdpic_count_got_plt_entries. */ - struct _bfinfdpic_dynamic_got_info *g; -}; - -/* Get the Blackfin ELF linker hash table from a link_info structure. */ - -#define bfinfdpic_hash_table(info) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \ - == BFIN_ELF_DATA ? ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash)) : NULL) - -#define bfinfdpic_got_section(info) \ - (bfinfdpic_hash_table (info)->elf.sgot) -#define bfinfdpic_gotrel_section(info) \ - (bfinfdpic_hash_table (info)->elf.srelgot) -#define bfinfdpic_gotfixup_section(info) \ - (bfinfdpic_hash_table (info)->sgotfixup) -#define bfinfdpic_plt_section(info) \ - (bfinfdpic_hash_table (info)->elf.splt) -#define bfinfdpic_pltrel_section(info) \ - (bfinfdpic_hash_table (info)->elf.srelplt) -#define bfinfdpic_relocs_info(info) \ - (bfinfdpic_hash_table (info)->relocs_info) -#define bfinfdpic_got_initial_offset(info) \ - (bfinfdpic_hash_table (info)->got0) -#define bfinfdpic_plt_initial_offset(info) \ - (bfinfdpic_hash_table (info)->plt0) -#define bfinfdpic_dynamic_got_plt_info(info) \ - (bfinfdpic_hash_table (info)->g) - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -#define DEFAULT_STACK_SIZE 0x20000 - -/* This structure is used to collect the number of entries present in - each addressable range of the got. */ -struct _bfinfdpic_dynamic_got_info -{ - /* Several bits of information about the current link. */ - struct bfd_link_info *info; - /* Total size needed for GOT entries within the 18- or 32-bit - ranges. */ - bfd_vma got17m4, gothilo; - /* Total size needed for function descriptor entries within the 18- - or 32-bit ranges. */ - bfd_vma fd17m4, fdhilo; - /* Total size needed function descriptor entries referenced in PLT - entries, that would be profitable to place in offsets close to - the PIC register. */ - bfd_vma fdplt; - /* Total size needed by lazy PLT entries. */ - bfd_vma lzplt; - /* Number of relocations carried over from input object files. */ - unsigned long relocs; - /* Number of fixups introduced by relocations in input object files. */ - unsigned long fixups; -}; - -/* Create a Blackfin ELF linker hash table. */ - -static struct bfd_link_hash_table * -bfinfdpic_elf_link_hash_table_create (bfd *abfd) -{ - struct bfinfdpic_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry), - BFIN_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->elf.root; -} - -/* Decide whether a reference to a symbol can be resolved locally or - not. If the symbol is protected, we want the local address, but - its function descriptor must be assigned by the dynamic linker. */ -#define BFINFDPIC_SYM_LOCAL(INFO, H) \ - (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \ - || ! elf_hash_table (INFO)->dynamic_sections_created) -#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \ - ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created) - -/* This structure collects information on what kind of GOT, PLT or - function descriptors are required by relocations that reference a - certain symbol. */ -struct bfinfdpic_relocs_info -{ - /* The index of the symbol, as stored in the relocation r_info, if - we have a local symbol; -1 otherwise. */ - long symndx; - union - { - /* The input bfd in which the symbol is defined, if it's a local - symbol. */ - bfd *abfd; - /* If symndx == -1, the hash table entry corresponding to a global - symbol (even if it turns out to bind locally, in which case it - should ideally be replaced with section's symndx + addend). */ - struct elf_link_hash_entry *h; - } d; - /* The addend of the relocation that references the symbol. */ - bfd_vma addend; - - /* The fields above are used to identify an entry. The fields below - contain information on how an entry is used and, later on, which - locations it was assigned. */ - /* The following 2 fields record whether the symbol+addend above was - ever referenced with a GOT relocation. The 17M4 suffix indicates a - GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs. */ - unsigned got17m4; - unsigned gothilo; - /* Whether a FUNCDESC relocation references symbol+addend. */ - unsigned fd; - /* Whether a FUNCDESC_GOT relocation references symbol+addend. */ - unsigned fdgot17m4; - unsigned fdgothilo; - /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */ - unsigned fdgoff17m4; - unsigned fdgoffhilo; - /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or - GOTOFFHI relocations. The addend doesn't really matter, since we - envision that this will only be used to check whether the symbol - is mapped to the same segment as the got. */ - unsigned gotoff; - /* Whether symbol+addend is referenced by a LABEL24 relocation. */ - unsigned call; - /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE - relocation. */ - unsigned sym; - /* Whether we need a PLT entry for a symbol. Should be implied by - something like: - (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)) */ - unsigned plt:1; - /* Whether a function descriptor should be created in this link unit - for symbol+addend. Should be implied by something like: - (plt || fdgotoff17m4 || fdgotofflohi - || ((fd || fdgot17m4 || fdgothilo) - && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h)))) */ - unsigned privfd:1; - /* Whether a lazy PLT entry is needed for this symbol+addend. - Should be implied by something like: - (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h) - && ! (info->flags & DF_BIND_NOW)) */ - unsigned lazyplt:1; - /* Whether we've already emitted GOT relocations and PLT entries as - needed for this symbol. */ - unsigned done:1; - - /* The number of R_BFIN_BYTE4_DATA, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE - relocations referencing the symbol. */ - unsigned relocs32, relocsfd, relocsfdv; - - /* The number of .rofixups entries and dynamic relocations allocated - for this symbol, minus any that might have already been used. */ - unsigned fixups, dynrelocs; - - /* The offsets of the GOT entries assigned to symbol+addend, to the - function descriptor's address, and to a function descriptor, - respectively. Should be zero if unassigned. The offsets are - counted from the value that will be assigned to the PIC register, - not from the beginning of the .got section. */ - bfd_signed_vma got_entry, fdgot_entry, fd_entry; - /* The offsets of the PLT entries assigned to symbol+addend, - non-lazy and lazy, respectively. If unassigned, should be - (bfd_vma)-1. */ - bfd_vma plt_entry, lzplt_entry; -}; - -/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry. */ -static hashval_t -bfinfdpic_relocs_info_hash (const void *entry_) -{ - const struct bfinfdpic_relocs_info *entry = entry_; - - return (entry->symndx == -1 - ? (long) entry->d.h->root.root.hash - : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend; -} - -/* Test whether the key fields of two bfinfdpic_relocs_info entries are - identical. */ -static int -bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2) -{ - const struct bfinfdpic_relocs_info *e1 = entry1; - const struct bfinfdpic_relocs_info *e2 = entry2; - - return e1->symndx == e2->symndx && e1->addend == e2->addend - && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd); -} - -/* Find or create an entry in a hash table HT that matches the key - fields of the given ENTRY. If it's not found, memory for a new - entry is allocated in ABFD's obstack. */ -static struct bfinfdpic_relocs_info * -bfinfdpic_relocs_info_find (struct htab *ht, - bfd *abfd, - const struct bfinfdpic_relocs_info *entry, - enum insert_option insert) -{ - struct bfinfdpic_relocs_info **loc; - - if (!ht) - return NULL; - - loc = (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert); - - if (! loc) - return NULL; - - if (*loc) - return *loc; - - *loc = bfd_zalloc (abfd, sizeof (**loc)); - - if (! *loc) - return *loc; - - (*loc)->symndx = entry->symndx; - (*loc)->d = entry->d; - (*loc)->addend = entry->addend; - (*loc)->plt_entry = (bfd_vma)-1; - (*loc)->lzplt_entry = (bfd_vma)-1; - - return *loc; -} - -/* Obtain the address of the entry in HT associated with H's symbol + - addend, creating a new entry if none existed. ABFD is only used - for memory allocation purposes. */ -inline static struct bfinfdpic_relocs_info * -bfinfdpic_relocs_info_for_global (struct htab *ht, - bfd *abfd, - struct elf_link_hash_entry *h, - bfd_vma addend, - enum insert_option insert) -{ - struct bfinfdpic_relocs_info entry; - - entry.symndx = -1; - entry.d.h = h; - entry.addend = addend; - - return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert); -} - -/* Obtain the address of the entry in HT associated with the SYMNDXth - local symbol of the input bfd ABFD, plus the addend, creating a new - entry if none existed. */ -inline static struct bfinfdpic_relocs_info * -bfinfdpic_relocs_info_for_local (struct htab *ht, - bfd *abfd, - long symndx, - bfd_vma addend, - enum insert_option insert) -{ - struct bfinfdpic_relocs_info entry; - - entry.symndx = symndx; - entry.d.abfd = abfd; - entry.addend = addend; - - return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert); -} - -/* Merge fields set by check_relocs() of two entries that end up being - mapped to the same (presumably global) symbol. */ - -inline static void -bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2, - struct bfinfdpic_relocs_info const *e1) -{ - e2->got17m4 |= e1->got17m4; - e2->gothilo |= e1->gothilo; - e2->fd |= e1->fd; - e2->fdgot17m4 |= e1->fdgot17m4; - e2->fdgothilo |= e1->fdgothilo; - e2->fdgoff17m4 |= e1->fdgoff17m4; - e2->fdgoffhilo |= e1->fdgoffhilo; - e2->gotoff |= e1->gotoff; - e2->call |= e1->call; - e2->sym |= e1->sym; -} - -/* Every block of 65535 lazy PLT entries shares a single call to the - resolver, inserted in the 32768th lazy PLT entry (i.e., entry # - 32767, counting from 0). All other lazy PLT entries branch to it - in a single instruction. */ - -#define LZPLT_RESOLVER_EXTRA 10 -#define LZPLT_NORMAL_SIZE 6 -#define LZPLT_ENTRIES 1362 - -#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA) -#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2) - -/* Add a dynamic relocation to the SRELOC section. */ - -inline static bfd_vma -_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, - int reloc_type, long dynindx, bfd_vma addend, - struct bfinfdpic_relocs_info *entry) -{ - Elf_Internal_Rela outrel; - bfd_vma reloc_offset; - - outrel.r_offset = offset; - outrel.r_info = ELF32_R_INFO (dynindx, reloc_type); - outrel.r_addend = addend; - - reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel); - BFD_ASSERT (reloc_offset < sreloc->size); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, - sreloc->contents + reloc_offset); - sreloc->reloc_count++; - - /* If the entry's index is zero, this relocation was probably to a - linkonce section that got discarded. We reserved a dynamic - relocation, but it was for another entry than the one we got at - the time of emitting the relocation. Unfortunately there's no - simple way for us to catch this situation, since the relocation - is cleared right before calling relocate_section, at which point - we no longer know what the relocation used to point to. */ - if (entry->symndx) - { - BFD_ASSERT (entry->dynrelocs > 0); - entry->dynrelocs--; - } - - return reloc_offset; -} - -/* Add a fixup to the ROFIXUP section. */ - -static bfd_vma -_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset, - struct bfinfdpic_relocs_info *entry) -{ - bfd_vma fixup_offset; - - if (rofixup->flags & SEC_EXCLUDE) - return -1; - - fixup_offset = rofixup->reloc_count * 4; - if (rofixup->contents) - { - BFD_ASSERT (fixup_offset < rofixup->size); - bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset); - } - rofixup->reloc_count++; - - if (entry && entry->symndx) - { - /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc - above. */ - BFD_ASSERT (entry->fixups > 0); - entry->fixups--; - } - - return fixup_offset; -} - -/* Find the segment number in which OSEC, and output section, is - located. */ - -static unsigned -_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec) -{ - Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec); - - return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1; -} - -inline static bfd_boolean -_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec) -{ - unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec); - - return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W); -} - -/* Generate relocations for GOT entries, function descriptors, and - code for PLT and lazy PLT entries. */ - -inline static bfd_boolean -_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry, - bfd *output_bfd, - struct bfd_link_info *info, - asection *sec, - Elf_Internal_Sym *sym, - bfd_vma addend) -{ - bfd_vma fd_lazy_rel_offset = (bfd_vma) -1; - int dynindx = -1; - - if (entry->done) - return TRUE; - entry->done = 1; - - if (entry->got_entry || entry->fdgot_entry || entry->fd_entry) - { - /* If the symbol is dynamic, consider it for dynamic - relocations, otherwise decay to section + offset. */ - if (entry->symndx == -1 && entry->d.h->dynindx != -1) - dynindx = entry->d.h->dynindx; - else - { - if (sec - && sec->output_section - && ! bfd_is_abs_section (sec->output_section) - && ! bfd_is_und_section (sec->output_section)) - dynindx = elf_section_data (sec->output_section)->dynindx; - else - dynindx = 0; - } - } - - /* Generate relocation for GOT entry pointing to the symbol. */ - if (entry->got_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - - /* If we're linking an executable at a fixed address, we can - omit the dynamic relocation as long as the symbol is local to - this module. */ - if (bfd_link_pde (info) - && (entry->symndx != -1 - || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (sec) - ad += sec->output_section->vma; - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info)->output_section - ->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->got_entry, entry); - } - else - _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - bfinfdpic_got_section (info), - bfinfdpic_got_initial_offset (info) - + entry->got_entry) - + bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info)->output_offset, - R_BFIN_BYTE4_DATA, idx, ad, entry); - - bfd_put_32 (output_bfd, ad, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->got_entry); - } - - /* Generate relocation for GOT entry pointing to a canonical - function descriptor. */ - if (entry->fdgot_entry) - { - int reloc, idx; - bfd_vma ad = 0; - - if (! (entry->symndx == -1 - && entry->d.h->root.type == bfd_link_hash_undefweak - && BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - /* If the symbol is dynamic and there may be dynamic symbol - resolution because we are, or are linked with, a shared - library, emit a FUNCDESC relocation such that the dynamic - linker will allocate the function descriptor. If the - symbol needs a non-local function descriptor but binds - locally (e.g., its visibility is protected, emit a - dynamic relocation decayed to section+offset. */ - if (entry->symndx == -1 - && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h) - && BFINFDPIC_SYM_LOCAL (info, entry->d.h) - && !bfd_link_pde (info)) - { - reloc = R_BFIN_FUNCDESC; - idx = elf_section_data (entry->d.h->root.u.def.section - ->output_section)->dynindx; - ad = entry->d.h->root.u.def.section->output_offset - + entry->d.h->root.u.def.value; - } - else if (entry->symndx == -1 - && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)) - { - reloc = R_BFIN_FUNCDESC; - idx = dynindx; - ad = addend; - if (ad) - return FALSE; - } - else - { - /* Otherwise, we know we have a private function descriptor, - so reference it directly. */ - if (elf_hash_table (info)->dynamic_sections_created) - BFD_ASSERT (entry->privfd); - reloc = R_BFIN_BYTE4_DATA; - idx = elf_section_data (bfinfdpic_got_section (info) - ->output_section)->dynindx; - ad = bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info) + entry->fd_entry; - } - - /* If there is room for dynamic symbol resolution, emit the - dynamic relocation. However, if we're linking an - executable at a fixed location, we won't have emitted a - dynamic symbol entry for the got section, so idx will be - zero, which means we can and should compute the address - of the private descriptor ourselves. */ - if (bfd_link_pde (info) - && (entry->symndx != -1 - || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))) - { - ad += bfinfdpic_got_section (info)->output_section->vma; - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->fdgot_entry, entry); - } - else - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - bfinfdpic_got_section (info), - bfinfdpic_got_initial_offset (info) - + entry->fdgot_entry) - + bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset, - reloc, idx, ad, entry); - } - - bfd_put_32 (output_bfd, ad, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->fdgot_entry); - } - - /* Generate relocation to fill in a private function descriptor in - the GOT. */ - if (entry->fd_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - bfd_vma ofst; - long lowword, highword; - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - - /* If we're linking an executable at a fixed address, we can - omit the dynamic relocation as long as the symbol is local to - this module. */ - if (bfd_link_pde (info) - && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (sec) - ad += sec->output_section->vma; - ofst = 0; - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - { - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry, entry); - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section (info), - bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry + 4, entry); - } - } - else - { - ofst - = _bfinfdpic_add_dyn_reloc (output_bfd, - entry->lazyplt - ? bfinfdpic_pltrel_section (info) - : bfinfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - bfinfdpic_got_section (info), - bfinfdpic_got_initial_offset (info) - + entry->fd_entry) - + bfinfdpic_got_section (info) - ->output_section->vma - + bfinfdpic_got_section (info) - ->output_offset, - R_BFIN_FUNCDESC_VALUE, idx, ad, entry); - } - - /* If we've omitted the dynamic relocation, just emit the fixed - addresses of the symbol and of the local GOT base offset. */ - if (bfd_link_pde (info) - && sec - && sec->output_section) - { - lowword = ad; - highword = bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info); - } - else if (entry->lazyplt) - { - if (ad) - return FALSE; - - fd_lazy_rel_offset = ofst; - - /* A function descriptor used for lazy or local resolving is - initialized such that its high word contains the output - section index in which the PLT entries are located, and - the low word contains the address of the lazy PLT entry - entry point, that must be within the memory region - assigned to that section. */ - lowword = entry->lzplt_entry + 4 - + bfinfdpic_plt_section (info)->output_offset - + bfinfdpic_plt_section (info)->output_section->vma; - highword = _bfinfdpic_osec_to_segment - (output_bfd, bfinfdpic_plt_section (info)->output_section); - } - else - { - /* A function descriptor for a local function gets the index - of the section. For a non-local function, it's - disregarded. */ - lowword = ad; - if (sec == NULL - || (entry->symndx == -1 && entry->d.h->dynindx != -1 - && entry->d.h->dynindx == idx)) - highword = 0; - else - highword = _bfinfdpic_osec_to_segment - (output_bfd, sec->output_section); - } - - bfd_put_32 (output_bfd, lowword, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry); - bfd_put_32 (output_bfd, highword, - bfinfdpic_got_section (info)->contents - + bfinfdpic_got_initial_offset (info) - + entry->fd_entry + 4); - } - - /* Generate code for the PLT entry. */ - if (entry->plt_entry != (bfd_vma) -1) - { - bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents - + entry->plt_entry; - - BFD_ASSERT (entry->fd_entry); - - /* Figure out what kind of PLT entry we need, depending on the - location of the function descriptor within the GOT. */ - if (entry->fd_entry >= -(1 << (18 - 1)) - && entry->fd_entry + 4 < (1 << (18 - 1))) - { - /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */ - bfd_put_32 (output_bfd, - 0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000), - plt_code); - bfd_put_32 (output_bfd, - 0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000), - plt_code + 4); - plt_code += 8; - } - else - { - /* P1.L = fd_entry; P1.H = fd_entry; - P3 = P3 + P1; - P1 = [P3]; - P3 = [P3 + 4]; */ - bfd_put_32 (output_bfd, - 0xe109 | (entry->fd_entry << 16), - plt_code); - bfd_put_32 (output_bfd, - 0xe149 | (entry->fd_entry & 0xFFFF0000), - plt_code + 4); - bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8); - bfd_put_16 (output_bfd, 0x9159, plt_code + 10); - bfd_put_16 (output_bfd, 0xac5b, plt_code + 12); - plt_code += 14; - } - /* JUMP (P1) */ - bfd_put_16 (output_bfd, 0x0051, plt_code); - } - - /* Generate code for the lazy PLT entry. */ - if (entry->lzplt_entry != (bfd_vma) -1) - { - bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents - + entry->lzplt_entry; - bfd_vma resolverStub_addr; - - bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code); - lzplt_code += 4; - - resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE - * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC; - if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info)) - resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA; - - if (entry->lzplt_entry == resolverStub_addr) - { - /* This is a lazy PLT entry that includes a resolver call. - P2 = [P3]; - R3 = [P3 + 4]; - JUMP (P2); */ - bfd_put_32 (output_bfd, - 0xa05b915a, - lzplt_code); - bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4); - } - else - { - /* JUMP.S resolverStub */ - bfd_put_16 (output_bfd, - 0x2000 - | (((resolverStub_addr - entry->lzplt_entry) - / 2) & (((bfd_vma)1 << 12) - 1)), - lzplt_code); - } - } - - return TRUE; -} - -/* Relocate an Blackfin ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -bfinfdpic_relocate_section (bfd * output_bfd, - struct bfd_link_info *info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - unsigned isec_segment, got_segment, plt_segment, - check_segment[2]; - int silence_segment_error = !bfd_link_pic (info); - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - isec_segment = _bfinfdpic_osec_to_segment (output_bfd, - input_section->output_section); - if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info)) - got_segment = _bfinfdpic_osec_to_segment (output_bfd, - bfinfdpic_got_section (info) - ->output_section); - else - got_segment = -1; - if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created) - plt_segment = _bfinfdpic_osec_to_segment (output_bfd, - bfinfdpic_plt_section (info) - ->output_section); - else - plt_segment = -1; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - asection *osec; - struct bfinfdpic_relocs_info *picrel; - bfd_vma orig_addend = rel->r_addend; - - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_BFIN_GNU_VTINHERIT - || r_type == R_BFIN_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - howto = bfin_reloc_type_lookup (input_bfd, r_type); - if (howto == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - osec = sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned, ignored; - bfd_boolean unresolved_reloc; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - osec = sec; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !BFINFDPIC_SYM_LOCAL (info, h)) - { - osec = sec = NULL; - relocation = 0; - } - - switch (r_type) - { - case R_BFIN_PCREL24: - case R_BFIN_PCREL24_JUMP_L: - case R_BFIN_BYTE4_DATA: - if (! IS_FDPIC (output_bfd)) - goto non_fdpic; - /* Fall through. */ - - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_GOTOFF17M4: - case R_BFIN_GOTOFFHI: - case R_BFIN_GOTOFFLO: - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - case R_BFIN_FUNCDESC: - case R_BFIN_FUNCDESC_VALUE: - if (h != NULL) - picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info - (info), input_bfd, h, - orig_addend, INSERT); - else - /* In order to find the entry we created before, we must - use the original addend, not the one that may have been - modified by _bfd_elf_rela_local_sym(). */ - picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info - (info), input_bfd, r_symndx, - orig_addend, INSERT); - if (! picrel) - return FALSE; - - if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info, - osec, sym, - rel->r_addend)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation at `%A+%#Lx' references symbol `%s' with nonzero addend"), - input_bfd, input_section, rel->r_offset, name); - return FALSE; - - } - - break; - - default: - non_fdpic: - picrel = NULL; - if (h && ! BFINFDPIC_SYM_LOCAL (info, h) - && _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - info->callbacks->warning - (info, _("relocation references symbol not defined in the module"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - break; - } - - switch (r_type) - { - case R_BFIN_PCREL24: - case R_BFIN_PCREL24_JUMP_L: - check_segment[0] = isec_segment; - if (! IS_FDPIC (output_bfd)) - check_segment[1] = isec_segment; - else if (picrel->plt) - { - relocation = bfinfdpic_plt_section (info)->output_section->vma - + bfinfdpic_plt_section (info)->output_offset - + picrel->plt_entry; - check_segment[1] = plt_segment; - } - /* We don't want to warn on calls to undefined weak symbols, - as calls to them must be protected by non-NULL tests - anyway, and unprotected calls would invoke undefined - behavior. */ - else if (picrel->symndx == -1 - && picrel->d.h->root.type == bfd_link_hash_undefweak) - check_segment[1] = check_segment[0]; - else - check_segment[1] = sec - ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - relocation = picrel->got_entry; - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - relocation = picrel->fdgot_entry; - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_BFIN_GOTOFFHI: - case R_BFIN_GOTOFF17M4: - case R_BFIN_GOTOFFLO: - relocation -= bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info); - check_segment[0] = got_segment; - check_segment[1] = sec - ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - relocation = picrel->fd_entry; - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_BFIN_FUNCDESC: - { - int dynindx; - bfd_vma addend = rel->r_addend; - - if (! (h && h->root.type == bfd_link_hash_undefweak - && BFINFDPIC_SYM_LOCAL (info, h))) - { - /* If the symbol is dynamic and there may be dynamic - symbol resolution because we are or are linked with a - shared library, emit a FUNCDESC relocation such that - the dynamic linker will allocate the function - descriptor. If the symbol needs a non-local function - descriptor but binds locally (e.g., its visibility is - protected, emit a dynamic relocation decayed to - section+offset. */ - if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h) - && BFINFDPIC_SYM_LOCAL (info, h) - && !bfd_link_pde (info)) - { - dynindx = elf_section_data (h->root.u.def.section - ->output_section)->dynindx; - addend += h->root.u.def.section->output_offset - + h->root.u.def.value; - } - else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)) - { - if (addend) - { - info->callbacks->warning - (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - dynindx = h->dynindx; - } - else - { - /* Otherwise, we know we have a private function - descriptor, so reference it directly. */ - BFD_ASSERT (picrel->privfd); - r_type = R_BFIN_BYTE4_DATA; - dynindx = elf_section_data (bfinfdpic_got_section (info) - ->output_section)->dynindx; - addend = bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info) - + picrel->fd_entry; - } - - /* If there is room for dynamic symbol resolution, emit - the dynamic relocation. However, if we're linking an - executable at a fixed location, we won't have emitted a - dynamic symbol entry for the got section, so idx will - be zero, which means we can and should compute the - address of the private descriptor ourselves. */ - if (bfd_link_pde (info) - && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h))) - { - bfd_vma offset; - - addend += bfinfdpic_got_section (info)->output_section->vma; - if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit fixups in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - - offset = _bfd_elf_section_offset - (output_bfd, info, - input_section, rel->r_offset); - - if (offset != (bfd_vma)-1) - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section - (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - picrel); - } - } - else if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma offset; - - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit dynamic relocations in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - offset = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - - if (offset != (bfd_vma)-1) - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - r_type, - dynindx, addend, picrel); - } - else - addend += bfinfdpic_got_section (info)->output_section->vma; - } - - /* We want the addend in-place because dynamic - relocations are REL. Setting relocation to it should - arrange for it to be installed. */ - relocation = addend - rel->r_addend; - } - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_BFIN_BYTE4_DATA: - if (! IS_FDPIC (output_bfd)) - { - check_segment[0] = check_segment[1] = -1; - break; - } - /* Fall through. */ - case R_BFIN_FUNCDESC_VALUE: - { - int dynindx; - bfd_vma addend = rel->r_addend; - bfd_vma offset; - offset = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (h && ! BFINFDPIC_SYM_LOCAL (info, h)) - { - if (addend && r_type == R_BFIN_FUNCDESC_VALUE) - { - info->callbacks->warning - (info, _("R_BFIN_FUNCDESC_VALUE references dynamic symbol with nonzero addend"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - dynindx = h->dynindx; - } - else - { - if (h) - addend += h->root.u.def.value; - else - addend += sym->st_value; - if (osec) - addend += osec->output_offset; - if (osec && osec->output_section - && ! bfd_is_abs_section (osec->output_section) - && ! bfd_is_und_section (osec->output_section)) - dynindx = elf_section_data (osec->output_section)->dynindx; - else - dynindx = 0; - } - - /* If we're linking an executable at a fixed address, we - can omit the dynamic relocation as long as the symbol - is defined in the current link unit (which is implied - by its output section not being NULL). */ - if (bfd_link_pde (info) - && (!h || BFINFDPIC_SYM_LOCAL (info, h))) - { - if (osec) - addend += osec->output_section->vma; - if (IS_FDPIC (input_bfd) - && (bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit fixups in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - if (!h || h->root.type != bfd_link_hash_undefweak) - { - if (offset != (bfd_vma)-1) - { - _bfinfdpic_add_rofixup (output_bfd, - bfinfdpic_gotfixup_section - (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - picrel); - - if (r_type == R_BFIN_FUNCDESC_VALUE) - _bfinfdpic_add_rofixup - (output_bfd, - bfinfdpic_gotfixup_section (info), - offset + input_section->output_section->vma - + input_section->output_offset + 4, picrel); - } - } - } - } - else - { - if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_bfinfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit dynamic relocations in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (offset != (bfd_vma)-1) - _bfinfdpic_add_dyn_reloc (output_bfd, - bfinfdpic_gotrel_section (info), - offset - + input_section->output_section->vma - + input_section->output_offset, - r_type, dynindx, addend, picrel); - } - else if (osec) - addend += osec->output_section->vma; - /* We want the addend in-place because dynamic - relocations are REL. Setting relocation to it - should arrange for it to be installed. */ - relocation = addend - rel->r_addend; - } - - if (r_type == R_BFIN_FUNCDESC_VALUE) - { - /* If we've omitted the dynamic relocation, just emit - the fixed addresses of the symbol and of the local - GOT base offset. */ - if (bfd_link_pde (info) - && (!h || BFINFDPIC_SYM_LOCAL (info, h))) - bfd_put_32 (output_bfd, - bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info), - contents + rel->r_offset + 4); - else - /* A function descriptor used for lazy or local - resolving is initialized such that its high word - contains the output section index in which the - PLT entries are located, and the low word - contains the offset of the lazy PLT entry entry - point into that section. */ - bfd_put_32 (output_bfd, - h && ! BFINFDPIC_SYM_LOCAL (info, h) - ? 0 - : _bfinfdpic_osec_to_segment (output_bfd, - sec - ->output_section), - contents + rel->r_offset + 4); - } - } - check_segment[0] = check_segment[1] = got_segment; - break; - - default: - check_segment[0] = isec_segment; - check_segment[1] = sec - ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - } - - if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd)) - { -#if 1 /* If you take this out, remove the #error from fdpic-static-6.d - in the ld testsuite. */ - /* This helps catch problems in GCC while we can't do more - than static linking. The idea is to test whether the - input file basename is crt0.o only once. */ - if (silence_segment_error == 1) - silence_segment_error = - (strlen (input_bfd->filename) == 6 - && filename_cmp (input_bfd->filename, "crt0.o") == 0) - || (strlen (input_bfd->filename) > 6 - && filename_cmp (input_bfd->filename - + strlen (input_bfd->filename) - 7, - "/crt0.o") == 0) - ? -1 : 0; -#endif - if (!silence_segment_error - /* We don't want duplicate errors for undefined - symbols. */ - && !(picrel && picrel->symndx == -1 - && picrel->d.h->root.type == bfd_link_hash_undefined)) - info->callbacks->warning - (info, - bfd_link_pic (info) - ? _("relocations between different segments are not supported") - : _("warning: relocation references a different segment"), - name, input_bfd, input_section, rel->r_offset); - if (!silence_segment_error && bfd_link_pic (info)) - return FALSE; - elf_elfheader (output_bfd)->e_flags |= EF_BFIN_PIC; - } - - switch (r_type) - { - case R_BFIN_GOTOFFHI: - /* We need the addend to be applied before we shift the - value right. */ - relocation += rel->r_addend; - /* Fall through. */ - case R_BFIN_GOTHI: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTOFFHI: - relocation >>= 16; - /* Fall through. */ - - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_GOTOFFLO: - case R_BFIN_FUNCDESC_GOTOFFLO: - relocation &= 0xffff; - break; - - default: - break; - } - - switch (r_type) - { - case R_BFIN_PCREL24: - case R_BFIN_PCREL24_JUMP_L: - if (! IS_FDPIC (output_bfd) || ! picrel->plt) - break; - /* Fall through. */ - - /* When referencing a GOT entry, a function descriptor or a - PLT, we don't want the addend to apply to the reference, - but rather to the referenced symbol. The actual entry - will have already been created taking the addend into - account, so cancel it out here. */ - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4 - here, since we do want to apply the addend to the others. - Note that we've applied the addend to GOTOFFHI before we - shifted it right. */ - case R_BFIN_GOTOFFHI: - relocation -= rel->r_addend; - break; - - default: - break; - } - - r = bfin_final_link_relocate (rel, howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* We need dynamic symbols for every section, since segments can - relocate independently. */ -static bfd_boolean -_bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - 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: - return FALSE; - - /* There shouldn't be section relative relocations - against any other section. */ - default: - return TRUE; - } -} - -/* Create a .got section, as well as its additional info field. This - is almost entirely copied from - elflink.c:_bfd_elf_create_got_section(). */ - -static bfd_boolean -_bfin_create_got_section (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags, pltflags; - 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 = elf_hash_table (info)->sgot; - if (s != NULL) - return TRUE; - - /* Machine specific: although pointers are 32-bits wide, we want the - GOT to be aligned to a 64-bit boundary, such that function - descriptors in it can be accessed with 64-bit loads and - stores. */ - ptralign = 3; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - pltflags = flags; - - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - elf_hash_table (info)->sgot = s; - 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; - - /* Machine-specific: we want the symbol for executables as - well. */ - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* The first bit of the global offset table is the header. */ - s->size += bed->got_header_size; - - /* This is the machine-specific part. Create and initialize section - data for the got. */ - if (IS_FDPIC (abfd)) - { - bfinfdpic_relocs_info (info) = htab_try_create (1, - bfinfdpic_relocs_info_hash, - bfinfdpic_relocs_info_eq, - (htab_del) NULL); - if (! bfinfdpic_relocs_info (info)) - return FALSE; - - s = bfd_make_section_anyway_with_flags (abfd, ".rel.got", - (flags | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - bfinfdpic_gotrel_section (info) = s; - - /* Machine-specific. */ - s = bfd_make_section_anyway_with_flags (abfd, ".rofixup", - (flags | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - bfinfdpic_gotfixup_section (info) = s; - } - - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - /* Blackfin-specific: remember it. */ - bfinfdpic_plt_section (info) = s; - - if (bed->want_plt_sym) - { - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - struct bfd_link_hash_entry *bh = NULL; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "__PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, 0, NULL, - FALSE, get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - - if (! bfd_link_executable (info) - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* Blackfin-specific: we want rel relocations for the plt. */ - s = bfd_make_section_anyway_with_flags (abfd, ".rel.plt", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - /* Blackfin-specific: remember it. */ - bfinfdpic_pltrel_section (info) = s; - - return TRUE; -} - -/* Make sure the got and plt sections exist, and that our pointers in - the link hash table point to them. */ - -static bfd_boolean -elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - /* This is mostly copied from - elflink.c:_bfd_elf_create_dynamic_sections(). */ - flagword flags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - - /* Blackfin-specific: we want to create the GOT in the Blackfin way. */ - if (! _bfin_create_got_section (abfd, info)) - return FALSE; - - /* Blackfin-specific: make sure we created everything we wanted. */ - BFD_ASSERT (bfinfdpic_got_section (info) && bfinfdpic_gotrel_section (info) - /* && bfinfdpic_gotfixup_section (info) */ - && bfinfdpic_plt_section (info) - && bfinfdpic_pltrel_section (info)); - - 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_anyway_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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - ".rela.bss", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - } - } - - return TRUE; -} - -/* Compute the total GOT size required by each symbol in each range. - Symbols may require up to 4 words in the GOT: an entry pointing to - the symbol, an entry pointing to its function descriptor, and a - private function descriptors taking two words. */ - -static void -_bfinfdpic_count_nontls_entries (struct bfinfdpic_relocs_info *entry, - struct _bfinfdpic_dynamic_got_info *dinfo) -{ - /* Allocate space for a GOT entry pointing to the symbol. */ - if (entry->got17m4) - dinfo->got17m4 += 4; - else if (entry->gothilo) - dinfo->gothilo += 4; - else - entry->relocs32--; - entry->relocs32++; - - /* Allocate space for a GOT entry pointing to the function - descriptor. */ - if (entry->fdgot17m4) - dinfo->got17m4 += 4; - else if (entry->fdgothilo) - dinfo->gothilo += 4; - else - entry->relocsfd--; - entry->relocsfd++; - - /* Decide whether we need a PLT entry, a function descriptor in the - GOT, and a lazy PLT entry for this symbol. */ - entry->plt = entry->call - && entry->symndx == -1 && ! BFINFDPIC_SYM_LOCAL (dinfo->info, entry->d.h) - && elf_hash_table (dinfo->info)->dynamic_sections_created; - entry->privfd = entry->plt - || entry->fdgoff17m4 || entry->fdgoffhilo - || ((entry->fd || entry->fdgot17m4 || entry->fdgothilo) - && (entry->symndx != -1 - || BFINFDPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h))); - entry->lazyplt = entry->privfd - && entry->symndx == -1 && ! BFINFDPIC_SYM_LOCAL (dinfo->info, entry->d.h) - && ! (dinfo->info->flags & DF_BIND_NOW) - && elf_hash_table (dinfo->info)->dynamic_sections_created; - - /* Allocate space for a function descriptor. */ - if (entry->fdgoff17m4) - dinfo->fd17m4 += 8; - else if (entry->privfd && entry->plt) - dinfo->fdplt += 8; - else if (entry->privfd) - dinfo->fdhilo += 8; - else - entry->relocsfdv--; - entry->relocsfdv++; - - if (entry->lazyplt) - dinfo->lzplt += LZPLT_NORMAL_SIZE; -} - -/* Compute the number of dynamic relocations and fixups that a symbol - requires, and add (or subtract) from the grand and per-symbol - totals. */ - -static void -_bfinfdpic_count_relocs_fixups (struct bfinfdpic_relocs_info *entry, - struct _bfinfdpic_dynamic_got_info *dinfo, - bfd_boolean subtract) -{ - bfd_vma relocs = 0, fixups = 0; - - if (!bfd_link_pde (dinfo->info)) - relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv; - else - { - if (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (dinfo->info, entry->d.h)) - { - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - fixups += entry->relocs32 + 2 * entry->relocsfdv; - } - else - relocs += entry->relocs32 + entry->relocsfdv; - - if (entry->symndx != -1 - || BFINFDPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h)) - { - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - fixups += entry->relocsfd; - } - else - relocs += entry->relocsfd; - } - - if (subtract) - { - relocs = - relocs; - fixups = - fixups; - } - - entry->dynrelocs += relocs; - entry->fixups += fixups; - dinfo->relocs += relocs; - dinfo->fixups += fixups; -} - -/* Compute the total GOT and PLT size required by each symbol in each range. * - Symbols may require up to 4 words in the GOT: an entry pointing to - the symbol, an entry pointing to its function descriptor, and a - private function descriptors taking two words. */ - -static int -_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_) -{ - struct bfinfdpic_relocs_info *entry = *entryp; - struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_; - - _bfinfdpic_count_nontls_entries (entry, dinfo); - - _bfinfdpic_count_relocs_fixups (entry, dinfo, FALSE); - - return 1; -} - -/* This structure is used to assign offsets to got entries, function - descriptors, plt entries and lazy plt entries. */ - -struct _bfinfdpic_dynamic_got_plt_info -{ - /* Summary information collected with _bfinfdpic_count_got_plt_entries. */ - struct _bfinfdpic_dynamic_got_info g; - - /* For each addressable range, we record a MAX (positive) and MIN - (negative) value. CUR is used to assign got entries, and it's - incremented from an initial positive value to MAX, then from MIN - to FDCUR (unless FDCUR wraps around first). FDCUR is used to - assign function descriptors, and it's decreased from an initial - non-positive value to MIN, then from MAX down to CUR (unless CUR - wraps around first). All of MIN, MAX, CUR and FDCUR always point - to even words. ODD, if non-zero, indicates an odd word to be - used for the next got entry, otherwise CUR is used and - incremented by a pair of words, wrapping around when it reaches - MAX. FDCUR is decremented (and wrapped) before the next function - descriptor is chosen. FDPLT indicates the number of remaining - slots that can be used for function descriptors used only by PLT - entries. */ - struct _bfinfdpic_dynamic_got_alloc_data - { - bfd_signed_vma max, cur, odd, fdcur, min; - bfd_vma fdplt; - } got17m4, gothilo; -}; - -/* Determine the positive and negative ranges to be used by each - offset range in the GOT. FDCUR and CUR, that must be aligned to a - double-word boundary, are the minimum (negative) and maximum - (positive) GOT offsets already used by previous ranges, except for - an ODD entry that may have been left behind. GOT and FD indicate - the size of GOT entries and function descriptors that must be - placed within the range from -WRAP to WRAP. If there's room left, - up to FDPLT bytes should be reserved for additional function - descriptors. */ - -inline static bfd_signed_vma -_bfinfdpic_compute_got_alloc_data (struct _bfinfdpic_dynamic_got_alloc_data *gad, - bfd_signed_vma fdcur, - bfd_signed_vma odd, - bfd_signed_vma cur, - bfd_vma got, - bfd_vma fd, - bfd_vma fdplt, - bfd_vma wrap) -{ - bfd_signed_vma wrapmin = -wrap; - - /* Start at the given initial points. */ - gad->fdcur = fdcur; - gad->cur = cur; - - /* If we had an incoming odd word and we have any got entries that - are going to use it, consume it, otherwise leave gad->odd at - zero. We might force gad->odd to zero and return the incoming - odd such that it is used by the next range, but then GOT entries - might appear to be out of order and we wouldn't be able to - shorten the GOT by one word if it turns out to end with an - unpaired GOT entry. */ - if (odd && got) - { - gad->odd = odd; - got -= 4; - odd = 0; - } - else - gad->odd = 0; - - /* If we're left with an unpaired GOT entry, compute its location - such that we can return it. Otherwise, if got doesn't require an - odd number of words here, either odd was already zero in the - block above, or it was set to zero because got was non-zero, or - got was already zero. In the latter case, we want the value of - odd to carry over to the return statement, so we don't want to - reset odd unless the condition below is true. */ - if (got & 4) - { - odd = cur + got; - got += 4; - } - - /* Compute the tentative boundaries of this range. */ - gad->max = cur + got; - gad->min = fdcur - fd; - gad->fdplt = 0; - - /* If function descriptors took too much space, wrap some of them - around. */ - if (gad->min < wrapmin) - { - gad->max += wrapmin - gad->min; - gad->min = wrapmin; - } - /* If there is space left and we have function descriptors - referenced in PLT entries that could take advantage of shorter - offsets, place them here. */ - else if (fdplt && gad->min > wrapmin) - { - bfd_vma fds; - if ((bfd_vma) (gad->min - wrapmin) < fdplt) - fds = gad->min - wrapmin; - else - fds = fdplt; - - fdplt -= fds; - gad->min -= fds; - gad->fdplt += fds; - } - - /* If GOT entries took too much space, wrap some of them around. - This may well cause gad->min to become lower than wrapmin. This - will cause a relocation overflow later on, so we don't have to - report it here . */ - if ((bfd_vma) gad->max > wrap) - { - gad->min -= gad->max - wrap; - gad->max = wrap; - } - /* If there is more space left, try to place some more function - descriptors for PLT entries. */ - else if (fdplt && (bfd_vma) gad->max < wrap) - { - bfd_vma fds; - if ((bfd_vma) (wrap - gad->max) < fdplt) - fds = wrap - gad->max; - else - fds = fdplt; - - fdplt -= fds; - gad->max += fds; - gad->fdplt += fds; - } - - /* If odd was initially computed as an offset past the wrap point, - wrap it around. */ - if (odd > gad->max) - odd = gad->min + odd - gad->max; - - /* _bfinfdpic_get_got_entry() below will always wrap gad->cur if needed - before returning, so do it here too. This guarantees that, - should cur and fdcur meet at the wrap point, they'll both be - equal to min. */ - if (gad->cur == gad->max) - gad->cur = gad->min; - - return odd; -} - -/* Compute the location of the next GOT entry, given the allocation - data for a range. */ - -inline static bfd_signed_vma -_bfinfdpic_get_got_entry (struct _bfinfdpic_dynamic_got_alloc_data *gad) -{ - bfd_signed_vma ret; - - if (gad->odd) - { - /* If there was an odd word left behind, use it. */ - ret = gad->odd; - gad->odd = 0; - } - else - { - /* Otherwise, use the word pointed to by cur, reserve the next - as an odd word, and skip to the next pair of words, possibly - wrapping around. */ - ret = gad->cur; - gad->odd = gad->cur + 4; - gad->cur += 8; - if (gad->cur == gad->max) - gad->cur = gad->min; - } - - return ret; -} - -/* Compute the location of the next function descriptor entry in the - GOT, given the allocation data for a range. */ - -inline static bfd_signed_vma -_bfinfdpic_get_fd_entry (struct _bfinfdpic_dynamic_got_alloc_data *gad) -{ - /* If we're at the bottom, wrap around, and only then allocate the - next pair of words. */ - if (gad->fdcur == gad->min) - gad->fdcur = gad->max; - return gad->fdcur -= 8; -} - -/* Assign GOT offsets for every GOT entry and function descriptor. - Doing everything in a single pass is tricky. */ - -static int -_bfinfdpic_assign_got_entries (void **entryp, void *info_) -{ - struct bfinfdpic_relocs_info *entry = *entryp; - struct _bfinfdpic_dynamic_got_plt_info *dinfo = info_; - - if (entry->got17m4) - entry->got_entry = _bfinfdpic_get_got_entry (&dinfo->got17m4); - else if (entry->gothilo) - entry->got_entry = _bfinfdpic_get_got_entry (&dinfo->gothilo); - - if (entry->fdgot17m4) - entry->fdgot_entry = _bfinfdpic_get_got_entry (&dinfo->got17m4); - else if (entry->fdgothilo) - entry->fdgot_entry = _bfinfdpic_get_got_entry (&dinfo->gothilo); - - if (entry->fdgoff17m4) - entry->fd_entry = _bfinfdpic_get_fd_entry (&dinfo->got17m4); - else if (entry->plt && dinfo->got17m4.fdplt) - { - dinfo->got17m4.fdplt -= 8; - entry->fd_entry = _bfinfdpic_get_fd_entry (&dinfo->got17m4); - } - else if (entry->plt) - { - dinfo->gothilo.fdplt -= 8; - entry->fd_entry = _bfinfdpic_get_fd_entry (&dinfo->gothilo); - } - else if (entry->privfd) - entry->fd_entry = _bfinfdpic_get_fd_entry (&dinfo->gothilo); - - return 1; -} - -/* Assign GOT offsets to private function descriptors used by PLT - entries (or referenced by 32-bit offsets), as well as PLT entries - and lazy PLT entries. */ - -static int -_bfinfdpic_assign_plt_entries (void **entryp, void *info_) -{ - struct bfinfdpic_relocs_info *entry = *entryp; - struct _bfinfdpic_dynamic_got_plt_info *dinfo = info_; - - /* If this symbol requires a local function descriptor, allocate - one. */ - if (entry->privfd && entry->fd_entry == 0) - { - if (dinfo->got17m4.fdplt) - { - entry->fd_entry = _bfinfdpic_get_fd_entry (&dinfo->got17m4); - dinfo->got17m4.fdplt -= 8; - } - else - { - BFD_ASSERT (dinfo->gothilo.fdplt); - entry->fd_entry = _bfinfdpic_get_fd_entry (&dinfo->gothilo); - dinfo->gothilo.fdplt -= 8; - } - } - - if (entry->plt) - { - int size; - - /* We use the section's raw size to mark the location of the - next PLT entry. */ - entry->plt_entry = bfinfdpic_plt_section (dinfo->g.info)->size; - - /* Figure out the length of this PLT entry based on the - addressing mode we need to reach the function descriptor. */ - BFD_ASSERT (entry->fd_entry); - if (entry->fd_entry >= -(1 << (18 - 1)) - && entry->fd_entry + 4 < (1 << (18 - 1))) - size = 10; - else - size = 16; - - bfinfdpic_plt_section (dinfo->g.info)->size += size; - } - - if (entry->lazyplt) - { - entry->lzplt_entry = dinfo->g.lzplt; - dinfo->g.lzplt += LZPLT_NORMAL_SIZE; - /* If this entry is the one that gets the resolver stub, account - for the additional instruction. */ - if (entry->lzplt_entry % BFINFDPIC_LZPLT_BLOCK_SIZE - == BFINFDPIC_LZPLT_RESOLV_LOC) - dinfo->g.lzplt += LZPLT_RESOLVER_EXTRA; - } - - return 1; -} - -/* Cancel out any effects of calling _bfinfdpic_assign_got_entries and - _bfinfdpic_assign_plt_entries. */ - -static int -_bfinfdpic_reset_got_plt_entries (void **entryp, void *ignore ATTRIBUTE_UNUSED) -{ - struct bfinfdpic_relocs_info *entry = *entryp; - - entry->got_entry = 0; - entry->fdgot_entry = 0; - entry->fd_entry = 0; - entry->plt_entry = (bfd_vma)-1; - entry->lzplt_entry = (bfd_vma)-1; - - return 1; -} - -/* Follow indirect and warning hash entries so that each got entry - points to the final symbol definition. P must point to a pointer - to the hash table we're traversing. Since this traversal may - modify the hash table, we set this pointer to NULL to indicate - we've made a potentially-destructive change to the hash table, so - the traversal must be restarted. */ -static int -_bfinfdpic_resolve_final_relocs_info (void **entryp, void *p) -{ - struct bfinfdpic_relocs_info *entry = *entryp; - htab_t *htab = p; - - if (entry->symndx == -1) - { - struct elf_link_hash_entry *h = entry->d.h; - struct bfinfdpic_relocs_info *oentry; - - 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 (entry->d.h == h) - return 1; - - oentry = bfinfdpic_relocs_info_for_global (*htab, 0, h, entry->addend, - NO_INSERT); - - if (oentry) - { - /* Merge the two entries. */ - bfinfdpic_pic_merge_early_relocs_info (oentry, entry); - htab_clear_slot (*htab, entryp); - return 1; - } - - entry->d.h = h; - - /* If we can't find this entry with the new bfd hash, re-insert - it, and get the traversal restarted. */ - if (! htab_find (*htab, entry)) - { - htab_clear_slot (*htab, entryp); - entryp = htab_find_slot (*htab, entry, INSERT); - if (! *entryp) - *entryp = entry; - /* Abort the traversal, since the whole table may have - moved, and leave it up to the parent to restart the - process. */ - *(htab_t *)p = NULL; - return 0; - } - } - - return 1; -} - -/* Compute the total size of the GOT, the PLT, the dynamic relocations - section and the rofixup section. Assign locations for GOT and PLT - entries. */ - -static bfd_boolean -_bfinfdpic_size_got_plt (bfd *output_bfd, - struct _bfinfdpic_dynamic_got_plt_info *gpinfop) -{ - bfd_signed_vma odd; - bfd_vma limit; - struct bfd_link_info *info = gpinfop->g.info; - bfd *dynobj = elf_hash_table (info)->dynobj; - - memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g, - sizeof (gpinfop->g)); - - odd = 12; - /* Compute the total size taken by entries in the 18-bit range, - to tell how many PLT function descriptors we can bring into it - without causing it to overflow. */ - limit = odd + gpinfop->g.got17m4 + gpinfop->g.fd17m4; - if (limit < (bfd_vma)1 << 18) - limit = ((bfd_vma)1 << 18) - limit; - else - limit = 0; - if (gpinfop->g.fdplt < limit) - limit = gpinfop->g.fdplt; - - /* Determine the ranges of GOT offsets that we can use for each - range of addressing modes. */ - odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4, - 0, - odd, - 16, - gpinfop->g.got17m4, - gpinfop->g.fd17m4, - limit, - (bfd_vma)1 << (18-1)); - odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo, - gpinfop->got17m4.min, - odd, - gpinfop->got17m4.max, - gpinfop->g.gothilo, - gpinfop->g.fdhilo, - gpinfop->g.fdplt - gpinfop->got17m4.fdplt, - (bfd_vma)1 << (32-1)); - - /* Now assign (most) GOT offsets. */ - htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries, - gpinfop); - - bfinfdpic_got_section (info)->size = gpinfop->gothilo.max - - gpinfop->gothilo.min - /* If an odd word is the last word of the GOT, we don't need this - word to be part of the GOT. */ - - (odd + 4 == gpinfop->gothilo.max ? 4 : 0); - if (bfinfdpic_got_section (info)->size == 0) - bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE; - else if (bfinfdpic_got_section (info)->size == 12 - && ! elf_hash_table (info)->dynamic_sections_created) - { - bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE; - bfinfdpic_got_section (info)->size = 0; - } - else - { - bfinfdpic_got_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_got_section (info)->size); - if (bfinfdpic_got_section (info)->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - /* Subtract the number of lzplt entries, since those will generate - relocations in the pltrel section. */ - bfinfdpic_gotrel_section (info)->size = - (gpinfop->g.relocs - gpinfop->g.lzplt / LZPLT_NORMAL_SIZE) - * get_elf_backend_data (output_bfd)->s->sizeof_rel; - else - BFD_ASSERT (gpinfop->g.relocs == 0); - if (bfinfdpic_gotrel_section (info)->size == 0) - bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE; - else - { - bfinfdpic_gotrel_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_gotrel_section (info)->size); - if (bfinfdpic_gotrel_section (info)->contents == NULL) - return FALSE; - } - - bfinfdpic_gotfixup_section (info)->size = (gpinfop->g.fixups + 1) * 4; - if (bfinfdpic_gotfixup_section (info)->size == 0) - bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE; - else - { - bfinfdpic_gotfixup_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_gotfixup_section (info)->size); - if (bfinfdpic_gotfixup_section (info)->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - bfinfdpic_pltrel_section (info)->size = - gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel; - if (bfinfdpic_pltrel_section (info)->size == 0) - bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE; - else - { - bfinfdpic_pltrel_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_pltrel_section (info)->size); - if (bfinfdpic_pltrel_section (info)->contents == NULL) - return FALSE; - } - - /* Add 4 bytes for every block of at most 65535 lazy PLT entries, - such that there's room for the additional instruction needed to - call the resolver. Since _bfinfdpic_assign_got_entries didn't - account for them, our block size is 4 bytes smaller than the real - block size. */ - if (elf_hash_table (info)->dynamic_sections_created) - { - bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt - + ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE) - / (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA); - } - - /* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to - actually assign lazy PLT entries addresses. */ - gpinfop->g.lzplt = 0; - - /* Save information that we're going to need to generate GOT and PLT - entries. */ - bfinfdpic_got_initial_offset (info) = -gpinfop->gothilo.min; - - if (get_elf_backend_data (output_bfd)->want_got_sym) - elf_hash_table (info)->hgot->root.u.def.value - = bfinfdpic_got_initial_offset (info); - - if (elf_hash_table (info)->dynamic_sections_created) - bfinfdpic_plt_initial_offset (info) = - bfinfdpic_plt_section (info)->size; - - htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries, - gpinfop); - - /* Allocate the PLT section contents only after - _bfinfdpic_assign_plt_entries has a chance to add the size of the - non-lazy PLT entries. */ - if (bfinfdpic_plt_section (info)->size == 0) - bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE; - else - { - bfinfdpic_plt_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - bfinfdpic_plt_section (info)->size); - if (bfinfdpic_plt_section (info)->contents == NULL) - return FALSE; - } - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_link_hash_table *htab; - bfd *dynobj; - asection *s; - struct _bfinfdpic_dynamic_got_plt_info gpinfo; - - htab = elf_hash_table (info); - dynobj = htab->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; - } - } - - memset (&gpinfo, 0, sizeof (gpinfo)); - gpinfo.g.info = info; - - for (;;) - { - htab_t relocs = bfinfdpic_relocs_info (info); - - htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs); - - if (relocs == bfinfdpic_relocs_info (info)) - break; - } - - htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries, - &gpinfo.g); - - /* Allocate space to save the summary information, we're going to - use it if we're doing relaxations. */ - bfinfdpic_dynamic_got_plt_info (info) = bfd_alloc (dynobj, sizeof (gpinfo.g)); - - if (!_bfinfdpic_size_got_plt (output_bfd, &gpinfo)) - return FALSE; - - if (elf_hash_table (info)->dynamic_sections_created) - { - if (bfinfdpic_got_section (info)->size) - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0)) - return FALSE; - - if (bfinfdpic_pltrel_section (info)->size) - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_REL) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) - return FALSE; - - if (bfinfdpic_gotrel_section (info)->size) - if (!_bfd_elf_add_dynamic_entry (info, DT_REL, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELENT, - sizeof (Elf32_External_Rel))) - return FALSE; - } - - s = bfd_get_linker_section (dynobj, ".dynbss"); - if (s && s->size == 0) - s->flags |= SEC_EXCLUDE; - - s = bfd_get_linker_section (dynobj, ".rela.bss"); - if (s && s->size == 0) - s->flags |= SEC_EXCLUDE; - - return TRUE; -} - -static bfd_boolean -elf32_bfinfdpic_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - if (!bfd_link_relocatable (info) - && !bfd_elf_stack_segment_size (output_bfd, info, - "__stacksize", DEFAULT_STACK_SIZE)) - return FALSE; - - return TRUE; -} - -/* Check whether any of the relocations was optimized away, and - subtract it from the relocation or fixup count. */ -static bfd_boolean -_bfinfdpic_check_discarded_relocs (bfd *abfd, asection *sec, - struct bfd_link_info *info, - bfd_boolean *changed) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; - Elf_Internal_Rela *rel, *erel; - - if ((sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym); - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; - - rel = elf_section_data (sec)->relocs; - - /* Now examine each relocation. */ - for (erel = rel + sec->reloc_count; rel < erel; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - struct bfinfdpic_relocs_info *picrel; - struct _bfinfdpic_dynamic_got_info *dinfo; - - if (ELF32_R_TYPE (rel->r_info) != R_BFIN_BYTE4_DATA - && ELF32_R_TYPE (rel->r_info) != R_BFIN_FUNCDESC) - continue; - - if (_bfd_elf_section_offset (sec->output_section->owner, - info, sec, rel->r_offset) - != (bfd_vma)-1) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *)h->root.u.i.link; - } - - if (h != NULL) - picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info), - abfd, h, - rel->r_addend, NO_INSERT); - else - picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info (info), - abfd, r_symndx, - rel->r_addend, NO_INSERT); - - if (! picrel) - return FALSE; - - *changed = TRUE; - dinfo = bfinfdpic_dynamic_got_plt_info (info); - - _bfinfdpic_count_relocs_fixups (picrel, dinfo, TRUE); - if (ELF32_R_TYPE (rel->r_info) == R_BFIN_BYTE4_DATA) - picrel->relocs32--; - else /* we know (ELF32_R_TYPE (rel->r_info) == R_BFIN_FUNCDESC) */ - picrel->relocsfd--; - _bfinfdpic_count_relocs_fixups (picrel, dinfo, FALSE); - } - - return TRUE; -} - -static bfd_boolean -bfinfdpic_elf_discard_info (bfd *ibfd, - struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd_boolean changed = FALSE; - asection *s; - bfd *obfd = NULL; - - /* Account for relaxation of .eh_frame section. */ - for (s = ibfd->sections; s; s = s->next) - if (s->sec_info_type == SEC_INFO_TYPE_EH_FRAME) - { - if (!_bfinfdpic_check_discarded_relocs (ibfd, s, info, &changed)) - return FALSE; - obfd = s->output_section->owner; - } - - if (changed) - { - struct _bfinfdpic_dynamic_got_plt_info gpinfo; - - memset (&gpinfo, 0, sizeof (gpinfo)); - memcpy (&gpinfo.g, bfinfdpic_dynamic_got_plt_info (info), - sizeof (gpinfo.g)); - - /* Clear GOT and PLT assignments. */ - htab_traverse (bfinfdpic_relocs_info (info), - _bfinfdpic_reset_got_plt_entries, - NULL); - - if (!_bfinfdpic_size_got_plt (obfd, &gpinfo)) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -elf32_bfinfdpic_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - if (bfinfdpic_got_section (info)) - { - BFD_ASSERT (bfinfdpic_gotrel_section (info)->size - /* PR 17334: It appears that the GOT section can end up - being bigger than the number of relocs. Presumably - because some relocs have been deleted. A test case has - yet to be generated for verify this, but in the meantime - the test below has been changed from == to >= so that - applications can continue to be built. */ - >= (bfinfdpic_gotrel_section (info)->reloc_count - * sizeof (Elf32_External_Rel))); - - if (bfinfdpic_gotfixup_section (info)) - { - struct elf_link_hash_entry *hgot = elf_hash_table (info)->hgot; - bfd_vma got_value = hgot->root.u.def.value - + hgot->root.u.def.section->output_section->vma - + hgot->root.u.def.section->output_offset; - - _bfinfdpic_add_rofixup (output_bfd, bfinfdpic_gotfixup_section (info), - got_value, 0); - - if (bfinfdpic_gotfixup_section (info)->size - != (bfinfdpic_gotfixup_section (info)->reloc_count * 4)) - { - _bfd_error_handler - ("LINKER BUG: .rofixup section size mismatch"); - return FALSE; - } - } - } - if (elf_hash_table (info)->dynamic_sections_created) - { - BFD_ASSERT (bfinfdpic_pltrel_section (info)->size - == (bfinfdpic_pltrel_section (info)->reloc_count - * sizeof (Elf32_External_Rel))); - } - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf32_External_Dyn * dyncon; - Elf32_External_Dyn * dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - dyn.d_un.d_ptr = bfinfdpic_got_section (info)->output_section->vma - + bfinfdpic_got_section (info)->output_offset - + bfinfdpic_got_initial_offset (info); - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - dyn.d_un.d_ptr = bfinfdpic_pltrel_section (info) - ->output_section->vma - + bfinfdpic_pltrel_section (info)->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = bfinfdpic_pltrel_section (info)->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - } - - return TRUE; -} - -/* Adjust a symbol defined by a dynamic object and referenced by a - regular object. */ - -static bfd_boolean -elf32_bfinfdpic_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd * dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - } - - return TRUE; -} - -/* Perform any actions needed for dynamic symbols. */ - -static bfd_boolean -elf32_bfinfdpic_finish_dynamic_symbol -(bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Decide whether to attempt to turn absptr or lsda encodings in - shared libraries into pcrel within the given input section. */ - -static bfd_boolean -bfinfdpic_elf_use_relative_eh_frame -(bfd *input_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *eh_frame_section ATTRIBUTE_UNUSED) -{ - /* We can't use PC-relative encodings in FDPIC binaries, in general. */ - return FALSE; -} - -/* Adjust the contents of an eh_frame_hdr section before they're output. */ - -static bfd_byte -bfinfdpic_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) -{ - struct elf_link_hash_entry *h; - - h = elf_hash_table (info)->hgot; - BFD_ASSERT (h && h->root.type == bfd_link_hash_defined); - - if (! h || (_bfinfdpic_osec_to_segment (abfd, osec) - == _bfinfdpic_osec_to_segment (abfd, loc_sec->output_section))) - return _bfd_elf_encode_eh_address (abfd, info, osec, offset, - loc_sec, loc_offset, encoded); - - BFD_ASSERT (_bfinfdpic_osec_to_segment (abfd, osec) - == (_bfinfdpic_osec_to_segment - (abfd, h->root.u.def.section->output_section))); - - *encoded = osec->vma + offset - - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - return DW_EH_PE_datarel | DW_EH_PE_sdata4; -} - - - -/* Look through the relocs for a section during the first phase. - - Besides handling virtual table relocs for gc, we have to deal with - all sorts of PIC-related relocations. We describe below the - general plan on how to handle such relocations, even though we only - collect information at this point, storing them in hash tables for - perusal of later passes. - - 32 relocations are propagated to the linker output when creating - position-independent output. LO16 and HI16 relocations are not - supposed to be encountered in this case. - - LABEL16 should always be resolvable by the linker, since it's only - used by branches. - - LABEL24, on the other hand, is used by calls. If it turns out that - the target of a call is a dynamic symbol, a PLT entry must be - created for it, which triggers the creation of a private function - descriptor and, unless lazy binding is disabled, a lazy PLT entry. - - GPREL relocations require the referenced symbol to be in the same - segment as _gp, but this can only be checked later. - - All GOT, GOTOFF and FUNCDESC relocations require a .got section to - exist. LABEL24 might as well, since it may require a PLT entry, - that will require a got. - - Non-FUNCDESC GOT relocations require a GOT entry to be created - regardless of whether the symbol is dynamic. However, since a - global symbol that turns out to not be exported may have the same - address of a non-dynamic symbol, we don't assign GOT entries at - this point, such that we can share them in this case. A relocation - for the GOT entry always has to be created, be it to offset a - private symbol by the section load address, be it to get the symbol - resolved dynamically. - - FUNCDESC GOT relocations require a GOT entry to be created, and - handled as if a FUNCDESC relocation was applied to the GOT entry in - an object file. - - FUNCDESC relocations referencing a symbol that turns out to NOT be - dynamic cause a private function descriptor to be created. The - FUNCDESC relocation then decays to a 32 relocation that points at - the private descriptor. If the symbol is dynamic, the FUNCDESC - relocation is propagated to the linker output, such that the - dynamic linker creates the canonical descriptor, pointing to the - dynamically-resolved definition of the function. - - Non-FUNCDESC GOTOFF relocations must always refer to non-dynamic - symbols that are assigned to the same segment as the GOT, but we - can only check this later, after we know the complete set of - symbols defined and/or exported. - - FUNCDESC GOTOFF relocations require a function descriptor to be - created and, unless lazy binding is disabled or the symbol is not - dynamic, a lazy PLT entry. Since we can't tell at this point - whether a symbol is going to be dynamic, we have to decide later - whether to create a lazy PLT entry or bind the descriptor directly - to the private function. - - FUNCDESC_VALUE relocations are not supposed to be present in object - files, but they may very well be simply propagated to the linker - output, since they have no side effect. - - - A function descriptor always requires a FUNCDESC_VALUE relocation. - Whether it's in .plt.rel or not depends on whether lazy binding is - enabled and on whether the referenced symbol is dynamic. - - The existence of a lazy PLT requires the resolverStub lazy PLT - entry to be present. - - - As for assignment of GOT, PLT and lazy PLT entries, and private - descriptors, we might do them all sequentially, but we can do - better than that. For example, we can place GOT entries and - private function descriptors referenced using 12-bit operands - closer to the PIC register value, such that these relocations don't - overflow. Those that are only referenced with LO16 relocations - could come next, but we may as well place PLT-required function - descriptors in the 12-bit range to make them shorter. Symbols - referenced with LO16/HI16 may come next, but we may place - additional function descriptors in the 16-bit range if we can - reliably tell that we've already placed entries that are ever - referenced with only LO16. PLT entries are therefore generated as - small as possible, while not introducing relocation overflows in - GOT or FUNCDESC_GOTOFF relocations. Lazy PLT entries could be - generated before or after PLT entries, but not intermingled with - them, such that we can have more lazy PLT entries in range for a - branch to the resolverStub. The resolverStub should be emitted at - the most distant location from the first lazy PLT entry such that - it's still in range for a branch, or closer, if there isn't a need - for so many lazy PLT entries. Additional lazy PLT entries may be - emitted after the resolverStub, as long as branches are still in - range. If the branch goes out of range, longer lazy PLT entries - are emitted. - - We could further optimize PLT and lazy PLT entries by giving them - priority in assignment to closer-to-gr17 locations depending on the - number of occurrences of references to them (assuming a function - that's called more often is more important for performance, so its - PLT entry should be faster), or taking hints from the compiler. - Given infinite time and money... :-) */ - -static bfd_boolean -bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd *dynobj; - struct bfinfdpic_relocs_info *picrel; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - dynobj = elf_hash_table (info)->dynobj; - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_BFIN_GOT17M4: - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - case R_BFIN_FUNCDESC_GOT17M4: - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - case R_BFIN_GOTOFF17M4: - case R_BFIN_GOTOFFHI: - case R_BFIN_GOTOFFLO: - case R_BFIN_FUNCDESC_GOTOFF17M4: - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - case R_BFIN_FUNCDESC: - case R_BFIN_FUNCDESC_VALUE: - if (! IS_FDPIC (abfd)) - goto bad_reloc; - /* Fall through. */ - case R_BFIN_PCREL24: - case R_BFIN_PCREL24_JUMP_L: - case R_BFIN_BYTE4_DATA: - if (IS_FDPIC (abfd) && ! dynobj) - { - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! _bfin_create_got_section (abfd, info)) - return FALSE; - } - if (! IS_FDPIC (abfd)) - { - picrel = NULL; - break; - } - if (h != NULL) - { - if (h->dynindx == -1) - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - break; - default: - bfd_elf_link_record_dynamic_symbol (info, h); - break; - } - picrel - = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info), - abfd, h, - rel->r_addend, INSERT); - } - else - picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info - (info), abfd, r_symndx, - rel->r_addend, INSERT); - if (! picrel) - return FALSE; - break; - - default: - picrel = NULL; - break; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_BFIN_PCREL24: - case R_BFIN_PCREL24_JUMP_L: - if (IS_FDPIC (abfd)) - picrel->call++; - break; - - case R_BFIN_FUNCDESC_VALUE: - picrel->relocsfdv++; - if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) - picrel->relocs32--; - /* Fall through. */ - - case R_BFIN_BYTE4_DATA: - if (! IS_FDPIC (abfd)) - break; - - picrel->sym++; - if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) - picrel->relocs32++; - break; - - case R_BFIN_GOT17M4: - picrel->got17m4++; - break; - - case R_BFIN_GOTHI: - case R_BFIN_GOTLO: - picrel->gothilo++; - break; - - case R_BFIN_FUNCDESC_GOT17M4: - picrel->fdgot17m4++; - break; - - case R_BFIN_FUNCDESC_GOTHI: - case R_BFIN_FUNCDESC_GOTLO: - picrel->fdgothilo++; - break; - - case R_BFIN_GOTOFF17M4: - case R_BFIN_GOTOFFHI: - case R_BFIN_GOTOFFLO: - picrel->gotoff++; - break; - - case R_BFIN_FUNCDESC_GOTOFF17M4: - picrel->fdgoff17m4++; - break; - - case R_BFIN_FUNCDESC_GOTOFFHI: - case R_BFIN_FUNCDESC_GOTOFFLO: - picrel->fdgoffhilo++; - break; - - case R_BFIN_FUNCDESC: - picrel->fd++; - picrel->relocsfd++; - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_BFIN_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_BFIN_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_BFIN_HUIMM16: - case R_BFIN_LUIMM16: - case R_BFIN_PCREL12_JUMP_S: - case R_BFIN_PCREL10: - break; - - default: - bad_reloc: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unsupported relocation type %d"), - abfd, (int) ELF32_R_TYPE (rel->r_info)); - return FALSE; - } - } - - return TRUE; -} - -/* Set the right machine number for a Blackfin ELF file. */ - -static bfd_boolean -elf32_bfin_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_bfin, 0); - return (((elf_elfheader (abfd)->e_flags & EF_BFIN_FDPIC) != 0) - == (IS_FDPIC (abfd))); -} - -static bfd_boolean -elf32_bfin_set_private_flags (bfd * abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Display the flags field. */ -static bfd_boolean -elf32_bfin_print_private_bfd_data (bfd * abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - if (flags & EF_BFIN_PIC) - fprintf (file, " -fpic"); - - if (flags & EF_BFIN_FDPIC) - fprintf (file, " -mfdpic"); - - fputc ('\n', file); - - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf32_bfin_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, new_flags; - bfd_boolean error = FALSE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (new_flags & EF_BFIN_FDPIC) - new_flags &= ~EF_BFIN_PIC; - -#ifndef DEBUG - if (0) -#endif - _bfd_error_handler - ("old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s, filename = %B", - old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no", ibfd); - - if (!elf_flags_init (obfd)) /* First call, no flags set. */ - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - - if (((new_flags & EF_BFIN_FDPIC) == 0) != (! IS_FDPIC (obfd))) - { - error = TRUE; - if (IS_FDPIC (obfd)) - _bfd_error_handler - (_("%B: cannot link non-fdpic object file into fdpic executable"), - ibfd); - else - _bfd_error_handler - (_("%B: cannot link fdpic object file into non-fdpic executable"), - ibfd); - } - - if (error) - bfd_set_error (bfd_error_bad_value); - - return !error; -} - -/* bfin ELF linker hash entry. */ - -struct bfin_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Number of PC relative relocs copied for this symbol. */ - struct bfin_pcrel_relocs_copied *pcrel_relocs_copied; -}; - -/* bfin ELF linker hash table. */ - -struct bfin_link_hash_table -{ - struct elf_link_hash_table root; - - /* Small local sym cache. */ - struct sym_cache sym_cache; -}; - -#define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent)) - -static struct bfd_hash_entry * -bfin_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, const char *string) -{ - struct bfd_hash_entry *ret = entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, sizeof (struct bfin_link_hash_entry)); - if (ret == NULL) - return ret; - - /* Call the allocation method of the superclass. */ - ret = _bfd_elf_link_hash_newfunc (ret, table, string); - if (ret != NULL) - bfin_hash_entry (ret)->pcrel_relocs_copied = NULL; - - return ret; -} - -/* Create an bfin ELF linker hash table. */ - -static struct bfd_link_hash_table * -bfin_link_hash_table_create (bfd * abfd) -{ - struct bfin_link_hash_table *ret; - bfd_size_type amt = sizeof (struct bfin_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - bfin_link_hash_newfunc, - sizeof (struct elf_link_hash_entry), - BFIN_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->sym_cache.abfd = NULL; - - return &ret->root.root; -} - -/* The size in bytes of an entry in the procedure linkage table. */ - -/* Finish up the dynamic sections. */ - -static bfd_boolean -bfin_finish_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - } - - } - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -bfin_finish_dynamic_symbol (bfd * output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym * sym) -{ - if (h->got.offset != (bfd_vma) - 1) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol has an entry in the global offset table. - Set it up. */ - - sgot = elf_hash_table (info)->sgot; - srela = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset & ~(bfd_vma) 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 || h->forced_local) && h->def_regular) - { - _bfd_error_handler (_("*** check this relocation %s"), - __FUNCTION__); - rela.r_info = ELF32_R_INFO (0, R_BFIN_PCREL24); - rela.r_addend = bfd_get_signed_32 (output_bfd, - (sgot->contents - + - (h->got. - offset & ~(bfd_vma) 1))); - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, - sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - rela.r_info = ELF32_R_INFO (h->dynindx, R_BFIN_GOT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - if (h->needs_copy) - { - BFD_ASSERT (0); - } - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (strcmp (h->root.root.string, "__DYNAMIC") == 0 - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - 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 -bfin_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj; - asection *s; - unsigned int power_of_two; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic && h->ref_regular && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC || h->needs_plt) - { - BFD_ASSERT(0); - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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. */ - - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - -#if 0 /* Bfin does not currently have a COPY reloc. */ - /* We must generate a R_BFIN_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - asection *srel; - - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } -#else - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - _bfd_error_handler (_("the bfin target does not currently support the generation of copy relocations")); - return FALSE; - } -#endif - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 3) - power_of_two = 3; - - /* Apply the required alignment. */ - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > bfd_get_section_alignment (dynobj, s)) - { - if (!bfd_set_section_alignment (dynobj, s, power_of_two)) - return FALSE; - } - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - - return TRUE; -} - -/* The bfin linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that it - can discard PC relative relocs if it doesn't need them when linking - with -Bsymbolic. We store the information in a field extending the - regular ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we have - copied for a given symbol. */ - -struct bfin_pcrel_relocs_copied -{ - /* Next section. */ - struct bfin_pcrel_relocs_copied *next; - /* A section in dynobj. */ - asection *section; - /* Number of relocs copied in this section. */ - bfd_size_type count; -}; - -/* This function is called via elf_link_hash_traverse if we are - creating a shared object. In the -Bsymbolic case it discards the - space allocated to copy PC relative relocs against symbols which - are defined in regular objects. For the normal shared case, it - discards space for pc-relative relocs that have become local due to - symbol visibility changes. We allocated space for them in the - check_relocs routine, but we won't fill them in in the - relocate_section routine. - - We also check whether any of the remaining relocations apply - against a readonly section, and set the DF_TEXTREL flag in this - case. */ - -static bfd_boolean -bfin_discard_copies (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info = (struct bfd_link_info *) inf; - struct bfin_pcrel_relocs_copied *s; - - if (!h->def_regular || (!info->symbolic && !h->forced_local)) - { - if ((info->flags & DF_TEXTREL) == 0) - { - /* Look for relocations against read-only sections. */ - for (s = bfin_hash_entry (h)->pcrel_relocs_copied; - s != NULL; s = s->next) - if ((s->section->flags & SEC_READONLY) != 0) - { - info->flags |= DF_TEXTREL; - break; - } - } - - return TRUE; - } - - for (s = bfin_hash_entry (h)->pcrel_relocs_copied; - s != NULL; s = s->next) - s->section->size -= s->count * sizeof (Elf32_External_Rela); - - return TRUE; -} - -static bfd_boolean -bfin_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean relocs; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = elf_hash_table (info)->srelgot; - if (s != NULL) - s->size = 0; - } - - /* If this is a -Bsymbolic shared link, then we need to discard all - PC relative relocs against symbols defined in a regular object. - For the normal shared case we discard the PC relative relocs - against symbols that have become local due to visibility changes. - We allocated space for them in the check_relocs routine, but we - will not fill them in in the relocate_section routine. */ - if (bfd_link_pic (info)) - elf_link_hash_traverse (elf_hash_table (info), - bfin_discard_copies, info); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - bfd_boolean strip; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - strip = FALSE; - - if (CONST_STRNEQ (name, ".rela")) - { - 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. */ - strip = TRUE; - } - else - { - 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 if (! CONST_STRNEQ (name, ".got")) - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (strip) - { - s->flags |= SEC_EXCLUDE; - continue; - } - - /* Allocate memory for the section contents. */ - /* FIXME: This should be a call to bfd_alloc not bfd_zalloc. - Unused entries should be reclaimed before the section's contents - are written out, but at the moment this does not happen. Thus in - order to prevent writing out garbage, we initialise the section's - contents to zero. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL && s->size != 0) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in bfin_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 (!bfd_link_pic (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - } - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Given a .data section and a .emreloc in-memory section, store - relocation information into the .emreloc section which can be - used at runtime to relocate the section. This is called by the - linker when the --embedded-relocs switch is used. This is called - after the add_symbols entry point has been called for all the - objects, and before the final_link entry point is called. */ - -bfd_boolean -bfd_bfin_elf32_create_embedded_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *datasec, - asection *relsec, - char **errmsg) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *p; - bfd_size_type amt; - - BFD_ASSERT (! bfd_link_relocatable (info)); - - *errmsg = NULL; - - if (datasec->reloc_count == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, datasec, NULL, (Elf_Internal_Rela *) NULL, - info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - amt = (bfd_size_type) datasec->reloc_count * 12; - relsec->contents = (bfd_byte *) bfd_alloc (abfd, amt); - if (relsec->contents == NULL) - goto error_return; - - p = relsec->contents; - - irelend = internal_relocs + datasec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++, p += 12) - { - asection *targetsec; - - /* We are going to write a four byte longword into the runtime - reloc section. The longword will be the address in the data - section which must be relocated. It is followed by the name - of the target section NUL-padded or truncated to 8 - characters. */ - - /* We can only relocate absolute longword relocs at run time. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_BFIN_BYTE4_DATA) - { - *errmsg = _("unsupported reloc type"); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - - /* Get the target section referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - targetsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - targetsec = h->root.u.def.section; - else - targetsec = NULL; - } - - bfd_put_32 (abfd, irel->r_offset + datasec->output_offset, p); - memset (p + 4, 0, 8); - if (targetsec != NULL) - strncpy ((char *) p + 4, targetsec->output_section->name, 8); - } - - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (datasec)->relocs != internal_relocs) - free (internal_relocs); - return TRUE; - -error_return: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (datasec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -struct bfd_elf_special_section const elf32_bfin_special_sections[] = -{ - { ".l1.text", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".l1.data", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } -}; - - -#define TARGET_LITTLE_SYM bfin_elf32_vec -#define TARGET_LITTLE_NAME "elf32-bfin" -#define ELF_ARCH bfd_arch_bfin -#define ELF_TARGET_ID BFIN_ELF_DATA -#define ELF_MACHINE_CODE EM_BLACKFIN -#define ELF_MAXPAGESIZE 0x1000 -#define elf_symbol_leading_char '_' - -#define bfd_elf32_bfd_reloc_type_lookup bfin_bfd_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - bfin_bfd_reloc_name_lookup -#define elf_info_to_howto bfin_info_to_howto -#define elf_info_to_howto_rel 0 -#define elf_backend_object_p elf32_bfin_object_p - -#define bfd_elf32_bfd_is_local_label_name \ - bfin_is_local_label_name -#define bfin_hash_table(p) \ - ((struct bfin_link_hash_table *) (p)->hash) - - - -#define elf_backend_create_dynamic_sections \ - _bfd_elf_create_dynamic_sections -#define bfd_elf32_bfd_link_hash_table_create \ - bfin_link_hash_table_create -#define bfd_elf32_bfd_final_link bfd_elf_gc_common_final_link - -#define elf_backend_check_relocs bfin_check_relocs -#define elf_backend_adjust_dynamic_symbol \ - bfin_adjust_dynamic_symbol -#define elf_backend_size_dynamic_sections \ - bfin_size_dynamic_sections -#define elf_backend_relocate_section bfin_relocate_section -#define elf_backend_finish_dynamic_symbol \ - bfin_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - bfin_finish_dynamic_sections -#define elf_backend_gc_mark_hook bfin_gc_mark_hook -#define bfd_elf32_bfd_merge_private_bfd_data \ - elf32_bfin_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags \ - elf32_bfin_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - elf32_bfin_print_private_bfd_data -#define elf_backend_final_write_processing \ - elf32_bfin_final_write_processing -#define elf_backend_reloc_type_class elf32_bfin_reloc_type_class -#define elf_backend_stack_align 8 -#define elf_backend_can_gc_sections 1 -#define elf_backend_special_sections elf32_bfin_special_sections -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_rela_normal 1 - -#include "elf32-target.h" - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfin_elf32_fdpic_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-bfinfdpic" -#undef elf32_bed -#define elf32_bed elf32_bfinfdpic_bed - -#undef elf_backend_got_header_size -#define elf_backend_got_header_size 0 - -#undef elf_backend_relocate_section -#define elf_backend_relocate_section bfinfdpic_relocate_section -#undef elf_backend_check_relocs -#define elf_backend_check_relocs bfinfdpic_check_relocs - -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create \ - bfinfdpic_elf_link_hash_table_create -#undef elf_backend_always_size_sections -#define elf_backend_always_size_sections \ - elf32_bfinfdpic_always_size_sections - -#undef elf_backend_create_dynamic_sections -#define elf_backend_create_dynamic_sections \ - elf32_bfinfdpic_create_dynamic_sections -#undef elf_backend_adjust_dynamic_symbol -#define elf_backend_adjust_dynamic_symbol \ - elf32_bfinfdpic_adjust_dynamic_symbol -#undef elf_backend_size_dynamic_sections -#define elf_backend_size_dynamic_sections \ - elf32_bfinfdpic_size_dynamic_sections -#undef elf_backend_finish_dynamic_symbol -#define elf_backend_finish_dynamic_symbol \ - elf32_bfinfdpic_finish_dynamic_symbol -#undef elf_backend_finish_dynamic_sections -#define elf_backend_finish_dynamic_sections \ - elf32_bfinfdpic_finish_dynamic_sections - -#undef elf_backend_discard_info -#define elf_backend_discard_info \ - bfinfdpic_elf_discard_info -#undef elf_backend_can_make_relative_eh_frame -#define elf_backend_can_make_relative_eh_frame \ - bfinfdpic_elf_use_relative_eh_frame -#undef elf_backend_can_make_lsda_relative_eh_frame -#define elf_backend_can_make_lsda_relative_eh_frame \ - bfinfdpic_elf_use_relative_eh_frame -#undef elf_backend_encode_eh_address -#define elf_backend_encode_eh_address \ - bfinfdpic_elf_encode_eh_address - -#undef elf_backend_may_use_rel_p -#define elf_backend_may_use_rel_p 1 -#undef elf_backend_may_use_rela_p -#define elf_backend_may_use_rela_p 1 -/* We use REL for dynamic relocations only. */ -#undef elf_backend_default_use_rela_p -#define elf_backend_default_use_rela_p 1 - -#undef elf_backend_omit_section_dynsym -#define elf_backend_omit_section_dynsym _bfinfdpic_link_omit_section_dynsym - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-cr16.c b/sdcc/support/sdbinutils/bfd/elf32-cr16.c deleted file mode 100644 index 7bb67a72e..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-cr16.c +++ /dev/null @@ -1,2940 +0,0 @@ -/* BFD back-end for National Semiconductor's CR16 ELF - Copyright (C) 2007-2018 Free Software Foundation, Inc. - Written by M R Swami Reddy. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "libiberty.h" -#include "elf-bfd.h" -#include "elf/cr16.h" - -/* The cr16 linker needs to keep track of the number of relocs that - it decides to copy in check_relocs for each symbol. This is so - that it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ - -struct elf32_cr16_link_hash_entry -{ - /* The basic elf link hash table entry. */ - struct elf_link_hash_entry root; - - /* For function symbols, the number of times this function is - called directly (ie by name). */ - unsigned int direct_calls; - - /* For function symbols, the size of this function's stack - (if <= 255 bytes). We stuff this into "call" instructions - to this target when it's valid and profitable to do so. - - This does not include stack allocated by movm! */ - unsigned char stack_size; - - /* For function symbols, arguments (if any) for movm instruction - in the prologue. We stuff this value into "call" instructions - to the target when it's valid and profitable to do so. */ - unsigned char movm_args; - - /* For function symbols, the amount of stack space that would be allocated - by the movm instruction. This is redundant with movm_args, but we - add it to the hash table to avoid computing it over and over. */ - unsigned char movm_stack_size; - -/* Used to mark functions which have had redundant parts of their - prologue deleted. */ -#define CR16_DELETED_PROLOGUE_BYTES 0x1 - unsigned char flags; - - /* Calculated value. */ - bfd_vma value; -}; - -/* cr16_reloc_map array maps BFD relocation enum into a CRGAS relocation type. */ - -struct cr16_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_enum; /* BFD relocation enum. */ - unsigned short cr16_reloc_type; /* CR16 relocation type. */ -}; - -static const struct cr16_reloc_map cr16_reloc_map[R_CR16_MAX] = -{ - {BFD_RELOC_NONE, R_CR16_NONE}, - {BFD_RELOC_CR16_NUM8, R_CR16_NUM8}, - {BFD_RELOC_CR16_NUM16, R_CR16_NUM16}, - {BFD_RELOC_CR16_NUM32, R_CR16_NUM32}, - {BFD_RELOC_CR16_NUM32a, R_CR16_NUM32a}, - {BFD_RELOC_CR16_REGREL4, R_CR16_REGREL4}, - {BFD_RELOC_CR16_REGREL4a, R_CR16_REGREL4a}, - {BFD_RELOC_CR16_REGREL14, R_CR16_REGREL14}, - {BFD_RELOC_CR16_REGREL14a, R_CR16_REGREL14a}, - {BFD_RELOC_CR16_REGREL16, R_CR16_REGREL16}, - {BFD_RELOC_CR16_REGREL20, R_CR16_REGREL20}, - {BFD_RELOC_CR16_REGREL20a, R_CR16_REGREL20a}, - {BFD_RELOC_CR16_ABS20, R_CR16_ABS20}, - {BFD_RELOC_CR16_ABS24, R_CR16_ABS24}, - {BFD_RELOC_CR16_IMM4, R_CR16_IMM4}, - {BFD_RELOC_CR16_IMM8, R_CR16_IMM8}, - {BFD_RELOC_CR16_IMM16, R_CR16_IMM16}, - {BFD_RELOC_CR16_IMM20, R_CR16_IMM20}, - {BFD_RELOC_CR16_IMM24, R_CR16_IMM24}, - {BFD_RELOC_CR16_IMM32, R_CR16_IMM32}, - {BFD_RELOC_CR16_IMM32a, R_CR16_IMM32a}, - {BFD_RELOC_CR16_DISP4, R_CR16_DISP4}, - {BFD_RELOC_CR16_DISP8, R_CR16_DISP8}, - {BFD_RELOC_CR16_DISP16, R_CR16_DISP16}, - {BFD_RELOC_CR16_DISP24, R_CR16_DISP24}, - {BFD_RELOC_CR16_DISP24a, R_CR16_DISP24a}, - {BFD_RELOC_CR16_SWITCH8, R_CR16_SWITCH8}, - {BFD_RELOC_CR16_SWITCH16, R_CR16_SWITCH16}, - {BFD_RELOC_CR16_SWITCH32, R_CR16_SWITCH32}, - {BFD_RELOC_CR16_GOT_REGREL20, R_CR16_GOT_REGREL20}, - {BFD_RELOC_CR16_GOTC_REGREL20, R_CR16_GOTC_REGREL20}, - {BFD_RELOC_CR16_GLOB_DAT, R_CR16_GLOB_DAT} -}; - -static reloc_howto_type cr16_elf_howto_table[] = -{ - HOWTO (R_CR16_NONE, /* type */ - 0, /* rightshift */ - 3, /* size */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_NUM8, /* type */ - 0, /* rightshift */ - 0, /* size */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_NUM8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_NUM16, /* type */ - 0, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_NUM16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_NUM32, /* type */ - 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_NUM32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_NUM32a, /* type */ - 1, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_NUM32a", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL4, /* type */ - 0, /* rightshift */ - 0, /* size */ - 4, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL4", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xf, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL4a, /* type */ - 0, /* rightshift */ - 0, /* size */ - 4, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL4a", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xf, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL14, /* type */ - 0, /* rightshift */ - 1, /* size */ - 14, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL14", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x3fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL14a, /* type */ - 0, /* rightshift */ - 1, /* size */ - 14, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL14a", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x3fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL16, /* type */ - 0, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL20, /* type */ - 0, /* rightshift */ - 2, /* size */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL20", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_REGREL20a, /* type */ - 0, /* rightshift */ - 2, /* size */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_REGREL20a", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_ABS20, /* type */ - 0, /* rightshift */ - 2, /* size */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_ABS20", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_ABS24, /* type */ - 0, /* rightshift */ - 2, /* size */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_ABS24", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM4, /* type */ - 0, /* rightshift */ - 0, /* size */ - 4, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM4", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xf, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM8, /* type */ - 0, /* rightshift */ - 0, /* size */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM16, /* type */ - 0, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM20, /* type */ - 0, /* rightshift */ - 2, /* size */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM20", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM24, /* type */ - 0, /* rightshift */ - 2, /* size */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM24", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM32, /* type */ - 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_IMM32a, /* type */ - 1, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_IMM32a", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_DISP4, /* type */ - 1, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 4, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_DISP4", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xf, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_DISP8, /* type */ - 1, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_DISP8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x1ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_DISP16, /* type */ - 0, /* rightshift REVIITS: To sync with WinIDEA*/ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_DISP16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x1ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* REVISIT: DISP24 should be left-shift by 2 as per ISA doc - but its not done, to sync with WinIDEA and CR16 4.1 tools */ - HOWTO (R_CR16_DISP24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_DISP24", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x1ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_DISP24a, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_DISP24a", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit switch table entry. This is generated for an expression - such as ``.byte L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_CR16_SWITCH8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_SWITCH8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit switch table entry. This is generated for an expression - such as ``.word L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_CR16_SWITCH16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_SWITCH16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit switch table entry. This is generated for an expression - such as ``.long L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_CR16_SWITCH32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_SWITCH32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_CR16_GOT_REGREL20, /* type */ - 0, /* rightshift */ - 2, /* size */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_GOT_REGREL20", /* name */ - TRUE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_GOTC_REGREL20, /* type */ - 0, /* rightshift */ - 2, /* size */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_GOTC_REGREL20", /* name */ - TRUE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CR16_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CR16_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE) /* pcrel_offset */ -}; - - -/* Create the GOT section. */ - -static bfd_boolean -_bfd_cr16_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); - struct elf_link_hash_table *htab = elf_hash_table (info); - int ptralign; - - /* This function may be called more than once. */ - if (htab->sgot != NULL) - return TRUE; - - switch (bed->s->arch_size) - { - case 16: - ptralign = 1; - break; - - case 32: - ptralign = 2; - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - htab->sgot= s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (bed->want_got_plt) - { - s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); - htab->sgotplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - - /* 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_"); - htab->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; -} - - -/* Retrieve a howto ptr using a BFD reloc_code. */ - -static reloc_howto_type * -elf_cr16_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < R_CR16_MAX; i++) - if (code == cr16_reloc_map[i].bfd_reloc_enum) - return &cr16_elf_howto_table[cr16_reloc_map[i].cr16_reloc_type]; - - _bfd_error_handler (_("Unsupported CR16 relocation type: 0x%x\n"), code); - return NULL; -} - -static reloc_howto_type * -elf_cr16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; ARRAY_SIZE (cr16_elf_howto_table); i++) - if (cr16_elf_howto_table[i].name != NULL - && strcasecmp (cr16_elf_howto_table[i].name, r_name) == 0) - return cr16_elf_howto_table + i; - - return NULL; -} - -/* Retrieve a howto ptr using an internal relocation entry. */ - -static void -elf_cr16_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - - if (r_type >= R_CR16_MAX) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised CR16 reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_CR16_NONE; - } - cache_ptr->howto = cr16_elf_howto_table + r_type; -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -cr16_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym * isymbuf = NULL; - struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd * dynobj; - bfd_vma * local_got_offsets; - asection * sgot; - asection * srelgot; - - sgot = NULL; - srelgot = NULL; - bfd_boolean result = FALSE; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; - - dynobj = elf_hash_table (info)->dynobj; - local_got_offsets = elf_local_got_offsets (abfd); - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - /* Some relocs require a global offset table. */ - if (dynobj == NULL) - { - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_CR16_GOT_REGREL20: - case R_CR16_GOTC_REGREL20: - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! _bfd_cr16_elf_create_got_section (dynobj, info)) - goto fail; - break; - - default: - break; - } - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_CR16_GOT_REGREL20: - case R_CR16_GOTC_REGREL20: - /* This symbol requires a global offset table entry. */ - - sgot = elf_hash_table (info)->sgot; - srelgot = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srelgot != NULL); - - if (h != NULL) - { - if (h->got.offset != (bfd_vma) -1) - /* We have already allocated space in the .got. */ - break; - - h->got.offset = sgot->size; - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - goto fail; - } - - srelgot->size += sizeof (Elf32_External_Rela); - } - else - { - /* This is a global offset table entry for a local - symbol. */ - if (local_got_offsets == NULL) - { - size_t size; - unsigned int i; - - size = symtab_hdr->sh_info * sizeof (bfd_vma); - local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); - - if (local_got_offsets == NULL) - goto fail; - - elf_local_got_offsets (abfd) = local_got_offsets; - - for (i = 0; i < symtab_hdr->sh_info; i++) - local_got_offsets[i] = (bfd_vma) -1; - } - - if (local_got_offsets[r_symndx] != (bfd_vma) -1) - /* We have already allocated space in the .got. */ - break; - - local_got_offsets[r_symndx] = sgot->size; - - if (bfd_link_executable (info)) - /* If we are generating a shared object, we need to - output a R_CR16_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - - sgot->size += 4; - break; - - } - } - - result = TRUE; - fail: - if (isymbuf != NULL) - free (isymbuf); - - return result; -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -cr16_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd_byte *contents, - bfd_vma offset, - bfd_vma Rvalue, - bfd_vma addend, - struct elf_link_hash_entry * h, - unsigned long symndx ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - unsigned short r_type = howto->type; - bfd_byte *hit_data = contents + offset; - bfd_vma reloc_bits, check, Rvalue1; - - switch (r_type) - { - case R_CR16_IMM4: - case R_CR16_IMM20: - case R_CR16_ABS20: - break; - - case R_CR16_IMM8: - case R_CR16_IMM16: - case R_CR16_IMM32: - case R_CR16_IMM32a: - case R_CR16_REGREL4: - case R_CR16_REGREL4a: - case R_CR16_REGREL14: - case R_CR16_REGREL14a: - case R_CR16_REGREL16: - case R_CR16_REGREL20: - case R_CR16_REGREL20a: - case R_CR16_GOT_REGREL20: - case R_CR16_GOTC_REGREL20: - case R_CR16_ABS24: - case R_CR16_DISP16: - case R_CR16_DISP24: - /* 'hit_data' is relative to the start of the instruction, not the - relocation offset. Advance it to account for the exact offset. */ - hit_data += 2; - break; - - case R_CR16_NONE: - return bfd_reloc_ok; - break; - - case R_CR16_DISP4: - if (is_local) - Rvalue += -1; - break; - - case R_CR16_DISP8: - case R_CR16_DISP24a: - if (is_local) - Rvalue -= -1; - break; - - case R_CR16_SWITCH8: - case R_CR16_SWITCH16: - case R_CR16_SWITCH32: - /* We only care about the addend, where the difference between - expressions is kept. */ - Rvalue = 0; - - default: - break; - } - - if (howto->pc_relative) - { - /* Subtract the address of the section containing the location. */ - Rvalue -= (input_section->output_section->vma - + input_section->output_offset); - /* Subtract the position of the location within the section. */ - Rvalue -= offset; - } - - /* Add in supplied addend. */ - Rvalue += addend; - - /* Complain if the bitfield overflows, whether it is considered - as signed or unsigned. */ - check = Rvalue >> howto->rightshift; - - /* Assumes two's complement. This expression avoids - overflow if howto->bitsize is the number of bits in - bfd_vma. */ - reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - /* For GOT and GOTC relocs no boundary checks applied. */ - if (!((r_type == R_CR16_GOT_REGREL20) - || (r_type == R_CR16_GOTC_REGREL20))) - { - if (((bfd_vma) check & ~reloc_bits) != 0 - && (((bfd_vma) check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits))) - { - /* The above right shift is incorrect for a signed - value. See if turning on the upper bits fixes the - overflow. */ - if (howto->rightshift && (bfd_signed_vma) Rvalue < 0) - { - check |= ((bfd_vma) - 1 - & ~((bfd_vma) - 1 - >> howto->rightshift)); - - if (((bfd_vma) check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits)) - return bfd_reloc_overflow; - } - else - return bfd_reloc_overflow; - } - - /* Drop unwanted bits from the value we are relocating to. */ - Rvalue >>= (bfd_vma) howto->rightshift; - - /* Apply dst_mask to select only relocatable part of the insn. */ - Rvalue &= howto->dst_mask; - } - - switch (howto->size) - { - case 0: - if (r_type == R_CR16_DISP8) - { - Rvalue1 = bfd_get_16 (input_bfd, hit_data); - Rvalue = ((Rvalue1 & 0xf000) | ((Rvalue << 4) & 0xf00) - | (Rvalue1 & 0x00f0) | (Rvalue & 0xf)); - bfd_put_16 (input_bfd, Rvalue, hit_data); - } - else if (r_type == R_CR16_IMM4) - { - Rvalue1 = bfd_get_16 (input_bfd, hit_data); - Rvalue = (((Rvalue1 & 0xff) << 8) | ((Rvalue << 4) & 0xf0) - | ((Rvalue1 & 0x0f00) >> 8)); - bfd_put_16 (input_bfd, Rvalue, hit_data); - } - else if (r_type == R_CR16_DISP4) - { - Rvalue1 = bfd_get_16 (input_bfd, hit_data); - Rvalue = (Rvalue1 | ((Rvalue & 0xf) << 4)); - bfd_put_16 (input_bfd, Rvalue, hit_data); - } - else - { - bfd_put_8 (input_bfd, (unsigned char) Rvalue, hit_data); - } - break; - - case 1: - if (r_type == R_CR16_DISP16) - { - Rvalue |= (bfd_get_16 (input_bfd, hit_data)); - Rvalue = ((Rvalue & 0xfffe) | ((Rvalue >> 16) & 0x1)); - } - if (r_type == R_CR16_IMM16) - { - Rvalue1 = bfd_get_16 (input_bfd, hit_data); - - /* Add or subtract the offset value. */ - if (Rvalue1 & 0x8000) - Rvalue -= (~Rvalue1 + 1) & 0xffff; - else - Rvalue += Rvalue1; - - /* Check for range. */ - if ((long) Rvalue > 0xffff || (long) Rvalue < 0x0) - return bfd_reloc_overflow; - } - - bfd_put_16 (input_bfd, Rvalue, hit_data); - break; - - case 2: - if ((r_type == R_CR16_ABS20) || (r_type == R_CR16_IMM20)) - { - Rvalue1 = (bfd_get_16 (input_bfd, hit_data + 2) - | (((bfd_get_16 (input_bfd, hit_data) & 0xf) <<16))); - - /* Add or subtract the offset value. */ - if (Rvalue1 & 0x80000) - Rvalue -= (~Rvalue1 + 1) & 0xfffff; - else - Rvalue += Rvalue1; - - /* Check for range. */ - if ((long) Rvalue > 0xfffff || (long) Rvalue < 0x0) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, ((bfd_get_16 (input_bfd, hit_data) & 0xfff0) - | ((Rvalue >> 16) & 0xf)), hit_data); - bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data + 2); - } - else if (r_type == R_CR16_GOT_REGREL20) - { - asection *sgot = elf_hash_table (info)->sgot; - - if (h != NULL) - { - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - if (! elf_hash_table (info)->dynamic_sections_created - || SYMBOL_REFERENCES_LOCAL (info, h)) - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. - 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. */ - bfd_put_32 (output_bfd, Rvalue, sgot->contents + off); - - Rvalue = sgot->output_offset + off; - } - else - { - bfd_vma off; - - off = elf_local_got_offsets (input_bfd)[symndx]; - bfd_put_32 (output_bfd,Rvalue, sgot->contents + off); - - Rvalue = sgot->output_offset + off; - } - - Rvalue += addend; - - /* REVISIT: if ((long) Rvalue > 0xffffff || - (long) Rvalue < -0x800000). */ - if ((long) Rvalue > 0xffffff || (long) Rvalue < 0) - return bfd_reloc_overflow; - - - bfd_put_16 (input_bfd, (bfd_get_16 (input_bfd, hit_data)) - | (((Rvalue >> 16) & 0xf) << 8), hit_data); - bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data + 2); - - } - else if (r_type == R_CR16_GOTC_REGREL20) - { - asection *sgot = elf_hash_table (info)->sgot; - - if (h != NULL) - { - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - Rvalue >>=1; /* For code symbols. */ - - if (! elf_hash_table (info)->dynamic_sections_created - || SYMBOL_REFERENCES_LOCAL (info, h)) - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. - 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. */ - bfd_put_32 (output_bfd, Rvalue, sgot->contents + off); - - Rvalue = sgot->output_offset + off; - } - else - { - bfd_vma off; - - off = elf_local_got_offsets (input_bfd)[symndx]; - Rvalue >>= 1; - bfd_put_32 (output_bfd,Rvalue, sgot->contents + off); - Rvalue = sgot->output_offset + off; - } - - Rvalue += addend; - - /* Check if any value in DISP. */ - Rvalue1 =((bfd_get_32 (input_bfd, hit_data) >>16) - | (((bfd_get_32 (input_bfd, hit_data) & 0xfff) >> 8) <<16)); - - /* Add or subtract the offset value. */ - if (Rvalue1 & 0x80000) - Rvalue -= (~Rvalue1 + 1) & 0xfffff; - else - Rvalue += Rvalue1; - - /* Check for range. */ - /* REVISIT: if ((long) Rvalue > 0xffffff - || (long) Rvalue < -0x800000). */ - if ((long) Rvalue > 0xffffff || (long) Rvalue < 0) - return bfd_reloc_overflow; - - bfd_put_16 (input_bfd, (bfd_get_16 (input_bfd, hit_data)) - | (((Rvalue >> 16) & 0xf) << 8), hit_data); - bfd_put_16 (input_bfd, (Rvalue) & 0xffff, hit_data + 2); - } - else - { - if (r_type == R_CR16_ABS24) - { - Rvalue1 = ((bfd_get_32 (input_bfd, hit_data) >> 16) - | (((bfd_get_32 (input_bfd, hit_data) & 0xfff) >> 8) <<16) - | (((bfd_get_32 (input_bfd, hit_data) & 0xf) <<20))); - - /* Add or subtract the offset value. */ - if (Rvalue1 & 0x800000) - Rvalue -= (~Rvalue1 + 1) & 0xffffff; - else - Rvalue += Rvalue1; - - /* Check for Range. */ - if ((long) Rvalue > 0xffffff || (long) Rvalue < 0x0) - return bfd_reloc_overflow; - - Rvalue = ((((Rvalue >> 20) & 0xf) | (((Rvalue >> 16) & 0xf)<<8) - | (bfd_get_32 (input_bfd, hit_data) & 0xf0f0)) - | ((Rvalue & 0xffff) << 16)); - } - else if (r_type == R_CR16_DISP24) - { - Rvalue = ((((Rvalue >> 20)& 0xf) | (((Rvalue >>16) & 0xf)<<8) - | (bfd_get_16 (input_bfd, hit_data))) - | (((Rvalue & 0xfffe) | ((Rvalue >> 24) & 0x1)) << 16)); - } - else if ((r_type == R_CR16_IMM32) || (r_type == R_CR16_IMM32a)) - { - Rvalue1 =((((bfd_get_32 (input_bfd, hit_data)) >> 16) &0xffff) - | (((bfd_get_32 (input_bfd, hit_data)) &0xffff)) << 16); - - /* Add or subtract the offset value. */ - if (Rvalue1 & 0x80000000) - Rvalue -= (~Rvalue1 + 1) & 0xffffffff; - else - Rvalue += Rvalue1; - - /* Check for range. */ - if (Rvalue > 0xffffffff || (long) Rvalue < 0x0) - return bfd_reloc_overflow; - - Rvalue = (((Rvalue >> 16)& 0xffff) | (Rvalue & 0xffff) << 16); - } - else if (r_type == R_CR16_DISP24a) - { - Rvalue = (((Rvalue & 0xfffffe) | (Rvalue >> 23))); - Rvalue = ((Rvalue >> 16) & 0xff) | ((Rvalue & 0xffff) << 16) - | (bfd_get_32 (input_bfd, hit_data)); - } - else if ((r_type == R_CR16_REGREL20) - || (r_type == R_CR16_REGREL20a)) - { - Rvalue1 = ((bfd_get_32 (input_bfd, hit_data) >> 16) - | (((bfd_get_32 (input_bfd, hit_data) & 0xfff) >> 8) <<16)); - /* Add or subtract the offset value. */ - if (Rvalue1 & 0x80000) - Rvalue -= (~Rvalue1 + 1) & 0xfffff; - else - Rvalue += Rvalue1; - - /* Check for range. */ - if ((long) Rvalue > 0xfffff || (long) Rvalue < 0x0) - return bfd_reloc_overflow; - - Rvalue = (((((Rvalue >> 20)& 0xf) | (((Rvalue >>16) & 0xf)<<8) - | ((Rvalue & 0xffff) << 16))) - | (bfd_get_32 (input_bfd, hit_data) & 0xf0ff)); - - } - else if (r_type == R_CR16_NUM32) - { - Rvalue1 = (bfd_get_32 (input_bfd, hit_data)); - - /* Add or subtract the offset value */ - if (Rvalue1 & 0x80000000) - Rvalue -= (~Rvalue1 + 1) & 0xffffffff; - else - Rvalue += Rvalue1; - - /* Check for Ranga */ - if (Rvalue > 0xffffffff) - return bfd_reloc_overflow; - } - - bfd_put_32 (input_bfd, Rvalue, hit_data); - } - break; - - default: - return bfd_reloc_notsupported; - } - - return bfd_reloc_ok; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -elf32_cr16_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, bfd_vma addr, int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - struct elf_link_hash_entry **start_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - /* Get the new reloc address. */ - if ((irel->r_offset > addr && irel->r_offset < toaddr)) - irel->r_offset -= count; - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - { - /* Adjust the addend of SWITCH relocations in this section, - which reference this local symbol. */ -#if 0 - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - unsigned long r_symndx; - Elf_Internal_Sym *rsym; - bfd_vma addsym, subsym; - - /* Skip if not a SWITCH relocation. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH8 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH16 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_SWITCH32) - continue; - - r_symndx = ELF32_R_SYM (irel->r_info); - rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx; - - /* Skip if not the local adjusted symbol. */ - if (rsym != isym) - continue; - - addsym = isym->st_value; - subsym = addsym - irel->r_addend; - - /* Fix the addend only when -->> (addsym > addr >= subsym). */ - if (subsym <= addr) - irel->r_addend -= count; - else - continue; - } -#endif - - isym->st_value -= count; - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = start_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - /* The '--wrap SYMBOL' option is causing a pain when the object file, - containing the definition of __wrap_SYMBOL, includes a direct - call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference - the same symbol (which is __wrap_SYMBOL), but still exist as two - different symbols in 'sym_hashes', we don't want to adjust - the global symbol __wrap_SYMBOL twice. - This check is only relevant when symbols are being wrapped. */ - if (link_info->wrap_hash != NULL) - { - struct elf_link_hash_entry **cur_sym_hashes; - - /* Loop only over the symbols whom been already checked. */ - for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; - cur_sym_hashes++) - /* If the current symbol is identical to 'sym_hash', that means - the symbol was already adjusted (or at least checked). */ - if (*cur_sym_hashes == sym_hash) - break; - - /* Don't adjust the symbol again. */ - if (cur_sym_hashes < sym_hashes) - continue; - } - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; - } - - return TRUE; -} - -/* Relocate a CR16 ELF section. */ - -static bfd_boolean -elf32_cr16_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - howto = cr16_elf_howto_table + (r_type); - - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = cr16_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - (struct elf_link_hash_entry *) h, - r_symndx, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char *name; - const char *msg = NULL; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* Fall through. */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses elf32_cr16_relocate_section. */ - -static bfd_byte * -elf32_cr16_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - asection **secpp; - bfd_size_type amt; - - internal_relocs = _bfd_elf_link_read_relocs (input_bfd, input_section, - NULL, NULL, FALSE); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! elf32_cr16_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - return NULL; -} - -/* Assorted hash table functions. */ - -/* Initialize an entry in the link hash table. */ - -/* Create an entry in an CR16 ELF linker hash table. */ - -static struct bfd_hash_entry * -elf32_cr16_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf32_cr16_link_hash_entry *ret = - (struct elf32_cr16_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct elf32_cr16_link_hash_entry *) NULL) - ret = ((struct elf32_cr16_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf32_cr16_link_hash_entry))); - if (ret == (struct elf32_cr16_link_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf32_cr16_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != (struct elf32_cr16_link_hash_entry *) NULL) - { - ret->direct_calls = 0; - ret->stack_size = 0; - ret->movm_args = 0; - ret->movm_stack_size = 0; - ret->flags = 0; - ret->value = 0; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an cr16 ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf32_cr16_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_link_hash_table); - - ret = (struct elf_link_hash_table *) bfd_zmalloc (amt); - if (ret == (struct elf_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (ret, abfd, - elf32_cr16_link_hash_newfunc, - sizeof (struct elf32_cr16_link_hash_entry), - GENERIC_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root; -} - -static unsigned long -elf_cr16_mach (flagword flags) -{ - switch (flags) - { - case EM_CR16: - default: - return bfd_mach_cr16; - } -} - -/* The final processing done just before writing out a CR16 ELF object - file. This gets the CR16 architecture right based on the machine - number. */ - -static void -_bfd_cr16_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_cr16: - val = EM_CR16; - break; - } - - - elf_elfheader (abfd)->e_flags |= val; -} - - -static bfd_boolean -_bfd_cr16_elf_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_cr16, - elf_cr16_mach (elf_elfheader (abfd)->e_flags)); - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -_bfd_cr16_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_mach (obfd) < bfd_get_mach (ibfd)) - { - if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd))) - return FALSE; - } - - return TRUE; -} - - -/* This function handles relaxing for the CR16. - - There's quite a few relaxing opportunites available on the CR16: - - * bcond:24 -> bcond:16 1 byte - * bcond:16 -> bcond:8 1 byte - * arithmetic imm32 -> arithmetic imm20 12 bits - * arithmetic imm20/imm16 -> arithmetic imm4 12/16 bits - - Symbol- and reloc-reading infrastructure copied from elf-m10200.c. */ - -static bfd_boolean -elf32_cr16_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP16 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_DISP24 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM32 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM20 - && ELF32_R_TYPE (irel->r_info) != (int) R_CR16_IMM16) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Try to turn a 24 branch/call into a 16bit relative - branch/call. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_DISP24) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 16 bits, note the high value is - 0xfffe + 2 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 0x10000 && (long) value > -0x10002) - { - unsigned int code; - - /* Get the opcode. */ - code = (unsigned int) bfd_get_32 (abfd, contents + irel->r_offset); - - /* Verify it's a 'bcond' and fix the opcode. */ - if ((code & 0xffff) == 0x0010) - bfd_put_16 (abfd, 0x1800 | ((0xf & (code >> 20)) << 4), contents + irel->r_offset); - else - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CR16_DISP16); - - /* Delete two bytes of data. */ - if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 16bit pc-relative branch into an - 8bit pc-relative branch. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_DISP16) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 8 bits, note the high value is - 0xfc + 2 as the target will be two bytes closer if we are - able to relax. */ - /*if ((long) value < 0x1fa && (long) value > -0x100) REVISIT:range */ - if ((long) value < 0xfa && (long) value > -0x100) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Verify it's a 'bcond' and fix the opcode. */ - if ((code & 0xff0f) == 0x1800) - bfd_put_16 (abfd, (code & 0xf0f0), contents + irel->r_offset); - else - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CR16_DISP8); - - /* Delete two bytes of data. */ - if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 32-bit IMM address into a 20/16-bit IMM address */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM32) - { - bfd_vma value = symval; - unsigned short is_add_mov = 0; - bfd_vma value1 = 0; - - /* Get the existing value from the mcode */ - value1 = ((bfd_get_32 (abfd, contents + irel->r_offset + 2) >> 16) - |(((bfd_get_32 (abfd, contents + irel->r_offset + 2) & 0xffff) << 16))); - - /* See if the value will fit in 20 bits. */ - if ((long) (value + value1) < 0xfffff && (long) (value + value1) > 0) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Verify it's a 'arithmetic ADDD or MOVD instruction'. - For ADDD and MOVD only, convert to IMM32 -> IMM20. */ - - if (((code & 0xfff0) == 0x0070) || ((code & 0xfff0) == 0x0020)) - is_add_mov = 1; - - if (is_add_mov) - { - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - if ((code & 0xfff0) == 0x0070) /* For movd. */ - bfd_put_8 (abfd, 0x05, contents + irel->r_offset + 1); - else /* code == 0x0020 for addd. */ - bfd_put_8 (abfd, 0x04, contents + irel->r_offset + 1); - - bfd_put_8 (abfd, (code & 0xf) << 4, contents + irel->r_offset); - - /* If existing value is nagavive adjust approriately - place the 16-20bits (ie 4 bit) in new opcode, - as the 0xffffxxxx, the higher 2 byte values removed. */ - if (value1 & 0x80000000) - bfd_put_8 (abfd, (0x0f | (bfd_get_8(abfd, contents + irel->r_offset))), contents + irel->r_offset); - else - bfd_put_8 (abfd, (((value1 >> 16)&0xf) | (bfd_get_8(abfd, contents + irel->r_offset))), contents + irel->r_offset); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CR16_IMM20); - - /* Delete two bytes of data. */ - if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* See if the value will fit in 16 bits. */ - if ((!is_add_mov) - && ((long)(value + value1) < 0x7fff && (long)(value + value1) > 0)) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - if ((code & 0xf0) == 0x70) /* For movd. */ - bfd_put_8 (abfd, 0x54, contents + irel->r_offset + 1); - else if ((code & 0xf0) == 0x20) /* For addd. */ - bfd_put_8 (abfd, 0x60, contents + irel->r_offset + 1); - else if ((code & 0xf0) == 0x90) /* For cmpd. */ - bfd_put_8 (abfd, 0x56, contents + irel->r_offset + 1); - else - continue; - - bfd_put_8 (abfd, 0xb0 | (code & 0xf), contents + irel->r_offset); - - /* If existing value is nagavive adjust approriately - place the 12-16bits (ie 4 bit) in new opcode, - as the 0xfffffxxx, the higher 2 byte values removed. */ - if (value1 & 0x80000000) - bfd_put_8 (abfd, (0x0f | (bfd_get_8(abfd, contents + irel->r_offset))), contents + irel->r_offset); - else - bfd_put_16 (abfd, value1, contents + irel->r_offset + 2); - - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CR16_IMM16); - - /* Delete two bytes of data. */ - if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - -#if 0 - /* Try to turn a 16bit immediate address into a 4bit - immediate address. */ - if ((ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM20) - || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM16)) - { - bfd_vma value = symval; - bfd_vma value1 = 0; - - /* Get the existing value from the mcode */ - value1 = ((bfd_get_16 (abfd, contents + irel->r_offset + 2) & 0xffff)); - - if (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_IMM20) - { - value1 |= ((bfd_get_16 (abfd, contents + irel->r_offset + 1) & 0xf000) << 0x4); - } - - /* See if the value will fit in 4 bits. */ - if ((((long) (value + value1)) < 0xf) - && (((long) (value + value1)) > 0)) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - if (((code & 0x0f00) == 0x0400) || ((code & 0x0f00) == 0x0500)) - { - if ((code & 0x0f00) == 0x0400) /* For movd imm20. */ - bfd_put_8 (abfd, 0x60, contents + irel->r_offset); - else /* For addd imm20. */ - bfd_put_8 (abfd, 0x54, contents + irel->r_offset); - bfd_put_8 (abfd, (code & 0xf0) >> 4, contents + irel->r_offset + 1); - } - else - { - if ((code & 0xfff0) == 0x56b0) /* For cmpd imm16. */ - bfd_put_8 (abfd, 0x56, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x54b0) /* For movd imm16. */ - bfd_put_8 (abfd, 0x54, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x58b0) /* For movb imm16. */ - bfd_put_8 (abfd, 0x58, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x5Ab0) /* For movw imm16. */ - bfd_put_8 (abfd, 0x5A, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x60b0) /* For addd imm16. */ - bfd_put_8 (abfd, 0x60, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x30b0) /* For addb imm16. */ - bfd_put_8 (abfd, 0x30, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x2Cb0) /* For addub imm16. */ - bfd_put_8 (abfd, 0x2C, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x32b0) /* For adduw imm16. */ - bfd_put_8 (abfd, 0x32, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x38b0) /* For subb imm16. */ - bfd_put_8 (abfd, 0x38, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x3Cb0) /* For subcb imm16. */ - bfd_put_8 (abfd, 0x3C, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x3Fb0) /* For subcw imm16. */ - bfd_put_8 (abfd, 0x3F, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x3Ab0) /* For subw imm16. */ - bfd_put_8 (abfd, 0x3A, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x50b0) /* For cmpb imm16. */ - bfd_put_8 (abfd, 0x50, contents + irel->r_offset); - else if ((code & 0xfff0) == 0x52b0) /* For cmpw imm16. */ - bfd_put_8 (abfd, 0x52, contents + irel->r_offset); - else - continue; - - bfd_put_8 (abfd, (code & 0xf), contents + irel->r_offset + 1); - } - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CR16_IMM4); - - /* Delete two bytes of data. */ - if (!elf32_cr16_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } -#endif - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -static asection * -elf32_cr16_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -_bfd_cr16_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags; - asection * s; - const struct elf_backend_data * bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab = elf_hash_table (info); - int ptralign = 0; - - switch (bed->s->arch_size) - { - case 16: - ptralign = 1; - break; - - case 32: - ptralign = 2; - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.plt" : ".rel.plt"), - flags | SEC_READONLY); - htab->srelplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (! _bfd_cr16_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_anyway_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 (! bfd_link_executable (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - 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 -_bfd_cr16_elf_adjust_dynamic_symbol (struct bfd_link_info * info, - struct elf_link_hash_entry * h) -{ - bfd * dynobj; - asection * s; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (! bfd_link_executable (info) - && !h->def_dynamic - && !h->ref_dynamic) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a REL32 - reloc instead. */ - BFD_ASSERT (h->needs_plt); - return TRUE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - - s = elf_hash_table (info)->sgotplt; - BFD_ASSERT (s != NULL); - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - - s = elf_hash_table (info)->srelplt; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - - return TRUE; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_executable (info)) - 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; - - /* 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. */ - - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - /* We must generate a R_CR16_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection * srel; - - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -_bfd_cr16_elf_size_dynamic_sections (bfd * output_bfd, - struct bfd_link_info * info) -{ - bfd * dynobj; - asection * s; - bfd_boolean plt; - bfd_boolean relocs; - bfd_boolean reltext; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { -#if 0 - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; -#endif - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = elf_hash_table (info)->srelgot; - if (s != NULL) - s->size = 0; - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char * name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - asection * target; - - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (strcmp (name, ".rela.plt") != 0) - { - const char * outname; - - relocs = TRUE; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL - entry. The entries in the .rela.plt section - really apply to the .got section, which we - created ourselves and so know is not readonly. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 5); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = 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 if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".dynbss") != 0) - /* 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_CR16_NONE reloc - instead of garbage. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in _bfd_cr16_elf_finish_dynamic_sections, - but we must add the entries now so that we get the correct - size for the .dynamic section. The DT_DEBUG entry is filled - in by the dynamic linker and used by the debugger. */ - if (! bfd_link_executable (info)) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - } - - if (reltext) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0)) - return FALSE; - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -_bfd_cr16_elf_finish_dynamic_symbol (bfd * output_bfd, - struct bfd_link_info * info, - struct elf_link_hash_entry * h, - Elf_Internal_Sym * sym) -{ - bfd * dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - if (h->got.offset != (bfd_vma) -1) - { - asection * sgot; - asection * srel; - Elf_Internal_Rela rel; - - /* This symbol has an entry in the global offset table. Set it up. */ - - sgot = elf_hash_table (info)->sgot; - srel = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srel != NULL); - - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset & ~1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_executable (info) - && (info->symbolic || h->dynindx == -1) - && h->def_regular) - { - rel.r_info = ELF32_R_INFO (0, R_CR16_GOT_REGREL20); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_CR16_GOT_REGREL20); - rel.r_addend = 0; - } - - bfd_elf32_swap_reloca_out (output_bfd, &rel, - (bfd_byte *) ((Elf32_External_Rela *) srel->contents - + srel->reloc_count)); - ++ srel->reloc_count; - } - - if (h->needs_copy) - { - asection * s; - Elf_Internal_Rela rel; - - /* This symbol needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - 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_CR16_GOT_REGREL20); - rel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rel, - (bfd_byte *) ((Elf32_External_Rela *) s->contents - + s->reloc_count)); - ++ s->reloc_count; - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -_bfd_cr16_elf_finish_dynamic_sections (bfd * output_bfd, - struct bfd_link_info * info) -{ - bfd * dynobj; - asection * sgot; - asection * sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - sgot = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgot != NULL); - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf32_External_Dyn * dyncon; - Elf32_External_Dyn * dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection * s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = elf_hash_table (info)->sgotplt; - goto get_vma; - - case DT_JMPREL: - s = elf_hash_table (info)->srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = elf_hash_table (info)->srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -/* Given a .data.rel section and a .emreloc in-memory section, store - relocation information into the .emreloc section which can be - used at runtime to relocate the section. This is called by the - linker when the --embedded-relocs switch is used. This is called - after the add_symbols entry point has been called for all the - objects, and before the final_link entry point is called. */ - -bfd_boolean -bfd_cr16_elf32_create_embedded_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *datasec, - asection *relsec, - char **errmsg) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *p; - bfd_size_type amt; - - BFD_ASSERT (! bfd_link_relocatable (info)); - - *errmsg = NULL; - - if (datasec->reloc_count == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, datasec, NULL, NULL, info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - amt = (bfd_size_type) datasec->reloc_count * 8; - relsec->contents = (bfd_byte *) bfd_alloc (abfd, amt); - if (relsec->contents == NULL) - goto error_return; - - p = relsec->contents; - - irelend = internal_relocs + datasec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++, p += 8) - { - asection *targetsec; - - /* We are going to write a four byte longword into the runtime - reloc section. The longword will be the address in the data - section which must be relocated. It is followed by the name - of the target section NUL-padded or truncated to 8 - characters. */ - - /* We can only relocate absolute longword relocs at run time. */ - if (!((ELF32_R_TYPE (irel->r_info) == (int) R_CR16_NUM32a) - || (ELF32_R_TYPE (irel->r_info) == (int) R_CR16_NUM32))) - { - *errmsg = _("unsupported reloc type"); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - - /* Get the target section referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - targetsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - targetsec = h->root.u.def.section; - else - targetsec = NULL; - } - - bfd_put_32 (abfd, irel->r_offset + datasec->output_offset, p); - memset (p + 4, 0, 4); - if ((ELF32_R_TYPE (irel->r_info) == (int) R_CR16_NUM32a) - && (targetsec != NULL) ) - strncpy ((char *) p + 4, targetsec->output_section->name, 4); - } - - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (datasec)->relocs != internal_relocs) - free (internal_relocs); - return TRUE; - -error_return: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (datasec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - - -/* Classify relocation types, such that combreloc can sort them - properly. */ - -static enum elf_reloc_type_class -_bfd_cr16_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_CR16_GOT_REGREL20: - case R_CR16_GOTC_REGREL20: - return reloc_class_relative; - default: - return reloc_class_normal; - } -} - -/* Definitions for setting CR16 target vector. */ -#define TARGET_LITTLE_SYM cr16_elf32_vec -#define TARGET_LITTLE_NAME "elf32-cr16" -#define ELF_ARCH bfd_arch_cr16 -#define ELF_MACHINE_CODE EM_CR16 -#define ELF_MACHINE_ALT1 EM_CR16_OLD -#define ELF_MAXPAGESIZE 0x1 -#define elf_symbol_leading_char '_' - -#define bfd_elf32_bfd_reloc_type_lookup elf_cr16_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf_cr16_reloc_name_lookup -#define elf_info_to_howto elf_cr16_info_to_howto -#define elf_info_to_howto_rel 0 -#define elf_backend_relocate_section elf32_cr16_relocate_section -#define bfd_elf32_bfd_relax_section elf32_cr16_relax_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - elf32_cr16_get_relocated_section_contents -#define elf_backend_gc_mark_hook elf32_cr16_gc_mark_hook -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 -#define elf_backend_check_relocs cr16_elf_check_relocs -/* So we can set bits in e_flags. */ -#define elf_backend_final_write_processing \ - _bfd_cr16_elf_final_write_processing -#define elf_backend_object_p _bfd_cr16_elf_object_p - -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_cr16_elf_merge_private_bfd_data - - -#define bfd_elf32_bfd_link_hash_table_create \ - elf32_cr16_link_hash_table_create - -#define elf_backend_create_dynamic_sections \ - _bfd_cr16_elf_create_dynamic_sections -#define elf_backend_adjust_dynamic_symbol \ - _bfd_cr16_elf_adjust_dynamic_symbol -#define elf_backend_size_dynamic_sections \ - _bfd_cr16_elf_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_finish_dynamic_symbol \ - _bfd_cr16_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_cr16_elf_finish_dynamic_sections - -#define elf_backend_reloc_type_class _bfd_cr16_elf_reloc_type_class - - -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-cr16c.c b/sdcc/support/sdbinutils/bfd/elf32-cr16c.c deleted file mode 100644 index ec2948de7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-cr16c.c +++ /dev/null @@ -1,960 +0,0 @@ -/* BFD back-end for National Semiconductor's CR16C ELF - Copyright (C) 2004-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "elf/cr16c.h" -#include "elf-bfd.h" - - -#define USE_REL 1 /* CR16C uses REL relocations instead of RELA. */ - -/* The following definition is based on EMPTY_HOWTO macro, - but also initiates the "name" field in HOWTO struct. */ -#define ONLY_NAME_HOWTO(C) \ - HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ - STRINGX(C), FALSE, 0, 0, FALSE) - -/* reloc_map_index array maps CRASM relocation type into a BFD - relocation enum. The array's indices are synchronized with - RINDEX_16C_* indices, created in include/elf/cr16c.h. - The array is used in: - 1. elf32-cr16c.c : elf_cr16c_reloc_type_lookup(). - 2. asreloc.c : find_reloc_type(). */ - -RELOC_MAP reloc_map_index[RINDEX_16C_MAX] = -{ - {R_16C_NUM08, BFD_RELOC_16C_NUM08}, - {R_16C_NUM08_C, BFD_RELOC_16C_NUM08_C}, - {R_16C_NUM16, BFD_RELOC_16C_NUM16}, - {R_16C_NUM16_C, BFD_RELOC_16C_NUM16_C}, - {R_16C_NUM32, BFD_RELOC_16C_NUM32}, - {R_16C_NUM32_C, BFD_RELOC_16C_NUM32_C}, - {R_16C_DISP04, BFD_RELOC_16C_DISP04}, - {R_16C_DISP04_C, BFD_RELOC_16C_DISP04_C}, - {R_16C_DISP08, BFD_RELOC_16C_DISP08}, - {R_16C_DISP08_C, BFD_RELOC_16C_DISP08_C}, - {R_16C_DISP16, BFD_RELOC_16C_DISP16}, - {R_16C_DISP16_C, BFD_RELOC_16C_DISP16_C}, - {R_16C_DISP24, BFD_RELOC_16C_DISP24}, - {R_16C_DISP24_C, BFD_RELOC_16C_DISP24_C}, - {R_16C_DISP24a, BFD_RELOC_16C_DISP24a}, - {R_16C_DISP24a_C, BFD_RELOC_16C_DISP24a_C}, - {R_16C_REG04, BFD_RELOC_16C_REG04}, - {R_16C_REG04_C, BFD_RELOC_16C_REG04_C}, - {R_16C_REG04a, BFD_RELOC_16C_REG04a}, - {R_16C_REG04a_C, BFD_RELOC_16C_REG04a_C}, - {R_16C_REG14, BFD_RELOC_16C_REG14}, - {R_16C_REG14_C, BFD_RELOC_16C_REG14_C}, - {R_16C_REG16, BFD_RELOC_16C_REG16}, - {R_16C_REG16_C, BFD_RELOC_16C_REG16_C}, - {R_16C_REG20, BFD_RELOC_16C_REG20}, - {R_16C_REG20_C, BFD_RELOC_16C_REG20_C}, - {R_16C_ABS20, BFD_RELOC_16C_ABS20}, - {R_16C_ABS20_C, BFD_RELOC_16C_ABS20_C}, - {R_16C_ABS24, BFD_RELOC_16C_ABS24}, - {R_16C_ABS24_C, BFD_RELOC_16C_ABS24_C}, - {R_16C_IMM04, BFD_RELOC_16C_IMM04}, - {R_16C_IMM04_C, BFD_RELOC_16C_IMM04_C}, - {R_16C_IMM16, BFD_RELOC_16C_IMM16}, - {R_16C_IMM16_C, BFD_RELOC_16C_IMM16_C}, - {R_16C_IMM20, BFD_RELOC_16C_IMM20}, - {R_16C_IMM20_C, BFD_RELOC_16C_IMM20_C}, - {R_16C_IMM24, BFD_RELOC_16C_IMM24}, - {R_16C_IMM24_C, BFD_RELOC_16C_IMM24_C}, - {R_16C_IMM32, BFD_RELOC_16C_IMM32}, - {R_16C_IMM32_C, BFD_RELOC_16C_IMM32_C} -}; - -static reloc_howto_type elf_howto_table[] = -{ - /* 00 */ ONLY_NAME_HOWTO (RINDEX_16C_NUM08), - /* 01 */ ONLY_NAME_HOWTO (RINDEX_16C_NUM08_C), - /* 02 */ ONLY_NAME_HOWTO (RINDEX_16C_NUM16), - /* 03 */ ONLY_NAME_HOWTO (RINDEX_16C_NUM16_C), - /* 04 */ ONLY_NAME_HOWTO (RINDEX_16C_NUM32), - /* 05 */ ONLY_NAME_HOWTO (RINDEX_16C_NUM32_C), - /* 06 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP04), - /* 07 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP04_C), - /* 08 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP08), - /* 09 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP08_C), - /* 10 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP16), - /* 11 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP16_C), - /* 12 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP24), - /* 13 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP24_C), - /* 14 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP24a), - /* 15 */ ONLY_NAME_HOWTO (RINDEX_16C_DISP24a_C), - /* 16 */ ONLY_NAME_HOWTO (RINDEX_16C_REG04), - /* 17 */ ONLY_NAME_HOWTO (RINDEX_16C_REG04_C), - /* 18 */ ONLY_NAME_HOWTO (RINDEX_16C_REG04a), - /* 19 */ ONLY_NAME_HOWTO (RINDEX_16C_REG04a_C), - /* 20 */ ONLY_NAME_HOWTO (RINDEX_16C_REG14), - /* 21 */ ONLY_NAME_HOWTO (RINDEX_16C_REG14_C), - /* 22 */ ONLY_NAME_HOWTO (RINDEX_16C_REG16), - /* 23 */ ONLY_NAME_HOWTO (RINDEX_16C_REG16_C), - /* 24 */ ONLY_NAME_HOWTO (RINDEX_16C_REG20), - /* 25 */ ONLY_NAME_HOWTO (RINDEX_16C_REG20_C), - /* 26 */ ONLY_NAME_HOWTO (RINDEX_16C_ABS20), - /* 27 */ ONLY_NAME_HOWTO (RINDEX_16C_ABS20_C), - /* 28 */ ONLY_NAME_HOWTO (RINDEX_16C_ABS24), - /* 29 */ ONLY_NAME_HOWTO (RINDEX_16C_ABS24_C), - /* 30 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM04), - /* 31 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM04_C), - /* 32 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM16), - /* 33 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM16_C), - /* 34 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM20), - /* 35 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM20_C), - /* 36 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM24), - /* 37 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM24_C), - /* 38 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM32), - /* 39 */ ONLY_NAME_HOWTO (RINDEX_16C_IMM32_C) -}; - - -/* Code to turn a code_type into a howto ptr, uses the above howto table. */ - -static reloc_howto_type * -elf_cr16c_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < RINDEX_16C_MAX; i++) - { - if (code == reloc_map_index[i].bfd_reloc_enum) - { - /* printf ("CR16C Relocation Type is - %x\n", code); */ - return & elf_howto_table[i]; - } - } - - /* printf ("This relocation Type is not supported - %x\n", code); */ - return 0; -} - -static reloc_howto_type * -elf_cr16c_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - return NULL; -} - -static void -elf_cr16c_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr ATTRIBUTE_UNUSED, - Elf_Internal_Rela *dst ATTRIBUTE_UNUSED) -{ - abort (); -} - -static void -elf_cr16c_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); - - if (r_type >= RINDEX_16C_MAX) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid CR16C reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_howto_table[r_type]; -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -cr16c_elf_final_link_relocate (reloc_howto_type *howto, - bfd *abfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd_byte *data, - bfd_vma octets, - bfd_vma Rvalue, - bfd_vma addend ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sym_sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - long value; - short sword; /* Extracted from the hole and put back. */ - unsigned long format, addr_type, code_factor; - unsigned short size; - unsigned short r_type; - - unsigned long disp20_opcod; - char neg = 0; - char neg2pos = 0; - - long left_val = 0; - long plus_factor = 0; /* To be added to the hole. */ - -#define MIN_BYTE ((int) 0xFFFFFF80) -#define MIN_WORD ((int) 0xFFFF8000) -#define MAX_UWORD ((unsigned) 0x0000FFFF) -#define MAX_UBYTE ((unsigned) 0x000000FF) - - r_type = reloc_map_index[howto->type].cr_reloc_type; - format = r_type & R_FORMAT; - size = r_type & R_SIZESP; - addr_type = r_type & R_ADDRTYPE; - code_factor = ((addr_type == R_CODE_ADDR) ? 1 : 0); - - switch (format) - { - case R_NUMBER: - switch (size) - { - case R_S_16C_08: /* One byte. */ - value = bfd_get_8 (abfd, (char *) data + octets); - break; - case R_S_16C_16: /* Two bytes. */ - sword = bfd_get_16 (abfd, (bfd_byte *) data + octets); - value = sword; - break; - case R_S_16C_32: /* Four bytes. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - break; - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_DISPL: - switch (size) - { - case R_S_16C_04: /* word1(4-7). */ - value = bfd_get_8 (abfd, (char *) data + octets); - left_val = value & 0xF; - value = (value & 0xF0) >> 4; - value++; - value <<= 1; - break; - case R_S_16C_08: /* word1(0-3,8-11). */ - sword = bfd_get_16 (abfd, (char *) data + octets); - value = sword & 0x000F; - value |= ((sword & 0x0F00) >> 4); - left_val = sword & 0xF0F0; - value <<= 1; - if (value & 0x100) - value |= 0xFFFFFF00; - break; - case R_S_16C_16: /* word2. */ - sword = bfd_get_16 (abfd, (bfd_byte *) data + octets); - value = sword; - value = ((value & 0xFFFE) >> 1) | ((value & 0x1) << 15); - value <<= 1; - if (value & 0x10000) - value |= 0xFFFF0000; - break; - case R_S_16C_24_a: /* word1(0-7),word2. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0x0000FF00; - value = ((value & 0xFFFE0000) >> 17) | - ((value & 0x00010000) << 7) | ((value & 0x000000FF) << 15); - value <<= 1; - if (value & 0x1000000) - value |= 0xFE000000; - break; - case R_S_16C_24: /* word2(0-3,8-11),word3. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0x0000F0F0; - value = ((value >> 16) & 0x0000FFFF) | - ((value & 0x00000F00) << 8) | ((value & 0x0000000F) << 20); - - value = ((value & 0x00FFFFFE) >> 1) | ((value & 0x00000001) << 23); - - value <<= 1; - if (value & 0x1000000) - value |= 0xFE000000; - break; - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_REGREL: - switch (size) - { - case R_S_16C_04: /* word1(12-15) not scaled. */ - value = bfd_get_8 (abfd, (char *) data + octets); - left_val = value & 0xF0; - value = value & 0xF; - break; - case R_S_16C_04_a: /* word1(12-15) scaled by 2. */ - value = bfd_get_8 (abfd, (char *) data + octets); - left_val = value & 0xF0; - value = value & 0xF; - value <<= 1; - break; - case R_S_16C_14: /* word1(4-5),word2(0-3,8-15). */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0x00F0FFCF; - value = ((value & 0xc0000000) >> 24) | - ((value & 0x3F000000) >> 16) | - ((value & 0x000F0000) >> 16) | (value & 0x00000030); - break; - case R_S_16C_16: /* word2. */ - sword = bfd_get_16 (abfd, (bfd_byte *) data + octets); - value = sword; - break; - case R_S_16C_20: /* word2(8-11),word3. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0xF0; - value = (value & 0xF) << 16; - sword = bfd_get_16 (abfd, (bfd_byte *) data + octets + 1); - value = value | (unsigned short) sword; - disp20_opcod = bfd_get_32 (abfd, (bfd_byte *) data + octets - 3); - disp20_opcod |= 0x0FFF0000; - if ((disp20_opcod == 0x4FFF0018) || /* loadb -disp20(reg) */ - (disp20_opcod == 0x5FFF0018) || /* loadb -disp20(rp) */ - (disp20_opcod == 0x8FFF0018) || /* loadd -disp20(reg) */ - (disp20_opcod == 0x9FFF0018) || /* loadd -disp20(rp) */ - (disp20_opcod == 0xCFFF0018) || /* loadw -disp20(reg) */ - (disp20_opcod == 0xDFFF0018) || /* loadw -disp20(rp) */ - (disp20_opcod == 0x4FFF0019) || /* storb -disp20(reg) */ - (disp20_opcod == 0x5FFF0019) || /* storb -disp20(rp) */ - (disp20_opcod == 0x8FFF0019) || /* stord -disp20(reg) */ - (disp20_opcod == 0x9FFF0019) || /* stord -disp20(rp) */ - (disp20_opcod == 0xCFFF0019) || /* storw -disp20(reg) */ - (disp20_opcod == 0xDFFF0019)) - { /* storw -disp20(rp). */ - neg = 1; - value |= 0xFFF00000; - } - - break; - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_ABS: - switch (size) - { - case R_S_16C_20: /* word1(0-3),word2. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0x0000FFF0; - value = ((value & 0xFFFF0000) >> 16) | - ((value & 0x0000000F) << 16); - break; - case R_S_16C_24: /* word2(0-3,8-11),word3. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0x0000F0F0; - value = ((value & 0xFFFF0000) >> 16) | - ((value & 0x00000F00) << 8) | ((value & 0x0000000F) << 20); - break; - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_IMMED: - switch (size) - { - case R_S_16C_04: /* word1/2(4-7). */ - value = bfd_get_8 (abfd, (char *) data + octets); - left_val = value & 0xF; - value = (value & 0xF0) >> 4; - break; - case R_S_16C_16: /* word2. */ - sword = bfd_get_16 (abfd, (bfd_byte *) data + octets); - value = sword; - break; - case R_S_16C_20: /* word1(0-3),word2. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - left_val = value & 0x0000FFF0; - value = ((value & 0xFFFF0000) >> 16) | - ((value & 0x0000000F) << 16); - break; - case R_S_16C_32: /* word2, word3. */ - value = bfd_get_32 (abfd, (bfd_byte *) data + octets); - value = ((value & 0x0000FFFF) << 16) | - ((value & 0xFFFF0000) >> 16); - break; - default: - return bfd_reloc_notsupported; - } - break; - default: - return bfd_reloc_notsupported; - } - - switch ((r_type & R_RELTO) >> 4) - { - - case 0: /* R_ABS. */ - plus_factor = Rvalue; - break; - case 1: /* R_PCREL. */ - plus_factor = Rvalue - - (input_section->output_section->vma + input_section->output_offset); - break; - default: - return bfd_reloc_notsupported; - } - - if (neg) - { - if (plus_factor >= -value) - neg2pos = 1; - /* We need to change load/stor with negative - displ opcode to positive disp opcode (CR16C). */ - } - - value = value + (plus_factor >> code_factor); - - switch (format) - { - case R_NUMBER: - switch (size) - { - case R_S_16C_08: /* One byte. */ - if (value > (int) MAX_UBYTE || value < MIN_BYTE) - return bfd_reloc_overflow; - value &= 0xFF; - bfd_put_8 (abfd, (bfd_vma) value, (unsigned char *) data + octets); - break; - - case R_S_16C_16: /* Two bytes. */ - if (value > (int) MAX_UWORD || value < MIN_WORD) - return bfd_reloc_overflow; - value &= 0xFFFF; - sword = value; - bfd_put_16 (abfd, (bfd_vma) sword, - (unsigned char *) data + octets); - break; - - case R_S_16C_32: /* Four bytes. */ - value &= 0xFFFFFFFF; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_DISPL: - switch (size) - { - case R_S_16C_04: /* word1(4-7). */ - if ((value - 32) > 32 || value < 2) - return bfd_reloc_overflow; - value >>= 1; - value--; - value &= 0xF; - value <<= 4; - value |= left_val; - bfd_put_8 (abfd, (bfd_vma) value, (unsigned char *) data + octets); - break; - - case R_S_16C_08: /* word1(0-3,8-11). */ - if (value > 255 || value < -256 || value == 0x80) - return bfd_reloc_overflow; - value &= 0x1FF; - value >>= 1; - sword = value & 0x000F; - sword |= (value & 0x00F0) << 4; - sword |= left_val; - bfd_put_16 (abfd, (bfd_vma) sword, - (unsigned char *) data + octets); - break; - - case R_S_16C_16: /* word2. */ - if (value > 65535 || value < -65536) - return bfd_reloc_overflow; - value >>= 1; - value &= 0xFFFF; - value = ((value & 0x8000) >> 15) | ((value & 0x7FFF) << 1); - sword = value; - bfd_put_16 (abfd, (bfd_vma) sword, - (unsigned char *) data + octets); - break; - - case R_S_16C_24_a: /* word1(0-7),word2. */ - if (value > 16777215 || value < -16777216) - return bfd_reloc_overflow; - value &= 0x1FFFFFF; - value >>= 1; - value = ((value & 0x00007FFF) << 17) | - ((value & 0x00800000) >> 7) | ((value & 0x007F8000) >> 15); - value |= left_val; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - case R_S_16C_24: /* word2(0-3,8-11),word3. */ - if (value > 16777215 || value < -16777216) - return bfd_reloc_overflow; - value &= 0x1FFFFFF; - value >>= 1; - - value = ((value & 0x007FFFFF) << 1) | ((value & 0x00800000) >> 23); - - value = ((value & 0x0000FFFF) << 16) | - ((value & 0x000F0000) >> 8) | ((value & 0x00F00000) >> 20); - value |= left_val; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_REGREL: - switch (size) - { - case R_S_16C_04: /* word1(12-15) not scaled. */ - if (value > 13 || value < 0) - return bfd_reloc_overflow; - value &= 0xF; - value |= left_val; - bfd_put_8 (abfd, (bfd_vma) value, (unsigned char *) data + octets); - break; - - case R_S_16C_04_a: /* word1(12-15) not scaled. */ - if (value > 26 || value < 0) - return bfd_reloc_overflow; - value &= 0x1F; - value >>= 1; - value |= left_val; - bfd_put_8 (abfd, (bfd_vma) value, (unsigned char *) data + octets); - break; - - case R_S_16C_14: /* word1(4-5),word2(0-3,8-15). */ - if (value < 0 || value > 16383) - return bfd_reloc_overflow; - value &= 0x3FFF; - value = ((value & 0x000000c0) << 24) | - ((value & 0x00003F00) << 16) | - ((value & 0x0000000F) << 16) | (value & 0x00000030); - value |= left_val; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - case R_S_16C_16: /* word2. */ - if (value > 65535 || value < 0) - return bfd_reloc_overflow; - value &= 0xFFFF; - sword = value; - bfd_put_16 (abfd, (bfd_vma) sword, - (unsigned char *) data + octets); - break; - - case R_S_16C_20: /* word2(8-11),word3. */ - /* if (value > 1048575 || value < 0) RELOC_ERROR(1); */ - value &= 0xFFFFF; - sword = value & 0x0000FFFF; - value = (value & 0x000F0000) >> 16; - value |= left_val; - bfd_put_8 (abfd, (bfd_vma) value, (unsigned char *) data + octets); - bfd_put_16 (abfd, (bfd_vma) sword, - (unsigned char *) data + octets + 1); - if (neg2pos) - { - /* Change load/stor negative displ opcode - to load/stor positive displ opcode. */ - value = bfd_get_8 (abfd, (char *) data + octets - 3); - value &= 0xF7; - value |= 0x2; - bfd_put_8 (abfd, (bfd_vma) value, - (unsigned char *) data + octets - 3); - } - break; - - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_ABS: - switch (size) - { - case R_S_16C_20: /* word1(0-3),word2. */ - if (value > 1048575 || value < 0) - return bfd_reloc_overflow; - value &= 0xFFFFF; - value = ((value & 0x0000FFFF) << 16) | - ((value & 0x000F0000) >> 16); - value |= left_val; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - case R_S_16C_24: /* word2(0-3,8-11),word3. */ - /* if (value > 16777215 || value < 0) RELOC_ERROR(1); */ - value &= 0xFFFFFF; - value = ((value & 0x0000FFFF) << 16) | - ((value & 0x000F0000) >> 8) | ((value & 0x00F00000) >> 20); - value |= left_val; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - default: - return bfd_reloc_notsupported; - } - break; - - case R_16C_IMMED: - switch (size) - { - case R_S_16C_04: /* word1/2(4-7). */ - if (value > 15 || value < -1) - return bfd_reloc_overflow; - value &= 0xF; - value <<= 4; - value |= left_val; - bfd_put_8 (abfd, (bfd_vma) value, (unsigned char *) data + octets); - break; - - case R_S_16C_16: /* word2. */ - if (value > 32767 || value < -32768) - return bfd_reloc_overflow; - value &= 0xFFFF; - sword = value; - bfd_put_16 (abfd, (bfd_vma) sword, - (unsigned char *) data + octets); - break; - - case R_S_16C_20: /* word1(0-3),word2. */ - if (value > 1048575 || value < 0) - return bfd_reloc_overflow; - value &= 0xFFFFF; - value = ((value & 0x0000FFFF) << 16) | - ((value & 0x000F0000) >> 16); - value |= left_val; - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - case R_S_16C_32: /* word2, word3. */ - value &= 0xFFFFFFFF; - value = ((value & 0x0000FFFF) << 16) | - ((value & 0xFFFF0000) >> 16); - bfd_put_32 (abfd, (bfd_vma) value, (bfd_byte *) data + octets); - break; - - default: - return bfd_reloc_notsupported; - } - break; - default: - return bfd_reloc_notsupported; - } - - return bfd_reloc_ok; -} - -/* Relocate a CR16C ELF section. */ - -static bfd_boolean -elf32_cr16c_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - howto = elf_howto_table + r_type; - - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - continue; - } - - r = cr16c_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char *name; - const char *msg = (const char *) 0; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* CR16C ELF uses three common sections: - One is for default common symbols (placed in usual common section). - Second is for near common symbols (placed in "ncommon" section). - Third is for far common symbols (placed in "fcommon" section). - The following implementation is based on elf32-mips architecture */ - -static asection cr16c_elf_fcom_section; -static asymbol cr16c_elf_fcom_symbol; -static asymbol * cr16c_elf_fcom_symbol_ptr; -static asection cr16c_elf_ncom_section; -static asymbol cr16c_elf_ncom_symbol; -static asymbol * cr16c_elf_ncom_symbol_ptr; - -/* Given a BFD section, try to locate the - corresponding ELF section index. */ - -static bfd_boolean -elf32_cr16c_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), ".fcommon") == 0) - *retval = SHN_CR16C_FCOMMON; - else if (strcmp (bfd_get_section_name (abfd, sec), ".ncommon") == 0) - *retval = SHN_CR16C_NCOMMON; - else - return FALSE; - - return TRUE; -} - -/* Handle the special CR16C section numbers that a symbol may use. */ - -static void -elf32_cr16c_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, - asymbol *asym) -{ - elf_symbol_type *elfsym = (elf_symbol_type *) asym; - unsigned int indx; - - indx = elfsym->internal_elf_sym.st_shndx; - - switch (indx) - { - case SHN_CR16C_FCOMMON: - if (cr16c_elf_fcom_section.name == NULL) - { - /* Initialize the far common section. */ - cr16c_elf_fcom_section.name = ".fcommon"; - cr16c_elf_fcom_section.flags = SEC_IS_COMMON | SEC_ALLOC; - cr16c_elf_fcom_section.output_section = &cr16c_elf_fcom_section; - cr16c_elf_fcom_section.symbol = &cr16c_elf_fcom_symbol; - cr16c_elf_fcom_section.symbol_ptr_ptr = &cr16c_elf_fcom_symbol_ptr; - cr16c_elf_fcom_symbol.name = ".fcommon"; - cr16c_elf_fcom_symbol.flags = BSF_SECTION_SYM; - cr16c_elf_fcom_symbol.section = &cr16c_elf_fcom_section; - cr16c_elf_fcom_symbol_ptr = &cr16c_elf_fcom_symbol; - } - asym->section = &cr16c_elf_fcom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - case SHN_CR16C_NCOMMON: - if (cr16c_elf_ncom_section.name == NULL) - { - /* Initialize the far common section. */ - cr16c_elf_ncom_section.name = ".ncommon"; - cr16c_elf_ncom_section.flags = SEC_IS_COMMON | SEC_ALLOC; - cr16c_elf_ncom_section.output_section = &cr16c_elf_ncom_section; - cr16c_elf_ncom_section.symbol = &cr16c_elf_ncom_symbol; - cr16c_elf_ncom_section.symbol_ptr_ptr = &cr16c_elf_ncom_symbol_ptr; - cr16c_elf_ncom_symbol.name = ".ncommon"; - cr16c_elf_ncom_symbol.flags = BSF_SECTION_SYM; - cr16c_elf_ncom_symbol.section = &cr16c_elf_ncom_section; - cr16c_elf_ncom_symbol_ptr = &cr16c_elf_ncom_symbol; - } - asym->section = &cr16c_elf_ncom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - } -} - -/* Hook called by the linker routine which adds symbols from an object - file. We must handle the special cr16c section numbers here. */ - -static bfd_boolean -elf32_cr16c_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) -{ - unsigned int indx = sym->st_shndx; - - switch (indx) - { - case SHN_CR16C_FCOMMON: - *secp = bfd_make_section_old_way (abfd, ".fcommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - case SHN_CR16C_NCOMMON: - *secp = bfd_make_section_old_way (abfd, ".ncommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - -static int -elf32_cr16c_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - /* If we see a common symbol, which implies a relocatable link, then - if a symbol was in a special common section in an input file, mark - it as a special common in the output file. */ - - if (sym->st_shndx == SHN_COMMON) - { - if (strcmp (input_sec->name, ".fcommon") == 0) - sym->st_shndx = SHN_CR16C_FCOMMON; - else if (strcmp (input_sec->name, ".ncommon") == 0) - sym->st_shndx = SHN_CR16C_NCOMMON; - } - - return 1; -} - -/* Definitions for setting CR16C target vector. */ -#define TARGET_LITTLE_SYM cr16c_elf32_vec -#define TARGET_LITTLE_NAME "elf32-cr16c" -#define ELF_ARCH bfd_arch_cr16c -#define ELF_MACHINE_CODE EM_CR -#define ELF_MAXPAGESIZE 0x1 -#define elf_symbol_leading_char '_' - -#define bfd_elf32_bfd_reloc_type_lookup elf_cr16c_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf_cr16c_reloc_name_lookup -#define elf_info_to_howto elf_cr16c_info_to_howto -#define elf_info_to_howto_rel elf_cr16c_info_to_howto_rel -#define elf_backend_relocate_section elf32_cr16c_relocate_section -#define elf_backend_symbol_processing elf32_cr16c_symbol_processing -#define elf_backend_section_from_bfd_section elf32_cr16c_section_from_bfd_section -#define elf_backend_add_symbol_hook elf32_cr16c_add_symbol_hook -#define elf_backend_link_output_symbol_hook elf32_cr16c_link_output_symbol_hook - -#define elf_backend_can_gc_sections 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-cris.c b/sdcc/support/sdbinutils/bfd/elf32-cris.c deleted file mode 100644 index 4cbe4c59c..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-cris.c +++ /dev/null @@ -1,4179 +0,0 @@ -/* CRIS-specific support for 32-bit ELF. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Axis Communications AB. - Written by Hans-Peter Nilsson, based on elf32-fr30.c - PIC and shlib bits based primarily on elf32-m68k.c and elf32-i386.c. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/cris.h" -#include - -bfd_reloc_status_type -cris_elf_pcrel_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_boolean -cris_elf_set_mach_from_flags (bfd *, unsigned long); - -/* Forward declarations. */ -static reloc_howto_type cris_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_CRIS_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_CRIS_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_8", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_CRIS_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_16", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_CRIS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - /* We don't want overflow complaints for 64-bit vma builds - for e.g. sym+0x40000000 (or actually sym-0xc0000000 in - 32-bit ELF) where sym=0xc0001234. - Don't do this for the PIC relocs, as we don't expect to - see them with large offsets. */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit PC-relative relocation. */ - HOWTO (R_CRIS_8_PCREL, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - cris_elf_pcrel_reloc, /* special_function */ - "R_CRIS_8_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit PC-relative relocation. */ - HOWTO (R_CRIS_16_PCREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - cris_elf_pcrel_reloc, /* special_function */ - "R_CRIS_16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit PC-relative relocation. */ - HOWTO (R_CRIS_32_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - cris_elf_pcrel_reloc, /* special_function */ - "R_CRIS_32_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_CRIS_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_CRIS_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_CRIS_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_CRIS_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_CRIS_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_CRIS_32, but used when setting global offset table entries. */ - HOWTO (R_CRIS_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marks a procedure linkage table entry for a symbol. */ - HOWTO (R_CRIS_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_JUMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_CRIS_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_CRIS_32, but referring to the GOT table entry for the symbol. */ - HOWTO (R_CRIS_16_GOT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_16_GOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRIS_32_GOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_32_GOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_CRIS_32_GOT, but referring to (and requesting a) PLT part of - the GOT table for the symbol. */ - HOWTO (R_CRIS_16_GOTPLT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_16_GOTPLT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRIS_32_GOTPLT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_32_GOTPLT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32-bit offset from GOT to (local const) symbol: no GOT entry should - be necessary. */ - HOWTO (R_CRIS_32_GOTREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_32_GOTREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32-bit offset from GOT to entry for this symbol in PLT and request - to create PLT entry for symbol. */ - HOWTO (R_CRIS_32_PLT_GOTREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRIS_32_PLT_GOTREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32-bit offset from PC (location after the relocation) + addend to - entry for this symbol in PLT and request to create PLT entry for - symbol. */ - HOWTO (R_CRIS_32_PLT_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - cris_elf_pcrel_reloc, /* special_function */ - "R_CRIS_32_PLT_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* We don't handle these in any special manner and cross-format - linking is not supported; just recognize them enough to pass them - around. FIXME: do the same for most PIC relocs and add sanity - tests to actually refuse gracefully to handle these and PIC - relocs for cross-format linking. */ -#define TLSHOWTO32(name) \ - HOWTO (name, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, \ - bfd_elf_generic_reloc, #name, FALSE, 0, 0xffffffff, FALSE) -#define TLSHOWTO16X(name, X) \ - HOWTO (name, 0, 1, 16, FALSE, 0, complain_overflow_ ## X, \ - bfd_elf_generic_reloc, #name, FALSE, 0, 0xffff, FALSE) -#define TLSHOWTO16(name) TLSHOWTO16X(name, unsigned) -#define TLSHOWTO16S(name) TLSHOWTO16X(name, signed) - - TLSHOWTO32 (R_CRIS_32_GOT_GD), - TLSHOWTO16 (R_CRIS_16_GOT_GD), - TLSHOWTO32 (R_CRIS_32_GD), - TLSHOWTO32 (R_CRIS_DTP), - TLSHOWTO32 (R_CRIS_32_DTPREL), - TLSHOWTO16S (R_CRIS_16_DTPREL), - TLSHOWTO32 (R_CRIS_32_GOT_TPREL), - TLSHOWTO16S (R_CRIS_16_GOT_TPREL), - TLSHOWTO32 (R_CRIS_32_TPREL), - TLSHOWTO16S (R_CRIS_16_TPREL), - TLSHOWTO32 (R_CRIS_DTPMOD), - TLSHOWTO32 (R_CRIS_32_IE) -}; - -/* Map BFD reloc types to CRIS ELF reloc types. */ - -struct cris_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int cris_reloc_val; -}; - -static const struct cris_reloc_map cris_reloc_map [] = -{ - { BFD_RELOC_NONE, R_CRIS_NONE }, - { BFD_RELOC_8, R_CRIS_8 }, - { BFD_RELOC_16, R_CRIS_16 }, - { BFD_RELOC_32, R_CRIS_32 }, - { BFD_RELOC_8_PCREL, R_CRIS_8_PCREL }, - { BFD_RELOC_16_PCREL, R_CRIS_16_PCREL }, - { BFD_RELOC_32_PCREL, R_CRIS_32_PCREL }, - { BFD_RELOC_VTABLE_INHERIT, R_CRIS_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_CRIS_GNU_VTENTRY }, - { BFD_RELOC_CRIS_COPY, R_CRIS_COPY }, - { BFD_RELOC_CRIS_GLOB_DAT, R_CRIS_GLOB_DAT }, - { BFD_RELOC_CRIS_JUMP_SLOT, R_CRIS_JUMP_SLOT }, - { BFD_RELOC_CRIS_RELATIVE, R_CRIS_RELATIVE }, - { BFD_RELOC_CRIS_16_GOT, R_CRIS_16_GOT }, - { BFD_RELOC_CRIS_32_GOT, R_CRIS_32_GOT }, - { BFD_RELOC_CRIS_16_GOTPLT, R_CRIS_16_GOTPLT }, - { BFD_RELOC_CRIS_32_GOTPLT, R_CRIS_32_GOTPLT }, - { BFD_RELOC_CRIS_32_GOTREL, R_CRIS_32_GOTREL }, - { BFD_RELOC_CRIS_32_PLT_GOTREL, R_CRIS_32_PLT_GOTREL }, - { BFD_RELOC_CRIS_32_PLT_PCREL, R_CRIS_32_PLT_PCREL }, - { BFD_RELOC_CRIS_32_GOT_GD, R_CRIS_32_GOT_GD }, - { BFD_RELOC_CRIS_16_GOT_GD, R_CRIS_16_GOT_GD }, - { BFD_RELOC_CRIS_32_GD, R_CRIS_32_GD }, - { BFD_RELOC_CRIS_DTP, R_CRIS_DTP }, - { BFD_RELOC_CRIS_32_DTPREL, R_CRIS_32_DTPREL }, - { BFD_RELOC_CRIS_16_DTPREL, R_CRIS_16_DTPREL }, - { BFD_RELOC_CRIS_32_GOT_TPREL, R_CRIS_32_GOT_TPREL }, - { BFD_RELOC_CRIS_16_GOT_TPREL, R_CRIS_16_GOT_TPREL }, - { BFD_RELOC_CRIS_32_TPREL, R_CRIS_32_TPREL }, - { BFD_RELOC_CRIS_16_TPREL, R_CRIS_16_TPREL }, - { BFD_RELOC_CRIS_DTPMOD, R_CRIS_DTPMOD }, - { BFD_RELOC_CRIS_32_IE, R_CRIS_32_IE } -}; - -static reloc_howto_type * -cris_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (cris_reloc_map) / sizeof (cris_reloc_map[0]); i++) - if (cris_reloc_map [i].bfd_reloc_val == code) - return & cris_elf_howto_table [cris_reloc_map[i].cris_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -cris_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (cris_elf_howto_table) / sizeof (cris_elf_howto_table[0]); - i++) - if (cris_elf_howto_table[i].name != NULL - && strcasecmp (cris_elf_howto_table[i].name, r_name) == 0) - return &cris_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an CRIS ELF reloc. */ - -static void -cris_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - enum elf_cris_reloc_type r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_CRIS_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid CRIS reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & cris_elf_howto_table [r_type]; -} - -bfd_reloc_status_type -cris_elf_pcrel_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) -{ - /* By default (using only bfd_elf_generic_reloc when linking to - non-ELF formats) PC-relative relocs are relative to the beginning - of the reloc. CRIS PC-relative relocs are relative to the position - *after* the reloc because that's what pre-CRISv32 PC points to - after reading an insn field with that reloc. (For CRISv32, PC is - actually relative to the start of the insn, but we keep the old - definition.) Still, we use as much generic machinery as we can. - - Only adjust when doing a final link. */ - if (output_bfd == (bfd *) NULL) - reloc_entry->addend -= 1 << reloc_entry->howto->size; - - return - bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - -/* Support for core dump NOTE sections. - The slightly unintuitive code layout is an attempt to keep at least - some similarities with other ports, hoping to simplify general - changes, while still keeping Linux/CRIS and Linux/CRISv32 code apart. */ - -static bfd_boolean -cris_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - if (bfd_get_mach (abfd) == bfd_mach_cris_v32) - switch (note->descsz) - { - default: - return FALSE; - - case 202: /* Linux/CRISv32 */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 22); - - /* pr_reg */ - offset = 70; - size = 128; - - break; - } - else - switch (note->descsz) - { - default: - return FALSE; - - case 214: /* Linux/CRIS */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 22); - - /* pr_reg */ - offset = 70; - size = 140; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -cris_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - if (bfd_get_mach (abfd) == bfd_mach_cris_v32) - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/CRISv32 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); - } - else - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/CRIS 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; -} - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -/* The size in bytes of an entry in the procedure linkage table. */ - -#define PLT_ENTRY_SIZE 20 -#define PLT_ENTRY_SIZE_V32 26 - -/* The first entry in an absolute procedure linkage table looks like this. */ - -static const bfd_byte elf_cris_plt0_entry[PLT_ENTRY_SIZE] = -{ - 0xfc, 0xe1, - 0x7e, 0x7e, /* push mof. */ - 0x7f, 0x0d, /* (dip [pc+]) */ - 0, 0, 0, 0, /* Replaced with address of .got + 4. */ - 0x30, 0x7a, /* move [...],mof */ - 0x7f, 0x0d, /* (dip [pc+]) */ - 0, 0, 0, 0, /* Replaced with address of .got + 8. */ - 0x30, 0x09 /* jump [...] */ -}; - -static const bfd_byte elf_cris_plt0_entry_v32[PLT_ENTRY_SIZE_V32] = -{ - 0x84, 0xe2, /* subq 4,$sp */ - 0x6f, 0xfe, /* move.d 0,$acr */ - 0, 0, 0, 0, /* Replaced by address of .got + 4. */ - 0x7e, 0x7a, /* move $mof,[$sp] */ - 0x3f, 0x7a, /* move [$acr],$mof */ - 0x04, 0xf2, /* addq 4,acr */ - 0x6f, 0xfa, /* move.d [$acr],$acr */ - 0xbf, 0x09, /* jump $acr */ - 0xb0, 0x05, /* nop */ - 0, 0 /* Pad out to 26 bytes. */ -}; - -/* Subsequent entries in an absolute procedure linkage table look like - this. */ - -static const bfd_byte elf_cris_plt_entry[PLT_ENTRY_SIZE] = -{ - 0x7f, 0x0d, /* (dip [pc+]) */ - 0, 0, 0, 0, /* Replaced with address of this symbol in .got. */ - 0x30, 0x09, /* jump [...] */ - 0x3f, 0x7e, /* move [pc+],mof */ - 0, 0, 0, 0, /* Replaced with offset into relocation table. */ - 0x2f, 0xfe, /* add.d [pc+],pc */ - 0xec, 0xff, - 0xff, 0xff /* Replaced with offset to start of .plt. */ -}; - -static const bfd_byte elf_cris_plt_entry_v32[PLT_ENTRY_SIZE_V32] = -{ - 0x6f, 0xfe, /* move.d 0,$acr */ - 0, 0, 0, 0, /* Replaced with address of this symbol in .got. */ - 0x6f, 0xfa, /* move.d [$acr],$acr */ - 0xbf, 0x09, /* jump $acr */ - 0xb0, 0x05, /* nop */ - 0x3f, 0x7e, /* move 0,mof */ - 0, 0, 0, 0, /* Replaced with offset into relocation table. */ - 0xbf, 0x0e, /* ba start_of_plt0_entry */ - 0, 0, 0, 0, /* Replaced with offset to plt0 entry. */ - 0xb0, 0x05 /* nop */ -}; - -/* The first entry in a PIC procedure linkage table looks like this. */ - -static const bfd_byte elf_cris_pic_plt0_entry[PLT_ENTRY_SIZE] = -{ - 0xfc, 0xe1, 0x7e, 0x7e, /* push mof */ - 0x04, 0x01, 0x30, 0x7a, /* move [r0+4],mof */ - 0x08, 0x01, 0x30, 0x09, /* jump [r0+8] */ - 0, 0, 0, 0, 0, 0, 0, 0, /* Pad out to 20 bytes. */ -}; - -static const bfd_byte elf_cris_pic_plt0_entry_v32[PLT_ENTRY_SIZE_V32] = -{ - 0x84, 0xe2, /* subq 4,$sp */ - 0x04, 0x01, /* addoq 4,$r0,$acr */ - 0x7e, 0x7a, /* move $mof,[$sp] */ - 0x3f, 0x7a, /* move [$acr],$mof */ - 0x04, 0xf2, /* addq 4,$acr */ - 0x6f, 0xfa, /* move.d [$acr],$acr */ - 0xbf, 0x09, /* jump $acr */ - 0xb0, 0x05, /* nop */ - 0, 0, /* Pad out to 26 bytes. */ - 0, 0, 0, 0, - 0, 0, 0, 0 -}; - -/* Subsequent entries in a PIC procedure linkage table look like this. */ - -static const bfd_byte elf_cris_pic_plt_entry[PLT_ENTRY_SIZE] = -{ - 0x6f, 0x0d, /* (bdap [pc+].d,r0) */ - 0, 0, 0, 0, /* Replaced with offset of this symbol in .got. */ - 0x30, 0x09, /* jump [...] */ - 0x3f, 0x7e, /* move [pc+],mof */ - 0, 0, 0, 0, /* Replaced with offset into relocation table. */ - 0x2f, 0xfe, /* add.d [pc+],pc */ - 0xec, 0xff, /* Replaced with offset to start of .plt. */ - 0xff, 0xff -}; - -static const bfd_byte elf_cris_pic_plt_entry_v32[PLT_ENTRY_SIZE_V32] = -{ - 0x6f, 0x0d, /* addo.d 0,$r0,$acr */ - 0, 0, 0, 0, /* Replaced with offset of this symbol in .got. */ - 0x6f, 0xfa, /* move.d [$acr],$acr */ - 0xbf, 0x09, /* jump $acr */ - 0xb0, 0x05, /* nop */ - 0x3f, 0x7e, /* move relocoffs,$mof */ - 0, 0, 0, 0, /* Replaced with offset into relocation table. */ - 0xbf, 0x0e, /* ba start_of_plt */ - 0, 0, 0, 0, /* Replaced with offset to start of .plt. */ - 0xb0, 0x05 /* nop */ -}; - -/* We copy elf32-m68k.c and elf32-i386.c for the basic linker hash bits - (and most other PIC/shlib stuff). Check that we don't drift away - without reason. - - The CRIS linker, like the m68k and i386 linkers (and probably the rest - too) needs to keep track of the number of relocs that it decides to - copy in check_relocs for each symbol. This is so that it can discard - PC relative relocs if it doesn't need them when linking with - -Bsymbolic. We store the information in a field extending the regular - ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we have - copied for a given symbol. */ - -struct elf_cris_pcrel_relocs_copied -{ - /* Next section. */ - struct elf_cris_pcrel_relocs_copied *next; - - /* A section in dynobj. */ - asection *section; - - /* Number of relocs copied in this section. */ - bfd_size_type count; - - /* Example of reloc being copied, for message. */ - enum elf_cris_reloc_type r_type; -}; - -/* CRIS ELF linker hash entry. */ - -struct elf_cris_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Number of PC relative relocs copied for this symbol. */ - struct elf_cris_pcrel_relocs_copied *pcrel_relocs_copied; - - /* The GOTPLT references are CRIS-specific; the goal is to avoid having - both a general GOT and a PLT-specific GOT entry for the same symbol, - when it is referenced both as a function and as a function pointer. - - Number of GOTPLT references for a function. */ - bfd_signed_vma gotplt_refcount; - - /* Actual GOTPLT index for this symbol, if applicable, or zero if not - (zero is never used as an index). FIXME: We should be able to fold - this with gotplt_refcount in a union, like the got and plt unions in - elf_link_hash_entry. */ - bfd_size_type gotplt_offset; - - /* The root.got.refcount is the sum of the regular reference counts - (this) and those members below. We have to keep a separate count - to track when we've found the first (or last) reference to a - regular got entry. The offset is in root.got.offset. */ - bfd_signed_vma reg_got_refcount; - - /* Similar to the above, the number of reloc references to this - symbols that need a R_CRIS_32_TPREL slot. The offset is in - root.got.offset, because this and .dtp_refcount can't validly - happen when there's also a regular GOT entry; that's invalid - input for which an error is emitted. */ - bfd_signed_vma tprel_refcount; - - /* Similar to the above, the number of reloc references to this - symbols that need a R_CRIS_DTP slot. The offset is in - root.got.offset; plus 4 if .tprel_refcount > 0. */ - bfd_signed_vma dtp_refcount; -}; - -static bfd_boolean -elf_cris_discard_excess_dso_dynamics (struct elf_cris_link_hash_entry *, - void * ); -static bfd_boolean -elf_cris_discard_excess_program_dynamics (struct elf_cris_link_hash_entry *, - void *); - -/* The local_got_refcounts and local_got_offsets are a multiple of - LSNUM in size, namely LGOT_ALLOC_NELTS_FOR(LSNUM) (plus one for the - refcount for GOT itself, see code), with the summary / group offset - for local symbols located at offset N, reference counts for - ordinary (address) relocs at offset N + LSNUM, for R_CRIS_DTP - relocs at offset N + 2*LSNUM, and for R_CRIS_32_TPREL relocs at N + - 3*LSNUM. */ - -#define LGOT_REG_NDX(x) ((x) + symtab_hdr->sh_info) -#define LGOT_DTP_NDX(x) ((x) + 2 * symtab_hdr->sh_info) -#define LGOT_TPREL_NDX(x) ((x) + 3 * symtab_hdr->sh_info) -#define LGOT_ALLOC_NELTS_FOR(x) ((x) * 4) - -/* CRIS ELF linker hash table. */ - -struct elf_cris_link_hash_table -{ - struct elf_link_hash_table root; - - /* We can't use the PLT offset and calculate to get the GOTPLT offset, - since we try and avoid creating GOTPLT:s when there's already a GOT. - Instead, we keep and update the next available index here. */ - bfd_size_type next_gotplt_entry; - - /* The number of R_CRIS_32_DTPREL and R_CRIS_16_DTPREL that have - been seen for any input; if != 0, then the constant-offset - R_CRIS_DTPMOD is needed for this DSO/executable. This turns - negative at relocation, so that we don't need an extra flag for - when the reloc is output. */ - bfd_signed_vma dtpmod_refcount; -}; - -/* Traverse a CRIS ELF linker hash table. */ - -#define elf_cris_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* Get the CRIS ELF linker hash table from a link_info structure. */ - -#define elf_cris_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == CRIS_ELF_DATA ? ((struct elf_cris_link_hash_table *) ((p)->hash)) : NULL) - -/* Get the CRIS ELF linker hash entry from a regular hash entry (the - "parent class"). The .root reference is just a simple type - check on the argument. */ - -#define elf_cris_hash_entry(p) \ - ((struct elf_cris_link_hash_entry *) (&(p)->root)) - -/* Create an entry in a CRIS ELF linker hash table. */ - -static struct bfd_hash_entry * -elf_cris_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_cris_link_hash_entry *ret = - (struct elf_cris_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct elf_cris_link_hash_entry *) NULL) - ret = ((struct elf_cris_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_cris_link_hash_entry))); - if (ret == (struct elf_cris_link_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_cris_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != (struct elf_cris_link_hash_entry *) NULL) - { - ret->pcrel_relocs_copied = NULL; - ret->gotplt_refcount = 0; - ret->gotplt_offset = 0; - ret->dtp_refcount = 0; - ret->tprel_refcount = 0; - ret->reg_got_refcount = 0; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create a CRIS ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf_cris_link_hash_table_create (bfd *abfd) -{ - struct elf_cris_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_cris_link_hash_table); - - ret = ((struct elf_cris_link_hash_table *) bfd_zmalloc (amt)); - if (ret == (struct elf_cris_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - elf_cris_link_hash_newfunc, - sizeof (struct elf_cris_link_hash_entry), - CRIS_ELF_DATA)) - { - free (ret); - return NULL; - } - - /* Initialize to skip over the first three entries in the gotplt; they - are used for run-time symbol evaluation. */ - ret->next_gotplt_entry = 12; - - return &ret->root.root; -} - -/* Perform a single relocation. By default we use the standard BFD - routines, with a few tweaks. */ - -static bfd_reloc_status_type -cris_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation) -{ - bfd_reloc_status_type r; - enum elf_cris_reloc_type r_type = ELF32_R_TYPE (rel->r_info); - - /* PC-relative relocations are relative to the position *after* - the reloc. Note that for R_CRIS_8_PCREL the adjustment is - not a single byte, since PC must be 16-bit-aligned. */ - switch (r_type) - { - /* Check that the 16-bit GOT relocs are positive. */ - case R_CRIS_16_GOTPLT: - case R_CRIS_16_GOT: - if ((bfd_signed_vma) relocation < 0) - return bfd_reloc_overflow; - break; - - case R_CRIS_32_PLT_PCREL: - case R_CRIS_32_PCREL: - relocation -= 2; - /* Fall through. */ - case R_CRIS_8_PCREL: - case R_CRIS_16_PCREL: - relocation -= 2; - break; - - default: - break; - } - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - return r; -} - - -/* The number of errors left before we stop outputting reloc-specific - explanatory messages. By coincidence, this works nicely together - with the default number of messages you'll get from LD about - "relocation truncated to fit" messages before you get an - "additional relocation overflows omitted from the output". */ -static int additional_relocation_error_msg_count = 10; - -/* Relocate an CRIS ELF section. See elf32-fr30.c, from where this was - copied, for further comments. */ - -static bfd_boolean -cris_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - struct elf_cris_link_hash_table * htab; - bfd *dynobj; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - asection *sgot; - asection *splt; - asection *sreloc; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - asection *srelgot; - - htab = elf_cris_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - local_got_offsets = elf_local_got_offsets (input_bfd); - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - sgot = NULL; - splt = NULL; - sreloc = NULL; - srelgot = NULL; - - if (dynobj != NULL) - { - splt = htab->root.splt; - sgot = htab->root.sgot; - } - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *symname = NULL; - enum elf_cris_reloc_type r_type; - bfd_boolean resolved_to_zero; - - r_type = ELF32_R_TYPE (rel->r_info); - - if ( r_type == R_CRIS_GNU_VTINHERIT - || r_type == R_CRIS_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - howto = cris_elf_howto_table + r_type; - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - symname = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (symname == NULL) - symname = bfd_section_name (input_bfd, sec); - } - else - { - bfd_boolean warned, ignored; - bfd_boolean unresolved_reloc; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - symname = h->root.root.string; - - if (unresolved_reloc - /* Perhaps we should detect the cases that - sec->output_section is expected to be NULL like i386 and - m68k, but apparently (and according to elfxx-ia64.c) all - valid cases are where the symbol is defined in a shared - object which we link dynamically against. This includes - PLT relocs for which we've created a PLT entry and other - relocs for which we're prepared to create dynamic - relocations. - - For now, new situations cause us to just err when - sec->output_offset is NULL but the object with the symbol - is *not* dynamically linked against. Thus this will - automatically remind us so we can see if there are other - valid cases we need to revisit. */ - && (sec->owner->flags & DYNAMIC) != 0) - relocation = 0; - - else if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - /* Here follow the cases where the relocation value must - be zero (or when further handling is simplified when - zero). I can't claim to understand the various - conditions and they weren't described in the files - where I copied them from (elf32-m68k.c and - elf32-i386.c), but let's mention examples of where - they happen. FIXME: Perhaps define and use a - dynamic_symbol_p function like ia64. - - - When creating a shared library, we can have an - ordinary relocation for a symbol defined in a shared - library (perhaps the one we create). We then make - the relocation value zero, as the value seen now will - be added into the relocation addend in this shared - library, but must be handled only at dynamic-link - time. FIXME: Not sure this example covers the - h->elf_link_hash_flags test, though it's there in - other targets. */ - if (bfd_link_pic (info) - && ((!SYMBOLIC_BIND (info, h) && h->dynindx != -1) - || !h->def_regular) - && (input_section->flags & SEC_ALLOC) != 0 - && (r_type == R_CRIS_8 - || r_type == R_CRIS_16 - || r_type == R_CRIS_32 - || r_type == R_CRIS_8_PCREL - || r_type == R_CRIS_16_PCREL - || r_type == R_CRIS_32_PCREL)) - relocation = 0; - else if (!bfd_link_relocatable (info) && unresolved_reloc - && (_bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset) - != (bfd_vma) -1)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: unresolvable relocation %s against symbol `%s'"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - symname); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch (r_type) - { - case R_CRIS_16_GOTPLT: - case R_CRIS_32_GOTPLT: - /* This is like the case for R_CRIS_32_GOT and R_CRIS_16_GOT, - but we require a PLT, and the PLT handling will take care of - filling in the PLT-specific GOT entry. For the GOT offset, - calculate it as we do when filling it in for the .got.plt - section. If we don't have a PLT, punt to GOT handling. */ - if (h != NULL - && ((struct elf_cris_link_hash_entry *) h)->gotplt_offset != 0) - { - asection *sgotplt = htab->root.sgotplt; - bfd_vma got_offset; - - BFD_ASSERT (h->dynindx != -1); - BFD_ASSERT (sgotplt != NULL); - - got_offset - = ((struct elf_cris_link_hash_entry *) h)->gotplt_offset; - - relocation = got_offset; - break; - } - - /* We didn't make a PLT entry for this symbol. Maybe everything is - folded into the GOT. Other than folding, this happens when - statically linking PIC code, or when using -Bsymbolic. Check - that we instead have a GOT entry as done for us by - elf_cris_adjust_dynamic_symbol, and drop through into the - ordinary GOT cases. This must not happen for the - executable, because any reference it does to a function - that is satisfied by a DSO must generate a PLT. We assume - these call-specific relocs don't address non-functions. */ - if (h != NULL - && (h->got.offset == (bfd_vma) -1 - || (!bfd_link_pic (info) - && !(h->def_regular - || (!h->def_dynamic - && h->root.type == bfd_link_hash_undefweak))))) - { - _bfd_error_handler - ((h->got.offset == (bfd_vma) -1) - /* xgettext:c-format */ - ? _("%B, section %A: No PLT nor GOT for relocation %s" - " against symbol `%s'") - /* xgettext:c-format */ - : _("%B, section %A: No PLT for relocation %s" - " against symbol `%s'"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - (symname != NULL && symname[0] != '\0' - ? symname : _("[whose name is lost]"))); - - /* FIXME: Perhaps blaming input is not the right thing to - do; this is probably an internal error. But it is true - that we didn't like that particular input. */ - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - /* Fall through. */ - - /* The size of the actual relocation is not used here; we only - fill in the GOT table here. */ - case R_CRIS_16_GOT: - case R_CRIS_32_GOT: - { - bfd_vma off; - - /* Note that despite using RELA relocations, the .got contents - is always filled in with the link-relative relocation - value; the addend. */ - - if (h != NULL) - { - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - if (!elf_hash_table (info)->dynamic_sections_created - || (! bfd_link_pic (info) - && (h->def_regular - || h->type == STT_FUNC - || h->needs_plt)) - || (bfd_link_pic (info) - && (SYMBOLIC_BIND (info, h) || h->dynindx == -1) - && h->def_regular)) - { - /* This wasn't checked above for ! bfd_link_pic (info), but - must hold there if we get here; the symbol must - be defined in the regular program or be undefweak - or be a function or otherwise need a PLT. */ - BFD_ASSERT (!elf_hash_table (info)->dynamic_sections_created - || bfd_link_pic (info) - || h->def_regular - || h->type == STT_FUNC - || h->needs_plt - || 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 is undefweak, or the symbol was forced to be - local because of a version file, or we're not - creating a dynamic object. 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. - - If this GOT entry should be runtime-initialized, we - will create a .rela.got relocation entry to - initialize the value. This is done in the - finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; - } - } - } - else - { - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already generated the necessary reloc. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - - local_got_offsets[r_symndx] |= 1; - } - } - - relocation = sgot->output_offset + off; - if (rel->r_addend != 0) - { - /* We can't do anything for a relocation which is against - a symbol *plus offset*. GOT holds relocations for - symbols. Make this an error; the compiler isn't - allowed to pass us these kinds of things. */ - if (h == NULL) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with non-zero addend %Ld" - " against local symbol"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - rel->r_addend); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with non-zero addend %Ld" - " against symbol `%s'"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - rel->r_addend, - symname[0] != '\0' ? symname : _("[whose name is lost]")); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - break; - - case R_CRIS_32_GOTREL: - /* This relocation must only be performed against local symbols. - It's also ok when we link a program and the symbol is either - defined in an ordinary (non-DSO) object or is undefined weak. */ - if (h != NULL - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !(!bfd_link_pic (info) - && (h->def_regular - || (!h->def_dynamic - && h->root.type == bfd_link_hash_undefweak)))) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s is" - " not allowed for global symbol: `%s'"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - symname); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* This can happen if we get a link error with the input ELF - variant mismatching the output variant. Emit an error so - it's noticed if it happens elsewhere. */ - if (sgot == NULL) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with no GOT created"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* This relocation is like a PC-relative one, except the - reference point is the location of GOT. Note that - sgot->output_offset is not involved in this calculation. We - always want the start of entire .got section, not the - position after the reserved header. */ - relocation -= sgot->output_section->vma; - break; - - case R_CRIS_32_PLT_PCREL: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* Resolve a PLT_PCREL reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - break; - - if (h->plt.offset == (bfd_vma) -1 - || 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 = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - break; - - case R_CRIS_32_PLT_GOTREL: - /* Like R_CRIS_32_PLT_PCREL, but the reference point is the - start of the .got section. See also comment at - R_CRIS_32_GOT. */ - relocation -= sgot->output_section->vma; - - /* Resolve a PLT_GOTREL reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - break; - - if (h->plt.offset == (bfd_vma) -1 - || 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 = (splt->output_section->vma - + splt->output_offset - + h->plt.offset - - sgot->output_section->vma); - break; - - case R_CRIS_8_PCREL: - case R_CRIS_16_PCREL: - case R_CRIS_32_PCREL: - /* If the symbol was local, we need no shlib-specific handling. */ - if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || h->dynindx == -1) - break; - - /* Fall through. */ - case R_CRIS_8: - case R_CRIS_16: - case R_CRIS_32: - if (bfd_link_pic (info) - && !resolved_to_zero - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0 - && ((r_type != R_CRIS_8_PCREL - && r_type != R_CRIS_16_PCREL - && r_type != R_CRIS_32_PCREL) - || (!SYMBOLIC_BIND (info, h) - || (h != NULL && !h->def_regular)))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip, relocate; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (dynobj, input_section, /*rela?*/ TRUE); - /* The section should have been created in cris_elf_check_relocs, - but that function will not be called for objects which fail in - cris_elf_merge_private_bfd_data. */ - if (sreloc == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - 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 - /* For now, undefined weak symbols with non-default - visibility (yielding 0), like exception info for - discarded sections, will get a R_CRIS_NONE - relocation rather than no relocation, because we - notice too late that the symbol doesn't need a - relocation. */ - || (h != NULL - && h->root.type == bfd_link_hash_undefweak - && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)) - 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 the symbol was marked to - become local. */ - else if (h != NULL - && ((!SYMBOLIC_BIND (info, h) && h->dynindx != -1) - || !h->def_regular)) - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - outrel.r_addend = relocation + rel->r_addend; - - if (r_type == R_CRIS_32) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE); - } - else - { - long indx; - - if (bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. */ - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - if (indx == 0) - { - osec = htab->root.text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - /* This reloc will be computed at runtime, so there's no - need to do anything now, except for R_CRIS_32 relocations - that have been turned into R_CRIS_RELATIVE. */ - if (!relocate) - continue; - } - - break; - - case R_CRIS_16_DTPREL: - case R_CRIS_32_DTPREL: - /* This relocation must only be performed against local - symbols, or to sections that are not loadable. It's also - ok when we link a program and the symbol is defined in an - ordinary (non-DSO) object (if it's undefined there, we've - already seen an error). */ - if (h != NULL - && (input_section->flags & SEC_ALLOC) != 0 - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && (bfd_link_pic (info) - || (!h->def_regular - && h->root.type != bfd_link_hash_undefined))) - { - _bfd_error_handler - ((h->root.type == bfd_link_hash_undefined) - /* We shouldn't get here for GCC-emitted code. */ - /* xgettext:c-format */ - ? _("%B, section %A: relocation %s has an undefined" - " reference to `%s', perhaps a declaration mixup?") - /* xgettext:c-format */ - : _("%B, section %A: relocation %s is" - " not allowed for `%s', a global symbol with default" - " visibility, perhaps a declaration mixup?"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - symname != NULL && symname[0] != '\0' - ? symname : _("[whose name is lost]")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - BFD_ASSERT ((input_section->flags & SEC_ALLOC) == 0 - || htab->dtpmod_refcount != 0); - - /* Fill in a R_CRIS_DTPMOD reloc at offset 3 if we haven't - already done so. Note that we do this in .got.plt, not - in .got, as .got.plt contains the first part, still the - reloc is against .got, because the linker script directs - (is required to direct) them both into .got. */ - if (htab->dtpmod_refcount > 0 - && (input_section->flags & SEC_ALLOC) != 0) - { - asection *sgotplt = htab->root.sgotplt; - BFD_ASSERT (sgotplt != NULL); - - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 12); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 16); - outrel.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset - + 12); - outrel.r_info = ELF32_R_INFO (0, R_CRIS_DTPMOD); - outrel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - { - /* For an executable, the GOT entry contents is known. */ - bfd_put_32 (output_bfd, (bfd_vma) 1, sgotplt->contents + 12); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 16); - } - - /* Reverse the sign to mark that we've emitted the - required GOT entry. */ - htab->dtpmod_refcount = - htab->dtpmod_refcount; - } - - /* The relocation is the offset from the start of the module - TLS block to the (local) symbol. */ - relocation -= elf_hash_table (info)->tls_sec == NULL - ? 0 : elf_hash_table (info)->tls_sec->vma; - break; - - case R_CRIS_32_GD: - if (bfd_link_pic (info)) - { - bfd_set_error (bfd_error_invalid_operation); - - /* We've already informed in cris_elf_check_relocs that - this is an error. */ - return FALSE; - } - /* Fall through. */ - - case R_CRIS_16_GOT_GD: - case R_CRIS_32_GOT_GD: - if (rel->r_addend != 0) - { - /* We can't do anything for a relocation which is against a - symbol *plus offset*. The GOT holds relocations for - symbols. Make this an error; the compiler isn't allowed - to pass us these kinds of things. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with non-zero addend %Ld" - " against symbol `%s'"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - rel->r_addend, - symname[0] != '\0' ? symname : _("[whose name is lost]")); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (!bfd_link_pic (info) - && (h == NULL || h->def_regular || ELF_COMMON_DEF_P (h))) - { - /* Known contents of the GOT. */ - bfd_vma off; - - /* The symbol is defined in the program, so just write - (1, known_tpoffset) into the GOT. */ - relocation -= elf_hash_table (info)->tls_sec->vma; - - if (h != NULL) - { - off = elf_cris_hash_entry (h)->tprel_refcount > 0 - ? h->got.offset + 4 : h->got.offset; - } - else - { - off = local_got_offsets[r_symndx]; - if (local_got_offsets[LGOT_TPREL_NDX (r_symndx)]) - off += 4; - } - - /* We use bit 1 of the offset as a flag for GOT entry with - the R_CRIS_DTP reloc, setting it when we've emitted the - GOT entry and reloc. Bit 0 is used for R_CRIS_32_TPREL - relocs. */ - if ((off & 2) == 0) - { - off &= ~3; - - if (h != NULL) - h->got.offset |= 2; - else - local_got_offsets[r_symndx] |= 2; - - bfd_put_32 (output_bfd, 1, sgot->contents + off); - bfd_put_32 (output_bfd, relocation, sgot->contents + off + 4); - } - else - off &= ~3; - - relocation = sgot->output_offset + off - + (r_type == R_CRIS_32_GD ? sgot->output_section->vma : 0); - } - else - { - /* Not all parts of the GOT entry are known; emit a real - relocation. */ - bfd_vma off; - - if (h != NULL) - off = elf_cris_hash_entry (h)->tprel_refcount > 0 - ? h->got.offset + 4 : h->got.offset; - else - { - off = local_got_offsets[r_symndx]; - if (local_got_offsets[LGOT_TPREL_NDX (r_symndx)]) - off += 4; - } - - /* See above re bit 1 and bit 0 usage. */ - if ((off & 2) == 0) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - off &= ~3; - - if (h != NULL) - h->got.offset |= 2; - else - local_got_offsets[r_symndx] |= 2; - - /* Clear the target contents of the GOT (just as a - gesture; it's already cleared on allocation): this - relocation is not like the other dynrelocs. */ - bfd_put_32 (output_bfd, 0, sgot->contents + off); - bfd_put_32 (output_bfd, 0, sgot->contents + off + 4); - - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - if (h != NULL && h->dynindx != -1) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_DTP); - relocation = 0; - } - else - { - outrel.r_info = ELF32_R_INFO (0, R_CRIS_DTP); - - /* NULL if we had an error. */ - relocation -= elf_hash_table (info)->tls_sec == NULL - ? 0 : elf_hash_table (info)->tls_sec->vma; - } - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - - /* NULL if we had an error. */ - if (srelgot->contents != NULL) - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - off &= ~3; - - relocation = sgot->output_offset + off - + (r_type == R_CRIS_32_GD ? sgot->output_section->vma : 0); - } - - /* The GOT-relative offset to the GOT entry is the - relocation, or for R_CRIS_32_GD, the actual address of - the GOT entry. */ - break; - - case R_CRIS_32_IE: - if (bfd_link_pic (info)) - { - bfd_set_error (bfd_error_invalid_operation); - - /* We've already informed in cris_elf_check_relocs that - this is an error. */ - return FALSE; - } - /* Fall through. */ - - case R_CRIS_32_GOT_TPREL: - case R_CRIS_16_GOT_TPREL: - if (rel->r_addend != 0) - { - /* We can't do anything for a relocation which is - against a symbol *plus offset*. GOT holds - relocations for symbols. Make this an error; the - compiler isn't allowed to pass us these kinds of - things. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with non-zero addend %Ld" - " against symbol `%s'"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - rel->r_addend, - symname[0] != '\0' ? symname : _("[whose name is lost]")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (!bfd_link_pic (info) - && (h == NULL || h->def_regular || ELF_COMMON_DEF_P (h))) - { - /* Known contents of the GOT. */ - bfd_vma off; - - /* The symbol is defined in the program, so just write - the -prog_tls_size+known_tpoffset into the GOT. */ - relocation -= elf_hash_table (info)->tls_sec->vma; - relocation -= elf_hash_table (info)->tls_size; - - if (h != NULL) - off = h->got.offset; - else - off = local_got_offsets[r_symndx]; - - /* Bit 0 is used to mark whether we've emitted the required - entry (and if needed R_CRIS_32_TPREL reloc). Bit 1 - is used similarly for R_CRIS_DTP, see above. */ - if ((off & 1) == 0) - { - off &= ~3; - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - } - else - off &= ~3; - - relocation = sgot->output_offset + off - + (r_type == R_CRIS_32_IE ? sgot->output_section->vma : 0); - } - else - { - /* Emit a real relocation. */ - bfd_vma off; - - if (h != NULL) - off = h->got.offset; - else - off = local_got_offsets[r_symndx]; - - /* See above re usage of bit 0 and 1. */ - if ((off & 1) == 0) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - off &= ~3; - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - if (h != NULL && h->dynindx != -1) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_32_TPREL); - relocation = 0; - } - else - { - outrel.r_info = ELF32_R_INFO (0, R_CRIS_32_TPREL); - - /* NULL if we had an error. */ - relocation -= elf_hash_table (info)->tls_sec == NULL - ? 0 : elf_hash_table (info)->tls_sec->vma; - } - - /* Just "define" the initial contents in some - semi-logical way. */ - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - /* NULL if we had an error. */ - if (srelgot->contents != NULL) - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - off &= ~3; - - relocation = sgot->output_offset + off - + (r_type == R_CRIS_32_IE ? sgot->output_section->vma : 0); - } - - /* The GOT-relative offset to the GOT entry is the relocation, - or for R_CRIS_32_GD, the actual address of the GOT entry. */ - break; - - case R_CRIS_16_TPREL: - case R_CRIS_32_TPREL: - /* This relocation must only be performed against symbols - defined in an ordinary (non-DSO) object. */ - if (bfd_link_pic (info)) - { - bfd_set_error (bfd_error_invalid_operation); - - /* We've already informed in cris_elf_check_relocs that - this is an error. */ - return FALSE; - } - - if (h != NULL - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !(h->def_regular || ELF_COMMON_DEF_P (h)) - /* If it's undefined, then an error message has already - been emitted. */ - && h->root.type != bfd_link_hash_undefined) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s is" - " not allowed for symbol: `%s'" - " which is defined outside the program," - " perhaps a declaration mixup?"), - input_bfd, - input_section, - cris_elf_howto_table[r_type].name, - symname); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* NULL if we had an error. */ - relocation -= elf_hash_table (info)->tls_sec == NULL - ? 0 - : (elf_hash_table (info)->tls_sec->vma - + elf_hash_table (info)->tls_size); - - /* The TLS-relative offset is the relocation. */ - break; - - default: - BFD_FAIL (); - return FALSE; - } - - r = cris_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), symname, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - if (additional_relocation_error_msg_count > 0) - { - additional_relocation_error_msg_count--; - switch (r_type) - { - case R_CRIS_16_GOTPLT: - case R_CRIS_16_GOT: - - /* Not just TLS is involved here, so we make - generation and message depend on -fPIC/-fpic - only. */ - case R_CRIS_16_GOT_TPREL: - case R_CRIS_16_GOT_GD: - _bfd_error_handler - (_("(too many global variables for -fpic:" - " recompile with -fPIC)")); - break; - - case R_CRIS_16_TPREL: - case R_CRIS_16_DTPREL: - _bfd_error_handler - (_("(thread-local data too big for -fpic or" - " -msmall-tls: recompile with -fPIC or" - " -mno-small-tls)")); - break; - - /* No known cause for overflow for other relocs. */ - default: - break; - } - } - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, symname, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, symname, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_cris_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_cris_link_hash_table * htab; - - /* Where in the plt entry to put values. */ - int plt_off1 = 2, plt_off2 = 10, plt_off3 = 16; - - /* What offset to add to the distance to the first PLT entry for the - value at plt_off3. */ - int plt_off3_value_bias = 4; - - /* Where in the PLT entry the call-dynlink-stub is (happens to be same - for PIC and non-PIC for v32 and pre-v32). */ - int plt_stub_offset = 8; - int plt_entry_size = PLT_ENTRY_SIZE; - const bfd_byte *plt_entry = elf_cris_plt_entry; - const bfd_byte *plt_pic_entry = elf_cris_pic_plt_entry; - - htab = elf_cris_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Adjust the various PLT entry offsets. */ - if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32) - { - plt_off2 = 14; - plt_off3 = 20; - plt_off3_value_bias = -2; - plt_stub_offset = 12; - plt_entry_size = PLT_ENTRY_SIZE_V32; - plt_entry = elf_cris_plt_entry_v32; - plt_pic_entry = elf_cris_pic_plt_entry_v32; - } - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgotplt; - asection *srela; - bfd_vma got_base; - - bfd_vma gotplt_offset - = elf_cris_hash_entry (h)->gotplt_offset; - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_boolean has_gotplt = gotplt_offset != 0; - - /* Get the index in the .rela.plt relocations for the .got.plt - entry that corresponds to this symbol. - We have to count backwards here, and the result is only valid - as an index into .rela.plt. We also have to undo the effect - of the R_CRIS_DTPMOD entry at .got index 3 (offset 12 into - .got.plt) for which gotplt_offset is adjusted, because while - that entry goes into .got.plt, its relocation goes into - .rela.got, not .rela.plt. (It's not PLT-specific; not to be - processed as part of the runtime lazy .rela.plt relocation). - FIXME: There be literal constants here... */ - bfd_vma rela_plt_index - = (htab->dtpmod_refcount != 0 - ? gotplt_offset/4 - 2 - 3 : gotplt_offset/4 - 3); - - /* Get the offset into the .got table of the entry that corresponds - to this function. Note that we embed knowledge that "incoming" - .got goes after .got.plt in the output without padding (pointer - aligned). However, that knowledge is present in several other - places too. */ - bfd_vma got_offset - = (has_gotplt - ? gotplt_offset - : h->got.offset + htab->next_gotplt_entry); - - /* This symbol has an entry in the procedure linkage table. Set it - up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgotplt = htab->root.sgotplt; - srela = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgotplt != NULL - && (! has_gotplt || srela != NULL)); - - got_base = sgotplt->output_section->vma + sgotplt->output_offset; - - /* Fill in the entry in the procedure linkage table. */ - if (! bfd_link_pic (info)) - { - memcpy (splt->contents + h->plt.offset, plt_entry, - plt_entry_size); - - /* We need to enter the absolute address of the GOT entry here. */ - bfd_put_32 (output_bfd, got_base + got_offset, - splt->contents + h->plt.offset + plt_off1); - } - else - { - memcpy (splt->contents + h->plt.offset, plt_pic_entry, - plt_entry_size); - bfd_put_32 (output_bfd, got_offset, - splt->contents + h->plt.offset + plt_off1); - } - - /* Fill in the plt entry and make a relocation, if this is a "real" - PLT entry. */ - if (has_gotplt) - { - /* Fill in the offset to the reloc table. */ - bfd_put_32 (output_bfd, - rela_plt_index * sizeof (Elf32_External_Rela), - splt->contents + h->plt.offset + plt_off2); - - /* Fill in the offset to the first PLT entry, where to "jump". */ - bfd_put_32 (output_bfd, - - (h->plt.offset + plt_off3 + plt_off3_value_bias), - splt->contents + h->plt.offset + plt_off3); - - /* Fill in the entry in the global offset table with the address of - the relocating stub. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + plt_stub_offset), - sgotplt->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_JUMP_SLOT); - rela.r_addend = 0; - loc = srela->contents + rela_plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - - /* FIXME: From elf32-sparc.c 2001-02-19 (1.18). I still don't - know whether resetting the value is significant; if it really - is, rather than a quirk or bug in the sparc port, then I - believe we'd see this elsewhere. */ - /* If the symbol is weak, we do need to clear the value. - Otherwise, the PLT entry would provide a definition for - the symbol even if the symbol wasn't defined anywhere, - and so the symbol would never be NULL. */ - if (!h->ref_regular_nonweak) - sym->st_value = 0; - } - } - - /* For an ordinary program, we emit .got relocs only for symbols that - are in the dynamic-symbols table and are either defined by the - program or are undefined weak symbols, or are function symbols - where we do not output a PLT: the PLT reloc was output above and all - references to the function symbol are redirected to the PLT. */ - if (h->got.offset != (bfd_vma) -1 - && (elf_cris_hash_entry (h)->reg_got_refcount > 0) - && (bfd_link_pic (info) - || (h->dynindx != -1 - && h->plt.offset == (bfd_vma) -1 - && !h->def_regular - && h->root.type != bfd_link_hash_undefweak))) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_byte *where; - - /* This symbol has an entry in the global offset table. Set it up. */ - - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + 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. */ - where = sgot->contents + (h->got.offset &~ (bfd_vma) 1); - if (! elf_hash_table (info)->dynamic_sections_created - || (bfd_link_pic (info) - && (SYMBOLIC_BIND (info, h) || h->dynindx == -1) - && h->def_regular)) - { - rela.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE); - rela.r_addend = bfd_get_signed_32 (output_bfd, where); - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, where); - rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_GLOB_DAT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - if (h->root.u.def.section == htab->root.sdynrelro) - s = htab->root.sreldynrelro; - else - s = htab->root.srelbss; - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_COPY); - rela.r_addend = 0; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. Do *not* emit relocs here, as their - offsets were changed, as part of -z combreloc handling, from those we - computed. */ - -static bfd_boolean -elf_cris_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sgot; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - sgot = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgot != NULL); - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - dyn.d_un.d_ptr = sgot->output_section->vma + sgot->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - /* Yes, we *can* have a .plt and no .plt.rela, for instance - if all symbols are found in the .got (not .got.plt). */ - s = elf_hash_table (info)->srelplt; - dyn.d_un.d_ptr = s != NULL ? (s->output_section->vma - + s->output_offset) : 0; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = elf_hash_table (info)->srelplt; - if (s == NULL) - dyn.d_un.d_val = 0; - else - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - if (splt->size > 0) - { - if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32) - { - if (bfd_link_pic (info)) - memcpy (splt->contents, elf_cris_pic_plt0_entry_v32, - PLT_ENTRY_SIZE_V32); - else - { - memcpy (splt->contents, elf_cris_plt0_entry_v32, - PLT_ENTRY_SIZE_V32); - bfd_put_32 (output_bfd, - sgot->output_section->vma - + sgot->output_offset + 4, - splt->contents + 4); - - elf_section_data (splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE_V32; - } - } - else - { - if (bfd_link_pic (info)) - memcpy (splt->contents, elf_cris_pic_plt0_entry, - PLT_ENTRY_SIZE); - else - { - memcpy (splt->contents, elf_cris_plt0_entry, - PLT_ENTRY_SIZE); - bfd_put_32 (output_bfd, - sgot->output_section->vma - + sgot->output_offset + 4, - splt->contents + 6); - bfd_put_32 (output_bfd, - sgot->output_section->vma - + sgot->output_offset + 8, - splt->contents + 14); - - elf_section_data (splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; - } - } - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -cris_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - enum elf_cris_reloc_type r_type = ELF32_R_TYPE (rel->r_info); - if (h != NULL) - switch (r_type) - { - case R_CRIS_GNU_VTINHERIT: - case R_CRIS_GNU_VTENTRY: - return NULL; - - default: - break; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* The elf_backend_plt_sym_val hook function. */ - -static bfd_vma -cris_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, const asection *plt, - const arelent *rel) -{ - bfd_size_type plt_entry_size; - bfd_size_type pltoffs; - bfd *abfd = plt->owner; - - /* Same for CRIS and CRIS v32; see elf_cris_(|pic_)plt_entry(|_v32)[]. */ - bfd_size_type plt_entry_got_offset = 2; - bfd_size_type plt_sec_size; - bfd_size_type got_vma_for_dyn; - asection *got; - - /* FIXME: the .got section should be readily available also when - we're not linking. */ - if ((got = bfd_get_section_by_name (abfd, ".got")) == NULL) - return (bfd_vma) -1; - - plt_sec_size = bfd_section_size (plt->owner, plt); - plt_entry_size - = (bfd_get_mach (abfd) == bfd_mach_cris_v32 - ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE); - - /* Data in PLT is GOT-relative for DYN, but absolute for EXE. */ - got_vma_for_dyn = (abfd->flags & EXEC_P) ? 0 : got->vma; - - /* Because we can have merged GOT entries; a single .got entry for - both GOT and the PLT part of the GOT (.got.plt), the index of the - reloc in .rela.plt is not the same as the index in the PLT. - Instead, we have to hunt down the GOT offset in the PLT that - corresponds to that of this reloc. Unfortunately, we will only - be called for the .rela.plt relocs, so we'll miss synthetic - symbols for .plt entries with merged GOT entries. (FIXME: - fixable by providing our own bfd_elf32_get_synthetic_symtab. - Doesn't seem worthwile at time of this writing.) FIXME: we've - gone from O(1) to O(N) (N number of PLT entries) for finding each - PLT address. Shouldn't matter in practice though. */ - - for (pltoffs = plt_entry_size; - pltoffs < plt_sec_size; - pltoffs += plt_entry_size) - { - bfd_size_type got_offset; - bfd_byte gotoffs_raw[4]; - - if (!bfd_get_section_contents (abfd, (asection *) plt, gotoffs_raw, - pltoffs + plt_entry_got_offset, - sizeof (gotoffs_raw))) - return (bfd_vma) -1; - - got_offset = bfd_get_32 (abfd, gotoffs_raw); - if (got_offset + got_vma_for_dyn == rel->address) - return plt->vma + pltoffs; - } - - /* While it's tempting to BFD_ASSERT that we shouldn't get here, - that'd not be graceful behavior for invalid input. */ - return (bfd_vma) -1; -} - -/* Make sure we emit a GOT entry if the symbol was supposed to have a PLT - entry but we found we will not create any. Called when we find we will - not have any PLT for this symbol, by for example - elf_cris_adjust_dynamic_symbol when we're doing a proper dynamic link, - or elf_cris_size_dynamic_sections if no dynamic sections will be - created (we're only linking static objects). */ - -static bfd_boolean -elf_cris_adjust_gotplt_to_got (struct elf_cris_link_hash_entry *h, void * p) -{ - struct bfd_link_info *info = (struct bfd_link_info *) p; - - /* A GOTPLT reloc, when activated, is supposed to be included into - the PLT refcount, when the symbol isn't set-or-forced local. */ - BFD_ASSERT (h->gotplt_refcount == 0 - || h->root.plt.refcount == -1 - || h->gotplt_refcount <= h->root.plt.refcount); - - /* If nobody wanted a GOTPLT with this symbol, we're done. */ - if (h->gotplt_refcount <= 0) - return TRUE; - - if (h->reg_got_refcount > 0) - { - /* There's a GOT entry for this symbol. Just adjust the refcounts. - Probably not necessary at this stage, but keeping them accurate - helps avoiding surprises later. */ - h->root.got.refcount += h->gotplt_refcount; - h->reg_got_refcount += h->gotplt_refcount; - h->gotplt_refcount = 0; - } - else - { - /* No GOT entry for this symbol. We need to create one. */ - asection *sgot; - asection *srelgot; - - sgot = elf_hash_table (info)->sgot; - srelgot = elf_hash_table (info)->srelgot; - - /* Put accurate refcounts there. */ - BFD_ASSERT (h->root.got.refcount >= 0); - h->root.got.refcount += h->gotplt_refcount; - h->reg_got_refcount = h->gotplt_refcount; - - h->gotplt_refcount = 0; - - /* We always have a .got and a .rela.got section if there were - GOTPLT relocs in input. */ - BFD_ASSERT (sgot != NULL && srelgot != NULL); - - /* Allocate space in the .got section. */ - sgot->size += 4; - - /* Allocate relocation space. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Try to fold PLT entries with GOT entries. There are two cases when we - want to do this: - - - When all PLT references are GOTPLT references, and there are GOT - references, and this is not the executable. We don't have to - generate a PLT at all. - - - When there are both (ordinary) PLT references and GOT references, - and this isn't the executable. - We want to make the PLT reference use the ordinary GOT entry rather - than R_CRIS_JUMP_SLOT, a run-time dynamically resolved GOTPLT entry, - since the GOT entry will have to be resolved at startup anyway. - - Though the latter case is handled when room for the PLT is allocated, - not here. - - By folding into the GOT, we may need a round-trip to a PLT in the - executable for calls, a loss in performance. Still, losing a - reloc is a win in size and at least in start-up time. - - Note that this function is called before symbols are forced local by - version scripts. The differing cases are handled by - elf_cris_hide_symbol. */ - -static bfd_boolean -elf_cris_try_fold_plt_to_got (struct elf_cris_link_hash_entry *h, void * p) -{ - struct bfd_link_info *info = (struct bfd_link_info *) p; - - /* If there are no GOT references for this symbol, we can't fold any - other reference so there's nothing to do. Likewise if there are no - PLT references; GOTPLT references included. */ - if (h->root.got.refcount <= 0 || h->root.plt.refcount <= 0) - return TRUE; - - /* GOTPLT relocs are supposed to be included into the PLT refcount. */ - BFD_ASSERT (h->gotplt_refcount <= h->root.plt.refcount); - - if (h->gotplt_refcount == h->root.plt.refcount) - { - /* The only PLT references are GOTPLT references, and there are GOT - references. Convert PLT to GOT references. */ - if (! elf_cris_adjust_gotplt_to_got (h, info)) - return FALSE; - - /* Clear the PLT references, so no PLT will be created. */ - h->root.plt.offset = (bfd_vma) -1; - } - - return TRUE; -} - -/* Our own version of hide_symbol, so that we can adjust a GOTPLT reloc - to use a GOT entry (and create one) rather than requiring a GOTPLT - entry. */ - -static void -elf_cris_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - bfd_boolean force_local) -{ - elf_cris_adjust_gotplt_to_got ((struct elf_cris_link_hash_entry *) h, info); - - _bfd_elf_link_hash_hide_symbol (info, h, force_local); -} - -/* 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_cris_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_cris_link_hash_table * htab; - bfd *dynobj; - asection *s; - asection *srel; - bfd_size_type plt_entry_size; - - htab = elf_cris_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - plt_entry_size - = (bfd_get_mach (dynobj) == bfd_mach_cris_v32 - ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE); - - /* 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 we link a program (not a DSO), we'll get rid of unnecessary - PLT entries; we point to the actual symbols -- even for pic - relocs, because a program built with -fpic should have the same - result as one built without -fpic, specifically considering weak - symbols. - FIXME: m68k and i386 differ here, for unclear reasons. */ - if (! bfd_link_pic (info) - && !h->def_dynamic) - { - /* This case can occur if we saw a PLT reloc in an input file, - but the symbol was not defined by a dynamic object. In such - a case, we don't actually need to build a procedure linkage - table, and we can just do an absolute or PC reloc instead, or - change a .got.plt index to a .got index for GOTPLT relocs. */ - BFD_ASSERT (h->needs_plt); - h->needs_plt = 0; - h->plt.offset = (bfd_vma) -1; - return - elf_cris_adjust_gotplt_to_got ((struct - elf_cris_link_hash_entry *) h, - info); - } - - /* If we had a R_CRIS_GLOB_DAT that didn't have to point to a PLT; - where a pointer-equivalent symbol was unimportant (i.e. more - like R_CRIS_JUMP_SLOT after symbol evaluation) we could get rid - of the PLT. We can't for the executable, because the GOT - entries will point to the PLT there (and be constant). */ - if (bfd_link_pic (info) - && !elf_cris_try_fold_plt_to_got ((struct elf_cris_link_hash_entry*) - h, info)) - return FALSE; - - /* GC or folding may have rendered this entry unused. */ - if (h->plt.refcount <= 0) - { - h->needs_plt = 0; - h->plt.offset = (bfd_vma) -1; - return TRUE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->root.splt; - BFD_ASSERT (s != NULL); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += plt_entry_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. */ - if (!bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = s->size; - } - - /* If there's already a GOT entry, use that, not a .got.plt. A - GOT field still has a reference count when we get here; it's - not yet changed to an offset. We can't do this for an - executable, because then the reloc associated with the PLT - would get a non-PLT reloc pointing to the PLT. FIXME: Move - this to elf_cris_try_fold_plt_to_got. */ - if (bfd_link_pic (info) && h->got.refcount > 0) - { - h->got.refcount += h->plt.refcount; - - /* Mark the PLT offset to use the GOT entry by setting the low - bit in the plt offset; it is always a multiple of - plt_entry_size (which is at least a multiple of 2). */ - BFD_ASSERT ((s->size % plt_entry_size) == 0); - - /* Change the PLT refcount to an offset. */ - h->plt.offset = s->size; - - /* By not setting gotplt_offset (i.e. it remains at 0), we signal - that the got entry should be used instead. */ - BFD_ASSERT (((struct elf_cris_link_hash_entry *) - h)->gotplt_offset == 0); - - /* Make room for this entry. */ - s->size += plt_entry_size; - - return TRUE; - } - - /* No GOT reference for this symbol; prepare for an ordinary PLT. */ - h->plt.offset = s->size; - - /* 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. */ - ((struct elf_cris_link_hash_entry *) h)->gotplt_offset - = htab->next_gotplt_entry; - htab->next_gotplt_entry += 4; - - s = htab->root.sgotplt; - BFD_ASSERT (s != NULL); - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - - s = htab->root.srelplt; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - - return TRUE; - } - - /* Reinitialize the plt offset now that it is not used as a reference - count any more. */ - 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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; - - /* 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_CRIS_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = htab->root.sdynrelro; - srel = htab->root.sreldynrelro; - } - else - { - s = htab->root.sdynbss; - srel = htab->root.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - BFD_ASSERT (s != NULL); - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Adjust our "subclass" elements for an indirect symbol. */ - -static void -elf_cris_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_cris_link_hash_entry *edir, *eind; - - edir = (struct elf_cris_link_hash_entry *) dir; - eind = (struct elf_cris_link_hash_entry *) ind; - - /* Only indirect symbols are replaced; we're not interested in - updating any of EIND's fields for other symbols. */ - if (eind->root.root.type != bfd_link_hash_indirect) - { - /* Still, we need to copy flags for e.g. weak definitions. */ - _bfd_elf_link_hash_copy_indirect (info, dir, ind); - return; - } - - BFD_ASSERT (edir->gotplt_offset == 0 || eind->gotplt_offset == 0); - -#define XMOVOPZ(F, OP, Z) edir->F OP eind->F; eind->F = Z -#define XMOVE(F) XMOVOPZ (F, +=, 0) - if (eind->pcrel_relocs_copied != NULL) - { - if (edir->pcrel_relocs_copied != NULL) - { - struct elf_cris_pcrel_relocs_copied **pp; - struct elf_cris_pcrel_relocs_copied *p; - - /* Add reloc counts against the indirect sym to the direct sym - list. Merge any entries against the same section. */ - for (pp = &eind->pcrel_relocs_copied; *pp != NULL;) - { - struct elf_cris_pcrel_relocs_copied *q; - p = *pp; - for (q = edir->pcrel_relocs_copied; q != NULL; q = q->next) - if (q->section == p->section) - { - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->pcrel_relocs_copied; - } - XMOVOPZ (pcrel_relocs_copied, =, NULL); - } - XMOVE (gotplt_refcount); - XMOVE (gotplt_offset); - XMOVE (reg_got_refcount); - XMOVE (tprel_refcount); - XMOVE (dtp_refcount); -#undef XMOVE -#undef XMOVOPZ - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Look through the relocs for a section during the first phase. */ - -static bfd_boolean -cris_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_cris_link_hash_table * htab; - bfd *dynobj; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_signed_vma *local_got_refcounts; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - asection *sgot; - asection *srelgot; - asection *sreloc; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = elf_cris_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - sgot = NULL; - srelgot = NULL; - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - enum elf_cris_reloc_type r_type; - bfd_signed_vma got_element_size = 4; - unsigned long r_symndx_lgot = INT_MAX; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - h = NULL; - r_symndx_lgot = LGOT_REG_NDX (r_symndx); - } - 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 = ELF32_R_TYPE (rel->r_info); - - /* Some relocs require linker-created sections; we need to hang them - on the first input bfd we found that contained dynamic relocs. */ - switch (r_type) - { - case R_CRIS_32_DTPREL: - if ((sec->flags & SEC_ALLOC) == 0) - /* This'd be a .dtpreld entry in e.g. debug info. We have - several different switch statements below, but none of - that is needed; we need no preparations for resolving - R_CRIS_32_DTPREL into a non-allocated section (debug - info), so let's just move on to the next - relocation. */ - continue; - /* Fall through. */ - case R_CRIS_16_DTPREL: - /* The first .got.plt entry is right after the R_CRIS_DTPMOD - entry at index 3. */ - if (htab->dtpmod_refcount == 0) - htab->next_gotplt_entry += 8; - - htab->dtpmod_refcount++; - /* Fall through. */ - - case R_CRIS_32_IE: - case R_CRIS_32_GD: - case R_CRIS_16_GOT_GD: - case R_CRIS_32_GOT_GD: - case R_CRIS_32_GOT_TPREL: - case R_CRIS_16_GOT_TPREL: - case R_CRIS_16_GOT: - case R_CRIS_32_GOT: - case R_CRIS_32_GOTREL: - case R_CRIS_32_PLT_GOTREL: - case R_CRIS_32_PLT_PCREL: - case R_CRIS_16_GOTPLT: - case R_CRIS_32_GOTPLT: - if (dynobj == NULL) - { - elf_hash_table (info)->dynobj = dynobj = abfd; - - /* We could handle this if we can get a handle on the - output bfd in elf_cris_adjust_dynamic_symbol. Failing - that, we must insist on dynobj being a specific mach. */ - if (bfd_get_mach (dynobj) == bfd_mach_cris_v10_v32) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A:\n v10/v32 compatible object" - " must not contain a PIC relocation"), - abfd, sec); - return FALSE; - } - } - - if (sgot == NULL) - { - /* We may have a dynobj but no .got section, if machine- - independent parts of the linker found a reason to create - a dynobj. We want to create the .got section now, so we - can assume it's always present whenever there's a dynobj. - It's ok to call this function more than once. */ - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - - sgot = elf_hash_table (info)->sgot; - srelgot = elf_hash_table (info)->srelgot; - } - - if (local_got_refcounts == NULL) - { - bfd_size_type amt; - - /* We use index local_got_refcounts[-1] to count all - GOT-relative relocations that do not have explicit - GOT entries. */ - amt = LGOT_ALLOC_NELTS_FOR (symtab_hdr->sh_info) + 1; - amt *= sizeof (bfd_signed_vma); - local_got_refcounts = ((bfd_signed_vma *) bfd_zalloc (abfd, amt)); - if (local_got_refcounts == NULL) - return FALSE; - - local_got_refcounts++; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - break; - - default: - break; - } - - /* Warn and error for invalid input. */ - switch (r_type) - { - case R_CRIS_32_IE: - case R_CRIS_32_TPREL: - case R_CRIS_16_TPREL: - case R_CRIS_32_GD: - if (bfd_link_pic (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A:\n relocation %s not valid" - " in a shared object;" - " typically an option mixup, recompile with -fPIC"), - abfd, - sec, - cris_elf_howto_table[r_type].name); - /* Don't return FALSE here; we want messages for all of - these and the error behavior is ungraceful - anyway. */ - } - default: - break; - } - - switch (r_type) - { - case R_CRIS_32_GD: - case R_CRIS_16_GOT_GD: - case R_CRIS_32_GOT_GD: - /* These are requests for tls_index entries, run-time R_CRIS_DTP. */ - got_element_size = 8; - r_symndx_lgot = LGOT_DTP_NDX (r_symndx); - break; - - case R_CRIS_16_DTPREL: - case R_CRIS_32_DTPREL: - /* These two just request for the constant-index - module-local tls_index-sized GOT entry, which we add - elsewhere. */ - break; - - case R_CRIS_32_IE: - case R_CRIS_32_GOT_TPREL: - case R_CRIS_16_GOT_TPREL: - r_symndx_lgot = LGOT_TPREL_NDX (r_symndx); - - /* Those relocs also require that a DSO is of type - Initial Exec. Like other targets, we don't reset this - flag even if the relocs are GC:ed away. */ - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - break; - - /* Let's list the other assembler-generated TLS-relocs too, - just to show that they're not forgotten. */ - case R_CRIS_16_TPREL: - case R_CRIS_32_TPREL: - default: - break; - } - - switch (r_type) - { - case R_CRIS_16_GOTPLT: - case R_CRIS_32_GOTPLT: - /* Mark that we need a GOT entry if the PLT entry (and its GOT - entry) is eliminated. We can only do this for a non-local - symbol. */ - if (h != NULL) - { - elf_cris_hash_entry (h)->gotplt_refcount++; - goto handle_gotplt_reloc; - } - /* If h is NULL then this is a local symbol, and we must make a - GOT entry for it, so handle it like a GOT reloc. */ - /* Fall through. */ - - case R_CRIS_32_IE: - case R_CRIS_32_GD: - case R_CRIS_16_GOT_GD: - case R_CRIS_32_GOT_GD: - case R_CRIS_32_GOT_TPREL: - case R_CRIS_16_GOT_TPREL: - case R_CRIS_16_GOT: - case R_CRIS_32_GOT: - /* This symbol requires a global offset table entry. */ - if (h != NULL) - { - if (h->got.refcount == 0) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - - /* Update the sum of reloc counts for this symbol. */ - h->got.refcount++; - - switch (r_type) - { - case R_CRIS_16_GOT: - case R_CRIS_32_GOT: - if (elf_cris_hash_entry (h)->reg_got_refcount == 0) - { - /* Allocate space in the .got section. */ - sgot->size += got_element_size; - /* Allocate relocation space. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - elf_cris_hash_entry (h)->reg_got_refcount++; - break; - - case R_CRIS_32_GD: - case R_CRIS_16_GOT_GD: - case R_CRIS_32_GOT_GD: - if (elf_cris_hash_entry (h)->dtp_refcount == 0) - { - /* Allocate space in the .got section. */ - sgot->size += got_element_size; - /* Allocate relocation space. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - elf_cris_hash_entry (h)->dtp_refcount++; - break; - - case R_CRIS_32_IE: - case R_CRIS_32_GOT_TPREL: - case R_CRIS_16_GOT_TPREL: - if (elf_cris_hash_entry (h)->tprel_refcount == 0) - { - /* Allocate space in the .got section. */ - sgot->size += got_element_size; - /* Allocate relocation space. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - elf_cris_hash_entry (h)->tprel_refcount++; - break; - - default: - BFD_FAIL (); - break; - } - } - else - { - /* This is a global offset table entry for a local symbol. */ - if (local_got_refcounts[r_symndx_lgot] == 0) - { - sgot->size += got_element_size; - if (bfd_link_pic (info)) - { - /* If we are generating a shared object, we need - to output a R_CRIS_RELATIVE reloc so that the - dynamic linker can adjust this GOT entry. - Similarly for non-regular got entries. */ - srelgot->size += sizeof (Elf32_External_Rela); - } - } - /* Update the reloc-specific count. */ - local_got_refcounts[r_symndx_lgot]++; - - /* This one is the sum of all the others. */ - local_got_refcounts[r_symndx]++; - } - break; - - case R_CRIS_16_DTPREL: - case R_CRIS_32_DTPREL: - case R_CRIS_32_GOTREL: - /* This reference requires a global offset table. - FIXME: The actual refcount isn't used currently; the .got - section can't be removed if there were any references in the - input. */ - local_got_refcounts[-1]++; - break; - - handle_gotplt_reloc: - - case R_CRIS_32_PLT_GOTREL: - /* This reference requires a global offset table. */ - local_got_refcounts[-1]++; - /* Fall through. */ - - case R_CRIS_32_PLT_PCREL: - /* 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. */ - - /* Beware: if we'd check for visibility of the symbol here - (and not marking the need for a PLT when non-visible), we'd - get into trouble with keeping handling consistent with - regards to relocs found before definition and GOTPLT - handling. Eliminable PLT entries will be dealt with later - anyway. */ - if (h == NULL) - continue; - - h->needs_plt = 1; - - /* If the symbol is forced local, the refcount is unavailable. */ - if (h->plt.refcount != -1) - h->plt.refcount++; - break; - - case R_CRIS_8: - case R_CRIS_16: - case R_CRIS_32: - /* Let's help debug shared library creation. Any of these - relocs *can* be used in shared libs, but pages containing - them cannot be shared, so they're not appropriate for - common use. Don't warn for sections we don't care about, - such as debug sections or non-constant sections. We - can't help tables of (global) function pointers, for - example, though they must be emitted in a (writable) data - section to avoid having impure text sections. */ - if (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (sec->flags & SEC_READONLY) != 0) - { - /* FIXME: How do we make this optionally a warning only? */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A:\n relocation %s should not" - " be used in a shared object; recompile with -fPIC"), - abfd, - sec, - cris_elf_howto_table[r_type].name); - } - - /* We don't need to handle relocs into sections not going into - the "real" output. */ - if ((sec->flags & SEC_ALLOC) == 0) - break; - - if (h != NULL) - { - h->non_got_ref = 1; - - /* Make sure a plt entry is created for this symbol if it - turns out to be a function defined by a dynamic object. */ - if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - h->plt.refcount++; - } - - /* If we are creating a shared library and this is not a local - symbol, we need to copy the reloc into the shared library. - However when linking with -Bsymbolic and this is a global - symbol which is defined in an object we are including in the - link (i.e., DEF_REGULAR is set), then we can resolve the - reloc directly. 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. */ - - /* No need to do anything if we're not creating a shared object. */ - if (! bfd_link_pic (info) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - break; - - /* We may need to create a reloc section in the dynobj and made room - for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - if (sec->flags & SEC_READONLY) - info->flags |= DF_TEXTREL; - - sreloc->size += sizeof (Elf32_External_Rela); - break; - - case R_CRIS_8_PCREL: - case R_CRIS_16_PCREL: - case R_CRIS_32_PCREL: - if (h != NULL) - { - h->non_got_ref = 1; - - /* Make sure a plt entry is created for this symbol if it - turns out to be a function defined by a dynamic object. */ - if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - h->plt.refcount++; - } - - /* If we are creating a shared library and this is not a local - symbol, we need to copy the reloc into the shared library. - However when linking with -Bsymbolic and this is a global - symbol which is defined in an object we are including in the - link (i.e., DEF_REGULAR is set), then we can resolve the - reloc directly. 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. */ - - /* No need to do anything if we're not creating a shared object. */ - if (! bfd_link_pic (info)) - break; - - /* We don't need to handle relocs into sections not going into - the "real" output. */ - if ((sec->flags & SEC_ALLOC) == 0) - break; - - /* If the symbol is local, then we know already we can - eliminate the reloc. */ - if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - break; - - /* If this is with -Bsymbolic and the symbol isn't weak, and - is defined by an ordinary object (the ones we include in - this shared library) then we can also eliminate the - reloc. See comment above for more eliminable cases which - we can't identify at this time. */ - if (SYMBOLIC_BIND (info, h) - && h->root.type != bfd_link_hash_defweak - && h->def_regular) - break; - - /* We may need to create a reloc section in the dynobj and made room - for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - sreloc->size += sizeof (Elf32_External_Rela); - - /* We count the number of PC relative relocations we have - entered for this symbol, so that we can discard them - again if the symbol is later defined by a regular object. - We know that h is really a pointer to an - elf_cris_link_hash_entry. */ - { - struct elf_cris_link_hash_entry *eh; - struct elf_cris_pcrel_relocs_copied *p; - - eh = elf_cris_hash_entry (h); - - for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next) - if (p->section == sec) - break; - - if (p == NULL) - { - p = ((struct elf_cris_pcrel_relocs_copied *) - bfd_alloc (dynobj, (bfd_size_type) sizeof *p)); - if (p == NULL) - return FALSE; - p->next = eh->pcrel_relocs_copied; - eh->pcrel_relocs_copied = p; - p->section = sec; - p->count = 0; - p->r_type = r_type; - } - - ++p->count; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_CRIS_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_CRIS_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_CRIS_16_TPREL: - case R_CRIS_32_TPREL: - /* Already warned above, when necessary. */ - break; - - default: - /* Other relocs do not appear here. */ - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_cris_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_cris_link_hash_table * htab; - bfd *dynobj; - asection *s; - bfd_boolean plt; - bfd_boolean relocs; - - htab = elf_cris_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* Adjust all expected GOTPLT uses to use a GOT entry instead. */ - elf_cris_link_hash_traverse (htab, elf_cris_adjust_gotplt_to_got, - info); - - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = htab->root.srelgot; - if (s != NULL) - s->size = 0; - } - - /* If this is a -Bsymbolic shared link, then we need to discard all PC - relative relocs against symbols defined in a regular object. We - allocated space for them in the check_relocs routine, but we will not - fill them in in the relocate_section routine. We also discard space - for relocs that have become for local symbols due to symbol - visibility changes. For programs, we discard space for relocs for - symbols not referenced by any dynamic object. */ - if (bfd_link_pic (info)) - elf_cris_link_hash_traverse (htab, - elf_cris_discard_excess_dso_dynamics, - info); - else - elf_cris_link_hash_traverse (htab, - elf_cris_discard_excess_program_dynamics, - info); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (strcmp (name, ".got.plt") == 0) - { - /* The .got.plt contains the .got header as well as the - actual .got.plt contents. The .got header may contain a - R_CRIS_DTPMOD entry at index 3. */ - s->size += htab->dtpmod_refcount != 0 - ? 8 : 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (strcmp (name, ".rela.got") == 0 - && htab->dtpmod_refcount != 0 - && bfd_link_pic (info)) - s->size += sizeof (Elf32_External_Rela); - - if (s->size != 0) - { - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (strcmp (name, ".rela.plt") != 0) - 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 if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".dynbss") != 0 - && s != htab->root.sdynrelro) - { - /* 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 will not write out garbage. For reloc sections, - this will make entries have the type R_CRIS_NONE. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf_cris_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 (!bfd_link_pic (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - } - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - info->flags |= DF_TEXTREL; - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* This function is called via elf_cris_link_hash_traverse if we are - creating a shared object. In the -Bsymbolic case, it discards the - space allocated to copy PC relative relocs against symbols which - are defined in regular objects. For the normal non-symbolic case, - we also discard space for relocs that have become local due to - symbol visibility changes. We allocated space for them in the - check_relocs routine, but we won't fill them in in the - relocate_section routine. */ - -static bfd_boolean -elf_cris_discard_excess_dso_dynamics (struct elf_cris_link_hash_entry *h, - void * inf) -{ - struct elf_cris_pcrel_relocs_copied *s; - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - /* If a symbol has been forced local or we have found a regular - definition for the symbolic link case, then we won't be needing - any relocs. */ - if (h->root.def_regular - && (h->root.forced_local - || SYMBOLIC_BIND (info, &h->root))) - { - for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) - { - asection *sreloc - = _bfd_elf_get_dynamic_reloc_section (elf_hash_table (info) - ->dynobj, - s->section, - /*rela?*/ TRUE); - sreloc->size -= s->count * sizeof (Elf32_External_Rela); - } - return TRUE; - } - - /* If we have accounted for PC-relative relocs for read-only - sections, now is the time to warn for them. We can't do it in - cris_elf_check_relocs, because we don't know the status of all - symbols at that time (and it's common to force symbols local - late). */ - - for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) - if ((s->section->flags & SEC_READONLY) != 0) - { - /* FIXME: How do we make this optionally a warning only? */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section `%A', to symbol `%s':\n" - " relocation %s should not be used" - " in a shared object; recompile with -fPIC"), - s->section->owner, - s->section, - h->root.root.root.string, - cris_elf_howto_table[s->r_type].name); - - info->flags |= DF_TEXTREL; - } - - return TRUE; -} - -/* This function is called via elf_cris_link_hash_traverse if we are *not* - creating a shared object. We discard space for relocs for symbols put - in the .got, but which we found we do not have to resolve at run-time. */ - -static bfd_boolean -elf_cris_discard_excess_program_dynamics (struct elf_cris_link_hash_entry *h, - void * inf) -{ - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - /* If we're not creating a shared library and have a symbol which is - referred to by .got references, but the symbol is defined locally, - (or rather, not defined by a DSO) then lose the reloc for the .got - (don't allocate room for it). Likewise for relocs for something - for which we create a PLT. */ - if (!h->root.def_dynamic - || h->root.plt.refcount > 0) - { - if (h->reg_got_refcount > 0 - /* The size of this section is only valid and in sync with the - various reference counts if we do dynamic; don't decrement it - otherwise. */ - && elf_hash_table (info)->dynamic_sections_created) - { - bfd *dynobj = elf_hash_table (info)->dynobj; - asection *srelgot = elf_hash_table (info)->srelgot; - - BFD_ASSERT (dynobj != NULL); - BFD_ASSERT (srelgot != NULL); - - srelgot->size -= sizeof (Elf32_External_Rela); - } - - /* If the locally-defined symbol isn't used by a DSO, then we don't - have to export it as a dynamic symbol. This was already done for - functions; doing this for all symbols would presumably not - introduce new problems. Of course we don't do this if we're - exporting all dynamic symbols, or all data symbols, regardless of - them being referenced or not. */ - if (! (info->export_dynamic - || (h->root.type != STT_FUNC && info->dynamic_data)) - && h->root.dynindx != -1 - && !h->root.dynamic - && !h->root.def_dynamic - && !h->root.ref_dynamic) - { - h->root.dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - h->root.dynstr_index); - } - } - - return TRUE; -} - -/* Reject a file depending on presence and expectation of prefixed - underscores on symbols. */ - -static bfd_boolean -cris_elf_object_p (bfd *abfd) -{ - if (! cris_elf_set_mach_from_flags (abfd, elf_elfheader (abfd)->e_flags)) - return FALSE; - - if ((elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE)) - return (bfd_get_symbol_leading_char (abfd) == '_'); - else - return (bfd_get_symbol_leading_char (abfd) == 0); -} - -/* Mark presence or absence of leading underscore. Set machine type - flags from mach type. */ - -static void -cris_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long e_flags = elf_elfheader (abfd)->e_flags; - - e_flags &= ~EF_CRIS_UNDERSCORE; - if (bfd_get_symbol_leading_char (abfd) == '_') - e_flags |= EF_CRIS_UNDERSCORE; - - switch (bfd_get_mach (abfd)) - { - case bfd_mach_cris_v0_v10: - e_flags |= EF_CRIS_VARIANT_ANY_V0_V10; - break; - - case bfd_mach_cris_v10_v32: - e_flags |= EF_CRIS_VARIANT_COMMON_V10_V32; - break; - - case bfd_mach_cris_v32: - e_flags |= EF_CRIS_VARIANT_V32; - break; - - default: - _bfd_abort (__FILE__, __LINE__, - _("Unexpected machine number")); - } - - elf_elfheader (abfd)->e_flags = e_flags; -} - -/* Set the mach type from e_flags value. */ - -static bfd_boolean -cris_elf_set_mach_from_flags (bfd *abfd, - unsigned long flags) -{ - switch (flags & EF_CRIS_VARIANT_MASK) - { - case EF_CRIS_VARIANT_ANY_V0_V10: - bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v0_v10); - break; - - case EF_CRIS_VARIANT_V32: - bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v32); - break; - - case EF_CRIS_VARIANT_COMMON_V10_V32: - bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v10_v32); - break; - - default: - /* Since we don't recognize them, we obviously can't support them - with this code; we'd have to require that all future handling - would be optional. */ - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - return TRUE; -} - -/* Display the flags field. */ - -static bfd_boolean -cris_elf_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - _bfd_elf_print_private_bfd_data (abfd, ptr); - - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - if (elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE) - fprintf (file, _(" [symbols have a _ prefix]")); - if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK) - == EF_CRIS_VARIANT_COMMON_V10_V32) - fprintf (file, _(" [v10 and v32]")); - if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK) - == EF_CRIS_VARIANT_V32) - fprintf (file, _(" [v32]")); - - fputc ('\n', file); - return TRUE; -} - -/* Don't mix files with and without a leading underscore. */ - -static bfd_boolean -cris_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - int imach, omach; - - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - imach = bfd_get_mach (ibfd); - - if (! elf_flags_init (obfd)) - { - /* This happens when ld starts out with a 'blank' output file. */ - elf_flags_init (obfd) = TRUE; - - /* We ignore the linker-set mach, and instead set it according to - the first input file. This would also happen if we could - somehow filter out the OUTPUT_ARCH () setting from elf.sc. - This allows us to keep the same linker config across - cris(v0..v10) and crisv32. The drawback is that we can't force - the output type, which might be a sane thing to do for a - v10+v32 compatibility object. */ - if (! bfd_set_arch_mach (obfd, bfd_arch_cris, imach)) - return FALSE; - } - - if (bfd_get_symbol_leading_char (ibfd) - != bfd_get_symbol_leading_char (obfd)) - { - _bfd_error_handler - (bfd_get_symbol_leading_char (ibfd) == '_' - ? _("%B: uses _-prefixed symbols, but writing file with non-prefixed symbols") - : _("%B: uses non-prefixed symbols, but writing file with _-prefixed symbols"), - ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - omach = bfd_get_mach (obfd); - - if (imach != omach) - { - /* We can get an incompatible combination only if either is - bfd_mach_cris_v32, and the other one isn't compatible. */ - if ((imach == bfd_mach_cris_v32 - && omach != bfd_mach_cris_v10_v32) - || (omach == bfd_mach_cris_v32 - && imach != bfd_mach_cris_v10_v32)) - { - _bfd_error_handler - ((imach == bfd_mach_cris_v32) - ? _("%B contains CRIS v32 code, incompatible" - " with previous objects") - : _("%B contains non-CRIS-v32 code, incompatible" - " with previous objects"), - ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* We don't have to check the case where the input is compatible - with v10 and v32, because the output is already known to be set - to the other (compatible) mach. */ - if (omach == bfd_mach_cris_v10_v32 - && ! bfd_set_arch_mach (obfd, bfd_arch_cris, imach)) - return FALSE; - } - - return TRUE; -} - -/* Do side-effects of e_flags copying to obfd. */ - -static bfd_boolean -cris_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; - - /* Call the base function. */ - if (!_bfd_elf_copy_private_bfd_data (ibfd, obfd)) - return FALSE; - - /* Do what we really came here for. */ - return bfd_set_arch_mach (obfd, bfd_arch_cris, bfd_get_mach (ibfd)); -} - -static enum elf_reloc_type_class -elf_cris_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - enum elf_cris_reloc_type r_type = ELF32_R_TYPE (rela->r_info); - switch (r_type) - { - case R_CRIS_RELATIVE: - return reloc_class_relative; - case R_CRIS_JUMP_SLOT: - return reloc_class_plt; - case R_CRIS_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* The elf_backend_got_elt_size worker. For one symbol, we can have up to - two GOT entries from three types with two different sizes. We handle - it as a single entry, so we can use the regular offset-calculation - machinery. */ - -static bfd_vma -elf_cris_got_elt_size (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *hr, - bfd *ibfd, - unsigned long symndx) -{ - struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) hr; - bfd_vma eltsiz = 0; - - /* We may have one regular GOT entry or up to two TLS GOT - entries. */ - if (h == NULL) - { - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (ibfd); - - BFD_ASSERT (local_got_refcounts != NULL); - - if (local_got_refcounts[LGOT_REG_NDX (symndx)] > 0) - { - /* We can't have a variable referred to both as a regular - variable and through TLS relocs. */ - BFD_ASSERT (local_got_refcounts[LGOT_DTP_NDX (symndx)] == 0 - && local_got_refcounts[LGOT_TPREL_NDX (symndx)] == 0); - return 4; - } - - if (local_got_refcounts[LGOT_DTP_NDX (symndx)] > 0) - eltsiz += 8; - - if (local_got_refcounts[LGOT_TPREL_NDX (symndx)] > 0) - eltsiz += 4; - } - else - { - struct elf_cris_link_hash_entry *hh = elf_cris_hash_entry (h); - if (hh->reg_got_refcount > 0) - { - /* The actual error-on-input is emitted elsewhere. */ - BFD_ASSERT (hh->dtp_refcount == 0 && hh->tprel_refcount == 0); - return 4; - } - - if (hh->dtp_refcount > 0) - eltsiz += 8; - - if (hh->tprel_refcount > 0) - eltsiz += 4; - } - - /* We're only called when h->got.refcount is non-zero, so we must - have a non-zero size. */ - BFD_ASSERT (eltsiz != 0); - return eltsiz; -} - -#define ELF_ARCH bfd_arch_cris -#define ELF_TARGET_ID CRIS_ELF_DATA -#define ELF_MACHINE_CODE EM_CRIS -#define ELF_MAXPAGESIZE 0x2000 - -#define TARGET_LITTLE_SYM cris_elf32_vec -#define TARGET_LITTLE_NAME "elf32-cris" -#define elf_symbol_leading_char 0 - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto cris_info_to_howto_rela -#define elf_backend_relocate_section cris_elf_relocate_section -#define elf_backend_gc_mark_hook cris_elf_gc_mark_hook -#define elf_backend_plt_sym_val cris_elf_plt_sym_val -#define elf_backend_check_relocs cris_elf_check_relocs -#define elf_backend_grok_prstatus cris_elf_grok_prstatus -#define elf_backend_grok_psinfo cris_elf_grok_psinfo - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 - -#define elf_backend_object_p cris_elf_object_p -#define elf_backend_final_write_processing \ - cris_elf_final_write_processing -#define bfd_elf32_bfd_print_private_bfd_data \ - cris_elf_print_private_bfd_data -#define bfd_elf32_bfd_merge_private_bfd_data \ - cris_elf_merge_private_bfd_data -#define bfd_elf32_bfd_copy_private_bfd_data \ - cris_elf_copy_private_bfd_data - -#define bfd_elf32_bfd_reloc_type_lookup cris_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup cris_reloc_name_lookup - -#define bfd_elf32_bfd_link_hash_table_create \ - elf_cris_link_hash_table_create -#define elf_backend_adjust_dynamic_symbol \ - elf_cris_adjust_dynamic_symbol -#define elf_backend_copy_indirect_symbol \ - elf_cris_copy_indirect_symbol -#define elf_backend_size_dynamic_sections \ - elf_cris_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_finish_dynamic_symbol \ - elf_cris_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf_cris_finish_dynamic_sections -#define elf_backend_create_dynamic_sections \ - _bfd_elf_create_dynamic_sections -#define bfd_elf32_bfd_final_link \ - bfd_elf_gc_common_final_link -#define elf_backend_hide_symbol elf_cris_hide_symbol -#define elf_backend_reloc_type_class elf_cris_reloc_type_class - -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_got_elt_size elf_cris_got_elt_size -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_want_dynrelro 1 - -/* Later, we my want to optimize RELA entries into REL entries for dynamic - linking and libraries (if it's a win of any significance). Until then, - take the easy route. */ -#define elf_backend_may_use_rel_p 0 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_rela_normal 1 - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef elf_symbol_leading_char - -#define TARGET_LITTLE_SYM cris_elf32_us_vec -#define TARGET_LITTLE_NAME "elf32-us-cris" -#define elf_symbol_leading_char '_' -#undef elf32_bed -#define elf32_bed elf32_us_cris_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-crx.c b/sdcc/support/sdbinutils/bfd/elf32-crx.c deleted file mode 100644 index d8a3862e2..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-crx.c +++ /dev/null @@ -1,1331 +0,0 @@ -/* BFD back-end for National Semiconductor's CRX ELF - Copyright (C) 2004-2018 Free Software Foundation, Inc. - Written by Tomer Levi, NSC, Israel. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/crx.h" - -static reloc_howto_type *elf_crx_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static void elf_crx_info_to_howto - (bfd *, arelent *, Elf_Internal_Rela *); -static bfd_boolean elf32_crx_relax_delete_bytes - (struct bfd_link_info *, bfd *, asection *, bfd_vma, int); -static bfd_reloc_status_type crx_elf_final_link_relocate - (reloc_howto_type *, bfd *, bfd *, asection *, - bfd_byte *, bfd_vma, bfd_vma, bfd_vma, - struct bfd_link_info *, asection *, int); -static bfd_boolean elf32_crx_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); -static bfd_boolean elf32_crx_relax_section - (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); -static bfd_byte * elf32_crx_get_relocated_section_contents - (bfd *, struct bfd_link_info *, struct bfd_link_order *, - bfd_byte *, bfd_boolean, asymbol **); - -/* crx_reloc_map array maps BFD relocation enum into a CRGAS relocation type. */ - -struct crx_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_enum; /* BFD relocation enum. */ - unsigned short crx_reloc_type; /* CRX relocation type. */ -}; - -static const struct crx_reloc_map crx_reloc_map[R_CRX_MAX] = -{ - {BFD_RELOC_NONE, R_CRX_NONE}, - {BFD_RELOC_CRX_REL4, R_CRX_REL4}, - {BFD_RELOC_CRX_REL8, R_CRX_REL8}, - {BFD_RELOC_CRX_REL8_CMP, R_CRX_REL8_CMP}, - {BFD_RELOC_CRX_REL16, R_CRX_REL16}, - {BFD_RELOC_CRX_REL24, R_CRX_REL24}, - {BFD_RELOC_CRX_REL32, R_CRX_REL32}, - {BFD_RELOC_CRX_REGREL12, R_CRX_REGREL12}, - {BFD_RELOC_CRX_REGREL22, R_CRX_REGREL22}, - {BFD_RELOC_CRX_REGREL28, R_CRX_REGREL28}, - {BFD_RELOC_CRX_REGREL32, R_CRX_REGREL32}, - {BFD_RELOC_CRX_ABS16, R_CRX_ABS16}, - {BFD_RELOC_CRX_ABS32, R_CRX_ABS32}, - {BFD_RELOC_CRX_NUM8, R_CRX_NUM8}, - {BFD_RELOC_CRX_NUM16, R_CRX_NUM16}, - {BFD_RELOC_CRX_NUM32, R_CRX_NUM32}, - {BFD_RELOC_CRX_IMM16, R_CRX_IMM16}, - {BFD_RELOC_CRX_IMM32, R_CRX_IMM32}, - {BFD_RELOC_CRX_SWITCH8, R_CRX_SWITCH8}, - {BFD_RELOC_CRX_SWITCH16, R_CRX_SWITCH16}, - {BFD_RELOC_CRX_SWITCH32, R_CRX_SWITCH32} -}; - -static reloc_howto_type crx_elf_howto_table[] = -{ - HOWTO (R_CRX_NONE, /* type */ - 0, /* rightshift */ - 3, /* size */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REL4, /* type */ - 1, /* rightshift */ - 0, /* size */ - 4, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REL4", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xf, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REL8, /* type */ - 1, /* rightshift */ - 0, /* size */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REL8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REL8_CMP, /* type */ - 1, /* rightshift */ - 0, /* size */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REL8_CMP", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REL16, /* type */ - 1, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REL16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REL24, /* type */ - 1, /* rightshift */ - 2, /* size */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REL24", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REL32, /* type */ - 1, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REL32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REGREL12, /* type */ - 0, /* rightshift */ - 1, /* size */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REGREL12", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REGREL22, /* type */ - 0, /* rightshift */ - 2, /* size */ - 22, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REGREL22", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x3fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REGREL28, /* type */ - 0, /* rightshift */ - 2, /* size */ - 28, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REGREL28", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_REGREL32, /* type */ - 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_REGREL32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_ABS16, /* type */ - 0, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_ABS32, /* type */ - 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_ABS32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_NUM8, /* type */ - 0, /* rightshift */ - 0, /* size */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_NUM8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_NUM16, /* type */ - 0, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_NUM16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_NUM32, /* type */ - 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_NUM32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_IMM16, /* type */ - 0, /* rightshift */ - 1, /* size */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_IMM16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_CRX_IMM32, /* type */ - 0, /* rightshift */ - 2, /* size */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_IMM32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit switch table entry. This is generated for an expression - such as ``.byte L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_CRX_SWITCH8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_SWITCH8", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit switch table entry. This is generated for an expression - such as ``.word L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_CRX_SWITCH16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_SWITCH16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit switch table entry. This is generated for an expression - such as ``.long L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_CRX_SWITCH32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_CRX_SWITCH32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE) /* pcrel_offset */ -}; - -/* Retrieve a howto ptr using a BFD reloc_code. */ - -static reloc_howto_type * -elf_crx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < R_CRX_MAX; i++) - if (code == crx_reloc_map[i].bfd_reloc_enum) - return &crx_elf_howto_table[crx_reloc_map[i].crx_reloc_type]; - - printf ("This relocation Type is not supported -0x%x\n", code); - return 0; -} - -static reloc_howto_type * -elf_crx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (crx_elf_howto_table) / sizeof (crx_elf_howto_table[0]); - i++) - if (crx_elf_howto_table[i].name != NULL - && strcasecmp (crx_elf_howto_table[i].name, r_name) == 0) - return &crx_elf_howto_table[i]; - - return NULL; -} - -/* Retrieve a howto ptr using an internal relocation entry. */ - -static void -elf_crx_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_CRX_MAX) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised CRX reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_CRX_NONE; - } - cache_ptr->howto = &crx_elf_howto_table[r_type]; -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -crx_elf_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section, bfd_byte *contents, - bfd_vma offset, bfd_vma Rvalue, bfd_vma addend, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - unsigned short r_type = howto->type; - bfd_byte *hit_data = contents + offset; - bfd_vma reloc_bits, check; - - switch (r_type) - { - case R_CRX_IMM16: - case R_CRX_IMM32: - case R_CRX_ABS16: - case R_CRX_ABS32: - case R_CRX_REL8_CMP: - case R_CRX_REL16: - case R_CRX_REL24: - case R_CRX_REL32: - case R_CRX_REGREL12: - case R_CRX_REGREL22: - case R_CRX_REGREL28: - case R_CRX_REGREL32: - /* 'hit_data' is relative to the start of the instruction, not the - relocation offset. Advance it to account for the exact offset. */ - hit_data += 2; - break; - - case R_CRX_REL4: - /* This relocation type is used only in 'Branch if Equal to 0' - instructions and requires special handling. */ - Rvalue -= 1; - break; - - case R_CRX_NONE: - return bfd_reloc_ok; - break; - - case R_CRX_SWITCH8: - case R_CRX_SWITCH16: - case R_CRX_SWITCH32: - /* We only care about the addend, where the difference between - expressions is kept. */ - Rvalue = 0; - - default: - break; - } - - if (howto->pc_relative) - { - /* Subtract the address of the section containing the location. */ - Rvalue -= (input_section->output_section->vma - + input_section->output_offset); - /* Subtract the position of the location within the section. */ - Rvalue -= offset; - } - - /* Add in supplied addend. */ - Rvalue += addend; - - /* Complain if the bitfield overflows, whether it is considered - as signed or unsigned. */ - check = Rvalue >> howto->rightshift; - - /* Assumes two's complement. This expression avoids - overflow if howto->bitsize is the number of bits in - bfd_vma. */ - reloc_bits = (((1 << (howto->bitsize - 1)) - 1) << 1) | 1; - - if (((bfd_vma) check & ~reloc_bits) != 0 - && (((bfd_vma) check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits))) - { - /* The above right shift is incorrect for a signed - value. See if turning on the upper bits fixes the - overflow. */ - if (howto->rightshift && (bfd_signed_vma) Rvalue < 0) - { - check |= ((bfd_vma) - 1 - & ~((bfd_vma) - 1 - >> howto->rightshift)); - if (((bfd_vma) check & ~reloc_bits) - != (-(bfd_vma) 1 & ~reloc_bits)) - return bfd_reloc_overflow; - } - else - return bfd_reloc_overflow; - } - - /* Drop unwanted bits from the value we are relocating to. */ - Rvalue >>= (bfd_vma) howto->rightshift; - - /* Apply dst_mask to select only relocatable part of the insn. */ - Rvalue &= howto->dst_mask; - - switch (howto->size) - { - case 0: - if (r_type == R_CRX_REL4) - { - Rvalue <<= 4; - Rvalue |= (bfd_get_8 (input_bfd, hit_data) & 0x0f); - } - - bfd_put_8 (input_bfd, (unsigned char) Rvalue, hit_data); - break; - - case 1: - if (r_type == R_CRX_REGREL12) - Rvalue |= (bfd_get_16 (input_bfd, hit_data) & 0xf000); - - bfd_put_16 (input_bfd, Rvalue, hit_data); - break; - - case 2: - if (r_type == R_CRX_REL24 - || r_type == R_CRX_REGREL22 - || r_type == R_CRX_REGREL28) - Rvalue |= (((bfd_get_16 (input_bfd, hit_data) << 16) | - bfd_get_16 (input_bfd, hit_data + 2)) & ~howto->dst_mask); - - if (r_type == R_CRX_NUM32 || r_type == R_CRX_SWITCH32) - /* Relocation on DATA is purely little-endian, that is, for a - multi-byte datum, the lowest address in memory contains the - little end of the datum, that is, the least significant byte. - Therefore we use BFD's byte Putting functions. */ - bfd_put_32 (input_bfd, Rvalue, hit_data); - else - /* Relocation on INSTRUCTIONS is different : Instructions are - word-addressable, that is, each word itself is arranged according - to little-endian convention, whereas the words are arranged with - respect to one another in BIG ENDIAN fashion. - When there is an immediate value that spans a word boundary, it is - split in a big-endian way with respect to the words. */ - { - bfd_put_16 (input_bfd, (Rvalue >> 16) & 0xffff, hit_data); - bfd_put_16 (input_bfd, Rvalue & 0xffff, hit_data + 2); - } - break; - - default: - return bfd_reloc_notsupported; - } - - return bfd_reloc_ok; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -elf32_crx_relax_delete_bytes (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, bfd_vma addr, int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - struct elf_link_hash_entry **start_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset < toaddr)) - irel->r_offset -= count; - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - { - /* Adjust the addend of SWITCH relocations in this section, - which reference this local symbol. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - unsigned long r_symndx; - Elf_Internal_Sym *rsym; - bfd_vma addsym, subsym; - - /* Skip if not a SWITCH relocation. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH8 - && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH16 - && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_SWITCH32) - continue; - - r_symndx = ELF32_R_SYM (irel->r_info); - rsym = (Elf_Internal_Sym *) symtab_hdr->contents + r_symndx; - - /* Skip if not the local adjusted symbol. */ - if (rsym != isym) - continue; - - addsym = isym->st_value; - subsym = addsym - irel->r_addend; - - /* Fix the addend only when -->> (addsym > addr >= subsym). */ - if (subsym <= addr) - irel->r_addend -= count; - else - continue; - } - - isym->st_value -= count; - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = start_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - /* The '--wrap SYMBOL' option is causing a pain when the object file, - containing the definition of __wrap_SYMBOL, includes a direct - call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference - the same symbol (which is __wrap_SYMBOL), but still exist as two - different symbols in 'sym_hashes', we don't want to adjust - the global symbol __wrap_SYMBOL twice. - This check is only relevant when symbols are being wrapped. */ - if (link_info->wrap_hash != NULL) - { - struct elf_link_hash_entry **cur_sym_hashes; - - /* Loop only over the symbols whom been already checked. */ - for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; - cur_sym_hashes++) - { - /* If the current symbol is identical to 'sym_hash', that means - the symbol was already adjusted (or at least checked). */ - if (*cur_sym_hashes == sym_hash) - break; - } - /* Don't adjust the symbol again. */ - if (cur_sym_hashes < sym_hashes) - continue; - } - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; - } - - return TRUE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses elf32_crx_relocate_section. */ - -static bfd_byte * -elf32_crx_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - asection **secpp; - bfd_size_type amt; - - internal_relocs = (_bfd_elf_link_read_relocs - (input_bfd, input_section, NULL, - (Elf_Internal_Rela *) NULL, FALSE)); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! elf32_crx_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - return NULL; -} - -/* Relocate a CRX ELF section. */ - -static bfd_boolean -elf32_crx_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - howto = crx_elf_howto_table + (r_type); - - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = crx_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char *name; - const char *msg = (const char *) 0; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* Fall through. */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* This function handles relaxing for the CRX. - - There's quite a few relaxing opportunites available on the CRX: - - * bal/bcond:32 -> bal/bcond:16 2 bytes - * bcond:16 -> bcond:8 2 bytes - * cmpbcond:24 -> cmpbcond:8 2 bytes - * arithmetic imm32 -> arithmetic imm16 2 bytes - - Symbol- and reloc-reading infrastructure copied from elf-m10200.c. */ - -static bfd_boolean -elf32_crx_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL32 - && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL16 - && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_REL24 - && ELF32_R_TYPE (irel->r_info) != (int) R_CRX_IMM32) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Try to turn a 32bit pc-relative branch/call into - a 16bit pc-relative branch/call. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL32) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 16 bits, note the high value is - 0xfffe + 2 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 0x10000 && (long) value > -0x10002) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Verify it's a 'bal'/'bcond' and fix the opcode. */ - if ((code & 0xfff0) == 0x3170) - bfd_put_8 (abfd, 0x30, contents + irel->r_offset + 1); - else if ((code & 0xf0ff) == 0x707f) - bfd_put_8 (abfd, 0x7e, contents + irel->r_offset); - else - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CRX_REL16); - - /* Delete two bytes of data. */ - if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 16bit pc-relative branch into an - 8bit pc-relative branch. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL16) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 8 bits, note the high value is - 0xfc + 2 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 0xfe && (long) value > -0x100) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Verify it's a 'bcond' opcode. */ - if ((code & 0xf0ff) != 0x707e) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CRX_REL8); - - /* Delete two bytes of data. */ - if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 24bit pc-relative cmp&branch into - an 8bit pc-relative cmp&branch. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_REL24) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 8 bits, note the high value is - 0x7e + 2 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 0x100 && (long) value > -0x100) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Verify it's a 'cmp&branch' opcode. */ - if ((code & 0xfff0) != 0x3180 && (code & 0xfff0) != 0x3190 - && (code & 0xfff0) != 0x31a0 && (code & 0xfff0) != 0x31c0 - && (code & 0xfff0) != 0x31d0 && (code & 0xfff0) != 0x31e0 - /* Or a Co-processor branch ('bcop'). */ - && (code & 0xfff0) != 0x3010 && (code & 0xfff0) != 0x3110) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, 0x30, contents + irel->r_offset + 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CRX_REL8_CMP); - - /* Delete two bytes of data. */ - if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 4, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 32bit immediate address into - a 16bit immediate address. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_CRX_IMM32) - { - bfd_vma value = symval; - - /* See if the value will fit in 16 bits. */ - if ((long) value < 0x7fff && (long) value > -0x8000) - { - unsigned short code; - - /* Get the opcode. */ - code = (unsigned short) bfd_get_16 (abfd, contents + irel->r_offset); - - /* Verify it's a 'arithmetic double'. */ - if ((code & 0xf0f0) != 0x20f0) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the opcode. */ - bfd_put_8 (abfd, (code & 0xff) - 0x10, contents + irel->r_offset); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_CRX_IMM16); - - /* Delete two bytes of data. */ - if (!elf32_crx_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* Definitions for setting CRX target vector. */ -#define TARGET_LITTLE_SYM crx_elf32_vec -#define TARGET_LITTLE_NAME "elf32-crx" -#define ELF_ARCH bfd_arch_crx -#define ELF_MACHINE_CODE EM_CRX -#define ELF_MAXPAGESIZE 0x1 -#define elf_symbol_leading_char '_' - -#define bfd_elf32_bfd_reloc_type_lookup elf_crx_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - elf_crx_reloc_name_lookup -#define elf_info_to_howto elf_crx_info_to_howto -#define elf_info_to_howto_rel 0 -#define elf_backend_relocate_section elf32_crx_relocate_section -#define bfd_elf32_bfd_relax_section elf32_crx_relax_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - elf32_crx_get_relocated_section_contents -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-d10v.c b/sdcc/support/sdbinutils/bfd/elf32-d10v.c deleted file mode 100644 index 0d1453cbc..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-d10v.c +++ /dev/null @@ -1,551 +0,0 @@ -/* D10V-specific support for 32-bit ELF - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Contributed by Martin Hunt (hunt@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/d10v.h" - -/* Use REL instead of RELA to save space. */ -#define USE_REL 1 - -static reloc_howto_type elf_d10v_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_D10V_NONE, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_NONE", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* An PC Relative 10-bit relocation, shifted by 2, right container. */ - HOWTO (R_D10V_10_PCREL_R, /* Type. */ - 2, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_10_PCREL_R", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xff, /* Src_mask. */ - 0xff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* An PC Relative 10-bit relocation, shifted by 2, left container. */ - HOWTO (R_D10V_10_PCREL_L, /* Type. */ - 2, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - TRUE, /* PC_relative. */ - 15, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_10_PCREL_L", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x07f8000, /* Src_mask. */ - 0x07f8000, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_D10V_16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_16", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* An 18 bit absolute relocation, right shifted 2. */ - HOWTO (R_D10V_18, /* Type. */ - 2, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_18", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A relative 18 bit relocation, right shifted by 2. */ - HOWTO (R_D10V_18_PCREL, /* Type. */ - 2, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_18_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_D10V_32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D10V_32", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_D10V_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_D10V_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_D10V_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_D10V_GNU_VTENTRY", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ -}; - -/* Map BFD reloc types to D10V ELF reloc types. */ - -struct d10v_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct d10v_reloc_map d10v_reloc_map[] = -{ - { BFD_RELOC_NONE, R_D10V_NONE, }, - { BFD_RELOC_D10V_10_PCREL_R, R_D10V_10_PCREL_R }, - { BFD_RELOC_D10V_10_PCREL_L, R_D10V_10_PCREL_L }, - { BFD_RELOC_16, R_D10V_16 }, - { BFD_RELOC_D10V_18, R_D10V_18 }, - { BFD_RELOC_D10V_18_PCREL, R_D10V_18_PCREL }, - { BFD_RELOC_32, R_D10V_32 }, - { BFD_RELOC_VTABLE_INHERIT, R_D10V_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_D10V_GNU_VTENTRY }, -}; - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (d10v_reloc_map) / sizeof (struct d10v_reloc_map); - i++) - if (d10v_reloc_map[i].bfd_reloc_val == code) - return &elf_d10v_howto_table[d10v_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf_d10v_howto_table) / sizeof (elf_d10v_howto_table[0]); - i++) - if (elf_d10v_howto_table[i].name != NULL - && strcasecmp (elf_d10v_howto_table[i].name, r_name) == 0) - return &elf_d10v_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an D10V ELF reloc. */ - -static void -d10v_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_D10V_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid D10V reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_d10v_howto_table[r_type]; -} - -static asection * -elf32_d10v_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_D10V_GNU_VTINHERIT: - case R_D10V_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -elf32_d10v_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_D10V_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_D10V_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - } - } - - return TRUE; -} - -static bfd_vma -extract_rel_addend (bfd *abfd, - bfd_byte *where, - reloc_howto_type *howto) -{ - bfd_vma insn, val; - - switch (howto->size) - { - case 0: - insn = bfd_get_8 (abfd, where); - break; - case 1: - insn = bfd_get_16 (abfd, where); - break; - case 2: - insn = bfd_get_32 (abfd, where); - break; - default: - abort (); - } - - val = (insn & howto->dst_mask) >> howto->bitpos << howto->rightshift; - /* We should really be testing for signed addends here, but we don't - have that info directly in the howto. */ - if (howto->pc_relative) - { - bfd_vma sign; - sign = howto->dst_mask & (~howto->dst_mask >> 1 | ~(-(bfd_vma) 1 >> 1)); - sign = sign >> howto->bitpos << howto->rightshift; - val = (val ^ sign) - sign; - } - return val; -} - -static void -insert_rel_addend (bfd *abfd, - bfd_byte *where, - reloc_howto_type *howto, - bfd_vma addend) -{ - bfd_vma insn; - - addend = (addend >> howto->rightshift << howto->bitpos) & howto->dst_mask; - insn = ~howto->dst_mask; - switch (howto->size) - { - case 0: - insn &= bfd_get_8 (abfd, where); - insn |= addend; - bfd_put_8 (abfd, insn, where); - break; - case 1: - insn &= bfd_get_16 (abfd, where); - insn |= addend; - bfd_put_16 (abfd, insn, where); - break; - case 2: - insn &= bfd_get_32 (abfd, where); - insn |= addend; - bfd_put_32 (abfd, insn, where); - break; - default: - abort (); - } -} - -/* Relocate a D10V ELF section. */ - -static bfd_boolean -elf32_d10v_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - const char *name; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_D10V_GNU_VTENTRY - || r_type == R_D10V_GNU_VTINHERIT) - continue; - - howto = elf_d10v_howto_table + r_type; - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION - && ((sec->flags & SEC_MERGE) != 0 - || (bfd_link_relocatable (info) - && sec->output_offset != 0))) - { - bfd_vma addend; - bfd_byte *where = contents + rel->r_offset; - - addend = extract_rel_addend (input_bfd, where, howto); - - if (bfd_link_relocatable (info)) - addend += sec->output_offset; - else - { - asection *msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, - addend); - addend -= relocation; - addend += msec->output_section->vma + msec->output_offset; - } - insert_rel_addend (input_bfd, where, howto, addend); - } - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, (bfd_vma) 0); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) 0; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} -#define ELF_ARCH bfd_arch_d10v -#define ELF_MACHINE_CODE EM_D10V -#define ELF_MACHINE_ALT1 EM_CYGNUS_D10V -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM d10v_elf32_vec -#define TARGET_BIG_NAME "elf32-d10v" - -#define elf_info_to_howto 0 -#define elf_info_to_howto_rel d10v_info_to_howto_rel -#define elf_backend_object_p 0 -#define elf_backend_final_write_processing 0 -#define elf_backend_gc_mark_hook elf32_d10v_gc_mark_hook -#define elf_backend_check_relocs elf32_d10v_check_relocs -#define elf_backend_relocate_section elf32_d10v_relocate_section -#define elf_backend_can_gc_sections 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-d30v.c b/sdcc/support/sdbinutils/bfd/elf32-d30v.c deleted file mode 100644 index 51d9b88c6..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-d30v.c +++ /dev/null @@ -1,560 +0,0 @@ -/* D30V-specific support for 32-bit ELF - Copyright (C) 1997-2018 Free Software Foundation, Inc. - Contributed by Martin Hunt (hunt@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/d30v.h" - -#define MAX32 ((bfd_signed_vma) 0x7fffffff) -#define MIN32 (- MAX32 - 1) - -static bfd_reloc_status_type -bfd_elf_d30v_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_signed_vma relocation; - bfd_vma in1, in2, num; - bfd_vma tmp_addr = 0; - bfd_reloc_status_type r; - asection *reloc_target_output_section; - bfd_size_type addr = reloc_entry->address; - bfd_reloc_status_type flag = bfd_reloc_ok; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - int make_absolute = 0; - - if (output_bfd != NULL) - { - /* Partial linking -- do nothing. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - if (r != bfd_reloc_continue) - return r; - - /* A hacked-up version of bfd_perform_reloc() follows. */ - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && output_bfd == NULL) - flag = bfd_reloc_undefined; - - /* 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. */ - 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) - { - tmp_addr = input_section->output_section->vma - + input_section->output_offset - + reloc_entry->address; - relocation -= tmp_addr; - } - - in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr); - in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4); - - /* Extract the addend. */ - num = ((in2 & 0x3FFFF) - | ((in2 & 0xFF00000) >> 2) - | ((in1 & 0x3F) << 26)); - in1 &= 0xFFFFFFC0; - in2 = 0x80000000; - - relocation += num; - - if (howto->pc_relative && howto->bitsize == 32) - { - /* The D30V has a PC that doesn't wrap and PC-relative jumps are - signed, so a PC-relative jump can't be more than +/- 2^31 bytes. - If one exceeds this, change it to an absolute jump. */ - if (relocation > MAX32 || relocation < MIN32) - { - relocation = (relocation + tmp_addr) & 0xffffffff; - make_absolute = 1; - } - } - - in1 |= (relocation >> 26) & 0x3F; /* Top 6 bits. */ - in2 |= ((relocation & 0x03FC0000) << 2); /* Next 8 bits. */ - in2 |= relocation & 0x0003FFFF; /* Bottom 18 bits. */ - - /* Change a PC-relative instruction to its - absolute equivalent with this simple hack. */ - if (make_absolute) - in1 |= 0x00100000; - - bfd_put_32 (abfd, in1, (bfd_byte *) data + addr); - bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4); - - return flag; -} - -static bfd_reloc_status_type -bfd_elf_d30v_reloc_21 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_vma relocation; - bfd_vma in1, num; - bfd_reloc_status_type r; - asection *reloc_target_output_section; - bfd_size_type addr = reloc_entry->address; - bfd_reloc_status_type flag = bfd_reloc_ok; - bfd_vma output_base = 0; - reloc_howto_type *howto = reloc_entry->howto; - int mask, max; - - if (output_bfd != NULL) - { - /* Partial linking -- do nothing. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - if (r != bfd_reloc_continue) - return r; - - /* A hacked-up version of bfd_perform_reloc() follows. */ - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && output_bfd == NULL) - flag = bfd_reloc_undefined; - - /* 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. */ - 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) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset); - if (howto->pcrel_offset) - relocation -= reloc_entry->address; - } - - in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr); - - mask = (1 << howto->bitsize) - 1; - if (howto->bitsize == 6) - mask <<= 12; - max = (1 << (howto->bitsize + 2)) - 1; - - /* Extract the addend. */ - num = in1 & mask; /* 18 bits. */ - if (howto->bitsize == 6) - num >>= 12; - num <<= 3; /* shift left 3. */ - in1 &= ~mask; /* Mask out addend. */ - - relocation += num; - if (howto->type == R_D30V_21_PCREL_R - || howto->type == R_D30V_15_PCREL_R - || howto->type == R_D30V_9_PCREL_R) - relocation += 4; - - if ((int) relocation < 0) - { - if (~ (int) relocation > max) - flag = bfd_reloc_overflow; - } - else - { - if ((int) relocation > max) - flag = bfd_reloc_overflow; - } - - relocation >>= 3; - if (howto->bitsize == 6) - in1 |= ((relocation & (mask >> 12)) << 12); - else - in1 |= relocation & mask; - - bfd_put_32 (abfd, in1, (bfd_byte *) data + addr); - - return flag; -} - -static reloc_howto_type elf_d30v_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_D30V_NONE, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D30V_NONE", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A 6 bit absolute relocation. */ - HOWTO (R_D30V_6, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 6, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D30V_6", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3f, /* Src_mask. */ - 0x3f, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A relative 9 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_9_PCREL, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 6, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc_21, /* Special_function. */ - "R_D30V_9_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3f, /* Src_mask. */ - 0x3f, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A relative 9 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_9_PCREL_R, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 6, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc_21, /* Special_function. */ - "R_D30V_9_PCREL_R", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3f, /* Src_mask. */ - 0x3f, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* An absolute 15 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_15, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 12, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D30V_15", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfff, /* Src_mask. */ - 0xfff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A relative 15 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_15_PCREL, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 12, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc_21, /* Special_function. */ - "R_D30V_15_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfff, /* Src_mask. */ - 0xfff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A relative 15 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_15_PCREL_R, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 12, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc_21, /* Special_function. */ - "R_D30V_15_PCREL_R", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfff, /* Src_mask. */ - 0xfff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* An absolute 21 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_21, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 18, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D30V_21", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3ffff, /* Src_mask. */ - 0x3ffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A relative 21 bit relocation, right shifted by 3. */ - HOWTO (R_D30V_21_PCREL, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 18, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc_21, /* Special_function. */ - "R_D30V_21_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3ffff, /* Src_mask. */ - 0x3ffff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A relative 21 bit relocation, right shifted by 3, in the Right container. */ - HOWTO (R_D30V_21_PCREL_R, /* Type. */ - 3, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 18, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc_21, /* Special_function. */ - "R_D30V_21_PCREL_R", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3ffff, /* Src_mask. */ - 0x3ffff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A D30V 32 bit absolute relocation. */ - HOWTO (R_D30V_32, /* Type. */ - 0, /* Rightshift. */ - 4, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc, /* Special_function. */ - "R_D30V_32", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A relative 32 bit relocation. */ - HOWTO (R_D30V_32_PCREL, /* Type. */ - 0, /* Rightshift. */ - 4, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - bfd_elf_d30v_reloc, /* Special_function. */ - "R_D30V_32_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A regular 32 bit absolute relocation. */ - HOWTO (R_D30V_32_NORMAL, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_D30V_32_NORMAL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - -}; - -/* Map BFD reloc types to D30V ELF reloc types. */ - -struct d30v_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct d30v_reloc_map d30v_reloc_map[] = -{ - { BFD_RELOC_NONE, R_D30V_NONE, }, - { BFD_RELOC_D30V_6, R_D30V_6 }, - { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL }, - { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R }, - { BFD_RELOC_D30V_15, R_D30V_15 }, - { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL }, - { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R }, - { BFD_RELOC_D30V_21, R_D30V_21 }, - { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL }, - { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R }, - { BFD_RELOC_D30V_32, R_D30V_32 }, - { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL }, - { BFD_RELOC_32, R_D30V_32_NORMAL }, -}; - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map); - i++) - { - if (d30v_reloc_map[i].bfd_reloc_val == code) - return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf_d30v_howto_table) / sizeof (elf_d30v_howto_table[0]); - i++) - if (elf_d30v_howto_table[i].name != NULL - && strcasecmp (elf_d30v_howto_table[i].name, r_name) == 0) - return &elf_d30v_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an D30V ELF reloc (type REL). */ - -static void -d30v_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_D30V_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid D30V reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_d30v_howto_table[r_type]; -} - -/* Set the howto pointer for an D30V ELF reloc (type RELA). */ - -static void -d30v_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_D30V_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid D30V reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_d30v_howto_table[r_type]; -} - -#define ELF_ARCH bfd_arch_d30v -#define ELF_MACHINE_CODE EM_D30V -#define ELF_MACHINE_ALT1 EM_CYGNUS_D30V -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM d30v_elf32_vec -#define TARGET_BIG_NAME "elf32-d30v" - -#define elf_info_to_howto d30v_info_to_howto_rela -#define elf_info_to_howto_rel d30v_info_to_howto_rel -#define elf_backend_object_p 0 -#define elf_backend_final_write_processing 0 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-dlx.c b/sdcc/support/sdbinutils/bfd/elf32-dlx.c deleted file mode 100644 index 468e6cbfa..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-dlx.c +++ /dev/null @@ -1,581 +0,0 @@ -/* DLX specific support for 32-bit ELF - Copyright (C) 2002-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/dlx.h" -#include "elf32-dlx.h" - -#define USE_REL 1 - -#define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf32_dlx_reloc_name_lookup -#define elf_info_to_howto elf32_dlx_info_to_howto -#define elf_info_to_howto_rel elf32_dlx_info_to_howto_rel -#define elf_backend_check_relocs elf32_dlx_check_relocs - -/* The gas default behavior is not to preform the %hi modifier so that the - GNU assembler can have the lower 16 bits offset placed in the insn, BUT - we do like the gas to indicate it is %hi reloc type so when we in the link - loader phase we can have the corrected hi16 vale replace the buggous lo16 - value that was placed there by gas. */ - -static int skip_dlx_elf_hi16_reloc = 0; - -int -set_dlx_skip_hi16_flag (int flag) -{ - skip_dlx_elf_hi16_reloc = flag; - return flag; -} - -static bfd_reloc_status_type -_bfd_dlx_elf_hi16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - - /* If the skip flag is set then we simply do the generic relocating, this - is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo - fixup like mips gld did. */ - if (skip_dlx_elf_hi16_reloc) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - ret = bfd_reloc_ok; - - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - ret = bfd_reloc_undefined; - - relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value; - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address); - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF), - (bfd_byte *)data + reloc_entry->address); - - return ret; -} - -/* 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. */ - -static bfd_reloc_status_type -elf32_dlx_relocate16 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - unsigned long insn, vallo, allignment; - int val; - - /* HACK: I think this first condition is necessary when producing - relocatable output. After the end of HACK, the code is identical - to bfd_elf_generic_reloc(). I would _guess_ the first change - belongs there rather than here. martindo 1998-10-23. */ - - if (skip_dlx_elf_hi16_reloc) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* Check undefined section and undefined symbols. */ - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - /* Can not support a long jump to sections other then .text. */ - if (strcmp (input_section->name, symbol->section->output_section->name) != 0) - { - _bfd_error_handler - (_("BFD Link Error: branch (PC rel16) to section (%s) not supported"), - symbol->section->output_section->name); - return bfd_reloc_undefined; - } - - insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address); - allignment = 1 << (input_section->output_section->alignment_power - 1); - vallo = insn & 0x0000FFFF; - - if (vallo & 0x8000) - vallo = ~(vallo | 0xFFFF0000) + 1; - - /* vallo points to the vma of next instruction. */ - vallo += (((unsigned long)(input_section->output_section->vma + - input_section->output_offset) + - allignment) & ~allignment); - - /* val is the displacement (PC relative to next instruction). */ - val = (symbol->section->output_offset + - symbol->section->output_section->vma + - symbol->value) - vallo; - - if (abs ((int) val) > 0x00007FFF) - return bfd_reloc_outofrange; - - insn = (insn & 0xFFFF0000) | (val & 0x0000FFFF); - - bfd_put_32 (abfd, insn, - (bfd_byte *) data + reloc_entry->address); - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -elf32_dlx_relocate26 (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - unsigned long insn, vallo, allignment; - int val; - - /* HACK: I think this first condition is necessary when producing - relocatable output. After the end of HACK, the code is identical - to bfd_elf_generic_reloc(). I would _guess_ the first change - belongs there rather than here. martindo 1998-10-23. */ - - if (skip_dlx_elf_hi16_reloc) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* Check undefined section and undefined symbols. */ - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - /* Can not support a long jump to sections other then .text */ - if (strcmp (input_section->name, symbol->section->output_section->name) != 0) - { - _bfd_error_handler - (_("BFD Link Error: jump (PC rel26) to section (%s) not supported"), - symbol->section->output_section->name); - return bfd_reloc_undefined; - } - - insn = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address); - allignment = 1 << (input_section->output_section->alignment_power - 1); - vallo = insn & 0x03FFFFFF; - - if (vallo & 0x03000000) - vallo = ~(vallo | 0xFC000000) + 1; - - /* vallo is the vma for the next instruction. */ - vallo += (((unsigned long) (input_section->output_section->vma + - input_section->output_offset) + - allignment) & ~allignment); - - /* val is the displacement (PC relative to next instruction). */ - val = (symbol->section->output_offset + - symbol->section->output_section->vma + symbol->value) - - vallo; - - if (abs ((int) val) > 0x01FFFFFF) - return bfd_reloc_outofrange; - - insn = (insn & 0xFC000000) | (val & 0x03FFFFFF); - bfd_put_32 (abfd, insn, - (bfd_byte *) data + reloc_entry->address); - - return bfd_reloc_ok; -} - -static reloc_howto_type dlx_elf_howto_table[]= -{ - /* No relocation. */ - HOWTO (R_DLX_NONE, /* Type. */ - 0, /* Rightshift. */ - 3, /* size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_DLX_NONE", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 8 bit relocation. */ - HOWTO (R_DLX_RELOC_8, /* Type. */ - 0, /* Rightshift. */ - 0, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_DLX_RELOC_8", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xff, /* Src_mask. */ - 0xff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit relocation. */ - HOWTO (R_DLX_RELOC_16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_DLX_RELOC_16", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 32 bit relocation. */ - HOWTO (R_DLX_RELOC_32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_DLX_RELOC_32", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_DLX_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_DLX_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_DLX_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_DLX_GNU_VTENTRY", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE) /* PCrel_offset. */ -}; - -/* 16 bit offset for pc-relative branches. */ -static reloc_howto_type elf_dlx_gnu_rel16_s2 = - HOWTO (R_DLX_RELOC_16_PCREL, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - elf32_dlx_relocate16, /* Special_function. */ - "R_DLX_RELOC_16_PCREL",/* Name. */ - TRUE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - TRUE); /* PCrel_offset. */ - -/* 26 bit offset for pc-relative branches. */ -static reloc_howto_type elf_dlx_gnu_rel26_s2 = - HOWTO (R_DLX_RELOC_26_PCREL, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 26, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - elf32_dlx_relocate26, /* Special_function. */ - "R_DLX_RELOC_26_PCREL",/* Name. */ - TRUE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - TRUE); /* PCrel_offset. */ - -/* High 16 bits of symbol value. */ -static reloc_howto_type elf_dlx_reloc_16_hi = - HOWTO (R_DLX_RELOC_16_HI, /* Type. */ - 16, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - _bfd_dlx_elf_hi16_reloc,/* Special_function. */ - "R_DLX_RELOC_16_HI", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xFFFF, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE); /* PCrel_offset. */ - - /* Low 16 bits of symbol value. */ -static reloc_howto_type elf_dlx_reloc_16_lo = - HOWTO (R_DLX_RELOC_16_LO, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont,/* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_DLX_RELOC_16_LO", /* Name. */ - TRUE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE); /* PCrel_offset. */ - -/* A mapping from BFD reloc types to DLX ELF reloc types. - Stolen from elf32-mips.c. - - More about this table - for dlx elf relocation we do not really - need this table, if we have a rtype defined in this table will - caused tc_gen_relocate confused and die on us, but if we remove - this table it will caused more problem, so for now simple solution - is to remove those entries which may cause problem. */ -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - enum elf_dlx_reloc_type elf_reloc_val; -}; - -static const struct elf_reloc_map dlx_reloc_map[] = -{ - { BFD_RELOC_NONE, R_DLX_NONE }, - { BFD_RELOC_16, R_DLX_RELOC_16 }, - { BFD_RELOC_32, R_DLX_RELOC_32 }, - { BFD_RELOC_DLX_HI16_S, R_DLX_RELOC_16_HI }, - { BFD_RELOC_DLX_LO16, R_DLX_RELOC_16_LO }, - { BFD_RELOC_VTABLE_INHERIT, R_DLX_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_DLX_GNU_VTENTRY } -}; - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -elf32_dlx_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_DLX_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_DLX_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* Given a BFD reloc type, return a howto structure. */ - -static reloc_howto_type * -elf32_dlx_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++) - if (dlx_reloc_map[i].bfd_reloc_val == code) - return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val]; - - switch (code) - { - default: - bfd_set_error (bfd_error_bad_value); - return NULL; - case BFD_RELOC_16_PCREL_S2: - return &elf_dlx_gnu_rel16_s2; - case BFD_RELOC_DLX_JMP26: - return &elf_dlx_gnu_rel26_s2; - case BFD_RELOC_HI16_S: - return &elf_dlx_reloc_16_hi; - case BFD_RELOC_LO16: - return &elf_dlx_reloc_16_lo; - } -} - -static reloc_howto_type * -elf32_dlx_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (dlx_elf_howto_table) / sizeof (dlx_elf_howto_table[0]); - i++) - if (dlx_elf_howto_table[i].name != NULL - && strcasecmp (dlx_elf_howto_table[i].name, r_name) == 0) - return &dlx_elf_howto_table[i]; - - if (strcasecmp (elf_dlx_gnu_rel16_s2.name, r_name) == 0) - return &elf_dlx_gnu_rel16_s2; - if (strcasecmp (elf_dlx_gnu_rel26_s2.name, r_name) == 0) - return &elf_dlx_gnu_rel26_s2; - if (strcasecmp (elf_dlx_reloc_16_hi.name, r_name) == 0) - return &elf_dlx_reloc_16_hi; - if (strcasecmp (elf_dlx_reloc_16_lo.name, r_name) == 0) - return &elf_dlx_reloc_16_lo; - - return NULL; -} - -static reloc_howto_type * -dlx_rtype_to_howto (unsigned int r_type) -{ - switch (r_type) - { - case R_DLX_RELOC_16_PCREL: - return & elf_dlx_gnu_rel16_s2; - case R_DLX_RELOC_26_PCREL: - return & elf_dlx_gnu_rel26_s2; - case R_DLX_RELOC_16_HI: - return & elf_dlx_reloc_16_hi; - case R_DLX_RELOC_16_LO: - return & elf_dlx_reloc_16_lo; - default: - if (r_type >= (unsigned int) R_DLX_max) - { - _bfd_error_handler (_("Invalid DLX reloc number: %d"), r_type); - r_type = 0; - } - return & dlx_elf_howto_table[r_type]; - } -} - -static void -elf32_dlx_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr ATTRIBUTE_UNUSED, - Elf_Internal_Rela * dst ATTRIBUTE_UNUSED) -{ - abort (); -} - -static void -elf32_dlx_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - cache_ptr->howto = dlx_rtype_to_howto (r_type); - return; -} - -#define TARGET_BIG_SYM dlx_elf32_be_vec -#define TARGET_BIG_NAME "elf32-dlx" -#define ELF_ARCH bfd_arch_dlx -#define ELF_MACHINE_CODE EM_DLX -#define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */ - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-dlx.h b/sdcc/support/sdbinutils/bfd/elf32-dlx.h deleted file mode 100644 index a0310c3c8..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-dlx.h +++ /dev/null @@ -1,34 +0,0 @@ -/* DLX specific support for 32-bit ELF - Copyright (C) 2002-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_DLX_H -#define _ELF32_DLX_H - -#ifdef __cplusplus -extern "C" { -#endif - -extern int set_dlx_skip_hi16_flag (int); - -#ifdef __cplusplus - } -#endif - -#endif /* _ELF32_DLX_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-epiphany.c b/sdcc/support/sdbinutils/bfd/elf32-epiphany.c deleted file mode 100644 index 1ad1184cc..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-epiphany.c +++ /dev/null @@ -1,612 +0,0 @@ -/* Adapteva epiphany specific support for 32-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Embecosm on behalf of Adapteva, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/epiphany.h" -#include "libiberty.h" - -/* Struct used to pass miscellaneous paramaters which - helps to avoid overly long parameter lists. */ -struct misc -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Rela * irelbase; - bfd_byte * contents; - Elf_Internal_Sym * isymbuf; -}; - -struct epiphany_opcode -{ - unsigned short opcode; - unsigned short mask; -}; - -static bfd_boolean epiphany_relaxed = FALSE; - -/* Relocation tables. */ -static reloc_howto_type epiphany_elf_howto_table [] = -{ -#define AHOW(t,rs,s,bs,pr,bp,co,name,sm,dm) \ - HOWTO(t, /* type */ \ - rs, /* rightshift */ \ - s, /* size (0 = byte, 1 = short, 2 = long) */ \ - bs, /* bitsize */ \ - pr, /* pc_relative */ \ - bp, /* bitpos */ \ - co, /* complain_on_overflow */ \ - bfd_elf_generic_reloc,/* special_function */ \ - name, /* name */ \ - FALSE, /* partial_inplace */ \ - sm, /* src_mask */ \ - dm, /* dst_mask */ \ - pr) /* pcrel_offset */ - - /* This reloc does nothing. */ - AHOW (R_EPIPHANY_NONE, 0, 3,0, FALSE, 0, complain_overflow_dont, "R_EPIPHANY_NONE", 0, 0), - - /* 8 bit absolute (not likely) */ - AHOW (R_EPIPHANY_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, "R_EPIPHANY_8", 0x000000ff, 0x000000ff), - /* 16 bit absolute */ - AHOW (R_EPIPHANY_16, 0, 1,16, FALSE, 0, complain_overflow_bitfield, "R_EPIPHANY_16", 0x0000ffff, 0x00ff1fe0), - /* A 32 bit absolute relocation. */ - AHOW (R_EPIPHANY_32, 0, 2,32, FALSE, 0, complain_overflow_dont, "R_EPIPHANY_32", 0xffffffff, 0xffffffff), - - /* 8 bit relative relocation */ - HOWTO ( R_EPIPHANY_8_PCREL, 0, 0, 8, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_EPIPHANY_8_PCREL", FALSE, 0x000000ff, 0x000000ff, FALSE), - /* 16 bit relative relocation */ - HOWTO ( R_EPIPHANY_16_PCREL, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_EPIPHANY_8_PCREL", FALSE, 0x000000ff, 0x000000ff, FALSE), - /* 32 bit relative relocation */ - HOWTO ( R_EPIPHANY_32_PCREL, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_EPIPHANY_8_PCREL", FALSE, 0x000000ff, 0x000000ff, FALSE), - - /* 8 bit pc-relative relocation */ - AHOW (R_EPIPHANY_SIMM8, 1, 0, 8, TRUE, 8, complain_overflow_signed, "R_EPIPHANY_SIMM8", 0x000000ff, 0x0000ff00), - /* 24 bit pc-relative relocation */ - AHOW (R_EPIPHANY_SIMM24, 1, 2,24, TRUE, 8, complain_overflow_signed, "R_EPIPHANY_SIMM24", 0x00ffffff, 0xffffff00), - - /* %HIGH(EA) */ - AHOW (R_EPIPHANY_HIGH, 0, 2,16, FALSE, 0, complain_overflow_dont, "R_EPIPHANY_HIGH", 0x0ff01fe0, 0x0ff01fe0), - - /* %LOW(EA) */ - AHOW (R_EPIPHANY_LOW, 0, 2,16, FALSE, 0, complain_overflow_dont, "R_EPIPHANY_LOW", 0x0ff01fe0, 0x0ff01fe0), - - /* simm11 */ - AHOW (R_EPIPHANY_SIMM11, 0, 2,11, FALSE, 0, complain_overflow_bitfield, "R_EPIPHANY_SIMM11", 0x00ff0380, 0x00ff0380), - /* imm12 - sign-magnitude */ - AHOW (R_EPIPHANY_IMM11, 0, 2,11, FALSE, 0, complain_overflow_bitfield, "R_EPIPHANY_IMM12", 0x00ff0380, 0x00ff0380), - /* imm8 */ - AHOW (R_EPIPHANY_IMM8, 0, 1, 8, FALSE, 8, complain_overflow_signed, "R_EPIPHANY_IMM8", 0x0000ff00, 0x0000ff00) - - -}; -#undef AHOW - -/* Map BFD reloc types to EPIPHANY ELF reloc types. */ - -static reloc_howto_type * -epiphany_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - /* Note that the epiphany_elf_howto_table is indxed by the R_ - constants. Thus, the order that the howto records appear in the - table *must* match the order of the relocation types defined in - include/elf/epiphany.h. */ - - switch (code) - { - case BFD_RELOC_NONE: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_NONE]; - - case BFD_RELOC_EPIPHANY_SIMM8: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_SIMM8]; - case BFD_RELOC_EPIPHANY_SIMM24: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_SIMM24]; - - case BFD_RELOC_8_PCREL: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_8_PCREL]; - case BFD_RELOC_16_PCREL: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_16_PCREL]; - case BFD_RELOC_32_PCREL: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_32_PCREL]; - - case BFD_RELOC_8: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_8]; - case BFD_RELOC_16: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_16]; - case BFD_RELOC_32: - return &epiphany_elf_howto_table[ (int) R_EPIPHANY_32]; - - case BFD_RELOC_EPIPHANY_HIGH: - return & epiphany_elf_howto_table[ (int) R_EPIPHANY_HIGH]; - case BFD_RELOC_EPIPHANY_LOW: - return & epiphany_elf_howto_table[ (int) R_EPIPHANY_LOW]; - - case BFD_RELOC_EPIPHANY_SIMM11: - return & epiphany_elf_howto_table[ (int) R_EPIPHANY_SIMM11]; - case BFD_RELOC_EPIPHANY_IMM11: - return & epiphany_elf_howto_table[ (int) R_EPIPHANY_IMM11]; - - case BFD_RELOC_EPIPHANY_IMM8: - return & epiphany_elf_howto_table[ (int) R_EPIPHANY_IMM8]; - - default: - /* Pacify gcc -Wall. */ - return NULL; - } - return NULL; -} - -static reloc_howto_type * -epiphany_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (epiphany_elf_howto_table); i++) - if (epiphany_elf_howto_table[i].name != NULL - && strcasecmp (epiphany_elf_howto_table[i].name, r_name) == 0) - return &epiphany_elf_howto_table[i]; - - return NULL; -} - -#define PAGENO(ABSADDR) ((ABSADDR) & 0xFFFFC000) -#define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset) - -/* This function handles relaxing for the epiphany. - Dummy placeholder for future optimizations. */ - -static bfd_boolean -epiphany_elf_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - static asection * first_section = NULL; - static unsigned long search_addr; - static unsigned long page_start = 0; - static unsigned long page_end = 0; - static unsigned int pass = 0; - static bfd_boolean new_pass = FALSE; - static bfd_boolean changed = FALSE; - struct misc misc ATTRIBUTE_UNUSED; - asection *stab; - - /* Assume nothing changes. */ - *again = FALSE; - - if (first_section == NULL) - { - epiphany_relaxed = TRUE; - first_section = sec; - } - - if (first_section == sec) - { - pass++; - new_pass = TRUE; - } - - /* We don't have to do anything for a relocatable link, - if this section does not have relocs, or if this is - not a code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Make sure the stac.rela stuff gets read in. */ - stab = bfd_get_section_by_name (abfd, ".stab"); - - if (stab) - { - /* So stab does exits. */ - Elf_Internal_Rela * irelbase ATTRIBUTE_UNUSED; - - irelbase = _bfd_elf_link_read_relocs (abfd, stab, NULL, NULL, - link_info->keep_memory); - } - - /* Get section contents cached copy if it exists. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's symbols cached copy if it exists. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - misc.symtab_hdr = symtab_hdr; - misc.isymbuf = isymbuf; - misc.irelbase = internal_relocs; - misc.contents = contents; - - /* This is where all the relaxation actually get done. */ - if ((pass == 1) || (new_pass && !changed)) - { - /* On the first pass we simply search for the lowest page that - we havn't relaxed yet. Note that the pass count is reset - each time a page is complete in order to move on to the next page. - If we can't find any more pages then we are finished. */ - if (new_pass) - { - pass = 1; - new_pass = FALSE; - changed = TRUE; /* Pre-initialize to break out of pass 1. */ - search_addr = 0xFFFFFFFF; - } - - if ((BASEADDR (sec) + sec->size < search_addr) - && (BASEADDR (sec) + sec->size > page_end)) - { - if (BASEADDR (sec) <= page_end) - search_addr = page_end + 1; - else - search_addr = BASEADDR (sec); - - /* Found a page => more work to do. */ - *again = TRUE; - } - } - else - { - if (new_pass) - { - new_pass = FALSE; - changed = FALSE; - page_start = PAGENO (search_addr); - page_end = page_start | 0x00003FFF; - } - - /* Only process sections in range. */ - if ((BASEADDR (sec) + sec->size >= page_start) - && (BASEADDR (sec) <= page_end)) - { -#if 0 - if (!epiphany_elf_relax_section_page (abfd, sec, &changed, &misc, - page_start, page_end)) -#endif - return FALSE; - } - *again = TRUE; - } - - /* Perform some house keeping after relaxing the section. */ - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - symtab_hdr->contents = (unsigned char *) isymbuf; - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -/* Set the howto pointer for a EPIPHANY ELF reloc. */ - -static void -epiphany_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_EPIPHANY_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid Epiphany reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & epiphany_elf_howto_table [r_type]; -} - -/* Perform a single relocation. - By default we use the standard BFD routines. */ - -static bfd_reloc_status_type -epiphany_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation) -{ - switch (howto->type) - { - /* Handle 16 bit immediates. */ - case R_EPIPHANY_HIGH: - relocation += rel->r_addend; - relocation >>= 16; - goto common; - - case R_EPIPHANY_LOW: - relocation += rel->r_addend; - common: - relocation = ((relocation & 0xff00L) << 12) - | ((relocation & 0x00ffL) << 5); - /* Sanity check the address. */ - if (rel->r_offset > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - return _bfd_relocate_contents (howto, input_bfd, relocation, - contents + rel->r_offset); - - case R_EPIPHANY_SIMM11: - relocation += rel->r_addend; - /* Check signed overflow. */ - if ((int)relocation > 1023 || (int)relocation < -1024) - return bfd_reloc_outofrange; - goto disp11; - - case R_EPIPHANY_IMM11: - relocation += rel->r_addend; - if ((unsigned int) relocation > 0x7ff) - return bfd_reloc_outofrange; - /* Fall through. */ - disp11: - relocation = (((relocation & 7) << 5) - | ((relocation & 0x7f8 ) << 13)); - return _bfd_relocate_contents (howto, input_bfd, relocation, - contents + rel->r_offset); - - /* Pass others through. */ - default: - break; - } - - /* Only install relocation if above tests did not disqualify it. */ - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); -} - -/* Relocate an EPIPHANY ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -epiphany_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type ATTRIBUTE_UNUSED; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - howto = epiphany_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = BASEADDR (sec) + sym->st_value; - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - /* Finally, the sole EPIPHANY-specific part. */ - r = epiphany_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - /* This is how epiphany_final_link_relocate tells us of a - non-kosher reference between insn & data address spaces. */ - case bfd_reloc_notsupported: - if (sym != NULL) /* Only if it's not an unresolved symbol. */ - msg = _("unsupported relocation between data/insn address spaces"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* We only have a little-endian target. */ -#define TARGET_LITTLE_SYM epiphany_elf32_vec -#define TARGET_LITTLE_NAME "elf32-epiphany" - -#define ELF_ARCH bfd_arch_epiphany -#define ELF_MACHINE_CODE EM_ADAPTEVA_EPIPHANY - -#define ELF_MAXPAGESIZE 0x8000 /* No pages on the EPIPHANY. */ - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto epiphany_info_to_howto_rela - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 -#define elf_backend_relocate_section epiphany_elf_relocate_section - -#define elf_symbol_leading_char '_' -#define bfd_elf32_bfd_reloc_type_lookup epiphany_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup epiphany_reloc_name_lookup -#define bfd_elf32_bfd_relax_section epiphany_elf_relax_section - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-fr30.c b/sdcc/support/sdbinutils/bfd/elf32-fr30.c deleted file mode 100644 index 679322a6e..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-fr30.c +++ /dev/null @@ -1,718 +0,0 @@ -/* FR30-specific support for 32-bit ELF. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/fr30.h" - -/* Forward declarations. */ -static bfd_reloc_status_type -fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data, - asection *, bfd *, char **error_message); -static bfd_reloc_status_type -fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -static reloc_howto_type fr30_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_FR30_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FR30_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_FR30_8, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FR30_8", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x0ff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 20 bit absolute relocation. */ - HOWTO (R_FR30_20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - fr30_elf_i20_reloc, /* special_function */ - "R_FR30_20", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00f0ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_FR30_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FR30_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit into 48 bits absolute relocation. */ - HOWTO (R_FR30_48, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - fr30_elf_i32_reloc, /* special_function */ - "R_FR30_48", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 6 bit absolute relocation. */ - HOWTO (R_FR30_6_IN_4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FR30_6_IN_4", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x00f0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_FR30_8_IN_8, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc,/* special_function */ - "R_FR30_8_IN_8", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x0ff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 9 bit absolute relocation. */ - HOWTO (R_FR30_9_IN_8, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc,/* special_function */ - "R_FR30_9_IN_8", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x0ff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 10 bit absolute relocation. */ - HOWTO (R_FR30_10_IN_8, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc,/* special_function */ - "R_FR30_10_IN_8", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x0ff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A PC relative 9 bit relocation, right shifted by 1. */ - HOWTO (R_FR30_9_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FR30_9_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A PC relative 12 bit relocation, right shifted by 1. */ - HOWTO (R_FR30_12_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FR30_12_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_FR30_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_FR30_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_FR30_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_FR30_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* Utility to actually perform an R_FR30_20 reloc. */ - -static bfd_reloc_status_type -fr30_elf_i20_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - unsigned long x; - - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_ok; - - relocation = - symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset - + reloc_entry->addend; - - if (relocation > (((bfd_vma) 1 << 20) - 1)) - return bfd_reloc_overflow; - - x = bfd_get_32 (abfd, (char *) data + reloc_entry->address); - x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4); - bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address); - - return bfd_reloc_ok; -} - -/* Utility to actually perform a R_FR30_48 reloc. */ - -static bfd_reloc_status_type -fr30_elf_i32_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_ok; - - relocation = - symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset - + reloc_entry->addend; - - bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2); - - return bfd_reloc_ok; -} - -/* Map BFD reloc types to FR30 ELF reloc types. */ - -struct fr30_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int fr30_reloc_val; -}; - -static const struct fr30_reloc_map fr30_reloc_map [] = -{ - { BFD_RELOC_NONE, R_FR30_NONE }, - { BFD_RELOC_8, R_FR30_8 }, - { BFD_RELOC_FR30_20, R_FR30_20 }, - { BFD_RELOC_32, R_FR30_32 }, - { BFD_RELOC_FR30_48, R_FR30_48 }, - { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 }, - { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 }, - { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 }, - { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 }, - { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL }, - { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL }, - { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY }, -}; - -static reloc_howto_type * -fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]); - i--;) - if (fr30_reloc_map [i].bfd_reloc_val == code) - return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]); - i++) - if (fr30_elf_howto_table[i].name != NULL - && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0) - return &fr30_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an FR30 ELF reloc. */ - -static void -fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_FR30_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid FR30 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & fr30_elf_howto_table [r_type]; -} - -/* Perform a single relocation. By default we use the standard BFD - routines, but a few relocs, we have to do them ourselves. */ - -static bfd_reloc_status_type -fr30_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - bfd_vma relocation) -{ - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma x; - bfd_signed_vma srel; - - switch (howto->type) - { - case R_FR30_20: - contents += rel->r_offset; - relocation += rel->r_addend; - - if (relocation > ((1 << 20) - 1)) - return bfd_reloc_overflow; - - x = bfd_get_32 (input_bfd, contents); - x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4); - bfd_put_32 (input_bfd, x, contents); - break; - - case R_FR30_48: - contents += rel->r_offset + 2; - relocation += rel->r_addend; - bfd_put_32 (input_bfd, relocation, contents); - break; - - case R_FR30_9_PCREL: - contents += rel->r_offset + 1; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - if (srel > ((1 << 8) - 1) || (srel < - (1 << 8))) - return bfd_reloc_overflow; - - bfd_put_8 (input_bfd, srel >> 1, contents); - break; - - case R_FR30_12_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - if (srel > ((1 << 11) - 1) || (srel < - (1 << 11))) - return bfd_reloc_overflow; - - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf800) | ((srel >> 1) & 0x7ff); - bfd_put_16 (input_bfd, x, contents); - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - return r; -} - -/* Relocate an FR30 ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -fr30_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - - if ( r_type == R_FR30_GNU_VTINHERIT - || r_type == R_FR30_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = fr30_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -fr30_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_FR30_GNU_VTINHERIT: - case R_FR30_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -fr30_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_FR30_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_FR30_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -#define ELF_ARCH bfd_arch_fr30 -#define ELF_MACHINE_CODE EM_FR30 -#define ELF_MACHINE_ALT1 EM_CYGNUS_FR30 -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM fr30_elf32_vec -#define TARGET_BIG_NAME "elf32-fr30" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto fr30_info_to_howto_rela -#define elf_backend_relocate_section fr30_elf_relocate_section -#define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook -#define elf_backend_check_relocs fr30_elf_check_relocs - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-frv.c b/sdcc/support/sdbinutils/bfd/elf32-frv.c deleted file mode 100644 index b8d033879..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-frv.c +++ /dev/null @@ -1,6878 +0,0 @@ -/* FRV-specific support for 32-bit ELF. - Copyright (C) 2002-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/frv.h" -#include "dwarf2.h" -#include "hashtab.h" - -/* Forward declarations. */ - - -static reloc_howto_type elf32_frv_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_FRV_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_FRV_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit pc-relative relocation. */ - HOWTO (R_FRV_LABEL16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_LABEL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 24-bit pc-relative relocation. */ - HOWTO (R_FRV_LABEL24, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_LABEL24", /* name */ - FALSE, /* partial_inplace */ - 0x7e03ffff, /* src_mask */ - 0x7e03ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_FRV_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_LO16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FRV_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_HI16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FRV_GPREL12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GPREL12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FRV_GPRELU12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GPRELU12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0x3f03f, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FRV_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GPREL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FRV_GPRELHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GPRELHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FRV_GPRELLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GPRELLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - the symbol. */ - HOWTO (R_FRV_GOT12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOT12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_FRV_GOTHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_FRV_GOTLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 32-bit address of the canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_GOT12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_GOT12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_GOTHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_GOTHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_GOTLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_GOTLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 64-bit descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_VALUE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_VALUE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_GOTOFF12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_GOTOFF12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_GOTOFFHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_GOTOFFHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - canonical descriptor of a function. */ - HOWTO (R_FRV_FUNCDESC_GOTOFFLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_GOTOFFLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the address of - the symbol. */ - HOWTO (R_FRV_GOTOFF12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTOFF12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_FRV_GOTOFFHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTOFFHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the address of the - symbol. */ - HOWTO (R_FRV_GOTOFFLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTOFFLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 24-bit pc-relative relocation referencing the TLS PLT entry for - a thread-local symbol. If the symbol number is 0, it refers to - the module. */ - HOWTO (R_FRV_GETTLSOFF, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GETTLSOFF", /* name */ - FALSE, /* partial_inplace */ - 0x7e03ffff, /* src_mask */ - 0x7e03ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 64-bit TLS descriptor for a symbol. This relocation is only - valid as a REL, dynamic relocation. */ - HOWTO (R_FRV_TLSDESC_VALUE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSDESC_VALUE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the TLS - descriptor of the symbol. */ - HOWTO (R_FRV_GOTTLSDESC12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTTLSDESC12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the TLS descriptor of the - symbol. */ - HOWTO (R_FRV_GOTTLSDESCHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTTLSDESCHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the TLS descriptor of the - symbol. */ - HOWTO (R_FRV_GOTTLSDESCLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTTLSDESCLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the offset from the module base - address to the thread-local symbol address. */ - HOWTO (R_FRV_TLSMOFF12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSMOFF12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the offset from the module base address to - the thread-local symbol address. */ - HOWTO (R_FRV_TLSMOFFHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSMOFFHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the offset from the module base address to - the thread-local symbol address. */ - HOWTO (R_FRV_TLSMOFFLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSMOFFLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12-bit signed operand with the GOT offset for the TLSOFF entry - for a symbol. */ - HOWTO (R_FRV_GOTTLSOFF12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTTLSOFF12", /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The upper 16 bits of the GOT offset for the TLSOFF entry for a - symbol. */ - HOWTO (R_FRV_GOTTLSOFFHI, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTTLSOFFHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The lower 16 bits of the GOT offset for the TLSOFF entry for a - symbol. */ - HOWTO (R_FRV_GOTTLSOFFLO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GOTTLSOFFLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 32-bit offset from the thread pointer (not the module base - address) to a thread-local symbol. */ - HOWTO (R_FRV_TLSOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An annotation for linker relaxation, that denotes the - symbol+addend whose TLS descriptor is referenced by the sum of - the two input registers of an ldd instruction. */ - HOWTO (R_FRV_TLSDESC_RELAX, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSDESC_RELAX", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An annotation for linker relaxation, that denotes the - symbol+addend whose TLS resolver entry point is given by the sum - of the two register operands of an calll instruction. */ - HOWTO (R_FRV_GETTLSOFF_RELAX, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_GETTLSOFF_RELAX", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An annotation for linker relaxation, that denotes the - symbol+addend whose TLS offset GOT entry is given by the sum of - the two input registers of an ld instruction. */ - HOWTO (R_FRV_TLSOFF_RELAX, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSOFF_RELAX", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32-bit offset from the module base address to - the thread-local symbol address. */ - HOWTO (R_FRV_TLSMOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSMOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* GNU extension to record C++ vtable hierarchy. */ -static reloc_howto_type elf32_frv_vtinherit_howto = - HOWTO (R_FRV_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_FRV_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - - /* GNU extension to record C++ vtable member usage. */ -static reloc_howto_type elf32_frv_vtentry_howto = - HOWTO (R_FRV_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_FRV_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* The following 3 relocations are REL. The only difference to the - entries in the table above are that partial_inplace is TRUE. */ -static reloc_howto_type elf32_frv_rel_32_howto = - HOWTO (R_FRV_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -static reloc_howto_type elf32_frv_rel_funcdesc_howto = - HOWTO (R_FRV_FUNCDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -static reloc_howto_type elf32_frv_rel_funcdesc_value_howto = - HOWTO (R_FRV_FUNCDESC_VALUE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_FUNCDESC_VALUE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -static reloc_howto_type elf32_frv_rel_tlsdesc_value_howto = - /* A 64-bit TLS descriptor for a symbol. The first word resolves to - an entry point, and the second resolves to a special argument. - If the symbol turns out to be in static TLS, the entry point is a - return instruction, and the special argument is the TLS offset - for the symbol. If it's in dynamic TLS, the entry point is a TLS - offset resolver, and the special argument is a pointer to a data - structure allocated by the dynamic loader, containing the GOT - address for the offset resolver, the module id, the offset within - the module, and anything else the TLS offset resolver might need - to determine the TLS offset for the symbol in the running - thread. */ - HOWTO (R_FRV_TLSDESC_VALUE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSDESC_VALUE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -static reloc_howto_type elf32_frv_rel_tlsoff_howto = - /* The 32-bit offset from the thread pointer (not the module base - address) to a thread-local symbol. */ - HOWTO (R_FRV_TLSOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FRV_TLSOFF", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - - - -extern const bfd_target frv_elf32_fdpic_vec; -#define IS_FDPIC(bfd) ((bfd)->xvec == &frv_elf32_fdpic_vec) - -/* An extension of the elf hash table data structure, containing some - additional FRV-specific data. */ -struct frvfdpic_elf_link_hash_table -{ - struct elf_link_hash_table elf; - - /* A pointer to the .rofixup section. */ - asection *sgotfixup; - /* GOT base offset. */ - bfd_vma got0; - /* Location of the first non-lazy PLT entry, i.e., the number of - bytes taken by lazy PLT entries. If locally-bound TLS - descriptors require a ret instruction, it will be placed at this - offset. */ - bfd_vma plt0; - /* A hash table holding information about which symbols were - referenced with which PIC-related relocations. */ - struct htab *relocs_info; - /* Summary reloc information collected by - _frvfdpic_count_got_plt_entries. */ - struct _frvfdpic_dynamic_got_info *g; -}; - -/* Get the FRV ELF linker hash table from a link_info structure. */ - -#define frvfdpic_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == FRV_ELF_DATA ? ((struct frvfdpic_elf_link_hash_table *) ((p)->hash)) : NULL) - -#define frvfdpic_got_section(info) \ - (frvfdpic_hash_table (info)->elf.sgot) -#define frvfdpic_gotrel_section(info) \ - (frvfdpic_hash_table (info)->elf.srelgot) -#define frvfdpic_gotfixup_section(info) \ - (frvfdpic_hash_table (info)->sgotfixup) -#define frvfdpic_plt_section(info) \ - (frvfdpic_hash_table (info)->elf.splt) -#define frvfdpic_pltrel_section(info) \ - (frvfdpic_hash_table (info)->elf.srelplt) -#define frvfdpic_relocs_info(info) \ - (frvfdpic_hash_table (info)->relocs_info) -#define frvfdpic_got_initial_offset(info) \ - (frvfdpic_hash_table (info)->got0) -#define frvfdpic_plt_initial_offset(info) \ - (frvfdpic_hash_table (info)->plt0) -#define frvfdpic_dynamic_got_plt_info(info) \ - (frvfdpic_hash_table (info)->g) - -/* Currently it's the same, but if some day we have a reason to change - it, we'd better be using a different macro. - - FIXME: if there's any TLS PLT entry that uses local-exec or - initial-exec models, we could use the ret at the end of any of them - instead of adding one more. */ -#define frvfdpic_plt_tls_ret_offset(info) \ - (frvfdpic_plt_initial_offset (info)) - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -#define DEFAULT_STACK_SIZE 0x20000 - -/* This structure is used to collect the number of entries present in - each addressable range of the got. */ -struct _frvfdpic_dynamic_got_info -{ - /* Several bits of information about the current link. */ - struct bfd_link_info *info; - /* Total GOT size needed for GOT entries within the 12-, 16- or 32-bit - ranges. */ - bfd_vma got12, gotlos, gothilo; - /* Total GOT size needed for function descriptor entries within the 12-, - 16- or 32-bit ranges. */ - bfd_vma fd12, fdlos, fdhilo; - /* Total GOT size needed by function descriptor entries referenced - in PLT entries, that would be profitable to place in offsets - close to the PIC register. */ - bfd_vma fdplt; - /* Total PLT size needed by lazy PLT entries. */ - bfd_vma lzplt; - /* Total GOT size needed for TLS descriptor entries within the 12-, - 16- or 32-bit ranges. */ - bfd_vma tlsd12, tlsdlos, tlsdhilo; - /* Total GOT size needed by TLS descriptors referenced in PLT - entries, that would be profitable to place in offers close to the - PIC register. */ - bfd_vma tlsdplt; - /* Total PLT size needed by TLS lazy PLT entries. */ - bfd_vma tlslzplt; - /* Number of relocations carried over from input object files. */ - unsigned long relocs; - /* Number of fixups introduced by relocations in input object files. */ - unsigned long fixups; - /* The number of fixups that reference the ret instruction added to - the PLT for locally-resolved TLS descriptors. */ - unsigned long tls_ret_refs; -}; - -/* This structure is used to assign offsets to got entries, function - descriptors, plt entries and lazy plt entries. */ - -struct _frvfdpic_dynamic_got_plt_info -{ - /* Summary information collected with _frvfdpic_count_got_plt_entries. */ - struct _frvfdpic_dynamic_got_info g; - - /* For each addressable range, we record a MAX (positive) and MIN - (negative) value. CUR is used to assign got entries, and it's - incremented from an initial positive value to MAX, then from MIN - to FDCUR (unless FDCUR wraps around first). FDCUR is used to - assign function descriptors, and it's decreased from an initial - non-positive value to MIN, then from MAX down to CUR (unless CUR - wraps around first). All of MIN, MAX, CUR and FDCUR always point - to even words. ODD, if non-zero, indicates an odd word to be - used for the next got entry, otherwise CUR is used and - incremented by a pair of words, wrapping around when it reaches - MAX. FDCUR is decremented (and wrapped) before the next function - descriptor is chosen. FDPLT indicates the number of remaining - slots that can be used for function descriptors used only by PLT - entries. - - TMAX, TMIN and TCUR are used to assign TLS descriptors. TCUR - starts as MAX, and grows up to TMAX, then wraps around to TMIN - and grows up to MIN. TLSDPLT indicates the number of remaining - slots that can be used for TLS descriptors used only by TLS PLT - entries. */ - struct _frvfdpic_dynamic_got_alloc_data - { - bfd_signed_vma max, cur, odd, fdcur, min; - bfd_signed_vma tmax, tcur, tmin; - bfd_vma fdplt, tlsdplt; - } got12, gotlos, gothilo; -}; - -/* Create an FRV ELF linker hash table. */ - -static struct bfd_link_hash_table * -frvfdpic_elf_link_hash_table_create (bfd *abfd) -{ - struct frvfdpic_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct frvfdpic_elf_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry), - FRV_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->elf.root; -} - -/* Decide whether a reference to a symbol can be resolved locally or - not. If the symbol is protected, we want the local address, but - its function descriptor must be assigned by the dynamic linker. */ -#define FRVFDPIC_SYM_LOCAL(INFO, H) \ - (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \ - || ! elf_hash_table (INFO)->dynamic_sections_created) -#define FRVFDPIC_FUNCDESC_LOCAL(INFO, H) \ - ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created) - -/* This structure collects information on what kind of GOT, PLT or - function descriptors are required by relocations that reference a - certain symbol. */ -struct frvfdpic_relocs_info -{ - /* The index of the symbol, as stored in the relocation r_info, if - we have a local symbol; -1 otherwise. */ - long symndx; - union - { - /* The input bfd in which the symbol is defined, if it's a local - symbol. */ - bfd *abfd; - /* If symndx == -1, the hash table entry corresponding to a global - symbol (even if it turns out to bind locally, in which case it - should ideally be replaced with section's symndx + addend). */ - struct elf_link_hash_entry *h; - } d; - /* The addend of the relocation that references the symbol. */ - bfd_vma addend; - - /* The fields above are used to identify an entry. The fields below - contain information on how an entry is used and, later on, which - locations it was assigned. */ - /* The following 3 fields record whether the symbol+addend above was - ever referenced with a GOT relocation. The 12 suffix indicates a - GOT12 relocation; los is used for GOTLO relocations that are not - matched by a GOTHI relocation; hilo is used for GOTLO/GOTHI - pairs. */ - unsigned got12:1; - unsigned gotlos:1; - unsigned gothilo:1; - /* Whether a FUNCDESC relocation references symbol+addend. */ - unsigned fd:1; - /* Whether a FUNCDESC_GOT relocation references symbol+addend. */ - unsigned fdgot12:1; - unsigned fdgotlos:1; - unsigned fdgothilo:1; - /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend. */ - unsigned fdgoff12:1; - unsigned fdgofflos:1; - unsigned fdgoffhilo:1; - /* Whether a GETTLSOFF relocation references symbol+addend. */ - unsigned tlsplt:1; - /* FIXME: we should probably add tlspltdesc, tlspltoff and - tlspltimm, to tell what kind of TLS PLT entry we're generating. - We might instead just pre-compute flags telling whether the - object is suitable for local exec, initial exec or general - dynamic addressing, and use that all over the place. We could - also try to do a better job of merging TLSOFF and TLSDESC entries - in main executables, but perhaps we can get rid of TLSDESC - entirely in them instead. */ - /* Whether a GOTTLSDESC relocation references symbol+addend. */ - unsigned tlsdesc12:1; - unsigned tlsdesclos:1; - unsigned tlsdeschilo:1; - /* Whether a GOTTLSOFF relocation references symbol+addend. */ - unsigned tlsoff12:1; - unsigned tlsofflos:1; - unsigned tlsoffhilo:1; - /* Whether symbol+addend is referenced with GOTOFF12, GOTOFFLO or - GOTOFFHI relocations. The addend doesn't really matter, since we - envision that this will only be used to check whether the symbol - is mapped to the same segment as the got. */ - unsigned gotoff:1; - /* Whether symbol+addend is referenced by a LABEL24 relocation. */ - unsigned call:1; - /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE - relocation. */ - unsigned sym:1; - /* Whether we need a PLT entry for a symbol. Should be implied by - something like: - (call && symndx == -1 && ! FRVFDPIC_SYM_LOCAL (info, d.h)) */ - unsigned plt:1; - /* Whether a function descriptor should be created in this link unit - for symbol+addend. Should be implied by something like: - (plt || fdgotoff12 || fdgotofflos || fdgotofflohi - || ((fd || fdgot12 || fdgotlos || fdgothilo) - && (symndx != -1 || FRVFDPIC_FUNCDESC_LOCAL (info, d.h)))) */ - unsigned privfd:1; - /* Whether a lazy PLT entry is needed for this symbol+addend. - Should be implied by something like: - (privfd && symndx == -1 && ! FRVFDPIC_SYM_LOCAL (info, d.h) - && ! (info->flags & DF_BIND_NOW)) */ - unsigned lazyplt:1; - /* Whether we've already emitted GOT relocations and PLT entries as - needed for this symbol. */ - unsigned done:1; - - /* The number of R_FRV_32, R_FRV_FUNCDESC, R_FRV_FUNCDESC_VALUE and - R_FRV_TLSDESC_VALUE, R_FRV_TLSOFF relocations referencing - symbol+addend. */ - unsigned relocs32, relocsfd, relocsfdv, relocstlsd, relocstlsoff; - - /* The number of .rofixups entries and dynamic relocations allocated - for this symbol, minus any that might have already been used. */ - unsigned fixups, dynrelocs; - - /* The offsets of the GOT entries assigned to symbol+addend, to the - function descriptor's address, and to a function descriptor, - respectively. Should be zero if unassigned. The offsets are - counted from the value that will be assigned to the PIC register, - not from the beginning of the .got section. */ - bfd_signed_vma got_entry, fdgot_entry, fd_entry; - /* The offsets of the PLT entries assigned to symbol+addend, - non-lazy and lazy, respectively. If unassigned, should be - (bfd_vma)-1. */ - bfd_vma plt_entry, lzplt_entry; - /* The offsets of the GOT entries for TLS offset and TLS descriptor. */ - bfd_signed_vma tlsoff_entry, tlsdesc_entry; - /* The offset of the TLS offset PLT entry. */ - bfd_vma tlsplt_entry; -}; - -/* Compute a hash with the key fields of an frvfdpic_relocs_info entry. */ -static hashval_t -frvfdpic_relocs_info_hash (const void *entry_) -{ - const struct frvfdpic_relocs_info *entry = entry_; - - return (entry->symndx == -1 - ? (long) entry->d.h->root.root.hash - : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend; -} - -/* Test whether the key fields of two frvfdpic_relocs_info entries are - identical. */ -static int -frvfdpic_relocs_info_eq (const void *entry1, const void *entry2) -{ - const struct frvfdpic_relocs_info *e1 = entry1; - const struct frvfdpic_relocs_info *e2 = entry2; - - return e1->symndx == e2->symndx && e1->addend == e2->addend - && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd); -} - -/* Find or create an entry in a hash table HT that matches the key - fields of the given ENTRY. If it's not found, memory for a new - entry is allocated in ABFD's obstack. */ -static struct frvfdpic_relocs_info * -frvfdpic_relocs_info_find (struct htab *ht, - bfd *abfd, - const struct frvfdpic_relocs_info *entry, - enum insert_option insert) -{ - struct frvfdpic_relocs_info **loc = - (struct frvfdpic_relocs_info **) htab_find_slot (ht, entry, insert); - - if (! loc) - return NULL; - - if (*loc) - return *loc; - - *loc = bfd_zalloc (abfd, sizeof (**loc)); - - if (! *loc) - return *loc; - - (*loc)->symndx = entry->symndx; - (*loc)->d = entry->d; - (*loc)->addend = entry->addend; - (*loc)->plt_entry = (bfd_vma)-1; - (*loc)->lzplt_entry = (bfd_vma)-1; - (*loc)->tlsplt_entry = (bfd_vma)-1; - - return *loc; -} - -/* Obtain the address of the entry in HT associated with H's symbol + - addend, creating a new entry if none existed. ABFD is only used - for memory allocation purposes. */ -inline static struct frvfdpic_relocs_info * -frvfdpic_relocs_info_for_global (struct htab *ht, - bfd *abfd, - struct elf_link_hash_entry *h, - bfd_vma addend, - enum insert_option insert) -{ - struct frvfdpic_relocs_info entry; - - entry.symndx = -1; - entry.d.h = h; - entry.addend = addend; - - return frvfdpic_relocs_info_find (ht, abfd, &entry, insert); -} - -/* Obtain the address of the entry in HT associated with the SYMNDXth - local symbol of the input bfd ABFD, plus the addend, creating a new - entry if none existed. */ -inline static struct frvfdpic_relocs_info * -frvfdpic_relocs_info_for_local (struct htab *ht, - bfd *abfd, - long symndx, - bfd_vma addend, - enum insert_option insert) -{ - struct frvfdpic_relocs_info entry; - - entry.symndx = symndx; - entry.d.abfd = abfd; - entry.addend = addend; - - return frvfdpic_relocs_info_find (ht, abfd, &entry, insert); -} - -/* Merge fields set by check_relocs() of two entries that end up being - mapped to the same (presumably global) symbol. */ - -inline static void -frvfdpic_pic_merge_early_relocs_info (struct frvfdpic_relocs_info *e2, - struct frvfdpic_relocs_info const *e1) -{ - e2->got12 |= e1->got12; - e2->gotlos |= e1->gotlos; - e2->gothilo |= e1->gothilo; - e2->fd |= e1->fd; - e2->fdgot12 |= e1->fdgot12; - e2->fdgotlos |= e1->fdgotlos; - e2->fdgothilo |= e1->fdgothilo; - e2->fdgoff12 |= e1->fdgoff12; - e2->fdgofflos |= e1->fdgofflos; - e2->fdgoffhilo |= e1->fdgoffhilo; - e2->tlsplt |= e1->tlsplt; - e2->tlsdesc12 |= e1->tlsdesc12; - e2->tlsdesclos |= e1->tlsdesclos; - e2->tlsdeschilo |= e1->tlsdeschilo; - e2->tlsoff12 |= e1->tlsoff12; - e2->tlsofflos |= e1->tlsofflos; - e2->tlsoffhilo |= e1->tlsoffhilo; - e2->gotoff |= e1->gotoff; - e2->call |= e1->call; - e2->sym |= e1->sym; -} - -/* Every block of 65535 lazy PLT entries shares a single call to the - resolver, inserted in the 32768th lazy PLT entry (i.e., entry # - 32767, counting from 0). All other lazy PLT entries branch to it - in a single instruction. */ - -#define FRVFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) 8 * 65535 + 4) -#define FRVFDPIC_LZPLT_RESOLV_LOC (8 * 32767) - -/* Add a dynamic relocation to the SRELOC section. */ - -inline static bfd_vma -_frvfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, - int reloc_type, long dynindx, bfd_vma addend, - struct frvfdpic_relocs_info *entry) -{ - Elf_Internal_Rela outrel; - bfd_vma reloc_offset; - - outrel.r_offset = offset; - outrel.r_info = ELF32_R_INFO (dynindx, reloc_type); - outrel.r_addend = addend; - - reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel); - BFD_ASSERT (reloc_offset < sreloc->size); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, - sreloc->contents + reloc_offset); - sreloc->reloc_count++; - - /* If the entry's index is zero, this relocation was probably to a - linkonce section that got discarded. We reserved a dynamic - relocation, but it was for another entry than the one we got at - the time of emitting the relocation. Unfortunately there's no - simple way for us to catch this situation, since the relocation - is cleared right before calling relocate_section, at which point - we no longer know what the relocation used to point to. */ - if (entry->symndx) - { - BFD_ASSERT (entry->dynrelocs > 0); - entry->dynrelocs--; - } - - return reloc_offset; -} - -/* Add a fixup to the ROFIXUP section. */ - -static bfd_vma -_frvfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset, - struct frvfdpic_relocs_info *entry) -{ - bfd_vma fixup_offset; - - if (rofixup->flags & SEC_EXCLUDE) - return -1; - - fixup_offset = rofixup->reloc_count * 4; - if (rofixup->contents) - { - BFD_ASSERT (fixup_offset < rofixup->size); - bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset); - } - rofixup->reloc_count++; - - if (entry && entry->symndx) - { - /* See discussion about symndx == 0 in _frvfdpic_add_dyn_reloc - above. */ - BFD_ASSERT (entry->fixups > 0); - entry->fixups--; - } - - return fixup_offset; -} - -/* Find the segment number in which OSEC, and output section, is - located. */ - -static unsigned -_frvfdpic_osec_to_segment (bfd *output_bfd, asection *osec) -{ - Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec); - - return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1; -} - -inline static bfd_boolean -_frvfdpic_osec_readonly_p (bfd *output_bfd, asection *osec) -{ - unsigned seg = _frvfdpic_osec_to_segment (output_bfd, osec); - - return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W); -} - -#define FRVFDPIC_TLS_BIAS (2048 - 16) - -/* Return the base VMA address which should be subtracted from real addresses - when resolving TLSMOFF relocation. - This is PT_TLS segment p_vaddr, plus the 2048-16 bias. */ - -static bfd_vma -tls_biased_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 FRVFDPIC_TLS_BIAS; - return elf_hash_table (info)->tls_sec->vma + FRVFDPIC_TLS_BIAS; -} - -/* Generate relocations for GOT entries, function descriptors, and - code for PLT and lazy PLT entries. */ - -inline static bfd_boolean -_frvfdpic_emit_got_relocs_plt_entries (struct frvfdpic_relocs_info *entry, - bfd *output_bfd, - struct bfd_link_info *info, - asection *sec, - Elf_Internal_Sym *sym, - bfd_vma addend) - -{ - bfd_vma fd_lazy_rel_offset = (bfd_vma)-1; - int dynindx = -1; - - if (entry->done) - return TRUE; - entry->done = 1; - - if (entry->got_entry || entry->fdgot_entry || entry->fd_entry - || entry->tlsoff_entry || entry->tlsdesc_entry) - { - /* If the symbol is dynamic, consider it for dynamic - relocations, otherwise decay to section + offset. */ - if (entry->symndx == -1 && entry->d.h->dynindx != -1) - dynindx = entry->d.h->dynindx; - else - { - if (sec - && sec->output_section - && ! bfd_is_abs_section (sec->output_section) - && ! bfd_is_und_section (sec->output_section)) - dynindx = elf_section_data (sec->output_section)->dynindx; - else - dynindx = 0; - } - } - - /* Generate relocation for GOT entry pointing to the symbol. */ - if (entry->got_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - - /* If we're linking an executable at a fixed address, we can - omit the dynamic relocation as long as the symbol is local to - this module. */ - if (bfd_link_pde (info) - && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (sec) - ad += sec->output_section->vma; - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section (info), - frvfdpic_got_section (info)->output_section - ->vma - + frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info) - + entry->got_entry, entry); - } - else - _frvfdpic_add_dyn_reloc (output_bfd, frvfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - frvfdpic_got_section (info), - frvfdpic_got_initial_offset (info) - + entry->got_entry) - + frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info)->output_offset, - R_FRV_32, idx, ad, entry); - - bfd_put_32 (output_bfd, ad, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->got_entry); - } - - /* Generate relocation for GOT entry pointing to a canonical - function descriptor. */ - if (entry->fdgot_entry) - { - int reloc, idx; - bfd_vma ad = 0; - - if (! (entry->symndx == -1 - && entry->d.h->root.type == bfd_link_hash_undefweak - && FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - /* If the symbol is dynamic and there may be dynamic symbol - resolution because we are, or are linked with, a shared - library, emit a FUNCDESC relocation such that the dynamic - linker will allocate the function descriptor. If the - symbol needs a non-local function descriptor but binds - locally (e.g., its visibility is protected, emit a - dynamic relocation decayed to section+offset. */ - if (entry->symndx == -1 - && ! FRVFDPIC_FUNCDESC_LOCAL (info, entry->d.h) - && FRVFDPIC_SYM_LOCAL (info, entry->d.h) - && !bfd_link_pde (info)) - { - reloc = R_FRV_FUNCDESC; - idx = elf_section_data (entry->d.h->root.u.def.section - ->output_section)->dynindx; - ad = entry->d.h->root.u.def.section->output_offset - + entry->d.h->root.u.def.value; - } - else if (entry->symndx == -1 - && ! FRVFDPIC_FUNCDESC_LOCAL (info, entry->d.h)) - { - reloc = R_FRV_FUNCDESC; - idx = dynindx; - ad = addend; - if (ad) - { - (*info->callbacks->reloc_dangerous) - (info, _("relocation requires zero addend"), - elf_hash_table (info)->dynobj, - frvfdpic_got_section (info), - entry->fdgot_entry); - return FALSE; - } - } - else - { - /* Otherwise, we know we have a private function descriptor, - so reference it directly. */ - if (elf_hash_table (info)->dynamic_sections_created) - BFD_ASSERT (entry->privfd); - reloc = R_FRV_32; - idx = elf_section_data (frvfdpic_got_section (info) - ->output_section)->dynindx; - ad = frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info) + entry->fd_entry; - } - - /* If there is room for dynamic symbol resolution, emit the - dynamic relocation. However, if we're linking an - executable at a fixed location, we won't have emitted a - dynamic symbol entry for the got section, so idx will be - zero, which means we can and should compute the address - of the private descriptor ourselves. */ - if (bfd_link_pde (info) - && (entry->symndx != -1 - || FRVFDPIC_FUNCDESC_LOCAL (info, entry->d.h))) - { - ad += frvfdpic_got_section (info)->output_section->vma; - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section (info), - frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset - + frvfdpic_got_initial_offset (info) - + entry->fdgot_entry, entry); - } - else - _frvfdpic_add_dyn_reloc (output_bfd, - frvfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - frvfdpic_got_section (info), - frvfdpic_got_initial_offset (info) - + entry->fdgot_entry) - + frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset, - reloc, idx, ad, entry); - } - - bfd_put_32 (output_bfd, ad, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->fdgot_entry); - } - - /* Generate relocation to fill in a private function descriptor in - the GOT. */ - if (entry->fd_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - bfd_vma ofst; - long lowword, highword; - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - - /* If we're linking an executable at a fixed address, we can - omit the dynamic relocation as long as the symbol is local to - this module. */ - if (bfd_link_pde (info) - && (entry->symndx != -1 || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (sec) - ad += sec->output_section->vma; - ofst = 0; - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - { - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section (info), - frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset - + frvfdpic_got_initial_offset (info) - + entry->fd_entry, entry); - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section (info), - frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset - + frvfdpic_got_initial_offset (info) - + entry->fd_entry + 4, entry); - } - } - else - { - ofst = - _frvfdpic_add_dyn_reloc (output_bfd, - entry->lazyplt - ? frvfdpic_pltrel_section (info) - : frvfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - frvfdpic_got_section (info), - frvfdpic_got_initial_offset (info) - + entry->fd_entry) - + frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset, - R_FRV_FUNCDESC_VALUE, idx, ad, entry); - } - - /* If we've omitted the dynamic relocation, just emit the fixed - addresses of the symbol and of the local GOT base offset. */ - if (bfd_link_pde (info) - && sec - && sec->output_section) - { - lowword = ad; - highword = frvfdpic_got_section (info)->output_section->vma - + frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info); - } - else if (entry->lazyplt) - { - if (ad) - { - (*info->callbacks->reloc_dangerous) - (info, _("relocation requires zero addend"), - elf_hash_table (info)->dynobj, - frvfdpic_got_section (info), - entry->fd_entry); - return FALSE; - } - - fd_lazy_rel_offset = ofst; - - /* A function descriptor used for lazy or local resolving is - initialized such that its high word contains the output - section index in which the PLT entries are located, and - the low word contains the address of the lazy PLT entry - entry point, that must be within the memory region - assigned to that section. */ - lowword = entry->lzplt_entry + 4 - + frvfdpic_plt_section (info)->output_offset - + frvfdpic_plt_section (info)->output_section->vma; - highword = _frvfdpic_osec_to_segment - (output_bfd, frvfdpic_plt_section (info)->output_section); - } - else - { - /* A function descriptor for a local function gets the index - of the section. For a non-local function, it's - disregarded. */ - lowword = ad; - if (sec == NULL - || (entry->symndx == -1 && entry->d.h->dynindx != -1 - && entry->d.h->dynindx == idx)) - highword = 0; - else - highword = _frvfdpic_osec_to_segment - (output_bfd, sec->output_section); - } - - bfd_put_32 (output_bfd, lowword, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->fd_entry); - bfd_put_32 (output_bfd, highword, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->fd_entry + 4); - } - - /* Generate code for the PLT entry. */ - if (entry->plt_entry != (bfd_vma) -1) - { - bfd_byte *plt_code = frvfdpic_plt_section (info)->contents - + entry->plt_entry; - - BFD_ASSERT (entry->fd_entry); - - /* Figure out what kind of PLT entry we need, depending on the - location of the function descriptor within the GOT. */ - if (entry->fd_entry >= -(1 << (12 - 1)) - && entry->fd_entry < (1 << (12 - 1))) - { - /* lddi @(gr15, fd_entry), gr14 */ - bfd_put_32 (output_bfd, - 0x9cccf000 | (entry->fd_entry & ((1 << 12) - 1)), - plt_code); - plt_code += 4; - } - else - { - if (entry->fd_entry >= -(1 << (16 - 1)) - && entry->fd_entry < (1 << (16 - 1))) - { - /* setlos lo(fd_entry), gr14 */ - bfd_put_32 (output_bfd, - 0x9cfc0000 - | (entry->fd_entry & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - else - { - /* sethi.p hi(fd_entry), gr14 - setlo lo(fd_entry), gr14 */ - bfd_put_32 (output_bfd, - 0x1cf80000 - | ((entry->fd_entry >> 16) - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - bfd_put_32 (output_bfd, - 0x9cf40000 - | (entry->fd_entry & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - /* ldd @(gr14,gr15),gr14 */ - bfd_put_32 (output_bfd, 0x9c08e14f, plt_code); - plt_code += 4; - } - /* jmpl @(gr14,gr0) */ - bfd_put_32 (output_bfd, 0x8030e000, plt_code); - } - - /* Generate code for the lazy PLT entry. */ - if (entry->lzplt_entry != (bfd_vma) -1) - { - bfd_byte *lzplt_code = frvfdpic_plt_section (info)->contents - + entry->lzplt_entry; - bfd_vma resolverStub_addr; - - bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code); - lzplt_code += 4; - - resolverStub_addr = entry->lzplt_entry / FRVFDPIC_LZPLT_BLOCK_SIZE - * FRVFDPIC_LZPLT_BLOCK_SIZE + FRVFDPIC_LZPLT_RESOLV_LOC; - if (resolverStub_addr >= frvfdpic_plt_initial_offset (info)) - resolverStub_addr = frvfdpic_plt_initial_offset (info) - 12; - - if (entry->lzplt_entry == resolverStub_addr) - { - /* This is a lazy PLT entry that includes a resolver call. */ - /* ldd @(gr15,gr0), gr4 - jmpl @(gr4,gr0) */ - bfd_put_32 (output_bfd, 0x8808f140, lzplt_code); - bfd_put_32 (output_bfd, 0x80304000, lzplt_code + 4); - } - else - { - /* bra resolverStub */ - bfd_put_32 (output_bfd, - 0xc01a0000 - | (((resolverStub_addr - entry->lzplt_entry) - / 4) & (((bfd_vma)1 << 16) - 1)), - lzplt_code); - } - } - - /* Generate relocation for GOT entry holding the TLS offset. */ - if (entry->tlsoff_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - - if (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h)) - { - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section - && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - } - - /* *ABS*+addend is special for TLS relocations, use only the - addend. */ - if (bfd_link_executable (info) - && idx == 0 - && (bfd_is_abs_section (sec) - || bfd_is_und_section (sec))) - ; - /* If we're linking an executable, we can entirely omit the - dynamic relocation if the symbol is local to this module. */ - else if (bfd_link_executable (info) - && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (sec) - ad += sec->output_section->vma - tls_biased_base (info); - } - else - { - if (idx == 0 - && (bfd_is_abs_section (sec) - || bfd_is_und_section (sec))) - { - if (! elf_hash_table (info)->tls_sec) - { - (*info->callbacks->undefined_symbol) - (info, "TLS section", elf_hash_table (info)->dynobj, - frvfdpic_got_section (info), entry->tlsoff_entry, TRUE); - return FALSE; - } - idx = elf_section_data (elf_hash_table (info)->tls_sec)->dynindx; - ad += FRVFDPIC_TLS_BIAS; - } - _frvfdpic_add_dyn_reloc (output_bfd, frvfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - frvfdpic_got_section (info), - frvfdpic_got_initial_offset (info) - + entry->tlsoff_entry) - + frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset, - R_FRV_TLSOFF, idx, ad, entry); - } - - bfd_put_32 (output_bfd, ad, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->tlsoff_entry); - } - - if (entry->tlsdesc_entry) - { - int idx = dynindx; - bfd_vma ad = addend; - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (sec && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - - /* If we didn't set up a TLS offset entry, but we're linking an - executable and the symbol binds locally, we can use the - module offset in the TLS descriptor in relaxations. */ - if (bfd_link_executable (info) && ! entry->tlsoff_entry) - entry->tlsoff_entry = entry->tlsdesc_entry + 4; - - if (bfd_link_pde (info) - && ((idx == 0 - && (bfd_is_abs_section (sec) - || bfd_is_und_section (sec))) - || entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - /* *ABS*+addend is special for TLS relocations, use only the - addend for the TLS offset, and take the module id as - 0. */ - if (idx == 0 - && (bfd_is_abs_section (sec) - || bfd_is_und_section (sec))) - ; - /* For other TLS symbols that bind locally, add the section - TLS offset to the addend. */ - else if (sec) - ad += sec->output_section->vma - tls_biased_base (info); - - bfd_put_32 (output_bfd, - frvfdpic_plt_section (info)->output_section->vma - + frvfdpic_plt_section (info)->output_offset - + frvfdpic_plt_tls_ret_offset (info), - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->tlsdesc_entry); - - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section (info), - frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset - + frvfdpic_got_initial_offset (info) - + entry->tlsdesc_entry, entry); - - BFD_ASSERT (frvfdpic_dynamic_got_plt_info (info)->tls_ret_refs); - - /* We've used one of the reserved fixups, so discount it so - that we can check at the end that we've used them - all. */ - frvfdpic_dynamic_got_plt_info (info)->tls_ret_refs--; - - /* While at that, make sure the ret instruction makes to the - right location in the PLT. We could do it only when we - got to 0, but since the check at the end will only print - a warning, make sure we have the ret in place in case the - warning is missed. */ - bfd_put_32 (output_bfd, 0xc03a4000, - frvfdpic_plt_section (info)->contents - + frvfdpic_plt_tls_ret_offset (info)); - } - else - { - if (idx == 0 - && (bfd_is_abs_section (sec) - || bfd_is_und_section (sec))) - { - if (! elf_hash_table (info)->tls_sec) - { - (*info->callbacks->undefined_symbol) - (info, "TLS section", elf_hash_table (info)->dynobj, - frvfdpic_got_section (info), entry->tlsdesc_entry, TRUE); - return FALSE; - } - idx = elf_section_data (elf_hash_table (info)->tls_sec)->dynindx; - ad += FRVFDPIC_TLS_BIAS; - } - - _frvfdpic_add_dyn_reloc (output_bfd, frvfdpic_gotrel_section (info), - _bfd_elf_section_offset - (output_bfd, info, - frvfdpic_got_section (info), - frvfdpic_got_initial_offset (info) - + entry->tlsdesc_entry) - + frvfdpic_got_section (info) - ->output_section->vma - + frvfdpic_got_section (info) - ->output_offset, - R_FRV_TLSDESC_VALUE, idx, ad, entry); - - bfd_put_32 (output_bfd, 0, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->tlsdesc_entry); - } - - bfd_put_32 (output_bfd, ad, - frvfdpic_got_section (info)->contents - + frvfdpic_got_initial_offset (info) - + entry->tlsdesc_entry + 4); - } - - /* Generate code for the get-TLS-offset PLT entry. */ - if (entry->tlsplt_entry != (bfd_vma) -1) - { - bfd_byte *plt_code = frvfdpic_plt_section (info)->contents - + entry->tlsplt_entry; - - if (bfd_link_executable (info) - && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (info, entry->d.h))) - { - int idx = dynindx; - bfd_vma ad = addend; - - /* sec may be NULL when referencing an undefweak symbol - while linking a static executable. */ - if (!sec) - { - BFD_ASSERT (entry->symndx == -1 - && entry->d.h->root.type == bfd_link_hash_undefweak); - } - else - { - if (entry->symndx == -1) - ad += entry->d.h->root.u.def.value; - else - ad += sym->st_value; - ad += sec->output_offset; - if (sec->output_section - && elf_section_data (sec->output_section)) - idx = elf_section_data (sec->output_section)->dynindx; - else - idx = 0; - } - - /* *ABS*+addend is special for TLS relocations, use only the - addend for the TLS offset, and take the module id as - 0. */ - if (idx == 0 - && (bfd_is_abs_section (sec) - || bfd_is_und_section (sec))) - ; - /* For other TLS symbols that bind locally, add the section - TLS offset to the addend. */ - else if (sec) - ad += sec->output_section->vma - tls_biased_base (info); - - if ((bfd_signed_vma)ad >= -(1 << (16 - 1)) - && (bfd_signed_vma)ad < (1 << (16 - 1))) - { - /* setlos lo(ad), gr9 */ - bfd_put_32 (output_bfd, - 0x92fc0000 - | (ad - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - else - { - /* sethi.p hi(ad), gr9 - setlo lo(ad), gr9 */ - bfd_put_32 (output_bfd, - 0x12f80000 - | ((ad >> 16) - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - bfd_put_32 (output_bfd, - 0x92f40000 - | (ad - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - /* ret */ - bfd_put_32 (output_bfd, 0xc03a4000, plt_code); - } - else if (entry->tlsoff_entry) - { - /* Figure out what kind of PLT entry we need, depending on the - location of the TLS descriptor within the GOT. */ - if (entry->tlsoff_entry >= -(1 << (12 - 1)) - && entry->tlsoff_entry < (1 << (12 - 1))) - { - /* ldi @(gr15, tlsoff_entry), gr9 */ - bfd_put_32 (output_bfd, - 0x92c8f000 | (entry->tlsoff_entry - & ((1 << 12) - 1)), - plt_code); - plt_code += 4; - } - else - { - if (entry->tlsoff_entry >= -(1 << (16 - 1)) - && entry->tlsoff_entry < (1 << (16 - 1))) - { - /* setlos lo(tlsoff_entry), gr8 */ - bfd_put_32 (output_bfd, - 0x90fc0000 - | (entry->tlsoff_entry - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - else - { - /* sethi.p hi(tlsoff_entry), gr8 - setlo lo(tlsoff_entry), gr8 */ - bfd_put_32 (output_bfd, - 0x10f80000 - | ((entry->tlsoff_entry >> 16) - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - bfd_put_32 (output_bfd, - 0x90f40000 - | (entry->tlsoff_entry - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - /* ld @(gr15,gr8),gr9 */ - bfd_put_32 (output_bfd, 0x9008f108, plt_code); - plt_code += 4; - } - /* ret */ - bfd_put_32 (output_bfd, 0xc03a4000, plt_code); - } - else - { - BFD_ASSERT (entry->tlsdesc_entry); - - /* Figure out what kind of PLT entry we need, depending on the - location of the TLS descriptor within the GOT. */ - if (entry->tlsdesc_entry >= -(1 << (12 - 1)) - && entry->tlsdesc_entry < (1 << (12 - 1))) - { - /* lddi @(gr15, tlsdesc_entry), gr8 */ - bfd_put_32 (output_bfd, - 0x90ccf000 | (entry->tlsdesc_entry - & ((1 << 12) - 1)), - plt_code); - plt_code += 4; - } - else - { - if (entry->tlsdesc_entry >= -(1 << (16 - 1)) - && entry->tlsdesc_entry < (1 << (16 - 1))) - { - /* setlos lo(tlsdesc_entry), gr8 */ - bfd_put_32 (output_bfd, - 0x90fc0000 - | (entry->tlsdesc_entry - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - else - { - /* sethi.p hi(tlsdesc_entry), gr8 - setlo lo(tlsdesc_entry), gr8 */ - bfd_put_32 (output_bfd, - 0x10f80000 - | ((entry->tlsdesc_entry >> 16) - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - bfd_put_32 (output_bfd, - 0x90f40000 - | (entry->tlsdesc_entry - & (((bfd_vma)1 << 16) - 1)), - plt_code); - plt_code += 4; - } - /* ldd @(gr15,gr8),gr8 */ - bfd_put_32 (output_bfd, 0x9008f148, plt_code); - plt_code += 4; - } - /* jmpl @(gr8,gr0) */ - bfd_put_32 (output_bfd, 0x80308000, plt_code); - } - } - - return TRUE; -} - -/* Handle an FRV small data reloc. */ - -static bfd_reloc_status_type -elf32_frv_relocate_gprel12 (struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *relocation, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - bfd_vma gp; - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); - - gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= input_section->output_section->vma; - value -= (gp - input_section->output_section->vma); - - insn = bfd_get_32 (input_bfd, contents + relocation->r_offset); - - value += relocation->r_addend; - - if ((long) value > 0x7ff || (long) value < -0x800) - return bfd_reloc_overflow; - - bfd_put_32 (input_bfd, - (insn & 0xfffff000) | (value & 0xfff), - contents + relocation->r_offset); - - return bfd_reloc_ok; -} - -/* Handle an FRV small data reloc. for the u12 field. */ - -static bfd_reloc_status_type -elf32_frv_relocate_gprelu12 (struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *relocation, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - bfd_vma gp; - struct bfd_link_hash_entry *h; - bfd_vma mask; - - h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); - - gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= input_section->output_section->vma; - value -= (gp - input_section->output_section->vma); - - insn = bfd_get_32 (input_bfd, contents + relocation->r_offset); - - value += relocation->r_addend; - - if ((long) value > 0x7ff || (long) value < -0x800) - return bfd_reloc_overflow; - - /* The high 6 bits go into bits 17-12. The low 6 bits go into bits 5-0. */ - mask = 0x3f03f; - insn = (insn & ~mask) | ((value & 0xfc0) << 12) | (value & 0x3f); - - bfd_put_32 (input_bfd, insn, contents + relocation->r_offset); - - return bfd_reloc_ok; -} - -/* Handle an FRV ELF HI16 reloc. */ - -static bfd_reloc_status_type -elf32_frv_relocate_hi16 (bfd *input_bfd, - Elf_Internal_Rela *relhi, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + relhi->r_offset); - - value += relhi->r_addend; - value = ((value >> 16) & 0xffff); - - insn = (insn & 0xffff0000) | value; - - if ((long) value > 0xffff || (long) value < -0x10000) - return bfd_reloc_overflow; - - bfd_put_32 (input_bfd, insn, contents + relhi->r_offset); - return bfd_reloc_ok; - -} -static bfd_reloc_status_type -elf32_frv_relocate_lo16 (bfd *input_bfd, - Elf_Internal_Rela *rello, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + rello->r_offset); - - value += rello->r_addend; - value = value & 0xffff; - - insn = (insn & 0xffff0000) | value; - - if ((long) value > 0xffff || (long) value < -0x10000) - return bfd_reloc_overflow; - - bfd_put_32 (input_bfd, insn, contents + rello->r_offset); - return bfd_reloc_ok; -} - -/* Perform the relocation for the CALL label24 instruction. */ - -static bfd_reloc_status_type -elf32_frv_relocate_label24 (bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *rello, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - bfd_vma label6; - bfd_vma label18; - - /* The format for the call instruction is: - - 0 000000 0001111 000000000000000000 - label6 opcode label18 - - The branch calculation is: pc + (4*label24) - where label24 is the concatenation of label6 and label18. */ - - /* Grab the instruction. */ - insn = bfd_get_32 (input_bfd, contents + rello->r_offset); - - value -= input_section->output_section->vma + input_section->output_offset; - value -= rello->r_offset; - value += rello->r_addend; - - value = value >> 2; - - label6 = value & 0xfc0000; - label6 = label6 << 7; - - label18 = value & 0x3ffff; - - insn = insn & 0x803c0000; - insn = insn | label6; - insn = insn | label18; - - bfd_put_32 (input_bfd, insn, contents + rello->r_offset); - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -elf32_frv_relocate_gprelhi (struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *relocation, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - bfd_vma gp; - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); - - gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= input_section->output_section->vma; - value -= (gp - input_section->output_section->vma); - value += relocation->r_addend; - value = ((value >> 16) & 0xffff); - - if ((long) value > 0xffff || (long) value < -0x10000) - return bfd_reloc_overflow; - - insn = bfd_get_32 (input_bfd, contents + relocation->r_offset); - insn = (insn & 0xffff0000) | value; - - bfd_put_32 (input_bfd, insn, contents + relocation->r_offset); - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -elf32_frv_relocate_gprello (struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *relocation, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - bfd_vma gp; - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); - - gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= input_section->output_section->vma; - value -= (gp - input_section->output_section->vma); - value += relocation->r_addend; - value = value & 0xffff; - - if ((long) value > 0xffff || (long) value < -0x10000) - return bfd_reloc_overflow; - - insn = bfd_get_32 (input_bfd, contents + relocation->r_offset); - insn = (insn & 0xffff0000) | value; - - bfd_put_32 (input_bfd, insn, contents + relocation->r_offset); - - return bfd_reloc_ok; -} - -static reloc_howto_type * -frv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - default: - break; - - case BFD_RELOC_NONE: - return &elf32_frv_howto_table[ (int) R_FRV_NONE]; - - case BFD_RELOC_32: - if (elf_elfheader (abfd)->e_type == ET_EXEC - || elf_elfheader (abfd)->e_type == ET_DYN) - return &elf32_frv_rel_32_howto; - /* Fall through. */ - case BFD_RELOC_CTOR: - return &elf32_frv_howto_table[ (int) R_FRV_32]; - - case BFD_RELOC_FRV_LABEL16: - return &elf32_frv_howto_table[ (int) R_FRV_LABEL16]; - - case BFD_RELOC_FRV_LABEL24: - return &elf32_frv_howto_table[ (int) R_FRV_LABEL24]; - - case BFD_RELOC_FRV_LO16: - return &elf32_frv_howto_table[ (int) R_FRV_LO16]; - - case BFD_RELOC_FRV_HI16: - return &elf32_frv_howto_table[ (int) R_FRV_HI16]; - - case BFD_RELOC_FRV_GPREL12: - return &elf32_frv_howto_table[ (int) R_FRV_GPREL12]; - - case BFD_RELOC_FRV_GPRELU12: - return &elf32_frv_howto_table[ (int) R_FRV_GPRELU12]; - - case BFD_RELOC_FRV_GPREL32: - return &elf32_frv_howto_table[ (int) R_FRV_GPREL32]; - - case BFD_RELOC_FRV_GPRELHI: - return &elf32_frv_howto_table[ (int) R_FRV_GPRELHI]; - - case BFD_RELOC_FRV_GPRELLO: - return &elf32_frv_howto_table[ (int) R_FRV_GPRELLO]; - - case BFD_RELOC_FRV_GOT12: - return &elf32_frv_howto_table[ (int) R_FRV_GOT12]; - - case BFD_RELOC_FRV_GOTHI: - return &elf32_frv_howto_table[ (int) R_FRV_GOTHI]; - - case BFD_RELOC_FRV_GOTLO: - return &elf32_frv_howto_table[ (int) R_FRV_GOTLO]; - - case BFD_RELOC_FRV_FUNCDESC: - if (elf_elfheader (abfd)->e_type == ET_EXEC - || elf_elfheader (abfd)->e_type == ET_DYN) - return &elf32_frv_rel_funcdesc_howto; - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC]; - - case BFD_RELOC_FRV_FUNCDESC_GOT12: - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOT12]; - - case BFD_RELOC_FRV_FUNCDESC_GOTHI: - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTHI]; - - case BFD_RELOC_FRV_FUNCDESC_GOTLO: - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTLO]; - - case BFD_RELOC_FRV_FUNCDESC_VALUE: - if (elf_elfheader (abfd)->e_type == ET_EXEC - || elf_elfheader (abfd)->e_type == ET_DYN) - return &elf32_frv_rel_funcdesc_value_howto; - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_VALUE]; - - case BFD_RELOC_FRV_FUNCDESC_GOTOFF12: - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTOFF12]; - - case BFD_RELOC_FRV_FUNCDESC_GOTOFFHI: - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTOFFHI]; - - case BFD_RELOC_FRV_FUNCDESC_GOTOFFLO: - return &elf32_frv_howto_table[ (int) R_FRV_FUNCDESC_GOTOFFLO]; - - case BFD_RELOC_FRV_GOTOFF12: - return &elf32_frv_howto_table[ (int) R_FRV_GOTOFF12]; - - case BFD_RELOC_FRV_GOTOFFHI: - return &elf32_frv_howto_table[ (int) R_FRV_GOTOFFHI]; - - case BFD_RELOC_FRV_GOTOFFLO: - return &elf32_frv_howto_table[ (int) R_FRV_GOTOFFLO]; - - case BFD_RELOC_FRV_GETTLSOFF: - return &elf32_frv_howto_table[ (int) R_FRV_GETTLSOFF]; - - case BFD_RELOC_FRV_TLSDESC_VALUE: - if (elf_elfheader (abfd)->e_type == ET_EXEC - || elf_elfheader (abfd)->e_type == ET_DYN) - return &elf32_frv_rel_tlsdesc_value_howto; - return &elf32_frv_howto_table[ (int) R_FRV_TLSDESC_VALUE]; - - case BFD_RELOC_FRV_GOTTLSDESC12: - return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSDESC12]; - - case BFD_RELOC_FRV_GOTTLSDESCHI: - return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSDESCHI]; - - case BFD_RELOC_FRV_GOTTLSDESCLO: - return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSDESCLO]; - - case BFD_RELOC_FRV_TLSMOFF12: - return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFF12]; - - case BFD_RELOC_FRV_TLSMOFFHI: - return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFFHI]; - - case BFD_RELOC_FRV_TLSMOFFLO: - return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFFLO]; - - case BFD_RELOC_FRV_GOTTLSOFF12: - return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSOFF12]; - - case BFD_RELOC_FRV_GOTTLSOFFHI: - return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSOFFHI]; - - case BFD_RELOC_FRV_GOTTLSOFFLO: - return &elf32_frv_howto_table[ (int) R_FRV_GOTTLSOFFLO]; - - case BFD_RELOC_FRV_TLSOFF: - if (elf_elfheader (abfd)->e_type == ET_EXEC - || elf_elfheader (abfd)->e_type == ET_DYN) - return &elf32_frv_rel_tlsoff_howto; - return &elf32_frv_howto_table[ (int) R_FRV_TLSOFF]; - - case BFD_RELOC_FRV_TLSDESC_RELAX: - return &elf32_frv_howto_table[ (int) R_FRV_TLSDESC_RELAX]; - - case BFD_RELOC_FRV_GETTLSOFF_RELAX: - return &elf32_frv_howto_table[ (int) R_FRV_GETTLSOFF_RELAX]; - - case BFD_RELOC_FRV_TLSOFF_RELAX: - return &elf32_frv_howto_table[ (int) R_FRV_TLSOFF_RELAX]; - - case BFD_RELOC_FRV_TLSMOFF: - return &elf32_frv_howto_table[ (int) R_FRV_TLSMOFF]; - - case BFD_RELOC_VTABLE_INHERIT: - return &elf32_frv_vtinherit_howto; - - case BFD_RELOC_VTABLE_ENTRY: - return &elf32_frv_vtentry_howto; - } - - return NULL; -} - -static reloc_howto_type * -frv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf32_frv_howto_table) / sizeof (elf32_frv_howto_table[0]); - i++) - if (elf32_frv_howto_table[i].name != NULL - && strcasecmp (elf32_frv_howto_table[i].name, r_name) == 0) - return &elf32_frv_howto_table[i]; - - if (strcasecmp (elf32_frv_vtinherit_howto.name, r_name) == 0) - return &elf32_frv_vtinherit_howto; - if (strcasecmp (elf32_frv_vtentry_howto.name, r_name) == 0) - return &elf32_frv_vtentry_howto; - - return NULL; -} - -/* Set the howto pointer for an FRV ELF reloc. */ - -static void -frv_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - switch (r_type) - { - case R_FRV_GNU_VTINHERIT: - cache_ptr->howto = &elf32_frv_vtinherit_howto; - break; - - case R_FRV_GNU_VTENTRY: - cache_ptr->howto = &elf32_frv_vtentry_howto; - break; - - default: - if (r_type >= (unsigned int) R_FRV_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid FRV reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & elf32_frv_howto_table [r_type]; - break; - } -} - -/* Set the howto pointer for an FRV ELF REL reloc. */ -static void -frvfdpic_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - switch (r_type) - { - case R_FRV_32: - cache_ptr->howto = &elf32_frv_rel_32_howto; - break; - - case R_FRV_FUNCDESC: - cache_ptr->howto = &elf32_frv_rel_funcdesc_howto; - break; - - case R_FRV_FUNCDESC_VALUE: - cache_ptr->howto = &elf32_frv_rel_funcdesc_value_howto; - break; - - case R_FRV_TLSDESC_VALUE: - cache_ptr->howto = &elf32_frv_rel_tlsdesc_value_howto; - break; - - case R_FRV_TLSOFF: - cache_ptr->howto = &elf32_frv_rel_tlsoff_howto; - break; - - default: - cache_ptr->howto = NULL; - break; - } -} - -/* Perform a single relocation. By default we use the standard BFD - routines, but a few relocs, we have to do them ourselves. */ - -static bfd_reloc_status_type -frv_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - bfd_vma relocation) -{ - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, relocation, - rel->r_addend); -} - - -/* Relocate an FRV ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -elf32_frv_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - unsigned isec_segment, got_segment, plt_segment, gprel_segment, tls_segment, - check_segment[2]; - int silence_segment_error = !bfd_link_pic (info); - unsigned long insn; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - isec_segment = _frvfdpic_osec_to_segment (output_bfd, - input_section->output_section); - if (IS_FDPIC (output_bfd) && frvfdpic_got_section (info)) - got_segment = _frvfdpic_osec_to_segment (output_bfd, - frvfdpic_got_section (info) - ->output_section); - else - got_segment = -1; - if (IS_FDPIC (output_bfd) && frvfdpic_gotfixup_section (info)) - gprel_segment = _frvfdpic_osec_to_segment (output_bfd, - frvfdpic_gotfixup_section (info) - ->output_section); - else - gprel_segment = -1; - if (IS_FDPIC (output_bfd) && frvfdpic_plt_section (info)) - plt_segment = _frvfdpic_osec_to_segment (output_bfd, - frvfdpic_plt_section (info) - ->output_section); - else - plt_segment = -1; - if (elf_hash_table (info)->tls_sec) - tls_segment = _frvfdpic_osec_to_segment (output_bfd, - elf_hash_table (info)->tls_sec); - else - tls_segment = -1; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name; - int r_type; - asection *osec; - struct frvfdpic_relocs_info *picrel; - bfd_vma orig_addend = rel->r_addend; - - r_type = ELF32_R_TYPE (rel->r_info); - - if ( r_type == R_FRV_GNU_VTINHERIT - || r_type == R_FRV_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - howto = elf32_frv_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - osec = sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - if (name == NULL || name[0] == 0) - name = bfd_section_name (input_bfd, sec); - } - else - { - bfd_boolean warned, ignored; - bfd_boolean unresolved_reloc; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - osec = sec; - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - if (r_type != R_FRV_TLSMOFF - && h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !FRVFDPIC_SYM_LOCAL (info, h)) - { - osec = sec = NULL; - relocation = 0; - } - - switch (r_type) - { - case R_FRV_LABEL24: - case R_FRV_32: - if (! IS_FDPIC (output_bfd)) - goto non_fdpic; - /* Fall through. */ - - case R_FRV_GOT12: - case R_FRV_GOTHI: - case R_FRV_GOTLO: - case R_FRV_FUNCDESC_GOT12: - case R_FRV_FUNCDESC_GOTHI: - case R_FRV_FUNCDESC_GOTLO: - case R_FRV_GOTOFF12: - case R_FRV_GOTOFFHI: - case R_FRV_GOTOFFLO: - case R_FRV_FUNCDESC_GOTOFF12: - case R_FRV_FUNCDESC_GOTOFFHI: - case R_FRV_FUNCDESC_GOTOFFLO: - case R_FRV_FUNCDESC: - case R_FRV_FUNCDESC_VALUE: - case R_FRV_GETTLSOFF: - case R_FRV_TLSDESC_VALUE: - case R_FRV_GOTTLSDESC12: - case R_FRV_GOTTLSDESCHI: - case R_FRV_GOTTLSDESCLO: - case R_FRV_TLSMOFF12: - case R_FRV_TLSMOFFHI: - case R_FRV_TLSMOFFLO: - case R_FRV_GOTTLSOFF12: - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSOFFLO: - case R_FRV_TLSOFF: - case R_FRV_TLSDESC_RELAX: - case R_FRV_GETTLSOFF_RELAX: - case R_FRV_TLSOFF_RELAX: - case R_FRV_TLSMOFF: - if (h != NULL) - picrel = frvfdpic_relocs_info_for_global (frvfdpic_relocs_info - (info), input_bfd, h, - orig_addend, INSERT); - else - /* In order to find the entry we created before, we must - use the original addend, not the one that may have been - modified by _bfd_elf_rela_local_sym(). */ - picrel = frvfdpic_relocs_info_for_local (frvfdpic_relocs_info - (info), input_bfd, r_symndx, - orig_addend, INSERT); - if (! picrel) - return FALSE; - - if (!_frvfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info, - osec, sym, - rel->r_addend)) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: relocation to `%s+%v'" - " may have caused the error above\n"), - input_bfd, input_section, rel->r_offset, name, rel->r_addend); - return FALSE; - } - - break; - - default: - non_fdpic: - picrel = NULL; - if (h - && ! FRVFDPIC_SYM_LOCAL (info, h) - && _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - info->callbacks->einfo - (_("%H: relocation references symbol" - " not defined in the module\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - break; - } - - switch (r_type) - { - case R_FRV_GETTLSOFF: - case R_FRV_TLSDESC_VALUE: - case R_FRV_GOTTLSDESC12: - case R_FRV_GOTTLSDESCHI: - case R_FRV_GOTTLSDESCLO: - case R_FRV_TLSMOFF12: - case R_FRV_TLSMOFFHI: - case R_FRV_TLSMOFFLO: - case R_FRV_GOTTLSOFF12: - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSOFFLO: - case R_FRV_TLSOFF: - case R_FRV_TLSDESC_RELAX: - case R_FRV_GETTLSOFF_RELAX: - case R_FRV_TLSOFF_RELAX: - case R_FRV_TLSMOFF: - if (sec && (bfd_is_abs_section (sec) || bfd_is_und_section (sec))) - relocation += tls_biased_base (info); - break; - - default: - break; - } - - /* Try to apply TLS relaxations. */ - if (1) - switch (r_type) - { - -#define LOCAL_EXEC_P(info, picrel) \ - (bfd_link_executable (info) \ - && (picrel->symndx != -1 || FRVFDPIC_SYM_LOCAL ((info), (picrel)->d.h))) -#define INITIAL_EXEC_P(info, picrel) \ - ((bfd_link_executable (info)|| (info)->flags & DF_STATIC_TLS) \ - && (picrel)->tlsoff_entry) - -#define IN_RANGE_FOR_OFST12_P(value) \ - ((bfd_vma)((value) + 2048) < (bfd_vma)4096) -#define IN_RANGE_FOR_SETLOS_P(value) \ - ((bfd_vma)((value) + 32768) < (bfd_vma)65536) -#define TLSMOFF_IN_RANGE_FOR_SETLOS_P(value, info) \ - (IN_RANGE_FOR_SETLOS_P ((value) - tls_biased_base (info))) - -#define RELAX_GETTLSOFF_LOCAL_EXEC_P(info, picrel, value) \ - (LOCAL_EXEC_P ((info), (picrel)) \ - && TLSMOFF_IN_RANGE_FOR_SETLOS_P((value), (info))) -#define RELAX_GETTLSOFF_INITIAL_EXEC_P(info, picrel) \ - (INITIAL_EXEC_P ((info), (picrel)) \ - && IN_RANGE_FOR_OFST12_P ((picrel)->tlsoff_entry)) - -#define RELAX_TLSDESC_LOCAL_EXEC_P(info, picrel, value) \ - (LOCAL_EXEC_P ((info), (picrel))) -#define RELAX_TLSDESC_INITIAL_EXEC_P(info, picrel) \ - (INITIAL_EXEC_P ((info), (picrel))) - -#define RELAX_GOTTLSOFF_LOCAL_EXEC_P(info, picrel, value) \ - (LOCAL_EXEC_P ((info), (picrel)) \ - && TLSMOFF_IN_RANGE_FOR_SETLOS_P((value), (info))) - - case R_FRV_GETTLSOFF: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a call instruction? */ - if ((insn & (unsigned long)0x01fc0000) != 0x003c0000) - { - info->callbacks->einfo - (_("%H: R_FRV_GETTLSOFF not applied to a call instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_GETTLSOFF_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend)) - { - /* Replace the call instruction (except the packing bit) - with setlos #tlsmofflo(symbol+offset), gr9. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x12fc0000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_GETTLSOFF_INITIAL_EXEC_P (info, picrel)) - { - /* Replace the call instruction (except the packing bit) - with ldi @(gr15, #gottlsoff12(symbol+addend)), gr9. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x12c8f000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_GOTTLSOFF12; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - break; - - case R_FRV_GOTTLSDESC12: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this an lddi instruction? */ - if ((insn & (unsigned long)0x01fc0000) != 0x00cc0000) - { - info->callbacks->einfo - (_("%H: R_FRV_GOTTLSDESC12" - " not applied to an lddi instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - && TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend, - info)) - { - /* Replace lddi @(grB, #gottlsdesc12(symbol+offset), grC - with setlos #tlsmofflo(symbol+offset), gr. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0x80000000) - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - insn |= (unsigned long)0x00fc0000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend)) - { - /* Replace lddi @(grB, #gottlsdesc12(symbol+offset), grC - with sethi #tlsmoffhi(symbol+offset), gr. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0x80000000) - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - insn |= (unsigned long)0x00f80000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFHI; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)) - { - /* Replace lddi @(grB, #gottlsdesc12(symbol+offset), grC - with ldi @(grB, #gottlsoff12(symbol+offset), - gr. Preserve the packing bit. If gottlsoff12 - overflows, we'll error out, but that's sort-of ok, - since we'd started with gottlsdesc12, that's actually - more demanding. Compiling with -fPIE instead of - -fpie would fix it; linking with --relax should fix - it as well. */ - insn = (insn & (unsigned long)0x80cbf000) - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_GOTTLSOFF12; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - break; - - case R_FRV_GOTTLSDESCHI: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a sethi instruction? */ - if ((insn & (unsigned long)0x01ff0000) != 0x00f80000) - { - info->callbacks->einfo - (_("%H: R_FRV_GOTTLSDESCHI" - " not applied to a sethi instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel) - && IN_RANGE_FOR_SETLOS_P (picrel->tlsoff_entry))) - { - /* Replace sethi with a nop. Preserve the packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)) - { - /* Simply decay GOTTLSDESC to GOTTLSOFF. */ - r_type = R_FRV_GOTTLSOFFHI; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - break; - - case R_FRV_GOTTLSDESCLO: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a setlo or setlos instruction? */ - if ((insn & (unsigned long)0x01f70000) != 0x00f40000) - { - info->callbacks->einfo - (_("%H: R_FRV_GOTTLSDESCLO" - " not applied to a setlo or setlos instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel) - && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry))) - { - /* Replace setlo/setlos with a nop. Preserve the - packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)) - { - /* If the corresponding sethi (if it exists) decayed - to a nop, make sure this becomes (or already is) a - setlos, not setlo. */ - if (IN_RANGE_FOR_SETLOS_P (picrel->tlsoff_entry)) - { - insn |= (unsigned long)0x00080000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - - /* Simply decay GOTTLSDESC to GOTTLSOFF. */ - r_type = R_FRV_GOTTLSOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - break; - - case R_FRV_TLSDESC_RELAX: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this an ldd instruction? */ - if ((insn & (unsigned long)0x01fc0fc0) != 0x00080140) - { - info->callbacks->einfo - (_("%H: R_FRV_TLSDESC_RELAX" - " not applied to an ldd instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - && TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend, - info)) - { - /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC - with setlos #tlsmofflo(symbol+offset), gr. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0x80000000) - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - insn |= (unsigned long)0x00fc0000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend)) - { - /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC - with sethi #tlsmoffhi(symbol+offset), gr. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0x80000000) - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - insn |= (unsigned long)0x00f80000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFHI; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel) - && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry)) - { - /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC - with ldi @(grB, #gottlsoff12(symbol+offset), gr. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0x8003f000) - | (unsigned long)0x00c80000 - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_GOTTLSOFF12; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)) - { - /* Replace ldd #tlsdesc(symbol+offset)@(grB, grA), grC - with ld #tlsoff(symbol+offset)@(grB, grA), gr. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0x81ffffbf) - | ((insn + (unsigned long)0x02000000) - & (unsigned long)0x7e000000); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* #tlsoff(symbol+offset) is just a relaxation - annotation, so there's nothing left to - relocate. */ - continue; - } - - break; - - case R_FRV_GETTLSOFF_RELAX: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a calll or callil instruction? */ - if ((insn & (unsigned long)0x7ff80fc0) != 0x02300000) - { - info->callbacks->einfo - (_("%H: R_FRV_GETTLSOFF_RELAX" - " not applied to a calll instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - && TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend, - info)) - { - /* Replace calll with a nop. Preserve the packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - else if (RELAX_TLSDESC_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend)) - { - /* Replace calll with setlo #tlsmofflo(symbol+offset), gr9. - Preserve the packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x12f40000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel)) - { - /* Replace calll with a nop. Preserve the packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - break; - - case R_FRV_GOTTLSOFF12: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this an ldi instruction? */ - if ((insn & (unsigned long)0x01fc0000) != 0x00c80000) - { - info->callbacks->einfo - (_("%H: R_FRV_GOTTLSOFF12" - " not applied to an ldi instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend)) - { - /* Replace ldi @(grB, #gottlsoff12(symbol+offset), grC - with setlos #tlsmofflo(symbol+offset), grC. - Preserve the packing bit. */ - insn &= (unsigned long)0xfe000000; - insn |= (unsigned long)0x00fc0000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - break; - - case R_FRV_GOTTLSOFFHI: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a sethi instruction? */ - if ((insn & (unsigned long)0x01ff0000) != 0x00f80000) - { - info->callbacks->einfo - (_("%H: R_FRV_GOTTLSOFFHI" - " not applied to a sethi instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel) - && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry))) - { - /* Replace sethi with a nop. Preserve the packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - break; - - case R_FRV_GOTTLSOFFLO: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a setlo or setlos instruction? */ - if ((insn & (unsigned long)0x01f70000) != 0x00f40000) - { - info->callbacks->einfo - (_("%H: R_FRV_GOTTLSOFFLO" - " not applied to a setlo or setlos instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend) - || (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel) - && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry))) - { - /* Replace setlo/setlos with a nop. Preserve the - packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - break; - - case R_FRV_TLSOFF_RELAX: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this an ld instruction? */ - if ((insn & (unsigned long)0x01fc0fc0) != 0x00080100) - { - info->callbacks->einfo - (_("%H: R_FRV_TLSOFF_RELAX" - " not applied to an ld instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (RELAX_GOTTLSOFF_LOCAL_EXEC_P (info, picrel, - relocation + rel->r_addend)) - { - /* Replace ld #gottlsoff(symbol+offset)@(grB, grA), grC - with setlos #tlsmofflo(symbol+offset), grC. - Preserve the packing bit. */ - insn &= (unsigned long)0xfe000000; - insn |= (unsigned long)0x00fc0000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_TLSMOFFLO; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - else if (RELAX_TLSDESC_INITIAL_EXEC_P (info, picrel) - && IN_RANGE_FOR_OFST12_P (picrel->tlsoff_entry)) - { - /* Replace ld #tlsoff(symbol+offset)@(grB, grA), grC - with ldi @(grB, #gottlsoff12(symbol+offset), grC. - Preserve the packing bit. */ - insn = (insn & (unsigned long)0xfe03f000) - | (unsigned long)0x00c80000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - r_type = R_FRV_GOTTLSOFF12; - howto = elf32_frv_howto_table + r_type; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - - break; - - case R_FRV_TLSMOFFHI: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a sethi instruction? */ - if ((insn & (unsigned long)0x01ff0000) != 0x00f80000) - { - info->callbacks->einfo - (_("%H: R_FRV_TLSMOFFHI" - " not applied to a sethi instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend, - info)) - { - /* Replace sethi with a nop. Preserve the packing bit. */ - insn &= (unsigned long)0x80000000; - insn |= (unsigned long)0x00880000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - /* Nothing to relocate. */ - continue; - } - - break; - - case R_FRV_TLSMOFFLO: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - /* Is this a setlo or setlos instruction? */ - if ((insn & (unsigned long)0x01f70000) != 0x00f40000) - { - info->callbacks->einfo - (_("R_FRV_TLSMOFFLO" - " not applied to a setlo or setlos instruction\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - if (TLSMOFF_IN_RANGE_FOR_SETLOS_P (relocation + rel->r_addend, - info)) - /* If the corresponding sethi (if it exists) decayed - to a nop, make sure this becomes (or already is) a - setlos, not setlo. */ - { - insn |= (unsigned long)0x00080000; - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - - break; - - /* - There's nothing to relax in these: - R_FRV_TLSDESC_VALUE - R_FRV_TLSOFF - R_FRV_TLSMOFF12 - R_FRV_TLSMOFFHI - R_FRV_TLSMOFFLO - R_FRV_TLSMOFF - */ - - default: - break; - } - - switch (r_type) - { - case R_FRV_LABEL24: - check_segment[0] = isec_segment; - if (! IS_FDPIC (output_bfd)) - check_segment[1] = isec_segment; - else if (picrel->plt) - { - relocation = frvfdpic_plt_section (info)->output_section->vma - + frvfdpic_plt_section (info)->output_offset - + picrel->plt_entry; - check_segment[1] = plt_segment; - } - /* We don't want to warn on calls to undefined weak symbols, - as calls to them must be protected by non-NULL tests - anyway, and unprotected calls would invoke undefined - behavior. */ - else if (picrel->symndx == -1 - && picrel->d.h->root.type == bfd_link_hash_undefweak) - check_segment[1] = check_segment[0]; - else - check_segment[1] = sec - ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - - case R_FRV_GOT12: - case R_FRV_GOTHI: - case R_FRV_GOTLO: - relocation = picrel->got_entry; - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_FRV_FUNCDESC_GOT12: - case R_FRV_FUNCDESC_GOTHI: - case R_FRV_FUNCDESC_GOTLO: - relocation = picrel->fdgot_entry; - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_FRV_GOTOFFHI: - case R_FRV_GOTOFF12: - case R_FRV_GOTOFFLO: - relocation -= frvfdpic_got_section (info)->output_section->vma - + frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info); - check_segment[0] = got_segment; - check_segment[1] = sec - ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - - case R_FRV_FUNCDESC_GOTOFF12: - case R_FRV_FUNCDESC_GOTOFFHI: - case R_FRV_FUNCDESC_GOTOFFLO: - relocation = picrel->fd_entry; - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_FRV_FUNCDESC: - { - int dynindx; - bfd_vma addend = rel->r_addend; - - if (! (h && h->root.type == bfd_link_hash_undefweak - && FRVFDPIC_SYM_LOCAL (info, h))) - { - /* If the symbol is dynamic and there may be dynamic - symbol resolution because we are or are linked with a - shared library, emit a FUNCDESC relocation such that - the dynamic linker will allocate the function - descriptor. If the symbol needs a non-local function - descriptor but binds locally (e.g., its visibility is - protected, emit a dynamic relocation decayed to - section+offset. */ - if (h && ! FRVFDPIC_FUNCDESC_LOCAL (info, h) - && FRVFDPIC_SYM_LOCAL (info, h) - && !bfd_link_pde (info)) - { - dynindx = elf_section_data (h->root.u.def.section - ->output_section)->dynindx; - addend += h->root.u.def.section->output_offset - + h->root.u.def.value; - } - else if (h && ! FRVFDPIC_FUNCDESC_LOCAL (info, h)) - { - if (addend) - { - info->callbacks->einfo - (_("%H: R_FRV_FUNCDESC references dynamic symbol" - " with nonzero addend\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - dynindx = h->dynindx; - } - else - { - /* Otherwise, we know we have a private function - descriptor, so reference it directly. */ - BFD_ASSERT (picrel->privfd); - r_type = R_FRV_32; - dynindx = elf_section_data (frvfdpic_got_section (info) - ->output_section)->dynindx; - addend = frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info) - + picrel->fd_entry; - } - - /* If there is room for dynamic symbol resolution, emit - the dynamic relocation. However, if we're linking an - executable at a fixed location, we won't have emitted a - dynamic symbol entry for the got section, so idx will - be zero, which means we can and should compute the - address of the private descriptor ourselves. */ - if (bfd_link_pde (info) - && (!h || FRVFDPIC_FUNCDESC_LOCAL (info, h))) - { - addend += frvfdpic_got_section (info)->output_section->vma; - if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma offset; - - if (_frvfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->einfo - (_("%H: cannot emit fixups" - " in read-only section\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - offset = _bfd_elf_section_offset - (output_bfd, info, - input_section, rel->r_offset); - - if (offset != (bfd_vma)-1) - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section - (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - picrel); - } - } - else if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma offset; - - if (_frvfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->einfo - (_("%H: cannot emit dynamic relocations" - " in read-only section\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - offset = _bfd_elf_section_offset - (output_bfd, info, - input_section, rel->r_offset); - - if (offset != (bfd_vma)-1) - _frvfdpic_add_dyn_reloc (output_bfd, - frvfdpic_gotrel_section (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - r_type, dynindx, addend, picrel); - } - else - addend += frvfdpic_got_section (info)->output_section->vma; - } - - /* We want the addend in-place because dynamic - relocations are REL. Setting relocation to it should - arrange for it to be installed. */ - relocation = addend - rel->r_addend; - } - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_FRV_32: - if (! IS_FDPIC (output_bfd)) - { - check_segment[0] = check_segment[1] = -1; - break; - } - /* Fall through. */ - case R_FRV_FUNCDESC_VALUE: - { - int dynindx; - bfd_vma addend = rel->r_addend; - - /* If the symbol is dynamic but binds locally, use - section+offset. */ - if (h && ! FRVFDPIC_SYM_LOCAL (info, h)) - { - if (addend && r_type == R_FRV_FUNCDESC_VALUE) - { - info->callbacks->einfo - (_("%H: R_FRV_FUNCDESC_VALUE" - " references dynamic symbol with nonzero addend\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - dynindx = h->dynindx; - } - else - { - if (h) - addend += h->root.u.def.value; - else - addend += sym->st_value; - if (osec) - addend += osec->output_offset; - if (osec && osec->output_section - && ! bfd_is_abs_section (osec->output_section) - && ! bfd_is_und_section (osec->output_section)) - dynindx = elf_section_data (osec->output_section)->dynindx; - else - dynindx = 0; - } - - /* If we're linking an executable at a fixed address, we - can omit the dynamic relocation as long as the symbol - is defined in the current link unit (which is implied - by its output section not being NULL). */ - if (bfd_link_pde (info) - && (!h || FRVFDPIC_SYM_LOCAL (info, h))) - { - if (osec) - addend += osec->output_section->vma; - if (IS_FDPIC (input_bfd) - && (bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - if (_frvfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->einfo - (_("%H: cannot emit fixups in read-only section\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - if (!h || h->root.type != bfd_link_hash_undefweak) - { - bfd_vma offset = _bfd_elf_section_offset - (output_bfd, info, - input_section, rel->r_offset); - - if (offset != (bfd_vma)-1) - { - _frvfdpic_add_rofixup (output_bfd, - frvfdpic_gotfixup_section - (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - picrel); - if (r_type == R_FRV_FUNCDESC_VALUE) - _frvfdpic_add_rofixup - (output_bfd, - frvfdpic_gotfixup_section (info), - offset - + input_section->output_section->vma - + input_section->output_offset + 4, picrel); - } - } - } - } - else - { - if ((bfd_get_section_flags (output_bfd, - input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma offset; - - if (_frvfdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->einfo - (_("%H: cannot emit dynamic relocations" - " in read-only section\n"), - input_bfd, input_section, rel->r_offset); - return FALSE; - } - - offset = _bfd_elf_section_offset - (output_bfd, info, - input_section, rel->r_offset); - - if (offset != (bfd_vma)-1) - _frvfdpic_add_dyn_reloc (output_bfd, - frvfdpic_gotrel_section (info), - offset + input_section - ->output_section->vma - + input_section->output_offset, - r_type, dynindx, addend, picrel); - } - else if (osec) - addend += osec->output_section->vma; - /* We want the addend in-place because dynamic - relocations are REL. Setting relocation to it - should arrange for it to be installed. */ - relocation = addend - rel->r_addend; - } - - if (r_type == R_FRV_FUNCDESC_VALUE) - { - /* If we've omitted the dynamic relocation, just emit - the fixed addresses of the symbol and of the local - GOT base offset. */ - if (bfd_link_pde (info) - && (!h || FRVFDPIC_SYM_LOCAL (info, h))) - bfd_put_32 (output_bfd, - frvfdpic_got_section (info)->output_section->vma - + frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info), - contents + rel->r_offset + 4); - else - /* A function descriptor used for lazy or local - resolving is initialized such that its high word - contains the output section index in which the - PLT entries are located, and the low word - contains the offset of the lazy PLT entry entry - point into that section. */ - bfd_put_32 (output_bfd, - h && ! FRVFDPIC_SYM_LOCAL (info, h) - ? 0 - : _frvfdpic_osec_to_segment (output_bfd, - sec - ->output_section), - contents + rel->r_offset + 4); - } - } - check_segment[0] = check_segment[1] = got_segment; - break; - - case R_FRV_GPREL12: - case R_FRV_GPRELU12: - case R_FRV_GPREL32: - case R_FRV_GPRELHI: - case R_FRV_GPRELLO: - check_segment[0] = gprel_segment; - check_segment[1] = sec - ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - - case R_FRV_GETTLSOFF: - relocation = frvfdpic_plt_section (info)->output_section->vma - + frvfdpic_plt_section (info)->output_offset - + picrel->tlsplt_entry; - BFD_ASSERT (picrel->tlsplt_entry != (bfd_vma)-1 - && picrel->tlsdesc_entry); - check_segment[0] = isec_segment; - check_segment[1] = plt_segment; - break; - - case R_FRV_GOTTLSDESC12: - case R_FRV_GOTTLSDESCHI: - case R_FRV_GOTTLSDESCLO: - BFD_ASSERT (picrel->tlsdesc_entry); - relocation = picrel->tlsdesc_entry; - check_segment[0] = tls_segment; - check_segment[1] = sec - && ! bfd_is_abs_section (sec) - && ! bfd_is_und_section (sec) - ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section) - : tls_segment; - break; - - case R_FRV_TLSMOFF12: - case R_FRV_TLSMOFFHI: - case R_FRV_TLSMOFFLO: - case R_FRV_TLSMOFF: - check_segment[0] = tls_segment; - if (! sec) - check_segment[1] = -1; - else if (bfd_is_abs_section (sec) - || bfd_is_und_section (sec)) - { - relocation = 0; - check_segment[1] = tls_segment; - } - else if (sec->output_section) - { - relocation -= tls_biased_base (info); - check_segment[1] = - _frvfdpic_osec_to_segment (output_bfd, sec->output_section); - } - else - check_segment[1] = -1; - break; - - case R_FRV_GOTTLSOFF12: - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSOFFLO: - BFD_ASSERT (picrel->tlsoff_entry); - relocation = picrel->tlsoff_entry; - check_segment[0] = tls_segment; - check_segment[1] = sec - && ! bfd_is_abs_section (sec) - && ! bfd_is_und_section (sec) - ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section) - : tls_segment; - break; - - case R_FRV_TLSDESC_VALUE: - case R_FRV_TLSOFF: - /* These shouldn't be present in input object files. */ - check_segment[0] = check_segment[1] = isec_segment; - break; - - case R_FRV_TLSDESC_RELAX: - case R_FRV_GETTLSOFF_RELAX: - case R_FRV_TLSOFF_RELAX: - /* These are just annotations for relaxation, nothing to do - here. */ - continue; - - default: - check_segment[0] = isec_segment; - check_segment[1] = sec - ? _frvfdpic_osec_to_segment (output_bfd, sec->output_section) - : (unsigned)-1; - break; - } - - if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd)) - { - /* If you take this out, remove the #error from fdpic-static-6.d - in the ld testsuite. */ - /* This helps catch problems in GCC while we can't do more - than static linking. The idea is to test whether the - input file basename is crt0.o only once. */ - if (silence_segment_error == 1) - silence_segment_error = - (strlen (input_bfd->filename) == 6 - && filename_cmp (input_bfd->filename, "crt0.o") == 0) - || (strlen (input_bfd->filename) > 6 - && filename_cmp (input_bfd->filename - + strlen (input_bfd->filename) - 7, - "/crt0.o") == 0) - ? -1 : 0; - if (!silence_segment_error - /* We don't want duplicate errors for undefined - symbols. */ - && !(picrel && picrel->symndx == -1 - && picrel->d.h->root.type == bfd_link_hash_undefined)) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: reloc against `%s' references a different segment\n"), - input_bfd, input_section, rel->r_offset, name); - } - if (!silence_segment_error && bfd_link_pic (info)) - return FALSE; - elf_elfheader (output_bfd)->e_flags |= EF_FRV_PIC; - } - - switch (r_type) - { - case R_FRV_GOTOFFHI: - case R_FRV_TLSMOFFHI: - /* We need the addend to be applied before we shift the - value right. */ - relocation += rel->r_addend; - /* Fall through. */ - case R_FRV_GOTHI: - case R_FRV_FUNCDESC_GOTHI: - case R_FRV_FUNCDESC_GOTOFFHI: - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSDESCHI: - relocation >>= 16; - /* Fall through. */ - - case R_FRV_GOTLO: - case R_FRV_FUNCDESC_GOTLO: - case R_FRV_GOTOFFLO: - case R_FRV_FUNCDESC_GOTOFFLO: - case R_FRV_GOTTLSOFFLO: - case R_FRV_GOTTLSDESCLO: - case R_FRV_TLSMOFFLO: - relocation &= 0xffff; - break; - - default: - break; - } - - switch (r_type) - { - case R_FRV_LABEL24: - if (! IS_FDPIC (output_bfd) || ! picrel->plt) - break; - /* Fall through. */ - - /* When referencing a GOT entry, a function descriptor or a - PLT, we don't want the addend to apply to the reference, - but rather to the referenced symbol. The actual entry - will have already been created taking the addend into - account, so cancel it out here. */ - case R_FRV_GOT12: - case R_FRV_GOTHI: - case R_FRV_GOTLO: - case R_FRV_FUNCDESC_GOT12: - case R_FRV_FUNCDESC_GOTHI: - case R_FRV_FUNCDESC_GOTLO: - case R_FRV_FUNCDESC_GOTOFF12: - case R_FRV_FUNCDESC_GOTOFFHI: - case R_FRV_FUNCDESC_GOTOFFLO: - case R_FRV_GETTLSOFF: - case R_FRV_GOTTLSDESC12: - case R_FRV_GOTTLSDESCHI: - case R_FRV_GOTTLSDESCLO: - case R_FRV_GOTTLSOFF12: - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSOFFLO: - /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF12 - here, since we do want to apply the addend to the others. - Note that we've applied the addend to GOTOFFHI before we - shifted it right. */ - case R_FRV_GOTOFFHI: - case R_FRV_TLSMOFFHI: - relocation -= rel->r_addend; - break; - - default: - break; - } - - if (r_type == R_FRV_HI16) - r = elf32_frv_relocate_hi16 (input_bfd, rel, contents, relocation); - - else if (r_type == R_FRV_LO16) - r = elf32_frv_relocate_lo16 (input_bfd, rel, contents, relocation); - - else if (r_type == R_FRV_LABEL24 || r_type == R_FRV_GETTLSOFF) - r = elf32_frv_relocate_label24 (input_bfd, input_section, rel, - contents, relocation); - - else if (r_type == R_FRV_GPREL12) - r = elf32_frv_relocate_gprel12 (info, input_bfd, input_section, rel, - contents, relocation); - - else if (r_type == R_FRV_GPRELU12) - r = elf32_frv_relocate_gprelu12 (info, input_bfd, input_section, rel, - contents, relocation); - - else if (r_type == R_FRV_GPRELLO) - r = elf32_frv_relocate_gprello (info, input_bfd, input_section, rel, - contents, relocation); - - else if (r_type == R_FRV_GPRELHI) - r = elf32_frv_relocate_gprelhi (info, input_bfd, input_section, rel, - contents, relocation); - - else if (r_type == R_FRV_TLSOFF - || r_type == R_FRV_TLSDESC_VALUE) - r = bfd_reloc_notsupported; - - else - r = frv_final_link_relocate (howto, input_bfd, input_section, contents, - rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: reloc against `%s': %s\n"), - input_bfd, input_section, rel->r_offset, name, msg); - return FALSE; - } - } - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -elf32_frv_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_FRV_GNU_VTINHERIT: - case R_FRV_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it to put .comm items in .scomm, and not .comm. */ - -static bfd_boolean -elf32_frv_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && (int)sym->st_size <= (int)bfd_get_gp_size (abfd)) - { - /* Common symbols less than or equal to -G nn bytes are - automatically put into .sbss. */ - - asection *scomm = bfd_get_section_by_name (abfd, ".scommon"); - - if (scomm == NULL) - { - scomm = bfd_make_section_with_flags (abfd, ".scommon", - (SEC_ALLOC - | SEC_IS_COMMON - | SEC_LINKER_CREATED)); - if (scomm == NULL) - return FALSE; - } - - *secp = scomm; - *valp = sym->st_size; - } - - return TRUE; -} - -/* We need dynamic symbols for every section, since segments can - relocate independently. */ -static bfd_boolean -_frvfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info - ATTRIBUTE_UNUSED, - asection *p ATTRIBUTE_UNUSED) -{ - 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: - return FALSE; - - /* There shouldn't be section relative relocations - against any other section. */ - default: - return TRUE; - } -} - -/* Create a .got section, as well as its additional info field. This - is almost entirely copied from - elflink.c:_bfd_elf_create_got_section(). */ - -static bfd_boolean -_frv_create_got_section (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags, pltflags; - asection *s; - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - int ptralign; - int offset; - - /* This function may be called more than once. */ - s = elf_hash_table (info)->sgot; - if (s != NULL) - return TRUE; - - /* Machine specific: although pointers are 32-bits wide, we want the - GOT to be aligned to a 64-bit boundary, such that function - descriptors in it can be accessed with 64-bit loads and - stores. */ - ptralign = 3; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - pltflags = flags; - - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - elf_hash_table (info)->sgot = s; - 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; - - /* Machine-specific: we want the symbol for executables as - well. */ - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* The first bit of the global offset table is the header. */ - s->size += bed->got_header_size; - - /* This is the machine-specific part. Create and initialize section - data for the got. */ - if (IS_FDPIC (abfd)) - { - frvfdpic_relocs_info (info) = htab_try_create (1, - frvfdpic_relocs_info_hash, - frvfdpic_relocs_info_eq, - (htab_del) NULL); - if (! frvfdpic_relocs_info (info)) - return FALSE; - - s = bfd_make_section_anyway_with_flags (abfd, ".rel.got", - (flags | SEC_READONLY)); - elf_hash_table (info)->srelgot = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* Machine-specific. */ - s = bfd_make_section_anyway_with_flags (abfd, ".rofixup", - (flags | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - frvfdpic_gotfixup_section (info) = s; - offset = -2048; - flags = BSF_GLOBAL; - } - else - { - offset = 2048; - flags = BSF_GLOBAL | BSF_WEAK; - } - - /* Define _gp in .rofixup, for FDPIC, or .got otherwise. If it - turns out that we're linking with a different linker script, the - linker script will override it. */ - bh = NULL; - if (!(_bfd_generic_link_add_one_symbol - (info, abfd, "_gp", flags, s, offset, (const char *) NULL, FALSE, - bed->collect, &bh))) - return FALSE; - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - /* h->other = STV_HIDDEN; */ /* Should we? */ - - /* Machine-specific: we want the symbol for executables as well. */ - if (IS_FDPIC (abfd) && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - if (!IS_FDPIC (abfd)) - return TRUE; - - /* FDPIC supports Thread Local Storage, and this may require a - procedure linkage table for TLS PLT entries. */ - - /* This is mostly copied from - elflink.c:_bfd_elf_create_dynamic_sections(). */ - - flags = pltflags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - /* FRV-specific: remember it. */ - frvfdpic_plt_section (info) = s; - - /* 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; - } - - /* FRV-specific: we want rel relocations for the plt. */ - s = bfd_make_section_anyway_with_flags (abfd, ".rel.plt", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - /* FRV-specific: remember it. */ - frvfdpic_pltrel_section (info) = s; - - return TRUE; -} - -/* Make sure the got and plt sections exist, and that our pointers in - the link hash table point to them. */ - -static bfd_boolean -elf32_frvfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - /* This is mostly copied from - elflink.c:_bfd_elf_create_dynamic_sections(). */ - flagword flags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - - /* FRV-specific: we want to create the GOT and the PLT in the FRV - way. */ - if (! _frv_create_got_section (abfd, info)) - return FALSE; - - /* FRV-specific: make sure we created everything we wanted. */ - BFD_ASSERT (frvfdpic_got_section (info) && frvfdpic_gotrel_section (info) - && frvfdpic_gotfixup_section (info) - && frvfdpic_plt_section (info) - && frvfdpic_pltrel_section (info)); - - 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_anyway_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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_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; -} - -/* Compute the total GOT and PLT size required by each symbol in each - range. Symbols may require up to 4 words in the GOT: an entry - pointing to the symbol, an entry pointing to its function - descriptor, and a private function descriptors taking two - words. */ - -static void -_frvfdpic_count_nontls_entries (struct frvfdpic_relocs_info *entry, - struct _frvfdpic_dynamic_got_info *dinfo) -{ - /* Allocate space for a GOT entry pointing to the symbol. */ - if (entry->got12) - dinfo->got12 += 4; - else if (entry->gotlos) - dinfo->gotlos += 4; - else if (entry->gothilo) - dinfo->gothilo += 4; - else - entry->relocs32--; - entry->relocs32++; - - /* Allocate space for a GOT entry pointing to the function - descriptor. */ - if (entry->fdgot12) - dinfo->got12 += 4; - else if (entry->fdgotlos) - dinfo->gotlos += 4; - else if (entry->fdgothilo) - dinfo->gothilo += 4; - else - entry->relocsfd--; - entry->relocsfd++; - - /* Decide whether we need a PLT entry, a function descriptor in the - GOT, and a lazy PLT entry for this symbol. */ - entry->plt = entry->call - && entry->symndx == -1 && ! FRVFDPIC_SYM_LOCAL (dinfo->info, entry->d.h) - && elf_hash_table (dinfo->info)->dynamic_sections_created; - entry->privfd = entry->plt - || entry->fdgoff12 || entry->fdgofflos || entry->fdgoffhilo - || ((entry->fd || entry->fdgot12 || entry->fdgotlos || entry->fdgothilo) - && (entry->symndx != -1 - || FRVFDPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h))); - entry->lazyplt = entry->privfd - && entry->symndx == -1 && ! FRVFDPIC_SYM_LOCAL (dinfo->info, entry->d.h) - && ! (dinfo->info->flags & DF_BIND_NOW) - && elf_hash_table (dinfo->info)->dynamic_sections_created; - - /* Allocate space for a function descriptor. */ - if (entry->fdgoff12) - dinfo->fd12 += 8; - else if (entry->fdgofflos) - dinfo->fdlos += 8; - else if (entry->privfd && entry->plt) - dinfo->fdplt += 8; - else if (entry->privfd) - dinfo->fdhilo += 8; - else - entry->relocsfdv--; - entry->relocsfdv++; - - if (entry->lazyplt) - dinfo->lzplt += 8; -} - -/* Compute the total GOT size required by each TLS symbol in each - range. Symbols may require up to 5 words in the GOT: an entry - holding the TLS offset for the symbol, and an entry with a full TLS - descriptor taking 4 words. */ - -static void -_frvfdpic_count_tls_entries (struct frvfdpic_relocs_info *entry, - struct _frvfdpic_dynamic_got_info *dinfo, - bfd_boolean subtract) -{ - const int l = subtract ? -1 : 1; - - /* Allocate space for a GOT entry with the TLS offset of the - symbol. */ - if (entry->tlsoff12) - dinfo->got12 += 4 * l; - else if (entry->tlsofflos) - dinfo->gotlos += 4 * l; - else if (entry->tlsoffhilo) - dinfo->gothilo += 4 * l; - else - entry->relocstlsoff -= l; - entry->relocstlsoff += l; - - /* If there's any TLSOFF relocation, mark the output file as not - suitable for dlopening. This mark will remain even if we relax - all such relocations, but this is not a problem, since we'll only - do so for executables, and we definitely don't want anyone - dlopening executables. */ - if (entry->relocstlsoff) - dinfo->info->flags |= DF_STATIC_TLS; - - /* Allocate space for a TLS descriptor. */ - if (entry->tlsdesc12) - dinfo->tlsd12 += 8 * l; - else if (entry->tlsdesclos) - dinfo->tlsdlos += 8 * l; - else if (entry->tlsplt) - dinfo->tlsdplt += 8 * l; - else if (entry->tlsdeschilo) - dinfo->tlsdhilo += 8 * l; - else - entry->relocstlsd -= l; - entry->relocstlsd += l; -} - -/* Compute the number of dynamic relocations and fixups that a symbol - requires, and add (or subtract) from the grand and per-symbol - totals. */ - -static void -_frvfdpic_count_relocs_fixups (struct frvfdpic_relocs_info *entry, - struct _frvfdpic_dynamic_got_info *dinfo, - bfd_boolean subtract) -{ - bfd_vma relocs = 0, fixups = 0, tlsrets = 0; - - if (!bfd_link_pde (dinfo->info)) - { - relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv - + entry->relocstlsd; - - /* In the executable, TLS relocations to symbols that bind - locally (including those that resolve to global TLS offsets) - are resolved immediately, without any need for fixups or - dynamic relocations. In shared libraries, however, we must - emit dynamic relocations even for local symbols, because we - don't know the module id the library is going to get at - run-time, nor its TLS base offset. */ - if (!bfd_link_executable (dinfo->info) - || (entry->symndx == -1 - && ! FRVFDPIC_SYM_LOCAL (dinfo->info, entry->d.h))) - relocs += entry->relocstlsoff; - } - else - { - if (entry->symndx != -1 || FRVFDPIC_SYM_LOCAL (dinfo->info, entry->d.h)) - { - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - fixups += entry->relocs32 + 2 * entry->relocsfdv; - fixups += entry->relocstlsd; - tlsrets += entry->relocstlsd; - } - else - { - relocs += entry->relocs32 + entry->relocsfdv - + entry->relocstlsoff + entry->relocstlsd; - } - - if (entry->symndx != -1 - || FRVFDPIC_FUNCDESC_LOCAL (dinfo->info, entry->d.h)) - { - if (entry->symndx != -1 - || entry->d.h->root.type != bfd_link_hash_undefweak) - fixups += entry->relocsfd; - } - else - relocs += entry->relocsfd; - } - - if (subtract) - { - relocs = - relocs; - fixups = - fixups; - tlsrets = - tlsrets; - } - - entry->dynrelocs += relocs; - entry->fixups += fixups; - dinfo->relocs += relocs; - dinfo->fixups += fixups; - dinfo->tls_ret_refs += tlsrets; -} - -/* Look for opportunities to relax TLS relocations. We can assume - we're linking the main executable or a static-tls library, since - otherwise we wouldn't have got here. When relaxing, we have to - first undo any previous accounting of TLS uses of fixups, dynamic - relocations, GOT and PLT entries. */ - -static void -_frvfdpic_relax_tls_entries (struct frvfdpic_relocs_info *entry, - struct _frvfdpic_dynamic_got_info *dinfo, - bfd_boolean relaxing) -{ - bfd_boolean changed = ! relaxing; - - BFD_ASSERT (bfd_link_executable (dinfo->info) - || (dinfo->info->flags & DF_STATIC_TLS)); - - if (entry->tlsdesc12 || entry->tlsdesclos || entry->tlsdeschilo) - { - if (! changed) - { - _frvfdpic_count_relocs_fixups (entry, dinfo, TRUE); - _frvfdpic_count_tls_entries (entry, dinfo, TRUE); - changed = TRUE; - } - - /* When linking an executable, we can always decay GOTTLSDESC to - TLSMOFF, if the symbol is local, or GOTTLSOFF, otherwise. - When linking a static-tls shared library, using TLSMOFF is - not an option, but we can still use GOTTLSOFF. When decaying - to GOTTLSOFF, we must keep the GOT entry in range. We know - it has to fit because we'll be trading the 4 words of hte TLS - descriptor for a single word in the same range. */ - if (! bfd_link_executable (dinfo->info) - || (entry->symndx == -1 - && ! FRVFDPIC_SYM_LOCAL (dinfo->info, entry->d.h))) - { - entry->tlsoff12 |= entry->tlsdesc12; - entry->tlsofflos |= entry->tlsdesclos; - entry->tlsoffhilo |= entry->tlsdeschilo; - } - - entry->tlsdesc12 = entry->tlsdesclos = entry->tlsdeschilo = 0; - } - - /* We can only decay TLSOFFs or call #gettlsoff to TLSMOFF in the - main executable. We have to check whether the symbol's TLSOFF is - in range for a setlos. For symbols with a hash entry, we can - determine exactly what to do; for others locals, we don't have - addresses handy, so we use the size of the TLS section as an - approximation. If we get it wrong, we'll retain a GOT entry - holding the TLS offset (without dynamic relocations or fixups), - but we'll still optimize away the loads from it. Since TLS sizes - are generally very small, it's probably not worth attempting to - do better than this. */ - if ((entry->tlsplt - || entry->tlsoff12 || entry->tlsofflos || entry->tlsoffhilo) - && bfd_link_executable (dinfo->info) && relaxing - && ((entry->symndx == -1 - && FRVFDPIC_SYM_LOCAL (dinfo->info, entry->d.h) - /* The above may hold for an undefweak TLS symbol, so make - sure we don't have this case before accessing def.value - and def.section. */ - && (entry->d.h->root.type == bfd_link_hash_undefweak - || (bfd_vma)(entry->d.h->root.u.def.value - + (entry->d.h->root.u.def.section - ->output_section->vma) - + entry->d.h->root.u.def.section->output_offset - + entry->addend - - tls_biased_base (dinfo->info) - + 32768) < (bfd_vma)65536)) - || (entry->symndx != -1 - && (elf_hash_table (dinfo->info)->tls_sec->size - + entry->addend < 32768 + FRVFDPIC_TLS_BIAS)))) - { - if (! changed) - { - _frvfdpic_count_relocs_fixups (entry, dinfo, TRUE); - _frvfdpic_count_tls_entries (entry, dinfo, TRUE); - changed = TRUE; - } - - entry->tlsplt = - entry->tlsoff12 = entry->tlsofflos = entry->tlsoffhilo = 0; - } - - /* We can decay `call #gettlsoff' to a ldi #tlsoff if we already - have a #gottlsoff12 relocation for this entry, or if we can fit - one more in the 12-bit (and 16-bit) ranges. */ - if (entry->tlsplt - && (entry->tlsoff12 - || (relaxing - && dinfo->got12 + dinfo->fd12 + dinfo->tlsd12 <= 4096 - 12 - 4 - && (dinfo->got12 + dinfo->fd12 + dinfo->tlsd12 - + dinfo->gotlos + dinfo->fdlos + dinfo->tlsdlos - <= 65536 - 12 - 4)))) - { - if (! changed) - { - _frvfdpic_count_relocs_fixups (entry, dinfo, TRUE); - _frvfdpic_count_tls_entries (entry, dinfo, TRUE); - changed = TRUE; - } - - entry->tlsoff12 = 1; - entry->tlsplt = 0; - } - - if (changed) - { - _frvfdpic_count_tls_entries (entry, dinfo, FALSE); - _frvfdpic_count_relocs_fixups (entry, dinfo, FALSE); - } - - return; -} - -/* Compute the total GOT and PLT size required by each symbol in each range. * - Symbols may require up to 4 words in the GOT: an entry pointing to - the symbol, an entry pointing to its function descriptor, and a - private function descriptors taking two words. */ - -static int -_frvfdpic_count_got_plt_entries (void **entryp, void *dinfo_) -{ - struct frvfdpic_relocs_info *entry = *entryp; - struct _frvfdpic_dynamic_got_info *dinfo = dinfo_; - - _frvfdpic_count_nontls_entries (entry, dinfo); - - if (bfd_link_executable (dinfo->info) - || (dinfo->info->flags & DF_STATIC_TLS)) - _frvfdpic_relax_tls_entries (entry, dinfo, FALSE); - else - { - _frvfdpic_count_tls_entries (entry, dinfo, FALSE); - _frvfdpic_count_relocs_fixups (entry, dinfo, FALSE); - } - - return 1; -} - -/* Determine the positive and negative ranges to be used by each - offset range in the GOT. FDCUR and CUR, that must be aligned to a - double-word boundary, are the minimum (negative) and maximum - (positive) GOT offsets already used by previous ranges, except for - an ODD entry that may have been left behind. GOT and FD indicate - the size of GOT entries and function descriptors that must be - placed within the range from -WRAP to WRAP. If there's room left, - up to FDPLT bytes should be reserved for additional function - descriptors. */ - -inline static bfd_signed_vma -_frvfdpic_compute_got_alloc_data (struct _frvfdpic_dynamic_got_alloc_data *gad, - bfd_signed_vma fdcur, - bfd_signed_vma odd, - bfd_signed_vma cur, - bfd_vma got, - bfd_vma fd, - bfd_vma fdplt, - bfd_vma tlsd, - bfd_vma tlsdplt, - bfd_vma wrap) -{ - bfd_signed_vma wrapmin = -wrap; - const bfd_vma tdescsz = 8; - - /* Start at the given initial points. */ - gad->fdcur = fdcur; - gad->cur = cur; - - /* If we had an incoming odd word and we have any got entries that - are going to use it, consume it, otherwise leave gad->odd at - zero. We might force gad->odd to zero and return the incoming - odd such that it is used by the next range, but then GOT entries - might appear to be out of order and we wouldn't be able to - shorten the GOT by one word if it turns out to end with an - unpaired GOT entry. */ - if (odd && got) - { - gad->odd = odd; - got -= 4; - odd = 0; - } - else - gad->odd = 0; - - /* If we're left with an unpaired GOT entry, compute its location - such that we can return it. Otherwise, if got doesn't require an - odd number of words here, either odd was already zero in the - block above, or it was set to zero because got was non-zero, or - got was already zero. In the latter case, we want the value of - odd to carry over to the return statement, so we don't want to - reset odd unless the condition below is true. */ - if (got & 4) - { - odd = cur + got; - got += 4; - } - - /* Compute the tentative boundaries of this range. */ - gad->max = cur + got; - gad->min = fdcur - fd; - gad->fdplt = 0; - - /* If function descriptors took too much space, wrap some of them - around. */ - if (gad->min < wrapmin) - { - gad->max += wrapmin - gad->min; - gad->tmin = gad->min = wrapmin; - } - - /* If GOT entries took too much space, wrap some of them around. - This may well cause gad->min to become lower than wrapmin. This - will cause a relocation overflow later on, so we don't have to - report it here . */ - if ((bfd_vma) gad->max > wrap) - { - gad->min -= gad->max - wrap; - gad->max = wrap; - } - - /* Add TLS descriptors. */ - gad->tmax = gad->max + tlsd; - gad->tmin = gad->min; - gad->tlsdplt = 0; - - /* If TLS descriptors took too much space, wrap an integral number - of them around. */ - if ((bfd_vma) gad->tmax > wrap) - { - bfd_vma wrapsize = gad->tmax - wrap; - - wrapsize += tdescsz / 2; - wrapsize &= ~ tdescsz / 2; - - gad->tmin -= wrapsize; - gad->tmax -= wrapsize; - } - - /* If there is space left and we have function descriptors - referenced in PLT entries that could take advantage of shorter - offsets, place them now. */ - if (fdplt && gad->tmin > wrapmin) - { - bfd_vma fds; - - if ((bfd_vma) (gad->tmin - wrapmin) < fdplt) - fds = gad->tmin - wrapmin; - else - fds = fdplt; - - fdplt -= fds; - gad->min -= fds; - gad->tmin -= fds; - gad->fdplt += fds; - } - - /* If there is more space left, try to place some more function - descriptors for PLT entries. */ - if (fdplt && (bfd_vma) gad->tmax < wrap) - { - bfd_vma fds; - - if ((bfd_vma) (wrap - gad->tmax) < fdplt) - fds = wrap - gad->tmax; - else - fds = fdplt; - - fdplt -= fds; - gad->max += fds; - gad->tmax += fds; - gad->fdplt += fds; - } - - /* If there is space left and we have TLS descriptors referenced in - PLT entries that could take advantage of shorter offsets, place - them now. */ - if (tlsdplt && gad->tmin > wrapmin) - { - bfd_vma tlsds; - - if ((bfd_vma) (gad->tmin - wrapmin) < tlsdplt) - tlsds = (gad->tmin - wrapmin) & ~ (tdescsz / 2); - else - tlsds = tlsdplt; - - tlsdplt -= tlsds; - gad->tmin -= tlsds; - gad->tlsdplt += tlsds; - } - - /* If there is more space left, try to place some more TLS - descriptors for PLT entries. Although we could try to fit an - additional TLS descriptor with half of it just before before the - wrap point and another right past the wrap point, this might - cause us to run out of space for the next region, so don't do - it. */ - if (tlsdplt && (bfd_vma) gad->tmax < wrap - tdescsz / 2) - { - bfd_vma tlsds; - - if ((bfd_vma) (wrap - gad->tmax) < tlsdplt) - tlsds = (wrap - gad->tmax) & ~ (tdescsz / 2); - else - tlsds = tlsdplt; - - tlsdplt -= tlsds; - gad->tmax += tlsds; - gad->tlsdplt += tlsds; - } - - /* If odd was initially computed as an offset past the wrap point, - wrap it around. */ - if (odd > gad->max) - odd = gad->min + odd - gad->max; - - /* _frvfdpic_get_got_entry() below will always wrap gad->cur if needed - before returning, so do it here too. This guarantees that, - should cur and fdcur meet at the wrap point, they'll both be - equal to min. */ - if (gad->cur == gad->max) - gad->cur = gad->min; - - /* Ditto for _frvfdpic_get_tlsdesc_entry(). */ - gad->tcur = gad->max; - if (gad->tcur == gad->tmax) - gad->tcur = gad->tmin; - - return odd; -} - -/* Compute the location of the next GOT entry, given the allocation - data for a range. */ - -inline static bfd_signed_vma -_frvfdpic_get_got_entry (struct _frvfdpic_dynamic_got_alloc_data *gad) -{ - bfd_signed_vma ret; - - if (gad->odd) - { - /* If there was an odd word left behind, use it. */ - ret = gad->odd; - gad->odd = 0; - } - else - { - /* Otherwise, use the word pointed to by cur, reserve the next - as an odd word, and skip to the next pair of words, possibly - wrapping around. */ - ret = gad->cur; - gad->odd = gad->cur + 4; - gad->cur += 8; - if (gad->cur == gad->max) - gad->cur = gad->min; - } - - return ret; -} - -/* Compute the location of the next function descriptor entry in the - GOT, given the allocation data for a range. */ - -inline static bfd_signed_vma -_frvfdpic_get_fd_entry (struct _frvfdpic_dynamic_got_alloc_data *gad) -{ - /* If we're at the bottom, wrap around, and only then allocate the - next pair of words. */ - if (gad->fdcur == gad->min) - gad->fdcur = gad->max; - return gad->fdcur -= 8; -} - -/* Compute the location of the next TLS descriptor entry in the GOT, - given the allocation data for a range. */ -inline static bfd_signed_vma -_frvfdpic_get_tlsdesc_entry (struct _frvfdpic_dynamic_got_alloc_data *gad) -{ - bfd_signed_vma ret; - - ret = gad->tcur; - - gad->tcur += 8; - - /* If we're at the top of the region, wrap around to the bottom. */ - if (gad->tcur == gad->tmax) - gad->tcur = gad->tmin; - - return ret; -} - -/* Assign GOT offsets for every GOT entry and function descriptor. - Doing everything in a single pass is tricky. */ - -static int -_frvfdpic_assign_got_entries (void **entryp, void *info_) -{ - struct frvfdpic_relocs_info *entry = *entryp; - struct _frvfdpic_dynamic_got_plt_info *dinfo = info_; - - if (entry->got12) - entry->got_entry = _frvfdpic_get_got_entry (&dinfo->got12); - else if (entry->gotlos) - entry->got_entry = _frvfdpic_get_got_entry (&dinfo->gotlos); - else if (entry->gothilo) - entry->got_entry = _frvfdpic_get_got_entry (&dinfo->gothilo); - - if (entry->fdgot12) - entry->fdgot_entry = _frvfdpic_get_got_entry (&dinfo->got12); - else if (entry->fdgotlos) - entry->fdgot_entry = _frvfdpic_get_got_entry (&dinfo->gotlos); - else if (entry->fdgothilo) - entry->fdgot_entry = _frvfdpic_get_got_entry (&dinfo->gothilo); - - if (entry->fdgoff12) - entry->fd_entry = _frvfdpic_get_fd_entry (&dinfo->got12); - else if (entry->plt && dinfo->got12.fdplt) - { - dinfo->got12.fdplt -= 8; - entry->fd_entry = _frvfdpic_get_fd_entry (&dinfo->got12); - } - else if (entry->fdgofflos) - entry->fd_entry = _frvfdpic_get_fd_entry (&dinfo->gotlos); - else if (entry->plt && dinfo->gotlos.fdplt) - { - dinfo->gotlos.fdplt -= 8; - entry->fd_entry = _frvfdpic_get_fd_entry (&dinfo->gotlos); - } - else if (entry->plt) - { - dinfo->gothilo.fdplt -= 8; - entry->fd_entry = _frvfdpic_get_fd_entry (&dinfo->gothilo); - } - else if (entry->privfd) - entry->fd_entry = _frvfdpic_get_fd_entry (&dinfo->gothilo); - - if (entry->tlsoff12) - entry->tlsoff_entry = _frvfdpic_get_got_entry (&dinfo->got12); - else if (entry->tlsofflos) - entry->tlsoff_entry = _frvfdpic_get_got_entry (&dinfo->gotlos); - else if (entry->tlsoffhilo) - entry->tlsoff_entry = _frvfdpic_get_got_entry (&dinfo->gothilo); - - if (entry->tlsdesc12) - entry->tlsdesc_entry = _frvfdpic_get_tlsdesc_entry (&dinfo->got12); - else if (entry->tlsplt && dinfo->got12.tlsdplt) - { - dinfo->got12.tlsdplt -= 8; - entry->tlsdesc_entry = _frvfdpic_get_tlsdesc_entry (&dinfo->got12); - } - else if (entry->tlsdesclos) - entry->tlsdesc_entry = _frvfdpic_get_tlsdesc_entry (&dinfo->gotlos); - else if (entry->tlsplt && dinfo->gotlos.tlsdplt) - { - dinfo->gotlos.tlsdplt -= 8; - entry->tlsdesc_entry = _frvfdpic_get_tlsdesc_entry (&dinfo->gotlos); - } - else if (entry->tlsplt) - { - dinfo->gothilo.tlsdplt -= 8; - entry->tlsdesc_entry = _frvfdpic_get_tlsdesc_entry (&dinfo->gothilo); - } - else if (entry->tlsdeschilo) - entry->tlsdesc_entry = _frvfdpic_get_tlsdesc_entry (&dinfo->gothilo); - - return 1; -} - -/* Assign GOT offsets to private function descriptors used by PLT - entries (or referenced by 32-bit offsets), as well as PLT entries - and lazy PLT entries. */ - -static int -_frvfdpic_assign_plt_entries (void **entryp, void *info_) -{ - struct frvfdpic_relocs_info *entry = *entryp; - struct _frvfdpic_dynamic_got_plt_info *dinfo = info_; - - if (entry->privfd) - BFD_ASSERT (entry->fd_entry); - - if (entry->plt) - { - int size; - - /* We use the section's raw size to mark the location of the - next PLT entry. */ - entry->plt_entry = frvfdpic_plt_section (dinfo->g.info)->size; - - /* Figure out the length of this PLT entry based on the - addressing mode we need to reach the function descriptor. */ - BFD_ASSERT (entry->fd_entry); - if (entry->fd_entry >= -(1 << (12 - 1)) - && entry->fd_entry < (1 << (12 - 1))) - size = 8; - else if (entry->fd_entry >= -(1 << (16 - 1)) - && entry->fd_entry < (1 << (16 - 1))) - size = 12; - else - size = 16; - - frvfdpic_plt_section (dinfo->g.info)->size += size; - } - - if (entry->lazyplt) - { - entry->lzplt_entry = dinfo->g.lzplt; - dinfo->g.lzplt += 8; - /* If this entry is the one that gets the resolver stub, account - for the additional instruction. */ - if (entry->lzplt_entry % FRVFDPIC_LZPLT_BLOCK_SIZE - == FRVFDPIC_LZPLT_RESOLV_LOC) - dinfo->g.lzplt += 4; - } - - if (entry->tlsplt) - { - int size; - - entry->tlsplt_entry - = frvfdpic_plt_section (dinfo->g.info)->size; - - if (bfd_link_executable (dinfo->g.info) - && (entry->symndx != -1 - || FRVFDPIC_SYM_LOCAL (dinfo->g.info, entry->d.h))) - { - if ((bfd_signed_vma)entry->addend >= -(1 << (16 - 1)) - /* FIXME: here we use the size of the TLS section - as an upper bound for the value of the TLS - symbol, because we may not know the exact value - yet. If we get it wrong, we'll just waste a - word in the PLT, and we should never get even - close to 32 KiB of TLS anyway. */ - && elf_hash_table (dinfo->g.info)->tls_sec - && (elf_hash_table (dinfo->g.info)->tls_sec->size - + (bfd_signed_vma)(entry->addend) <= (1 << (16 - 1)))) - size = 8; - else - size = 12; - } - else if (entry->tlsoff_entry) - { - if (entry->tlsoff_entry >= -(1 << (12 - 1)) - && entry->tlsoff_entry < (1 << (12 - 1))) - size = 8; - else if (entry->tlsoff_entry >= -(1 << (16 - 1)) - && entry->tlsoff_entry < (1 << (16 - 1))) - size = 12; - else - size = 16; - } - else - { - BFD_ASSERT (entry->tlsdesc_entry); - - if (entry->tlsdesc_entry >= -(1 << (12 - 1)) - && entry->tlsdesc_entry < (1 << (12 - 1))) - size = 8; - else if (entry->tlsdesc_entry >= -(1 << (16 - 1)) - && entry->tlsdesc_entry < (1 << (16 - 1))) - size = 12; - else - size = 16; - } - - frvfdpic_plt_section (dinfo->g.info)->size += size; - } - - return 1; -} - -/* Cancel out any effects of calling _frvfdpic_assign_got_entries and - _frvfdpic_assign_plt_entries. */ - -static int -_frvfdpic_reset_got_plt_entries (void **entryp, void *ignore ATTRIBUTE_UNUSED) -{ - struct frvfdpic_relocs_info *entry = *entryp; - - entry->got_entry = 0; - entry->fdgot_entry = 0; - entry->fd_entry = 0; - entry->plt_entry = (bfd_vma)-1; - entry->lzplt_entry = (bfd_vma)-1; - entry->tlsoff_entry = 0; - entry->tlsdesc_entry = 0; - entry->tlsplt_entry = (bfd_vma)-1; - - return 1; -} - -/* Follow indirect and warning hash entries so that each got entry - points to the final symbol definition. P must point to a pointer - to the hash table we're traversing. Since this traversal may - modify the hash table, we set this pointer to NULL to indicate - we've made a potentially-destructive change to the hash table, so - the traversal must be restarted. */ -static int -_frvfdpic_resolve_final_relocs_info (void **entryp, void *p) -{ - struct frvfdpic_relocs_info *entry = *entryp; - htab_t *htab = p; - - if (entry->symndx == -1) - { - struct elf_link_hash_entry *h = entry->d.h; - struct frvfdpic_relocs_info *oentry; - - 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 (entry->d.h == h) - return 1; - - oentry = frvfdpic_relocs_info_for_global (*htab, 0, h, entry->addend, - NO_INSERT); - - if (oentry) - { - /* Merge the two entries. */ - frvfdpic_pic_merge_early_relocs_info (oentry, entry); - htab_clear_slot (*htab, entryp); - return 1; - } - - entry->d.h = h; - - /* If we can't find this entry with the new bfd hash, re-insert - it, and get the traversal restarted. */ - if (! htab_find (*htab, entry)) - { - htab_clear_slot (*htab, entryp); - entryp = htab_find_slot (*htab, entry, INSERT); - if (! *entryp) - *entryp = entry; - /* Abort the traversal, since the whole table may have - moved, and leave it up to the parent to restart the - process. */ - *(htab_t *)p = NULL; - return 0; - } - } - - return 1; -} - -/* Compute the total size of the GOT, the PLT, the dynamic relocations - section and the rofixup section. Assign locations for GOT and PLT - entries. */ - -static bfd_boolean -_frvfdpic_size_got_plt (bfd *output_bfd, - struct _frvfdpic_dynamic_got_plt_info *gpinfop) -{ - bfd_signed_vma odd; - bfd_vma limit, tlslimit; - struct bfd_link_info *info = gpinfop->g.info; - bfd *dynobj = elf_hash_table (info)->dynobj; - - memcpy (frvfdpic_dynamic_got_plt_info (info), &gpinfop->g, - sizeof (gpinfop->g)); - - odd = 12; - /* Compute the total size taken by entries in the 12-bit and 16-bit - ranges, to tell how many PLT function descriptors we can bring - into the 12-bit range without causing the 16-bit range to - overflow. */ - limit = odd + gpinfop->g.got12 + gpinfop->g.gotlos - + gpinfop->g.fd12 + gpinfop->g.fdlos - + gpinfop->g.tlsd12 + gpinfop->g.tlsdlos; - if (limit < (bfd_vma)1 << 16) - limit = ((bfd_vma)1 << 16) - limit; - else - limit = 0; - if (gpinfop->g.fdplt < limit) - { - tlslimit = (limit - gpinfop->g.fdplt) & ~ (bfd_vma) 8; - limit = gpinfop->g.fdplt; - } - else - tlslimit = 0; - if (gpinfop->g.tlsdplt < tlslimit) - tlslimit = gpinfop->g.tlsdplt; - - /* Determine the ranges of GOT offsets that we can use for each - range of addressing modes. */ - odd = _frvfdpic_compute_got_alloc_data (&gpinfop->got12, - 0, - odd, - 16, - gpinfop->g.got12, - gpinfop->g.fd12, - limit, - gpinfop->g.tlsd12, - tlslimit, - (bfd_vma)1 << (12-1)); - odd = _frvfdpic_compute_got_alloc_data (&gpinfop->gotlos, - gpinfop->got12.tmin, - odd, - gpinfop->got12.tmax, - gpinfop->g.gotlos, - gpinfop->g.fdlos, - gpinfop->g.fdplt - - gpinfop->got12.fdplt, - gpinfop->g.tlsdlos, - gpinfop->g.tlsdplt - - gpinfop->got12.tlsdplt, - (bfd_vma)1 << (16-1)); - odd = _frvfdpic_compute_got_alloc_data (&gpinfop->gothilo, - gpinfop->gotlos.tmin, - odd, - gpinfop->gotlos.tmax, - gpinfop->g.gothilo, - gpinfop->g.fdhilo, - gpinfop->g.fdplt - - gpinfop->got12.fdplt - - gpinfop->gotlos.fdplt, - gpinfop->g.tlsdhilo, - gpinfop->g.tlsdplt - - gpinfop->got12.tlsdplt - - gpinfop->gotlos.tlsdplt, - (bfd_vma)1 << (32-1)); - - /* Now assign (most) GOT offsets. */ - htab_traverse (frvfdpic_relocs_info (info), _frvfdpic_assign_got_entries, - gpinfop); - - frvfdpic_got_section (info)->size = gpinfop->gothilo.tmax - - gpinfop->gothilo.tmin - /* If an odd word is the last word of the GOT, we don't need this - word to be part of the GOT. */ - - (odd + 4 == gpinfop->gothilo.tmax ? 4 : 0); - if (frvfdpic_got_section (info)->size == 0) - frvfdpic_got_section (info)->flags |= SEC_EXCLUDE; - else if (frvfdpic_got_section (info)->size == 12 - && ! elf_hash_table (info)->dynamic_sections_created) - { - frvfdpic_got_section (info)->flags |= SEC_EXCLUDE; - frvfdpic_got_section (info)->size = 0; - } - /* This will be non-NULL during relaxation. The assumption is that - the size of one of these sections will never grow, only shrink, - so we can use the larger buffer we allocated before. */ - else if (frvfdpic_got_section (info)->contents == NULL) - { - frvfdpic_got_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - frvfdpic_got_section (info)->size); - if (frvfdpic_got_section (info)->contents == NULL) - return FALSE; - } - - if (frvfdpic_gotrel_section (info)) - /* Subtract the number of lzplt entries, since those will generate - relocations in the pltrel section. */ - frvfdpic_gotrel_section (info)->size = - (gpinfop->g.relocs - gpinfop->g.lzplt / 8) - * get_elf_backend_data (output_bfd)->s->sizeof_rel; - else - BFD_ASSERT (gpinfop->g.relocs == 0); - if (frvfdpic_gotrel_section (info)->size == 0) - frvfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE; - else if (frvfdpic_gotrel_section (info)->contents == NULL) - { - frvfdpic_gotrel_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - frvfdpic_gotrel_section (info)->size); - if (frvfdpic_gotrel_section (info)->contents == NULL) - return FALSE; - } - - frvfdpic_gotfixup_section (info)->size = (gpinfop->g.fixups + 1) * 4; - if (frvfdpic_gotfixup_section (info)->size == 0) - frvfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE; - else if (frvfdpic_gotfixup_section (info)->contents == NULL) - { - frvfdpic_gotfixup_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - frvfdpic_gotfixup_section (info)->size); - if (frvfdpic_gotfixup_section (info)->contents == NULL) - return FALSE; - } - - if (frvfdpic_pltrel_section (info)) - { - frvfdpic_pltrel_section (info)->size = - gpinfop->g.lzplt / 8 - * get_elf_backend_data (output_bfd)->s->sizeof_rel; - if (frvfdpic_pltrel_section (info)->size == 0) - frvfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE; - else if (frvfdpic_pltrel_section (info)->contents == NULL) - { - frvfdpic_pltrel_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - frvfdpic_pltrel_section (info)->size); - if (frvfdpic_pltrel_section (info)->contents == NULL) - return FALSE; - } - } - - /* Add 4 bytes for every block of at most 65535 lazy PLT entries, - such that there's room for the additional instruction needed to - call the resolver. Since _frvfdpic_assign_got_entries didn't - account for them, our block size is 4 bytes smaller than the real - block size. */ - if (frvfdpic_plt_section (info)) - { - frvfdpic_plt_section (info)->size = gpinfop->g.lzplt - + ((gpinfop->g.lzplt + (FRVFDPIC_LZPLT_BLOCK_SIZE - 4) - 8) - / (FRVFDPIC_LZPLT_BLOCK_SIZE - 4) * 4); - } - - /* Reset it, such that _frvfdpic_assign_plt_entries() can use it to - actually assign lazy PLT entries addresses. */ - gpinfop->g.lzplt = 0; - - /* Save information that we're going to need to generate GOT and PLT - entries. */ - frvfdpic_got_initial_offset (info) = -gpinfop->gothilo.tmin; - - if (get_elf_backend_data (output_bfd)->want_got_sym) - elf_hash_table (info)->hgot->root.u.def.value - = frvfdpic_got_initial_offset (info); - - if (frvfdpic_plt_section (info)) - frvfdpic_plt_initial_offset (info) = - frvfdpic_plt_section (info)->size; - - /* Allocate a ret statement at plt_initial_offset, to be used by - locally-resolved TLS descriptors. */ - if (gpinfop->g.tls_ret_refs) - frvfdpic_plt_section (info)->size += 4; - - htab_traverse (frvfdpic_relocs_info (info), _frvfdpic_assign_plt_entries, - gpinfop); - - /* Allocate the PLT section contents only after - _frvfdpic_assign_plt_entries has a chance to add the size of the - non-lazy PLT entries. */ - if (frvfdpic_plt_section (info)) - { - if (frvfdpic_plt_section (info)->size == 0) - frvfdpic_plt_section (info)->flags |= SEC_EXCLUDE; - else if (frvfdpic_plt_section (info)->contents == NULL) - { - frvfdpic_plt_section (info)->contents = - (bfd_byte *) bfd_zalloc (dynobj, - frvfdpic_plt_section (info)->size); - if (frvfdpic_plt_section (info)->contents == NULL) - return FALSE; - } - } - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf32_frvfdpic_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - struct _frvfdpic_dynamic_got_plt_info gpinfo; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; - } - } - - memset (&gpinfo, 0, sizeof (gpinfo)); - gpinfo.g.info = info; - - for (;;) - { - htab_t relocs = frvfdpic_relocs_info (info); - - htab_traverse (relocs, _frvfdpic_resolve_final_relocs_info, &relocs); - - if (relocs == frvfdpic_relocs_info (info)) - break; - } - - htab_traverse (frvfdpic_relocs_info (info), _frvfdpic_count_got_plt_entries, - &gpinfo.g); - - /* Allocate space to save the summary information, we're going to - use it if we're doing relaxations. */ - frvfdpic_dynamic_got_plt_info (info) = bfd_alloc (dynobj, sizeof (gpinfo.g)); - - if (!_frvfdpic_size_got_plt (output_bfd, &gpinfo)) - return FALSE; - - if (elf_hash_table (info)->dynamic_sections_created) - { - if (frvfdpic_got_section (info)->size) - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0)) - return FALSE; - - if (frvfdpic_pltrel_section (info)->size) - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_REL) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) - return FALSE; - - if (frvfdpic_gotrel_section (info)->size) - if (!_bfd_elf_add_dynamic_entry (info, DT_REL, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELENT, - sizeof (Elf32_External_Rel))) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -elf32_frvfdpic_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - if (!bfd_link_relocatable (info) - && !bfd_elf_stack_segment_size (output_bfd, info, - "__stacksize", DEFAULT_STACK_SIZE)) - return FALSE; - - return TRUE; -} - -/* Check whether any of the relocations was optimized away, and - subtract it from the relocation or fixup count. */ -static bfd_boolean -_frvfdpic_check_discarded_relocs (bfd *abfd, asection *sec, - struct bfd_link_info *info, - - bfd_boolean *changed) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *erel; - - if ((sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel = elf_section_data (sec)->relocs; - - /* Now examine each relocation. */ - for (erel = rel + sec->reloc_count; rel < erel; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - struct frvfdpic_relocs_info *picrel; - struct _frvfdpic_dynamic_got_info *dinfo; - - if (ELF32_R_TYPE (rel->r_info) != R_FRV_32 - && ELF32_R_TYPE (rel->r_info) != R_FRV_FUNCDESC) - continue; - - if (_bfd_elf_section_offset (sec->output_section->owner, - info, sec, rel->r_offset) - != (bfd_vma)-1) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *)h->root.u.i.link; - } - - if (h != NULL) - picrel = frvfdpic_relocs_info_for_global (frvfdpic_relocs_info (info), - abfd, h, - rel->r_addend, NO_INSERT); - else - picrel = frvfdpic_relocs_info_for_local (frvfdpic_relocs_info (info), - abfd, r_symndx, - rel->r_addend, NO_INSERT); - - if (! picrel) - return FALSE; - - *changed = TRUE; - dinfo = frvfdpic_dynamic_got_plt_info (info); - - _frvfdpic_count_relocs_fixups (picrel, dinfo, TRUE); - if (ELF32_R_TYPE (rel->r_info) == R_FRV_32) - picrel->relocs32--; - else /* we know (ELF32_R_TYPE (rel->r_info) == R_FRV_FUNCDESC) */ - picrel->relocsfd--; - _frvfdpic_count_relocs_fixups (picrel, dinfo, FALSE); - } - - return TRUE; -} - -static bfd_boolean -frvfdpic_elf_discard_info (bfd *ibfd, - struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd_boolean changed = FALSE; - asection *s; - bfd *obfd = NULL; - - /* Account for relaxation of .eh_frame section. */ - for (s = ibfd->sections; s; s = s->next) - if (s->sec_info_type == SEC_INFO_TYPE_EH_FRAME) - { - if (!_frvfdpic_check_discarded_relocs (ibfd, s, info, &changed)) - return FALSE; - obfd = s->output_section->owner; - } - - if (changed) - { - struct _frvfdpic_dynamic_got_plt_info gpinfo; - - memset (&gpinfo, 0, sizeof (gpinfo)); - memcpy (&gpinfo.g, frvfdpic_dynamic_got_plt_info (info), - sizeof (gpinfo.g)); - - /* Clear GOT and PLT assignments. */ - htab_traverse (frvfdpic_relocs_info (info), - _frvfdpic_reset_got_plt_entries, - NULL); - - if (!_frvfdpic_size_got_plt (obfd, &gpinfo)) - return FALSE; - } - - return TRUE; -} - -/* Look for opportunities to relax TLS relocations. We can assume - we're linking the main executable or a static-tls library, since - otherwise we wouldn't have got here. */ - -static int -_frvfdpic_relax_got_plt_entries (void **entryp, void *dinfo_) -{ - struct frvfdpic_relocs_info *entry = *entryp; - struct _frvfdpic_dynamic_got_info *dinfo = dinfo_; - - _frvfdpic_relax_tls_entries (entry, dinfo, TRUE); - - return 1; -} - -static bfd_boolean -elf32_frvfdpic_relax_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, - struct bfd_link_info *info, bfd_boolean *again) -{ - struct _frvfdpic_dynamic_got_plt_info gpinfo; - - if (bfd_link_relocatable (info)) - (*info->callbacks->einfo) - (_("%P%F: --relax and -r may not be used together\n")); - - /* If we return early, we didn't change anything. */ - *again = FALSE; - - /* We'll do our thing when requested to relax the GOT section. */ - if (sec != frvfdpic_got_section (info)) - return TRUE; - - /* We can only relax when linking the main executable or a library - that can't be dlopened. */ - if (! bfd_link_executable (info) && ! (info->flags & DF_STATIC_TLS)) - return TRUE; - - /* If there isn't a TLS section for this binary, we can't do - anything about its TLS relocations (it probably doesn't have - any. */ - if (elf_hash_table (info)->tls_sec == NULL) - return TRUE; - - memset (&gpinfo, 0, sizeof (gpinfo)); - memcpy (&gpinfo.g, frvfdpic_dynamic_got_plt_info (info), sizeof (gpinfo.g)); - - /* Now look for opportunities to relax, adjusting the GOT usage - as needed. */ - htab_traverse (frvfdpic_relocs_info (info), - _frvfdpic_relax_got_plt_entries, - &gpinfo.g); - - /* If we changed anything, reset and re-assign GOT and PLT entries. */ - if (memcmp (frvfdpic_dynamic_got_plt_info (info), - &gpinfo.g, sizeof (gpinfo.g)) != 0) - { - /* Clear GOT and PLT assignments. */ - htab_traverse (frvfdpic_relocs_info (info), - _frvfdpic_reset_got_plt_entries, - NULL); - - /* The owner of the TLS section is the output bfd. There should - be a better way to get to it. */ - if (!_frvfdpic_size_got_plt (elf_hash_table (info)->tls_sec->owner, - &gpinfo)) - return FALSE; - - /* Repeat until we don't make any further changes. We could fail to - introduce changes in a round if, for example, the 12-bit range is - full, but we later release some space by getting rid of TLS - descriptors in it. We have to repeat the whole process because - we might have changed the size of a section processed before this - one. */ - *again = TRUE; - } - - return TRUE; -} - -/* Fill in code and data in dynamic sections. */ - -static bfd_boolean -elf32_frv_finish_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - /* Nothing to be done for non-FDPIC. */ - return TRUE; -} - -static bfd_boolean -elf32_frvfdpic_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - if (frvfdpic_dynamic_got_plt_info (info)) - { - BFD_ASSERT (frvfdpic_dynamic_got_plt_info (info)->tls_ret_refs == 0); - } - if (frvfdpic_got_section (info)) - { - BFD_ASSERT (frvfdpic_gotrel_section (info)->size - == (frvfdpic_gotrel_section (info)->reloc_count - * sizeof (Elf32_External_Rel))); - - if (frvfdpic_gotfixup_section (info)) - { - struct elf_link_hash_entry *hgot = elf_hash_table (info)->hgot; - bfd_vma got_value = hgot->root.u.def.value - + hgot->root.u.def.section->output_section->vma - + hgot->root.u.def.section->output_offset; - struct bfd_link_hash_entry *hend; - - _frvfdpic_add_rofixup (output_bfd, frvfdpic_gotfixup_section (info), - got_value, 0); - - if (frvfdpic_gotfixup_section (info)->size - != (frvfdpic_gotfixup_section (info)->reloc_count * 4)) - { - error: - info->callbacks->einfo - ("LINKER BUG: .rofixup section size mismatch\n"); - return FALSE; - } - - hend = bfd_link_hash_lookup (info->hash, "__ROFIXUP_END__", - FALSE, FALSE, TRUE); - if (hend - && (hend->type == bfd_link_hash_defined - || hend->type == bfd_link_hash_defweak) - && hend->u.def.section->output_section != NULL) - { - bfd_vma value = - frvfdpic_gotfixup_section (info)->output_section->vma - + frvfdpic_gotfixup_section (info)->output_offset - + frvfdpic_gotfixup_section (info)->size - - hend->u.def.section->output_section->vma - - hend->u.def.section->output_offset; - BFD_ASSERT (hend->u.def.value == value); - if (hend->u.def.value != value) - goto error; - } - } - } - if (frvfdpic_pltrel_section (info)) - { - BFD_ASSERT (frvfdpic_pltrel_section (info)->size - == (frvfdpic_pltrel_section (info)->reloc_count - * sizeof (Elf32_External_Rel))); - } - - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf32_External_Dyn * dyncon; - Elf32_External_Dyn * dynconend; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - dyn.d_un.d_ptr = frvfdpic_got_section (info)->output_section->vma - + frvfdpic_got_section (info)->output_offset - + frvfdpic_got_initial_offset (info); - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - dyn.d_un.d_ptr = frvfdpic_pltrel_section (info) - ->output_section->vma - + frvfdpic_pltrel_section (info)->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = frvfdpic_pltrel_section (info)->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - } - - return TRUE; -} - -/* Adjust a symbol defined by a dynamic object and referenced by a - regular object. */ - -static bfd_boolean -elf32_frvfdpic_adjust_dynamic_symbol -(struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - bfd * dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - return TRUE; -} - -/* Perform any actions needed for dynamic symbols. */ - -static bfd_boolean -elf32_frvfdpic_finish_dynamic_symbol -(bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Decide whether to attempt to turn absptr or lsda encodings in - shared libraries into pcrel within the given input section. */ - -static bfd_boolean -frvfdpic_elf_use_relative_eh_frame -(bfd *input_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *eh_frame_section ATTRIBUTE_UNUSED) -{ - /* We can't use PC-relative encodings in FDPIC binaries, in general. */ - return FALSE; -} - -/* Adjust the contents of an eh_frame_hdr section before they're output. */ - -static bfd_byte -frvfdpic_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) -{ - struct elf_link_hash_entry *h; - - h = elf_hash_table (info)->hgot; - BFD_ASSERT (h && h->root.type == bfd_link_hash_defined); - - if (! h || (_frvfdpic_osec_to_segment (abfd, osec) - == _frvfdpic_osec_to_segment (abfd, loc_sec->output_section))) - return _bfd_elf_encode_eh_address (abfd, info, osec, offset, - loc_sec, loc_offset, encoded); - - BFD_ASSERT (_frvfdpic_osec_to_segment (abfd, osec) - == (_frvfdpic_osec_to_segment - (abfd, h->root.u.def.section->output_section))); - - *encoded = osec->vma + offset - - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - return DW_EH_PE_datarel | DW_EH_PE_sdata4; -} - -/* Look through the relocs for a section during the first phase. - - Besides handling virtual table relocs for gc, we have to deal with - all sorts of PIC-related relocations. We describe below the - general plan on how to handle such relocations, even though we only - collect information at this point, storing them in hash tables for - perusal of later passes. - - 32 relocations are propagated to the linker output when creating - position-independent output. LO16 and HI16 relocations are not - supposed to be encountered in this case. - - LABEL16 should always be resolvable by the linker, since it's only - used by branches. - - LABEL24, on the other hand, is used by calls. If it turns out that - the target of a call is a dynamic symbol, a PLT entry must be - created for it, which triggers the creation of a private function - descriptor and, unless lazy binding is disabled, a lazy PLT entry. - - GPREL relocations require the referenced symbol to be in the same - segment as _gp, but this can only be checked later. - - All GOT, GOTOFF and FUNCDESC relocations require a .got section to - exist. LABEL24 might as well, since it may require a PLT entry, - that will require a got. - - Non-FUNCDESC GOT relocations require a GOT entry to be created - regardless of whether the symbol is dynamic. However, since a - global symbol that turns out to not be exported may have the same - address of a non-dynamic symbol, we don't assign GOT entries at - this point, such that we can share them in this case. A relocation - for the GOT entry always has to be created, be it to offset a - private symbol by the section load address, be it to get the symbol - resolved dynamically. - - FUNCDESC GOT relocations require a GOT entry to be created, and - handled as if a FUNCDESC relocation was applied to the GOT entry in - an object file. - - FUNCDESC relocations referencing a symbol that turns out to NOT be - dynamic cause a private function descriptor to be created. The - FUNCDESC relocation then decays to a 32 relocation that points at - the private descriptor. If the symbol is dynamic, the FUNCDESC - relocation is propagated to the linker output, such that the - dynamic linker creates the canonical descriptor, pointing to the - dynamically-resolved definition of the function. - - Non-FUNCDESC GOTOFF relocations must always refer to non-dynamic - symbols that are assigned to the same segment as the GOT, but we - can only check this later, after we know the complete set of - symbols defined and/or exported. - - FUNCDESC GOTOFF relocations require a function descriptor to be - created and, unless lazy binding is disabled or the symbol is not - dynamic, a lazy PLT entry. Since we can't tell at this point - whether a symbol is going to be dynamic, we have to decide later - whether to create a lazy PLT entry or bind the descriptor directly - to the private function. - - FUNCDESC_VALUE relocations are not supposed to be present in object - files, but they may very well be simply propagated to the linker - output, since they have no side effect. - - - A function descriptor always requires a FUNCDESC_VALUE relocation. - Whether it's in .plt.rel or not depends on whether lazy binding is - enabled and on whether the referenced symbol is dynamic. - - The existence of a lazy PLT requires the resolverStub lazy PLT - entry to be present. - - - As for assignment of GOT, PLT and lazy PLT entries, and private - descriptors, we might do them all sequentially, but we can do - better than that. For example, we can place GOT entries and - private function descriptors referenced using 12-bit operands - closer to the PIC register value, such that these relocations don't - overflow. Those that are only referenced with LO16 relocations - could come next, but we may as well place PLT-required function - descriptors in the 12-bit range to make them shorter. Symbols - referenced with LO16/HI16 may come next, but we may place - additional function descriptors in the 16-bit range if we can - reliably tell that we've already placed entries that are ever - referenced with only LO16. PLT entries are therefore generated as - small as possible, while not introducing relocation overflows in - GOT or FUNCDESC_GOTOFF relocations. Lazy PLT entries could be - generated before or after PLT entries, but not intermingled with - them, such that we can have more lazy PLT entries in range for a - branch to the resolverStub. The resolverStub should be emitted at - the most distant location from the first lazy PLT entry such that - it's still in range for a branch, or closer, if there isn't a need - for so many lazy PLT entries. Additional lazy PLT entries may be - emitted after the resolverStub, as long as branches are still in - range. If the branch goes out of range, longer lazy PLT entries - are emitted. - - We could further optimize PLT and lazy PLT entries by giving them - priority in assignment to closer-to-gr17 locations depending on the - number of occurrences of references to them (assuming a function - that's called more often is more important for performance, so its - PLT entry should be faster), or taking hints from the compiler. - Given infinite time and money... :-) */ - -static bfd_boolean -elf32_frv_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd *dynobj; - struct frvfdpic_relocs_info *picrel; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - dynobj = elf_hash_table (info)->dynobj; - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_FRV_GETTLSOFF: - case R_FRV_TLSDESC_VALUE: - case R_FRV_GOTTLSDESC12: - case R_FRV_GOTTLSDESCHI: - case R_FRV_GOTTLSDESCLO: - case R_FRV_GOTTLSOFF12: - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSOFFLO: - case R_FRV_TLSOFF: - case R_FRV_GOT12: - case R_FRV_GOTHI: - case R_FRV_GOTLO: - case R_FRV_FUNCDESC_GOT12: - case R_FRV_FUNCDESC_GOTHI: - case R_FRV_FUNCDESC_GOTLO: - case R_FRV_GOTOFF12: - case R_FRV_GOTOFFHI: - case R_FRV_GOTOFFLO: - case R_FRV_FUNCDESC_GOTOFF12: - case R_FRV_FUNCDESC_GOTOFFHI: - case R_FRV_FUNCDESC_GOTOFFLO: - case R_FRV_FUNCDESC: - case R_FRV_FUNCDESC_VALUE: - case R_FRV_TLSMOFF12: - case R_FRV_TLSMOFFHI: - case R_FRV_TLSMOFFLO: - case R_FRV_TLSMOFF: - if (! IS_FDPIC (abfd)) - goto bad_reloc; - /* Fall through. */ - case R_FRV_GPREL12: - case R_FRV_GPRELU12: - case R_FRV_GPRELHI: - case R_FRV_GPRELLO: - case R_FRV_LABEL24: - case R_FRV_32: - if (! dynobj) - { - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! _frv_create_got_section (abfd, info)) - return FALSE; - } - if (! IS_FDPIC (abfd)) - { - picrel = NULL; - break; - } - if (h != NULL) - { - if (h->dynindx == -1) - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - break; - default: - bfd_elf_link_record_dynamic_symbol (info, h); - break; - } - picrel - = frvfdpic_relocs_info_for_global (frvfdpic_relocs_info (info), - abfd, h, - rel->r_addend, INSERT); - } - else - picrel = frvfdpic_relocs_info_for_local (frvfdpic_relocs_info - (info), abfd, r_symndx, - rel->r_addend, INSERT); - if (! picrel) - return FALSE; - break; - - default: - picrel = NULL; - break; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_FRV_LABEL24: - if (IS_FDPIC (abfd)) - picrel->call = 1; - break; - - case R_FRV_FUNCDESC_VALUE: - picrel->relocsfdv++; - if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) - picrel->relocs32--; - /* Fall through. */ - - case R_FRV_32: - if (! IS_FDPIC (abfd)) - break; - - picrel->sym = 1; - if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC) - picrel->relocs32++; - break; - - case R_FRV_GOT12: - picrel->got12 = 1; - break; - - case R_FRV_GOTHI: - case R_FRV_GOTLO: - picrel->gothilo = 1; - break; - - case R_FRV_FUNCDESC_GOT12: - picrel->fdgot12 = 1; - break; - - case R_FRV_FUNCDESC_GOTHI: - case R_FRV_FUNCDESC_GOTLO: - picrel->fdgothilo = 1; - break; - - case R_FRV_GOTOFF12: - case R_FRV_GOTOFFHI: - case R_FRV_GOTOFFLO: - picrel->gotoff = 1; - break; - - case R_FRV_FUNCDESC_GOTOFF12: - picrel->fdgoff12 = 1; - break; - - case R_FRV_FUNCDESC_GOTOFFHI: - case R_FRV_FUNCDESC_GOTOFFLO: - picrel->fdgoffhilo = 1; - break; - - case R_FRV_FUNCDESC: - picrel->fd = 1; - picrel->relocsfd++; - break; - - case R_FRV_GETTLSOFF: - picrel->tlsplt = 1; - break; - - case R_FRV_TLSDESC_VALUE: - picrel->relocstlsd++; - goto bad_reloc; - - case R_FRV_GOTTLSDESC12: - picrel->tlsdesc12 = 1; - break; - - case R_FRV_GOTTLSDESCHI: - case R_FRV_GOTTLSDESCLO: - picrel->tlsdeschilo = 1; - break; - - case R_FRV_TLSMOFF12: - case R_FRV_TLSMOFFHI: - case R_FRV_TLSMOFFLO: - case R_FRV_TLSMOFF: - break; - - case R_FRV_GOTTLSOFF12: - picrel->tlsoff12 = 1; - info->flags |= DF_STATIC_TLS; - break; - - case R_FRV_GOTTLSOFFHI: - case R_FRV_GOTTLSOFFLO: - picrel->tlsoffhilo = 1; - info->flags |= DF_STATIC_TLS; - break; - - case R_FRV_TLSOFF: - picrel->relocstlsoff++; - info->flags |= DF_STATIC_TLS; - goto bad_reloc; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_FRV_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_FRV_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_FRV_LABEL16: - case R_FRV_LO16: - case R_FRV_HI16: - case R_FRV_GPREL12: - case R_FRV_GPRELU12: - case R_FRV_GPREL32: - case R_FRV_GPRELHI: - case R_FRV_GPRELLO: - case R_FRV_TLSDESC_RELAX: - case R_FRV_GETTLSOFF_RELAX: - case R_FRV_TLSOFF_RELAX: - break; - - default: - bad_reloc: - info->callbacks->einfo - /* xgettext:c-format */ - (_("%B: unsupported relocation type %i\n"), - abfd, ELF32_R_TYPE (rel->r_info)); - return FALSE; - } - } - - return TRUE; -} - - -/* Return the machine subcode from the ELF e_flags header. */ - -static int -elf32_frv_machine (bfd *abfd) -{ - switch (elf_elfheader (abfd)->e_flags & EF_FRV_CPU_MASK) - { - default: break; - case EF_FRV_CPU_FR550: return bfd_mach_fr550; - case EF_FRV_CPU_FR500: return bfd_mach_fr500; - case EF_FRV_CPU_FR450: return bfd_mach_fr450; - case EF_FRV_CPU_FR405: return bfd_mach_fr400; - case EF_FRV_CPU_FR400: return bfd_mach_fr400; - case EF_FRV_CPU_FR300: return bfd_mach_fr300; - case EF_FRV_CPU_SIMPLE: return bfd_mach_frvsimple; - case EF_FRV_CPU_TOMCAT: return bfd_mach_frvtomcat; - } - - return bfd_mach_frv; -} - -/* Set the right machine number for a FRV ELF file. */ - -static bfd_boolean -elf32_frv_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_frv, elf32_frv_machine (abfd)); - return (((elf_elfheader (abfd)->e_flags & EF_FRV_FDPIC) != 0) - == (IS_FDPIC (abfd))); -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -frv_elf_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Return true if the architecture described by elf header flag - EXTENSION is an extension of the architecture described by BASE. */ - -static bfd_boolean -frv_elf_arch_extension_p (flagword base, flagword extension) -{ - if (base == extension) - return TRUE; - - /* CPU_GENERIC code can be merged with code for a specific - architecture, in which case the result is marked as being - for the specific architecture. Everything is therefore - an extension of CPU_GENERIC. */ - if (base == EF_FRV_CPU_GENERIC) - return TRUE; - - if (extension == EF_FRV_CPU_FR450) - if (base == EF_FRV_CPU_FR400 || base == EF_FRV_CPU_FR405) - return TRUE; - - if (extension == EF_FRV_CPU_FR405) - if (base == EF_FRV_CPU_FR400) - return TRUE; - - return FALSE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -frv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, old_partial; - flagword new_flags, new_partial; - bfd_boolean error = FALSE; - char new_opt[80]; - char old_opt[80]; - - new_opt[0] = old_opt[0] = '\0'; - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (new_flags & EF_FRV_FDPIC) - new_flags &= ~EF_FRV_PIC; - -#ifdef DEBUG - _bfd_error_handler - ("old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s, filename = %s", - old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no", - bfd_get_filename (ibfd)); -#endif - - if (!elf_flags_init (obfd)) /* First call, no flags set. */ - { - elf_flags_init (obfd) = TRUE; - old_flags = new_flags; - } - - else if (new_flags == old_flags) /* Compatible flags are ok. */ - ; - - else /* Possibly incompatible flags. */ - { - /* Warn if different # of gprs are used. Note, 0 means nothing is - said about the size of gprs. */ - new_partial = (new_flags & EF_FRV_GPR_MASK); - old_partial = (old_flags & EF_FRV_GPR_MASK); - if (new_partial == old_partial) - ; - - else if (new_partial == 0) - ; - - else if (old_partial == 0) - old_flags |= new_partial; - - else - { - switch (new_partial) - { - default: strcat (new_opt, " -mgpr-??"); break; - case EF_FRV_GPR_32: strcat (new_opt, " -mgpr-32"); break; - case EF_FRV_GPR_64: strcat (new_opt, " -mgpr-64"); break; - } - - switch (old_partial) - { - default: strcat (old_opt, " -mgpr-??"); break; - case EF_FRV_GPR_32: strcat (old_opt, " -mgpr-32"); break; - case EF_FRV_GPR_64: strcat (old_opt, " -mgpr-64"); break; - } - } - - /* Warn if different # of fprs are used. Note, 0 means nothing is - said about the size of fprs. */ - new_partial = (new_flags & EF_FRV_FPR_MASK); - old_partial = (old_flags & EF_FRV_FPR_MASK); - if (new_partial == old_partial) - ; - - else if (new_partial == 0) - ; - - else if (old_partial == 0) - old_flags |= new_partial; - - else - { - switch (new_partial) - { - default: strcat (new_opt, " -mfpr-?"); break; - case EF_FRV_FPR_32: strcat (new_opt, " -mfpr-32"); break; - case EF_FRV_FPR_64: strcat (new_opt, " -mfpr-64"); break; - case EF_FRV_FPR_NONE: strcat (new_opt, " -msoft-float"); break; - } - - switch (old_partial) - { - default: strcat (old_opt, " -mfpr-?"); break; - case EF_FRV_FPR_32: strcat (old_opt, " -mfpr-32"); break; - case EF_FRV_FPR_64: strcat (old_opt, " -mfpr-64"); break; - case EF_FRV_FPR_NONE: strcat (old_opt, " -msoft-float"); break; - } - } - - /* Warn if different dword support was used. Note, 0 means nothing is - said about the dword support. */ - new_partial = (new_flags & EF_FRV_DWORD_MASK); - old_partial = (old_flags & EF_FRV_DWORD_MASK); - if (new_partial == old_partial) - ; - - else if (new_partial == 0) - ; - - else if (old_partial == 0) - old_flags |= new_partial; - - else - { - switch (new_partial) - { - default: strcat (new_opt, " -mdword-?"); break; - case EF_FRV_DWORD_YES: strcat (new_opt, " -mdword"); break; - case EF_FRV_DWORD_NO: strcat (new_opt, " -mno-dword"); break; - } - - switch (old_partial) - { - default: strcat (old_opt, " -mdword-?"); break; - case EF_FRV_DWORD_YES: strcat (old_opt, " -mdword"); break; - case EF_FRV_DWORD_NO: strcat (old_opt, " -mno-dword"); break; - } - } - - /* Or in flags that accumulate (ie, if one module uses it, mark that the - feature is used. */ - old_flags |= new_flags & (EF_FRV_DOUBLE - | EF_FRV_MEDIA - | EF_FRV_MULADD - | EF_FRV_NON_PIC_RELOCS); - - /* If any module was compiled without -G0, clear the G0 bit. */ - old_flags = ((old_flags & ~ EF_FRV_G0) - | (old_flags & new_flags & EF_FRV_G0)); - - /* If any module was compiled without -mnopack, clear the mnopack bit. */ - old_flags = ((old_flags & ~ EF_FRV_NOPACK) - | (old_flags & new_flags & EF_FRV_NOPACK)); - - /* We don't have to do anything if the pic flags are the same, or the new - module(s) were compiled with -mlibrary-pic. */ - new_partial = (new_flags & EF_FRV_PIC_FLAGS); - old_partial = (old_flags & EF_FRV_PIC_FLAGS); - if ((new_partial == old_partial) || ((new_partial & EF_FRV_LIBPIC) != 0)) - ; - - /* If the old module(s) were compiled with -mlibrary-pic, copy in the pic - flags if any from the new module. */ - else if ((old_partial & EF_FRV_LIBPIC) != 0) - old_flags = (old_flags & ~ EF_FRV_PIC_FLAGS) | new_partial; - - /* If we have mixtures of -fpic and -fPIC, or in both bits. */ - else if (new_partial != 0 && old_partial != 0) - old_flags |= new_partial; - - /* One module was compiled for pic and the other was not, see if we have - had any relocations that are not pic-safe. */ - else - { - if ((old_flags & EF_FRV_NON_PIC_RELOCS) == 0) - old_flags |= new_partial; - else - { - old_flags &= ~ EF_FRV_PIC_FLAGS; -#ifndef FRV_NO_PIC_ERROR - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: compiled with %s and linked with modules" - " that use non-pic relocations"), - ibfd, (new_flags & EF_FRV_BIGPIC) ? "-fPIC" : "-fpic"); -#endif - } - } - - /* Warn if different cpu is used (allow a specific cpu to override - the generic cpu). */ - new_partial = (new_flags & EF_FRV_CPU_MASK); - old_partial = (old_flags & EF_FRV_CPU_MASK); - if (frv_elf_arch_extension_p (new_partial, old_partial)) - ; - - else if (frv_elf_arch_extension_p (old_partial, new_partial)) - old_flags = (old_flags & ~EF_FRV_CPU_MASK) | new_partial; - - else - { - switch (new_partial) - { - default: strcat (new_opt, " -mcpu=?"); break; - case EF_FRV_CPU_GENERIC: strcat (new_opt, " -mcpu=frv"); break; - case EF_FRV_CPU_SIMPLE: strcat (new_opt, " -mcpu=simple"); break; - case EF_FRV_CPU_FR550: strcat (new_opt, " -mcpu=fr550"); break; - case EF_FRV_CPU_FR500: strcat (new_opt, " -mcpu=fr500"); break; - case EF_FRV_CPU_FR450: strcat (new_opt, " -mcpu=fr450"); break; - case EF_FRV_CPU_FR405: strcat (new_opt, " -mcpu=fr405"); break; - case EF_FRV_CPU_FR400: strcat (new_opt, " -mcpu=fr400"); break; - case EF_FRV_CPU_FR300: strcat (new_opt, " -mcpu=fr300"); break; - case EF_FRV_CPU_TOMCAT: strcat (new_opt, " -mcpu=tomcat"); break; - } - - switch (old_partial) - { - default: strcat (old_opt, " -mcpu=?"); break; - case EF_FRV_CPU_GENERIC: strcat (old_opt, " -mcpu=frv"); break; - case EF_FRV_CPU_SIMPLE: strcat (old_opt, " -mcpu=simple"); break; - case EF_FRV_CPU_FR550: strcat (old_opt, " -mcpu=fr550"); break; - case EF_FRV_CPU_FR500: strcat (old_opt, " -mcpu=fr500"); break; - case EF_FRV_CPU_FR450: strcat (old_opt, " -mcpu=fr450"); break; - case EF_FRV_CPU_FR405: strcat (old_opt, " -mcpu=fr405"); break; - case EF_FRV_CPU_FR400: strcat (old_opt, " -mcpu=fr400"); break; - case EF_FRV_CPU_FR300: strcat (old_opt, " -mcpu=fr300"); break; - case EF_FRV_CPU_TOMCAT: strcat (old_opt, " -mcpu=tomcat"); break; - } - } - - /* Print out any mismatches from above. */ - if (new_opt[0]) - { - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: compiled with %s and linked with modules compiled with %s"), - ibfd, new_opt, old_opt); - } - - /* Warn about any other mismatches */ - new_partial = (new_flags & ~ EF_FRV_ALL_FLAGS); - old_partial = (old_flags & ~ EF_FRV_ALL_FLAGS); - if (new_partial != old_partial) - { - old_flags |= new_partial; - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different unknown e_flags (%#x) fields" - " than previous modules (%#x)"), - ibfd, new_partial, old_partial); - } - } - - /* If the cpu is -mcpu=simple, then set the -mnopack bit. */ - if ((old_flags & EF_FRV_CPU_MASK) == EF_FRV_CPU_SIMPLE) - old_flags |= EF_FRV_NOPACK; - - /* Update the old flags now with changes made above. */ - old_partial = elf_elfheader (obfd)->e_flags & EF_FRV_CPU_MASK; - elf_elfheader (obfd)->e_flags = old_flags; - if (old_partial != (old_flags & EF_FRV_CPU_MASK)) - bfd_default_set_arch_mach (obfd, bfd_arch_frv, elf32_frv_machine (obfd)); - - if (((new_flags & EF_FRV_FDPIC) == 0) - != (! IS_FDPIC (ibfd))) - { - error = TRUE; - if (IS_FDPIC (obfd)) - _bfd_error_handler - (_("%B: cannot link non-fdpic object file into fdpic executable"), - ibfd); - else - _bfd_error_handler - (_("%B: cannot link fdpic object file into non-fdpic executable"), - ibfd); - } - - if (error) - bfd_set_error (bfd_error_bad_value); - - return !error; -} - - -static bfd_boolean -frv_elf_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (unsigned long) flags); - - switch (flags & EF_FRV_CPU_MASK) - { - default: break; - case EF_FRV_CPU_SIMPLE: fprintf (file, " -mcpu=simple"); break; - case EF_FRV_CPU_FR550: fprintf (file, " -mcpu=fr550"); break; - case EF_FRV_CPU_FR500: fprintf (file, " -mcpu=fr500"); break; - case EF_FRV_CPU_FR450: fprintf (file, " -mcpu=fr450"); break; - case EF_FRV_CPU_FR405: fprintf (file, " -mcpu=fr405"); break; - case EF_FRV_CPU_FR400: fprintf (file, " -mcpu=fr400"); break; - case EF_FRV_CPU_FR300: fprintf (file, " -mcpu=fr300"); break; - case EF_FRV_CPU_TOMCAT: fprintf (file, " -mcpu=tomcat"); break; - } - - switch (flags & EF_FRV_GPR_MASK) - { - default: break; - case EF_FRV_GPR_32: fprintf (file, " -mgpr-32"); break; - case EF_FRV_GPR_64: fprintf (file, " -mgpr-64"); break; - } - - switch (flags & EF_FRV_FPR_MASK) - { - default: break; - case EF_FRV_FPR_32: fprintf (file, " -mfpr-32"); break; - case EF_FRV_FPR_64: fprintf (file, " -mfpr-64"); break; - case EF_FRV_FPR_NONE: fprintf (file, " -msoft-float"); break; - } - - switch (flags & EF_FRV_DWORD_MASK) - { - default: break; - case EF_FRV_DWORD_YES: fprintf (file, " -mdword"); break; - case EF_FRV_DWORD_NO: fprintf (file, " -mno-dword"); break; - } - - if (flags & EF_FRV_DOUBLE) - fprintf (file, " -mdouble"); - - if (flags & EF_FRV_MEDIA) - fprintf (file, " -mmedia"); - - if (flags & EF_FRV_MULADD) - fprintf (file, " -mmuladd"); - - if (flags & EF_FRV_PIC) - fprintf (file, " -fpic"); - - if (flags & EF_FRV_BIGPIC) - fprintf (file, " -fPIC"); - - if (flags & EF_FRV_LIBPIC) - fprintf (file, " -mlibrary-pic"); - - if (flags & EF_FRV_FDPIC) - fprintf (file, " -mfdpic"); - - if (flags & EF_FRV_NON_PIC_RELOCS) - fprintf (file, " non-pic relocations"); - - if (flags & EF_FRV_G0) - fprintf (file, " -G0"); - - fputc ('\n', file); - return TRUE; -} - - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf32_frv_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int raw_size; - - switch (note->descsz) - { - default: - return FALSE; - - /* The Linux/FRV elf_prstatus struct is 268 bytes long. The other - hardcoded offsets and sizes listed below (and contained within - this lexical block) refer to fields in the target's elf_prstatus - struct. */ - case 268: - /* `pr_cursig' is at offset 12. */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* `pr_pid' is at offset 24. */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* `pr_reg' is at offset 72. */ - offset = 72; - - /* Most grok_prstatus implementations set `raw_size' to the size - of the pr_reg field. For Linux/FRV, we set `raw_size' to be - the size of `pr_reg' plus the size of `pr_exec_fdpic_loadmap' - and `pr_interp_fdpic_loadmap', both of which (by design) - immediately follow `pr_reg'. This will allow these fields to - be viewed by GDB as registers. - - `pr_reg' is 184 bytes long. `pr_exec_fdpic_loadmap' and - `pr_interp_fdpic_loadmap' are 4 bytes each. */ - raw_size = 184 + 4 + 4; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, - note->descpos + offset); -} - -static bfd_boolean -elf32_frv_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - /* The Linux/FRV elf_prpsinfo struct is 124 bytes long. */ - case 124: - - /* `pr_fname' is found at offset 28 and is 16 bytes long. */ - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); - - /* `pr_psargs' is found at offset 44 and is 80 bytes long. */ - 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; -} -#define ELF_ARCH bfd_arch_frv -#define ELF_MACHINE_CODE EM_CYGNUS_FRV -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM frv_elf32_vec -#define TARGET_BIG_NAME "elf32-frv" - -#define elf_info_to_howto frv_info_to_howto_rela -#define elf_backend_relocate_section elf32_frv_relocate_section -#define elf_backend_gc_mark_hook elf32_frv_gc_mark_hook -#define elf_backend_check_relocs elf32_frv_check_relocs -#define elf_backend_object_p elf32_frv_object_p -#define elf_backend_add_symbol_hook elf32_frv_add_symbol_hook - -#define elf_backend_stack_align 8 -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_reloc_type_lookup frv_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup frv_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags frv_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data frv_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data frv_elf_print_private_bfd_data - -#define elf_backend_want_got_sym 1 -#define elf_backend_got_header_size 0 -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_plt_header_size 0 - -#define elf_backend_finish_dynamic_sections \ - elf32_frv_finish_dynamic_sections - -#define elf_backend_grok_prstatus elf32_frv_grok_prstatus -#define elf_backend_grok_psinfo elf32_frv_grok_psinfo - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" - -#undef ELF_TARGET_ID -#define ELF_TARGET_ID FRV_ELF_DATA -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x4000 - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM frv_elf32_fdpic_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-frvfdpic" -#undef elf32_bed -#define elf32_bed elf32_frvfdpic_bed - -#undef elf_info_to_howto_rel -#define elf_info_to_howto_rel frvfdpic_info_to_howto_rel - -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create \ - frvfdpic_elf_link_hash_table_create -#undef elf_backend_always_size_sections -#define elf_backend_always_size_sections \ - elf32_frvfdpic_always_size_sections - -#undef elf_backend_create_dynamic_sections -#define elf_backend_create_dynamic_sections \ - elf32_frvfdpic_create_dynamic_sections -#undef elf_backend_adjust_dynamic_symbol -#define elf_backend_adjust_dynamic_symbol \ - elf32_frvfdpic_adjust_dynamic_symbol -#undef elf_backend_size_dynamic_sections -#define elf_backend_size_dynamic_sections \ - elf32_frvfdpic_size_dynamic_sections -#undef bfd_elf32_bfd_relax_section -#define bfd_elf32_bfd_relax_section \ - elf32_frvfdpic_relax_section -#undef elf_backend_finish_dynamic_symbol -#define elf_backend_finish_dynamic_symbol \ - elf32_frvfdpic_finish_dynamic_symbol -#undef elf_backend_finish_dynamic_sections -#define elf_backend_finish_dynamic_sections \ - elf32_frvfdpic_finish_dynamic_sections - -#undef elf_backend_discard_info -#define elf_backend_discard_info \ - frvfdpic_elf_discard_info -#undef elf_backend_can_make_relative_eh_frame -#define elf_backend_can_make_relative_eh_frame \ - frvfdpic_elf_use_relative_eh_frame -#undef elf_backend_can_make_lsda_relative_eh_frame -#define elf_backend_can_make_lsda_relative_eh_frame \ - frvfdpic_elf_use_relative_eh_frame -#undef elf_backend_encode_eh_address -#define elf_backend_encode_eh_address \ - frvfdpic_elf_encode_eh_address - -#undef elf_backend_may_use_rel_p -#define elf_backend_may_use_rel_p 1 -#undef elf_backend_may_use_rela_p -#define elf_backend_may_use_rela_p 1 -/* We use REL for dynamic relocations only. */ -#undef elf_backend_default_use_rela_p -#define elf_backend_default_use_rela_p 1 - -#undef elf_backend_omit_section_dynsym -#define elf_backend_omit_section_dynsym _frvfdpic_link_omit_section_dynsym - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-ft32.c b/sdcc/support/sdbinutils/bfd/elf32-ft32.c deleted file mode 100644 index 86157d86b..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-ft32.c +++ /dev/null @@ -1,1256 +0,0 @@ -/* ft32-specific support for 32-bit ELF. - Copyright (C) 2013-2018 Free Software Foundation, Inc. - - Copied from elf32-moxie.c which is.. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/ft32.h" -#include "opcode/ft32.h" - -static bfd_boolean debug_relax = FALSE; - -static bfd_reloc_status_type -bfd_elf_ft32_diff_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -static reloc_howto_type ft32_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_FT32_NONE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - - HOWTO (R_FT32_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_16", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_8", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_10, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_10", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00003ff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_20", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_17, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_17", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0001ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_18, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_18", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0003ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_RELAX, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_RELAX", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_FT32_SC0, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_SC0", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_FT32_SC1, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 22, /* bitsize */ - TRUE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_SC1", /* name */ - TRUE, /* partial_inplace */ - 0x07ffff80, /* src_mask */ - 0x07ffff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_FT32_15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_FT32_15", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_FT32_DIFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_ft32_diff_reloc, /* special_function */ - "R_FT32_DIFF32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - - -/* Map BFD reloc types to FT32 ELF reloc types. */ - -struct ft32_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int ft32_reloc_val; -}; - -static const struct ft32_reloc_map ft32_reloc_map [] = -{ - { BFD_RELOC_NONE, R_FT32_NONE }, - { BFD_RELOC_32, R_FT32_32 }, - { BFD_RELOC_16, R_FT32_16 }, - { BFD_RELOC_8, R_FT32_8 }, - { BFD_RELOC_FT32_10, R_FT32_10 }, - { BFD_RELOC_FT32_20, R_FT32_20 }, - { BFD_RELOC_FT32_17, R_FT32_17 }, - { BFD_RELOC_FT32_18, R_FT32_18 }, - { BFD_RELOC_FT32_RELAX, R_FT32_RELAX }, - { BFD_RELOC_FT32_SC0, R_FT32_SC0 }, - { BFD_RELOC_FT32_SC1, R_FT32_SC1 }, - { BFD_RELOC_FT32_15, R_FT32_15 }, - { BFD_RELOC_FT32_DIFF32, R_FT32_DIFF32 }, -}; - -/* Perform a diff relocation. Nothing to do, as the difference value is - already written into the section's contents. */ - -static bfd_reloc_status_type -bfd_elf_ft32_diff_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - return bfd_reloc_ok; -} - -static reloc_howto_type * -ft32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = sizeof (ft32_reloc_map) / sizeof (ft32_reloc_map[0]); - --i;) - if (ft32_reloc_map [i].bfd_reloc_val == code) - return & ft32_elf_howto_table [ft32_reloc_map[i].ft32_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -ft32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (ft32_elf_howto_table) / sizeof (ft32_elf_howto_table[0]); - i++) - if (ft32_elf_howto_table[i].name != NULL - && strcasecmp (ft32_elf_howto_table[i].name, r_name) == 0) - return &ft32_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an FT32 ELF reloc. */ - -static void -ft32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - BFD_ASSERT (r_type < (unsigned int) R_FT32_max); - cache_ptr->howto = & ft32_elf_howto_table [r_type]; -} - -/* Relocate an FT32 ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -ft32_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - howto = ft32_elf_howto_table + r_type; - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (howto->type) - { - case R_FT32_SC0: - { - unsigned int insn; - int offset; - unsigned int code15[2]; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - ft32_split_shortcode (insn, code15); - - offset = (int)relocation; - offset += (int)(rel->r_addend - rel->r_offset); - offset -= (input_section->output_section->vma + - input_section->output_offset); - if ((offset < -1024) || (offset >= 1024)) - { - r = bfd_reloc_outofrange; - break; - } - code15[0] |= ((offset / 4) & 511); - insn = ft32_merge_shortcode (code15); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - r = bfd_reloc_ok; - break; - - case R_FT32_SC1: - { - unsigned int insn; - int offset; - unsigned int code15[2]; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - ft32_split_shortcode (insn, code15); - - offset = (int)relocation; - offset += (int)(rel->r_addend - rel->r_offset); - offset -= (input_section->output_section->vma + - input_section->output_offset); - if ((offset < -1024) || (offset >= 1024)) - { - r = bfd_reloc_outofrange; - break; - } - code15[1] |= ((offset / 4) & 511); - insn = ft32_merge_shortcode (code15); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - r = bfd_reloc_ok; - break; - - case R_FT32_DIFF32: - r = bfd_reloc_ok; - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Relaxation. */ - -static bfd_boolean -ft32_reloc_shortable - (bfd * abfd, - asection * sec, - Elf_Internal_Sym * isymbuf ATTRIBUTE_UNUSED, - bfd_byte * contents, - bfd_vma pc ATTRIBUTE_UNUSED, - Elf_Internal_Rela * irel, - unsigned int * sc) -{ - Elf_Internal_Shdr *symtab_hdr ATTRIBUTE_UNUSED; - bfd_vma symval; - - enum elf_ft32_reloc_type r_type; - reloc_howto_type *howto = NULL; - unsigned int insn; - int offset; - bfd_vma dot, value; - - r_type = ELF32_R_TYPE (irel->r_info); - howto = &ft32_elf_howto_table [r_type]; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec) - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - return FALSE; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - switch (r_type) - { - case R_FT32_8: - case R_FT32_10: - case R_FT32_16: - case R_FT32_20: - case R_FT32_RELAX: - if (symval != 0) - return FALSE; - insn = bfd_get_32 (abfd, contents + irel->r_offset); - insn |= ((symval + irel->r_addend) << howto->bitpos) & howto->dst_mask; - return ft32_shortcode (insn, sc); - - case R_FT32_18: - insn = bfd_get_32 (abfd, contents + irel->r_offset); - /* Get the address of this instruction. */ - dot = (sec->output_section->vma - + sec->output_offset + irel->r_offset); - value = symval + irel->r_addend; - offset = (value - dot) / 4; - - if ((dot > 0x8c) && (-256 <= offset) && (offset < 256)) - { - switch (insn) - { - case 0x00200000: *sc = (3 << 13) | (0 << 9); return TRUE; - case 0x00280000: *sc = (3 << 13) | (1 << 9); return TRUE; - case 0x00600000: *sc = (3 << 13) | (2 << 9); return TRUE; - case 0x00680000: *sc = (3 << 13) | (3 << 9); return TRUE; - case 0x00a00000: *sc = (3 << 13) | (4 << 9); return TRUE; - case 0x00a80000: *sc = (3 << 13) | (5 << 9); return TRUE; - case 0x00e00000: *sc = (3 << 13) | (6 << 9); return TRUE; - case 0x00e80000: *sc = (3 << 13) | (7 << 9); return TRUE; - case 0x01200000: *sc = (3 << 13) | (8 << 9); return TRUE; - case 0x01280000: *sc = (3 << 13) | (9 << 9); return TRUE; - case 0x01600000: *sc = (3 << 13) | (10 << 9); return TRUE; - case 0x01680000: *sc = (3 << 13) | (11 << 9); return TRUE; - case 0x01a00000: *sc = (3 << 13) | (12 << 9); return TRUE; - case 0x01a80000: *sc = (3 << 13) | (13 << 9); return TRUE; - - case 0x00300000: *sc = (3 << 13) | (14 << 9); return TRUE; - case 0x00340000: *sc = (3 << 13) | (15 << 9); return TRUE; - - default: - break; - } - } - break; - - default: - break; - } - return FALSE; -} - -/* Returns whether the relocation type passed is a diff reloc. */ - -static bfd_boolean -elf32_ft32_is_diff_reloc (Elf_Internal_Rela *irel) -{ - return (ELF32_R_TYPE (irel->r_info) == R_FT32_DIFF32); -} - -/* Reduce the diff value written in the section by count if the shrinked - insn address happens to fall between the two symbols for which this - diff reloc was emitted. */ - -static bfd_boolean -elf32_ft32_adjust_diff_reloc_value (bfd *abfd, - struct bfd_section *isec, - Elf_Internal_Rela *irel, - bfd_vma symval, - bfd_vma shrinked_insn_address, - int count) -{ - unsigned char * reloc_contents = NULL; - unsigned char * isec_contents = elf_section_data (isec)->this_hdr.contents; - bfd_signed_vma x = 0; - bfd_vma sym2_address; - bfd_vma sym1_address; - bfd_vma start_address; - bfd_vma end_address; - - - if (isec_contents == NULL) - { - if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents)) - return FALSE; - - elf_section_data (isec)->this_hdr.contents = isec_contents; - } - - reloc_contents = isec_contents + irel->r_offset; - - /* Read value written in object file. */ - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_FT32_DIFF32: - x = bfd_get_signed_32 (abfd, reloc_contents); - break; - - default: - return FALSE; - } - - /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written - into the object file at the reloc offset. sym2's logical value is - symval () + reloc addend. Compute the start and end - addresses and check if the shrinked insn falls between sym1 and sym2. */ - sym2_address = symval + irel->r_addend; - sym1_address = sym2_address - x; - - /* Don't assume sym2 is bigger than sym1 - the difference - could be negative. Compute start and end addresses, and - use those to see if they span shrinked_insn_address. */ - start_address = sym1_address < sym2_address ? sym1_address : sym2_address; - end_address = sym1_address > sym2_address ? sym1_address : sym2_address; - - if (shrinked_insn_address >= start_address - && shrinked_insn_address < end_address) - { - /* Reduce the diff value by count bytes and write it back into section - contents. */ - bfd_signed_vma new_diff = x < 0 ? x + count : x - count; - - if (sym2_address > shrinked_insn_address) - irel->r_addend -= count; - - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_FT32_DIFF32: - bfd_put_signed_32 (abfd, new_diff & 0xFFFFFFFF, reloc_contents); - break; - - default: - return FALSE; - } - } - - return TRUE; -} - -static bfd_boolean -elf32_ft32_adjust_reloc_if_spans_insn (bfd *abfd, - asection *isec, - Elf_Internal_Rela *irel, bfd_vma symval, - bfd_vma shrinked_insn_address, - bfd_vma shrink_boundary, - int count) -{ - - if (elf32_ft32_is_diff_reloc (irel)) - { - if (!elf32_ft32_adjust_diff_reloc_value (abfd, isec, irel, - symval, - shrinked_insn_address, - count)) - return FALSE; - } - else - { - bfd_vma reloc_value = symval + irel->r_addend; - bfd_boolean addend_within_shrink_boundary = - (reloc_value <= shrink_boundary); - bfd_boolean reloc_spans_insn = - (symval <= shrinked_insn_address - && reloc_value > shrinked_insn_address - && addend_within_shrink_boundary); - - if (! reloc_spans_insn) - return TRUE; - - irel->r_addend -= count; - - if (debug_relax) - printf ("Relocation's addend needed to be fixed \n"); - } - return TRUE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -elf32_ft32_relax_delete_bytes (struct bfd_link_info *link_info, bfd * abfd, - asection * sec, bfd_vma addr, int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - struct elf_link_hash_entry **start_hashes; - unsigned int symcount; - Elf_Internal_Sym *isymbuf = NULL; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - /* Get the new reloc address. */ - if ((irel->r_offset > addr && irel->r_offset < toaddr)) - irel->r_offset -= count; - - /* The reloc's own addresses are now ok. However, we need to readjust - the reloc's addend, i.e. the reloc's value if two conditions are met: - 1.) the reloc is relative to a symbol in this section that - is located in front of the shrinked instruction - 2.) symbol plus addend end up behind the shrinked instruction. - - The most common case where this happens are relocs relative to - the section-start symbol. - - This step needs to be done for all of the sections of the bfd. */ - { - struct bfd_section *isec; - - for (isec = abfd->sections; isec; isec = isec->next) - { - bfd_vma symval; - bfd_vma shrinked_insn_address; - - if (isec->reloc_count == 0) - continue; - - shrinked_insn_address = (sec->output_section->vma - + sec->output_offset + addr - count); - - irel = elf_section_data (isec)->relocs; - /* PR 12161: Read in the relocs for this section if necessary. */ - if (irel == NULL) - irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); - - for (irelend = irel + isec->reloc_count; irel < irelend; irel++) - { - /* Read this BFD's local symbols if we haven't done - so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec == sec) - { - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - - if (debug_relax) - printf ("Checking if the relocation's " - "addend needs corrections.\n" - "Address of anchor symbol: 0x%x \n" - "Address of relocation target: 0x%x \n" - "Address of relaxed insn: 0x%x \n", - (unsigned int) symval, - (unsigned int) (symval + irel->r_addend), - (unsigned int) shrinked_insn_address); - - if (symval <= shrinked_insn_address - && (symval + irel->r_addend) > shrinked_insn_address) - { - /* If there is an alignment boundary, we only need to - adjust addends that end up below the boundary. */ - bfd_vma shrink_boundary = (toaddr - + sec->output_section->vma - + sec->output_offset); - - if (debug_relax) - printf - ("Relocation's addend needed to be fixed \n"); - - if (!elf32_ft32_adjust_reloc_if_spans_insn (abfd, isec, - irel, symval, - shrinked_insn_address, - shrink_boundary, - count)) - return FALSE; - } - } - /* else reference symbol is absolute. No adjustment needed. */ - } - /* else...Reference symbol is extern. No need for adjusting - the addend. */ - } - } - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isym) - { - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr && isym->st_value < toaddr) - isym->st_value -= count; - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = start_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - /* The '--wrap SYMBOL' option is causing a pain when the object file, - containing the definition of __wrap_SYMBOL, includes a direct - call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference - the same symbol (which is __wrap_SYMBOL), but still exist as two - different symbols in 'sym_hashes', we don't want to adjust - the global symbol __wrap_SYMBOL twice. - This check is only relevant when symbols are being wrapped. */ - if (link_info->wrap_hash != NULL) - { - struct elf_link_hash_entry **cur_sym_hashes; - - /* Loop only over the symbols whom been already checked. */ - for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; - cur_sym_hashes++) - /* If the current symbol is identical to 'sym_hash', that means - the symbol was already adjusted (or at least checked). */ - if (*cur_sym_hashes == sym_hash) - break; - - /* Don't adjust the symbol again. */ - if (cur_sym_hashes < sym_hashes) - continue; - } - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; - } - - return TRUE; -} - -/* Return TRUE if LOC can be a target of a branch, jump or call. */ - -static bfd_boolean -elf32_ft32_relax_is_branch_target (struct bfd_link_info *link_info, - bfd * abfd, asection * sec, - bfd_vma loc) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymbuf = NULL; - bfd_vma symval; - struct bfd_section *isec; - - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - struct elf_link_hash_entry **start_hashes; - unsigned int symcount; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Now we check for relocations pointing to ret. */ - for (isec = abfd->sections; isec; isec = isec->next) - { - irel = elf_section_data (isec)->relocs; - if (irel == NULL) - irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); - - irelend = irel + isec->reloc_count; - - for (; irel < irelend; irel++) - { - /* Read this BFD's local symbols if we haven't done - so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec == sec) - { - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - - if (debug_relax) - printf ("0x%x: Address of anchor symbol: 0x%x " - "Address of relocation target: 0x%x \n", - (unsigned int) irel->r_offset, - (unsigned int) symval, - (unsigned int) (symval + irel->r_addend)); - if ((irel->r_addend) == loc) - return TRUE; - } - } - } - } - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = start_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - /* The '--wrap SYMBOL' option is causing a pain when the object file, - containing the definition of __wrap_SYMBOL, includes a direct - call to SYMBOL as well. Since both __wrap_SYMBOL and SYMBOL reference - the same symbol (which is __wrap_SYMBOL), but still exist as two - different symbols in 'sym_hashes', we don't want to adjust - the global symbol __wrap_SYMBOL twice. - This check is only relevant when symbols are being wrapped. */ - if (link_info->wrap_hash != NULL) - { - struct elf_link_hash_entry **cur_sym_hashes; - - /* Loop only over the symbols whom been already checked. */ - for (cur_sym_hashes = start_hashes; cur_sym_hashes < sym_hashes; - cur_sym_hashes++) - /* If the current symbol is identical to 'sym_hash', that means - the symbol was already adjusted (or at least checked). */ - if (*cur_sym_hashes == sym_hash) - break; - - /* Don't adjust the symbol again. */ - if (cur_sym_hashes < sym_hashes) - continue; - } - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == loc) - return TRUE; - } - - return FALSE; -} - -static bfd_boolean -ft32_elf_relax_section - (bfd * abfd, - asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - Elf_Internal_Rela * free_relocs = NULL; - Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * irelend; - Elf_Internal_Rela * irel; - bfd_byte * contents = NULL; - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Sym * isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else - { - if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - elf_section_data (sec)->this_hdr.contents = contents; - } - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - symtab_hdr->contents = (unsigned char *) isymbuf; - } - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - if (! link_info->keep_memory) - free_relocs = internal_relocs; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - - /* Test every adjacent pair of relocs. If both have shortcodes, - fuse them and delete the relocs. */ - irel = internal_relocs; - while (irel < irelend - 1) - { - Elf_Internal_Rela * irel_next = irel + 1; - unsigned int sc0, sc1; - bfd_vma pc; - - pc = irel->r_offset; - - if (((pc + 4) == (irel_next->r_offset)) - && ft32_reloc_shortable (abfd, sec, isymbuf, contents, pc, irel, - &sc0) - && ft32_reloc_shortable (abfd, sec, isymbuf, contents, pc, - irel_next, &sc1) - && !elf32_ft32_relax_is_branch_target (link_info, abfd, sec, - irel_next->r_offset)) - { - unsigned int code30 = (sc1 << 15) | sc0; - unsigned int code27 = code30 >> 3; - unsigned int code3 = code30 & 7; - static const unsigned char pat3[] = {2, 3, 4, 5, 6, 9, 10, 14}; - unsigned int pattern = pat3[code3]; - unsigned int fused = (pattern << 27) | code27; - - /* Move second reloc to same place as first. */ - irel_next->r_offset = irel->r_offset; - - /* Change both relocs to R_FT32_NONE. */ - - if (ELF32_R_TYPE (irel->r_info) == R_FT32_18) - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_FT32_SC0); - } - else - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_FT32_NONE); - } - - if (ELF32_R_TYPE (irel_next->r_info) == R_FT32_18) - { - irel_next->r_info = ELF32_R_INFO (ELF32_R_SYM (irel_next->r_info), - R_FT32_SC1); - } - else - { - irel_next->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_FT32_NONE); - } - - /* Replace the first insn with the fused version. */ - bfd_put_32 (abfd, fused, contents + irel->r_offset); - - /* Delete the second insn. */ - if (!elf32_ft32_relax_delete_bytes (link_info, abfd, sec, - irel->r_offset + 4, 4)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - - irel += 2; - } - else - { - irel += 1; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (free_relocs != NULL) - free (free_relocs); - - return TRUE; -} - -#define ELF_ARCH bfd_arch_ft32 -#define ELF_MACHINE_CODE EM_FT32 -#define ELF_MAXPAGESIZE 0x1 - -#define TARGET_LITTLE_SYM ft32_elf32_vec -#define TARGET_LITTLE_NAME "elf32-ft32" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto ft32_info_to_howto_rela -#define elf_backend_relocate_section ft32_elf_relocate_section - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_reloc_type_lookup ft32_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup ft32_reloc_name_lookup - -#define bfd_elf32_bfd_relax_section ft32_elf_relax_section - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-gen.c b/sdcc/support/sdbinutils/bfd/elf32-gen.c deleted file mode 100644 index 9ffaf59a9..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-gen.c +++ /dev/null @@ -1,103 +0,0 @@ -/* Generic support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -/* 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); - /* xgettext:c-format */ - _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 -elf32_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 elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-little" -#define TARGET_BIG_SYM elf32_be_vec -#define TARGET_BIG_NAME "elf32-big" -#define ELF_ARCH bfd_arch_unknown -#define ELF_MACHINE_CODE EM_NONE -#define ELF_MAXPAGESIZE 0x1 -#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup -#define bfd_elf32_bfd_link_add_symbols elf32_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 "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-h8300.c b/sdcc/support/sdbinutils/bfd/elf32-h8300.c deleted file mode 100644 index 041242499..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-h8300.c +++ /dev/null @@ -1,1752 +0,0 @@ -/* BFD back-end for Renesas H8/300 ELF binaries. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/h8.h" - -static reloc_howto_type *elf32_h8_reloc_type_lookup - (bfd *abfd, bfd_reloc_code_real_type code); -static void elf32_h8_info_to_howto - (bfd *, arelent *, Elf_Internal_Rela *); -static void elf32_h8_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); -static unsigned long elf32_h8_mach (flagword); -static void elf32_h8_final_write_processing (bfd *, bfd_boolean); -static bfd_boolean elf32_h8_object_p (bfd *); -static bfd_boolean elf32_h8_merge_private_bfd_data - (bfd *, struct bfd_link_info *); -static bfd_boolean elf32_h8_relax_section - (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); -static bfd_boolean elf32_h8_relax_delete_bytes - (bfd *, asection *, bfd_vma, int); -static bfd_boolean elf32_h8_symbol_address_p (bfd *, asection *, bfd_vma); -static bfd_byte *elf32_h8_get_relocated_section_contents - (bfd *, struct bfd_link_info *, struct bfd_link_order *, - bfd_byte *, bfd_boolean, asymbol **); -static bfd_reloc_status_type elf32_h8_final_link_relocate - (unsigned long, bfd *, bfd *, asection *, - bfd_byte *, bfd_vma, bfd_vma, bfd_vma, - struct bfd_link_info *, asection *, int); -static bfd_boolean elf32_h8_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, - bfd_byte *, Elf_Internal_Rela *, - Elf_Internal_Sym *, asection **); -static bfd_reloc_status_type special - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -/* This does not include any relocation information, but should be - good enough for GDB or objdump to read the file. */ - -static reloc_howto_type h8_elf_howto_table[] = -{ -#define R_H8_NONE_X 0 - HOWTO (R_H8_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR32_X (R_H8_NONE_X + 1) - HOWTO (R_H8_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR16_X (R_H8_DIR32_X + 1) - HOWTO (R_H8_DIR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR8_X (R_H8_DIR16_X + 1) - HOWTO (R_H8_DIR8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR16A8_X (R_H8_DIR8_X + 1) - HOWTO (R_H8_DIR16A8, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR16A8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR16R8_X (R_H8_DIR16A8_X + 1) - HOWTO (R_H8_DIR16R8, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR16R8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR24A8_X (R_H8_DIR16R8_X + 1) - HOWTO (R_H8_DIR24A8, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR24A8", /* name */ - TRUE, /* partial_inplace */ - 0xff000000, /* src_mask */ - 0x00ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR24R8_X (R_H8_DIR24A8_X + 1) - HOWTO (R_H8_DIR24R8, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR24R8", /* name */ - TRUE, /* partial_inplace */ - 0xff000000, /* src_mask */ - 0x00ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DIR32A16_X (R_H8_DIR24R8_X + 1) - HOWTO (R_H8_DIR32A16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_DIR32A16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_DISP32A16_X (R_H8_DIR32A16_X + 1) - HOWTO (R_H8_DISP32A16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_DISP32A16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -#define R_H8_PCREL16_X (R_H8_DISP32A16_X + 1) - HOWTO (R_H8_PCREL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_PCREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -#define R_H8_PCREL8_X (R_H8_PCREL16_X + 1) - HOWTO (R_H8_PCREL8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - special, /* special_function */ - "R_H8_PCREL8", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* This structure is used to map BFD reloc codes to H8 ELF relocs. */ - -struct elf_reloc_map { - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char howto_index; -}; - -/* An array mapping BFD reloc codes to H8 ELF relocs. */ - -static const struct elf_reloc_map h8_reloc_map[] = { - { BFD_RELOC_NONE, R_H8_NONE_X }, - { BFD_RELOC_32, R_H8_DIR32_X }, - { BFD_RELOC_16, R_H8_DIR16_X }, - { BFD_RELOC_8, R_H8_DIR8_X }, - { BFD_RELOC_H8_DIR16A8, R_H8_DIR16A8_X }, - { BFD_RELOC_H8_DIR16R8, R_H8_DIR16R8_X }, - { BFD_RELOC_H8_DIR24A8, R_H8_DIR24A8_X }, - { BFD_RELOC_H8_DIR24R8, R_H8_DIR24R8_X }, - { BFD_RELOC_H8_DIR32A16, R_H8_DIR32A16_X }, - { BFD_RELOC_H8_DISP32A16, R_H8_DISP32A16_X }, - { BFD_RELOC_16_PCREL, R_H8_PCREL16_X }, - { BFD_RELOC_8_PCREL, R_H8_PCREL8_X }, -}; - - -static reloc_howto_type * -elf32_h8_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (h8_reloc_map) / sizeof (struct elf_reloc_map); i++) - { - if (h8_reloc_map[i].bfd_reloc_val == code) - return &h8_elf_howto_table[(int) h8_reloc_map[i].howto_index]; - } - return NULL; -} - -static reloc_howto_type * -elf32_h8_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (h8_elf_howto_table) / sizeof (h8_elf_howto_table[0]); - i++) - if (h8_elf_howto_table[i].name != NULL - && strcasecmp (h8_elf_howto_table[i].name, r_name) == 0) - return &h8_elf_howto_table[i]; - - return NULL; -} - -static void -elf32_h8_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r; - unsigned int i; - - r = ELF32_R_TYPE (elf_reloc->r_info); - for (i = 0; i < sizeof (h8_elf_howto_table) / sizeof (reloc_howto_type); i++) - if (h8_elf_howto_table[i].type == r) - { - bfd_reloc->howto = &h8_elf_howto_table[i]; - return; - } - abort (); -} - -static void -elf32_h8_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED) -{ - unsigned int r; - - abort (); - r = ELF32_R_TYPE (elf_reloc->r_info); - bfd_reloc->howto = &h8_elf_howto_table[r]; -} - -/* Special handling for H8/300 relocs. - We only come here for pcrel stuff and return normally if not an -r link. - When doing -r, we can't do any arithmetic for the pcrel stuff, because - we support relaxing on the H8/300 series chips. */ -static bfd_reloc_status_type -special (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd == (bfd *) NULL) - return bfd_reloc_continue; - - /* Adjust the reloc address to that in the output section. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -/* Perform a relocation as part of a final link. */ -static bfd_reloc_status_type -elf32_h8_final_link_relocate (unsigned long r_type, bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd_byte *contents, bfd_vma offset, - bfd_vma value, bfd_vma addend, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sym_sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - bfd_byte *hit_data = contents + offset; - - switch (r_type) - { - case R_H8_NONE: - return bfd_reloc_ok; - - case R_H8_DIR32: - case R_H8_DIR32A16: - case R_H8_DISP32A16: - case R_H8_DIR24A8: - value += addend; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_H8_DIR16: - case R_H8_DIR16A8: - case R_H8_DIR16R8: - value += addend; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - /* AKA R_RELBYTE */ - case R_H8_DIR8: - value += addend; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_H8_DIR24R8: - value += addend; - - /* HIT_DATA is the address for the first byte for the relocated - value. Subtract 1 so that we can manipulate the data in 32-bit - hunks. */ - hit_data--; - - /* Clear out the top byte in value. */ - value &= 0xffffff; - - /* Retrieve the type byte for value from the section contents. */ - value |= (bfd_get_32 (input_bfd, hit_data) & 0xff000000); - - /* Now scribble it out in one 32-bit hunk. */ - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_H8_PCREL16: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - /* The value is relative to the start of the instruction, - not the relocation offset. Subtract 2 to account for - this minor issue. */ - value -= 2; - - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_H8_PCREL8: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - value += addend; - - /* The value is relative to the start of the instruction, - not the relocation offset. Subtract 1 to account for - this minor issue. */ - value -= 1; - - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - default: - return bfd_reloc_notsupported; - } -} - -/* Relocate an H8 ELF section. */ -static bfd_boolean -elf32_h8_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - unsigned int r_type; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - arelent bfd_reloc; - reloc_howto_type *howto; - - elf32_h8_info_to_howto (input_bfd, &bfd_reloc, rel); - howto = bfd_reloc.howto; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = elf32_h8_final_link_relocate (r_type, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char *name; - const char *msg = (const char *) 0; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* Object files encode the specific H8 model they were compiled - for in the ELF flags field. - - Examine that field and return the proper BFD machine type for - the object file. */ -static unsigned long -elf32_h8_mach (flagword flags) -{ - switch (flags & EF_H8_MACH) - { - case E_H8_MACH_H8300: - default: - return bfd_mach_h8300; - - case E_H8_MACH_H8300H: - return bfd_mach_h8300h; - - case E_H8_MACH_H8300S: - return bfd_mach_h8300s; - - case E_H8_MACH_H8300HN: - return bfd_mach_h8300hn; - - case E_H8_MACH_H8300SN: - return bfd_mach_h8300sn; - - case E_H8_MACH_H8300SX: - return bfd_mach_h8300sx; - - case E_H8_MACH_H8300SXN: - return bfd_mach_h8300sxn; - } -} - -/* The final processing done just before writing out a H8 ELF object - file. We use this opportunity to encode the BFD machine type - into the flags field in the object file. */ - -static void -elf32_h8_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_h8300: - val = E_H8_MACH_H8300; - break; - - case bfd_mach_h8300h: - val = E_H8_MACH_H8300H; - break; - - case bfd_mach_h8300s: - val = E_H8_MACH_H8300S; - break; - - case bfd_mach_h8300hn: - val = E_H8_MACH_H8300HN; - break; - - case bfd_mach_h8300sn: - val = E_H8_MACH_H8300SN; - break; - - case bfd_mach_h8300sx: - val = E_H8_MACH_H8300SX; - break; - - case bfd_mach_h8300sxn: - val = E_H8_MACH_H8300SXN; - break; - } - - elf_elfheader (abfd)->e_flags &= ~ (EF_H8_MACH); - elf_elfheader (abfd)->e_flags |= val; -} - -/* Return nonzero if ABFD represents a valid H8 ELF object file; also - record the encoded machine type found in the ELF flags. */ - -static bfd_boolean -elf32_h8_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_h8300, - elf32_h8_mach (elf_elfheader (abfd)->e_flags)); - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. The only data we need to copy at this - time is the architecture/machine information. */ - -static bfd_boolean -elf32_h8_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_mach (obfd) < bfd_get_mach (ibfd)) - { - if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd))) - return FALSE; - } - - return TRUE; -} - -/* This function handles relaxing for the H8.. - - There are a few relaxing opportunities available on the H8: - - jmp/jsr:24 -> bra/bsr:8 2 bytes - The jmp may be completely eliminated if the previous insn is a - conditional branch to the insn after the jump. In that case - we invert the branch and delete the jump and save 4 bytes. - - bCC:16 -> bCC:8 2 bytes - bsr:16 -> bsr:8 2 bytes - - bset:16 -> bset:8 2 bytes - bset:24/32 -> bset:8 4 bytes - (also applicable to other bit manipulation instructions) - - mov.b:16 -> mov.b:8 2 bytes - mov.b:24/32 -> mov.b:8 4 bytes - - bset:24/32 -> bset:16 2 bytes - (also applicable to other bit manipulation instructions) - - mov.[bwl]:24/32 -> mov.[bwl]:16 2 bytes - - mov.[bwl] @(displ:24/32+ERx) -> mov.[bwl] @(displ:16+ERx) 4 bytes. */ - -static bfd_boolean -elf32_h8_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - static asection *last_input_section = NULL; - static Elf_Internal_Rela *last_reloc = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - if (sec != last_input_section) - last_reloc = NULL; - - last_input_section = sec; - - /* Walk through the relocs looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - { - arelent bfd_reloc; - - elf32_h8_info_to_howto (abfd, &bfd_reloc, irel); - } - /* Keep track of the previous reloc so that we can delete - some long jumps created by the compiler. */ - if (irel != internal_relocs) - last_reloc = irel - 1; - - switch(ELF32_R_TYPE (irel->r_info)) - { - case R_H8_DIR24R8: - case R_H8_PCREL16: - case R_H8_DIR16A8: - case R_H8_DIR24A8: - case R_H8_DIR32A16: - case R_H8_DISP32A16: - break; - default: - continue; - } - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec) - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - } - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - switch (ELF32_R_TYPE (irel->r_info)) - { - /* Try to turn a 24-bit absolute branch/call into an 8-bit - pc-relative branch/call. */ - case R_H8_DIR24R8: - { - bfd_vma value = symval + irel->r_addend; - bfd_vma dot, gap; - - /* Get the address of this instruction. */ - dot = (sec->output_section->vma - + sec->output_offset + irel->r_offset - 1); - - /* Compute the distance from this insn to the branch target. */ - gap = value - dot; - - /* If the distance is within -126..+130 inclusive, then we can - relax this jump. +130 is valid since the target will move - two bytes closer if we do relax this branch. */ - if ((int) gap >= -126 && (int) gap <= 130) - { - unsigned char code; - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Get the instruction code being relaxed. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* If the previous instruction conditionally jumped around - this instruction, we may be able to reverse the condition - and redirect the previous instruction to the target of - this instruction. - - Such sequences are used by the compiler to deal with - long conditional branches. - - Only perform this optimisation for jumps (code 0x5a) not - subroutine calls, as otherwise it could transform: - - mov.w r0,r0 - beq .L1 - jsr @_bar - .L1: rts - _bar: rts - into: - mov.w r0,r0 - bne _bar - rts - _bar: rts - - which changes the call (jsr) into a branch (bne). */ - if (code == 0x5a /* jmp24. */ - && (int) gap <= 130 - && (int) gap >= -128 - && last_reloc - && ELF32_R_TYPE (last_reloc->r_info) == R_H8_PCREL8 - && ELF32_R_SYM (last_reloc->r_info) < symtab_hdr->sh_info) - { - bfd_vma last_value; - asection *last_sym_sec; - Elf_Internal_Sym *last_sym; - - /* We will need to examine the symbol used by the - previous relocation. */ - - last_sym = isymbuf + ELF32_R_SYM (last_reloc->r_info); - last_sym_sec - = bfd_section_from_elf_index (abfd, last_sym->st_shndx); - last_value = (last_sym->st_value - + last_sym_sec->output_section->vma - + last_sym_sec->output_offset); - - /* Verify that the previous relocation was for a - branch around this instruction and that no symbol - exists at the current location. */ - if (last_value == dot + 4 - && last_reloc->r_offset + 2 == irel->r_offset - && ! elf32_h8_symbol_address_p (abfd, sec, dot)) - { - /* We can eliminate this jump. Twiddle the - previous relocation as necessary. */ - irel->r_info - = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - ELF32_R_TYPE (R_H8_NONE)); - - last_reloc->r_info - = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - ELF32_R_TYPE (R_H8_PCREL8)); - last_reloc->r_addend = irel->r_addend; - - code = bfd_get_8 (abfd, - contents + last_reloc->r_offset - 1); - code ^= 1; - bfd_put_8 (abfd, - code, - contents + last_reloc->r_offset - 1); - - /* Delete four bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, - irel->r_offset - 1, - 4)) - goto error_return; - - *again = TRUE; - break; - } - } - - if (code == 0x5e) - /* This is jsr24 */ - bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 1); /* bsr8. */ - else if (code == 0x5a) - /* This is jmp24 */ - bfd_put_8 (abfd, 0x40, contents + irel->r_offset - 1); /* bra8. */ - else - abort (); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_H8_PCREL8); - - /* Delete two bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - break; - } - - /* Try to turn a 16-bit pc-relative branch into a 8-bit pc-relative - branch. */ - case R_H8_PCREL16: - { - bfd_vma value = symval + irel->r_addend; - bfd_vma dot; - bfd_vma gap; - - /* Get the address of this instruction. */ - dot = (sec->output_section->vma - + sec->output_offset - + irel->r_offset - 2); - - gap = value - dot; - - /* If the distance is within -126..+130 inclusive, then we can - relax this jump. +130 is valid since the target will move - two bytes closer if we do relax this branch. */ - if ((int) gap >= -126 && (int) gap <= 130) - { - unsigned char code; - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - if (code == 0x58) - { - /* bCC:16 -> bCC:8 */ - /* Get the second byte of the original insn, which - contains the condition code. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* Compute the first byte of the relaxed - instruction. The original sequence 0x58 0xX0 - is relaxed to 0x4X, where X represents the - condition code. */ - code &= 0xf0; - code >>= 4; - code |= 0x40; - bfd_put_8 (abfd, code, contents + irel->r_offset - 2); /* bCC:8. */ - } - else if (code == 0x5c) /* bsr16. */ - /* This is bsr. */ - bfd_put_8 (abfd, 0x55, contents + irel->r_offset - 2); /* bsr8. */ - else - /* Might be MOVSD. */ - break; - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_H8_PCREL8); - irel->r_offset--; - - /* Delete two bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - break; - } - - /* This is a 16-bit absolute address in one of the following - instructions: - - "band", "bclr", "biand", "bild", "bior", "bist", "bixor", - "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", and - "mov.b" - - We may relax this into an 8-bit absolute address if it's in - the right range. */ - case R_H8_DIR16A8: - { - bfd_vma value; - - value = bfd_h8300_pad_address (abfd, symval + irel->r_addend); - if (value >= 0xffffff00u) - { - unsigned char code; - unsigned char temp_code; - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - /* All instructions with R_H8_DIR16A8 start with - 0x6a. */ - if (code != 0x6a) - abort (); - - temp_code = code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - /* If this is a mov.b instruction, clear the lower - nibble, which contains the source/destination - register number. */ - if ((temp_code & 0x10) != 0x10) - temp_code &= 0xf0; - - switch (temp_code) - { - case 0x00: - /* This is mov.b @aa:16,Rd. */ - bfd_put_8 (abfd, (code & 0xf) | 0x20, - contents + irel->r_offset - 2); - break; - case 0x80: - /* This is mov.b Rs,@aa:16. */ - bfd_put_8 (abfd, (code & 0xf) | 0x30, - contents + irel->r_offset - 2); - break; - case 0x18: - /* This is a bit-maniputation instruction that - stores one bit into memory, one of "bclr", - "bist", "bnot", "bset", and "bst". */ - bfd_put_8 (abfd, 0x7f, contents + irel->r_offset - 2); - break; - case 0x10: - /* This is a bit-maniputation instruction that - loads one bit from memory, one of "band", - "biand", "bild", "bior", "bixor", "bld", "bor", - "btst", and "bxor". */ - bfd_put_8 (abfd, 0x7e, contents + irel->r_offset - 2); - break; - default: - abort (); - } - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_H8_DIR8); - - /* Move the relocation. */ - irel->r_offset--; - - /* Delete two bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - break; - } - - /* This is a 24-bit absolute address in one of the following - instructions: - - "band", "bclr", "biand", "bild", "bior", "bist", "bixor", - "bld", "bnot", "bor", "bset", "bst", "btst", "bxor", and - "mov.b" - - We may relax this into an 8-bit absolute address if it's in - the right range. */ - case R_H8_DIR24A8: - { - bfd_vma value; - - value = bfd_h8300_pad_address (abfd, symval + irel->r_addend); - if (value >= 0xffffff00u) - { - unsigned char code; - unsigned char temp_code; - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 2); - - /* All instructions with R_H8_DIR24A8 start with - 0x6a. */ - if (code != 0x6a) - abort (); - - temp_code = code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* If this is a mov.b instruction, clear the lower - nibble, which contains the source/destination - register number. */ - if ((temp_code & 0x30) != 0x30) - temp_code &= 0xf0; - - switch (temp_code) - { - case 0x20: - /* This is mov.b @aa:24/32,Rd. */ - bfd_put_8 (abfd, (code & 0xf) | 0x20, - contents + irel->r_offset - 2); - break; - case 0xa0: - /* This is mov.b Rs,@aa:24/32. */ - bfd_put_8 (abfd, (code & 0xf) | 0x30, - contents + irel->r_offset - 2); - break; - case 0x38: - /* This is a bit-maniputation instruction that - stores one bit into memory, one of "bclr", - "bist", "bnot", "bset", and "bst". */ - bfd_put_8 (abfd, 0x7f, contents + irel->r_offset - 2); - break; - case 0x30: - /* This is a bit-maniputation instruction that - loads one bit from memory, one of "band", - "biand", "bild", "bior", "bixor", "bld", "bor", - "btst", and "bxor". */ - bfd_put_8 (abfd, 0x7e, contents + irel->r_offset - 2); - break; - default: - abort(); - } - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_H8_DIR8); - irel->r_offset--; - - /* Delete four bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 4)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - break; - } - } - - /* Fall through. */ - - /* This is a 24-/32-bit absolute address in one of the - following instructions: - - "band", "bclr", "biand", "bild", "bior", "bist", - "bixor", "bld", "bnot", "bor", "bset", "bst", "btst", - "bxor", "ldc.w", "stc.w" and "mov.[bwl]" - - We may relax this into an 16-bit absolute address if it's - in the right range. */ - case R_H8_DIR32A16: - { - bfd_vma value; - - value = bfd_h8300_pad_address (abfd, symval + irel->r_addend); - if (value <= 0x7fff || value >= 0xffff8000u) - { - unsigned char code; - unsigned char op0, op1, op2, op3; - unsigned char *op_ptr; - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - if (irel->r_offset >= 4) - { - /* Check for 4-byte MOVA relaxation (SH-specific). */ - int second_reloc = 0; - - op_ptr = contents + irel->r_offset - 4; - - if (last_reloc) - { - arelent bfd_reloc; - reloc_howto_type *h; - bfd_vma last_reloc_size; - - elf32_h8_info_to_howto (abfd, &bfd_reloc, last_reloc); - h = bfd_reloc.howto; - last_reloc_size = 1 << h->size; - if (last_reloc->r_offset + last_reloc_size - == irel->r_offset) - { - op_ptr -= last_reloc_size; - second_reloc = 1; - } - } - - if (irel + 1 < irelend) - { - Elf_Internal_Rela *next_reloc = irel + 1; - arelent bfd_reloc; - reloc_howto_type *h; - bfd_vma next_reloc_size; - - elf32_h8_info_to_howto (abfd, &bfd_reloc, next_reloc); - h = bfd_reloc.howto; - next_reloc_size = 1 << h->size; - if (next_reloc->r_offset + next_reloc_size - == irel->r_offset) - { - op_ptr -= next_reloc_size; - second_reloc = 1; - } - } - - op0 = bfd_get_8 (abfd, op_ptr + 0); - op1 = bfd_get_8 (abfd, op_ptr + 1); - op2 = bfd_get_8 (abfd, op_ptr + 2); - op3 = bfd_get_8 (abfd, op_ptr + 3); - - if (op0 == 0x01 - && (op1 & 0xdf) == 0x5f - && (op2 & 0x40) == 0x40 - && (op3 & 0x80) == 0x80) - { - if ((op2 & 0x08) == 0) - second_reloc = 1; - - if (second_reloc) - { - op3 &= ~0x08; - bfd_put_8 (abfd, op3, op_ptr + 3); - } - else - { - op2 &= ~0x08; - bfd_put_8 (abfd, op2, op_ptr + 2); - } - goto r_h8_dir32a16_common; - } - } - - /* Now check for short version of MOVA. (SH-specific) */ - op_ptr = contents + irel->r_offset - 2; - op0 = bfd_get_8 (abfd, op_ptr + 0); - op1 = bfd_get_8 (abfd, op_ptr + 1); - - if (op0 == 0x7a - && (op1 & 0x88) == 0x80) - { - op1 |= 0x08; - bfd_put_8 (abfd, op1, op_ptr + 1); - goto r_h8_dir32a16_common; - } - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - /* Fix the opcode. For all the instructions that - belong to this relaxation, we simply need to turn - off bit 0x20 in the previous byte. */ - code &= ~0x20; - - bfd_put_8 (abfd, code, contents + irel->r_offset - 1); - - r_h8_dir32a16_common: - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_H8_DIR16); - - /* Delete two bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - break; /* case R_H8_DIR32A16 */ - } - - case R_H8_DISP32A16: - /* mov.[bwl] @(displ:24/32+ERx) -> mov.[bwl] @(displ:16+ERx) 4 bytes - It is assured that instruction uses at least 4 bytes opcode before - reloc entry addressing mode "register indirect with displacement" - relaxing options (all saving 4 bytes): - 0x78 0sss0000 0x6A 0010dddd disp:32 mov.b @(d:32,ERs),Rd -> - 0x6E 0sssdddd disp:16 mov.b @(d:16,ERs),Rd - 0x78 0sss0000 0x6B 0010dddd disp:32 mov.w @(d:32,ERs),Rd -> - 0x6F 0sssdddd disp:16 mov.w @(d:16,ERs),Rd - 0x01 0x00 0x78 0sss0000 0x6B 00100ddd disp:32 mov.l @(d:32,ERs),ERd -> - 0x01 0x00 0x6F 0sss0ddd disp:16 mov.l @(d:16,ERs),ERd - - 0x78 0ddd0000 0x6A 1010ssss disp:32 mov.b Rs,@(d:32,ERd) -> - 0x6E 1dddssss disp:16 mov.b Rs,@(d:16,ERd) - 0x78 0ddd0000 0x6B 1010ssss disp:32 mov.w Rs,@(d:32,ERd) -> - 0x6F 1dddssss disp:16 mov.w Rs,@(d:16,ERd) - 0x01 0x00 0x78 xddd0000 0x6B 10100sss disp:32 mov.l ERs,@(d:32,ERd) -> - 0x01 0x00 0x6F 1ddd0sss disp:16 mov.l ERs,@(d:16,ERd) - mov.l prefix 0x01 0x00 can be left as is and mov.l handled same - as mov.w/ */ - { - bfd_vma value; - - value = bfd_h8300_pad_address (abfd, symval + irel->r_addend); - if (value <= 0x7fff || value >= 0xffff8000u) - { - unsigned char op0, op1, op2, op3, op0n, op1n; - int relax = 0; - - /* Note that we've changed the relocs, section contents, - etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - if (irel->r_offset >= 4) - { - op0 = bfd_get_8 (abfd, contents + irel->r_offset - 4); - op1 = bfd_get_8 (abfd, contents + irel->r_offset - 3); - op2 = bfd_get_8 (abfd, contents + irel->r_offset - 2); - op3 = bfd_get_8 (abfd, contents + irel->r_offset - 1); - - if (op0 == 0x78) - { - switch(op2) - { - case 0x6A: - if ((op1 & 0x8F) == 0x00 && (op3 & 0x70) == 0x20) - { - /* mov.b. */ - op0n = 0x6E; - relax = 1; - } - break; - case 0x6B: - if ((op1 & 0x0F) == 0x00 && (op3 & 0x70) == 0x20) - { - /* mov.w/l. */ - op0n = 0x6F; - relax = 1; - } - break; - default: - break; - } - } - } - - if (relax) - { - op1n = (op3 & 0x8F) | (op1 & 0x70); - bfd_put_8 (abfd, op0n, contents + irel->r_offset - 4); - bfd_put_8 (abfd, op1n, contents + irel->r_offset - 3); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_H8_DIR16); - irel->r_offset -= 2; - - /* Delete four bytes of data. */ - if (!elf32_h8_relax_delete_bytes (abfd, sec, irel->r_offset + 2, 4)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - } - break; - - default: - break; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - symtab_hdr->contents = (unsigned char *) isymbuf; - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -elf32_h8_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - bfd_vma toaddr; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset <= toaddr)) - irel->r_offset -= count; - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - isymend = isym + symtab_hdr->sh_info; - for (; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value <= toaddr) - isym->st_value -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value <= toaddr) - sym_hash->root.u.def.value -= count; - } - - return TRUE; -} - -/* Return TRUE if a symbol exists at the given address, else return - FALSE. */ -static bfd_boolean -elf32_h8_symbol_address_p (bfd *abfd, asection *sec, bfd_vma addr) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* Examine all the symbols. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - isymend = isym + symtab_hdr->sh_info; - for (; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value == addr) - return TRUE; - } - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == addr) - return TRUE; - } - - return FALSE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses elf32_h8_relocate_section. */ - -static bfd_byte * -elf32_h8_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - asection **secpp; - Elf_Internal_Sym *isym, *isymend; - bfd_size_type amt; - - internal_relocs = (_bfd_elf_link_read_relocs - (input_bfd, input_section, NULL, - (Elf_Internal_Rela *) NULL, FALSE)); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = (asection **) bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! elf32_h8_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - return NULL; -} - - -#define TARGET_BIG_SYM h8300_elf32_vec -#define TARGET_BIG_NAME "elf32-h8300" -#define ELF_ARCH bfd_arch_h8300 -#define ELF_MACHINE_CODE EM_H8_300 -#define ELF_MAXPAGESIZE 0x1 -#define bfd_elf32_bfd_reloc_type_lookup elf32_h8_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf32_h8_reloc_name_lookup -#define elf_info_to_howto elf32_h8_info_to_howto -#define elf_info_to_howto_rel elf32_h8_info_to_howto_rel - -/* So we can set/examine bits in e_flags to get the specific - H8 architecture in use. */ -#define elf_backend_final_write_processing \ - elf32_h8_final_write_processing -#define elf_backend_object_p \ - elf32_h8_object_p -#define bfd_elf32_bfd_merge_private_bfd_data \ - elf32_h8_merge_private_bfd_data - -/* ??? when elf_backend_relocate_section is not defined, elf32-target.h - defaults to using _bfd_generic_link_hash_table_create, but - bfd_elf_size_dynamic_sections uses - dynobj = elf_hash_table (info)->dynobj; - and thus requires an elf hash table. */ -#define bfd_elf32_bfd_link_hash_table_create _bfd_elf_link_hash_table_create - -/* Use an H8 specific linker, not the ELF generic linker. */ -#define elf_backend_relocate_section elf32_h8_relocate_section -#define elf_backend_rela_normal 1 -#define elf_backend_can_gc_sections 1 - -/* And relaxing stuff. */ -#define bfd_elf32_bfd_relax_section elf32_h8_relax_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - elf32_h8_get_relocated_section_contents - -#define elf_symbol_leading_char '_' - -#include "elf32-target.h" - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM h8300_elf32_linux_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-h8300-linux" -#undef elf_symbol_leading_char -#define elf32_bed elf32_h8300_linux_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-hppa.c b/sdcc/support/sdbinutils/bfd/elf32-hppa.c deleted file mode 100644 index 7454f48ad..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-hppa.c +++ /dev/null @@ -1,4599 +0,0 @@ -/* BFD back-end for HP PA-RISC ELF files. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - - Original code by - Center for Software Science - Department of Computer Science - University of Utah - Largely rewritten by Alan Modra - Naming cleanup by Carlos O'Donell - TLS support written by Randolph Chung - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/hppa.h" -#include "libhppa.h" -#include "elf32-hppa.h" -#define ARCH_SIZE 32 -#include "elf32-hppa.h" -#include "elf-hppa.h" - -/* 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 elf32_hppa_* are called by external routines, other - functions are only called locally. elf32_hppa_* functions appear - in this file more or less in the order in which they are called - from external routines. eg. elf32_hppa_check_relocs is called - early in the link process, elf32_hppa_finish_dynamic_sections is - one of the last functions. */ - -/* We use two hash tables to hold information for linking PA ELF objects. - - The first is the elf32_hppa_link_hash_table which is derived - from the standard ELF linker hash table. We use this as a place to - attach other hash tables and static information. - - The second is the stub hash table which is derived from the - base BFD hash table. The stub hash table holds the information - necessary to build the linker stubs during a link. - - There are a number of different stubs generated by the linker. - - Long branch stub: - : ldil LR'X,%r1 - : be,n RR'X(%sr4,%r1) - - PIC long branch stub: - : b,l .+8,%r1 - : addil LR'X - ($PIC_pcrel$0 - 4),%r1 - : be,n RR'X - ($PIC_pcrel$0 - 8)(%sr4,%r1) - - Import stub to call shared library routine from normal object file - (single sub-space version) - : addil LR'lt_ptr+ltoff,%dp ; get procedure entry point - : ldw RR'lt_ptr+ltoff(%r1),%r21 - : bv %r0(%r21) - : ldw RR'lt_ptr+ltoff+4(%r1),%r19 ; get new dlt value. - - Import stub to call shared library routine from shared library - (single sub-space version) - : addil LR'ltoff,%r19 ; get procedure entry point - : ldw RR'ltoff(%r1),%r21 - : bv %r0(%r21) - : ldw RR'ltoff+4(%r1),%r19 ; get new dlt value. - - Import stub to call shared library routine from normal object file - (multiple sub-space support) - : addil LR'lt_ptr+ltoff,%dp ; get procedure entry point - : ldw RR'lt_ptr+ltoff(%r1),%r21 - : ldw RR'lt_ptr+ltoff+4(%r1),%r19 ; get new dlt value. - : ldsid (%r21),%r1 - : mtsp %r1,%sr0 - : be 0(%sr0,%r21) ; branch to target - : stw %rp,-24(%sp) ; save rp - - Import stub to call shared library routine from shared library - (multiple sub-space support) - : addil LR'ltoff,%r19 ; get procedure entry point - : ldw RR'ltoff(%r1),%r21 - : ldw RR'ltoff+4(%r1),%r19 ; get new dlt value. - : ldsid (%r21),%r1 - : mtsp %r1,%sr0 - : be 0(%sr0,%r21) ; branch to target - : stw %rp,-24(%sp) ; save rp - - Export stub to return from shared lib routine (multiple sub-space support) - One of these is created for each exported procedure in a shared - library (and stored in the shared lib). Shared lib routines are - called via the first instruction in the export stub so that we can - do an inter-space return. Not required for single sub-space. - : bl,n X,%rp ; trap the return - : nop - : ldw -24(%sp),%rp ; restore the original rp - : ldsid (%rp),%r1 - : mtsp %r1,%sr0 - : be,n 0(%sr0,%rp) ; inter-space return. */ - - -/* Variable names follow a coding style. - Please follow this (Apps Hungarian) style: - - Structure/Variable Prefix - elf_link_hash_table "etab" - elf_link_hash_entry "eh" - - elf32_hppa_link_hash_table "htab" - elf32_hppa_link_hash_entry "hh" - - bfd_hash_table "btab" - bfd_hash_entry "bh" - - bfd_hash_table containing stubs "bstab" - elf32_hppa_stub_hash_entry "hsh" - - Always remember to use GNU Coding Style. */ - -#define PLT_ENTRY_SIZE 8 -#define GOT_ENTRY_SIZE 4 -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -static const bfd_byte plt_stub[] = -{ - 0x0e, 0x80, 0x10, 0x96, /* 1: ldw 0(%r20),%r22 */ - 0xea, 0xc0, 0xc0, 0x00, /* bv %r0(%r22) */ - 0x0e, 0x88, 0x10, 0x95, /* ldw 4(%r20),%r21 */ -#define PLT_STUB_ENTRY (3*4) - 0xea, 0x9f, 0x1f, 0xdd, /* b,l 1b,%r20 */ - 0xd6, 0x80, 0x1c, 0x1e, /* depi 0,31,2,%r20 */ - 0x00, 0xc0, 0xff, 0xee, /* 9: .word fixup_func */ - 0xde, 0xad, 0xbe, 0xef /* .word fixup_ltp */ -}; - -/* Section name for stubs is the associated section name plus this - string. */ -#define STUB_SUFFIX ".stub" - -/* We don't need to copy certain PC- or GP-relative dynamic relocs - into a shared object's dynamic section. All the relocs of the - limited class we are interested in, are absolute. */ -#ifndef RELATIVE_DYNRELOCS -#define RELATIVE_DYNRELOCS 0 -#define IS_ABSOLUTE_RELOC(r_type) 1 -#define pc_dynrelocs(hh) 0 -#endif - -/* 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 - -enum elf32_hppa_stub_type -{ - hppa_stub_long_branch, - hppa_stub_long_branch_shared, - hppa_stub_import, - hppa_stub_import_shared, - hppa_stub_export, - hppa_stub_none -}; - -struct elf32_hppa_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry bh_root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; - - enum elf32_hppa_stub_type stub_type; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf32_hppa_link_hash_entry *hh; - - /* Where this stub is being called from, or, in the case of combined - stub sections, the first input section in the group. */ - asection *id_sec; -}; - -enum _tls_type - { - GOT_UNKNOWN = 0, - GOT_NORMAL = 1, - GOT_TLS_GD = 2, - GOT_TLS_LDM = 4, - GOT_TLS_IE = 8 - }; - -struct elf32_hppa_link_hash_entry -{ - struct elf_link_hash_entry eh; - - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct elf32_hppa_stub_hash_entry *hsh_cache; - - /* Used to count relocations for delayed sizing of relocation - sections. */ - struct elf_dyn_relocs *dyn_relocs; - - ENUM_BITFIELD (_tls_type) tls_type : 8; - - /* Set if this symbol is used by a plabel reloc. */ - unsigned int plabel:1; -}; - -struct elf32_hppa_link_hash_table -{ - /* The main hash table. */ - struct elf_link_hash_table etab; - - /* The stub hash table. */ - struct bfd_hash_table bstab; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *); - void (*layout_sections_again) (void); - - /* Array to keep track of which stub sections have been created, and - information on stub grouping. */ - struct map_stub - { - /* This is the section to which stubs in the group will be - attached. */ - asection *link_sec; - /* The stub section. */ - asection *stub_sec; - } *stub_group; - - /* Assorted information used by elf32_hppa_size_stubs. */ - unsigned int bfd_count; - unsigned int top_index; - asection **input_list; - Elf_Internal_Sym **all_local_syms; - - /* Used during a final link to store the base of the text and data - segments so that we can perform SEGREL relocations. */ - bfd_vma text_segment_base; - bfd_vma data_segment_base; - - /* Whether we support multiple sub-spaces for shared libs. */ - unsigned int multi_subspace:1; - - /* Flags set when various size branches are detected. Used to - select suitable defaults for the stub group size. */ - unsigned int has_12bit_branch:1; - unsigned int has_17bit_branch:1; - unsigned int has_22bit_branch:1; - - /* Set if we need a .plt stub to support lazy dynamic linking. */ - unsigned int need_plt_stub:1; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* Data for LDM relocations. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; -}; - -/* Various hash macros and functions. */ -#define hppa_link_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == HPPA32_ELF_DATA ? ((struct elf32_hppa_link_hash_table *) ((p)->hash)) : NULL) - -#define hppa_elf_hash_entry(ent) \ - ((struct elf32_hppa_link_hash_entry *)(ent)) - -#define hppa_stub_hash_entry(ent) \ - ((struct elf32_hppa_stub_hash_entry *)(ent)) - -#define hppa_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_hppa_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -#define hppa_elf_local_got_tls_type(abfd) \ - ((char *)(elf_local_got_offsets (abfd) + (elf_tdata (abfd)->symtab_hdr.sh_info * 2))) - -#define hh_name(hh) \ - (hh ? hh->eh.root.root.string : "") - -#define eh_name(eh) \ - (eh ? eh->root.root.string : "") - -/* Assorted hash table functions. */ - -/* Initialize an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_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 elf32_hppa_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf32_hppa_stub_hash_entry *hsh; - - /* Initialize the local fields. */ - hsh = hppa_stub_hash_entry (entry); - hsh->stub_sec = NULL; - hsh->stub_offset = 0; - hsh->target_value = 0; - hsh->target_section = NULL; - hsh->stub_type = hppa_stub_long_branch; - hsh->hh = NULL; - hsh->id_sec = NULL; - } - - return entry; -} - -/* Initialize an entry in the link hash table. */ - -static struct bfd_hash_entry * -hppa_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 elf32_hppa_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 elf32_hppa_link_hash_entry *hh; - - /* Initialize the local fields. */ - hh = hppa_elf_hash_entry (entry); - hh->hsh_cache = NULL; - hh->dyn_relocs = NULL; - hh->plabel = 0; - hh->tls_type = GOT_UNKNOWN; - } - - return entry; -} - -/* Free the derived linker hash table. */ - -static void -elf32_hppa_link_hash_table_free (bfd *obfd) -{ - struct elf32_hppa_link_hash_table *htab - = (struct elf32_hppa_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (&htab->bstab); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create the derived linker hash table. The PA ELF port uses the derived - hash table to keep information specific to the PA ELF linker (without - using static variables). */ - -static struct bfd_link_hash_table * -elf32_hppa_link_hash_table_create (bfd *abfd) -{ - struct elf32_hppa_link_hash_table *htab; - bfd_size_type amt = sizeof (*htab); - - htab = bfd_zmalloc (amt); - if (htab == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&htab->etab, abfd, hppa_link_hash_newfunc, - sizeof (struct elf32_hppa_link_hash_entry), - HPPA32_ELF_DATA)) - { - free (htab); - return NULL; - } - - /* Init the stub hash table too. */ - if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc, - sizeof (struct elf32_hppa_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - htab->etab.root.hash_table_free = elf32_hppa_link_hash_table_free; - - htab->text_segment_base = (bfd_vma) -1; - htab->data_segment_base = (bfd_vma) -1; - return &htab->etab.root; -} - -/* Initialize the linker stubs BFD so that we can use it for linker - created dynamic sections. */ - -void -elf32_hppa_init_stub_bfd (bfd *abfd, struct bfd_link_info *info) -{ - struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info); - - elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS32; - htab->etab.dynobj = abfd; -} - -/* Build a name for an entry in the stub hash table. */ - -static char * -hppa_stub_name (const asection *input_section, - const asection *sym_sec, - const struct elf32_hppa_link_hash_entry *hh, - const Elf_Internal_Rela *rela) -{ - char *stub_name; - bfd_size_type len; - - if (hh) - { - len = 8 + 1 + strlen (hh_name (hh)) + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - sprintf (stub_name, "%08x_%s+%x", - input_section->id & 0xffffffff, - hh_name (hh), - (int) rela->r_addend & 0xffffffff); - } - else - { - len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - sprintf (stub_name, "%08x_%x:%x+%x", - input_section->id & 0xffffffff, - sym_sec->id & 0xffffffff, - (int) ELF32_R_SYM (rela->r_info) & 0xffffffff, - (int) rela->r_addend & 0xffffffff); - } - return stub_name; -} - -/* Look up an entry in the stub hash. Stub entries are cached because - creating the stub name takes a bit of time. */ - -static struct elf32_hppa_stub_hash_entry * -hppa_get_stub_entry (const asection *input_section, - const asection *sym_sec, - struct elf32_hppa_link_hash_entry *hh, - const Elf_Internal_Rela *rela, - struct elf32_hppa_link_hash_table *htab) -{ - struct elf32_hppa_stub_hash_entry *hsh_entry; - const asection *id_sec; - - /* If this input section is part of a group of sections sharing one - stub section, then use the id of the first section in the group. - Stub names need to include a section id, as there may well be - more than one stub used to reach say, printf, and we need to - distinguish between them. */ - id_sec = htab->stub_group[input_section->id].link_sec; - - if (hh != NULL && hh->hsh_cache != NULL - && hh->hsh_cache->hh == hh - && hh->hsh_cache->id_sec == id_sec) - { - hsh_entry = hh->hsh_cache; - } - else - { - char *stub_name; - - stub_name = hppa_stub_name (id_sec, sym_sec, hh, rela); - if (stub_name == NULL) - return NULL; - - hsh_entry = hppa_stub_hash_lookup (&htab->bstab, - stub_name, FALSE, FALSE); - if (hh != NULL) - hh->hsh_cache = hsh_entry; - - free (stub_name); - } - - return hsh_entry; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ - -static struct elf32_hppa_stub_hash_entry * -hppa_add_stub (const char *stub_name, - asection *section, - struct elf32_hppa_link_hash_table *htab) -{ - asection *link_sec; - asection *stub_sec; - struct elf32_hppa_stub_hash_entry *hsh; - - link_sec = htab->stub_group[section->id].link_sec; - stub_sec = htab->stub_group[section->id].stub_sec; - if (stub_sec == NULL) - { - stub_sec = htab->stub_group[link_sec->id].stub_sec; - if (stub_sec == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - stub_sec = (*htab->add_stub_section) (s_name, link_sec); - if (stub_sec == NULL) - return NULL; - htab->stub_group[link_sec->id].stub_sec = stub_sec; - } - htab->stub_group[section->id].stub_sec = stub_sec; - } - - /* Enter this entry into the linker stub hash table. */ - hsh = hppa_stub_hash_lookup (&htab->bstab, stub_name, - TRUE, FALSE); - if (hsh == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: cannot create stub entry %s"), - section->owner, stub_name); - return NULL; - } - - hsh->stub_sec = stub_sec; - hsh->stub_offset = 0; - hsh->id_sec = link_sec; - return hsh; -} - -/* Determine the type of stub needed, if any, for a call. */ - -static enum elf32_hppa_stub_type -hppa_type_of_stub (asection *input_sec, - const Elf_Internal_Rela *rela, - struct elf32_hppa_link_hash_entry *hh, - bfd_vma destination, - struct bfd_link_info *info) -{ - bfd_vma location; - bfd_vma branch_offset; - bfd_vma max_branch_offset; - unsigned int r_type; - - if (hh != NULL - && hh->eh.plt.offset != (bfd_vma) -1 - && hh->eh.dynindx != -1 - && !hh->plabel - && (bfd_link_pic (info) - || !hh->eh.def_regular - || hh->eh.root.type == bfd_link_hash_defweak)) - { - /* We need an import stub. Decide between hppa_stub_import - and hppa_stub_import_shared later. */ - return hppa_stub_import; - } - - /* Determine where the call point is. */ - location = (input_sec->output_offset - + input_sec->output_section->vma - + rela->r_offset); - - branch_offset = destination - location - 8; - r_type = ELF32_R_TYPE (rela->r_info); - - /* Determine if a long branch stub is needed. parisc branch offsets - are relative to the second instruction past the branch, ie. +8 - bytes on from the branch instruction location. The offset is - signed and counts in units of 4 bytes. */ - if (r_type == (unsigned int) R_PARISC_PCREL17F) - max_branch_offset = (1 << (17 - 1)) << 2; - - else if (r_type == (unsigned int) R_PARISC_PCREL12F) - max_branch_offset = (1 << (12 - 1)) << 2; - - else /* R_PARISC_PCREL22F. */ - max_branch_offset = (1 << (22 - 1)) << 2; - - if (branch_offset + max_branch_offset >= 2*max_branch_offset) - return hppa_stub_long_branch; - - return hppa_stub_none; -} - -/* Build one linker stub as defined by the stub hash table entry GEN_ENTRY. - IN_ARG contains the link info pointer. */ - -#define LDIL_R1 0x20200000 /* ldil LR'XXX,%r1 */ -#define BE_SR4_R1 0xe0202002 /* be,n RR'XXX(%sr4,%r1) */ - -#define BL_R1 0xe8200000 /* b,l .+8,%r1 */ -#define ADDIL_R1 0x28200000 /* addil LR'XXX,%r1,%r1 */ -#define DEPI_R1 0xd4201c1e /* depi 0,31,2,%r1 */ - -#define ADDIL_DP 0x2b600000 /* addil LR'XXX,%dp,%r1 */ -#define LDW_R1_R21 0x48350000 /* ldw RR'XXX(%sr0,%r1),%r21 */ -#define BV_R0_R21 0xeaa0c000 /* bv %r0(%r21) */ -#define LDW_R1_R19 0x48330000 /* ldw RR'XXX(%sr0,%r1),%r19 */ - -#define ADDIL_R19 0x2a600000 /* addil LR'XXX,%r19,%r1 */ -#define LDW_R1_DP 0x483b0000 /* ldw RR'XXX(%sr0,%r1),%dp */ - -#define LDSID_R21_R1 0x02a010a1 /* ldsid (%sr0,%r21),%r1 */ -#define MTSP_R1 0x00011820 /* mtsp %r1,%sr0 */ -#define BE_SR0_R21 0xe2a00000 /* be 0(%sr0,%r21) */ -#define STW_RP 0x6bc23fd1 /* stw %rp,-24(%sr0,%sp) */ - -#define BL22_RP 0xe800a002 /* b,l,n XXX,%rp */ -#define BL_RP 0xe8400002 /* b,l,n XXX,%rp */ -#define NOP 0x08000240 /* nop */ -#define LDW_RP 0x4bc23fd1 /* ldw -24(%sr0,%sp),%rp */ -#define LDSID_RP_R1 0x004010a1 /* ldsid (%sr0,%rp),%r1 */ -#define BE_SR0_RP 0xe0400002 /* be,n 0(%sr0,%rp) */ - -#ifndef R19_STUBS -#define R19_STUBS 1 -#endif - -#if R19_STUBS -#define LDW_R1_DLT LDW_R1_R19 -#else -#define LDW_R1_DLT LDW_R1_DP -#endif - -static bfd_boolean -hppa_build_one_stub (struct bfd_hash_entry *bh, void *in_arg) -{ - struct elf32_hppa_stub_hash_entry *hsh; - struct bfd_link_info *info; - struct elf32_hppa_link_hash_table *htab; - asection *stub_sec; - bfd *stub_bfd; - bfd_byte *loc; - bfd_vma sym_value; - bfd_vma insn; - bfd_vma off; - int val; - int size; - - /* Massage our args to the form they really have. */ - hsh = hppa_stub_hash_entry (bh); - info = (struct bfd_link_info *)in_arg; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - stub_sec = hsh->stub_sec; - - /* Make a note of the offset within the stubs for this entry. */ - hsh->stub_offset = stub_sec->size; - loc = stub_sec->contents + hsh->stub_offset; - - stub_bfd = stub_sec->owner; - - switch (hsh->stub_type) - { - case hppa_stub_long_branch: - /* Create the long branch. A long branch is formed with "ldil" - loading the upper bits of the target address into a register, - then branching with "be" which adds in the lower bits. - The "be" has its delay slot nullified. */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma); - - val = hppa_field_adjust (sym_value, 0, e_lrsel); - insn = hppa_rebuild_insn ((int) LDIL_R1, val, 21); - bfd_put_32 (stub_bfd, insn, loc); - - val = hppa_field_adjust (sym_value, 0, e_rrsel) >> 2; - insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17); - bfd_put_32 (stub_bfd, insn, loc + 4); - - size = 8; - break; - - case hppa_stub_long_branch_shared: - /* Branches are relative. This is where we are going to. */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma); - - /* And this is where we are coming from, more or less. */ - sym_value -= (hsh->stub_offset - + stub_sec->output_offset - + stub_sec->output_section->vma); - - bfd_put_32 (stub_bfd, (bfd_vma) BL_R1, loc); - val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_lrsel); - insn = hppa_rebuild_insn ((int) ADDIL_R1, val, 21); - bfd_put_32 (stub_bfd, insn, loc + 4); - - val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_rrsel) >> 2; - insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17); - bfd_put_32 (stub_bfd, insn, loc + 8); - size = 12; - break; - - case hppa_stub_import: - case hppa_stub_import_shared: - off = hsh->hh->eh.plt.offset; - if (off >= (bfd_vma) -2) - abort (); - - off &= ~ (bfd_vma) 1; - sym_value = (off - + htab->etab.splt->output_offset - + htab->etab.splt->output_section->vma - - elf_gp (htab->etab.splt->output_section->owner)); - - insn = ADDIL_DP; -#if R19_STUBS - if (hsh->stub_type == hppa_stub_import_shared) - insn = ADDIL_R19; -#endif - val = hppa_field_adjust (sym_value, 0, e_lrsel), - insn = hppa_rebuild_insn ((int) insn, val, 21); - bfd_put_32 (stub_bfd, insn, loc); - - /* It is critical to use lrsel/rrsel here because we are using - two different offsets (+0 and +4) from sym_value. If we use - lsel/rsel then with unfortunate sym_values we will round - sym_value+4 up to the next 2k block leading to a mis-match - between the lsel and rsel value. */ - val = hppa_field_adjust (sym_value, 0, e_rrsel); - insn = hppa_rebuild_insn ((int) LDW_R1_R21, val, 14); - bfd_put_32 (stub_bfd, insn, loc + 4); - - if (htab->multi_subspace) - { - val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rrsel); - insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14); - bfd_put_32 (stub_bfd, insn, loc + 8); - - bfd_put_32 (stub_bfd, (bfd_vma) LDSID_R21_R1, loc + 12); - bfd_put_32 (stub_bfd, (bfd_vma) MTSP_R1, loc + 16); - bfd_put_32 (stub_bfd, (bfd_vma) BE_SR0_R21, loc + 20); - bfd_put_32 (stub_bfd, (bfd_vma) STW_RP, loc + 24); - - size = 28; - } - else - { - bfd_put_32 (stub_bfd, (bfd_vma) BV_R0_R21, loc + 8); - val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rrsel); - insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14); - bfd_put_32 (stub_bfd, insn, loc + 12); - - size = 16; - } - - break; - - case hppa_stub_export: - /* Branches are relative. This is where we are going to. */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma); - - /* And this is where we are coming from. */ - sym_value -= (hsh->stub_offset - + stub_sec->output_offset - + stub_sec->output_section->vma); - - if (sym_value - 8 + (1 << (17 + 1)) >= (1 << (17 + 2)) - && (!htab->has_22bit_branch - || sym_value - 8 + (1 << (22 + 1)) >= (1 << (22 + 2)))) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): cannot reach %s, recompile with -ffunction-sections"), - hsh->target_section->owner, - stub_sec, - hsh->stub_offset, - hsh->bh_root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_fsel) >> 2; - if (!htab->has_22bit_branch) - insn = hppa_rebuild_insn ((int) BL_RP, val, 17); - else - insn = hppa_rebuild_insn ((int) BL22_RP, val, 22); - bfd_put_32 (stub_bfd, insn, loc); - - bfd_put_32 (stub_bfd, (bfd_vma) NOP, loc + 4); - bfd_put_32 (stub_bfd, (bfd_vma) LDW_RP, loc + 8); - bfd_put_32 (stub_bfd, (bfd_vma) LDSID_RP_R1, loc + 12); - bfd_put_32 (stub_bfd, (bfd_vma) MTSP_R1, loc + 16); - bfd_put_32 (stub_bfd, (bfd_vma) BE_SR0_RP, loc + 20); - - /* Point the function symbol at the stub. */ - hsh->hh->eh.root.u.def.section = stub_sec; - hsh->hh->eh.root.u.def.value = stub_sec->size; - - size = 24; - break; - - default: - BFD_FAIL (); - return FALSE; - } - - stub_sec->size += size; - return TRUE; -} - -#undef LDIL_R1 -#undef BE_SR4_R1 -#undef BL_R1 -#undef ADDIL_R1 -#undef DEPI_R1 -#undef LDW_R1_R21 -#undef LDW_R1_DLT -#undef LDW_R1_R19 -#undef ADDIL_R19 -#undef LDW_R1_DP -#undef LDSID_R21_R1 -#undef MTSP_R1 -#undef BE_SR0_R21 -#undef STW_RP -#undef BV_R0_R21 -#undef BL_RP -#undef NOP -#undef LDW_RP -#undef LDSID_RP_R1 -#undef BE_SR0_RP - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ - -static bfd_boolean -hppa_size_one_stub (struct bfd_hash_entry *bh, void *in_arg) -{ - struct elf32_hppa_stub_hash_entry *hsh; - struct elf32_hppa_link_hash_table *htab; - int size; - - /* Massage our args to the form they really have. */ - hsh = hppa_stub_hash_entry (bh); - htab = in_arg; - - if (hsh->stub_type == hppa_stub_long_branch) - size = 8; - else if (hsh->stub_type == hppa_stub_long_branch_shared) - size = 12; - else if (hsh->stub_type == hppa_stub_export) - size = 24; - else /* hppa_stub_import or hppa_stub_import_shared. */ - { - if (htab->multi_subspace) - size = 28; - else - size = 16; - } - - hsh->stub_sec->size += size; - return TRUE; -} - -/* Return nonzero if ABFD represents an HPPA ELF32 file. - Additionally we set the default architecture and machine. */ - -static bfd_boolean -elf32_hppa_object_p (bfd *abfd) -{ - Elf_Internal_Ehdr * i_ehdrp; - unsigned int flags; - - i_ehdrp = elf_elfheader (abfd); - if (strcmp (bfd_get_target (abfd), "elf32-hppa-linux") == 0) - { - /* GCC on hppa-linux produces binaries with OSABI=GNU, - but the kernel produces corefiles with OSABI=SysV. */ - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_GNU && - i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_NONE) /* aka SYSV */ - return FALSE; - } - else if (strcmp (bfd_get_target (abfd), "elf32-hppa-netbsd") == 0) - { - /* GCC on hppa-netbsd produces binaries with OSABI=NetBSD, - but the kernel produces corefiles with OSABI=SysV. */ - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_NETBSD && - i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_NONE) /* aka SYSV */ - return FALSE; - } - else - { - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_HPUX) - return FALSE; - } - - flags = i_ehdrp->e_flags; - switch (flags & (EF_PARISC_ARCH | EF_PARISC_WIDE)) - { - case EFA_PARISC_1_0: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 10); - case EFA_PARISC_1_1: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 11); - case EFA_PARISC_2_0: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 20); - case EFA_PARISC_2_0 | EF_PARISC_WIDE: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 25); - } - return TRUE; -} - -/* Create the .plt and .got sections, and set up our hash table - short-cuts to various dynamic sections. */ - -static bfd_boolean -elf32_hppa_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf32_hppa_link_hash_table *htab; - struct elf_link_hash_entry *eh; - - /* Don't try to create the .plt and .got twice. */ - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - if (htab->etab.splt != NULL) - return TRUE; - - /* Call the generic code to do most of the work. */ - if (! _bfd_elf_create_dynamic_sections (abfd, info)) - return FALSE; - - /* hppa-linux needs _GLOBAL_OFFSET_TABLE_ to be visible from the main - application, because __canonicalize_funcptr_for_compare needs it. */ - eh = elf_hash_table (info)->hgot; - eh->forced_local = 0; - eh->other = STV_DEFAULT; - return bfd_elf_link_record_dynamic_symbol (info, eh); -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf32_hppa_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *eh_dir, - struct elf_link_hash_entry *eh_ind) -{ - struct elf32_hppa_link_hash_entry *hh_dir, *hh_ind; - - hh_dir = hppa_elf_hash_entry (eh_dir); - hh_ind = hppa_elf_hash_entry (eh_ind); - - if (hh_ind->dyn_relocs != NULL - && eh_ind->root.type == bfd_link_hash_indirect) - { - if (hh_dir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **hdh_pp; - struct elf_dyn_relocs *hdh_p; - - /* Add reloc counts against the indirect sym to the direct sym - list. Merge any entries against the same section. */ - for (hdh_pp = &hh_ind->dyn_relocs; (hdh_p = *hdh_pp) != NULL; ) - { - struct elf_dyn_relocs *hdh_q; - - for (hdh_q = hh_dir->dyn_relocs; - hdh_q != NULL; - hdh_q = hdh_q->next) - if (hdh_q->sec == hdh_p->sec) - { -#if RELATIVE_DYNRELOCS - hdh_q->pc_count += hdh_p->pc_count; -#endif - hdh_q->count += hdh_p->count; - *hdh_pp = hdh_p->next; - break; - } - if (hdh_q == NULL) - hdh_pp = &hdh_p->next; - } - *hdh_pp = hh_dir->dyn_relocs; - } - - hh_dir->dyn_relocs = hh_ind->dyn_relocs; - hh_ind->dyn_relocs = NULL; - } - - if (eh_ind->root.type == bfd_link_hash_indirect) - { - hh_dir->plabel |= hh_ind->plabel; - hh_dir->tls_type |= hh_ind->tls_type; - hh_ind->tls_type = GOT_UNKNOWN; - } - - _bfd_elf_link_hash_copy_indirect (info, eh_dir, eh_ind); -} - -static int -elf32_hppa_optimized_tls_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED, - int r_type, int is_local ATTRIBUTE_UNUSED) -{ - /* For now we don't support linker optimizations. */ - return r_type; -} - -/* Return a pointer to the local GOT, PLT and TLS reference counts - for ABFD. Returns NULL if the storage allocation fails. */ - -static bfd_signed_vma * -hppa32_elf_local_refcounts (bfd *abfd) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - bfd_signed_vma *local_refcounts; - - local_refcounts = elf_local_got_refcounts (abfd); - if (local_refcounts == NULL) - { - bfd_size_type size; - - /* Allocate space for local GOT and PLT reference - counts. Done this way to save polluting elf_obj_tdata - with another target specific pointer. */ - size = symtab_hdr->sh_info; - size *= 2 * sizeof (bfd_signed_vma); - /* Add in space to store the local GOT TLS types. */ - size += symtab_hdr->sh_info; - local_refcounts = bfd_zalloc (abfd, size); - if (local_refcounts == NULL) - return NULL; - elf_local_got_refcounts (abfd) = local_refcounts; - memset (hppa_elf_local_got_tls_type (abfd), GOT_UNKNOWN, - symtab_hdr->sh_info); - } - return local_refcounts; -} - - -/* 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. At this point we haven't - necessarily read all the input files. */ - -static bfd_boolean -elf32_hppa_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **eh_syms; - const Elf_Internal_Rela *rela; - const Elf_Internal_Rela *rela_end; - struct elf32_hppa_link_hash_table *htab; - asection *sreloc; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - eh_syms = elf_sym_hashes (abfd); - sreloc = NULL; - - rela_end = relocs + sec->reloc_count; - for (rela = relocs; rela < rela_end; rela++) - { - enum { - NEED_GOT = 1, - NEED_PLT = 2, - NEED_DYNREL = 4, - PLT_PLABEL = 8 - }; - - unsigned int r_symndx, r_type; - struct elf32_hppa_link_hash_entry *hh; - int need_entry = 0; - - r_symndx = ELF32_R_SYM (rela->r_info); - - if (r_symndx < symtab_hdr->sh_info) - hh = NULL; - else - { - hh = hppa_elf_hash_entry (eh_syms[r_symndx - symtab_hdr->sh_info]); - while (hh->eh.root.type == bfd_link_hash_indirect - || hh->eh.root.type == bfd_link_hash_warning) - hh = hppa_elf_hash_entry (hh->eh.root.u.i.link); - } - - r_type = ELF32_R_TYPE (rela->r_info); - r_type = elf32_hppa_optimized_tls_reloc (info, r_type, hh == NULL); - - switch (r_type) - { - case R_PARISC_DLTIND14F: - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND21L: - /* This symbol requires a global offset table entry. */ - need_entry = NEED_GOT; - break; - - case R_PARISC_PLABEL14R: /* "Official" procedure labels. */ - case R_PARISC_PLABEL21L: - case R_PARISC_PLABEL32: - /* If the addend is non-zero, we break badly. */ - if (rela->r_addend != 0) - abort (); - - /* If we are creating a shared library, then we need to - create a PLT entry for all PLABELs, because PLABELs with - local symbols may be passed via a pointer to another - object. Additionally, output a dynamic relocation - pointing to the PLT entry. - - For executables, the original 32-bit ABI allowed two - different styles of PLABELs (function pointers): For - global functions, the PLABEL word points into the .plt - two bytes past a (function address, gp) pair, and for - local functions the PLABEL points directly at the - function. The magic +2 for the first type allows us to - differentiate between the two. As you can imagine, this - is a real pain when it comes to generating code to call - functions indirectly or to compare function pointers. - We avoid the mess by always pointing a PLABEL into the - .plt, even for local functions. */ - need_entry = PLT_PLABEL | NEED_PLT; - if (bfd_link_pic (info)) - need_entry |= NEED_DYNREL; - break; - - case R_PARISC_PCREL12F: - htab->has_12bit_branch = 1; - goto branch_common; - - case R_PARISC_PCREL17C: - case R_PARISC_PCREL17F: - htab->has_17bit_branch = 1; - goto branch_common; - - case R_PARISC_PCREL22F: - htab->has_22bit_branch = 1; - branch_common: - /* Function calls might need to go through the .plt, and - might require long branch stubs. */ - if (hh == NULL) - { - /* We know local syms won't need a .plt entry, and if - they need a long branch stub we can't guarantee that - we can reach the stub. So just flag an error later - if we're doing a shared link and find we need a long - branch stub. */ - continue; - } - else - { - /* Global symbols will need a .plt entry if they remain - global, and in most cases won't need a long branch - stub. Unfortunately, we have to cater for the case - where a symbol is forced local by versioning, or due - to symbolic linking, and we lose the .plt entry. */ - need_entry = NEED_PLT; - if (hh->eh.type == STT_PARISC_MILLI) - need_entry = 0; - } - break; - - case R_PARISC_SEGBASE: /* Used to set segment base. */ - case R_PARISC_SEGREL32: /* Relative reloc, used for unwind. */ - case R_PARISC_PCREL14F: /* PC relative load/store. */ - case R_PARISC_PCREL14R: - case R_PARISC_PCREL17R: /* External branches. */ - case R_PARISC_PCREL21L: /* As above, and for load/store too. */ - case R_PARISC_PCREL32: - /* We don't need to propagate the relocation if linking a - shared object since these are section relative. */ - continue; - - case R_PARISC_DPREL14F: /* Used for gp rel data load/store. */ - case R_PARISC_DPREL14R: - case R_PARISC_DPREL21L: - if (bfd_link_pic (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s can not be used when making a shared object; recompile with -fPIC"), - abfd, - elf_hppa_howto_table[r_type].name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - /* Fall through. */ - - case R_PARISC_DIR17F: /* Used for external branches. */ - case R_PARISC_DIR17R: - case R_PARISC_DIR14F: /* Used for load/store from absolute locn. */ - case R_PARISC_DIR14R: - case R_PARISC_DIR21L: /* As above, and for ext branches too. */ - case R_PARISC_DIR32: /* .word relocs. */ - /* We may want to output a dynamic relocation later. */ - need_entry = NEED_DYNREL; - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_PARISC_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, &hh->eh, rela->r_offset)) - return FALSE; - continue; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_PARISC_GNU_VTENTRY: - BFD_ASSERT (hh != NULL); - if (hh != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, &hh->eh, rela->r_addend)) - return FALSE; - continue; - - case R_PARISC_TLS_GD21L: - case R_PARISC_TLS_GD14R: - case R_PARISC_TLS_LDM21L: - case R_PARISC_TLS_LDM14R: - need_entry = NEED_GOT; - break; - - case R_PARISC_TLS_IE21L: - case R_PARISC_TLS_IE14R: - if (bfd_link_dll (info)) - info->flags |= DF_STATIC_TLS; - need_entry = NEED_GOT; - break; - - default: - continue; - } - - /* Now carry out our orders. */ - if (need_entry & NEED_GOT) - { - int tls_type = GOT_NORMAL; - - switch (r_type) - { - default: - break; - case R_PARISC_TLS_GD21L: - case R_PARISC_TLS_GD14R: - tls_type = GOT_TLS_GD; - break; - case R_PARISC_TLS_LDM21L: - case R_PARISC_TLS_LDM14R: - tls_type = GOT_TLS_LDM; - break; - case R_PARISC_TLS_IE21L: - case R_PARISC_TLS_IE14R: - tls_type = GOT_TLS_IE; - break; - } - - /* Allocate space for a GOT entry, as well as a dynamic - relocation for this entry. */ - if (htab->etab.sgot == NULL) - { - if (!elf32_hppa_create_dynamic_sections (htab->etab.dynobj, info)) - return FALSE; - } - - if (hh != NULL) - { - if (tls_type == GOT_TLS_LDM) - htab->tls_ldm_got.refcount += 1; - else - hh->eh.got.refcount += 1; - hh->tls_type |= tls_type; - } - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = hppa32_elf_local_refcounts (abfd); - if (local_got_refcounts == NULL) - return FALSE; - if (tls_type == GOT_TLS_LDM) - htab->tls_ldm_got.refcount += 1; - else - local_got_refcounts[r_symndx] += 1; - - hppa_elf_local_got_tls_type (abfd) [r_symndx] |= tls_type; - } - } - - if (need_entry & NEED_PLT) - { - /* If we are creating a shared library, and this is a reloc - against a weak symbol or a global symbol in a dynamic - object, then we will be creating an import stub and a - .plt entry for the symbol. Similarly, on a normal link - to symbols defined in a dynamic object we'll need the - import stub and a .plt entry. We don't know yet whether - the symbol is defined or not, so make an entry anyway and - clean up later in adjust_dynamic_symbol. */ - if ((sec->flags & SEC_ALLOC) != 0) - { - if (hh != NULL) - { - hh->eh.needs_plt = 1; - hh->eh.plt.refcount += 1; - - /* If this .plt entry is for a plabel, mark it so - that adjust_dynamic_symbol will keep the entry - even if it appears to be local. */ - if (need_entry & PLT_PLABEL) - hh->plabel = 1; - } - else if (need_entry & PLT_PLABEL) - { - bfd_signed_vma *local_got_refcounts; - bfd_signed_vma *local_plt_refcounts; - - local_got_refcounts = hppa32_elf_local_refcounts (abfd); - if (local_got_refcounts == NULL) - return FALSE; - local_plt_refcounts = (local_got_refcounts - + symtab_hdr->sh_info); - local_plt_refcounts[r_symndx] += 1; - } - } - } - - if ((need_entry & NEED_DYNREL) != 0 - && (sec->flags & SEC_ALLOC) != 0) - { - /* Flag this symbol as having a non-got, non-plt reference - so that we generate copy relocs if it turns out to be - dynamic. */ - if (hh != NULL) - hh->eh.non_got_ref = 1; - - /* If we are creating a shared library then we need to copy - the reloc into the shared library. However, if we are - linking with -Bsymbolic, we need only copy absolute - relocs or relocs against symbols that are not defined in - an object we are including in the link. PC- or DP- or - DLT-relative relocs against any local sym or global sym - with DEF_REGULAR set, can be discarded. At this point we - have not seen all the input files, so it is possible that - DEF_REGULAR is not set now but will be set later (it is - never cleared). We account for that possibility below by - storing information in the dyn_relocs field of the - hash table entry. - - A similar situation to the -Bsymbolic case occurs when - creating shared libraries and symbol visibility changes - render the symbol local. - - As it turns out, all the relocs we will be creating here - are absolute, so we cannot remove them on -Bsymbolic - links or visibility changes anyway. A STUB_REL reloc - is absolute too, as in that case it is the reloc in the - stub we will be creating, rather than copying the PCREL - reloc in the branch. - - 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 ((bfd_link_pic (info) - && (IS_ABSOLUTE_RELOC (r_type) - || (hh != NULL - && (!SYMBOLIC_BIND (info, &hh->eh) - || hh->eh.root.type == bfd_link_hash_defweak - || !hh->eh.def_regular)))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && hh != NULL - && (hh->eh.root.type == bfd_link_hash_defweak - || !hh->eh.def_regular))) - { - struct elf_dyn_relocs *hdh_p; - struct elf_dyn_relocs **hdh_head; - - /* Create a reloc section in dynobj and make room for - this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->etab.dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (hh != NULL) - { - hdh_head = &hh->dyn_relocs; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - asection *sr; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - sr = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (sr == NULL) - sr = sec; - - vpp = &elf_section_data (sr)->local_dynrel; - hdh_head = (struct elf_dyn_relocs **) vpp; - } - - hdh_p = *hdh_head; - if (hdh_p == NULL || hdh_p->sec != sec) - { - hdh_p = bfd_alloc (htab->etab.dynobj, sizeof *hdh_p); - if (hdh_p == NULL) - return FALSE; - hdh_p->next = *hdh_head; - *hdh_head = hdh_p; - hdh_p->sec = sec; - hdh_p->count = 0; -#if RELATIVE_DYNRELOCS - hdh_p->pc_count = 0; -#endif - } - - hdh_p->count += 1; -#if RELATIVE_DYNRELOCS - if (!IS_ABSOLUTE_RELOC (rtype)) - hdh_p->pc_count += 1; -#endif - } - } - } - - return TRUE; -} - -/* Return the section that should be marked against garbage collection - for a given relocation. */ - -static asection * -elf32_hppa_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rela, - struct elf_link_hash_entry *hh, - Elf_Internal_Sym *sym) -{ - if (hh != NULL) - switch ((unsigned int) ELF32_R_TYPE (rela->r_info)) - { - case R_PARISC_GNU_VTINHERIT: - case R_PARISC_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rela, hh, sym); -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf32_hppa_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 396: /* Linux/hppa */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 320; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf32_hppa_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/hppa 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; -} - -/* Our own version of hide_symbol, so that we can keep plt entries for - plabels. */ - -static void -elf32_hppa_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *eh, - bfd_boolean force_local) -{ - if (force_local) - { - eh->forced_local = 1; - if (eh->dynindx != -1) - { - eh->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - eh->dynstr_index); - } - - /* PR 16082: Remove version information from hidden symbol. */ - eh->verinfo.verdef = NULL; - eh->verinfo.vertree = NULL; - } - - /* STT_GNU_IFUNC symbol must go through PLT. */ - if (! hppa_elf_hash_entry (eh)->plabel - && eh->type != STT_GNU_IFUNC) - { - eh->needs_plt = 0; - eh->plt = elf_hash_table (info)->init_plt_offset; - } -} - -/* Find any dynamic relocs that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *eh) -{ - struct elf32_hppa_link_hash_entry *hh; - struct elf_dyn_relocs *hdh_p; - - hh = hppa_elf_hash_entry (eh); - for (hdh_p = hh->dyn_relocs; hdh_p != NULL; hdh_p = hdh_p->next) - { - asection *sec = hdh_p->sec->output_section; - - if (sec != NULL && (sec->flags & SEC_READONLY) != 0) - return hdh_p->sec; - } - return NULL; -} - -/* Return true if we have dynamic relocs against H or any of its weak - aliases, that apply to read-only sections. Cannot be used after - size_dynamic_sections. */ - -static bfd_boolean -alias_readonly_dynrelocs (struct elf_link_hash_entry *eh) -{ - struct elf32_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - do - { - if (readonly_dynrelocs (&hh->eh)) - return TRUE; - hh = hppa_elf_hash_entry (hh->eh.u.alias); - } while (hh != NULL && &hh->eh != eh); - - return FALSE; -} - -/* 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 -elf32_hppa_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *eh) -{ - struct elf32_hppa_link_hash_table *htab; - asection *sec, *srel; - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later. */ - if (eh->type == STT_FUNC - || eh->needs_plt) - { - bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, eh) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh)); - /* Discard dyn_relocs when non-pic if we've decided that a - function symbol is local. */ - if (!bfd_link_pic (info) && local) - hppa_elf_hash_entry (eh)->dyn_relocs = NULL; - - /* If the symbol is used by a plabel, we must allocate a PLT slot. - The refcounts are not reliable when it has been hidden since - hide_symbol can be called before the plabel flag is set. */ - if (hppa_elf_hash_entry (eh)->plabel) - eh->plt.refcount = 1; - - /* Note that unlike some other backends, the refcount is not - incremented for a non-call (and non-plabel) function reference. */ - else if (eh->plt.refcount <= 0 - || local) - { - /* The .plt entry is not needed when: - a) Garbage collection has removed all references to the - symbol, or - b) We know for certain the symbol is defined in this - object, and it's not a weak definition, nor is the symbol - used by a plabel relocation. Either this object is the - application or we are doing a shared symbolic link. */ - eh->plt.offset = (bfd_vma) -1; - eh->needs_plt = 0; - } - - /* Unlike other targets, elf32-hppa.c does not define a function - symbol in a non-pic executable on PLT stub code, so we don't - have a local definition in that case. ie. dyn_relocs can't - be discarded. */ - - /* Function symbols can't have copy relocs. */ - return TRUE; - } - else - eh->plt.offset = (bfd_vma) -1; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - /* 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 (eh->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (eh); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - eh->root.u.def.section = def->root.u.def.section; - eh->root.u.def.value = def->root.u.def.value; - if (def->root.u.def.section == htab->etab.sdynbss - || def->root.u.def.section == htab->etab.sdynrelro) - hppa_elf_hash_entry (eh)->dyn_relocs = NULL; - 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 (bfd_link_pic (info)) - 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 (!eh->non_got_ref) - return TRUE; - - /* If -z nocopyreloc was given, we won't generate them either. */ - if (info->nocopyreloc) - return TRUE; - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (ELIMINATE_COPY_RELOCS - && !alias_readonly_dynrelocs (eh)) - 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. */ - if ((eh->root.u.def.section->flags & SEC_READONLY) != 0) - { - sec = htab->etab.sdynrelro; - srel = htab->etab.sreldynrelro; - } - else - { - sec = htab->etab.sdynbss; - srel = htab->etab.srelbss; - } - if ((eh->root.u.def.section->flags & SEC_ALLOC) != 0 && eh->size != 0) - { - /* We must generate a COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. */ - srel->size += sizeof (Elf32_External_Rela); - eh->needs_copy = 1; - } - - /* We no longer want dyn_relocs. */ - hppa_elf_hash_entry (eh)->dyn_relocs = NULL; - return _bfd_elf_adjust_dynamic_copy (info, eh, sec); -} - -/* If EH is undefined, make it dynamic if that makes sense. */ - -static bfd_boolean -ensure_undef_dynamic (struct bfd_link_info *info, - struct elf_link_hash_entry *eh) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (htab->dynamic_sections_created - && (eh->root.type == bfd_link_hash_undefweak - || eh->root.type == bfd_link_hash_undefined) - && eh->dynindx == -1 - && !eh->forced_local - && eh->type != STT_PARISC_MILLI - && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh) - && ELF_ST_VISIBILITY (eh->other) == STV_DEFAULT) - return bfd_elf_link_record_dynamic_symbol (info, eh); - return TRUE; -} - -/* Allocate space in the .plt for entries that won't have relocations. - ie. plabel entries. */ - -static bfd_boolean -allocate_plt_static (struct elf_link_hash_entry *eh, void *inf) -{ - struct bfd_link_info *info; - struct elf32_hppa_link_hash_table *htab; - struct elf32_hppa_link_hash_entry *hh; - asection *sec; - - if (eh->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - hh = hppa_elf_hash_entry (eh); - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - if (htab->etab.dynamic_sections_created - && eh->plt.refcount > 0) - { - if (!ensure_undef_dynamic (info, eh)) - return FALSE; - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), eh)) - { - /* Allocate these later. From this point on, h->plabel - means that the plt entry is only used by a plabel. - We'll be using a normal plt entry for this symbol, so - clear the plabel indicator. */ - - hh->plabel = 0; - } - else if (hh->plabel) - { - /* Make an entry in the .plt section for plabel references - that won't have a .plt entry for other reasons. */ - sec = htab->etab.splt; - eh->plt.offset = sec->size; - sec->size += PLT_ENTRY_SIZE; - if (bfd_link_pic (info)) - htab->etab.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - /* No .plt entry needed. */ - eh->plt.offset = (bfd_vma) -1; - eh->needs_plt = 0; - } - } - else - { - eh->plt.offset = (bfd_vma) -1; - eh->needs_plt = 0; - } - - return TRUE; -} - -/* Calculate size of GOT entries for symbol given its TLS_TYPE. */ - -static inline unsigned int -got_entries_needed (int tls_type) -{ - unsigned int need = 0; - - if ((tls_type & GOT_NORMAL) != 0) - need += GOT_ENTRY_SIZE; - if ((tls_type & GOT_TLS_GD) != 0) - need += GOT_ENTRY_SIZE * 2; - if ((tls_type & GOT_TLS_IE) != 0) - need += GOT_ENTRY_SIZE; - return need; -} - -/* Calculate size of relocs needed for symbol given its TLS_TYPE and - NEEDed GOT entries. KNOWN says a TPREL offset can be calculated - at link time. */ - -static inline unsigned int -got_relocs_needed (int tls_type, unsigned int need, bfd_boolean known) -{ - /* All the entries we allocated need relocs. - Except IE in executable with a local symbol. We could also omit - the DTPOFF reloc on the second word of a GD entry under the same - condition as that for IE, but ld.so might want to differentiate - LD and GD entries at some stage. */ - if ((tls_type & GOT_TLS_IE) != 0 && known) - need -= GOT_ENTRY_SIZE; - return need * sizeof (Elf32_External_Rela) / GOT_ENTRY_SIZE; -} - -/* Allocate space in .plt, .got and associated reloc sections for - global syms. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf) -{ - struct bfd_link_info *info; - struct elf32_hppa_link_hash_table *htab; - asection *sec; - struct elf32_hppa_link_hash_entry *hh; - struct elf_dyn_relocs *hdh_p; - - if (eh->root.type == bfd_link_hash_indirect) - return TRUE; - - info = inf; - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - hh = hppa_elf_hash_entry (eh); - - if (htab->etab.dynamic_sections_created - && eh->plt.offset != (bfd_vma) -1 - && !hh->plabel - && eh->plt.refcount > 0) - { - /* Make an entry in the .plt section. */ - sec = htab->etab.splt; - eh->plt.offset = sec->size; - sec->size += PLT_ENTRY_SIZE; - - /* We also need to make an entry in the .rela.plt section. */ - htab->etab.srelplt->size += sizeof (Elf32_External_Rela); - htab->need_plt_stub = 1; - } - - if (eh->got.refcount > 0) - { - unsigned int need; - - if (!ensure_undef_dynamic (info, eh)) - return FALSE; - - sec = htab->etab.sgot; - eh->got.offset = sec->size; - need = got_entries_needed (hh->tls_type); - sec->size += need; - if (htab->etab.dynamic_sections_created - && (bfd_link_pic (info) - || (eh->dynindx != -1 - && !SYMBOL_REFERENCES_LOCAL (info, eh))) - && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh)) - { - bfd_boolean tprel_known = (bfd_link_executable (info) - && SYMBOL_REFERENCES_LOCAL (info, eh)); - htab->etab.srelgot->size - += got_relocs_needed (hh->tls_type, need, tprel_known); - } - } - else - eh->got.offset = (bfd_vma) -1; - - /* If no dynamic sections we can't have dynamic relocs. */ - if (!htab->etab.dynamic_sections_created) - hh->dyn_relocs = NULL; - - /* Discard relocs on undefined syms with non-default visibility. */ - else if ((eh->root.type == bfd_link_hash_undefined - && ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh)) - hh->dyn_relocs = NULL; - - if (hh->dyn_relocs == NULL) - return TRUE; - - /* If this is a -Bsymbolic shared link, then we need to discard all - space allocated for dynamic pc-relative relocs against symbols - defined in a regular object. For the normal shared case, discard - space for relocs that have become local due to symbol visibility - changes. */ - if (bfd_link_pic (info)) - { -#if RELATIVE_DYNRELOCS - if (SYMBOL_CALLS_LOCAL (info, eh)) - { - struct elf_dyn_relocs **hdh_pp; - - for (hdh_pp = &hh->dyn_relocs; (hdh_p = *hdh_pp) != NULL; ) - { - hdh_p->count -= hdh_p->pc_count; - hdh_p->pc_count = 0; - if (hdh_p->count == 0) - *hdh_pp = hdh_p->next; - else - hdh_pp = &hdh_p->next; - } - } -#endif - - if (hh->dyn_relocs != NULL) - { - if (!ensure_undef_dynamic (info, eh)) - 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 (eh->dynamic_adjusted - && !eh->def_regular - && !ELF_COMMON_DEF_P (eh)) - { - if (!ensure_undef_dynamic (info, eh)) - return FALSE; - - if (eh->dynindx == -1) - hh->dyn_relocs = NULL; - } - else - hh->dyn_relocs = NULL; - } - - /* Finally, allocate space. */ - for (hdh_p = hh->dyn_relocs; hdh_p != NULL; hdh_p = hdh_p->next) - { - asection *sreloc = elf_section_data (hdh_p->sec)->sreloc; - sreloc->size += hdh_p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* This function is called via elf_link_hash_traverse to force - millicode symbols local so they do not end up as globals in the - dynamic symbol table. We ought to be able to do this in - adjust_dynamic_symbol, but our adjust_dynamic_symbol is not called - for all dynamic symbols. Arguably, this is a bug in - elf_adjust_dynamic_symbol. */ - -static bfd_boolean -clobber_millicode_symbols (struct elf_link_hash_entry *eh, - struct bfd_link_info *info) -{ - if (eh->type == STT_PARISC_MILLI - && !eh->forced_local) - { - elf32_hppa_hide_symbol (info, eh, TRUE); - } - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *eh, void *inf) -{ - asection *sec; - - if (eh->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (eh); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, eh->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf32_hppa_link_hash_table *htab; - bfd *dynobj; - bfd *ibfd; - asection *sec; - bfd_boolean relocs; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->etab.dynobj; - if (dynobj == NULL) - abort (); - - if (htab->etab.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - sec = bfd_get_linker_section (dynobj, ".interp"); - if (sec == NULL) - abort (); - sec->size = sizeof ELF_DYNAMIC_INTERPRETER; - sec->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - - /* Force millicode symbols local. */ - elf_link_hash_traverse (&htab->etab, - clobber_millicode_symbols, - info); - } - - /* Set up .got and .plt offsets for local syms, and space for local - dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - bfd_signed_vma *local_plt; - bfd_signed_vma *end_local_plt; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - char *local_tls_type; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - struct elf_dyn_relocs *hdh_p; - - for (hdh_p = ((struct elf_dyn_relocs *) - elf_section_data (sec)->local_dynrel); - hdh_p != NULL; - hdh_p = hdh_p->next) - { - if (!bfd_is_abs_section (hdh_p->sec) - && bfd_is_abs_section (hdh_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 (hdh_p->count != 0) - { - srel = elf_section_data (hdh_p->sec)->sreloc; - srel->size += hdh_p->count * sizeof (Elf32_External_Rela); - if ((hdh_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 = hppa_elf_local_got_tls_type (ibfd); - sec = htab->etab.sgot; - srel = htab->etab.srelgot; - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - unsigned int need; - - *local_got = sec->size; - need = got_entries_needed (*local_tls_type); - sec->size += need; - if (bfd_link_pic (info)) - { - bfd_boolean tprel_known = bfd_link_executable (info); - htab->etab.srelgot->size - += got_relocs_needed (*local_tls_type, need, tprel_known); - } - } - else - *local_got = (bfd_vma) -1; - - ++local_tls_type; - } - - local_plt = end_local_got; - end_local_plt = local_plt + locsymcount; - if (! htab->etab.dynamic_sections_created) - { - /* Won't be used, but be safe. */ - for (; local_plt < end_local_plt; ++local_plt) - *local_plt = (bfd_vma) -1; - } - else - { - sec = htab->etab.splt; - srel = htab->etab.srelplt; - for (; local_plt < end_local_plt; ++local_plt) - { - if (*local_plt > 0) - { - *local_plt = sec->size; - sec->size += PLT_ENTRY_SIZE; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); - } - else - *local_plt = (bfd_vma) -1; - } - } - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate 2 got entries and 1 dynamic reloc for - R_PARISC_TLS_DTPMOD32 relocs. */ - htab->tls_ldm_got.offset = htab->etab.sgot->size; - htab->etab.sgot->size += (GOT_ENTRY_SIZE * 2); - htab->etab.srelgot->size += sizeof (Elf32_External_Rela); - } - else - htab->tls_ldm_got.offset = -1; - - /* Do all the .plt entries without relocs first. The dynamic linker - uses the last .plt reloc to find the end of the .plt (and hence - the start of the .got) for lazy linking. */ - elf_link_hash_traverse (&htab->etab, allocate_plt_static, info); - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->etab, allocate_dynrelocs, info); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - relocs = FALSE; - for (sec = dynobj->sections; sec != NULL; sec = sec->next) - { - if ((sec->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (sec == htab->etab.splt) - { - if (htab->need_plt_stub) - { - /* Make space for the plt stub at the end of the .plt - section. We want this stub right at the end, up - against the .got section. */ - int gotalign = bfd_section_alignment (dynobj, htab->etab.sgot); - int pltalign = bfd_section_alignment (dynobj, sec); - bfd_size_type mask; - - if (gotalign > pltalign) - (void) bfd_set_section_alignment (dynobj, sec, gotalign); - mask = ((bfd_size_type) 1 << gotalign) - 1; - sec->size = (sec->size + sizeof (plt_stub) + mask) & ~mask; - } - } - else if (sec == htab->etab.sgot - || sec == htab->etab.sdynbss - || sec == htab->etab.sdynrelro) - ; - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, sec), ".rela")) - { - if (sec->size != 0) - { - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (sec != htab->etab.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - sec->reloc_count = 0; - } - } - else - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (sec->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. */ - sec->flags |= SEC_EXCLUDE; - continue; - } - - if ((sec->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. Zero it, because - we may not fill in all the reloc sections. */ - sec->contents = bfd_zalloc (dynobj, sec->size); - if (sec->contents == NULL) - return FALSE; - } - - if (htab->etab.dynamic_sections_created) - { - /* Like IA-64 and HPPA64, always create a DT_PLTGOT. It - actually has nothing to do with the PLT, it is how we - communicate the LTP value of a load module to the dynamic - linker. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (!add_dynamic_entry (DT_PLTGOT, 0)) - return FALSE; - - /* Add some entries to the .dynamic section. We fill in the - values later, in elf32_hppa_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. */ - if (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->etab.srelplt->size != 0) - { - if (!add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->etab, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* External entry points for sizing and building linker stubs. */ - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ - -int -elf32_hppa_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - bfd_size_type amt; - struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info); - - if (htab == NULL) - return -1; - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - if (top_id < section->id) - top_id = section->id; - } - } - htab->bfd_count = bfd_count; - - amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = bfd_zmalloc (amt); - if (htab->stub_group == NULL) - return -1; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - { - if ((section->flags & SEC_CODE) != 0) - input_list[section->index] = NULL; - } - - return 1; -} - -/* The linker repeatedly calls this function for each input section, - in the order that input sections are linked into output sections. - Build lists of input sections to determine groupings between which - we may insert linker stubs. */ - -void -elf32_hppa_next_input_section (struct bfd_link_info *info, asection *isec) -{ - struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info); - - if (htab == NULL) - return; - - if (isec->output_section->index <= htab->top_index) - { - asection **list = htab->input_list + isec->output_section->index; - if (*list != bfd_abs_section_ptr) - { - /* Steal the link_sec pointer for our list. */ -#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) - /* This happens to make the list in reverse order, - which is what we want. */ - PREV_SEC (isec) = *list; - *list = isec; - } - } -} - -/* See whether we can group stub sections together. Grouping stub - sections may result in fewer stubs. More importantly, we need to - put all .init* and .fini* stubs at the beginning of the .init or - .fini output sections respectively, because glibc splits the - _init and _fini functions into multiple parts. Putting a stub in - the middle of a function is not a good idea. */ - -static void -group_sections (struct elf32_hppa_link_hash_table *htab, - bfd_size_type stub_group_size, - bfd_boolean stubs_always_before_branch) -{ - asection **list = htab->input_list + htab->top_index; - do - { - asection *tail = *list; - if (tail == bfd_abs_section_ptr) - continue; - while (tail != NULL) - { - asection *curr; - asection *prev; - bfd_size_type total; - bfd_boolean big_sec; - - curr = tail; - total = tail->size; - big_sec = total >= stub_group_size; - - while ((prev = PREV_SEC (curr)) != NULL - && ((total += curr->output_offset - prev->output_offset) - < stub_group_size)) - curr = prev; - - /* OK, the size from the start of CURR to the end is less - than 240000 bytes and thus can be handled by one stub - section. (or the tail section is itself larger than - 240000 bytes, in which case we may be toast.) - We should really be keeping track of the total size of - stubs added here, as stubs contribute to the final output - section size. That's a little tricky, and this way will - only break if stubs added total more than 22144 bytes, or - 2768 long branch stubs. It seems unlikely for more than - 2768 different functions to be called, especially from - code only 240000 bytes long. This limit used to be - 250000, but c++ code tends to generate lots of little - functions, and sometimes violated the assumption. */ - do - { - prev = PREV_SEC (tail); - /* Set up this stub group. */ - htab->stub_group[tail->id].link_sec = curr; - } - while (tail != curr && (tail = prev) != NULL); - - /* But wait, there's more! Input sections up to 240000 - bytes before the stub section can be handled by it too. - Don't do this if we have a really large section after the - stubs, as adding more stubs increases the chance that - branches may not reach into the stub section. */ - if (!stubs_always_before_branch && !big_sec) - { - total = 0; - while (prev != NULL - && ((total += tail->output_offset - prev->output_offset) - < stub_group_size)) - { - tail = prev; - prev = PREV_SEC (tail); - htab->stub_group[tail->id].link_sec = curr; - } - } - tail = prev; - } - } - while (list-- != htab->input_list); - free (htab->input_list); -#undef PREV_SEC -} - -/* Read in all local syms for all input bfds, and create hash entries - for export stubs if we are building a multi-subspace shared lib. - Returns -1 on error, 1 if export stubs created, 0 otherwise. */ - -static int -get_local_syms (bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *info) -{ - unsigned int bfd_indx; - Elf_Internal_Sym *local_syms, **all_local_syms; - int stub_changed = 0; - struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info); - - if (htab == NULL) - return -1; - - /* We want to read in symbol extension records only once. To do this - we need to read in the local symbols in parallel and save them for - later use; so hold pointers to the local symbols in an array. */ - bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count; - all_local_syms = bfd_zmalloc (amt); - htab->all_local_syms = all_local_syms; - if (all_local_syms == NULL) - return -1; - - /* Walk over all the input BFDs, swapping in local symbols. - If we are creating a shared library, create hash entries for the - export stubs. */ - for (bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* We need an array of the local symbols attached to the input bfd. */ - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - { - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - /* Cache them for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - if (local_syms == NULL) - return -1; - - all_local_syms[bfd_indx] = local_syms; - - if (bfd_link_pic (info) && htab->multi_subspace) - { - struct elf_link_hash_entry **eh_syms; - struct elf_link_hash_entry **eh_symend; - unsigned int symcount; - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - eh_syms = (struct elf_link_hash_entry **) elf_sym_hashes (input_bfd); - eh_symend = (struct elf_link_hash_entry **) (eh_syms + symcount); - - /* Look through the global syms for functions; We need to - build export stubs for all globally visible functions. */ - for (; eh_syms < eh_symend; eh_syms++) - { - struct elf32_hppa_link_hash_entry *hh; - - hh = hppa_elf_hash_entry (*eh_syms); - - while (hh->eh.root.type == bfd_link_hash_indirect - || hh->eh.root.type == bfd_link_hash_warning) - hh = hppa_elf_hash_entry (hh->eh.root.u.i.link); - - /* At this point in the link, undefined syms have been - resolved, so we need to check that the symbol was - defined in this BFD. */ - if ((hh->eh.root.type == bfd_link_hash_defined - || hh->eh.root.type == bfd_link_hash_defweak) - && hh->eh.type == STT_FUNC - && hh->eh.root.u.def.section->output_section != NULL - && (hh->eh.root.u.def.section->output_section->owner - == output_bfd) - && hh->eh.root.u.def.section->owner == input_bfd - && hh->eh.def_regular - && !hh->eh.forced_local - && ELF_ST_VISIBILITY (hh->eh.other) == STV_DEFAULT) - { - asection *sec; - const char *stub_name; - struct elf32_hppa_stub_hash_entry *hsh; - - sec = hh->eh.root.u.def.section; - stub_name = hh_name (hh); - hsh = hppa_stub_hash_lookup (&htab->bstab, - stub_name, - FALSE, FALSE); - if (hsh == NULL) - { - hsh = hppa_add_stub (stub_name, sec, htab); - if (!hsh) - return -1; - - hsh->target_value = hh->eh.root.u.def.value; - hsh->target_section = hh->eh.root.u.def.section; - hsh->stub_type = hppa_stub_export; - hsh->hh = hh; - stub_changed = 1; - } - else - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: duplicate export stub %s"), - input_bfd, stub_name); - } - } - } - } - } - - return stub_changed; -} - -/* Determine and set the size of the stub section for a final link. - - The basic idea here is to examine all the relocations looking for - PC-relative calls to a target that is unreachable with a "bl" - instruction. */ - -bfd_boolean -elf32_hppa_size_stubs - (bfd *output_bfd, bfd *stub_bfd, struct bfd_link_info *info, - bfd_boolean multi_subspace, bfd_signed_vma group_size, - asection * (*add_stub_section) (const char *, asection *), - void (*layout_sections_again) (void)) -{ - bfd_size_type stub_group_size; - bfd_boolean stubs_always_before_branch; - bfd_boolean stub_changed; - struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info); - - if (htab == NULL) - return FALSE; - - /* Stash our params away. */ - htab->stub_bfd = stub_bfd; - htab->multi_subspace = multi_subspace; - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; - stubs_always_before_branch = group_size < 0; - if (group_size < 0) - stub_group_size = -group_size; - else - stub_group_size = group_size; - if (stub_group_size == 1) - { - /* Default values. */ - if (stubs_always_before_branch) - { - stub_group_size = 7680000; - if (htab->has_17bit_branch || htab->multi_subspace) - stub_group_size = 240000; - if (htab->has_12bit_branch) - stub_group_size = 7500; - } - else - { - stub_group_size = 6971392; - if (htab->has_17bit_branch || htab->multi_subspace) - stub_group_size = 217856; - if (htab->has_12bit_branch) - stub_group_size = 6808; - } - } - - group_sections (htab, stub_group_size, stubs_always_before_branch); - - switch (get_local_syms (output_bfd, info->input_bfds, info)) - { - default: - if (htab->all_local_syms) - goto error_ret_free_local; - return FALSE; - - case 0: - stub_changed = FALSE; - break; - - case 1: - stub_changed = TRUE; - break; - } - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - asection *stub_sec; - - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - local_syms = htab->all_local_syms[bfd_indx]; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - enum elf32_hppa_stub_type stub_type; - struct elf32_hppa_stub_hash_entry *hsh; - asection *sym_sec; - bfd_vma sym_value; - bfd_vma destination; - struct elf32_hppa_link_hash_entry *hh; - char *stub_name; - const asection *id_sec; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED) - { - bfd_set_error (bfd_error_bad_value); - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - goto error_ret_free_local; - } - - /* Only look for stubs on call instructions. */ - if (r_type != (unsigned int) R_PARISC_PCREL12F - && r_type != (unsigned int) R_PARISC_PCREL17F - && r_type != (unsigned int) R_PARISC_PCREL22F) - continue; - - /* Now determine the call target, its name, value, - section. */ - sym_sec = NULL; - sym_value = 0; - destination = 0; - hh = NULL; - if (r_indx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - Elf_Internal_Sym *sym; - Elf_Internal_Shdr *hdr; - unsigned int shndx; - - sym = local_syms + r_indx; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - sym_value = sym->st_value; - shndx = sym->st_shndx; - if (shndx < elf_numsections (input_bfd)) - { - hdr = elf_elfsections (input_bfd)[shndx]; - sym_sec = hdr->bfd_section; - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - } - else - { - /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hh = hppa_elf_hash_entry (elf_sym_hashes (input_bfd)[e_indx]); - - while (hh->eh.root.type == bfd_link_hash_indirect - || hh->eh.root.type == bfd_link_hash_warning) - hh = hppa_elf_hash_entry (hh->eh.root.u.i.link); - - if (hh->eh.root.type == bfd_link_hash_defined - || hh->eh.root.type == bfd_link_hash_defweak) - { - sym_sec = hh->eh.root.u.def.section; - sym_value = hh->eh.root.u.def.value; - if (sym_sec->output_section != NULL) - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - else if (hh->eh.root.type == bfd_link_hash_undefweak) - { - if (! bfd_link_pic (info)) - continue; - } - else if (hh->eh.root.type == bfd_link_hash_undefined) - { - if (! (info->unresolved_syms_in_objects == RM_IGNORE - && (ELF_ST_VISIBILITY (hh->eh.other) - == STV_DEFAULT) - && hh->eh.type != STT_PARISC_MILLI)) - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - } - - /* Determine what (if any) linker stub is needed. */ - stub_type = hppa_type_of_stub (section, irela, hh, - destination, info); - if (stub_type == hppa_stub_none) - continue; - - /* Support for grouping stub sections. */ - id_sec = htab->stub_group[section->id].link_sec; - - /* Get the name of this stub. */ - stub_name = hppa_stub_name (id_sec, sym_sec, hh, irela); - if (!stub_name) - goto error_ret_free_internal; - - hsh = hppa_stub_hash_lookup (&htab->bstab, - stub_name, - FALSE, FALSE); - if (hsh != NULL) - { - /* The proper stub has already been created. */ - free (stub_name); - continue; - } - - hsh = hppa_add_stub (stub_name, section, htab); - if (hsh == NULL) - { - free (stub_name); - goto error_ret_free_internal; - } - - hsh->target_value = sym_value; - hsh->target_section = sym_sec; - hsh->stub_type = stub_type; - if (bfd_link_pic (info)) - { - if (stub_type == hppa_stub_import) - hsh->stub_type = hppa_stub_import_shared; - else if (stub_type == hppa_stub_long_branch) - hsh->stub_type = hppa_stub_long_branch_shared; - } - hsh->hh = hh; - stub_changed = TRUE; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - } - - if (!stub_changed) - break; - - /* OK, we've added some stubs. Find out the new size of the - stub sections. */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - stub_sec->size = 0; - - bfd_hash_traverse (&htab->bstab, hppa_size_one_stub, htab); - - /* Ask the linker to do its stuff. */ - (*htab->layout_sections_again) (); - stub_changed = FALSE; - } - - free (htab->all_local_syms); - return TRUE; - - error_ret_free_local: - free (htab->all_local_syms); - return FALSE; -} - -/* For a final link, this function is called after we have sized the - stubs to provide a value for __gp. */ - -bfd_boolean -elf32_hppa_set_gp (bfd *abfd, struct bfd_link_info *info) -{ - struct bfd_link_hash_entry *h; - asection *sec = NULL; - bfd_vma gp_val = 0; - - h = bfd_link_hash_lookup (info->hash, "$global$", FALSE, FALSE, FALSE); - - if (h != NULL - && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - { - gp_val = h->u.def.value; - sec = h->u.def.section; - } - else - { - asection *splt = bfd_get_section_by_name (abfd, ".plt"); - asection *sgot = bfd_get_section_by_name (abfd, ".got"); - - /* Choose to point our LTP at, in this order, one of .plt, .got, - or .data, if these sections exist. In the case of choosing - .plt try to make the LTP ideal for addressing anywhere in the - .plt or .got with a 14 bit signed offset. Typically, the end - of the .plt is the start of the .got, so choose .plt + 0x2000 - if either the .plt or .got is larger than 0x2000. If both - the .plt and .got are smaller than 0x2000, choose the end of - the .plt section. */ - sec = strcmp (bfd_get_target (abfd), "elf32-hppa-netbsd") == 0 - ? NULL : splt; - if (sec != NULL) - { - gp_val = sec->size; - if (gp_val > 0x2000 || (sgot && sgot->size > 0x2000)) - { - gp_val = 0x2000; - } - } - else - { - sec = sgot; - if (sec != NULL) - { - if (strcmp (bfd_get_target (abfd), "elf32-hppa-netbsd") != 0) - { - /* We know we don't have a .plt. If .got is large, - offset our LTP. */ - if (sec->size > 0x2000) - gp_val = 0x2000; - } - } - else - { - /* No .plt or .got. Who cares what the LTP is? */ - sec = bfd_get_section_by_name (abfd, ".data"); - } - } - - if (h != NULL) - { - h->type = bfd_link_hash_defined; - h->u.def.value = gp_val; - if (sec != NULL) - h->u.def.section = sec; - else - h->u.def.section = bfd_abs_section_ptr; - } - } - - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) - { - if (sec != NULL && sec->output_section != NULL) - gp_val += sec->output_section->vma + sec->output_offset; - - elf_gp (abfd) = gp_val; - } - return TRUE; -} - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. We also set up the .plt entries for statically linked PIC - functions here. This function is called via hppaelf_finish in the - linker. */ - -bfd_boolean -elf32_hppa_build_stubs (struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - struct elf32_hppa_link_hash_table *htab; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0 - && stub_sec->size != 0) - { - /* Allocate memory to hold the linker stubs. */ - stub_sec->contents = bfd_zalloc (htab->stub_bfd, stub_sec->size); - if (stub_sec->contents == NULL) - return FALSE; - stub_sec->size = 0; - } - - /* Build the stubs as directed by the stub hash table. */ - table = &htab->bstab; - bfd_hash_traverse (table, hppa_build_one_stub, info); - - return TRUE; -} - -/* Return the base vma address which should be subtracted from the real - address when resolving a 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 R_PARISC_TLS_TPOFF*.. */ - -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; - /* hppa TLS ABI is variant I and static TLS block start just after - tcbhead structure which has 2 pointer fields. */ - return (address - htab->tls_sec->vma - + align_power ((bfd_vma) 8, htab->tls_sec->alignment_power)); -} - -/* Perform a final link. */ - -static bfd_boolean -elf32_hppa_final_link (bfd *abfd, struct bfd_link_info *info) -{ - struct stat buf; - - /* Invoke the regular ELF linker to do all the work. */ - if (!bfd_elf_final_link (abfd, info)) - return FALSE; - - /* If we're producing a final executable, sort the contents of the - unwind section. */ - if (bfd_link_relocatable (info)) - return TRUE; - - /* Do not attempt to sort non-regular files. This is here - especially for configure scripts and kernel builds which run - tests with "ld [...] -o /dev/null". */ - if (stat (abfd->filename, &buf) != 0 - || !S_ISREG(buf.st_mode)) - return TRUE; - - return elf_hppa_sort_unwind (abfd); -} - -/* Record the lowest address for the data and text segments. */ - -static void -hppa_record_segment_addr (bfd *abfd, asection *section, void *data) -{ - struct elf32_hppa_link_hash_table *htab; - - htab = (struct elf32_hppa_link_hash_table*) data; - if (htab == NULL) - return; - - if ((section->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma value; - Elf_Internal_Phdr *p; - - p = _bfd_elf_find_segment_containing_section (abfd, section->output_section); - BFD_ASSERT (p != NULL); - value = p->p_vaddr; - - if ((section->flags & SEC_READONLY) != 0) - { - if (value < htab->text_segment_base) - htab->text_segment_base = value; - } - else - { - if (value < htab->data_segment_base) - htab->data_segment_base = value; - } - } -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -final_link_relocate (asection *input_section, - bfd_byte *contents, - const Elf_Internal_Rela *rela, - bfd_vma value, - struct elf32_hppa_link_hash_table *htab, - asection *sym_sec, - struct elf32_hppa_link_hash_entry *hh, - struct bfd_link_info *info) -{ - int insn; - unsigned int r_type = ELF32_R_TYPE (rela->r_info); - unsigned int orig_r_type = r_type; - reloc_howto_type *howto = elf_hppa_howto_table + r_type; - int r_format = howto->bitsize; - enum hppa_reloc_field_selector_type_alt r_field; - bfd *input_bfd = input_section->owner; - bfd_vma offset = rela->r_offset; - bfd_vma max_branch_offset = 0; - bfd_byte *hit_data = contents + offset; - bfd_signed_vma addend = rela->r_addend; - bfd_vma location; - struct elf32_hppa_stub_hash_entry *hsh = NULL; - int val; - - if (r_type == R_PARISC_NONE) - return bfd_reloc_ok; - - insn = bfd_get_32 (input_bfd, hit_data); - - /* Find out where we are and where we're going. */ - location = (offset + - input_section->output_offset + - input_section->output_section->vma); - - /* If we are not building a shared library, convert DLTIND relocs to - DPREL relocs. */ - if (!bfd_link_pic (info)) - { - switch (r_type) - { - case R_PARISC_DLTIND21L: - case R_PARISC_TLS_GD21L: - case R_PARISC_TLS_LDM21L: - case R_PARISC_TLS_IE21L: - r_type = R_PARISC_DPREL21L; - break; - - case R_PARISC_DLTIND14R: - case R_PARISC_TLS_GD14R: - case R_PARISC_TLS_LDM14R: - case R_PARISC_TLS_IE14R: - r_type = R_PARISC_DPREL14R; - break; - - case R_PARISC_DLTIND14F: - r_type = R_PARISC_DPREL14F; - break; - } - } - - switch (r_type) - { - case R_PARISC_PCREL12F: - case R_PARISC_PCREL17F: - case R_PARISC_PCREL22F: - /* If this call should go via the plt, find the import stub in - the stub hash. */ - if (sym_sec == NULL - || sym_sec->output_section == NULL - || (hh != NULL - && hh->eh.plt.offset != (bfd_vma) -1 - && hh->eh.dynindx != -1 - && !hh->plabel - && (bfd_link_pic (info) - || !hh->eh.def_regular - || hh->eh.root.type == bfd_link_hash_defweak))) - { - hsh = hppa_get_stub_entry (input_section, sym_sec, - hh, rela, htab); - if (hsh != NULL) - { - value = (hsh->stub_offset - + hsh->stub_sec->output_offset - + hsh->stub_sec->output_section->vma); - addend = 0; - } - else if (sym_sec == NULL && hh != NULL - && hh->eh.root.type == bfd_link_hash_undefweak) - { - /* It's OK if undefined weak. Calls to undefined weak - symbols behave as if the "called" function - immediately returns. We can thus call to a weak - function without first checking whether the function - is defined. */ - value = location; - addend = 8; - } - else - return bfd_reloc_undefined; - } - /* Fall thru. */ - - case R_PARISC_PCREL21L: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL17R: - case R_PARISC_PCREL14R: - case R_PARISC_PCREL14F: - case R_PARISC_PCREL32: - /* Make it a pc relative offset. */ - value -= location; - addend -= 8; - break; - - case R_PARISC_DPREL21L: - case R_PARISC_DPREL14R: - case R_PARISC_DPREL14F: - /* Convert instructions that use the linkage table pointer (r19) to - instructions that use the global data pointer (dp). This is the - most efficient way of using PIC code in an incomplete executable, - but the user must follow the standard runtime conventions for - accessing data for this to work. */ - if (orig_r_type != r_type) - { - if (r_type == R_PARISC_DPREL21L) - { - /* GCC sometimes uses a register other than r19 for the - operation, so we must convert any addil instruction - that uses this relocation. */ - if ((insn & 0xfc000000) == ((int) OP_ADDIL << 26)) - insn = ADDIL_DP; - else - /* We must have a ldil instruction. It's too hard to find - and convert the associated add instruction, so issue an - error. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s fixup for insn %#x is not supported in a non-shared link"), - input_bfd, - input_section, - offset, - howto->name, - insn); - } - else if (r_type == R_PARISC_DPREL14F) - { - /* This must be a format 1 load/store. Change the base - register to dp. */ - insn = (insn & 0xfc1ffff) | (27 << 21); - } - } - - /* For all the DP relative relocations, we need to examine the symbol's - section. If it has no section or if it's a code section, then - "data pointer relative" makes no sense. In that case we don't - adjust the "value", and for 21 bit addil instructions, we change the - source addend register from %dp to %r0. This situation commonly - arises for undefined weak symbols and when a variable's "constness" - is declared differently from the way the variable is defined. For - instance: "extern int foo" with foo defined as "const int foo". */ - if (sym_sec == NULL || (sym_sec->flags & SEC_CODE) != 0) - { - if ((insn & ((0x3f << 26) | (0x1f << 21))) - == (((int) OP_ADDIL << 26) | (27 << 21))) - { - insn &= ~ (0x1f << 21); - } - /* Now try to make things easy for the dynamic linker. */ - - break; - } - /* Fall thru. */ - - case R_PARISC_DLTIND21L: - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND14F: - case R_PARISC_TLS_GD21L: - case R_PARISC_TLS_LDM21L: - case R_PARISC_TLS_IE21L: - case R_PARISC_TLS_GD14R: - case R_PARISC_TLS_LDM14R: - case R_PARISC_TLS_IE14R: - value -= elf_gp (input_section->output_section->owner); - break; - - case R_PARISC_SEGREL32: - if ((sym_sec->flags & SEC_CODE) != 0) - value -= htab->text_segment_base; - else - value -= htab->data_segment_base; - break; - - default: - break; - } - - switch (r_type) - { - case R_PARISC_DIR32: - case R_PARISC_DIR14F: - case R_PARISC_DIR17F: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL14F: - case R_PARISC_PCREL32: - case R_PARISC_DPREL14F: - case R_PARISC_PLABEL32: - case R_PARISC_DLTIND14F: - case R_PARISC_SEGBASE: - case R_PARISC_SEGREL32: - case R_PARISC_TLS_DTPMOD32: - case R_PARISC_TLS_DTPOFF32: - case R_PARISC_TLS_TPREL32: - r_field = e_fsel; - break; - - case R_PARISC_DLTIND21L: - case R_PARISC_PCREL21L: - case R_PARISC_PLABEL21L: - r_field = e_lsel; - break; - - case R_PARISC_DIR21L: - case R_PARISC_DPREL21L: - case R_PARISC_TLS_GD21L: - case R_PARISC_TLS_LDM21L: - case R_PARISC_TLS_LDO21L: - case R_PARISC_TLS_IE21L: - case R_PARISC_TLS_LE21L: - r_field = e_lrsel; - break; - - case R_PARISC_PCREL17R: - case R_PARISC_PCREL14R: - case R_PARISC_PLABEL14R: - case R_PARISC_DLTIND14R: - r_field = e_rsel; - break; - - case R_PARISC_DIR17R: - case R_PARISC_DIR14R: - case R_PARISC_DPREL14R: - case R_PARISC_TLS_GD14R: - case R_PARISC_TLS_LDM14R: - case R_PARISC_TLS_LDO14R: - case R_PARISC_TLS_IE14R: - case R_PARISC_TLS_LE14R: - r_field = e_rrsel; - break; - - case R_PARISC_PCREL12F: - case R_PARISC_PCREL17F: - case R_PARISC_PCREL22F: - r_field = e_fsel; - - if (r_type == (unsigned int) R_PARISC_PCREL17F) - { - max_branch_offset = (1 << (17-1)) << 2; - } - else if (r_type == (unsigned int) R_PARISC_PCREL12F) - { - max_branch_offset = (1 << (12-1)) << 2; - } - else - { - max_branch_offset = (1 << (22-1)) << 2; - } - - /* sym_sec is NULL on undefined weak syms or when shared on - undefined syms. We've already checked for a stub for the - shared undefined case. */ - if (sym_sec == NULL) - break; - - /* If the branch is out of reach, then redirect the - call to the local stub for this function. */ - if (value + addend + max_branch_offset >= 2*max_branch_offset) - { - hsh = hppa_get_stub_entry (input_section, sym_sec, - hh, rela, htab); - if (hsh == NULL) - return bfd_reloc_undefined; - - /* Munge up the value and addend so that we call the stub - rather than the procedure directly. */ - value = (hsh->stub_offset - + hsh->stub_sec->output_offset - + hsh->stub_sec->output_section->vma - - location); - addend = -8; - } - break; - - /* Something we don't know how to handle. */ - default: - return bfd_reloc_notsupported; - } - - /* Make sure we can reach the stub. */ - if (max_branch_offset != 0 - && value + addend + max_branch_offset >= 2*max_branch_offset) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): cannot reach %s, recompile with -ffunction-sections"), - input_bfd, - input_section, - offset, - hsh->bh_root.string); - bfd_set_error (bfd_error_bad_value); - return bfd_reloc_notsupported; - } - - val = hppa_field_adjust (value, addend, r_field); - - switch (r_type) - { - case R_PARISC_PCREL12F: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL17F: - case R_PARISC_PCREL17R: - case R_PARISC_PCREL22F: - case R_PARISC_DIR17F: - case R_PARISC_DIR17R: - /* This is a branch. Divide the offset by four. - Note that we need to decide whether it's a branch or - otherwise by inspecting the reloc. Inspecting insn won't - work as insn might be from a .word directive. */ - val >>= 2; - break; - - default: - break; - } - - insn = hppa_rebuild_insn (insn, val, r_format); - - /* Update the instruction word. */ - bfd_put_32 (input_bfd, (bfd_vma) insn, hit_data); - return bfd_reloc_ok; -} - -/* Relocate an HPPA ELF section. */ - -static bfd_boolean -elf32_hppa_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) -{ - bfd_vma *local_got_offsets; - struct elf32_hppa_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rela; - Elf_Internal_Rela *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - local_got_offsets = elf_local_got_offsets (input_bfd); - - rela = relocs; - relend = relocs + input_section->reloc_count; - for (; rela < relend; rela++) - { - unsigned int r_type; - reloc_howto_type *howto; - unsigned int r_symndx; - struct elf32_hppa_link_hash_entry *hh; - Elf_Internal_Sym *sym; - asection *sym_sec; - bfd_vma relocation; - bfd_reloc_status_type rstatus; - const char *sym_name; - bfd_boolean plabel; - bfd_boolean warned_undef; - - r_type = ELF32_R_TYPE (rela->r_info); - if (r_type >= (unsigned int) R_PARISC_UNIMPLEMENTED) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - if (r_type == (unsigned int) R_PARISC_GNU_VTENTRY - || r_type == (unsigned int) R_PARISC_GNU_VTINHERIT) - continue; - - r_symndx = ELF32_R_SYM (rela->r_info); - hh = NULL; - sym = NULL; - sym_sec = NULL; - warned_undef = FALSE; - if (r_symndx < symtab_hdr->sh_info) - { - /* This is a local symbol, h defaults to NULL. */ - sym = local_syms + r_symndx; - sym_sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sym_sec, rela); - } - else - { - struct elf_link_hash_entry *eh; - bfd_boolean unresolved_reloc, ignored; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rela, - r_symndx, symtab_hdr, sym_hashes, - eh, sym_sec, relocation, - unresolved_reloc, warned_undef, - ignored); - - if (!bfd_link_relocatable (info) - && relocation == 0 - && eh->root.type != bfd_link_hash_defined - && eh->root.type != bfd_link_hash_defweak - && eh->root.type != bfd_link_hash_undefweak) - { - if (info->unresolved_syms_in_objects == RM_IGNORE - && ELF_ST_VISIBILITY (eh->other) == STV_DEFAULT - && eh->type == STT_PARISC_MILLI) - { - (*info->callbacks->undefined_symbol) - (info, eh_name (eh), input_bfd, - input_section, rela->r_offset, FALSE); - warned_undef = TRUE; - } - } - hh = hppa_elf_hash_entry (eh); - } - - if (sym_sec != NULL && discarded_section (sym_sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rela, 1, relend, - elf_hppa_howto_table + r_type, 0, - contents); - - if (bfd_link_relocatable (info)) - continue; - - /* Do any required modifications to the relocation value, and - determine what types of dynamic info we need to output, if - any. */ - plabel = 0; - switch (r_type) - { - case R_PARISC_DLTIND14F: - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND21L: - { - bfd_vma off; - bfd_boolean do_got = FALSE; - bfd_boolean reloc = bfd_link_pic (info); - - /* Relocation is to the entry for this symbol in the - global offset table. */ - if (hh != NULL) - { - bfd_boolean dyn; - - off = hh->eh.got.offset; - dyn = htab->etab.dynamic_sections_created; - reloc = (!UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh) - && (reloc - || (hh->eh.dynindx != -1 - && !SYMBOL_REFERENCES_LOCAL (info, &hh->eh)))); - if (!reloc - || !WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - &hh->eh)) - { - /* If we aren't going to call finish_dynamic_symbol, - then we need to handle initialisation of the .got - entry and create needed relocs here. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialised it already. */ - if ((off & 1) != 0) - off &= ~1; - else - { - hh->eh.got.offset |= 1; - do_got = TRUE; - } - } - } - else - { - /* Local symbol case. */ - 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 - { - local_got_offsets[r_symndx] |= 1; - do_got = TRUE; - } - } - - if (do_got) - { - if (reloc) - { - /* Output a dynamic relocation for this GOT entry. - In this case it is relative to the base of the - object because the symbol index is zero. */ - Elf_Internal_Rela outrel; - bfd_byte *loc; - asection *sec = htab->etab.srelgot; - - outrel.r_offset = (off - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - outrel.r_info = ELF32_R_INFO (0, R_PARISC_DIR32); - outrel.r_addend = relocation; - loc = sec->contents; - loc += sec->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - bfd_put_32 (output_bfd, relocation, - htab->etab.sgot->contents + off); - } - - if (off >= (bfd_vma) -2) - abort (); - - /* Add the base of the GOT to the relocation value. */ - relocation = (off - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - } - break; - - case R_PARISC_SEGREL32: - /* If this is the first SEGREL relocation, then initialize - the segment base values. */ - if (htab->text_segment_base == (bfd_vma) -1) - bfd_map_over_sections (output_bfd, hppa_record_segment_addr, htab); - break; - - case R_PARISC_PLABEL14R: - case R_PARISC_PLABEL21L: - case R_PARISC_PLABEL32: - if (htab->etab.dynamic_sections_created) - { - bfd_vma off; - bfd_boolean do_plt = 0; - /* If we have a global symbol with a PLT slot, then - redirect this relocation to it. */ - if (hh != NULL) - { - off = hh->eh.plt.offset; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, - bfd_link_pic (info), - &hh->eh)) - { - /* In a non-shared link, adjust_dynamic_symbol - isn't called for symbols forced local. We - need to write out the plt entry here. */ - if ((off & 1) != 0) - off &= ~1; - else - { - hh->eh.plt.offset |= 1; - do_plt = 1; - } - } - } - else - { - bfd_vma *local_plt_offsets; - - if (local_got_offsets == NULL) - abort (); - - local_plt_offsets = local_got_offsets + symtab_hdr->sh_info; - off = local_plt_offsets[r_symndx]; - - /* As for the local .got entry case, we use the last - bit to record whether we've already initialised - this local .plt entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - local_plt_offsets[r_symndx] |= 1; - do_plt = 1; - } - } - - if (do_plt) - { - if (bfd_link_pic (info)) - { - /* Output a dynamic IPLT relocation for this - PLT entry. */ - Elf_Internal_Rela outrel; - bfd_byte *loc; - asection *s = htab->etab.srelplt; - - outrel.r_offset = (off - + htab->etab.splt->output_offset - + htab->etab.splt->output_section->vma); - outrel.r_info = ELF32_R_INFO (0, R_PARISC_IPLT); - outrel.r_addend = relocation; - loc = s->contents; - loc += s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - { - bfd_put_32 (output_bfd, - relocation, - htab->etab.splt->contents + off); - bfd_put_32 (output_bfd, - elf_gp (htab->etab.splt->output_section->owner), - htab->etab.splt->contents + off + 4); - } - } - - if (off >= (bfd_vma) -2) - abort (); - - /* PLABELs contain function pointers. Relocation is to - the entry for the function in the .plt. The magic +2 - offset signals to $$dyncall that the function pointer - is in the .plt and thus has a gp pointer too. - Exception: Undefined PLABELs should have a value of - zero. */ - if (hh == NULL - || (hh->eh.root.type != bfd_link_hash_undefweak - && hh->eh.root.type != bfd_link_hash_undefined)) - { - relocation = (off - + htab->etab.splt->output_offset - + htab->etab.splt->output_section->vma - + 2); - } - plabel = 1; - } - /* Fall through. */ - - case R_PARISC_DIR17F: - case R_PARISC_DIR17R: - case R_PARISC_DIR14F: - case R_PARISC_DIR14R: - case R_PARISC_DIR21L: - case R_PARISC_DPREL14F: - case R_PARISC_DPREL14R: - case R_PARISC_DPREL21L: - case R_PARISC_DIR32: - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - if (bfd_link_pic (info) - ? ((hh == NULL - || hh->dyn_relocs != NULL) - && ((hh != NULL && pc_dynrelocs (hh)) - || IS_ABSOLUTE_RELOC (r_type))) - : (hh != NULL - && hh->dyn_relocs != NULL)) - { - Elf_Internal_Rela outrel; - bfd_boolean skip; - asection *sreloc; - bfd_byte *loc; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - outrel.r_addend = rela->r_addend; - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rela->r_offset); - skip = (outrel.r_offset == (bfd_vma) -1 - || outrel.r_offset == (bfd_vma) -2); - outrel.r_offset += (input_section->output_offset - + input_section->output_section->vma); - - if (skip) - { - memset (&outrel, 0, sizeof (outrel)); - } - else if (hh != NULL - && hh->eh.dynindx != -1 - && (plabel - || !IS_ABSOLUTE_RELOC (r_type) - || !bfd_link_pic (info) - || !SYMBOLIC_BIND (info, &hh->eh) - || !hh->eh.def_regular)) - { - outrel.r_info = ELF32_R_INFO (hh->eh.dynindx, r_type); - } - else /* It's a local symbol, or one marked to become local. */ - { - int indx = 0; - - /* Add the absolute offset of the symbol. */ - outrel.r_addend += relocation; - - /* Global plabels need to be processed by the - dynamic linker so that functions have at most one - fptr. For this reason, we need to differentiate - between global and local plabels, which we do by - providing the function symbol for a global plabel - reloc, and no symbol for local plabels. */ - if (! plabel - && sym_sec != NULL - && sym_sec->output_section != NULL - && ! bfd_is_abs_section (sym_sec)) - { - asection *osec; - - osec = sym_sec->output_section; - indx = elf_section_data (osec)->dynindx; - if (indx == 0) - { - osec = htab->etab.text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); - - /* We are turning this relocation into one - against a section symbol, so subtract out the - output section's address but not the offset - of the input section in the output section. */ - outrel.r_addend -= osec->vma; - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - } - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - break; - - case R_PARISC_TLS_LDM21L: - case R_PARISC_TLS_LDM14R: - { - bfd_vma off; - - off = htab->tls_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - outrel.r_offset = (off - + htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset); - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (0, R_PARISC_TLS_DTPMOD32); - loc = htab->etab.srelgot->contents; - loc += htab->etab.srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->tls_ldm_got.offset |= 1; - } - - /* Add the base of the GOT to the relocation value. */ - relocation = (off - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - - break; - } - - case R_PARISC_TLS_LDO21L: - case R_PARISC_TLS_LDO14R: - relocation -= dtpoff_base (info); - break; - - case R_PARISC_TLS_GD21L: - case R_PARISC_TLS_GD14R: - case R_PARISC_TLS_IE21L: - case R_PARISC_TLS_IE14R: - { - bfd_vma off; - int indx; - char tls_type; - - indx = 0; - if (hh != NULL) - { - if (!htab->etab.dynamic_sections_created - || hh->eh.dynindx == -1 - || SYMBOL_REFERENCES_LOCAL (info, &hh->eh) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh)) - /* 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. */ - ; - else - indx = hh->eh.dynindx; - off = hh->eh.got.offset; - tls_type = hh->tls_type; - } - else - { - off = local_got_offsets[r_symndx]; - tls_type = hppa_elf_local_got_tls_type (input_bfd)[r_symndx]; - } - - if (tls_type == GOT_UNKNOWN) - abort (); - - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_boolean need_relocs = FALSE; - Elf_Internal_Rela outrel; - bfd_byte *loc = NULL; - int cur_off = off; - - /* The GOT entries have not been initialized yet. Do it - now, and emit any relocations. If both an IE GOT and a - GD GOT are necessary, we emit the GD first. */ - - if (indx != 0 - || (bfd_link_pic (info) - && (hh == NULL - || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh)))) - { - need_relocs = TRUE; - loc = htab->etab.srelgot->contents; - loc += (htab->etab.srelgot->reloc_count - * sizeof (Elf32_External_Rela)); - } - - if (tls_type & GOT_TLS_GD) - { - if (need_relocs) - { - outrel.r_offset - = (cur_off - + htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset); - outrel.r_info - = ELF32_R_INFO (indx, R_PARISC_TLS_DTPMOD32); - outrel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->etab.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - outrel.r_info - = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32); - outrel.r_offset += 4; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->etab.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - bfd_put_32 (output_bfd, 0, - htab->etab.sgot->contents + cur_off); - bfd_put_32 (output_bfd, 0, - htab->etab.sgot->contents + cur_off + 4); - } - else - { - /* If we are not emitting relocations for a - general dynamic reference, then we must be in a - static link or an executable link with the - symbol binding locally. Mark it as belonging - to module 1, the executable. */ - bfd_put_32 (output_bfd, 1, - htab->etab.sgot->contents + cur_off); - bfd_put_32 (output_bfd, relocation - dtpoff_base (info), - htab->etab.sgot->contents + cur_off + 4); - } - cur_off += 8; - } - - if (tls_type & GOT_TLS_IE) - { - if (need_relocs - && !(bfd_link_executable (info) - && SYMBOL_REFERENCES_LOCAL (info, &hh->eh))) - { - outrel.r_offset - = (cur_off - + htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset); - outrel.r_info = ELF32_R_INFO (indx, - R_PARISC_TLS_TPREL32); - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->etab.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - } - else - bfd_put_32 (output_bfd, tpoff (info, relocation), - htab->etab.sgot->contents + cur_off); - cur_off += 4; - } - - if (hh != NULL) - hh->eh.got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - if ((tls_type & GOT_NORMAL) != 0 - && (tls_type & (GOT_TLS_GD | GOT_TLS_LDM | GOT_TLS_IE)) != 0) - { - if (hh != NULL) - _bfd_error_handler (_("%s has both normal and TLS relocs"), - hh_name (hh)); - else - { - Elf_Internal_Sym *isym - = bfd_sym_from_r_symndx (&htab->sym_cache, - input_bfd, r_symndx); - if (isym == NULL) - return FALSE; - sym_name - = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - isym->st_name); - if (sym_name == NULL) - return FALSE; - if (*sym_name == '\0') - sym_name = bfd_section_name (input_bfd, sym_sec); - _bfd_error_handler - (_("%B:%s has both normal and TLS relocs"), - input_bfd, sym_name); - } - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if ((tls_type & GOT_TLS_GD) - && r_type != R_PARISC_TLS_GD21L - && r_type != R_PARISC_TLS_GD14R) - off += 2 * GOT_ENTRY_SIZE; - - /* Add the base of the GOT to the relocation value. */ - relocation = (off - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - - break; - } - - case R_PARISC_TLS_LE21L: - case R_PARISC_TLS_LE14R: - { - relocation = tpoff (info, relocation); - break; - } - break; - - default: - break; - } - - rstatus = final_link_relocate (input_section, contents, rela, relocation, - htab, sym_sec, hh, info); - - if (rstatus == bfd_reloc_ok) - continue; - - if (hh != NULL) - sym_name = hh_name (hh); - else - { - sym_name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (sym_name == NULL) - return FALSE; - if (*sym_name == '\0') - sym_name = bfd_section_name (input_bfd, sym_sec); - } - - howto = elf_hppa_howto_table + r_type; - - if (rstatus == bfd_reloc_undefined || rstatus == bfd_reloc_notsupported) - { - if (rstatus == bfd_reloc_notsupported || !warned_undef) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): cannot handle %s for %s"), - input_bfd, - input_section, - rela->r_offset, - howto->name, - sym_name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - else - (*info->callbacks->reloc_overflow) - (info, (hh ? &hh->eh.root : NULL), sym_name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rela->r_offset); - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf32_hppa_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *eh, - Elf_Internal_Sym *sym) -{ - struct elf32_hppa_link_hash_table *htab; - Elf_Internal_Rela rela; - bfd_byte *loc; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - if (eh->plt.offset != (bfd_vma) -1) - { - bfd_vma value; - - if (eh->plt.offset & 1) - abort (); - - /* This symbol has an entry in the procedure linkage table. Set - it up. - - The format of a plt entry is - - <__gp> - */ - value = 0; - if (eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak) - { - value = eh->root.u.def.value; - if (eh->root.u.def.section->output_section != NULL) - value += (eh->root.u.def.section->output_offset - + eh->root.u.def.section->output_section->vma); - } - - /* Create a dynamic IPLT relocation for this entry. */ - rela.r_offset = (eh->plt.offset - + htab->etab.splt->output_offset - + htab->etab.splt->output_section->vma); - if (eh->dynindx != -1) - { - rela.r_info = ELF32_R_INFO (eh->dynindx, R_PARISC_IPLT); - rela.r_addend = 0; - } - else - { - /* This symbol has been marked to become local, and is - used by a plabel so must be kept in the .plt. */ - rela.r_info = ELF32_R_INFO (0, R_PARISC_IPLT); - rela.r_addend = value; - } - - loc = htab->etab.srelplt->contents; - loc += htab->etab.srelplt->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (htab->etab.splt->output_section->owner, &rela, loc); - - if (!eh->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (eh->got.offset != (bfd_vma) -1 - && (hppa_elf_hash_entry (eh)->tls_type & GOT_NORMAL) != 0 - && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh)) - { - bfd_boolean is_dyn = (eh->dynindx != -1 - && !SYMBOL_REFERENCES_LOCAL (info, eh)); - - if (is_dyn || bfd_link_pic (info)) - { - /* This symbol has an entry in the global offset table. Set - it up. */ - - rela.r_offset = ((eh->got.offset &~ (bfd_vma) 1) - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - - /* If this 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 (!is_dyn) - { - rela.r_info = ELF32_R_INFO (0, R_PARISC_DIR32); - rela.r_addend = (eh->root.u.def.value - + eh->root.u.def.section->output_offset - + eh->root.u.def.section->output_section->vma); - } - else - { - if ((eh->got.offset & 1) != 0) - abort (); - - bfd_put_32 (output_bfd, 0, - htab->etab.sgot->contents + (eh->got.offset & ~1)); - rela.r_info = ELF32_R_INFO (eh->dynindx, R_PARISC_DIR32); - rela.r_addend = 0; - } - - loc = htab->etab.srelgot->contents; - loc += (htab->etab.srelgot->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - } - - if (eh->needs_copy) - { - asection *sec; - - /* This symbol needs a copy reloc. Set it up. */ - - if (! (eh->dynindx != -1 - && (eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak))) - abort (); - - rela.r_offset = (eh->root.u.def.value - + eh->root.u.def.section->output_offset - + eh->root.u.def.section->output_section->vma); - rela.r_addend = 0; - rela.r_info = ELF32_R_INFO (eh->dynindx, R_PARISC_COPY); - if (eh->root.u.def.section == htab->etab.sdynrelro) - sec = htab->etab.sreldynrelro; - else - sec = htab->etab.srelbss; - loc = sec->contents + sec->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (eh == htab->etab.hdynamic || eh == htab->etab.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 -elf32_hppa_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - /* Handle TLS relocs first; we don't want them to be marked - relative by the "if (ELF32_R_SYM (rela->r_info) == STN_UNDEF)" - check below. */ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_PARISC_TLS_DTPMOD32: - case R_PARISC_TLS_DTPOFF32: - case R_PARISC_TLS_TPREL32: - return reloc_class_normal; - } - - if (ELF32_R_SYM (rela->r_info) == STN_UNDEF) - return reloc_class_relative; - - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_PARISC_IPLT: - return reloc_class_plt; - case R_PARISC_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf32_hppa_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - struct elf32_hppa_link_hash_table *htab; - asection *sdyn; - asection * sgot; - - htab = hppa_link_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->etab.dynobj; - - sgot = htab->etab.sgot; - /* A broken linker script might have discarded the dynamic sections. - Catch this here so that we do not seg-fault later on. */ - if (sgot != NULL && bfd_is_abs_section (sgot->output_section)) - return FALSE; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->etab.dynamic_sections_created) - { - Elf32_External_Dyn *dyncon, *dynconend; - - if (sdyn == 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: - /* Use PLTGOT to set the GOT register. */ - dyn.d_un.d_ptr = elf_gp (output_bfd); - break; - - case DT_JMPREL: - s = htab->etab.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - s = htab->etab.srelplt; - dyn.d_un.d_val = s->size; - break; - } - - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - - if (sgot != NULL && sgot->size != 0) - { - /* Fill in the first entry in the global offset table. - We use it to point to our dynamic section, if we have one. */ - bfd_put_32 (output_bfd, - sdyn ? sdyn->output_section->vma + sdyn->output_offset : 0, - sgot->contents); - - /* The second entry is reserved for use by the dynamic linker. */ - memset (sgot->contents + GOT_ENTRY_SIZE, 0, GOT_ENTRY_SIZE); - - /* Set .got entry size. */ - elf_section_data (sgot->output_section) - ->this_hdr.sh_entsize = GOT_ENTRY_SIZE; - } - - if (htab->etab.splt != NULL && htab->etab.splt->size != 0) - { - /* Set plt entry size to 0 instead of PLT_ENTRY_SIZE, since we add the - plt stubs and as such the section does not hold a table of fixed-size - entries. */ - elf_section_data (htab->etab.splt->output_section)->this_hdr.sh_entsize = 0; - - if (htab->need_plt_stub) - { - /* Set up the .plt stub. */ - memcpy (htab->etab.splt->contents - + htab->etab.splt->size - sizeof (plt_stub), - plt_stub, sizeof (plt_stub)); - - if ((htab->etab.splt->output_offset - + htab->etab.splt->output_section->vma - + htab->etab.splt->size) - != (sgot->output_offset - + sgot->output_section->vma)) - { - _bfd_error_handler - (_(".got section not immediately after .plt section")); - return FALSE; - } - } - } - - return TRUE; -} - -/* Called when writing out an object file to decide the type of a - symbol. */ -static int -elf32_hppa_elf_get_symbol_type (Elf_Internal_Sym *elf_sym, int type) -{ - if (ELF_ST_TYPE (elf_sym->st_info) == STT_PARISC_MILLI) - return STT_PARISC_MILLI; - else - return type; -} - -/* Misc BFD support code. */ -#define bfd_elf32_bfd_is_local_label_name elf_hppa_is_local_label_name -#define bfd_elf32_bfd_reloc_type_lookup elf_hppa_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf_hppa_reloc_name_lookup -#define elf_info_to_howto elf_hppa_info_to_howto -#define elf_info_to_howto_rel elf_hppa_info_to_howto_rel - -/* Stuff for the BFD linker. */ -#define bfd_elf32_bfd_final_link elf32_hppa_final_link -#define bfd_elf32_bfd_link_hash_table_create elf32_hppa_link_hash_table_create -#define elf_backend_adjust_dynamic_symbol elf32_hppa_adjust_dynamic_symbol -#define elf_backend_copy_indirect_symbol elf32_hppa_copy_indirect_symbol -#define elf_backend_check_relocs elf32_hppa_check_relocs -#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible -#define elf_backend_create_dynamic_sections elf32_hppa_create_dynamic_sections -#define elf_backend_fake_sections elf_hppa_fake_sections -#define elf_backend_relocate_section elf32_hppa_relocate_section -#define elf_backend_hide_symbol elf32_hppa_hide_symbol -#define elf_backend_finish_dynamic_symbol elf32_hppa_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections elf32_hppa_finish_dynamic_sections -#define elf_backend_size_dynamic_sections elf32_hppa_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_gc_mark_hook elf32_hppa_gc_mark_hook -#define elf_backend_grok_prstatus elf32_hppa_grok_prstatus -#define elf_backend_grok_psinfo elf32_hppa_grok_psinfo -#define elf_backend_object_p elf32_hppa_object_p -#define elf_backend_final_write_processing elf_hppa_final_write_processing -#define elf_backend_get_symbol_type elf32_hppa_elf_get_symbol_type -#define elf_backend_reloc_type_class elf32_hppa_reloc_type_class -#define elf_backend_action_discarded elf_hppa_action_discarded - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_plt_alignment 2 -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 0 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 8 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_no_page_alias 1 - -#define TARGET_BIG_SYM hppa_elf32_vec -#define TARGET_BIG_NAME "elf32-hppa" -#define ELF_ARCH bfd_arch_hppa -#define ELF_TARGET_ID HPPA32_ELF_DATA -#define ELF_MACHINE_CODE EM_PARISC -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_OSABI ELFOSABI_HPUX -#define elf32_bed elf32_hppa_hpux_bed - -#include "elf32-target.h" - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM hppa_elf32_linux_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-hppa-linux" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_GNU -#undef elf32_bed -#define elf32_bed elf32_hppa_linux_bed - -#include "elf32-target.h" - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM hppa_elf32_nbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-hppa-netbsd" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_NETBSD -#undef elf32_bed -#define elf32_bed elf32_hppa_netbsd_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-hppa.h b/sdcc/support/sdbinutils/bfd/elf32-hppa.h deleted file mode 100644 index 0a58dd3d7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-hppa.h +++ /dev/null @@ -1,88 +0,0 @@ -/* ELF32/HPPA support - - This file contains ELF32/HPPA relocation support as specified - in the Stratus FTX/Golf Object File Format (SED-1762) dated - February 1994. - - Copyright (C) 1990-2018 Free Software Foundation, Inc. - - Written by: - - Center for Software Science - Department of Computer Science - University of Utah - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_HPPA_H -#define _ELF32_HPPA_H - -#include "elf-bfd.h" -#include "libhppa.h" -#include "elf/hppa.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void elf32_hppa_init_stub_bfd - (bfd *, struct bfd_link_info *); - -int elf32_hppa_setup_section_lists - (bfd *, struct bfd_link_info *); - -void elf32_hppa_next_input_section - (struct bfd_link_info *, asection *); - -bfd_boolean elf32_hppa_size_stubs - (bfd *, bfd *, struct bfd_link_info *, bfd_boolean, bfd_signed_vma, - asection * (*) (const char *, asection *), void (*) (void)); - -bfd_boolean elf32_hppa_set_gp - (bfd *, struct bfd_link_info *); - -bfd_boolean elf32_hppa_build_stubs - (struct bfd_link_info *); - -elf_hppa_reloc_type elf32_hppa_reloc_final_type - (bfd *, elf_hppa_reloc_type, int, unsigned int); - -extern elf_hppa_reloc_type ** _bfd_elf32_hppa_gen_reloc_type - (bfd *, elf_hppa_reloc_type, int, unsigned int, int, asymbol *); - -/* Define groups of basic relocations. FIXME: These should - be the only basic relocations created by GAS. The rest - should be internal to the BFD backend. - - The idea is both SOM and ELF define these basic relocation - types so they map into a SOM or ELF specific relocation - as appropriate. This allows GAS to share much more code - between the two target object formats. */ - -#define R_HPPA_NONE R_PARISC_NONE -#define R_HPPA R_PARISC_DIR32 -#define R_HPPA_GOTOFF R_PARISC_DPREL21L -#define R_HPPA_PCREL_CALL R_PARISC_PCREL21L -#define R_HPPA_ABS_CALL R_PARISC_DIR17F -#define R_HPPA_COMPLEX R_PARISC_UNIMPLEMENTED - -#ifdef __cplusplus -} -#endif - -#endif /* _ELF32_HPPA_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-i370.c b/sdcc/support/sdbinutils/bfd/elf32-i370.c deleted file mode 100644 index 88be84b57..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-i370.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* i370-specific support for 32-bit ELF - Copyright (C) 1994-2018 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support. - Hacked by Linas Vepstas for i370 linas@linas.org - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* This file is based on a preliminary PowerPC ELF ABI. - But its been hacked on for the IBM 360/370 architectures. - Basically, the 31bit relocation works, and just about everything - else is a wild card. In particular, don't expect shared libs or - dynamic loading to work ... its never been tested. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/i370.h" - -static reloc_howto_type *i370_elf_howto_table[ (int)R_I370_max ]; - -static reloc_howto_type i370_elf_howto_raw[] = -{ - /* This reloc does nothing. */ - HOWTO (R_I370_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 31 bit relocation. */ - HOWTO (R_I370_ADDR31, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 31, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_ADDR31", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x7fffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 32 bit relocation. */ - HOWTO (R_I370_ADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_ADDR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 16 bit relocation. */ - HOWTO (R_I370_ADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_ADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 31-bit PC relative. */ - HOWTO (R_I370_REL31, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 31, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_REL31", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x7fffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32-bit PC relative. */ - HOWTO (R_I370_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A standard 12 bit relocation. */ - HOWTO (R_I370_ADDR12, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_ADDR12", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 12-bit PC relative. */ - HOWTO (R_I370_REL12, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_REL12", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A standard 8 bit relocation. */ - HOWTO (R_I370_ADDR8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_ADDR8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 8-bit PC relative. */ - HOWTO (R_I370_REL8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_REL8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_I370_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_I370_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_I370_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Initialize the i370_elf_howto_table, so that linear accesses can be done. */ - -static void -i370_elf_howto_init (void) -{ - unsigned int i, type; - - for (i = 0; i < sizeof (i370_elf_howto_raw) / sizeof (i370_elf_howto_raw[0]); i++) - { - type = i370_elf_howto_raw[i].type; - BFD_ASSERT (type < sizeof (i370_elf_howto_table) / sizeof (i370_elf_howto_table[0])); - i370_elf_howto_table[type] = &i370_elf_howto_raw[i]; - } -} - -static reloc_howto_type * -i370_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - enum i370_reloc_type i370_reloc = R_I370_NONE; - - if (!i370_elf_howto_table[ R_I370_ADDR31 ]) - /* Initialize howto table if needed. */ - i370_elf_howto_init (); - - switch ((int) code) - { - default: - return NULL; - - case BFD_RELOC_NONE: i370_reloc = R_I370_NONE; break; - case BFD_RELOC_32: i370_reloc = R_I370_ADDR31; break; - case BFD_RELOC_16: i370_reloc = R_I370_ADDR16; break; - case BFD_RELOC_32_PCREL: i370_reloc = R_I370_REL31; break; - case BFD_RELOC_CTOR: i370_reloc = R_I370_ADDR31; break; - case BFD_RELOC_I370_D12: i370_reloc = R_I370_ADDR12; break; - } - - return i370_elf_howto_table[ (int)i370_reloc ]; -}; - -static reloc_howto_type * -i370_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (i370_elf_howto_raw) / sizeof (i370_elf_howto_raw[0]); - i++) - if (i370_elf_howto_raw[i].name != NULL - && strcasecmp (i370_elf_howto_raw[i].name, r_name) == 0) - return &i370_elf_howto_raw[i]; - - return NULL; -} - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so" - -/* Set the howto pointer for an i370 ELF reloc. */ - -static void -i370_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - if (!i370_elf_howto_table[ R_I370_ADDR31 ]) - /* Initialize howto table. */ - i370_elf_howto_init (); - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_I370_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised I370 reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_I370_NONE; - } - cache_ptr->howto = i370_elf_howto_table[r_type]; -} - -/* Hack alert -- the following several routines look generic to me ... - why are we bothering with them ? */ -/* Function to set whether a module needs the -mrelocatable bit set. */ - -static bfd_boolean -i370_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -i370_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - if (!elf_flags_init (obfd)) /* First call, no flags set. */ - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - - else if (new_flags == old_flags) /* Compatible flags are ok. */ - ; - - else /* Incompatible flags. */ - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields than previous modules (%#x)"), - ibfd, new_flags, old_flags); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - return TRUE; -} - -/* Handle an i370 specific section when reading an object file. This - is called when elfcode.h finds a section with an unknown type. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) -{ - asection *newsect; - flagword flags; - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - newsect = hdr->bfd_section; - flags = bfd_get_section_flags (abfd, newsect); - if (hdr->sh_type == SHT_ORDERED) - flags |= SEC_SORT_ENTRIES; - - bfd_set_section_flags (abfd, newsect, flags); - return TRUE; -} - -/* Set up any other section flags and such that may be necessary. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *shdr, - asection *asect) -{ - if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE) - shdr->sh_flags |= SHF_EXCLUDE; - - if ((asect->flags & SEC_SORT_ENTRIES) != 0) - shdr->sh_type = SHT_ORDERED; - - return TRUE; -} - -/* We have to create .dynsbss and .rela.sbss here so that they get mapped - to output sections (just like _bfd_elf_create_dynamic_sections has - to create .dynbss and .rela.bss). */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - asection *s; - flagword flags; - - if (!_bfd_elf_create_dynamic_sections(abfd, info)) - return FALSE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss", - SEC_ALLOC | SEC_LINKER_CREATED); - if (s == NULL) - return FALSE; - - if (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - } - - /* XXX beats me, seem to need a rela.text ... */ - s = bfd_make_section_anyway_with_flags (abfd, ".rela.text", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - 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. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj = elf_hash_table (info)->dynobj; - asection *s; - -#ifdef DEBUG - fprintf (stderr, "i370_elf_adjust_dynamic_symbol called for %s\n", - h->root.root.string); -#endif - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - s = bfd_get_linker_section (dynobj, ".rela.text"); - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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. - - Of course, if the symbol is sufficiently small, we must instead - allocate it in .sbss. FIXME: It would be better to do this if and - only if there were actually SDAREL relocs for that symbol. */ - - if (h->size <= elf_gp_size (dynobj)) - s = bfd_get_linker_section (dynobj, ".dynsbss"); - else - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - /* We must generate a R_I370_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - if (h->size <= elf_gp_size (dynobj)) - srel = bfd_get_linker_section (dynobj, ".rela.sbss"); - else - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Increment the index of a dynamic symbol by a given amount. Called - via elf_link_hash_traverse. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_adjust_dynindx (struct elf_link_hash_entry *h, void * cparg) -{ - int *cp = (int *) cparg; - -#ifdef DEBUG - fprintf (stderr, - "i370_elf_adjust_dynindx called, h->dynindx = %ld, *cp = %d\n", - h->dynindx, *cp); -#endif - - if (h->dynindx != -1) - h->dynindx += *cp; - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean plt; - bfd_boolean relocs; - bfd_boolean reltext; - -#ifdef DEBUG - fprintf (stderr, "i370_elf_size_dynamic_sections called\n"); -#endif - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got, .rela.sdata, and - .rela.sdata2 sections. However, if we are not creating the - dynamic sections, we will not actually use these entries. Reset - the size of .rela.got, et al, which will cause it to get - stripped from the output file below. */ - static char *rela_sections[] = { ".rela.got", ".rela.sdata", - ".rela.sdata2", ".rela.sbss", - NULL }; - char **p; - - for (p = rela_sections; *p != NULL; p++) - { - s = bfd_get_linker_section (dynobj, *p); - if (s != NULL) - s->size = 0; - } - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - asection *target; - const char *outname; - - /* Remember whether there are any relocation sections. */ - relocs = TRUE; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL entry. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 5); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = 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 if (strcmp (name, ".got") != 0 - && strcmp (name, ".sdata") != 0 - && strcmp (name, ".sdata2") != 0 - && strcmp (name, ".dynbss") != 0 - && strcmp (name, ".dynsbss") != 0) - { - /* 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. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in i370_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (!bfd_link_pic (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - } - - if (reltext) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - info->flags |= DF_TEXTREL; - } - } -#undef add_dynamic_entry - - /* If we are generating a shared library, we generate a section - symbol for each output section. These are local symbols, which - means that they must come first in the dynamic symbol table. - That means we must increment the dynamic symbol index of every - other dynamic symbol. - - FIXME: We assume that there will never be relocations to - locations in linker-created sections that do not have - externally-visible names. Instead, we should work out precisely - which sections relocations are targeted at. */ - if (bfd_link_pic (info)) - { - int c; - - for (c = 0, s = output_bfd->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) != 0 - || (s->flags & SEC_ALLOC) == 0) - { - elf_section_data (s)->dynindx = -1; - continue; - } - - /* These symbols will have no names, so we don't need to - fiddle with dynstr_index. */ - - elf_section_data (s)->dynindx = c + 1; - - c++; - } - - elf_link_hash_traverse (elf_hash_table (info), - i370_elf_adjust_dynindx, & c); - elf_hash_table (info)->dynsymcount += c; - } - - return TRUE; -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - 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 (bfd_link_relocatable (info)) - return TRUE; - -#ifdef DEBUG - _bfd_error_handler ("i370_elf_check_relocs called for section %A in %B", - sec, abfd); -#endif - - dynobj = elf_hash_table (info)->dynobj; - 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 long r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - if (bfd_link_pic (info)) - { -#ifdef DEBUG - fprintf (stderr, - "i370_elf_check_relocs needs to create relocation for %s\n", - (h && h->root.root.string) - ? h->root.root.string : ""); -#endif - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - sreloc->size += sizeof (Elf32_External_Rela); - - /* FIXME: We should here do what the m68k and i386 - backends do: if the reloc is pc-relative, record it - in case it turns out that the reloc is unnecessary - because the symbol is forced local by versioning or - we are linking with -Bdynamic. Fortunately this - case is not frequent. */ - } - } - - return TRUE; -} - -/* Finish up the dynamic sections. */ -/* XXX hack alert bogus This routine is mostly all junk and almost - certainly does the wrong thing. Its here simply because it does - just enough to allow glibc-2.1 ld.so to compile & link. */ - -static bfd_boolean -i370_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *sdyn; - bfd *dynobj = elf_hash_table (info)->dynobj; - asection *sgot = elf_hash_table (info)->sgot; - -#ifdef DEBUG - fprintf (stderr, "i370_elf_finish_dynamic_sections called\n"); -#endif - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - bfd_boolean size; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_PLTGOT: - s = elf_hash_table (info)->splt; - size = FALSE; - break; - case DT_PLTRELSZ: - s = elf_hash_table (info)->srelplt; - size = TRUE; - break; - case DT_JMPREL: - s = elf_hash_table (info)->srelplt; - size = FALSE; - break; - default: - continue; - } - - if (s == NULL) - dyn.d_un.d_val = 0; - else - { - if (!size) - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - else - dyn.d_un.d_val = s->size; - } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - - if (sgot && sgot->size != 0) - { - unsigned char *contents = sgot->contents; - - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - contents); - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - if (bfd_link_pic (info)) - { - asection *sdynsym; - asection *s; - Elf_Internal_Sym sym; - int maxdindx = 0; - - /* Set up the section symbols for the output sections. */ - - sdynsym = bfd_get_linker_section (dynobj, ".dynsym"); - BFD_ASSERT (sdynsym != NULL); - - sym.st_size = 0; - sym.st_name = 0; - sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); - sym.st_other = 0; - sym.st_target_internal = 0; - - for (s = output_bfd->sections; s != NULL; s = s->next) - { - int indx, dindx; - Elf32_External_Sym *esym; - - sym.st_value = s->vma; - - indx = elf_section_data (s)->this_idx; - dindx = elf_section_data (s)->dynindx; - if (dindx != -1) - { - BFD_ASSERT(indx > 0); - BFD_ASSERT(dindx > 0); - - if (dindx > maxdindx) - maxdindx = dindx; - - sym.st_shndx = indx; - - esym = (Elf32_External_Sym *) sdynsym->contents + dindx; - bfd_elf32_swap_symbol_out (output_bfd, &sym, esym, NULL); - } - } - - /* Set the sh_info field of the output .dynsym section to the - index of the first global symbol. */ - elf_section_data (sdynsym->output_section)->this_hdr.sh_info = - maxdindx + 1; - } - - return TRUE; -} - -/* 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. */ - -static bfd_boolean -i370_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - Elf_Internal_Rela *rel = relocs; - Elf_Internal_Rela *relend = relocs + input_section->reloc_count; - asection *sreloc = NULL; - bfd_boolean ret = TRUE; - -#ifdef DEBUG - _bfd_error_handler ("i370_elf_relocate_section called for %B section %A, %u relocations%s", - input_bfd, input_section, - input_section->reloc_count, - (bfd_link_relocatable (info)) ? " (relocatable)" : ""); -#endif - - if (!i370_elf_howto_table[ R_I370_ADDR31 ]) - /* Initialize howto table if needed. */ - i370_elf_howto_init (); - - for (; rel < relend; rel++) - { - enum i370_reloc_type r_type = (enum i370_reloc_type) ELF32_R_TYPE (rel->r_info); - bfd_vma offset = rel->r_offset; - bfd_vma addend = rel->r_addend; - bfd_reloc_status_type r = bfd_reloc_other; - Elf_Internal_Sym *sym = NULL; - asection *sec = NULL; - struct elf_link_hash_entry * h = NULL; - const char *sym_name = NULL; - reloc_howto_type *howto; - unsigned long r_symndx; - bfd_vma relocation; - - /* Unknown relocation handling. */ - if ((unsigned) r_type >= (unsigned) R_I370_max - || !i370_elf_howto_table[(int)r_type]) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - } - - howto = i370_elf_howto_table[(int) r_type]; - r_symndx = ELF32_R_SYM (rel->r_info); - relocation = 0; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - sym_name = ""; - - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, & sec, rel); - addend = rel->r_addend; - } - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - h = ((struct elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &h->root)); - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - sym_name = h->root.root.string; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sec = h->root.u.def.section; - if (bfd_link_pic (info) - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular) - && (input_section->flags & SEC_ALLOC) != 0 - && (r_type == R_I370_ADDR31 - || r_type == R_I370_COPY - || r_type == R_I370_ADDR16 - || r_type == R_I370_RELATIVE)) - /* In these cases, we don't need the relocation - value. We check specially because in some - obscure cases sec->output_section will be NULL. */ - ; - 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 if (!bfd_link_relocatable (info)) - { - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, rel->r_offset, - (info->unresolved_syms_in_objects == RM_GENERATE_ERROR - || ELF_ST_VISIBILITY (h->other))); - ret = FALSE; - continue; - } - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch ((int) r_type) - { - default: - _bfd_error_handler - (_("%B: unknown relocation type %d for symbol %s"), - input_bfd, (int) r_type, sym_name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - - case (int) R_I370_NONE: - continue; - - /* Relocations that may need to be propagated if this is a shared - object. */ - case (int) R_I370_REL31: - /* If these relocations are not to a named symbol, they can be - handled right here, no need to bother the dynamic linker. */ - if (h == NULL - || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - break; - /* Fall through. */ - - /* Relocations that always need to be propagated if this is a shared - object. */ - case (int) R_I370_ADDR31: - case (int) R_I370_ADDR16: - if (bfd_link_pic (info) - && r_symndx != STN_UNDEF) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - int skip; - -#ifdef DEBUG - fprintf (stderr, - "i370_elf_relocate_section needs to create relocation for %s\n", - (h && h->root.root.string) ? h->root.root.string : ""); -#endif - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - skip = 0; - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1 - || outrel.r_offset == (bfd_vma) -2) - skip = (int) outrel.r_offset; - 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 - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - if (r_type == R_I370_ADDR31) - { - outrel.r_info = ELF32_R_INFO (0, R_I370_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - long indx; - - if (bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. */ - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - if (indx == 0) - { - struct elf_link_hash_table *htab; - htab = elf_hash_table (info); - osec = htab->text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); -#ifdef DEBUG - if (indx <= 0) - { - printf ("indx=%ld section=%s flags=%08x name=%s\n", - indx, osec->name, osec->flags, - h->root.root.string); - } -#endif - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - outrel.r_addend = relocation + rel->r_addend; - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - /* This reloc will be computed at runtime, so there's no - need to do anything now, unless this is a RELATIVE - reloc in an unallocated section. */ - if (skip == -1 - || (input_section->flags & SEC_ALLOC) != 0 - || ELF32_R_TYPE (outrel.r_info) != R_I370_RELATIVE) - continue; - } - break; - - case (int) R_I370_COPY: - case (int) R_I370_RELATIVE: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Relocation %s is not yet supported for symbol %s."), - input_bfd, - i370_elf_howto_table[(int) r_type]->name, - sym_name); - - bfd_set_error (bfd_error_invalid_operation); - ret = FALSE; - continue; - } - -#ifdef DEBUG - fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, offset = %ld, addend = %ld\n", - howto->name, - (int)r_type, - sym_name, - r_symndx, - (long) offset, - (long) addend); -#endif - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - offset, relocation, addend); - - if (r != bfd_reloc_ok) - { - ret = FALSE; - switch (r) - { - default: - break; - - case bfd_reloc_overflow: - { - const char *name; - - if (h != NULL) - name = NULL; - else - { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL) - break; - - if (*name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - (*info->callbacks->reloc_overflow) (info, - (h ? &h->root : NULL), - name, - howto->name, - (bfd_vma) 0, - input_bfd, - input_section, - offset); - } - break; - } - } - } - -#ifdef DEBUG - fprintf (stderr, "\n"); -#endif - - return ret; -} - -#define TARGET_BIG_SYM i370_elf32_vec -#define TARGET_BIG_NAME "elf32-i370" -#define ELF_ARCH bfd_arch_i370 -#define ELF_MACHINE_CODE EM_S370 -#ifdef EM_I370_OLD -#define ELF_MACHINE_ALT1 EM_I370_OLD -#endif -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_OSABI ELFOSABI_GNU - -#define elf_info_to_howto i370_elf_info_to_howto - -#define elf_backend_plt_not_loaded 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_reloc_type_lookup i370_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup i370_elf_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags i370_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data i370_elf_merge_private_bfd_data -#define elf_backend_relocate_section i370_elf_relocate_section - -/* Dynamic loader support is mostly broken; just enough here to be able to - link glibc's ld.so without errors. */ -#define elf_backend_create_dynamic_sections i370_elf_create_dynamic_sections -#define elf_backend_size_dynamic_sections i370_elf_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_finish_dynamic_sections i370_elf_finish_dynamic_sections -#define elf_backend_fake_sections i370_elf_fake_sections -#define elf_backend_section_from_shdr i370_elf_section_from_shdr -#define elf_backend_adjust_dynamic_symbol i370_elf_adjust_dynamic_symbol -#define elf_backend_check_relocs i370_elf_check_relocs - -static int -i370_noop (void) -{ - return 1; -} - -#define elf_backend_finish_dynamic_symbol \ - (bfd_boolean (*) \ - (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, \ - Elf_Internal_Sym *)) i370_noop - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-i386.c b/sdcc/support/sdbinutils/bfd/elf32-i386.c deleted file mode 100644 index 1f380dbdc..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-i386.c +++ /dev/null @@ -1,4839 +0,0 @@ -/* Intel 80386/80486-specific support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "elfxx-x86.h" -#include "elf-nacl.h" -#include "elf-vxworks.h" -#include "dwarf2.h" -#include "opcode/i386.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, 3, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_386_NONE", - TRUE, 0x00000000, 0x00000000, FALSE), - HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - 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), - HOWTO(R_386_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, - bfd_elf_generic_reloc, "R_386_SIZE32", - TRUE, 0xffffffff, 0xffffffff, FALSE), - 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), - HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_386_IRELATIVE", - TRUE, 0xffffffff, 0xffffffff, FALSE), - HOWTO(R_386_GOT32X, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_386_GOT32X", - TRUE, 0xffffffff, 0xffffffff, FALSE), - - /* Another gap. */ -#define R_386_ext2 (R_386_GOT32X + 1 - R_386_tls_offset) -#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_ext2) - -/* 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) - -}; - -#define X86_PCREL_TYPE_P(TYPE) ((TYPE) == R_386_PC32) - -#define X86_SIZE_TYPE_P(TYPE) ((TYPE) == R_386_SIZE32) - -#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_SIZE32: - TRACE ("BFD_RELOC_SIZE32"); - return &elf_howto_table[R_386_SIZE32 - 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_386_IRELATIVE: - TRACE ("BFD_RELOC_386_IRELATIVE"); - return &elf_howto_table[R_386_IRELATIVE - R_386_tls_offset]; - - case BFD_RELOC_386_GOT32X: - TRACE ("BFD_RELOC_386_GOT32X"); - return &elf_howto_table[R_386_GOT32X - 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 reloc_howto_type * -elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - return NULL; -} - -static reloc_howto_type * -elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) -{ - 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_ext2 - R_386_ext) - && ((indx = r_type - R_386_vt_offset) - R_386_ext2 - >= R_386_vt - R_386_ext2)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) r_type); - indx = R_386_NONE; - } - /* PR 17512: file: 0f67f69d. */ - if (elf_howto_table [indx].type != r_type) - return NULL; - return &elf_howto_table[indx]; -} - -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); - cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type); -} - -/* 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->lwpid = 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->lwpid = 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->pid - = bfd_get_32 (abfd, note->descdata + 12); - 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 size in bytes of an entry in the lazy procedure linkage table. */ - -#define LAZY_PLT_ENTRY_SIZE 16 - -/* The size in bytes of an entry in the non-lazy procedure linkage - table. */ - -#define NON_LAZY_PLT_ENTRY_SIZE 8 - -/* The first entry in an absolute lazy procedure linkage table looks - like this. See the SVR4 ABI i386 supplement to see how this works. - Will be padded to LAZY_PLT_ENTRY_SIZE with lazy_plt->plt0_pad_byte. */ - -static const bfd_byte elf_i386_lazy_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 lazy procedure linkage table look - like this. */ - -static const bfd_byte elf_i386_lazy_plt_entry[LAZY_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 lazy procedure linkage table look like - this. Will be padded to LAZY_PLT_ENTRY_SIZE with - lazy_plt->plt0_pad_byte. */ - -static const bfd_byte elf_i386_pic_lazy_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 lazy procedure linkage table look like - this. */ - -static const bfd_byte elf_i386_pic_lazy_plt_entry[LAZY_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. */ -}; - -/* Entries in the non-lazy procedure linkage table look like this. */ - -static const bfd_byte elf_i386_non_lazy_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0x25, /* jmp indirect */ - 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ - 0x66, 0x90 /* xchg %ax,%ax */ -}; - -/* Entries in the PIC non-lazy procedure linkage table look like - this. */ - -static const bfd_byte elf_i386_pic_non_lazy_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0xa3, /* jmp *offset(%ebx) */ - 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ - 0x66, 0x90 /* xchg %ax,%ax */ -}; - -/* The first entry in an absolute IBT-enabled lazy procedure linkage - table looks like this. */ - -static const bfd_byte elf_i386_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0x35, 0, 0, 0, 0, /* pushl GOT[1] */ - 0xff, 0x25, 0, 0, 0, 0, /* jmp *GOT[2] */ - 0x0f, 0x1f, 0x40, 0x00 /* nopl 0(%rax) */ -}; - -/* Subsequent entries for an absolute IBT-enabled lazy procedure linkage - table look like this. Subsequent entries for a PIC IBT-enabled lazy - procedure linkage table are the same. */ - -static const bfd_byte elf_i386_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfb, /* endbr32 */ - 0x68, 0, 0, 0, 0, /* pushl immediate */ - 0xe9, 0, 0, 0, 0, /* jmp relative */ - 0x66, 0x90 /* xchg %ax,%ax */ -}; - -/* The first entry in a PIC IBT-enabled lazy procedure linkage table - look like. */ - -static const bfd_byte elf_i386_pic_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ - 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ - 0x0f, 0x1f, 0x40, 0x00 /* nopl 0(%rax) */ -}; - -/* Entries for branches with IBT-enabled in the absolute non-lazey - procedure linkage table look like this. They have the same size - as the lazy PLT entry. */ - -static const bfd_byte elf_i386_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfb, /* endbr32 */ - 0xff, 0x25, 0, 0, 0, 0, /* jmp *name@GOT */ - 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */ -}; - -/* Entries for branches with IBT-enabled in the PIC non-lazey procedure - linkage table look like this. They have the same size as the lazy - PLT entry. */ - -static const bfd_byte elf_i386_pic_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfb, /* endbr32 */ - 0xff, 0xa3, 0, 0, 0, 0, /* jmp *name@GOT(%ebx) */ - 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */ -}; - -/* .eh_frame covering the lazy .plt section. */ - -static const bfd_byte elf_i386_eh_frame_lazy_plt[] = -{ - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x7c, /* Data alignment factor */ - 8, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ - DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_386_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ - DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 11, /* Block length */ - DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ - DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ - DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge, - DW_OP_lit2, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* .eh_frame covering the lazy .plt section with IBT-enabled. */ - -static const bfd_byte elf_i386_eh_frame_lazy_ibt_plt[] = -{ - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x7c, /* Data alignment factor */ - 8, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ - DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_386_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ - DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 11, /* Block length */ - DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ - DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ - DW_OP_lit15, DW_OP_and, DW_OP_lit9, DW_OP_ge, - DW_OP_lit2, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* .eh_frame covering the non-lazy .plt section. */ - -static const bfd_byte elf_i386_eh_frame_non_lazy_plt[] = -{ -#define PLT_GOT_FDE_LENGTH 16 - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x7c, /* Data alignment factor */ - 8, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ - DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_GOT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* the start of non-lazy .plt goes here */ - 0, 0, 0, 0, /* non-lazy .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* These are the standard parameters. */ -static const struct elf_x86_lazy_plt_layout elf_i386_lazy_plt = - { - elf_i386_lazy_plt0_entry, /* plt0_entry */ - sizeof (elf_i386_lazy_plt0_entry), /* plt0_entry_size */ - elf_i386_lazy_plt_entry, /* plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 8, /* plt0_got2_offset */ - 0, /* plt0_got2_insn_end */ - 2, /* plt_got_offset */ - 7, /* plt_reloc_offset */ - 12, /* plt_plt_offset */ - 0, /* plt_got_insn_size */ - 0, /* plt_plt_insn_end */ - 6, /* plt_lazy_offset */ - elf_i386_pic_lazy_plt0_entry, /* pic_plt0_entry */ - elf_i386_pic_lazy_plt_entry, /* pic_plt_entry */ - elf_i386_eh_frame_lazy_plt, /* eh_frame_plt */ - sizeof (elf_i386_eh_frame_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_non_lazy_plt_layout elf_i386_non_lazy_plt = - { - elf_i386_non_lazy_plt_entry, /* plt_entry */ - elf_i386_pic_non_lazy_plt_entry, /* pic_plt_entry */ - NON_LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt_got_offset */ - 0, /* plt_got_insn_size */ - elf_i386_eh_frame_non_lazy_plt, /* eh_frame_plt */ - sizeof (elf_i386_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_lazy_plt_layout elf_i386_lazy_ibt_plt = - { - elf_i386_lazy_ibt_plt0_entry, /* plt0_entry */ - sizeof (elf_i386_lazy_ibt_plt0_entry), /* plt0_entry_size */ - elf_i386_lazy_ibt_plt_entry, /* plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 8, /* plt0_got2_offset */ - 0, /* plt0_got2_insn_end */ - 4+2, /* plt_got_offset */ - 4+1, /* plt_reloc_offset */ - 4+6, /* plt_plt_offset */ - 0, /* plt_got_insn_size */ - 0, /* plt_plt_insn_end */ - 0, /* plt_lazy_offset */ - elf_i386_pic_lazy_ibt_plt0_entry, /* pic_plt0_entry */ - elf_i386_lazy_ibt_plt_entry, /* pic_plt_entry */ - elf_i386_eh_frame_lazy_ibt_plt, /* eh_frame_plt */ - sizeof (elf_i386_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_non_lazy_plt_layout elf_i386_non_lazy_ibt_plt = - { - elf_i386_non_lazy_ibt_plt_entry, /* plt_entry */ - elf_i386_pic_non_lazy_ibt_plt_entry,/* pic_plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 4+2, /* plt_got_offset */ - 0, /* plt_got_insn_size */ - elf_i386_eh_frame_non_lazy_plt, /* eh_frame_plt */ - sizeof (elf_i386_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ - }; - - -/* 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 - -/* These are the standard parameters. */ -static const struct elf_x86_backend_data elf_i386_arch_bed = - { - is_normal /* os */ - }; - -#define elf_backend_arch_data &elf_i386_arch_bed - -/* Return TRUE if the TLS access code sequence support transition - from R_TYPE. */ - -static bfd_boolean -elf_i386_check_tls_transition (asection *sec, - bfd_byte *contents, - Elf_Internal_Shdr *symtab_hdr, - struct elf_link_hash_entry **sym_hashes, - unsigned int r_type, - const Elf_Internal_Rela *rel, - const Elf_Internal_Rela *relend) -{ - unsigned int val, type, reg; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - bfd_vma offset; - bfd_byte *call; - bfd_boolean indirect_call; - - offset = rel->r_offset; - switch (r_type) - { - case R_386_TLS_GD: - case R_386_TLS_LDM: - if (offset < 2 || (rel + 1) >= relend) - return FALSE; - - indirect_call = FALSE; - call = contents + offset + 4; - val = *(call - 5); - type = *(call - 6); - if (r_type == R_386_TLS_GD) - { - /* Check transition from GD access model. Only - leal foo@tlsgd(,%ebx,1), %eax - call ___tls_get_addr@PLT - or - leal foo@tlsgd(%ebx) %eax - call ___tls_get_addr@PLT - nop - or - leal foo@tlsgd(%reg), %eax - call *___tls_get_addr@GOT(%reg) - which may be converted to - addr32 call ___tls_get_addr - can transit to different access model. */ - if ((offset + 10) > sec->size - || (type != 0x8d && type != 0x04)) - return FALSE; - - if (type == 0x04) - { - /* leal foo@tlsgd(,%ebx,1), %eax - call ___tls_get_addr@PLT */ - if (offset < 3) - return FALSE; - - if (*(call - 7) != 0x8d - || val != 0x1d - || call[0] != 0xe8) - return FALSE; - } - else - { - /* This must be - leal foo@tlsgd(%ebx), %eax - call ___tls_get_addr@PLT - nop - or - leal foo@tlsgd(%reg), %eax - call *___tls_get_addr@GOT(%reg) - which may be converted to - addr32 call ___tls_get_addr - - %eax can't be used as the GOT base register since it - is used to pass parameter to ___tls_get_addr. */ - reg = val & 7; - if ((val & 0xf8) != 0x80 || reg == 4 || reg == 0) - return FALSE; - - indirect_call = call[0] == 0xff; - if (!(reg == 3 && call[0] == 0xe8 && call[5] == 0x90) - && !(call[0] == 0x67 && call[1] == 0xe8) - && !(indirect_call - && (call[1] & 0xf8) == 0x90 - && (call[1] & 0x7) == reg)) - return FALSE; - } - } - else - { - /* Check transition from LD access model. Only - leal foo@tlsldm(%ebx), %eax - call ___tls_get_addr@PLT - or - leal foo@tlsldm(%reg), %eax - call *___tls_get_addr@GOT(%reg) - which may be converted to - addr32 call ___tls_get_addr - can transit to different access model. */ - if (type != 0x8d || (offset + 9) > sec->size) - return FALSE; - - /* %eax can't be used as the GOT base register since it is - used to pass parameter to ___tls_get_addr. */ - reg = val & 7; - if ((val & 0xf8) != 0x80 || reg == 4 || reg == 0) - return FALSE; - - indirect_call = call[0] == 0xff; - if (!(reg == 3 && call[0] == 0xe8) - && !(call[0] == 0x67 && call[1] == 0xe8) - && !(indirect_call - && (call[1] & 0xf8) == 0x90 - && (call[1] & 0x7) == reg)) - return FALSE; - } - - r_symndx = ELF32_R_SYM (rel[1].r_info); - if (r_symndx < symtab_hdr->sh_info) - return FALSE; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h == NULL - || !((struct elf_x86_link_hash_entry *) h)->tls_get_addr) - return FALSE; - else if (indirect_call) - return (ELF32_R_TYPE (rel[1].r_info) == R_386_GOT32X); - else - return (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32 - || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); - - case R_386_TLS_IE: - /* Check transition from IE access model: - movl foo@indntpoff(%rip), %eax - movl foo@indntpoff(%rip), %reg - addl foo@indntpoff(%rip), %reg - */ - - if (offset < 1 || (offset + 4) > sec->size) - return FALSE; - - /* Check "movl foo@tpoff(%rip), %eax" first. */ - val = bfd_get_8 (abfd, contents + offset - 1); - if (val == 0xa1) - return TRUE; - - if (offset < 2) - return FALSE; - - /* Check movl|addl foo@tpoff(%rip), %reg. */ - type = bfd_get_8 (abfd, contents + offset - 2); - return ((type == 0x8b || type == 0x03) - && (val & 0xc7) == 0x05); - - case R_386_TLS_GOTIE: - case R_386_TLS_IE_32: - /* Check transition from {IE_32,GOTIE} access model: - subl foo@{tpoff,gontoff}(%reg1), %reg2 - movl foo@{tpoff,gontoff}(%reg1), %reg2 - addl foo@{tpoff,gontoff}(%reg1), %reg2 - */ - - if (offset < 2 || (offset + 4) > sec->size) - return FALSE; - - val = bfd_get_8 (abfd, contents + offset - 1); - if ((val & 0xc0) != 0x80 || (val & 7) == 4) - return FALSE; - - type = bfd_get_8 (abfd, contents + offset - 2); - return type == 0x8b || type == 0x2b || type == 0x03; - - case R_386_TLS_GOTDESC: - /* Check transition from GDesc access model: - leal x@tlsdesc(%ebx), %eax - - 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. */ - - if (offset < 2 || (offset + 4) > sec->size) - return FALSE; - - if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d) - return FALSE; - - val = bfd_get_8 (abfd, contents + offset - 1); - return (val & 0xc7) == 0x83; - - case R_386_TLS_DESC_CALL: - /* Check transition from GDesc access model: - call *x@tlsdesc(%eax) - */ - if (offset + 2 <= sec->size) - { - /* Make sure that it's a call *x@tlsdesc(%eax). */ - call = contents + offset; - return call[0] == 0xff && call[1] == 0x10; - } - - return FALSE; - - default: - abort (); - } -} - -/* Return TRUE if the TLS access transition is OK or no transition - will be performed. Update R_TYPE if there is a transition. */ - -static bfd_boolean -elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, - asection *sec, bfd_byte *contents, - Elf_Internal_Shdr *symtab_hdr, - struct elf_link_hash_entry **sym_hashes, - unsigned int *r_type, int tls_type, - const Elf_Internal_Rela *rel, - const Elf_Internal_Rela *relend, - struct elf_link_hash_entry *h, - unsigned long r_symndx, - bfd_boolean from_relocate_section) -{ - unsigned int from_type = *r_type; - unsigned int to_type = from_type; - bfd_boolean check = TRUE; - - /* Skip TLS transition for functions. */ - if (h != NULL - && (h->type == STT_FUNC - || h->type == STT_GNU_IFUNC)) - return TRUE; - - switch (from_type) - { - 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: - if (bfd_link_executable (info)) - { - if (h == NULL) - to_type = R_386_TLS_LE_32; - else if (from_type != R_386_TLS_IE - && from_type != R_386_TLS_GOTIE) - to_type = R_386_TLS_IE_32; - } - - /* When we are called from elf_i386_relocate_section, there may - be additional transitions based on TLS_TYPE. */ - if (from_relocate_section) - { - unsigned int new_to_type = to_type; - - if (TLS_TRANSITION_IE_TO_LE_P (info, h, tls_type)) - new_to_type = R_386_TLS_LE_32; - - if (to_type == R_386_TLS_GD - || to_type == R_386_TLS_GOTDESC - || to_type == R_386_TLS_DESC_CALL) - { - if (tls_type == GOT_TLS_IE_POS) - new_to_type = R_386_TLS_GOTIE; - else if (tls_type & GOT_TLS_IE) - new_to_type = R_386_TLS_IE_32; - } - - /* We checked the transition before when we were called from - elf_i386_check_relocs. We only want to check the new - transition which hasn't been checked before. */ - check = new_to_type != to_type && from_type == to_type; - to_type = new_to_type; - } - - break; - - case R_386_TLS_LDM: - if (bfd_link_executable (info)) - to_type = R_386_TLS_LE_32; - break; - - default: - return TRUE; - } - - /* Return TRUE if there is no transition. */ - if (from_type == to_type) - return TRUE; - - /* Check if the transition can be performed. */ - if (check - && ! elf_i386_check_tls_transition (sec, contents, - symtab_hdr, sym_hashes, - from_type, rel, relend)) - { - reloc_howto_type *from, *to; - const char *name; - - from = elf_i386_rtype_to_howto (abfd, from_type); - to = elf_i386_rtype_to_howto (abfd, to_type); - - if (h) - name = h->root.root.string; - else - { - struct elf_x86_link_hash_table *htab; - - htab = elf_x86_hash_table (info, I386_ELF_DATA); - if (htab == NULL) - name = "*unknown*"; - else - { - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); - } - } - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: TLS transition from %s to %s against `%s' at %#Lx " - "in section `%A' failed"), - abfd, from->name, to->name, name, - rel->r_offset, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - *r_type = to_type; - return TRUE; -} - -/* With the local symbol, foo, we convert - mov foo@GOT[(%reg1)], %reg2 - to - lea foo[@GOTOFF(%reg1)], %reg2 - and convert - call/jmp *foo@GOT[(%reg)] - to - nop call foo/jmp foo nop - When PIC is false, convert - test %reg1, foo@GOT[(%reg2)] - to - test $foo, %reg1 - and convert - binop foo@GOT[(%reg1)], %reg2 - to - binop $foo, %reg2 - where binop is one of adc, add, and, cmp, or, sbb, sub, xor - instructions. */ - -static -bfd_boolean -elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, - bfd_byte *contents, - unsigned int *r_type_p, - Elf_Internal_Rela *irel, - struct elf_link_hash_entry *h, - bfd_boolean *converted, - struct bfd_link_info *link_info) -{ - struct elf_x86_link_hash_table *htab; - unsigned int opcode; - unsigned int modrm; - bfd_boolean baseless; - Elf_Internal_Sym *isym; - unsigned int addend; - unsigned int nop; - bfd_vma nop_offset; - bfd_boolean is_pic; - bfd_boolean to_reloc_32; - unsigned int r_type; - unsigned int r_symndx; - bfd_vma roff = irel->r_offset; - bfd_boolean local_ref; - struct elf_x86_link_hash_entry *eh; - - if (roff < 2) - return TRUE; - - /* Addend for R_386_GOT32X relocations must be 0. */ - addend = bfd_get_32 (abfd, contents + roff); - if (addend != 0) - return TRUE; - - htab = elf_x86_hash_table (link_info, I386_ELF_DATA); - is_pic = bfd_link_pic (link_info); - - r_type = *r_type_p; - r_symndx = ELF32_R_SYM (irel->r_info); - - modrm = bfd_get_8 (abfd, contents + roff - 1); - baseless = (modrm & 0xc7) == 0x5; - - if (baseless && is_pic) - { - /* For PIC, disallow R_386_GOT32X without a base register - since we don't know what the GOT base is. */ - const char *name; - - if (h == NULL) - { - isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, - r_symndx); - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); - } - else - name = h->root.root.string; - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base" - " register can not be used when making a shared object"), - abfd, name); - return FALSE; - } - - opcode = bfd_get_8 (abfd, contents + roff - 2); - - /* Convert to R_386_32 if PIC is false or there is no base - register. */ - to_reloc_32 = !is_pic || baseless; - - eh = elf_x86_hash_entry (h); - - /* Try to convert R_386_GOT32X. Get the symbol referred to by the - reloc. */ - if (h == NULL) - { - if (opcode == 0x0ff) - /* Convert "call/jmp *foo@GOT[(%reg)]". */ - goto convert_branch; - else - /* Convert "mov foo@GOT[(%reg1)], %reg2", - "test %reg1, foo@GOT(%reg2)" and - "binop foo@GOT[(%reg1)], %reg2". */ - goto convert_load; - } - - /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P. */ - local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h); - - /* Undefined weak symbol is only bound locally in executable - and its reference is resolved as 0. */ - if (h->root.type == bfd_link_hash_undefweak - && !eh->linker_def - && local_ref) - { - if (opcode == 0xff) - { - /* No direct branch to 0 for PIC. */ - if (is_pic) - return TRUE; - else - goto convert_branch; - } - else - { - /* We can convert load of address 0 to R_386_32. */ - to_reloc_32 = TRUE; - goto convert_load; - } - } - - if (opcode == 0xff) - { - /* We have "call/jmp *foo@GOT[(%reg)]". */ - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && local_ref) - { - /* The function is locally defined. */ -convert_branch: - /* Convert R_386_GOT32X to R_386_PC32. */ - if (modrm == 0x15 || (modrm & 0xf8) == 0x90) - { - /* Convert to "nop call foo". ADDR_PREFIX_OPCODE - is a nop prefix. */ - modrm = 0xe8; - /* To support TLS optimization, always use addr32 prefix - for "call *___tls_get_addr@GOT(%reg)". */ - if (eh && eh->tls_get_addr) - { - nop = 0x67; - nop_offset = irel->r_offset - 2; - } - else - { - nop = link_info->call_nop_byte; - if (link_info->call_nop_as_suffix) - { - nop_offset = roff + 3; - irel->r_offset -= 1; - } - else - nop_offset = roff - 2; - } - } - else - { - /* Convert to "jmp foo nop". */ - modrm = 0xe9; - nop = NOP_OPCODE; - nop_offset = roff + 3; - irel->r_offset -= 1; - } - - bfd_put_8 (abfd, nop, contents + nop_offset); - bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1); - /* When converting to PC-relative relocation, we - need to adjust addend by -4. */ - bfd_put_32 (abfd, -4, contents + irel->r_offset); - irel->r_info = ELF32_R_INFO (r_symndx, R_386_PC32); - *r_type_p = R_386_PC32; - *converted = TRUE; - } - } - else - { - /* We have "mov foo@GOT[(%re1g)], %reg2", - "test %reg1, foo@GOT(%reg2)" and - "binop foo@GOT[(%reg1)], %reg2". - - Avoid optimizing _DYNAMIC since ld.so may use its - link-time address. */ - if (h == htab->elf.hdynamic) - return TRUE; - - /* def_regular is set by an assignment in a linker script in - bfd_elf_record_link_assignment. start_stop is set on - __start_SECNAME/__stop_SECNAME which mark section SECNAME. */ - if (h->start_stop - || eh->linker_def - || ((h->def_regular - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && local_ref)) - { -convert_load: - if (opcode == 0x8b) - { - if (to_reloc_32) - { - /* Convert "mov foo@GOT[(%reg1)], %reg2" to - "mov $foo, %reg2" with R_386_32. */ - r_type = R_386_32; - modrm = 0xc0 | (modrm & 0x38) >> 3; - bfd_put_8 (abfd, modrm, contents + roff - 1); - opcode = 0xc7; - } - else - { - /* Convert "mov foo@GOT(%reg1), %reg2" to - "lea foo@GOTOFF(%reg1), %reg2". */ - r_type = R_386_GOTOFF; - opcode = 0x8d; - } - } - else - { - /* Only R_386_32 is supported. */ - if (!to_reloc_32) - return TRUE; - - if (opcode == 0x85) - { - /* Convert "test %reg1, foo@GOT(%reg2)" to - "test $foo, %reg1". */ - modrm = 0xc0 | (modrm & 0x38) >> 3; - opcode = 0xf7; - } - else - { - /* Convert "binop foo@GOT(%reg1), %reg2" to - "binop $foo, %reg2". */ - modrm = (0xc0 - | (modrm & 0x38) >> 3 - | (opcode & 0x3c)); - opcode = 0x81; - } - bfd_put_8 (abfd, modrm, contents + roff - 1); - r_type = R_386_32; - } - - bfd_put_8 (abfd, opcode, contents + roff - 2); - irel->r_info = ELF32_R_INFO (r_symndx, r_type); - *r_type_p = r_type; - *converted = TRUE; - } - } - - return TRUE; -} - -/* Rename some of the generic section flags to better document how they - are used here. */ -#define check_relocs_failed sec_flg0 - -/* Look through the relocs for a section during the first phase, and - calculate needed space in the global offset table, procedure linkage - table, and dynamic reloc sections. */ - -static bfd_boolean -elf_i386_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_x86_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; - bfd_byte *contents; - bfd_boolean converted; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - htab = elf_x86_hash_table (info, I386_ELF_DATA); - if (htab == NULL) - { - sec->check_relocs_failed = 1; - return FALSE; - } - - BFD_ASSERT (is_x86_elf (abfd, htab)); - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - { - sec->check_relocs_failed = 1; - return FALSE; - } - - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - - converted = FALSE; - - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned int r_symndx; - struct elf_link_hash_entry *h; - struct elf_x86_link_hash_entry *eh; - Elf_Internal_Sym *isym; - const char *name; - bfd_boolean size_reloc; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), - abfd, r_symndx); - goto error_return; - } - - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - goto error_return; - - /* Check relocation against local STT_GNU_IFUNC symbol. */ - if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - h = _bfd_elf_x86_get_local_sym_hash (htab, abfd, rel, TRUE); - if (h == NULL) - goto error_return; - - /* Fake a STT_GNU_IFUNC symbol. */ - h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr, - isym, NULL); - h->type = STT_GNU_IFUNC; - h->def_regular = 1; - h->ref_regular = 1; - h->forced_local = 1; - h->root.type = bfd_link_hash_defined; - } - else - h = NULL; - } - else - { - isym = NULL; - 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_x86_link_hash_entry *) h; - if (h != NULL) - { - if (r_type == R_386_GOTOFF) - eh->gotoff_ref = 1; - - /* It is referenced by a non-shared object. */ - h->ref_regular = 1; - - if (h->type == STT_GNU_IFUNC) - elf_tdata (info->output_bfd)->has_gnu_symbols - |= elf_gnu_symbol_ifunc; - } - - if (r_type == R_386_GOT32X - && (h == NULL || h->type != STT_GNU_IFUNC)) - { - Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel; - if (!elf_i386_convert_load_reloc (abfd, symtab_hdr, contents, - &r_type, irel, h, - &converted, info)) - goto error_return; - } - - if (! elf_i386_tls_transition (info, abfd, sec, contents, - symtab_hdr, sym_hashes, - &r_type, GOT_UNKNOWN, - rel, rel_end, h, r_symndx, FALSE)) - goto error_return; - - switch (r_type) - { - case R_386_TLS_LDM: - htab->tls_ld_or_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; - - eh->zero_undefweak &= 0x2; - h->needs_plt = 1; - h->plt.refcount = 1; - break; - - case R_386_SIZE32: - size_reloc = TRUE; - goto do_size; - - case R_386_TLS_IE_32: - case R_386_TLS_IE: - case R_386_TLS_GOTIE: - if (!bfd_link_executable (info)) - info->flags |= DF_STATIC_TLS; - /* Fall through */ - - case R_386_GOT32: - case R_386_GOT32X: - 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: - case R_386_GOT32X: - 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 this is a GD->IE transition, we may use either of - R_386_TLS_TPOFF and R_386_TLS_TPOFF32. */ - tls_type = GOT_TLS_IE; - break; - case R_386_TLS_IE: - case R_386_TLS_GOTIE: - tls_type = GOT_TLS_IE_POS; break; - } - - if (h != NULL) - { - h->got.refcount = 1; - old_tls_type = elf_x86_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) - goto error_return; - elf_local_got_refcounts (abfd) = local_got_refcounts; - elf_x86_local_tlsdesc_gotent (abfd) - = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); - elf_x86_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx] = 1; - old_tls_type = elf_x86_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 - { - if (h) - name = h->root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, - NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as normal and " - "thread local symbol"), - abfd, name); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - } - - if (old_tls_type != tls_type) - { - if (h != NULL) - elf_x86_hash_entry (h)->tls_type = tls_type; - else - elf_x86_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - } - /* Fall through */ - - case R_386_GOTOFF: - case R_386_GOTPC: - create_got: - if (r_type != R_386_TLS_IE) - { - if (eh != NULL) - eh->zero_undefweak &= 0x2; - break; - } - /* Fall through */ - - case R_386_TLS_LE_32: - case R_386_TLS_LE: - if (eh != NULL) - eh->zero_undefweak &= 0x2; - if (bfd_link_executable (info)) - break; - info->flags |= DF_STATIC_TLS; - goto do_relocation; - - case R_386_32: - case R_386_PC32: - if (eh != NULL && (sec->flags & SEC_CODE) != 0) - eh->zero_undefweak |= 0x2; -do_relocation: - /* We are called after all symbols have been resolved. Only - relocation against STT_GNU_IFUNC symbol must go through - PLT. */ - if (h != NULL - && (bfd_link_executable (info) - || h->type == STT_GNU_IFUNC)) - { - bfd_boolean func_pointer_ref = FALSE; - - if (r_type == R_386_PC32) - { - /* Since something like ".long foo - ." may be used - as pointer, make sure that PLT is used if foo is - a function defined in a shared library. */ - if ((sec->flags & SEC_CODE) == 0) - h->pointer_equality_needed = 1; - else if (h->type == STT_GNU_IFUNC - && bfd_link_pic (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unsupported non-PIC call to IFUNC `%s'"), - abfd, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - } - else - { - h->pointer_equality_needed = 1; - /* R_386_32 can be resolved at run-time. */ - if (r_type == R_386_32 - && (sec->flags & SEC_READONLY) == 0) - func_pointer_ref = TRUE; - } - - if (!func_pointer_ref) - { - /* 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 symbol is a function - defined in a shared lib or is a function referenced - from the code or read-only section. */ - if (!h->def_regular - || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0) - h->plt.refcount = 1; - } - } - - size_reloc = FALSE; -do_size: - if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type, - R_386_32)) - { - struct elf_dyn_relocs *p; - struct elf_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) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ FALSE); - - if (sreloc == NULL) - goto error_return; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - { - head = &eh->dyn_relocs; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - void **vpp; - asection *s; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - goto error_return; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **)vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, - amt); - if (p == NULL) - goto error_return; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - /* Count size relocation as PC-relative relocation. */ - if (r_type == R_386_PC32 || size_reloc) - 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)) - goto error_return; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_386_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - goto error_return; - break; - - default: - break; - } - } - - if (elf_section_data (sec)->this_hdr.contents != contents) - { - if (!converted && !info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd if any - load is converted or --no-keep-memory isn't used. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - /* Cache relocations if any load is converted. */ - if (elf_section_data (sec)->relocs != relocs && converted) - elf_section_data (sec)->relocs = (Elf_Internal_Rela *) relocs; - - return TRUE; - -error_return: - if (elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - sec->check_relocs_failed = 1; - return FALSE; -} - -/* 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) -{ - 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 relocation value for @tpoff relocation - if STT_TLS virtual address is ADDRESS. */ - -static bfd_vma -elf_i386_tpoff (struct bfd_link_info *info, bfd_vma address) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); - bfd_vma static_tls_size; - - /* If tls_sec is NULL, we should have signalled an error already. */ - if (htab->tls_sec == NULL) - return 0; - - /* Consider special static TLS alignment requirements. */ - static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment); - return static_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_x86_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 *wrel; - Elf_Internal_Rela *relend; - bfd_boolean is_vxworks_tls; - unsigned plt_entry_size; - - /* Skip if check_relocs failed. */ - if (input_section->check_relocs_failed) - return FALSE; - - htab = elf_x86_hash_table (info, I386_ELF_DATA); - if (htab == NULL) - return FALSE; - - BFD_ASSERT (is_x86_elf (input_bfd, htab)); - - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - local_tlsdesc_gotents = elf_x86_local_tlsdesc_gotent (input_bfd); - /* We have to handle relocations in vxworks .tls_vars sections - specially, because the dynamic loader is 'weird'. */ - is_vxworks_tls = (htab->target_os == is_vxworks - && bfd_link_pic (info) - && !strcmp (input_section->output_section->name, - ".tls_vars")); - - _bfd_x86_elf_set_tls_module_base (info); - - plt_entry_size = htab->plt.plt_entry_size; - - rel = wrel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; wrel++, rel++) - { - unsigned int r_type, r_type_tls; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - struct elf_x86_link_hash_entry *eh; - Elf_Internal_Sym *sym; - asection *sec; - bfd_vma off, offplt, plt_offset; - bfd_vma relocation; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - unsigned int indx; - int tls_type; - bfd_vma st_size; - asection *resolved_plt; - bfd_boolean resolved_to_zero; - bfd_boolean relative_reloc; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_386_GNU_VTINHERIT - || r_type == R_386_GNU_VTENTRY) - { - if (wrel != rel) - *wrel = *rel; - 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_ext2 - R_386_ext)) - return _bfd_unrecognized_reloc (input_bfd, input_section, r_type); - - howto = elf_howto_table + indx; - - r_symndx = ELF32_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 = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - st_size = sym->st_size; - - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION - && ((sec->flags & SEC_MERGE) != 0 - || (bfd_link_relocatable (info) - && sec->output_offset != 0))) - { - 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 (); - } - - if (bfd_link_relocatable (info)) - addend += sec->output_offset; - else - { - asection *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 if (!bfd_link_relocatable (info) - && ELF32_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - /* Relocate against local STT_GNU_IFUNC symbol. */ - h = _bfd_elf_x86_get_local_sym_hash (htab, input_bfd, rel, - FALSE); - if (h == NULL) - abort (); - - /* Set STT_GNU_IFUNC symbol value. */ - h->root.u.def.value = sym->st_value; - h->root.u.def.section = sec; - } - } - else - { - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - st_size = h->size; - } - - if (sec != NULL && discarded_section (sec)) - { - _bfd_clear_contents (howto, input_bfd, input_section, - contents + rel->r_offset); - wrel->r_offset = rel->r_offset; - wrel->r_info = 0; - wrel->r_addend = 0; - - /* For ld -r, remove relocations in debug sections against - sections defined in discarded sections. Not done for - eh_frame editing code expects to be present. */ - if (bfd_link_relocatable (info) - && (input_section->flags & SEC_DEBUGGING)) - wrel--; - - continue; - } - - if (bfd_link_relocatable (info)) - { - if (wrel != rel) - *wrel = *rel; - continue; - } - - eh = (struct elf_x86_link_hash_entry *) h; - - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle - it here if it is defined in a non-shared object. */ - if (h != NULL - && h->type == STT_GNU_IFUNC - && h->def_regular) - { - asection *gotplt, *base_got; - bfd_vma plt_index; - const char *name; - - if ((input_section->flags & SEC_ALLOC) == 0) - { - /* 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 ((input_section->flags & SEC_DEBUGGING) != 0) - continue; - abort (); - } - - /* STT_GNU_IFUNC symbol must go through PLT. */ - if (htab->elf.splt != NULL) - { - if (htab->plt_second != NULL) - { - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = htab->elf.splt; - plt_offset = h->plt.offset; - } - gotplt = htab->elf.sgotplt; - } - else - { - resolved_plt = htab->elf.iplt; - plt_offset = h->plt.offset; - gotplt = htab->elf.igotplt; - } - - switch (r_type) - { - default: - break; - - case R_386_GOT32: - case R_386_GOT32X: - base_got = htab->elf.sgot; - off = h->got.offset; - - if (base_got == NULL) - abort (); - - if (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. */ - - if (h->plt.offset == (bfd_vma) -1) - abort (); - - if (htab->elf.splt != NULL) - { - plt_index = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); - off = (plt_index + 3) * 4; - base_got = htab->elf.sgotplt; - } - else - { - plt_index = h->plt.offset / plt_entry_size; - off = plt_index * 4; - base_got = htab->elf.igotplt; - } - - if (h->dynindx == -1 - || h->forced_local - || info->symbolic) - { - /* This references the local defitionion. 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_32 (output_bfd, relocation, - base_got->contents + off); - h->got.offset |= 1; - } - } - - relocation = off; - } - else - relocation = (base_got->output_section->vma - + base_got->output_offset + off - - gotplt->output_section->vma - - gotplt->output_offset); - - if (rel->r_offset > 1 - && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5 - && *(contents + rel->r_offset - 2) != 0x8d) - { - if (bfd_link_pic (info)) - goto disallow_got32; - - /* Add the GOT base if there is no base register. */ - relocation += (gotplt->output_section->vma - + gotplt->output_offset); - } - else if (htab->elf.splt == NULL) - { - /* Adjust for static executables. */ - relocation += gotplt->output_offset; - } - - goto do_relocation; - } - - if (h->plt.offset == (bfd_vma) -1) - { - /* Handle static pointers of STT_GNU_IFUNC symbols. */ - if (r_type == R_386_32 - && (input_section->flags & SEC_CODE) == 0) - goto do_ifunc_pointer; - goto bad_ifunc_reloc; - } - - relocation = (resolved_plt->output_section->vma - + resolved_plt->output_offset + plt_offset); - - switch (r_type) - { - default: -bad_ifunc_reloc: - if (h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' isn't supported"), input_bfd, - howto->name, name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case R_386_32: - /* Generate dynamic relcoation only when there is a - non-GOT reference in a shared object. */ - if ((bfd_link_pic (info) && h->non_got_ref) - || h->plt.offset == (bfd_vma) -1) - { - Elf_Internal_Rela outrel; - asection *sreloc; - bfd_vma offset; - -do_ifunc_pointer: - /* Need a dynamic relocation to get the real function - adddress. */ - offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (offset == (bfd_vma) -1 - || offset == (bfd_vma) -2) - abort (); - - outrel.r_offset = (input_section->output_section->vma - + input_section->output_offset - + offset); - - if (POINTER_LOCAL_IFUNC_P (info, h)) - { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), - h->root.root.string, - h->root.u.def.section->owner); - - /* This symbol is resolved locally. */ - outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); - bfd_put_32 (output_bfd, - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset), - contents + offset); - } - else - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - - /* Dynamic relocations are stored in - 1. .rel.ifunc section in PIC object. - 2. .rel.got section in dynamic executable. - 3. .rel.iplt section in static executable. */ - if (bfd_link_pic (info)) - sreloc = htab->elf.irelifunc; - else if (htab->elf.splt != NULL) - sreloc = htab->elf.srelgot; - else - sreloc = htab->elf.irelplt; - elf_append_rel (output_bfd, sreloc, &outrel); - - /* 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. For an - internal symbol, we have updated addend. */ - continue; - } - /* FALLTHROUGH */ - case R_386_PC32: - case R_386_PLT32: - goto do_relocation; - - case R_386_GOTOFF: - relocation -= (gotplt->output_section->vma - + gotplt->output_offset); - goto do_relocation; - } - } - - resolved_to_zero = (eh != NULL - && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh)); - - switch (r_type) - { - case R_386_GOT32X: - /* Avoid optimizing _DYNAMIC since ld.so may use its - link-time address. */ - if (h == htab->elf.hdynamic) - goto r_386_got32; - - if (bfd_link_pic (info)) - { - /* It is OK to convert mov to lea and convert indirect - branch to direct branch. It is OK to convert adc, - add, and, cmp, or, sbb, sub, test, xor only when PIC - is false. */ - unsigned int opcode, addend; - addend = bfd_get_32 (input_bfd, contents + rel->r_offset); - if (addend != 0) - goto r_386_got32; - opcode = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); - if (opcode != 0x8b && opcode != 0xff) - goto r_386_got32; - } - - /* Resolve "mov GOT[(%reg)], %reg", - "call/jmp *GOT[(%reg)]", "test %reg, foo@GOT[(%reg)]" - and "binop foo@GOT[(%reg)], %reg". */ - if (h == NULL - || (h->plt.offset == (bfd_vma) -1 - && h->got.offset == (bfd_vma) -1) - || htab->elf.sgotplt == NULL) - abort (); - - offplt = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset); - - /* It is relative to .got.plt section. */ - if (h->got.offset != (bfd_vma) -1) - /* Use GOT entry. Mask off the least significant bit in - GOT offset which may be set by R_386_GOT32 processing - below. */ - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + (h->got.offset & ~1) - offplt); - else - /* Use GOTPLT entry. */ - relocation = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0 + 3) * 4; - - if (!bfd_link_pic (info)) - { - /* If not PIC, add the .got.plt section address for - baseless addressing. */ - unsigned int modrm; - modrm = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); - if ((modrm & 0xc7) == 0x5) - relocation += offplt; - } - - unresolved_reloc = FALSE; - break; - - case R_386_GOT32: -r_386_got32: - /* Relocation is to the entry for this symbol in the global - offset table. */ - if (htab->elf.sgot == NULL) - abort (); - - relative_reloc = FALSE; - if (h != NULL) - { - off = h->got.offset; - if (RESOLVED_LOCALLY_P (info, h, htab)) - { - /* 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->elf.sgot->contents + off); - h->got.offset |= 1; - - if (GENERATE_RELATIVE_RELOC_P (info, h)) - { - /* PR ld/21402: If this symbol isn't dynamic - in PIC, generate R_386_RELATIVE here. */ - eh->no_finish_dynamic_symbol = 1; - relative_reloc = TRUE; - } - } - } - 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->elf.sgot->contents + off); - local_got_offsets[r_symndx] |= 1; - - if (bfd_link_pic (info)) - relative_reloc = TRUE; - } - } - - if (relative_reloc) - { - asection *s; - Elf_Internal_Rela outrel; - - s = htab->elf.srelgot; - if (s == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - elf_append_rel (output_bfd, s, &outrel); - } - - if (off >= (bfd_vma) -2) - abort (); - - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - if (rel->r_offset > 1 - && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5 - && *(contents + rel->r_offset - 2) != 0x8d) - { - if (bfd_link_pic (info)) - { - /* For PIC, disallow R_386_GOT32 without a base - register, except for "lea foo@GOT, %reg", since - we don't know what the GOT base is. */ - const char *name; - -disallow_got32: - if (h == NULL || h->root.root.string == NULL) - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - NULL); - else - name = h->root.root.string; - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: direct GOT relocation %s against `%s'" - " without base register can not be used" - " when making a shared object"), - input_bfd, howto->name, name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - else - { - /* Subtract the .got.plt section address only with a base - register. */ - relocation -= (htab->elf.sgotplt->output_section->vma - + htab->elf.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 or data - symbol for shared library since it may not be local when - used as function address or with copy relocation. We also - need to make sure that a symbol is referenced locally. */ - if (!bfd_link_executable (info) && h) - { - if (!h->def_regular) - { - const char *v; - - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_HIDDEN: - v = _("hidden symbol"); - break; - case STV_INTERNAL: - v = _("internal symbol"); - break; - case STV_PROTECTED: - v = _("protected symbol"); - break; - default: - v = _("symbol"); - break; - } - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation R_386_GOTOFF against undefined %s" - " `%s' can not be used when making a shared object"), - input_bfd, v, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else if (!SYMBOL_REFERENCES_LOCAL_P (info, h) - && (h->type == STT_FUNC - || h->type == STT_OBJECT) - && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation R_386_GOTOFF against protected %s" - " `%s' can not be used when making a shared object"), - input_bfd, - h->type == STT_FUNC ? "function" : "data", - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - /* 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->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset; - break; - - case R_386_GOTPC: - /* Use global offset table as symbol value. */ - relocation = htab->elf.sgotplt->output_section->vma - + htab->elf.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 - && eh->plt_got.offset == (bfd_vma) -1) - || htab->elf.splt == NULL) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } - - if (h->plt.offset != (bfd_vma) -1) - { - if (htab->plt_second != NULL) - { - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = htab->elf.splt; - plt_offset = h->plt.offset; - } - } - else - { - resolved_plt = htab->plt_got; - plt_offset = eh->plt_got.offset; - } - - relocation = (resolved_plt->output_section->vma - + resolved_plt->output_offset - + plt_offset); - unresolved_reloc = FALSE; - break; - - case R_386_SIZE32: - /* Set to symbol size. */ - relocation = st_size; - /* Fall through. */ - - case R_386_32: - case R_386_PC32: - if ((input_section->flags & SEC_ALLOC) == 0 - || is_vxworks_tls) - break; - - if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, - FALSE, resolved_to_zero, - (r_type == R_386_PC32))) - { - Elf_Internal_Rela outrel; - 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 (COPY_INPUT_RELOC_P (info, h, r_type)) - 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 || sreloc->contents == NULL) - { - r = bfd_reloc_notsupported; - goto check_relocation_error; - } - - elf_append_rel (output_bfd, sreloc, &outrel); - - /* 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 (!bfd_link_executable (info)) - { - Elf_Internal_Rela outrel; - 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 (); - elf_append_rel (output_bfd, sreloc, &outrel); - } - /* 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: - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - tls_type = elf_x86_hash_entry(h)->tls_type; - if (tls_type == GOT_TLS_IE) - tls_type = GOT_TLS_IE_NEG; - - r_type_tls = r_type; - if (! elf_i386_tls_transition (info, input_bfd, - input_section, contents, - symtab_hdr, sym_hashes, - &r_type_tls, tls_type, rel, - relend, h, r_symndx, TRUE)) - return FALSE; - - if (r_type_tls == R_386_TLS_LE_32) - { - BFD_ASSERT (! unresolved_reloc); - if (r_type == R_386_TLS_GD) - { - unsigned int type; - bfd_vma roff; - - /* GD->LE transition. */ - type = *(contents + rel->r_offset - 2); - if (type == 0x04) - { - /* Change - leal foo@tlsgd(,%ebx,1), %eax - call ___tls_get_addr@PLT - into: - movl %gs:0, %eax - subl $foo@tpoff, %eax - (6 byte form of subl). */ - roff = rel->r_offset + 5; - } - else - { - /* Change - leal foo@tlsgd(%ebx), %eax - call ___tls_get_addr@PLT - nop - or - leal foo@tlsgd(%reg), %eax - call *___tls_get_addr@GOT(%reg) - which may be converted to - addr32 call ___tls_get_addr - into: - movl %gs:0, %eax; subl $foo@tpoff, %eax - (6 byte form of subl). */ - roff = rel->r_offset + 6; - } - memcpy (contents + roff - 8, - "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); - bfd_put_32 (output_bfd, elf_i386_tpoff (info, relocation), - contents + roff); - /* Skip R_386_PC32, R_386_PLT32 and R_386_GOT32X. */ - rel++; - wrel++; - continue; - } - else if (r_type == 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; - bfd_vma roff; - - roff = rel->r_offset; - val = bfd_get_8 (input_bfd, contents + roff - 1); - - /* 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, -elf_i386_tpoff (info, relocation), - contents + roff); - continue; - } - else if (r_type == R_386_TLS_DESC_CALL) - { - /* GDesc -> LE transition. - It's originally: - call *(%eax) - Turn it into: - xchg %ax,%ax */ - - bfd_vma roff; - - roff = rel->r_offset; - bfd_put_8 (output_bfd, 0x66, contents + roff); - bfd_put_8 (output_bfd, 0x90, contents + roff + 1); - continue; - } - else if (r_type == R_386_TLS_IE) - { - unsigned int val; - - /* 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. */ - val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); - if (val == 0xa1) - { - /* movl foo, %eax. */ - bfd_put_8 (output_bfd, 0xb8, - contents + rel->r_offset - 1); - } - else - { - unsigned int type; - - type = bfd_get_8 (input_bfd, - contents + rel->r_offset - 2); - switch (type) - { - case 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); - break; - case 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); - break; - default: - BFD_FAIL (); - break; - } - } - bfd_put_32 (output_bfd, -elf_i386_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. */ - type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); - val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); - 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 (r_type == R_386_TLS_GOTIE) - bfd_put_32 (output_bfd, -elf_i386_tpoff (info, relocation), - contents + rel->r_offset); - else - bfd_put_32 (output_bfd, elf_i386_tpoff (info, relocation), - contents + rel->r_offset); - continue; - } - } - - if (htab->elf.sgot == NULL) - abort (); - - if (h != NULL) - { - off = h->got.offset; - offplt = elf_x86_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; - int dr_type; - asection *sreloc; - - if (htab->elf.srelgot == NULL) - abort (); - - indx = h && h->dynindx != -1 ? h->dynindx : 0; - - if (GOT_TLS_GDESC_P (tls_type)) - { - bfd_byte *loc; - outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_DESC); - BFD_ASSERT (htab->sgotplt_jump_table_size + offplt + 8 - <= htab->elf.sgotplt->size); - outrel.r_offset = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + offplt - + htab->sgotplt_jump_table_size); - sreloc = htab->elf.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 - _bfd_x86_elf_dtpoff_base (info), - htab->elf.sgotplt->contents + offplt - + htab->sgotplt_jump_table_size + 4); - } - else - { - bfd_put_32 (output_bfd, 0, - htab->elf.sgotplt->contents + offplt - + htab->sgotplt_jump_table_size + 4); - } - } - - sreloc = htab->elf.srelgot; - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.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 - _bfd_x86_elf_dtpoff_base (info), - htab->elf.sgot->contents + off); - else if (dr_type == R_386_TLS_TPOFF32 && indx == 0) - bfd_put_32 (output_bfd, - _bfd_x86_elf_dtpoff_base (info) - relocation, - htab->elf.sgot->contents + off); - else if (dr_type != R_386_TLS_DESC) - bfd_put_32 (output_bfd, 0, - htab->elf.sgot->contents + off); - outrel.r_info = ELF32_R_INFO (indx, dr_type); - - elf_append_rel (output_bfd, sreloc, &outrel); - - if (GOT_TLS_GD_P (tls_type)) - { - if (indx == 0) - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_32 (output_bfd, - relocation - _bfd_x86_elf_dtpoff_base (info), - htab->elf.sgot->contents + off + 4); - } - else - { - bfd_put_32 (output_bfd, 0, - htab->elf.sgot->contents + off + 4); - outrel.r_info = ELF32_R_INFO (indx, - R_386_TLS_DTPOFF32); - outrel.r_offset += 4; - elf_append_rel (output_bfd, sreloc, &outrel); - } - } - else if (tls_type == GOT_TLS_IE_BOTH) - { - bfd_put_32 (output_bfd, - (indx == 0 - ? relocation - _bfd_x86_elf_dtpoff_base (info) - : 0), - htab->elf.sgot->contents + off + 4); - outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); - outrel.r_offset += 4; - elf_append_rel (output_bfd, sreloc, &outrel); - } - - 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_tls == R_386_TLS_GOTDESC - || r_type_tls == R_386_TLS_DESC_CALL) - { - relocation = htab->sgotplt_jump_table_size + offplt; - unresolved_reloc = FALSE; - } - else if (r_type_tls == r_type) - { - bfd_vma g_o_t = htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset; - relocation = htab->elf.sgot->output_section->vma - + htab->elf.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 (r_type == R_386_TLS_GD) - { - unsigned int val, type; - bfd_vma roff; - - /* GD->IE transition. */ - type = *(contents + rel->r_offset - 2); - val = *(contents + rel->r_offset - 1); - if (type == 0x04) - { - /* Change - leal foo@tlsgd(,%ebx,1), %eax - call ___tls_get_addr@PLT - into: - movl %gs:0, %eax - subl $foo@gottpoff(%ebx), %eax. */ - val >>= 3; - roff = rel->r_offset - 3; - } - else - { - /* Change - leal foo@tlsgd(%ebx), %eax - call ___tls_get_addr@PLT - nop - or - leal foo@tlsgd(%reg), %eax - call *___tls_get_addr@GOT(%reg) - which may be converted to - addr32 call ___tls_get_addr - into: - movl %gs:0, %eax; - subl $foo@gottpoff(%reg), %eax. */ - 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 (tls_type == GOT_TLS_IE_POS) - contents[roff + 6] = 0x03; - bfd_put_32 (output_bfd, - htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - htab->elf.sgotplt->output_section->vma - - htab->elf.sgotplt->output_offset, - contents + roff + 8); - /* Skip R_386_PLT32 and R_386_GOT32X. */ - rel++; - wrel++; - continue; - } - else if (r_type == 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 xchg %ax,%ax - or: - movl x@gottpoff(%ebx), %eax # before negl %eax - - Registers other than %eax may be set up here. */ - - 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; - - /* 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->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - htab->elf.sgotplt->output_section->vma - - htab->elf.sgotplt->output_offset, - contents + roff); - continue; - } - else if (r_type == R_386_TLS_DESC_CALL) - { - /* GDesc -> IE transition. - It's originally: - call *(%eax) - - Change it to: - xchg %ax,%ax - or - negl %eax - depending on how we transformed the TLS_GOTDESC above. - */ - - bfd_vma roff; - - roff = rel->r_offset; - - /* Now modify the instruction as appropriate. */ - if (tls_type != GOT_TLS_IE_NEG) - { - /* xchg %ax,%ax */ - bfd_put_8 (output_bfd, 0x66, 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 (! elf_i386_tls_transition (info, input_bfd, - input_section, contents, - symtab_hdr, sym_hashes, - &r_type, GOT_UNKNOWN, rel, - relend, h, r_symndx, TRUE)) - return FALSE; - - if (r_type != R_386_TLS_LDM) - { - /* LD->LE transition. Change - leal foo@tlsldm(%ebx) %eax - call ___tls_get_addr@PLT - into: - movl %gs:0, %eax - nop - leal 0(%esi,1), %esi - or change - leal foo@tlsldm(%reg) %eax - call *___tls_get_addr@GOT(%reg) - which may be converted to - addr32 call ___tls_get_addr - into: - movl %gs:0, %eax - leal 0(%esi), %esi */ - BFD_ASSERT (r_type == R_386_TLS_LE_32); - if (*(contents + rel->r_offset + 4) == 0xff - || *(contents + rel->r_offset + 4) == 0x67) - memcpy (contents + rel->r_offset - 2, - "\x65\xa1\0\0\0\0\x8d\xb6\0\0\0", 12); - else - memcpy (contents + rel->r_offset - 2, - "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11); - /* Skip R_386_PC32/R_386_PLT32. */ - rel++; - wrel++; - continue; - } - - if (htab->elf.sgot == NULL) - abort (); - - off = htab->tls_ld_or_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - - if (htab->elf.srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - - bfd_put_32 (output_bfd, 0, - htab->elf.sgot->contents + off); - bfd_put_32 (output_bfd, 0, - htab->elf.sgot->contents + off + 4); - outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32); - elf_append_rel (output_bfd, htab->elf.srelgot, &outrel); - htab->tls_ld_or_ldm_got.offset |= 1; - } - relocation = htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - htab->elf.sgotplt->output_section->vma - - htab->elf.sgotplt->output_offset; - unresolved_reloc = FALSE; - break; - - case R_386_TLS_LDO_32: - if (!bfd_link_executable (info) - || (input_section->flags & SEC_CODE) == 0) - relocation -= _bfd_x86_elf_dtpoff_base (info); - else - /* When converting LDO to LE, we must negate. */ - relocation = -elf_i386_tpoff (info, relocation); - break; - - case R_386_TLS_LE_32: - case R_386_TLS_LE: - if (!bfd_link_executable (info)) - { - Elf_Internal_Rela outrel; - asection *sreloc; - - 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 (); - elf_append_rel (output_bfd, sreloc, &outrel); - if (indx) - continue; - else if (r_type == R_386_TLS_LE_32) - relocation = _bfd_x86_elf_dtpoff_base (info) - relocation; - else - relocation -= _bfd_x86_elf_dtpoff_base (info); - } - else if (r_type == R_386_TLS_LE_32) - relocation = elf_i386_tpoff (info, relocation); - else - relocation = -elf_i386_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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - return FALSE; - } - -do_relocation: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, 0); - -check_relocation_error: - 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) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), - input_bfd, input_section, - rel->r_offset, name, (int) r); - return FALSE; - } - } - - if (wrel != rel) - *wrel = *rel; - } - - if (wrel != rel) - { - Elf_Internal_Shdr *rel_hdr; - size_t deleted = rel - wrel; - - rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - if (rel_hdr->sh_size == 0) - { - /* It is too late to remove an empty reloc section. Leave - one NONE reloc. - ??? What is wrong with an empty section??? */ - rel_hdr->sh_size = rel_hdr->sh_entsize; - deleted -= 1; - } - rel_hdr = _bfd_elf_single_rel_hdr (input_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - input_section->reloc_count -= deleted; - } - - 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_x86_link_hash_table *htab; - unsigned plt_entry_size; - struct elf_x86_link_hash_entry *eh; - bfd_boolean local_undefweak; - bfd_boolean use_plt_second; - - htab = elf_x86_hash_table (info, I386_ELF_DATA); - if (htab == NULL) - return FALSE; - - plt_entry_size = htab->plt.plt_entry_size; - - /* Use the second PLT section only if there is .plt section. */ - use_plt_second = htab->elf.splt != NULL && htab->plt_second != NULL; - - eh = (struct elf_x86_link_hash_entry *) h; - if (eh->no_finish_dynamic_symbol) - abort (); - - /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for - resolved undefined weak symbols in executable so that their - references have value 0 at run-time. */ - local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh); - - if (h->plt.offset != (bfd_vma) -1) - { - bfd_vma plt_index, plt_offset; - bfd_vma got_offset; - Elf_Internal_Rela rel; - bfd_byte *loc; - asection *plt, *resolved_plt, *gotplt, *relplt; - - /* When building a static executable, use .iplt, .igot.plt and - .rel.iplt sections for STT_GNU_IFUNC symbols. */ - if (htab->elf.splt != NULL) - { - plt = htab->elf.splt; - gotplt = htab->elf.sgotplt; - relplt = htab->elf.srelplt; - } - else - { - plt = htab->elf.iplt; - gotplt = htab->elf.igotplt; - relplt = htab->elf.irelplt; - } - - VERIFY_PLT_ENTRY (info, h, plt, gotplt, relplt, local_undefweak) - - /* 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. - - 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. - - For static executables, we don't reserve anything. */ - - if (plt == htab->elf.splt) - { - got_offset = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); - got_offset = (got_offset + 3) * 4; - } - else - { - got_offset = h->plt.offset / plt_entry_size; - got_offset = got_offset * 4; - } - - /* Fill in the entry in the procedure linkage table and update - the first slot. */ - memcpy (plt->contents + h->plt.offset, htab->plt.plt_entry, - plt_entry_size); - - if (use_plt_second) - { - const bfd_byte *plt_entry; - if (bfd_link_pic (info)) - plt_entry = htab->non_lazy_plt->pic_plt_entry; - else - plt_entry = htab->non_lazy_plt->plt_entry; - memcpy (htab->plt_second->contents + eh->plt_second.offset, - plt_entry, htab->non_lazy_plt->plt_entry_size); - - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = plt; - plt_offset = h->plt.offset; - } - - if (! bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, - (gotplt->output_section->vma - + gotplt->output_offset - + got_offset), - resolved_plt->contents + plt_offset - + htab->plt.plt_got_offset); - - if (htab->target_os == 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 - htab->plt.plt_entry_size) - / htab->plt.plt_entry_size); - /* K: Number of relocations for PLTResolve. */ - if (bfd_link_pic (info)) - 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 = (plt->output_section->vma - + plt->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->elf.sgotplt->output_section->vma - + htab->elf.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 - { - bfd_put_32 (output_bfd, got_offset, - resolved_plt->contents + plt_offset - + htab->plt.plt_got_offset); - } - - /* Fill in the entry in the global offset table. Leave the entry - as zero for undefined weak symbol in PIE. No PLT relocation - against undefined weak symbol in PIE. */ - if (!local_undefweak) - { - if (htab->plt.has_plt0) - bfd_put_32 (output_bfd, - (plt->output_section->vma - + plt->output_offset - + h->plt.offset - + htab->lazy_plt->plt_lazy_offset), - gotplt->contents + got_offset); - - /* Fill in the entry in the .rel.plt section. */ - rel.r_offset = (gotplt->output_section->vma - + gotplt->output_offset - + got_offset); - if (PLT_LOCAL_IFUNC_P (info, h)) - { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), - h->root.root.string, - h->root.u.def.section->owner); - - /* If an STT_GNU_IFUNC symbol is locally defined, generate - R_386_IRELATIVE instead of R_386_JUMP_SLOT. Store addend - in the .got.plt section. */ - bfd_put_32 (output_bfd, - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset), - gotplt->contents + got_offset); - rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); - /* R_386_IRELATIVE comes last. */ - plt_index = htab->next_irelative_index--; - } - else - { - rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); - plt_index = htab->next_jump_slot_index++; - } - - loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - - /* Don't fill the second and third slots in PLT entry for - static executables nor without PLT0. */ - if (plt == htab->elf.splt && htab->plt.has_plt0) - { - bfd_put_32 (output_bfd, - plt_index * sizeof (Elf32_External_Rel), - plt->contents + h->plt.offset - + htab->lazy_plt->plt_reloc_offset); - bfd_put_32 (output_bfd, - - (h->plt.offset - + htab->lazy_plt->plt_plt_offset + 4), - (plt->contents + h->plt.offset - + htab->lazy_plt->plt_plt_offset)); - } - } - } - else if (eh->plt_got.offset != (bfd_vma) -1) - { - bfd_vma got_offset, plt_offset; - asection *plt, *got, *gotplt; - const bfd_byte *got_plt_entry; - - /* Set the entry in the GOT procedure linkage table. */ - plt = htab->plt_got; - got = htab->elf.sgot; - gotplt = htab->elf.sgotplt; - got_offset = h->got.offset; - - if (got_offset == (bfd_vma) -1 - || plt == NULL - || got == NULL - || gotplt == NULL) - abort (); - - /* Fill in the entry in the GOT procedure linkage table. */ - if (! bfd_link_pic (info)) - { - got_plt_entry = htab->non_lazy_plt->plt_entry; - got_offset += got->output_section->vma + got->output_offset; - } - else - { - got_plt_entry = htab->non_lazy_plt->pic_plt_entry; - got_offset += (got->output_section->vma - + got->output_offset - - gotplt->output_section->vma - - gotplt->output_offset); - } - - plt_offset = eh->plt_got.offset; - memcpy (plt->contents + plt_offset, got_plt_entry, - htab->non_lazy_plt->plt_entry_size); - bfd_put_32 (output_bfd, got_offset, - (plt->contents + plt_offset - + htab->non_lazy_plt->plt_got_offset)); - } - - if (!local_undefweak - && !h->def_regular - && (h->plt.offset != (bfd_vma) -1 - || eh->plt_got.offset != (bfd_vma) -1)) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value if there were any - relocations where pointer equality matters (this is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library), otherwise set it to zero. If a function is only - called from a binary, there is no need to slow down - shared libraries because of that. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; - } - - /* Don't generate dynamic GOT relocation against undefined weak - symbol in executable. */ - if (h->got.offset != (bfd_vma) -1 - && ! GOT_TLS_GD_ANY_P (elf_x86_hash_entry(h)->tls_type) - && (elf_x86_hash_entry(h)->tls_type & GOT_TLS_IE) == 0 - && !local_undefweak) - { - Elf_Internal_Rela rel; - asection *relgot = htab->elf.srelgot; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL) - abort (); - - rel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.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 (h->def_regular - && h->type == STT_GNU_IFUNC) - { - if (h->plt.offset == (bfd_vma) -1) - { - /* STT_GNU_IFUNC is referenced without PLT. */ - if (htab->elf.splt == NULL) - { - /* use .rel[a].iplt section to store .got relocations - in static executable. */ - relgot = htab->elf.irelplt; - } - if (SYMBOL_REFERENCES_LOCAL_P (info, h)) - { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), - h->root.root.string, - h->root.u.def.section->owner); - - bfd_put_32 (output_bfd, - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset), - htab->elf.sgot->contents + h->got.offset); - rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); - } - else - goto do_glob_dat; - } - else if (bfd_link_pic (info)) - { - /* Generate R_386_GLOB_DAT. */ - goto do_glob_dat; - } - else - { - asection *plt; - bfd_vma plt_offset; - - if (!h->pointer_equality_needed) - abort (); - - /* For non-shared object, we can't use .got.plt, which - contains the real function addres if we need pointer - equality. We load the GOT entry with the PLT entry. */ - if (htab->plt_second != NULL) - { - plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; - plt_offset = h->plt.offset; - } - bfd_put_32 (output_bfd, - (plt->output_section->vma - + plt->output_offset + plt_offset), - htab->elf.sgot->contents + h->got.offset); - return TRUE; - } - } - else if (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL_P (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); -do_glob_dat: - bfd_put_32 (output_bfd, (bfd_vma) 0, - htab->elf.sgot->contents + h->got.offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); - } - - elf_append_rel (output_bfd, relgot, &rel); - } - - if (h->needs_copy) - { - Elf_Internal_Rela rel; - asection *s; - - /* This symbol needs a copy reloc. Set it up. */ - VERIFY_COPY_RELOC (h, htab) - - 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); - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - elf_append_rel (output_bfd, s, &rel); - } - - return TRUE; -} - -/* Finish up local dynamic symbol handling. We set the contents of - various dynamic sections here. */ - -static bfd_boolean -elf_i386_finish_local_dynamic_symbol (void **slot, void *inf) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) *slot; - struct bfd_link_info *info - = (struct bfd_link_info *) inf; - - return elf_i386_finish_dynamic_symbol (info->output_bfd, info, - h, NULL); -} - -/* Finish up undefined weak symbol handling in PIE. Fill its PLT entry - here since undefined weak symbol may not be dynamic and may not be - called for elf_i386_finish_dynamic_symbol. */ - -static bfd_boolean -elf_i386_pie_finish_undefweak_symbol (struct bfd_hash_entry *bh, - void *inf) -{ - struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh; - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - if (h->root.type != bfd_link_hash_undefweak - || h->dynindx != -1) - return TRUE; - - return elf_i386_finish_dynamic_symbol (info->output_bfd, - info, h, NULL); -} - -/* 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 struct bfd_link_info *info, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - bfd *abfd = info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (htab->dynsym != NULL - && htab->dynsym->contents != NULL) - { - /* Check relocation against STT_GNU_IFUNC symbol if there are - dynamic symbols. */ - unsigned long r_symndx = ELF32_R_SYM (rela->r_info); - if (r_symndx != STN_UNDEF) - { - Elf_Internal_Sym sym; - if (!bed->s->swap_symbol_in (abfd, - (htab->dynsym->contents - + r_symndx * sizeof (Elf32_External_Sym)), - 0, &sym)) - abort (); - - if (ELF32_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) - return reloc_class_ifunc; - } - } - - switch (ELF32_R_TYPE (rela->r_info)) - { - case R_386_IRELATIVE: - return reloc_class_ifunc; - 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_x86_link_hash_table *htab; - - htab = _bfd_x86_elf_finish_dynamic_sections (output_bfd, info); - if (htab == NULL) - return FALSE; - - if (!htab->elf.dynamic_sections_created) - return TRUE; - - if (htab->elf.splt && htab->elf.splt->size > 0) - { - /* UnixWare sets the entsize of .plt to 4, although that doesn't - really seem like the right value. */ - elf_section_data (htab->elf.splt->output_section) - ->this_hdr.sh_entsize = 4; - - if (htab->plt.has_plt0) - { - /* Fill in the special first entry in the procedure linkage - table. */ - memcpy (htab->elf.splt->contents, htab->plt.plt0_entry, - htab->lazy_plt->plt0_entry_size); - memset (htab->elf.splt->contents + htab->lazy_plt->plt0_entry_size, - htab->plt0_pad_byte, - htab->plt.plt_entry_size - htab->lazy_plt->plt0_entry_size); - if (!bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 4), - htab->elf.splt->contents - + htab->lazy_plt->plt0_got1_offset); - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 8), - htab->elf.splt->contents - + htab->lazy_plt->plt0_got2_offset); - - if (htab->target_os == is_vxworks) - { - Elf_Internal_Rela rel; - int num_plts = (htab->elf.splt->size - / htab->plt.plt_entry_size) - 1; - unsigned char *p; - asection *srelplt2 = htab->srelplt2; - - /* 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->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + htab->lazy_plt->plt0_got1_offset); - rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, - R_386_32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, - srelplt2->contents); - /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ - + 8. */ - rel.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + htab->lazy_plt->plt0_got2_offset); - rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, - R_386_32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, - srelplt2->contents + - sizeof (Elf32_External_Rel)); - /* Correct the .rel.plt.unloaded relocations. */ - p = srelplt2->contents; - if (bfd_link_pic (info)) - p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); - else - p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel); - - for (; num_plts; num_plts--) - { - 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); - } - } - } - } - } - - /* Fill PLT entries for undefined weak symbols in PIE. */ - if (bfd_link_pie (info)) - bfd_hash_traverse (&info->hash->table, - elf_i386_pie_finish_undefweak_symbol, - info); - - return TRUE; -} - -/* Fill PLT/GOT entries and allocate dynamic relocations for local - STT_GNU_IFUNC symbols, which aren't in the ELF linker hash table. - It has to be done before elf_link_sort_relocs is called so that - dynamic relocations are properly sorted. */ - -static bfd_boolean -elf_i386_output_arch_local_syms - (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - void *flaginfo ATTRIBUTE_UNUSED, - int (*func) (void *, const char *, - Elf_Internal_Sym *, - asection *, - struct elf_link_hash_entry *) ATTRIBUTE_UNUSED) -{ - struct elf_x86_link_hash_table *htab - = elf_x86_hash_table (info, I386_ELF_DATA); - if (htab == NULL) - return FALSE; - - /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ - htab_traverse (htab->loc_hash_table, - elf_i386_finish_local_dynamic_symbol, - info); - - return TRUE; -} - -/* Forward declaration. */ -static const struct elf_x86_lazy_plt_layout elf_i386_nacl_plt; - -/* Similar to _bfd_elf_get_synthetic_symtab. Support PLTs with all - dynamic relocations. */ - -static long -elf_i386_get_synthetic_symtab (bfd *abfd, - long symcount ATTRIBUTE_UNUSED, - asymbol **syms ATTRIBUTE_UNUSED, - long dynsymcount, - asymbol **dynsyms, - asymbol **ret) -{ - long count, i, n; - int j; - bfd_byte *plt_contents; - long relsize; - const struct elf_x86_lazy_plt_layout *lazy_plt; - const struct elf_x86_non_lazy_plt_layout *non_lazy_plt; - const struct elf_x86_lazy_plt_layout *lazy_ibt_plt; - const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt; - asection *plt; - bfd_vma got_addr; - enum elf_x86_plt_type plt_type; - struct elf_x86_plt plts[] = - { - { ".plt", NULL, NULL, plt_unknown, 0, 0, 0, 0 }, - { ".plt.got", NULL, NULL, plt_non_lazy, 0, 0, 0, 0 }, - { ".plt.sec", NULL, NULL, plt_second, 0, 0, 0, 0 }, - { NULL, NULL, NULL, plt_non_lazy, 0, 0, 0, 0 } - }; - - *ret = NULL; - - if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) - return 0; - - if (dynsymcount <= 0) - return 0; - - relsize = bfd_get_dynamic_reloc_upper_bound (abfd); - if (relsize <= 0) - return -1; - - non_lazy_plt = NULL; - /* Silence GCC 6. */ - lazy_plt = NULL; - non_lazy_ibt_plt = NULL; - lazy_ibt_plt = NULL; - switch (get_elf_x86_backend_data (abfd)->target_os) - { - case is_normal: - non_lazy_plt = &elf_i386_non_lazy_plt; - lazy_ibt_plt = &elf_i386_lazy_ibt_plt; - non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt; - /* Fall through */ - case is_vxworks: - lazy_plt = &elf_i386_lazy_plt; - break; - case is_nacl: - lazy_plt = &elf_i386_nacl_plt; - break; - } - - got_addr = 0; - - count = 0; - for (j = 0; plts[j].name != NULL; j++) - { - plt = bfd_get_section_by_name (abfd, plts[j].name); - if (plt == NULL || plt->size == 0) - continue; - - /* Get the PLT section contents. */ - plt_contents = (bfd_byte *) bfd_malloc (plt->size); - if (plt_contents == NULL) - break; - if (!bfd_get_section_contents (abfd, (asection *) plt, - plt_contents, 0, plt->size)) - { - free (plt_contents); - break; - } - - /* Check what kind of PLT it is. */ - plt_type = plt_unknown; - if (plts[j].type == plt_unknown - && (plt->size >= (lazy_plt->plt0_entry_size - + lazy_plt->plt_entry_size))) - { - /* Match lazy PLT first. */ - if (memcmp (plt_contents, lazy_plt->plt0_entry, - lazy_plt->plt0_got1_offset) == 0) - { - /* The fist entry in the lazy IBT PLT is the same as the - normal lazy PLT. */ - if (lazy_ibt_plt != NULL - && (memcmp (plt_contents + lazy_ibt_plt->plt0_entry_size, - lazy_ibt_plt->plt_entry, - lazy_ibt_plt->plt_got_offset) == 0)) - plt_type = plt_lazy | plt_second; - else - plt_type = plt_lazy; - } - else if (memcmp (plt_contents, lazy_plt->pic_plt0_entry, - lazy_plt->plt0_got1_offset) == 0) - { - /* The fist entry in the PIC lazy IBT PLT is the same as - the normal PIC lazy PLT. */ - if (lazy_ibt_plt != NULL - && (memcmp (plt_contents + lazy_ibt_plt->plt0_entry_size, - lazy_ibt_plt->pic_plt_entry, - lazy_ibt_plt->plt_got_offset) == 0)) - plt_type = plt_lazy | plt_pic | plt_second; - else - plt_type = plt_lazy | plt_pic; - } - } - - if (non_lazy_plt != NULL - && (plt_type == plt_unknown || plt_type == plt_non_lazy) - && plt->size >= non_lazy_plt->plt_entry_size) - { - /* Match non-lazy PLT. */ - if (memcmp (plt_contents, non_lazy_plt->plt_entry, - non_lazy_plt->plt_got_offset) == 0) - plt_type = plt_non_lazy; - else if (memcmp (plt_contents, non_lazy_plt->pic_plt_entry, - non_lazy_plt->plt_got_offset) == 0) - plt_type = plt_pic; - } - - if ((non_lazy_ibt_plt != NULL) - && (plt_type == plt_unknown || plt_type == plt_second) - && plt->size >= non_lazy_ibt_plt->plt_entry_size) - { - if (memcmp (plt_contents, - non_lazy_ibt_plt->plt_entry, - non_lazy_ibt_plt->plt_got_offset) == 0) - { - /* Match IBT PLT. */ - plt_type = plt_second; - non_lazy_plt = non_lazy_ibt_plt; - } - else if (memcmp (plt_contents, - non_lazy_ibt_plt->pic_plt_entry, - non_lazy_ibt_plt->plt_got_offset) == 0) - { - /* Match PIC IBT PLT. */ - plt_type = plt_second | plt_pic; - non_lazy_plt = non_lazy_ibt_plt; - } - } - - if (plt_type == plt_unknown) - { - free (plt_contents); - continue; - } - - plts[j].sec = plt; - plts[j].type = plt_type; - - if ((plt_type & plt_lazy)) - { - plts[j].plt_got_offset = lazy_plt->plt_got_offset; - plts[j].plt_entry_size = lazy_plt->plt_entry_size; - /* Skip PLT0 in lazy PLT. */ - i = 1; - } - else - { - plts[j].plt_got_offset = non_lazy_plt->plt_got_offset; - plts[j].plt_entry_size = non_lazy_plt->plt_entry_size; - i = 0; - } - - /* Skip lazy PLT when the second PLT is used. */ - if ((plt_type & (plt_lazy | plt_second)) - == (plt_lazy | plt_second)) - plts[j].count = 0; - else - { - n = plt->size / plts[j].plt_entry_size; - plts[j].count = n; - count += n - i; - } - - plts[j].contents = plt_contents; - - /* The _GLOBAL_OFFSET_TABLE_ address is needed. */ - if ((plt_type & plt_pic)) - got_addr = (bfd_vma) -1; - } - - return _bfd_x86_elf_get_synthetic_symtab (abfd, count, relsize, - got_addr, plts, dynsyms, - ret); -} - -/* Set up i386 GNU properties. Return the first relocatable ELF input - with GNU properties if found. Otherwise, return NULL. */ - -static bfd * -elf_i386_link_setup_gnu_properties (struct bfd_link_info *info) -{ - struct elf_x86_init_table init_table; - - switch (get_elf_x86_backend_data (info->output_bfd)->target_os) - { - case is_normal: - init_table.plt0_pad_byte = 0x0; - init_table.lazy_plt = &elf_i386_lazy_plt; - init_table.non_lazy_plt = &elf_i386_non_lazy_plt; - init_table.lazy_ibt_plt = &elf_i386_lazy_ibt_plt; - init_table.non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt; - break; - case is_vxworks: - init_table.plt0_pad_byte = 0x90; - init_table.lazy_plt = &elf_i386_lazy_plt; - init_table.non_lazy_plt = NULL; - init_table.lazy_ibt_plt = NULL; - init_table.non_lazy_ibt_plt = NULL; - break; - case is_nacl: - init_table.plt0_pad_byte = 0x90; - init_table.lazy_plt = &elf_i386_nacl_plt; - init_table.non_lazy_plt = NULL; - init_table.lazy_ibt_plt = NULL; - init_table.non_lazy_ibt_plt = NULL; - break; - } - - init_table.r_info = elf32_r_info; - init_table.r_sym = elf32_r_sym; - - return _bfd_x86_elf_link_setup_gnu_properties (info, &init_table); -} - -#define TARGET_LITTLE_SYM i386_elf32_vec -#define TARGET_LITTLE_NAME "elf32-i386" -#define ELF_ARCH bfd_arch_i386 -#define ELF_TARGET_ID I386_ELF_DATA -#define ELF_MACHINE_CODE EM_386 -#define ELF_MAXPAGESIZE 0x1000 - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_plt_alignment 4 -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_extern_protected_data 1 -#define elf_backend_caches_rawsize 1 -#define elf_backend_want_dynrelro 1 - -/* 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_bfd_is_local_label_name elf_i386_is_local_label_name -#define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup -#define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab - -#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible -#define elf_backend_check_relocs elf_i386_check_relocs -#define elf_backend_create_dynamic_sections _bfd_elf_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_output_arch_local_syms elf_i386_output_arch_local_syms -#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_setup_gnu_properties elf_i386_link_setup_gnu_properties -#define elf_backend_hide_symbol _bfd_x86_elf_hide_symbol - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" - -/* FreeBSD support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM i386_elf32_fbsd_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-i386-freebsd" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_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_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info) -{ - _bfd_elf_post_process_headers (abfd, info); - -#ifdef OLD_FREEBSD_ABI_LABEL - { - /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ - Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); - } -#endif -} - -#undef elf_backend_post_process_headers -#define elf_backend_post_process_headers elf_i386_fbsd_post_process_headers -#undef elf32_bed -#define elf32_bed elf32_i386_fbsd_bed - -#undef elf_backend_add_symbol_hook - -#include "elf32-target.h" - -/* Solaris 2. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM i386_elf32_sol2_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-i386-sol2" - -#undef elf_backend_post_process_headers - -/* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE - objects won't be recognized. */ -#undef ELF_OSABI - -#undef elf32_bed -#define elf32_bed elf32_i386_sol2_bed - -/* The 32-bit static TLS arena size is rounded to the nearest 8-byte - boundary. */ -#undef elf_backend_static_tls_alignment -#define elf_backend_static_tls_alignment 8 - -/* The Solaris 2 ABI requires a plt symbol on all platforms. - - Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output - File, p.63. */ -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 1 - -#undef elf_backend_strtab_flags -#define elf_backend_strtab_flags SHF_STRINGS - -/* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which - has a type >= SHT_LOOS. Returns TRUE if these fields were initialised - FALSE otherwise. ISECTION is the best guess matching section from the - input bfd IBFD, but it might be NULL. */ - -static bfd_boolean -elf32_i386_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED, - bfd *obfd ATTRIBUTE_UNUSED, - const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *osection ATTRIBUTE_UNUSED) -{ - /* PR 19938: FIXME: Need to add code for setting the sh_info - and sh_link fields of Solaris specific section types. */ - return FALSE; - - /* Based upon Oracle Solaris 11.3 Linkers and Libraries Guide, Ch. 13, - Object File Format, Table 13-9 ELF sh_link and sh_info Interpretation: - -http://docs.oracle.com/cd/E53394_01/html/E54813/chapter6-94076.html#scrolltoc - - The following values should be set: - -Type Link Info ------------------------------------------------------------------------------ -SHT_SUNW_ancillary The section header index of 0 - [0x6fffffee] the associated string table. - -SHT_SUNW_capinfo The section header index of For a dynamic object, the - [0x6ffffff0] the associated symbol table. section header index of - the associated - SHT_SUNW_capchain table, - otherwise 0. - -SHT_SUNW_symsort The section header index of 0 - [0x6ffffff1] the associated symbol table. - -SHT_SUNW_tlssort The section header index of 0 - [0x6ffffff2] the associated symbol table. - -SHT_SUNW_LDYNSYM The section header index of One greater than the - [0x6ffffff3] the associated string table. symbol table index of the - This index is the same string last local symbol, - table used by the SHT_DYNSYM STB_LOCAL. Since - section. SHT_SUNW_LDYNSYM only - contains local symbols, - sh_info is equivalent to - the number of symbols in - the table. - -SHT_SUNW_cap If symbol capabilities exist, If any capabilities refer - [0x6ffffff5] the section header index of to named strings, the - the associated section header index of - SHT_SUNW_capinfo table, the associated string - otherwise 0. table, otherwise 0. - -SHT_SUNW_move The section header index of 0 - [0x6ffffffa] the associated symbol table. - -SHT_SUNW_COMDAT 0 0 - [0x6ffffffb] - -SHT_SUNW_syminfo The section header index of The section header index - [0x6ffffffc] the associated symbol table. of the associated - .dynamic section. - -SHT_SUNW_verdef The section header index of The number of version - [0x6ffffffd] the associated string table. definitions within the - section. - -SHT_SUNW_verneed The section header index of The number of version - [0x6ffffffe] the associated string table. dependencies within the - section. - -SHT_SUNW_versym The section header index of 0 - [0x6fffffff] the associated symbol table. */ -} - -#undef elf_backend_copy_special_section_fields -#define elf_backend_copy_special_section_fields elf32_i386_copy_solaris_special_section_fields - -#include "elf32-target.h" - -/* Intel MCU support. */ - -static bfd_boolean -elf32_iamcu_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for an IAMCU elf32 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_iamcu, bfd_mach_i386_iamcu); - return TRUE; -} - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM iamcu_elf32_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-iamcu" -#undef ELF_ARCH -#define ELF_ARCH bfd_arch_iamcu - -#undef ELF_MACHINE_CODE -#define ELF_MACHINE_CODE EM_IAMCU - -#undef ELF_OSABI - -#undef elf32_bed -#define elf32_bed elf32_iamcu_bed - -#undef elf_backend_object_p -#define elf_backend_object_p elf32_iamcu_elf_object_p - -#undef elf_backend_static_tls_alignment - -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 0 - -#undef elf_backend_strtab_flags -#undef elf_backend_copy_special_section_fields - -#include "elf32-target.h" - -/* Restore defaults. */ -#undef ELF_ARCH -#define ELF_ARCH bfd_arch_i386 -#undef ELF_MACHINE_CODE -#define ELF_MACHINE_CODE EM_386 - -/* Native Client support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM i386_elf32_nacl_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-i386-nacl" -#undef elf32_bed -#define elf32_bed elf32_i386_nacl_bed - -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x10000 - -/* Restore defaults. */ -#undef ELF_OSABI -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 0 -#undef elf_backend_post_process_headers -#undef elf_backend_static_tls_alignment - -/* NaCl uses substantially different PLT entries for the same effects. */ - -#undef elf_backend_plt_alignment -#define elf_backend_plt_alignment 5 -#define NACL_PLT_ENTRY_SIZE 64 -#define NACLMASK 0xe0 /* 32-byte alignment mask. */ - -static const bfd_byte elf_i386_nacl_plt0_entry[] = - { - 0xff, 0x35, /* pushl contents of address */ - 0, 0, 0, 0, /* replaced with address of .got + 4. */ - 0x8b, 0x0d, /* movl contents of address, %ecx */ - 0, 0, 0, 0, /* replaced with address of .got + 8. */ - 0x83, 0xe1, NACLMASK, /* andl $NACLMASK, %ecx */ - 0xff, 0xe1 /* jmp *%ecx */ - }; - -static const bfd_byte elf_i386_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] = - { - 0x8b, 0x0d, /* movl contents of address, %ecx */ - 0, 0, 0, 0, /* replaced with GOT slot address. */ - 0x83, 0xe1, NACLMASK, /* andl $NACLMASK, %ecx */ - 0xff, 0xe1, /* jmp *%ecx */ - - /* Pad to the next 32-byte boundary with nop instructions. */ - 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - - /* Lazy GOT entries point here (32-byte aligned). */ - 0x68, /* pushl immediate */ - 0, 0, 0, 0, /* replaced with reloc offset. */ - 0xe9, /* jmp relative */ - 0, 0, 0, 0, /* replaced with offset to .plt. */ - - /* Pad to the next 32-byte boundary with nop instructions. */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90 - }; - -static const bfd_byte -elf_i386_nacl_pic_plt0_entry[sizeof (elf_i386_nacl_plt0_entry)] = - { - 0xff, 0x73, 0x04, /* pushl 4(%ebx) */ - 0x8b, 0x4b, 0x08, /* mov 0x8(%ebx), %ecx */ - 0x83, 0xe1, 0xe0, /* and $NACLMASK, %ecx */ - 0xff, 0xe1, /* jmp *%ecx */ - - /* This is expected to be the same size as elf_i386_nacl_plt0_entry, - so pad to that size with nop instructions. */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 - }; - -static const bfd_byte elf_i386_nacl_pic_plt_entry[NACL_PLT_ENTRY_SIZE] = - { - 0x8b, 0x8b, /* movl offset(%ebx), %ecx */ - 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ - 0x83, 0xe1, 0xe0, /* andl $NACLMASK, %ecx */ - 0xff, 0xe1, /* jmp *%ecx */ - - /* Pad to the next 32-byte boundary with nop instructions. */ - 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - - /* Lazy GOT entries point here (32-byte aligned). */ - 0x68, /* pushl immediate */ - 0, 0, 0, 0, /* replaced with offset into relocation table. */ - 0xe9, /* jmp relative */ - 0, 0, 0, 0, /* replaced with offset to start of .plt. */ - - /* Pad to the next 32-byte boundary with nop instructions. */ - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90 - }; - -static const bfd_byte elf_i386_nacl_eh_frame_plt[] = - { -#if (PLT_CIE_LENGTH != 20 \ - || PLT_FDE_LENGTH != 36 \ - || PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8 \ - || PLT_FDE_LEN_OFFSET != 4 + PLT_CIE_LENGTH + 12) -# error "Need elf_x86_backend_data parameters for eh_frame_plt offsets!" -#endif - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x7c, /* Data alignment factor: -4 */ - 8, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ - DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_386_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ - DW_CFA_advance_loc + 58, /* DW_CFA_advance_loc: 58 to __PLT__+64 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 13, /* Block length */ - DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ - DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ - DW_OP_const1u, 63, DW_OP_and, DW_OP_const1u, 37, DW_OP_ge, - DW_OP_lit2, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop - }; - -static const struct elf_x86_lazy_plt_layout elf_i386_nacl_plt = - { - elf_i386_nacl_plt0_entry, /* plt0_entry */ - sizeof (elf_i386_nacl_plt0_entry), /* plt0_entry_size */ - elf_i386_nacl_plt_entry, /* plt_entry */ - NACL_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 8, /* plt0_got2_offset */ - 0, /* plt0_got2_insn_end */ - 2, /* plt_got_offset */ - 33, /* plt_reloc_offset */ - 38, /* plt_plt_offset */ - 0, /* plt_got_insn_size */ - 0, /* plt_plt_insn_end */ - 32, /* plt_lazy_offset */ - elf_i386_nacl_pic_plt0_entry, /* pic_plt0_entry */ - elf_i386_nacl_pic_plt_entry, /* pic_plt_entry */ - elf_i386_nacl_eh_frame_plt, /* eh_frame_plt */ - sizeof (elf_i386_nacl_eh_frame_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_backend_data elf_i386_nacl_arch_bed = - { - is_nacl /* os */ - }; - -static bfd_boolean -elf32_i386_nacl_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for a NaCl i386 ELF32 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_i386_i386_nacl); - return TRUE; -} - -#undef elf_backend_arch_data -#define elf_backend_arch_data &elf_i386_nacl_arch_bed - -#undef elf_backend_object_p -#define elf_backend_object_p elf32_i386_nacl_elf_object_p -#undef elf_backend_modify_segment_map -#define elf_backend_modify_segment_map nacl_modify_segment_map -#undef elf_backend_modify_program_headers -#define elf_backend_modify_program_headers nacl_modify_program_headers -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing nacl_final_write_processing - -#include "elf32-target.h" - -/* Restore defaults. */ -#undef elf_backend_object_p -#undef elf_backend_modify_segment_map -#undef elf_backend_modify_program_headers -#undef elf_backend_final_write_processing - -/* VxWorks support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM i386_elf32_vxworks_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-i386-vxworks" -#undef ELF_OSABI -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x1000 -#undef elf_backend_plt_alignment -#define elf_backend_plt_alignment 4 - -static const struct elf_x86_backend_data elf_i386_vxworks_arch_bed = - { - is_vxworks /* os */ - }; - -#undef elf_backend_arch_data -#define elf_backend_arch_data &elf_i386_vxworks_arch_bed - -#undef elf_backend_relocs_compatible -#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 -#undef elf_backend_static_tls_alignment - -/* 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/sdcc/support/sdbinutils/bfd/elf32-i860.c b/sdcc/support/sdbinutils/bfd/elf32-i860.c deleted file mode 100644 index e34965c04..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-i860.c +++ /dev/null @@ -1,1265 +0,0 @@ -/* Intel i860 specific support for 32-bit ELF. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - Full i860 support contributed by Jason Eckhardt . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/i860.h" - -/* special_function for R_860_PC26 relocation. */ -static bfd_reloc_status_type -i860_howto_pc26_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) -{ - bfd_vma insn; - bfd_vma relocation; - bfd_byte *addr; - - 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; - } - - /* Used elf32-mips.c as an example. */ - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Adjust for PC-relative relocation. */ - relocation -= (input_section->output_section->vma - + input_section->output_offset - + reloc_entry->address - + 4); - - /* Check for target out of range. */ - if ((bfd_signed_vma)relocation > (0x3ffffff << 2) - || (bfd_signed_vma)relocation < (-0x4000000 * 4)) - return bfd_reloc_outofrange; - - addr = (bfd_byte *) data + reloc_entry->address; - insn = bfd_get_32 (abfd, addr); - - relocation >>= reloc_entry->howto->rightshift; - insn = (insn & ~reloc_entry->howto->dst_mask) - | (relocation & reloc_entry->howto->dst_mask); - - bfd_put_32 (abfd, (bfd_vma) insn, addr); - - return bfd_reloc_ok; -} - -/* special_function for R_860_PC16 relocation. */ -static bfd_reloc_status_type -i860_howto_pc16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma insn; - bfd_vma relocation; - bfd_byte *addr; - - 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; - } - - /* Used elf32-mips.c as an example. */ - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Adjust for PC-relative relocation. */ - relocation -= (input_section->output_section->vma - + input_section->output_offset - + reloc_entry->address - + 4); - - /* Check for target out of range. */ - if ((bfd_signed_vma)relocation > (0x7fff << 2) - || (bfd_signed_vma)relocation < (-0x8000 * 4)) - return bfd_reloc_outofrange; - - addr = (bfd_byte *) data + reloc_entry->address; - insn = bfd_get_32 (abfd, addr); - - relocation >>= reloc_entry->howto->rightshift; - relocation = (((relocation & 0xf800) << 5) | (relocation & 0x7ff)) - & reloc_entry->howto->dst_mask; - insn = (insn & ~reloc_entry->howto->dst_mask) | relocation; - - bfd_put_32 (abfd, (bfd_vma) insn, addr); - - return bfd_reloc_ok; -} - -/* special_function for R_860_HIGHADJ relocation. */ -static bfd_reloc_status_type -i860_howto_highadj_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma insn; - bfd_vma relocation; - bfd_byte *addr; - - 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; - } - - /* Used elf32-mips.c as an example. */ - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - relocation += 0x8000; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - addr = (bfd_byte *) data + reloc_entry->address; - insn = bfd_get_32 (abfd, addr); - - relocation = ((relocation >> 16) & 0xffff); - - insn = (insn & 0xffff0000) | relocation; - - bfd_put_32 (abfd, (bfd_vma) insn, addr); - - return bfd_reloc_ok; -} - -/* special_function for R_860_SPLITn relocations. */ -static bfd_reloc_status_type -i860_howto_splitn_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma insn; - bfd_vma relocation; - bfd_byte *addr; - - 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; - } - - /* Used elf32-mips.c as an example. */ - if (bfd_is_und_section (symbol->section) - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - addr = (bfd_byte *) data + reloc_entry->address; - insn = bfd_get_32 (abfd, addr); - - relocation = (((relocation & 0xf800) << 5) | (relocation & 0x7ff)) - & reloc_entry->howto->dst_mask; - insn = (insn & ~reloc_entry->howto->dst_mask) | relocation; - - bfd_put_32 (abfd, (bfd_vma) insn, addr); - - return bfd_reloc_ok; -} - -/* This howto table is preliminary. */ -static reloc_howto_type elf32_i860_howto_table [] = -{ - /* This relocation does nothing. */ - HOWTO (R_860_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32-bit absolute relocation. */ - HOWTO (R_860_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_COPY", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_GLOB_DAT", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_JUMP_SLOT", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_RELATIVE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 26-bit PC-relative relocation. */ - HOWTO (R_860_PC26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - i860_howto_pc26_reloc, /* special_function */ - "R_860_PC26", /* name */ - FALSE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_PLT26, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_PLT26", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16-bit PC-relative relocation. */ - HOWTO (R_860_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - i860_howto_pc16_reloc, /* special_function */ - "R_860_PC16", /* name */ - FALSE, /* partial_inplace */ - 0x1f07ff, /* src_mask */ - 0x1f07ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_LOW0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOW0", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_SPLIT0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - i860_howto_splitn_reloc, /* special_function */ - "R_860_SPLIT0", /* name */ - FALSE, /* partial_inplace */ - 0x1f07ff, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOW1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOW1", /* name */ - FALSE, /* partial_inplace */ - 0xfffe, /* src_mask */ - 0xfffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_SPLIT1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - i860_howto_splitn_reloc, /* special_function */ - "R_860_SPLIT1", /* name */ - FALSE, /* partial_inplace */ - 0x1f07fe, /* src_mask */ - 0x1f07fe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOW2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOW2", /* name */ - FALSE, /* partial_inplace */ - 0xfffc, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_SPLIT2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - i860_howto_splitn_reloc, /* special_function */ - "R_860_SPLIT2", /* name */ - FALSE, /* partial_inplace */ - 0x1f07fc, /* src_mask */ - 0x1f07fc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOW3, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOW3", /* name */ - FALSE, /* partial_inplace */ - 0xfff8, /* src_mask */ - 0xfff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOGOT0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOGOT0", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_SPGOT0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_SPGOT0", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_LOGOT1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOGOT1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_SPGOT1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_SPGOT1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_LOGOTOFF0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOGOTOFF0", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_SPGOTOFF0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_SPGOTOFF0", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOGOTOFF1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOGOTOFF1", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_SPGOTOFF1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_SPGOTOFF1", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOGOTOFF2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOGOTOFF2", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOGOTOFF3, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOGOTOFF3", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_LOPC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_LOPC", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_HIGHADJ, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - i860_howto_highadj_reloc, /* special_function */ - "R_860_HIGHADJ", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_HAGOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_HAGOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_HAGOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_HAGOTOFF", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_HAPC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_HAPC", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_HIGH, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_HIGH", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_860_HIGOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_HIGOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_860_HIGOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_860_HIGOTOFF", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static unsigned char elf_code_to_howto_index[R_860_max + 1]; - -static reloc_howto_type * -lookup_howto (unsigned int rtype) -{ - static int initialized = 0; - int i; - int howto_tbl_size = (int) (sizeof (elf32_i860_howto_table) - / sizeof (elf32_i860_howto_table[0])); - - if (! initialized) - { - initialized = 1; - memset (elf_code_to_howto_index, 0xff, - sizeof (elf_code_to_howto_index)); - for (i = 0; i < howto_tbl_size; i++) - elf_code_to_howto_index[elf32_i860_howto_table[i].type] = i; - } - - BFD_ASSERT (rtype <= R_860_max); - i = elf_code_to_howto_index[rtype]; - if (i >= howto_tbl_size) - return 0; - return elf32_i860_howto_table + i; -} - -/* Given a BFD reloc, return the matching HOWTO structure. */ -static reloc_howto_type * -elf32_i860_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int rtype; - - switch (code) - { - case BFD_RELOC_NONE: - rtype = R_860_NONE; - break; - case BFD_RELOC_32: - rtype = R_860_32; - break; - case BFD_RELOC_860_COPY: - rtype = R_860_COPY; - break; - case BFD_RELOC_860_GLOB_DAT: - rtype = R_860_GLOB_DAT; - break; - case BFD_RELOC_860_JUMP_SLOT: - rtype = R_860_JUMP_SLOT; - break; - case BFD_RELOC_860_RELATIVE: - rtype = R_860_RELATIVE; - break; - case BFD_RELOC_860_PC26: - rtype = R_860_PC26; - break; - case BFD_RELOC_860_PLT26: - rtype = R_860_PLT26; - break; - case BFD_RELOC_860_PC16: - rtype = R_860_PC16; - break; - case BFD_RELOC_860_LOW0: - rtype = R_860_LOW0; - break; - case BFD_RELOC_860_SPLIT0: - rtype = R_860_SPLIT0; - break; - case BFD_RELOC_860_LOW1: - rtype = R_860_LOW1; - break; - case BFD_RELOC_860_SPLIT1: - rtype = R_860_SPLIT1; - break; - case BFD_RELOC_860_LOW2: - rtype = R_860_LOW2; - break; - case BFD_RELOC_860_SPLIT2: - rtype = R_860_SPLIT2; - break; - case BFD_RELOC_860_LOW3: - rtype = R_860_LOW3; - break; - case BFD_RELOC_860_LOGOT0: - rtype = R_860_LOGOT0; - break; - case BFD_RELOC_860_SPGOT0: - rtype = R_860_SPGOT0; - break; - case BFD_RELOC_860_LOGOT1: - rtype = R_860_LOGOT1; - break; - case BFD_RELOC_860_SPGOT1: - rtype = R_860_SPGOT1; - break; - case BFD_RELOC_860_LOGOTOFF0: - rtype = R_860_LOGOTOFF0; - break; - case BFD_RELOC_860_SPGOTOFF0: - rtype = R_860_SPGOTOFF0; - break; - case BFD_RELOC_860_LOGOTOFF1: - rtype = R_860_LOGOTOFF1; - break; - case BFD_RELOC_860_SPGOTOFF1: - rtype = R_860_SPGOTOFF1; - break; - case BFD_RELOC_860_LOGOTOFF2: - rtype = R_860_LOGOTOFF2; - break; - case BFD_RELOC_860_LOGOTOFF3: - rtype = R_860_LOGOTOFF3; - break; - case BFD_RELOC_860_LOPC: - rtype = R_860_LOPC; - break; - case BFD_RELOC_860_HIGHADJ: - rtype = R_860_HIGHADJ; - break; - case BFD_RELOC_860_HAGOT: - rtype = R_860_HAGOT; - break; - case BFD_RELOC_860_HAGOTOFF: - rtype = R_860_HAGOTOFF; - break; - case BFD_RELOC_860_HAPC: - rtype = R_860_HAPC; - break; - case BFD_RELOC_860_HIGH: - rtype = R_860_HIGH; - break; - case BFD_RELOC_860_HIGOT: - rtype = R_860_HIGOT; - break; - case BFD_RELOC_860_HIGOTOFF: - rtype = R_860_HIGOTOFF; - break; - default: - rtype = 0; - break; - } - return lookup_howto (rtype); -} - -static reloc_howto_type * -elf32_i860_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf32_i860_howto_table) - / sizeof (elf32_i860_howto_table[0])); - i++) - if (elf32_i860_howto_table[i].name != NULL - && strcasecmp (elf32_i860_howto_table[i].name, r_name) == 0) - return &elf32_i860_howto_table[i]; - - return NULL; -} - -/* Given a ELF reloc, return the matching HOWTO structure. */ -static void -elf32_i860_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - bfd_reloc->howto - = lookup_howto ((unsigned) ELF32_R_TYPE (elf_reloc->r_info)); -} - -/* Specialized relocation handler for R_860_SPLITn. These relocations - involves a 16-bit field that is split into two contiguous parts. */ -static bfd_reloc_status_type -elf32_i860_relocate_splitn (bfd *input_bfd, - Elf_Internal_Rela *rello, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - reloc_howto_type *howto; - howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info)); - insn = bfd_get_32 (input_bfd, contents + rello->r_offset); - - /* Relocate. */ - value += rello->r_addend; - - /* Separate the fields and insert. */ - value = (((value & 0xf800) << 5) | (value & 0x7ff)) & howto->dst_mask; - insn = (insn & ~howto->dst_mask) | value; - - bfd_put_32 (input_bfd, insn, contents + rello->r_offset); - return bfd_reloc_ok; -} - -/* Specialized relocation handler for R_860_PC16. This relocation - involves a 16-bit, PC-relative field that is split into two contiguous - parts. */ -static bfd_reloc_status_type -elf32_i860_relocate_pc16 (bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *rello, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - reloc_howto_type *howto; - howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info)); - insn = bfd_get_32 (input_bfd, contents + rello->r_offset); - - /* Adjust for PC-relative relocation. */ - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= rello->r_offset; - - /* Relocate. */ - value += rello->r_addend; - - /* Adjust the value by 4, then separate the fields and insert. */ - value = (value - 4) >> howto->rightshift; - value = (((value & 0xf800) << 5) | (value & 0x7ff)) & howto->dst_mask; - insn = (insn & ~howto->dst_mask) | value; - - bfd_put_32 (input_bfd, insn, contents + rello->r_offset); - return bfd_reloc_ok; - -} - -/* Specialized relocation handler for R_860_PC26. This relocation - involves a 26-bit, PC-relative field which must be adjusted by 4. */ -static bfd_reloc_status_type -elf32_i860_relocate_pc26 (bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *rello, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - reloc_howto_type *howto; - howto = lookup_howto ((unsigned) ELF32_R_TYPE (rello->r_info)); - insn = bfd_get_32 (input_bfd, contents + rello->r_offset); - - /* Adjust for PC-relative relocation. */ - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= rello->r_offset; - - /* Relocate. */ - value += rello->r_addend; - - /* Adjust value by 4 and insert the field. */ - value = ((value - 4) >> howto->rightshift) & howto->dst_mask; - insn = (insn & ~howto->dst_mask) | value; - - bfd_put_32 (input_bfd, insn, contents + rello->r_offset); - return bfd_reloc_ok; - -} - -/* Specialized relocation handler for R_860_HIGHADJ. */ -static bfd_reloc_status_type -elf32_i860_relocate_highadj (bfd *input_bfd, - Elf_Internal_Rela *rel, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - value += rel->r_addend; - value += 0x8000; - value = ((value >> 16) & 0xffff); - - insn = (insn & 0xffff0000) | value; - - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - return bfd_reloc_ok; -} - -/* Perform a single relocation. By default we use the standard BFD - routines. However, we handle some specially. */ -static bfd_reloc_status_type -i860_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - bfd_vma relocation) -{ - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, relocation, - rel->r_addend); -} - -/* Relocate an i860 ELF section. - - This is boiler-plate code copied from fr30. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ -static bfd_boolean -elf32_i860_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info)); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (r_type) - { - default: - r = i860_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - break; - - case R_860_HIGHADJ: - r = elf32_i860_relocate_highadj (input_bfd, rel, contents, - relocation); - break; - - case R_860_PC16: - r = elf32_i860_relocate_pc16 (input_bfd, input_section, rel, - contents, relocation); - break; - - case R_860_PC26: - r = elf32_i860_relocate_pc26 (input_bfd, input_section, rel, - contents, relocation); - break; - - case R_860_SPLIT0: - case R_860_SPLIT1: - case R_860_SPLIT2: - r = elf32_i860_relocate_splitn (input_bfd, rel, contents, - relocation); - break; - - /* We do not yet handle GOT/PLT/Dynamic relocations. */ - case R_860_COPY: - case R_860_GLOB_DAT: - case R_860_JUMP_SLOT: - case R_860_RELATIVE: - case R_860_PLT26: - case R_860_LOGOT0: - case R_860_SPGOT0: - case R_860_LOGOT1: - case R_860_SPGOT1: - case R_860_LOGOTOFF0: - case R_860_SPGOTOFF0: - case R_860_LOGOTOFF1: - case R_860_SPGOTOFF1: - case R_860_LOGOTOFF2: - case R_860_LOGOTOFF3: - case R_860_LOPC: - case R_860_HAGOT: - case R_860_HAGOTOFF: - case R_860_HAPC: - case R_860_HIGOT: - case R_860_HIGOTOFF: - r = bfd_reloc_notsupported; - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Return whether a symbol name implies a local label. SVR4/860 compilers - generate labels of the form ".ep.function_name" to denote the end of a - function prolog. These should be local. - ??? Do any other SVR4 compilers have this convention? If so, this should - be added to the generic routine. */ -static bfd_boolean -elf32_i860_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == '.' && name[1] == 'e' && name[2] == 'p' && name[3] == '.') - return TRUE; - - return _bfd_elf_is_local_label_name (abfd, name); -} - -#define TARGET_BIG_SYM i860_elf32_vec -#define TARGET_BIG_NAME "elf32-i860" -#define TARGET_LITTLE_SYM i860_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-i860-little" -#define ELF_ARCH bfd_arch_i860 -#define ELF_MACHINE_CODE EM_860 -#define ELF_MAXPAGESIZE 4096 - -#define elf_backend_rela_normal 1 -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto elf32_i860_info_to_howto_rela -#define elf_backend_relocate_section elf32_i860_relocate_section -#define bfd_elf32_bfd_reloc_type_lookup elf32_i860_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf32_i860_reloc_name_lookup -#define bfd_elf32_bfd_is_local_label_name elf32_i860_is_local_label_name - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-i960.c b/sdcc/support/sdbinutils/bfd/elf32-i960.c deleted file mode 100644 index 61a7f9d9e..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-i960.c +++ /dev/null @@ -1,174 +0,0 @@ -/* Intel 960 specific support for 32-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/i960.h" - -#define USE_REL 1 - -#define bfd_elf32_bfd_reloc_type_lookup elf32_i960_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - elf32_i960_reloc_name_lookup -#define elf_info_to_howto elf32_i960_info_to_howto -#define elf_info_to_howto_rel elf32_i960_info_to_howto_rel - -/* 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. */ - -static bfd_reloc_status_type -elf32_i960_relocate (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* HACK: I think this first condition is necessary when producing - relocatable output. After the end of HACK, the code is identical - to bfd_elf_generic_reloc(). I would _guess_ the first change - belongs there rather than here. martindo 1998-10-23. */ - if (output_bfd != (bfd *) NULL - && reloc_entry->howto->pc_relative - && !reloc_entry->howto->pcrel_offset) - reloc_entry->addend -= symbol->value; - - /* This is more dubious. */ - else if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) != 0) - reloc_entry->addend -= symbol->section->output_section->vma; - - else - { - /* ...end of HACK. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - } - - return bfd_reloc_continue; -} - -static reloc_howto_type elf_howto_table[]= -{ - HOWTO (R_960_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, - elf32_i960_relocate, "R_960_NONE", TRUE, - 0x00000000, 0x00000000, FALSE), - EMPTY_HOWTO (1), - HOWTO (R_960_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - elf32_i960_relocate, "R_960_32", TRUE, - 0xffffffff, 0xffffffff, FALSE), - HOWTO (R_960_IP24, 0, 2, 24, TRUE, 0, complain_overflow_signed, - elf32_i960_relocate, "R_960_IP24 ", TRUE, - 0x00ffffff, 0x00ffffff, FALSE), - EMPTY_HOWTO (4), - EMPTY_HOWTO (5), - EMPTY_HOWTO (6), - EMPTY_HOWTO (7) -}; - -static enum elf_i960_reloc_type -elf32_i960_bfd_to_reloc_type (bfd_reloc_code_real_type code) -{ - switch (code) - { - default: - return R_960_NONE; - case BFD_RELOC_I960_CALLJ: - return R_960_OPTCALL; - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - return R_960_32; - case BFD_RELOC_24_PCREL: - return R_960_IP24; - } -} - -static void -elf32_i960_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr ATTRIBUTE_UNUSED, - Elf_Internal_Rela * dst ATTRIBUTE_UNUSED) -{ - abort (); -} - -static void -elf32_i960_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - enum elf_i960_reloc_type type; - - type = (enum elf_i960_reloc_type) ELF32_R_TYPE (dst->r_info); - - /* PR 17521: file: 9609b8d6. */ - if (type >= R_960_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid i960 reloc number: %d"), abfd, type); - type = 0; - } - - cache_ptr->howto = &elf_howto_table[(int) type]; -} - -static reloc_howto_type * -elf32_i960_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - return elf_howto_table + elf32_i960_bfd_to_reloc_type (code); -} - -static reloc_howto_type * -elf32_i960_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - return NULL; -} - -#define TARGET_LITTLE_SYM i960_elf32_vec -#define TARGET_LITTLE_NAME "elf32-i960" -#define ELF_ARCH bfd_arch_i960 -#define ELF_MACHINE_CODE EM_960 -#define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */ - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-ip2k.c b/sdcc/support/sdbinutils/bfd/elf32-ip2k.c deleted file mode 100644 index 3733ebb2f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-ip2k.c +++ /dev/null @@ -1,1523 +0,0 @@ -/* Ubicom IP2xxx specific support for 32-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/ip2k.h" - -/* Struct used to pass miscellaneous paramaters which - helps to avoid overly long parameter lists. */ -struct misc -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Rela * irelbase; - bfd_byte * contents; - Elf_Internal_Sym * isymbuf; -}; - -struct ip2k_opcode -{ - unsigned short opcode; - unsigned short mask; -}; - -static bfd_boolean ip2k_relaxed = FALSE; - -static const struct ip2k_opcode ip2k_page_opcode[] = -{ - {0x0010, 0xFFF8}, /* Page. */ - {0x0000, 0x0000}, -}; - -#define IS_PAGE_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_page_opcode) - -static const struct ip2k_opcode ip2k_jmp_opcode[] = -{ - {0xE000, 0xE000}, /* Jmp. */ - {0x0000, 0x0000}, -}; - -#define IS_JMP_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_jmp_opcode) - -static const struct ip2k_opcode ip2k_snc_opcode[] = -{ - {0xA00B, 0xFFFF}, /* Snc. */ - {0x0000, 0x0000}, -}; - -#define IS_SNC_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_snc_opcode) - -static const struct ip2k_opcode ip2k_inc_1sp_opcode[] = -{ - {0x2B81, 0xFFFF}, /* Inc 1(SP). */ - {0x0000, 0x0000}, -}; - -#define IS_INC_1SP_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_inc_1sp_opcode) - -static const struct ip2k_opcode ip2k_add_2sp_w_opcode[] = -{ - {0x1F82, 0xFFFF}, /* Add 2(SP),w. */ - {0x0000, 0x0000}, -}; - -#define IS_ADD_2SP_W_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_add_2sp_w_opcode) - -static const struct ip2k_opcode ip2k_add_w_wreg_opcode[] = -{ - {0x1C0A, 0xFFFF}, /* Add w,wreg. */ - {0x1E0A, 0xFFFF}, /* Add wreg,w. */ - {0x0000, 0x0000}, -}; - -#define IS_ADD_W_WREG_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_add_w_wreg_opcode) - -static const struct ip2k_opcode ip2k_add_pcl_w_opcode[] = -{ - {0x1E09, 0xFFFF}, /* Add pcl,w. */ - {0x0000, 0x0000}, -}; - -#define IS_ADD_PCL_W_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_add_pcl_w_opcode) - -static const struct ip2k_opcode ip2k_skip_opcodes[] = -{ - {0xB000, 0xF000}, /* sb */ - {0xA000, 0xF000}, /* snb */ - {0x7600, 0xFE00}, /* cse/csne #lit */ - {0x5800, 0xFC00}, /* incsnz */ - {0x4C00, 0xFC00}, /* decsnz */ - {0x4000, 0xFC00}, /* cse/csne */ - {0x3C00, 0xFC00}, /* incsz */ - {0x2C00, 0xFC00}, /* decsz */ - {0x0000, 0x0000}, -}; - -#define IS_SKIP_OPCODE(code) \ - ip2k_is_opcode (code, ip2k_skip_opcodes) - -/* Relocation tables. */ -static reloc_howto_type ip2k_elf_howto_table [] = -{ -#define IP2K_HOWTO(t,rs,s,bs,pr,bp,name,sm,dm) \ - HOWTO(t, /* type */ \ - rs, /* rightshift */ \ - s, /* size (0 = byte, 1 = short, 2 = long) */ \ - bs, /* bitsize */ \ - pr, /* pc_relative */ \ - bp, /* bitpos */ \ - complain_overflow_dont,/* complain_on_overflow */ \ - bfd_elf_generic_reloc,/* special_function */ \ - name, /* name */ \ - FALSE, /* partial_inplace */ \ - sm, /* src_mask */ \ - dm, /* dst_mask */ \ - pr) /* pcrel_offset */ - - /* This reloc does nothing. */ - IP2K_HOWTO (R_IP2K_NONE, 0,3,0, FALSE, 0, "R_IP2K_NONE", 0, 0), - /* A 16 bit absolute relocation. */ - IP2K_HOWTO (R_IP2K_16, 0,1,16, FALSE, 0, "R_IP2K_16", 0, 0xffff), - /* A 32 bit absolute relocation. */ - IP2K_HOWTO (R_IP2K_32, 0,2,32, FALSE, 0, "R_IP2K_32", 0, 0xffffffff), - /* A 8-bit data relocation for the FR9 field. Ninth bit is computed specially. */ - IP2K_HOWTO (R_IP2K_FR9, 0,1,9, FALSE, 0, "R_IP2K_FR9", 0, 0x00ff), - /* A 4-bit data relocation. */ - IP2K_HOWTO (R_IP2K_BANK, 8,1,4, FALSE, 0, "R_IP2K_BANK", 0, 0x000f), - /* A 13-bit insn relocation - word address => right-shift 1 bit extra. */ - IP2K_HOWTO (R_IP2K_ADDR16CJP, 1,1,13, FALSE, 0, "R_IP2K_ADDR16CJP", 0, 0x1fff), - /* A 3-bit insn relocation - word address => right-shift 1 bit extra. */ - IP2K_HOWTO (R_IP2K_PAGE3, 14,1,3, FALSE, 0, "R_IP2K_PAGE3", 0, 0x0007), - /* Two 8-bit data relocations. */ - IP2K_HOWTO (R_IP2K_LO8DATA, 0,1,8, FALSE, 0, "R_IP2K_LO8DATA", 0, 0x00ff), - IP2K_HOWTO (R_IP2K_HI8DATA, 8,1,8, FALSE, 0, "R_IP2K_HI8DATA", 0, 0x00ff), - /* Two 8-bit insn relocations. word address => right-shift 1 bit extra. */ - IP2K_HOWTO (R_IP2K_LO8INSN, 1,1,8, FALSE, 0, "R_IP2K_LO8INSN", 0, 0x00ff), - IP2K_HOWTO (R_IP2K_HI8INSN, 9,1,8, FALSE, 0, "R_IP2K_HI8INSN", 0, 0x00ff), - - /* Special 1 bit relocation for SKIP instructions. */ - IP2K_HOWTO (R_IP2K_PC_SKIP, 1,1,1, FALSE, 12, "R_IP2K_PC_SKIP", 0xfffe, 0x1000), - /* 16 bit word address. */ - IP2K_HOWTO (R_IP2K_TEXT, 1,1,16, FALSE, 0, "R_IP2K_TEXT", 0, 0xffff), - /* A 7-bit offset relocation for the FR9 field. Eigth and ninth bit comes from insn. */ - IP2K_HOWTO (R_IP2K_FR_OFFSET, 0,1,9, FALSE, 0, "R_IP2K_FR_OFFSET", 0x180, 0x007f), - /* Bits 23:16 of an address. */ - IP2K_HOWTO (R_IP2K_EX8DATA, 16,1,8, FALSE, 0, "R_IP2K_EX8DATA", 0, 0x00ff), -}; - - -/* Map BFD reloc types to IP2K ELF reloc types. */ - -static reloc_howto_type * -ip2k_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - /* Note that the ip2k_elf_howto_table is indxed by the R_ - constants. Thus, the order that the howto records appear in the - table *must* match the order of the relocation types defined in - include/elf/ip2k.h. */ - - switch (code) - { - case BFD_RELOC_NONE: - return &ip2k_elf_howto_table[ (int) R_IP2K_NONE]; - case BFD_RELOC_16: - return &ip2k_elf_howto_table[ (int) R_IP2K_16]; - case BFD_RELOC_32: - return &ip2k_elf_howto_table[ (int) R_IP2K_32]; - case BFD_RELOC_IP2K_FR9: - return &ip2k_elf_howto_table[ (int) R_IP2K_FR9]; - case BFD_RELOC_IP2K_BANK: - return &ip2k_elf_howto_table[ (int) R_IP2K_BANK]; - case BFD_RELOC_IP2K_ADDR16CJP: - return &ip2k_elf_howto_table[ (int) R_IP2K_ADDR16CJP]; - case BFD_RELOC_IP2K_PAGE3: - return &ip2k_elf_howto_table[ (int) R_IP2K_PAGE3]; - case BFD_RELOC_IP2K_LO8DATA: - return &ip2k_elf_howto_table[ (int) R_IP2K_LO8DATA]; - case BFD_RELOC_IP2K_HI8DATA: - return &ip2k_elf_howto_table[ (int) R_IP2K_HI8DATA]; - case BFD_RELOC_IP2K_LO8INSN: - return &ip2k_elf_howto_table[ (int) R_IP2K_LO8INSN]; - case BFD_RELOC_IP2K_HI8INSN: - return &ip2k_elf_howto_table[ (int) R_IP2K_HI8INSN]; - case BFD_RELOC_IP2K_PC_SKIP: - return &ip2k_elf_howto_table[ (int) R_IP2K_PC_SKIP]; - case BFD_RELOC_IP2K_TEXT: - return &ip2k_elf_howto_table[ (int) R_IP2K_TEXT]; - case BFD_RELOC_IP2K_FR_OFFSET: - return &ip2k_elf_howto_table[ (int) R_IP2K_FR_OFFSET]; - case BFD_RELOC_IP2K_EX8DATA: - return &ip2k_elf_howto_table[ (int) R_IP2K_EX8DATA]; - default: - /* Pacify gcc -Wall. */ - return NULL; - } - return NULL; -} - -static reloc_howto_type * -ip2k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (ip2k_elf_howto_table) / sizeof (ip2k_elf_howto_table[0]); - i++) - if (ip2k_elf_howto_table[i].name != NULL - && strcasecmp (ip2k_elf_howto_table[i].name, r_name) == 0) - return &ip2k_elf_howto_table[i]; - - return NULL; -} - -static void -ip2k_get_mem (bfd *abfd ATTRIBUTE_UNUSED, - bfd_byte *addr, - int length, - bfd_byte *ptr) -{ - while (length --) - * ptr ++ = bfd_get_8 (abfd, addr ++); -} - -static bfd_boolean -ip2k_is_opcode (bfd_byte *code, const struct ip2k_opcode *opcodes) -{ - unsigned short insn = (code[0] << 8) | code[1]; - - while (opcodes->mask != 0) - { - if ((insn & opcodes->mask) == opcodes->opcode) - return TRUE; - - opcodes ++; - } - - return FALSE; -} - -#define PAGENO(ABSADDR) ((ABSADDR) & 0xFFFFC000) -#define BASEADDR(SEC) ((SEC)->output_section->vma + (SEC)->output_offset) - -#define UNDEFINED_SYMBOL (~(bfd_vma)0) - -/* Return the value of the symbol associated with the relocation IREL. */ - -static bfd_vma -symbol_value (bfd *abfd, - Elf_Internal_Shdr *symtab_hdr, - Elf_Internal_Sym *isymbuf, - Elf_Internal_Rela *irel) -{ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - return isym->st_value + BASEADDR (sym_sec); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - return UNDEFINED_SYMBOL; - - return (h->root.u.def.value + BASEADDR (h->root.u.def.section)); - } -} - -/* Determine if the instruction sequence matches that for - the prologue of a switch dispatch table with fewer than - 128 entries. - - sc - page $nnn0 - jmp $nnn0 - add w,wreg - add pcl,w - addr=> - page $nnn1 - jmp $nnn1 - page $nnn2 - jmp $nnn2 - ... - page $nnnN - jmp $nnnN - - After relaxation. - sc - page $nnn0 - jmp $nnn0 - add pcl,w - addr=> - jmp $nnn1 - jmp $nnn2 - ... - jmp $nnnN */ - -static int -ip2k_is_switch_table_128 (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - bfd_vma addr, - bfd_byte *contents) -{ - bfd_byte code[4]; - int table_index = 0; - - /* Check current page-jmp. */ - if (addr + 4 > sec->size) - return -1; - - ip2k_get_mem (abfd, contents + addr, 4, code); - - if ((! IS_PAGE_OPCODE (code + 0)) - || (! IS_JMP_OPCODE (code + 2))) - return -1; - - /* Search back. */ - while (1) - { - if (addr < 4) - return -1; - - /* Check previous 2 instructions. */ - ip2k_get_mem (abfd, contents + addr - 4, 4, code); - if ((IS_ADD_W_WREG_OPCODE (code + 0)) - && (IS_ADD_PCL_W_OPCODE (code + 2))) - return table_index; - - if ((! IS_PAGE_OPCODE (code + 0)) - || (! IS_JMP_OPCODE (code + 2))) - return -1; - - table_index++; - addr -= 4; - } -} - -/* Determine if the instruction sequence matches that for - the prologue switch dispatch table with fewer than - 256 entries but more than 127. - - Before relaxation. - push %lo8insn(label) ; Push address of table - push %hi8insn(label) - add w,wreg ; index*2 => offset - snc ; CARRY SET? - inc 1(sp) ; Propagate MSB into table address - add 2(sp),w ; Add low bits of offset to table address - snc ; and handle any carry-out - inc 1(sp) - addr=> - page __indjmp ; Do an indirect jump to that location - jmp __indjmp - label: ; case dispatch table starts here - page $nnn1 - jmp $nnn1 - page $nnn2 - jmp $nnn2 - ... - page $nnnN - jmp $nnnN - - After relaxation. - push %lo8insn(label) ; Push address of table - push %hi8insn(label) - add 2(sp),w ; Add low bits of offset to table address - snc ; and handle any carry-out - inc 1(sp) - addr=> - page __indjmp ; Do an indirect jump to that location - jmp __indjmp - label: ; case dispatch table starts here - jmp $nnn1 - jmp $nnn2 - ... - jmp $nnnN */ - -static int -ip2k_is_switch_table_256 (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - bfd_vma addr, - bfd_byte *contents) -{ - bfd_byte code[16]; - int table_index = 0; - - /* Check current page-jmp. */ - if (addr + 4 > sec->size) - return -1; - - ip2k_get_mem (abfd, contents + addr, 4, code); - if ((! IS_PAGE_OPCODE (code + 0)) - || (! IS_JMP_OPCODE (code + 2))) - return -1; - - /* Search back. */ - while (1) - { - if (addr < 16) - return -1; - - /* Check previous 8 instructions. */ - ip2k_get_mem (abfd, contents + addr - 16, 16, code); - if ((IS_ADD_W_WREG_OPCODE (code + 0)) - && (IS_SNC_OPCODE (code + 2)) - && (IS_INC_1SP_OPCODE (code + 4)) - && (IS_ADD_2SP_W_OPCODE (code + 6)) - && (IS_SNC_OPCODE (code + 8)) - && (IS_INC_1SP_OPCODE (code + 10)) - && (IS_PAGE_OPCODE (code + 12)) - && (IS_JMP_OPCODE (code + 14))) - return table_index; - - if ((IS_ADD_W_WREG_OPCODE (code + 2)) - && (IS_SNC_OPCODE (code + 4)) - && (IS_INC_1SP_OPCODE (code + 6)) - && (IS_ADD_2SP_W_OPCODE (code + 8)) - && (IS_SNC_OPCODE (code + 10)) - && (IS_INC_1SP_OPCODE (code + 12)) - && (IS_JMP_OPCODE (code + 14))) - return table_index; - - if ((! IS_PAGE_OPCODE (code + 0)) - || (! IS_JMP_OPCODE (code + 2))) - return -1; - - table_index++; - addr -= 4; - } -} - -/* Returns the expected page state for the given instruction not including - the effect of page instructions. */ - -static bfd_vma -ip2k_nominal_page_bits (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - bfd_vma addr, - bfd_byte *contents) -{ - bfd_vma page = PAGENO (BASEADDR (sec) + addr); - - /* Check if section flows into this page. If not then the page - bits are assumed to match the PC. This will be true unless - the user has a page instruction without a call/jump, in which - case they are on their own. */ - if (PAGENO (BASEADDR (sec)) == page) - return page; - - /* Section flows across page boundary. The page bits should match - the PC unless there is a possible flow from the previous page, - in which case it is not possible to determine the value of the - page bits. */ - while (PAGENO (BASEADDR (sec) + addr - 2) == page) - { - bfd_byte code[2]; - - addr -= 2; - ip2k_get_mem (abfd, contents + addr, 2, code); - if (!IS_PAGE_OPCODE (code)) - continue; - - /* Found a page instruction, check if jump table. */ - if (ip2k_is_switch_table_128 (abfd, sec, addr, contents) != -1) - /* Jump table => page is conditional. */ - continue; - - if (ip2k_is_switch_table_256 (abfd, sec, addr, contents) != -1) - /* Jump table => page is conditional. */ - continue; - - /* Found a page instruction, check if conditional. */ - if (addr >= 2) - { - ip2k_get_mem (abfd, contents + addr - 2, 2, code); - if (IS_SKIP_OPCODE (code)) - /* Page is conditional. */ - continue; - } - - /* Unconditional page instruction => page bits should be correct. */ - return page; - } - - /* Flow from previous page => page bits are impossible to determine. */ - return 0; -} - -static bfd_boolean -ip2k_test_page_insn (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - Elf_Internal_Rela *irel, - struct misc *misc) -{ - bfd_vma symval; - - /* Get the value of the symbol referred to by the reloc. */ - symval = symbol_value (abfd, misc->symtab_hdr, misc->isymbuf, irel); - if (symval == UNDEFINED_SYMBOL) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - return FALSE; - - /* Test if we can delete this page instruction. */ - if (PAGENO (symval + irel->r_addend) != - ip2k_nominal_page_bits (abfd, sec, irel->r_offset, misc->contents)) - return FALSE; - - return TRUE; -} - -/* Parts of a Stabs entry. */ - -#define STRDXOFF 0 -#define TYPEOFF 4 -#define OTHEROFF 5 -#define DESCOFF 6 -#define VALOFF 8 -#define STABSIZE 12 - -/* Adjust all the relocations entries after adding or inserting instructions. */ - -static void -adjust_all_relocations (bfd *abfd, - asection *sec, - bfd_vma addr, - bfd_vma endaddr, - int count, - int noadj) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf, *isym, *isymend; - unsigned int shndx; - Elf_Internal_Rela *irel, *irelend, *irelbase; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - asection *stab; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - - shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - irelbase = elf_section_data (sec)->relocs; - irelend = irelbase + sec->reloc_count; - - for (irel = irelbase; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) != R_IP2K_NONE) - { - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - asection *sym_sec; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - if (isym->st_shndx == shndx) - { - bfd_vma baseaddr = BASEADDR (sec); - bfd_vma symval = BASEADDR (sym_sec) + isym->st_value - + irel->r_addend; - - if ((baseaddr + addr + noadj) <= symval - && symval < (baseaddr + endaddr)) - irel->r_addend += count; - } - } - } - - /* Do this only for PC space relocations. */ - if (addr <= irel->r_offset && irel->r_offset < endaddr) - irel->r_offset += count; - } - - /* Now fix the stab relocations. */ - stab = bfd_get_section_by_name (abfd, ".stab"); - if (stab) - { - bfd_byte *stabcontents, *stabend, *stabp; - bfd_size_type stab_size = stab->rawsize ? stab->rawsize : stab->size; - - irelbase = elf_section_data (stab)->relocs; - irelend = irelbase + stab->reloc_count; - - /* Pull out the contents of the stab section. */ - if (elf_section_data (stab)->this_hdr.contents != NULL) - stabcontents = elf_section_data (stab)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (abfd, stab, &stabcontents)) - { - if (stabcontents != NULL) - free (stabcontents); - return; - } - - /* We need to remember this. */ - elf_section_data (stab)->this_hdr.contents = stabcontents; - } - - stabend = stabcontents + stab_size; - - for (irel = irelbase; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) != R_IP2K_NONE) - { - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - asection *sym_sec; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - if (sym_sec == sec) - { - const char *name; - unsigned char type; - bfd_vma value; - bfd_vma baseaddr = BASEADDR (sec); - bfd_vma symval = BASEADDR (sym_sec) + isym->st_value - + irel->r_addend; - - if ((baseaddr + addr) <= symval - && symval <= (baseaddr + endaddr)) - irel->r_addend += count; - - /* Go hunt up a function and fix its line info if needed. */ - stabp = stabcontents + irel->r_offset - 8; - - /* Go pullout the stab entry. */ - type = bfd_h_get_8 (abfd, stabp + TYPEOFF); - value = bfd_h_get_32 (abfd, stabp + VALOFF); - - name = bfd_get_stab_name (type); - - if (strcmp (name, "FUN") == 0) - { - int function_adjusted = 0; - - if (symval > (baseaddr + addr)) - /* Not in this function. */ - continue; - - /* Hey we got a function hit. */ - stabp += STABSIZE; - for (;stabp < stabend; stabp += STABSIZE) - { - /* Go pullout the stab entry. */ - type = bfd_h_get_8 (abfd, stabp + TYPEOFF); - value = bfd_h_get_32 (abfd, stabp + VALOFF); - - name = bfd_get_stab_name (type); - - if (strcmp (name, "FUN") == 0) - { - /* Hit another function entry. */ - if (function_adjusted) - { - /* Adjust the value. */ - value += count; - - /* We need to put it back. */ - bfd_h_put_32 (abfd, value,stabp + VALOFF); - } - - /* And then bale out. */ - break; - } - - if (strcmp (name, "SLINE") == 0) - { - /* Got a line entry. */ - if ((baseaddr + addr) <= (symval + value)) - { - /* Adjust the line entry. */ - value += count; - - /* We need to put it back. */ - bfd_h_put_32 (abfd, value,stabp + VALOFF); - function_adjusted = 1; - } - } - } - } - } - } - } - } - } - - /* When adding an instruction back it is sometimes necessary to move any - global or local symbol that was referencing the first instruction of - the moved block to refer to the first instruction of the inserted block. - - For example adding a PAGE instruction before a CALL or JMP requires - that any label on the CALL or JMP is moved to the PAGE insn. */ - addr += noadj; - - /* Adjust the local symbols defined in this section. */ - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf; isym < isymend; isym++) - { - if (isym->st_shndx == shndx - && addr <= isym->st_value - && isym->st_value < endaddr) - isym->st_value += count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - if (addr <= sym_hash->root.u.def.value - && sym_hash->root.u.def.value < endaddr) - sym_hash->root.u.def.value += count; - } - } - - return; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -ip2k_elf_relax_delete_bytes (bfd *abfd, - asection *sec, - bfd_vma addr, - int count) -{ - bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; - bfd_vma endaddr = sec->size; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - endaddr - addr - count); - - sec->size -= count; - - adjust_all_relocations (abfd, sec, addr + count, endaddr, -count, 0); - return TRUE; -} - -static bfd_boolean -ip2k_delete_page_insn (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - Elf_Internal_Rela *irel, - bfd_boolean *again, - struct misc *misc) -{ - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = misc->irelbase; - elf_section_data (sec)->this_hdr.contents = misc->contents; - misc->symtab_hdr->contents = (bfd_byte *) misc->isymbuf; - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_IP2K_NONE); - - /* Delete the PAGE insn. */ - if (!ip2k_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 2)) - return FALSE; - - /* Modified => will need to iterate relaxation again. */ - *again = TRUE; - - return TRUE; -} - -static bfd_boolean -ip2k_relax_switch_table_128 (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - Elf_Internal_Rela *irel, - bfd_boolean *again, - struct misc *misc) -{ - Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; - Elf_Internal_Rela *ireltest = irel; - bfd_byte code[4]; - bfd_vma addr; - - /* Test all page instructions. */ - addr = irel->r_offset; - while (1) - { - if (addr + 4 > sec->size) - break; - - ip2k_get_mem (abfd, misc->contents + addr, 4, code); - if ((! IS_PAGE_OPCODE (code + 0)) - || (! IS_JMP_OPCODE (code + 2))) - break; - - /* Validate relocation entry (every entry should have a matching - relocation entry). */ - if (ireltest >= irelend) - { - _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); - return FALSE; - } - - if (ireltest->r_offset != addr) - { - _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); - return FALSE; - } - - if (! ip2k_test_page_insn (abfd, sec, ireltest, misc)) - /* Un-removable page insn => nothing can be done. */ - return TRUE; - - addr += 4; - ireltest += 2; - } - - /* Relaxable. Adjust table header. */ - ip2k_get_mem (abfd, misc->contents + irel->r_offset - 4, 4, code); - if ((! IS_ADD_W_WREG_OPCODE (code + 0)) - || (! IS_ADD_PCL_W_OPCODE (code + 2))) - { - _bfd_error_handler (_("ip2k relaxer: switch table header corrupt.")); - return FALSE; - } - - if (!ip2k_elf_relax_delete_bytes (abfd, sec, irel->r_offset - 4, 2)) - return FALSE; - - *again = TRUE; - - /* Delete all page instructions in table. */ - while (irel < ireltest) - { - if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc)) - return FALSE; - irel += 2; - } - - return TRUE; -} - -static bfd_boolean -ip2k_relax_switch_table_256 (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - Elf_Internal_Rela *irel, - bfd_boolean *again, - struct misc *misc) -{ - Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; - Elf_Internal_Rela *ireltest = irel; - bfd_byte code[12]; - bfd_vma addr; - - /* Test all page instructions. */ - addr = irel->r_offset; - - while (1) - { - if (addr + 4 > sec->size) - break; - - ip2k_get_mem (abfd, misc->contents + addr, 4, code); - - if ((! IS_PAGE_OPCODE (code + 0)) - || (! IS_JMP_OPCODE (code + 2))) - break; - - /* Validate relocation entry (every entry should have a matching - relocation entry). */ - if (ireltest >= irelend) - { - _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); - return FALSE; - } - - if (ireltest->r_offset != addr) - { - _bfd_error_handler (_("ip2k relaxer: switch table without complete matching relocation information.")); - return FALSE; - } - - if (!ip2k_test_page_insn (abfd, sec, ireltest, misc)) - /* Un-removable page insn => nothing can be done. */ - return TRUE; - - addr += 4; - ireltest += 2; - } - - /* Relaxable. Adjust table header. */ - ip2k_get_mem (abfd, misc->contents + irel->r_offset - 4, 2, code); - if (IS_PAGE_OPCODE (code)) - addr = irel->r_offset - 16; - else - addr = irel->r_offset - 14; - - ip2k_get_mem (abfd, misc->contents + addr, 12, code); - if ((!IS_ADD_W_WREG_OPCODE (code + 0)) - || (!IS_SNC_OPCODE (code + 2)) - || (!IS_INC_1SP_OPCODE (code + 4)) - || (!IS_ADD_2SP_W_OPCODE (code + 6)) - || (!IS_SNC_OPCODE (code + 8)) - || (!IS_INC_1SP_OPCODE (code + 10))) - { - _bfd_error_handler (_("ip2k relaxer: switch table header corrupt.")); - return FALSE; - } - - /* Delete first 3 opcodes. */ - if (!ip2k_elf_relax_delete_bytes (abfd, sec, addr + 0, 6)) - return FALSE; - - *again = TRUE; - - /* Delete all page instructions in table. */ - while (irel < ireltest) - { - if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc)) - return FALSE; - irel += 2; - } - - return TRUE; -} - -/* This function handles relaxation of a section in a specific page. */ - -static bfd_boolean -ip2k_elf_relax_section_page (bfd *abfd, - asection *sec, - bfd_boolean *again, - struct misc *misc, - unsigned long page_start, - unsigned long page_end) -{ - Elf_Internal_Rela *irelend = misc->irelbase + sec->reloc_count; - Elf_Internal_Rela *irel; - int switch_table_128; - int switch_table_256; - - /* Walk thru the section looking for relaxation opportunities. */ - for (irel = misc->irelbase; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) != (int) R_IP2K_PAGE3) - /* Ignore non page instructions. */ - continue; - - if (BASEADDR (sec) + irel->r_offset < page_start) - /* Ignore page instructions on earlier page - they have - already been processed. Remember that there is code flow - that crosses a page boundary. */ - continue; - - if (BASEADDR (sec) + irel->r_offset > page_end) - /* Flow beyond end of page => nothing more to do for this page. */ - return TRUE; - - /* Detect switch tables. */ - switch_table_128 = ip2k_is_switch_table_128 (abfd, sec, irel->r_offset, misc->contents); - switch_table_256 = ip2k_is_switch_table_256 (abfd, sec, irel->r_offset, misc->contents); - - if ((switch_table_128 > 0) || (switch_table_256 > 0)) - /* If the index is greater than 0 then it has already been processed. */ - continue; - - if (switch_table_128 == 0) - { - if (!ip2k_relax_switch_table_128 (abfd, sec, irel, again, misc)) - return FALSE; - - continue; - } - - if (switch_table_256 == 0) - { - if (!ip2k_relax_switch_table_256 (abfd, sec, irel, again, misc)) - return FALSE; - - continue; - } - - /* Simple relax. */ - if (ip2k_test_page_insn (abfd, sec, irel, misc)) - { - if (!ip2k_delete_page_insn (abfd, sec, irel, again, misc)) - return FALSE; - - continue; - } - } - - return TRUE; -} - -/* This function handles relaxing for the ip2k. - - Principle: Start with the first page and remove page instructions that - are not require on this first page. By removing page instructions more - code will fit into this page - repeat until nothing more can be achieved - for this page. Move on to the next page. - - Processing the pages one at a time from the lowest page allows a removal - only policy to be used - pages can be removed but are never reinserted. */ - -static bfd_boolean -ip2k_elf_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - static asection * first_section = NULL; - static unsigned long search_addr; - static unsigned long page_start = 0; - static unsigned long page_end = 0; - static unsigned int pass = 0; - static bfd_boolean new_pass = FALSE; - static bfd_boolean changed = FALSE; - struct misc misc; - - /* Assume nothing changes. */ - *again = FALSE; - - if (first_section == NULL) - { - ip2k_relaxed = TRUE; - first_section = sec; - } - - if (first_section == sec) - { - pass++; - new_pass = TRUE; - } - - /* We don't have to do anything for a relocatable link, - if this section does not have relocs, or if this is - not a code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Get section contents cached copy if it exists. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's symbols cached copy if it exists. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - misc.symtab_hdr = symtab_hdr; - misc.isymbuf = isymbuf; - misc.irelbase = internal_relocs; - misc.contents = contents; - - /* This is where all the relaxation actually get done. */ - if ((pass == 1) || (new_pass && !changed)) - { - /* On the first pass we simply search for the lowest page that - we havn't relaxed yet. Note that the pass count is reset - each time a page is complete in order to move on to the next page. - If we can't find any more pages then we are finished. */ - if (new_pass) - { - pass = 1; - new_pass = FALSE; - changed = TRUE; /* Pre-initialize to break out of pass 1. */ - search_addr = 0xFFFFFFFF; - } - - if ((BASEADDR (sec) + sec->size < search_addr) - && (BASEADDR (sec) + sec->size > page_end)) - { - if (BASEADDR (sec) <= page_end) - search_addr = page_end + 1; - else - search_addr = BASEADDR (sec); - - /* Found a page => more work to do. */ - *again = TRUE; - } - } - else - { - if (new_pass) - { - new_pass = FALSE; - changed = FALSE; - page_start = PAGENO (search_addr); - page_end = page_start | 0x00003FFF; - } - - /* Only process sections in range. */ - if ((BASEADDR (sec) + sec->size >= page_start) - && (BASEADDR (sec) <= page_end)) - { - if (!ip2k_elf_relax_section_page (abfd, sec, &changed, &misc, page_start, page_end)) - return FALSE; - } - *again = TRUE; - } - - /* Perform some house keeping after relaxing the section. */ - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - symtab_hdr->contents = (unsigned char *) isymbuf; - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -/* Set the howto pointer for a IP2K ELF reloc. */ - -static void -ip2k_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_IP2K_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid IP2K reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & ip2k_elf_howto_table [r_type]; -} - -/* Perform a single relocation. - By default we use the standard BFD routines. */ - -static bfd_reloc_status_type -ip2k_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation) -{ - static bfd_vma page_addr = 0; - - bfd_reloc_status_type r = bfd_reloc_ok; - switch (howto->type) - { - /* Handle data space relocations. */ - case R_IP2K_FR9: - case R_IP2K_BANK: - if ((relocation & IP2K_DATA_MASK) == IP2K_DATA_VALUE) - relocation &= ~IP2K_DATA_MASK; - else - r = bfd_reloc_notsupported; - break; - - case R_IP2K_LO8DATA: - case R_IP2K_HI8DATA: - case R_IP2K_EX8DATA: - break; - - /* Handle insn space relocations. */ - case R_IP2K_PAGE3: - page_addr = BASEADDR (input_section) + rel->r_offset; - if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE) - relocation &= ~IP2K_INSN_MASK; - else - r = bfd_reloc_notsupported; - break; - - case R_IP2K_ADDR16CJP: - if (BASEADDR (input_section) + rel->r_offset != page_addr + 2) - { - /* No preceding page instruction, verify that it isn't needed. */ - if (PAGENO (relocation + rel->r_addend) != - ip2k_nominal_page_bits (input_bfd, input_section, - rel->r_offset, contents)) - /* xgettext:c-format */ - _bfd_error_handler (_("ip2k linker: missing page instruction at %#Lx (dest = %#Lx)"), - BASEADDR (input_section) + rel->r_offset, - relocation + rel->r_addend); - } - else if (ip2k_relaxed) - { - /* Preceding page instruction. Verify that the page instruction is - really needed. One reason for the relaxation to miss a page is if - the section is not marked as executable. */ - if (!ip2k_is_switch_table_128 (input_bfd, input_section, - rel->r_offset - 2, contents) - && !ip2k_is_switch_table_256 (input_bfd, input_section, - rel->r_offset - 2, contents) - && (PAGENO (relocation + rel->r_addend) == - ip2k_nominal_page_bits (input_bfd, input_section, - rel->r_offset - 2, contents))) - /* xgettext:c-format */ - _bfd_error_handler (_("ip2k linker: redundant page instruction at %#Lx (dest = %#Lx)"), - page_addr, - relocation + rel->r_addend); - } - if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE) - relocation &= ~IP2K_INSN_MASK; - else - r = bfd_reloc_notsupported; - break; - - case R_IP2K_LO8INSN: - case R_IP2K_HI8INSN: - case R_IP2K_PC_SKIP: - if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE) - relocation &= ~IP2K_INSN_MASK; - else - r = bfd_reloc_notsupported; - break; - - case R_IP2K_16: - /* If this is a relocation involving a TEXT - symbol, reduce it to a word address. */ - if ((relocation & IP2K_INSN_MASK) == IP2K_INSN_VALUE) - howto = &ip2k_elf_howto_table[ (int) R_IP2K_TEXT]; - break; - - /* Pass others through. */ - default: - break; - } - - /* Only install relocation if above tests did not disqualify it. */ - if (r == bfd_reloc_ok) - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - return r; -} - -/* Relocate a IP2K ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -ip2k_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - howto = ip2k_elf_howto_table + r_type; - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = BASEADDR (sec) + sym->st_value; - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned, ignored; - bfd_boolean unresolved_reloc; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - /* Finally, the sole IP2K-specific part. */ - r = ip2k_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - /* This is how ip2k_final_link_relocate tells us of a non-kosher - reference between insn & data address spaces. */ - case bfd_reloc_notsupported: - if (sym != NULL) /* Only if it's not an unresolved symbol. */ - msg = _("unsupported relocation between data/insn address spaces"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -#define TARGET_BIG_SYM ip2k_elf32_vec -#define TARGET_BIG_NAME "elf32-ip2k" - -#define ELF_ARCH bfd_arch_ip2k -#define ELF_MACHINE_CODE EM_IP2K -#define ELF_MACHINE_ALT1 EM_IP2K_OLD -#define ELF_MAXPAGESIZE 1 /* No pages on the IP2K. */ - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto ip2k_info_to_howto_rela - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 -#define elf_backend_relocate_section ip2k_elf_relocate_section - -#define elf_symbol_leading_char '_' -#define bfd_elf32_bfd_reloc_type_lookup ip2k_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup ip2k_reloc_name_lookup -#define bfd_elf32_bfd_relax_section ip2k_elf_relax_section - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-iq2000.c b/sdcc/support/sdbinutils/bfd/elf32-iq2000.c deleted file mode 100644 index b29b9cbb2..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-iq2000.c +++ /dev/null @@ -1,917 +0,0 @@ -/* IQ2000-specific support for 32-bit ELF. - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/iq2000.h" - -/* Forward declarations. */ - -static bfd_reloc_status_type iq2000_elf_howto_hi16_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - - -static reloc_howto_type iq2000_elf_howto_table [] = -{ - /* This reloc does nothing. */ - - HOWTO (R_IQ2000_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_IQ2000_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_IQ2000_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 31, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x7fffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 26 bit branch address. */ - HOWTO (R_IQ2000_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_26", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x03ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative reference. */ - HOWTO (R_IQ2000_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_PC16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* high 16 bits of symbol value. */ - HOWTO (R_IQ2000_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - iq2000_elf_howto_hi16_reloc, /* special_function */ - "R_IQ2000_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_IQ2000_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit jump offset. */ - HOWTO (R_IQ2000_OFFSET_16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_OFFSET_16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 21-bit jump offset. */ - HOWTO (R_IQ2000_OFFSET_21, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_OFFSET_21", /* name */ - FALSE, /* partial_inplace */ - 0x000000, /* src_mask */ - 0x1fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* unsigned high 16 bits of value. */ - HOWTO (R_IQ2000_OFFSET_21, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_UHI16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute debug relocation. */ - HOWTO (R_IQ2000_32_DEBUG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_IQ2000_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* GNU extension to record C++ vtable hierarchy. */ -static reloc_howto_type iq2000_elf_vtinherit_howto = - HOWTO (R_IQ2000_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_IQ2000_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* GNU extension to record C++ vtable member usage. */ -static reloc_howto_type iq2000_elf_vtentry_howto = - HOWTO (R_IQ2000_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_IQ2000_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - - -static bfd_reloc_status_type -iq2000_elf_howto_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - - /* If we're relocating and this an external symbol, - we don't want to change anything. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - /* If %lo will have sign-extension, compensate by add 0x10000 to hi portion. */ - if (relocation & 0x8000) - reloc_entry->addend += 0x10000; - - /* Now do the reloc in the usual way. */ - ret = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* Put it back the way it was. */ - if (relocation & 0x8000) - reloc_entry->addend -= 0x10000; - - return ret; -} - -static bfd_reloc_status_type -iq2000_elf_relocate_hi16 (bfd *input_bfd, - Elf_Internal_Rela *relhi, - bfd_byte *contents, - bfd_vma value) -{ - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + relhi->r_offset); - - value += relhi->r_addend; - value &= 0x7fffffff; /* Mask off top-bit which is Harvard mask bit. */ - - /* If top-bit of %lo value is on, this means that %lo will - sign-propagate and so we compensate by adding 1 to %hi value. */ - if (value & 0x8000) - value += 0x10000; - - value >>= 16; - insn = ((insn & ~0xFFFF) | value); - - bfd_put_32 (input_bfd, insn, contents + relhi->r_offset); - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -iq2000_elf_relocate_offset16 (bfd *input_bfd, - Elf_Internal_Rela *rel, - bfd_byte *contents, - bfd_vma value, - bfd_vma location) -{ - bfd_vma insn; - bfd_vma jtarget; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - - value += rel->r_addend; - - if (value & 3) - return bfd_reloc_dangerous; - - jtarget = (value & 0x3fffc) | (location & 0xf0000000L); - - if (jtarget != value) - return bfd_reloc_overflow; - - insn = (insn & ~0xFFFF) | ((value >> 2) & 0xFFFF); - - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - return bfd_reloc_ok; -} - -/* Map BFD reloc types to IQ2000 ELF reloc types. */ - -static reloc_howto_type * -iq2000_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - /* Note that the iq2000_elf_howto_table is indxed by the R_ - constants. Thus, the order that the howto records appear in the - table *must* match the order of the relocation types defined in - include/elf/iq2000.h. */ - - switch (code) - { - case BFD_RELOC_NONE: - return &iq2000_elf_howto_table[ (int) R_IQ2000_NONE]; - case BFD_RELOC_16: - return &iq2000_elf_howto_table[ (int) R_IQ2000_16]; - case BFD_RELOC_32: - return &iq2000_elf_howto_table[ (int) R_IQ2000_32]; - case BFD_RELOC_MIPS_JMP: - return &iq2000_elf_howto_table[ (int) R_IQ2000_26]; - case BFD_RELOC_IQ2000_OFFSET_16: - return &iq2000_elf_howto_table[ (int) R_IQ2000_OFFSET_16]; - case BFD_RELOC_IQ2000_OFFSET_21: - return &iq2000_elf_howto_table[ (int) R_IQ2000_OFFSET_21]; - case BFD_RELOC_16_PCREL_S2: - return &iq2000_elf_howto_table[ (int) R_IQ2000_PC16]; - case BFD_RELOC_HI16: - return &iq2000_elf_howto_table[ (int) R_IQ2000_HI16]; - case BFD_RELOC_IQ2000_UHI16: - return &iq2000_elf_howto_table[ (int) R_IQ2000_UHI16]; - case BFD_RELOC_LO16: - return &iq2000_elf_howto_table[ (int) R_IQ2000_LO16]; - case BFD_RELOC_VTABLE_INHERIT: - return &iq2000_elf_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &iq2000_elf_vtentry_howto; - default: - /* Pacify gcc -Wall. */ - return NULL; - } - return NULL; -} - -static reloc_howto_type * -iq2000_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (iq2000_elf_howto_table) - / sizeof (iq2000_elf_howto_table[0])); - i++) - if (iq2000_elf_howto_table[i].name != NULL - && strcasecmp (iq2000_elf_howto_table[i].name, r_name) == 0) - return &iq2000_elf_howto_table[i]; - - if (strcasecmp (iq2000_elf_vtinherit_howto.name, r_name) == 0) - return &iq2000_elf_vtinherit_howto; - if (strcasecmp (iq2000_elf_vtentry_howto.name, r_name) == 0) - return &iq2000_elf_vtentry_howto; - - return NULL; -} - -/* Perform a single relocation. By default we use the standard BFD - routines. */ - -static bfd_reloc_status_type -iq2000_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation) -{ - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); -} - -/* Set the howto pointer for a IQ2000 ELF reloc. */ - -static void -iq2000_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - switch (r_type) - { - case R_IQ2000_GNU_VTINHERIT: - cache_ptr->howto = & iq2000_elf_vtinherit_howto; - break; - - case R_IQ2000_GNU_VTENTRY: - cache_ptr->howto = & iq2000_elf_vtentry_howto; - break; - - default: - if (r_type >= (unsigned int) R_IQ2000_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid IQ2000 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & iq2000_elf_howto_table [r_type]; - break; - } -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -iq2000_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd_boolean changed = FALSE; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable - hierarchy. Reconstruct it for later use during GC. */ - case R_IQ2000_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_IQ2000_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_IQ2000_32: - /* For debug section, change to special harvard-aware relocations. */ - if (CONST_STRNEQ (sec->name, ".debug") - || CONST_STRNEQ (sec->name, ".stab") - || CONST_STRNEQ (sec->name, ".eh_frame")) - { - ((Elf_Internal_Rela *) rel)->r_info - = ELF32_R_INFO (ELF32_R_SYM (rel->r_info), R_IQ2000_32_DEBUG); - changed = TRUE; - } - break; - } - } - - if (changed) - /* Note that we've changed relocs, otherwise if !info->keep_memory - we'll free the relocs and lose our changes. */ - elf_section_data (sec)->relocs = (Elf_Internal_Rela *) relocs; - - return TRUE; -} - - -/* Relocate a IQ2000 ELF section. - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -iq2000_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - - if ( r_type == R_IQ2000_GNU_VTINHERIT - || r_type == R_IQ2000_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = iq2000_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - asection *osec; - - sym = local_syms + r_symndx; - osec = sec = local_sections [r_symndx]; - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - /* This relocation is relative to a section symbol that is - going to be merged. Change it so that it is relative - to the merged section symbol. */ - rel->r_addend = _bfd_elf_rel_local_sym (output_bfd, sym, &sec, - rel->r_addend); - - relocation = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, osec) : name; - } - else - { - bfd_boolean unresolved_reloc; - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (r_type) - { - case R_IQ2000_HI16: - r = iq2000_elf_relocate_hi16 (input_bfd, rel, contents, relocation); - break; - - case R_IQ2000_OFFSET_16: - r = iq2000_elf_relocate_offset16 (input_bfd, rel, contents, relocation, - input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - break; - - case R_IQ2000_PC16: - rel->r_addend -= 4; - /* Fall through. */ - - default: - r = iq2000_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -iq2000_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_IQ2000_GNU_VTINHERIT: - case R_IQ2000_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - - -/* Return the MACH for an e_flags value. */ - -static int -elf32_iq2000_machine (bfd *abfd) -{ - switch (elf_elfheader (abfd)->e_flags & EF_IQ2000_CPU_MASK) - { - case EF_IQ2000_CPU_IQ10: - return bfd_mach_iq10; - - case EF_IQ2000_CPU_IQ2000: - default: - return bfd_mach_iq2000; - } -} - - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -iq2000_elf_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object - file to the output object file when linking. */ - -static bfd_boolean -iq2000_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, old_partial; - flagword new_flags, new_partial; - bfd_boolean error = FALSE; - char new_opt[80]; - char old_opt[80]; - - new_opt[0] = old_opt[0] = '\0'; - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - - else if (new_flags != old_flags) - { - /* Warn if different cpu is used, but allow a - specific cpu to override the generic cpu. */ - new_partial = (new_flags & EF_IQ2000_CPU_MASK); - old_partial = (old_flags & EF_IQ2000_CPU_MASK); - - if (new_partial != old_partial) - { - switch (new_partial) - { - case EF_IQ2000_CPU_IQ10: - strcat (new_opt, " -m10"); - break; - - default: - case EF_IQ2000_CPU_IQ2000: - strcat (new_opt, " -m2000"); - break; - } - - switch (old_partial) - { - case EF_IQ2000_CPU_IQ10: - strcat (old_opt, " -m10"); - break; - - default: - case EF_IQ2000_CPU_IQ2000: - strcat (old_opt, " -m2000"); - break; - } - } - - /* Print out any mismatches from above. */ - if (new_opt[0]) - { - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: compiled with %s and linked with modules compiled with %s"), - ibfd, new_opt, old_opt); - } - - new_flags &= ~ EF_IQ2000_ALL_FLAGS; - old_flags &= ~ EF_IQ2000_ALL_FLAGS; - - /* Warn about any other mismatches. */ - if (new_flags != old_flags) - { - error = TRUE; - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields than previous modules (%#x)"), - ibfd, new_flags, old_flags); - } - } - - if (error) - bfd_set_error (bfd_error_bad_value); - - return !error; -} - - -static bfd_boolean -iq2000_elf_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (unsigned long) flags); - - switch (flags & EF_IQ2000_CPU_MASK) - { - case EF_IQ2000_CPU_IQ10: - fprintf (file, " -m10"); - break; - case EF_IQ2000_CPU_IQ2000: - fprintf (file, " -m2000"); - break; - default: - break; - } - - fputc ('\n', file); - return TRUE; -} - -static -bfd_boolean -iq2000_elf_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_iq2000, - elf32_iq2000_machine (abfd)); - return TRUE; -} - - -#define ELF_ARCH bfd_arch_iq2000 -#define ELF_MACHINE_CODE EM_IQ2000 -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM iq2000_elf32_vec -#define TARGET_BIG_NAME "elf32-iq2000" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto iq2000_info_to_howto_rela -#define elf_backend_relocate_section iq2000_elf_relocate_section -#define elf_backend_gc_mark_hook iq2000_elf_gc_mark_hook -#define elf_backend_check_relocs iq2000_elf_check_relocs -#define elf_backend_object_p iq2000_elf_object_p -#define elf_backend_rela_normal 1 - -#define elf_backend_can_gc_sections 1 - -#define bfd_elf32_bfd_reloc_type_lookup iq2000_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup iq2000_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags iq2000_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data iq2000_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data iq2000_elf_print_private_bfd_data - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-lm32.c b/sdcc/support/sdbinutils/bfd/elf32-lm32.c deleted file mode 100644 index 089ec84a3..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-lm32.c +++ /dev/null @@ -1,2608 +0,0 @@ -/* Lattice Mico32-specific support for 32-bit ELF - Copyright (C) 2008-2018 Free Software Foundation, Inc. - Contributed by Jon Beniston - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/lm32.h" - -#define DEFAULT_STACK_SIZE 0x20000 - -#define PLT_ENTRY_SIZE 20 - -#define PLT0_ENTRY_WORD0 0 -#define PLT0_ENTRY_WORD1 0 -#define PLT0_ENTRY_WORD2 0 -#define PLT0_ENTRY_WORD3 0 -#define PLT0_ENTRY_WORD4 0 - -#define PLT0_PIC_ENTRY_WORD0 0 -#define PLT0_PIC_ENTRY_WORD1 0 -#define PLT0_PIC_ENTRY_WORD2 0 -#define PLT0_PIC_ENTRY_WORD3 0 -#define PLT0_PIC_ENTRY_WORD4 0 - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" - -extern const bfd_target lm32_elf32_fdpic_vec; - -#define IS_FDPIC(bfd) ((bfd)->xvec == &lm32_elf32_fdpic_vec) - -static bfd_reloc_status_type lm32_elf_gprel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -/* lm32 ELF linker hash entry. */ - -struct elf_lm32_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; -}; - -/* lm32 ELF linker hash table. */ - -struct elf_lm32_link_hash_table -{ - struct elf_link_hash_table root; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sfixup32; - asection *sdynbss; - asection *srelbss; - - int relocs32; -}; - -/* Get the lm32 ELF linker hash table from a link_info structure. */ - -#define lm32_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == LM32_ELF_DATA ? ((struct elf_lm32_link_hash_table *) ((p)->hash)) : NULL) - -#define lm32fdpic_got_section(info) \ - (lm32_elf_hash_table (info)->root.sgot) -#define lm32fdpic_gotrel_section(info) \ - (lm32_elf_hash_table (info)->root.srelgot) -#define lm32fdpic_fixup32_section(info) \ - (lm32_elf_hash_table (info)->sfixup32) - -struct weak_symbol_list -{ - const char *name; - struct weak_symbol_list *next; -}; - -/* Create an entry in an lm32 ELF linker hash table. */ - -static struct bfd_hash_entry * -lm32_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_lm32_link_hash_entry *ret = - (struct elf_lm32_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, - sizeof (struct elf_lm32_link_hash_entry)); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_lm32_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != NULL) - { - struct elf_lm32_link_hash_entry *eh; - - eh = (struct elf_lm32_link_hash_entry *) ret; - eh->dyn_relocs = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an lm32 ELF linker hash table. */ - -static struct bfd_link_hash_table * -lm32_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_lm32_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_lm32_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - lm32_elf_link_hash_newfunc, - sizeof (struct elf_lm32_link_hash_entry), - LM32_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -/* Add a fixup to the ROFIXUP section. */ - -static bfd_vma -_lm32fdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma relocation) -{ - bfd_vma fixup_offset; - - if (rofixup->flags & SEC_EXCLUDE) - return -1; - - fixup_offset = rofixup->reloc_count * 4; - if (rofixup->contents) - { - BFD_ASSERT (fixup_offset < rofixup->size); - if (fixup_offset < rofixup->size) - bfd_put_32 (output_bfd, relocation, rofixup->contents + fixup_offset); - } - rofixup->reloc_count++; - - return fixup_offset; -} - -/* Create .rofixup sections in DYNOBJ, and set up - shortcuts to them in our hash table. */ - -static bfd_boolean -create_rofixup_section (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf_lm32_link_hash_table *htab; - htab = lm32_elf_hash_table (info); - - if (htab == NULL) - return FALSE; - - /* Fixup section for R_LM32_32 relocs. */ - lm32fdpic_fixup32_section (info) - = bfd_make_section_anyway_with_flags (dynobj, - ".rofixup", - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (lm32fdpic_fixup32_section (info) == NULL - || ! bfd_set_section_alignment (dynobj, - lm32fdpic_fixup32_section (info), 2)) - return FALSE; - - return TRUE; -} - -static reloc_howto_type lm32_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_LM32_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_LM32_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_LM32_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_LM32_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - lm32_elf_gprel_reloc, /* special_function */ - "R_LM32_GPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_CALL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_CALL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_LM32_BRANCH, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_BRANCH", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_LM32_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_LM32_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_LM32_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_LM32_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_16_GOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_16_GOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_GOTOFF_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_GOTOFF_HI16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_GOTOFF_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_GOTOFF_LO16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_COPY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_LM32_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_LM32_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Map BFD reloc types to lm32 ELF reloc types. */ - -struct lm32_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct lm32_reloc_map lm32_reloc_map[] = -{ - { BFD_RELOC_NONE, R_LM32_NONE }, - { BFD_RELOC_8, R_LM32_8 }, - { BFD_RELOC_16, R_LM32_16 }, - { BFD_RELOC_32, R_LM32_32 }, - { BFD_RELOC_HI16, R_LM32_HI16 }, - { BFD_RELOC_LO16, R_LM32_LO16 }, - { BFD_RELOC_GPREL16, R_LM32_GPREL16 }, - { BFD_RELOC_LM32_CALL, R_LM32_CALL }, - { BFD_RELOC_LM32_BRANCH, R_LM32_BRANCH }, - { BFD_RELOC_VTABLE_INHERIT, R_LM32_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_LM32_GNU_VTENTRY }, - { BFD_RELOC_LM32_16_GOT, R_LM32_16_GOT }, - { BFD_RELOC_LM32_GOTOFF_HI16, R_LM32_GOTOFF_HI16 }, - { BFD_RELOC_LM32_GOTOFF_LO16, R_LM32_GOTOFF_LO16 }, - { BFD_RELOC_LM32_COPY, R_LM32_COPY }, - { BFD_RELOC_LM32_GLOB_DAT, R_LM32_GLOB_DAT }, - { BFD_RELOC_LM32_JMP_SLOT, R_LM32_JMP_SLOT }, - { BFD_RELOC_LM32_RELATIVE, R_LM32_RELATIVE }, -}; - -static reloc_howto_type * -lm32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (lm32_reloc_map) / sizeof (lm32_reloc_map[0]); i++) - if (lm32_reloc_map[i].bfd_reloc_val == code) - return &lm32_elf_howto_table[lm32_reloc_map[i].elf_reloc_val]; - return NULL; -} - -static reloc_howto_type * -lm32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (lm32_elf_howto_table) / sizeof (lm32_elf_howto_table[0]); - i++) - if (lm32_elf_howto_table[i].name != NULL - && strcasecmp (lm32_elf_howto_table[i].name, r_name) == 0) - return &lm32_elf_howto_table[i]; - - return NULL; -} - - -/* Set the howto pointer for an Lattice Mico32 ELF reloc. */ - -static void -lm32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_LM32_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid LM32 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &lm32_elf_howto_table[r_type]; -} - -/* Set the right machine number for an Lattice Mico32 ELF file. */ - -static bfd_boolean -lm32_elf_object_p (bfd *abfd) -{ - return bfd_default_set_arch_mach (abfd, bfd_arch_lm32, bfd_mach_lm32); -} - -/* Set machine type flags just before file is written out. */ - -static void -lm32_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) -{ - elf_elfheader (abfd)->e_machine = EM_LATTICEMICO32; - elf_elfheader (abfd)->e_flags &=~ EF_LM32_MACH; - switch (bfd_get_mach (abfd)) - { - case bfd_mach_lm32: - elf_elfheader (abfd)->e_flags |= E_LM32_MACH; - break; - default: - abort (); - } -} - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ - -static bfd_boolean -lm32_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) -{ - unsigned int count; - asymbol **sym; - unsigned int i; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - /* The linker script will have created a symbol named `_gp' with the - appropriate value. */ - if (sym == NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - *pgp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, *pgp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - return TRUE; -} - -/* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static bfd_reloc_status_type -lm32_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, - char **error_message, bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) && !relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 && (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma + 0x4000; - _bfd_set_gp_value (output_bfd, *pgp); - } - else if (!lm32_elf_assign_gp (output_bfd, pgp)) - { - *error_message = - (char *) - _("global pointer relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -lm32_elf_do_gprel_relocate (bfd *abfd, - reloc_howto_type *howto, - asection *input_section ATTRIBUTE_UNUSED, - bfd_byte *data, - bfd_vma offset, - bfd_vma symbol_value, - bfd_vma addend) -{ - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -lm32_elf_gprel_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **msg) -{ - bfd_vma relocation; - bfd_vma gp; - bfd_reloc_status_type r; - - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - return bfd_reloc_ok; - - relocation = symbol->value - + symbol->section->output_section->vma + symbol->section->output_offset; - - if ((r = - lm32_elf_final_gp (abfd, symbol, FALSE, msg, &gp)) == bfd_reloc_ok) - { - relocation = relocation + reloc_entry->addend - gp; - reloc_entry->addend = 0; - if ((signed) relocation < -32768 || (signed) relocation > 32767) - { - *msg = _("global pointer relative address out of range"); - r = bfd_reloc_outofrange; - } - else - { - r = lm32_elf_do_gprel_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - relocation, reloc_entry->addend); - } - } - - return r; -} - -/* Find the segment number in which OSEC, and output section, is - located. */ - -static unsigned -_lm32fdpic_osec_to_segment (bfd *output_bfd, asection *osec) -{ - struct elf_segment_map *m; - Elf_Internal_Phdr *p; - - /* Find the segment that contains the output_section. */ - for (m = elf_seg_map (output_bfd), p = elf_tdata (output_bfd)->phdr; - m != NULL; - m = m->next, p++) - { - int i; - - for (i = m->count - 1; i >= 0; i--) - if (m->sections[i] == osec) - break; - - if (i >= 0) - break; - } - - return p - elf_tdata (output_bfd)->phdr; -} - -/* Determine if an output section is read-only. */ - -inline static bfd_boolean -_lm32fdpic_osec_readonly_p (bfd *output_bfd, asection *osec) -{ - unsigned seg = _lm32fdpic_osec_to_segment (output_bfd, osec); - - return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W); -} - -/* Relocate a section */ - -static bfd_boolean -lm32_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - Elf_Internal_Rela *rel, *relend; - struct elf_lm32_link_hash_table *htab = lm32_elf_hash_table (info); - bfd_vma *local_got_offsets; - asection *sgot; - - if (htab == NULL) - return FALSE; - - local_got_offsets = elf_local_got_offsets (input_bfd); - - sgot = htab->root.sgot; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - reloc_howto_type *howto; - unsigned int r_type; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_vma gp; - bfd_reloc_status_type r; - const char *name = NULL; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_LM32_GNU_VTENTRY - || r_type == R_LM32_GNU_VTINHERIT ) - continue; - - h = NULL; - sym = NULL; - sec = NULL; - - howto = lm32_elf_howto_table + r_type; - - if (r_symndx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - /* It's a global symbol. */ - bfd_boolean unresolved_reloc; - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym == NULL || ELF_ST_TYPE (sym->st_info) != STT_SECTION) - continue; - - /* If partial_inplace, we need to store any additional addend - back in the section. */ - if (! howto->partial_inplace) - continue; - - /* Shouldn't reach here. */ - abort (); - r = bfd_reloc_ok; - } - else - { - switch (howto->type) - { - case R_LM32_GPREL16: - if (!lm32_elf_assign_gp (output_bfd, &gp)) - r = bfd_reloc_dangerous; - else - { - relocation = relocation + rel->r_addend - gp; - rel->r_addend = 0; - if ((signed)relocation < -32768 || (signed)relocation > 32767) - r = bfd_reloc_outofrange; - else - { - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - } - } - break; - case R_LM32_16_GOT: - /* Relocation is to the entry for this symbol in the global - offset table. */ - BFD_ASSERT (sgot != NULL); - if (h != NULL) - { - bfd_boolean dyn; - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - dyn = htab->root.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - /* Write entry in GOT */ - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - /* Create entry in .rofixup pointing to GOT entry. */ - if (IS_FDPIC (output_bfd) && h->root.type != bfd_link_hash_undefweak) - { - _lm32fdpic_add_rofixup (output_bfd, - lm32fdpic_fixup32_section - (info), - sgot->output_section->vma - + sgot->output_offset - + off); - } - /* Mark GOT entry as having been written. */ - h->got.offset |= 1; - } - } - - relocation = sgot->output_offset + off; - } - else - { - bfd_vma off; - bfd_byte *loc; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - /* Get offset into GOT table. */ - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - /* Write entry in GOT. */ - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - /* Create entry in .rofixup pointing to GOT entry. */ - if (IS_FDPIC (output_bfd)) - { - _lm32fdpic_add_rofixup (output_bfd, - lm32fdpic_fixup32_section - (info), - sgot->output_section->vma - + sgot->output_offset - + off); - } - - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_LM32_RELATIVE reloc - for the dynamic linker. */ - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_LM32_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc); - ++srelgot->reloc_count; - } - - local_got_offsets[r_symndx] |= 1; - } - - - relocation = sgot->output_offset + off; - } - - /* Addend should be zero. */ - if (rel->r_addend != 0) - _bfd_error_handler (_("internal error: addend should be zero for R_LM32_16_GOT")); - - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - - case R_LM32_GOTOFF_LO16: - case R_LM32_GOTOFF_HI16: - /* Relocation is offset from GOT. */ - BFD_ASSERT (sgot != NULL); - relocation -= sgot->output_section->vma; - /* Account for sign-extension. */ - if ((r_type == R_LM32_GOTOFF_HI16) - && ((relocation + rel->r_addend) & 0x8000)) - rel->r_addend += 0x10000; - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - - case R_LM32_32: - if (IS_FDPIC (output_bfd)) - { - if ((!h) || (h && h->root.type != bfd_link_hash_undefweak)) - { - /* Only create .rofixup entries for relocs in loadable sections. */ - if ((bfd_get_section_flags (output_bfd, input_section->output_section) - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - - { - /* Check address to be modified is writable. */ - if (_lm32fdpic_osec_readonly_p (output_bfd, - input_section - ->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit dynamic relocations in read-only section"), - name, input_bfd, input_section, rel->r_offset); - return FALSE; - } - /* Create entry in .rofixup section. */ - _lm32fdpic_add_rofixup (output_bfd, - lm32fdpic_fixup32_section (info), - input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - } - } - } - /* Fall through. */ - - default: - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - } - } - - if (r != bfd_reloc_ok) - { - const char *msg = NULL; - arelent bfd_reloc; - - lm32_info_to_howto_rela (input_bfd, &bfd_reloc, rel); - howto = bfd_reloc.howto; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - if ((h != NULL) - && (h->root.type == bfd_link_hash_undefweak)) - break; - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -static asection * -lm32_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_LM32_GNU_VTINHERIT: - case R_LM32_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. */ - -static bfd_boolean -lm32_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - struct elf_lm32_link_hash_table *htab; - bfd *dynobj; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; - - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - int r_type; - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - /* Some relocs require a global offset table. */ - if (htab->root.sgot == NULL) - { - switch (r_type) - { - case R_LM32_16_GOT: - case R_LM32_GOTOFF_HI16: - case R_LM32_GOTOFF_LO16: - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - break; - } - } - - /* Some relocs require a rofixup table. */ - if (IS_FDPIC (abfd)) - { - switch (r_type) - { - case R_LM32_32: - /* FDPIC requires a GOT if there is a .rofixup section - (Normal ELF doesn't). */ - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - /* Create .rofixup section */ - if (htab->sfixup32 == NULL) - { - if (! create_rofixup_section (dynobj, info)) - return FALSE; - } - break; - case R_LM32_16_GOT: - case R_LM32_GOTOFF_HI16: - case R_LM32_GOTOFF_LO16: - /* Create .rofixup section. */ - if (htab->sfixup32 == NULL) - { - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - if (! create_rofixup_section (dynobj, info)) - return FALSE; - } - break; - } - } - - switch (r_type) - { - case R_LM32_16_GOT: - if (h != NULL) - h->got.refcount += 1; - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - local_got_refcounts[r_symndx] += 1; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_LM32_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_LM32_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - } - } - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -lm32_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_lm32_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - asection *sgot; - - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - sgot = htab->root.sgotplt; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sgot != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = htab->root.sgotplt; - goto get_vma; - case DT_JMPREL: - s = htab->root.srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; - if (splt && splt->size > 0) - { - if (bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD0, splt->contents); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD1, splt->contents + 4); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD2, splt->contents + 8); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD3, splt->contents + 12); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD4, splt->contents + 16); - } - else - { - unsigned long addr; - /* addr = .got + 4 */ - addr = sgot->output_section->vma + sgot->output_offset + 4; - bfd_put_32 (output_bfd, - PLT0_ENTRY_WORD0 | ((addr >> 16) & 0xffff), - splt->contents); - bfd_put_32 (output_bfd, - PLT0_ENTRY_WORD1 | (addr & 0xffff), - splt->contents + 4); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD2, splt->contents + 8); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD3, splt->contents + 12); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD4, splt->contents + 16); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot && sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - - /* FIXME: This can be null if create_dynamic_sections wasn't called. */ - if (elf_section_data (sgot->output_section) != NULL) - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - if (lm32fdpic_fixup32_section (info)) - { - struct elf_link_hash_entry *hgot = elf_hash_table (info)->hgot; - bfd_vma got_value = hgot->root.u.def.value - + hgot->root.u.def.section->output_section->vma - + hgot->root.u.def.section->output_offset; - struct bfd_link_hash_entry *hend; - - /* Last entry is pointer to GOT. */ - _lm32fdpic_add_rofixup (output_bfd, lm32fdpic_fixup32_section (info), got_value); - - /* Check we wrote enough entries. */ - if (lm32fdpic_fixup32_section (info)->size - != (lm32fdpic_fixup32_section (info)->reloc_count * 4)) - { - _bfd_error_handler - ("LINKER BUG: .rofixup section size mismatch: size/4 %Ld != relocs %d", - lm32fdpic_fixup32_section (info)->size/4, - lm32fdpic_fixup32_section (info)->reloc_count); - return FALSE; - } - - hend = bfd_link_hash_lookup (info->hash, "__ROFIXUP_END__", - FALSE, FALSE, TRUE); - if (hend - && (hend->type == bfd_link_hash_defined - || hend->type == bfd_link_hash_defweak)) - { - bfd_vma value = - lm32fdpic_fixup32_section (info)->output_section->vma - + lm32fdpic_fixup32_section (info)->output_offset - + lm32fdpic_fixup32_section (info)->size - - hend->u.def.section->output_section->vma - - hend->u.def.section->output_offset; - BFD_ASSERT (hend->u.def.value == value); - if (hend->u.def.value != value) - { - _bfd_error_handler - ("LINKER BUG: .rofixup section hend->u.def.value != value: %Ld != %Ld", hend->u.def.value, value); - return FALSE; - } - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -lm32_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_lm32_link_hash_table *htab; - bfd_byte *loc; - - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgot; - asection *srela; - - bfd_vma plt_index; - bfd_vma got_offset; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srela = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; - - /* Get the offset into the .got table of the entry that - corresponds to this function. Each .got entry is 4 bytes. - The first three are reserved. */ - got_offset = (plt_index + 3) * 4; - - /* Fill in the entry in the procedure linkage table. */ - if (! bfd_link_pic (info)) - { - /* TODO */ - } - else - { - /* TODO */ - } - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + 12), /* same offset */ - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_LM32_JMP_SLOT); - rela.r_addend = 0; - loc = srela->contents; - loc += plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - - } - - if (h->got.offset != (bfd_vma) -1) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the global offset table. Set it - up. */ - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset &~ 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular) - { - rela.r_info = ELF32_R_INFO (0, R_LM32_RELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - BFD_ASSERT ((h->got.offset & 1) == 0); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_LM32_GLOB_DAT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++srela->reloc_count; - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - - /* This symbols needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (htab->root.dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_LM32_COPY); - rela.r_addend = 0; - loc = s->contents; - loc += s->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++s->reloc_count; - } - - /* Mark some specially defined symbols as absolute. */ - if (h == htab->root.hdynamic || h == htab->root.hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -static enum elf_reloc_type_class -lm32_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_LM32_RELATIVE: return reloc_class_relative; - case R_LM32_JMP_SLOT: return reloc_class_plt; - case R_LM32_COPY: return reloc_class_copy; - default: return reloc_class_normal; - } -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - struct elf_lm32_link_hash_entry *eh = (struct elf_lm32_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) - return p->sec; - } - return NULL; -} - -/* 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 -lm32_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_lm32_link_hash_table *htab; - bfd *dynobj; - asection *s; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (! bfd_link_pic (info) - && !h->def_dynamic - && !h->ref_dynamic - && h->root.type != bfd_link_hash_undefweak - && h->root.type != bfd_link_hash_undefined) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a PCREL - reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - return TRUE; - } - else - h->plt.offset = (bfd_vma) -1; - - /* If this is a weak symbol, and there is a real definition, the - processor independent code will have arranged for us to see the - real definition first, and we can just use the same value. */ - if (h->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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 (0 && info->nocopyreloc) - { - h->non_got_ref = 0; - return TRUE; - } - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (0 && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - s = htab->sdynbss; - BFD_ASSERT (s != NULL); - - /* We must generate a R_LM32_COPY reloc to tell the dynamic linker - to copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - srel = htab->srelbss; - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info; - struct elf_lm32_link_hash_table *htab; - struct elf_lm32_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - eh = (struct elf_lm32_link_hash_entry *) h; - - if (htab->root.dynamic_sections_created - && h->plt.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->root.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 (! bfd_link_pic (info) - && !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->root.sgotplt->size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - - /* 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->root.sgot; - - h->got.offset = s->size; - s->size += 4; - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (h->def_regular - && (h->forced_local - || info->symbolic)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) - { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -lm32_elf_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_lm32_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - p != NULL; - p = p->next) - { - if (! bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - s = htab->root.sgot; - srel = htab->root.srelgot; - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += 4; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); - } - else - *local_got = (bfd_vma) -1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->root.splt - || s == htab->root.sgot - || s == htab->root.sgotplt - || s == htab->sdynbss) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 && s != htab->root.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - else - /* It's not one of our sections, so don't allocate space. */ - continue; - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is mostly to handle .rela.bss and - .rela.plt. We must create both sections in - create_dynamic_sections, because they must be created - before the linker maps input sections to output - sections. The linker does that before - adjust_dynamic_symbol is called, and it is that - function which decides whether anything needs to go - into these sections. */ - s->flags |= SEC_EXCLUDE; - continue; - } - - if ((s->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. We use bfd_zalloc - here in case unused entries are not reclaimed before the - section's contents are written out. This should not happen, - but this way if it does, we get a R_LM32_NONE reloc instead - of garbage. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (htab->root.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in lm32_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (! add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->root.splt->size != 0) - { - if (! add_dynamic_entry (DT_PLTGOT, 0) - || ! add_dynamic_entry (DT_PLTRELSZ, 0) - || ! add_dynamic_entry (DT_PLTREL, DT_RELA) - || ! add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (! add_dynamic_entry (DT_RELA, 0) - || ! add_dynamic_entry (DT_RELASZ, 0) - || ! add_dynamic_entry (DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (! add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - /* Allocate .rofixup section. */ - if (IS_FDPIC (output_bfd)) - { - struct weak_symbol_list *list_start = NULL, *list_end = NULL; - int rgot_weak_count = 0; - int r32_count = 0; - int rgot_count = 0; - /* Look for deleted sections. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - for (s = ibfd->sections; s != NULL; s = s->next) - { - if (s->reloc_count) - { - /* Count relocs that need .rofixup entires. */ - Elf_Internal_Rela *internal_relocs, *end; - internal_relocs = elf_section_data (s)->relocs; - if (internal_relocs == NULL) - internal_relocs = (_bfd_elf_link_read_relocs (ibfd, s, NULL, NULL, FALSE)); - if (internal_relocs != NULL) - { - end = internal_relocs + s->reloc_count; - while (internal_relocs < end) - { - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (ibfd); - r_symndx = ELF32_R_SYM (internal_relocs->r_info); - h = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - } - 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; - } - - /* Don't generate entries for weak symbols. */ - if (!h || (h && h->root.type != bfd_link_hash_undefweak)) - { - if (!discarded_section (s) && !((bfd_get_section_flags (ibfd, s) & SEC_ALLOC) == 0)) - { - switch (ELF32_R_TYPE (internal_relocs->r_info)) - { - case R_LM32_32: - r32_count++; - break; - case R_LM32_16_GOT: - rgot_count++; - break; - } - } - } - else - { - struct weak_symbol_list *current, *new_entry; - /* Is this symbol already in the list? */ - for (current = list_start; current; current = current->next) - { - if (!strcmp (current->name, h->root.root.string)) - break; - } - if (!current && !discarded_section (s) && (bfd_get_section_flags (ibfd, s) & SEC_ALLOC)) - { - /* Will this have an entry in the GOT. */ - if (ELF32_R_TYPE (internal_relocs->r_info) == R_LM32_16_GOT) - { - /* Create a new entry. */ - new_entry = malloc (sizeof (struct weak_symbol_list)); - if (!new_entry) - return FALSE; - new_entry->name = h->root.root.string; - new_entry->next = NULL; - /* Add to list */ - if (list_start == NULL) - { - list_start = new_entry; - list_end = new_entry; - } - else - { - list_end->next = new_entry; - list_end = new_entry; - } - /* Increase count of undefined weak symbols in the got. */ - rgot_weak_count++; - } - } - } - internal_relocs++; - } - } - else - return FALSE; - } - } - } - /* Free list. */ - while (list_start) - { - list_end = list_start->next; - free (list_start); - list_start = list_end; - } - - /* Size sections. */ - lm32fdpic_fixup32_section (info)->size - = (r32_count + (htab->root.sgot->size / 4) - rgot_weak_count + 1) * 4; - if (lm32fdpic_fixup32_section (info)->size == 0) - lm32fdpic_fixup32_section (info)->flags |= SEC_EXCLUDE; - else - { - lm32fdpic_fixup32_section (info)->contents = - bfd_zalloc (dynobj, lm32fdpic_fixup32_section (info)->size); - if (lm32fdpic_fixup32_section (info)->contents == NULL) - return FALSE; - } - } - - return TRUE; -} - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -lm32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_lm32_link_hash_table *htab; - flagword flags, pltflags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - int ptralign = 2; /* 32bit */ - - htab = lm32_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Make sure we have a GOT - For the case where we have a dynamic object - but none of the relocs in check_relocs */ - if (!_bfd_elf_create_got_section (abfd, info)) - return FALSE; - if (IS_FDPIC (abfd) && (htab->sfixup32 == NULL)) - { - if (! create_rofixup_section (abfd, info)) - return FALSE; - } - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - pltflags = flags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - htab->root.splt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - - if (bed->want_plt_sym) - { - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - struct bfd_link_hash_entry *bh = NULL; - struct elf_link_hash_entry *h; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, - (bfd_vma) 0, NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - htab->root.hplt = h; - - if (bfd_link_pic (info) - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = bfd_make_section_anyway_with_flags (abfd, - bed->default_use_rela_p - ? ".rela.plt" : ".rel.plt", - flags | SEC_READONLY); - htab->root.srelplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (htab->root.sgot == NULL - && !_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_anyway_with_flags (abfd, ".dynbss", - SEC_ALLOC | SEC_LINKER_CREATED); - htab->sdynbss = s; - 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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - htab->srelbss = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -lm32_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_lm32_link_hash_entry * edir; - struct elf_lm32_link_hash_entry * eind; - - edir = (struct elf_lm32_link_hash_entry *) dir; - eind = (struct elf_lm32_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -static bfd_boolean -lm32_elf_always_size_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - if (!bfd_link_relocatable (info)) - { - if (!bfd_elf_stack_segment_size (output_bfd, info, - "__stacksize", DEFAULT_STACK_SIZE)) - return FALSE; - - asection *sec = bfd_get_section_by_name (output_bfd, ".stack"); - if (sec) - sec->size = info->stacksize >= 0 ? info->stacksize : 0; - } - - return TRUE; -} - -static bfd_boolean -lm32_elf_fdpic_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - unsigned i; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (! _bfd_elf_copy_private_bfd_data (ibfd, obfd)) - return FALSE; - - if (! elf_tdata (ibfd) || ! elf_tdata (ibfd)->phdr - || ! elf_tdata (obfd) || ! elf_tdata (obfd)->phdr) - return TRUE; - - /* Copy the stack size. */ - for (i = 0; i < elf_elfheader (ibfd)->e_phnum; i++) - if (elf_tdata (ibfd)->phdr[i].p_type == PT_GNU_STACK) - { - Elf_Internal_Phdr *iphdr = &elf_tdata (ibfd)->phdr[i]; - - for (i = 0; i < elf_elfheader (obfd)->e_phnum; i++) - if (elf_tdata (obfd)->phdr[i].p_type == PT_GNU_STACK) - { - memcpy (&elf_tdata (obfd)->phdr[i], iphdr, sizeof (*iphdr)); - - /* Rewrite the phdrs, since we're only called after they were first written. */ - if (bfd_seek (obfd, (bfd_signed_vma) get_elf_backend_data (obfd) - ->s->sizeof_ehdr, SEEK_SET) != 0 - || get_elf_backend_data (obfd)->s->write_out_phdrs (obfd, elf_tdata (obfd)->phdr, - elf_elfheader (obfd)->e_phnum) != 0) - return FALSE; - break; - } - - break; - } - - return TRUE; -} - - -#define ELF_ARCH bfd_arch_lm32 -#define ELF_TARGET_ID LM32_ELF_DATA -#define ELF_MACHINE_CODE EM_LATTICEMICO32 -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM lm32_elf32_vec -#define TARGET_BIG_NAME "elf32-lm32" - -#define bfd_elf32_bfd_reloc_type_lookup lm32_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup lm32_reloc_name_lookup -#define elf_info_to_howto lm32_info_to_howto_rela -#define elf_info_to_howto_rel 0 -#define elf_backend_rela_normal 1 -#define elf_backend_object_p lm32_elf_object_p -#define elf_backend_final_write_processing lm32_elf_final_write_processing -#define elf_backend_stack_align 8 -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_gc_mark_hook lm32_elf_gc_mark_hook -#define elf_backend_plt_readonly 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 -#define bfd_elf32_bfd_link_hash_table_create lm32_elf_link_hash_table_create -#define elf_backend_check_relocs lm32_elf_check_relocs -#define elf_backend_reloc_type_class lm32_elf_reloc_type_class -#define elf_backend_copy_indirect_symbol lm32_elf_copy_indirect_symbol -#define elf_backend_size_dynamic_sections lm32_elf_size_dynamic_sections -#define elf_backend_omit_section_dynsym ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_create_dynamic_sections lm32_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections lm32_elf_finish_dynamic_sections -#define elf_backend_adjust_dynamic_symbol lm32_elf_adjust_dynamic_symbol -#define elf_backend_finish_dynamic_symbol lm32_elf_finish_dynamic_symbol -#define elf_backend_relocate_section lm32_elf_relocate_section - -#include "elf32-target.h" - -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x4000 - - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM lm32_elf32_fdpic_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-lm32fdpic" -#undef elf32_bed -#define elf32_bed elf32_lm32fdpic_bed - -#undef elf_backend_always_size_sections -#define elf_backend_always_size_sections lm32_elf_always_size_sections -#undef bfd_elf32_bfd_copy_private_bfd_data -#define bfd_elf32_bfd_copy_private_bfd_data lm32_elf_fdpic_copy_private_bfd_data - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-m32c.c b/sdcc/support/sdbinutils/bfd/elf32-m32c.c deleted file mode 100644 index dfb8a1ed3..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m32c.c +++ /dev/null @@ -1,2152 +0,0 @@ -/* M16C/M32C specific support for 32-bit ELF. - Copyright (C) 2005-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/m32c.h" -#include "libiberty.h" - -/* Forward declarations. */ -static reloc_howto_type * m32c_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static void m32c_info_to_howto_rela - (bfd *, arelent *, Elf_Internal_Rela *); -static bfd_boolean m32c_elf_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); -static bfd_boolean m32c_elf_check_relocs - (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); -static bfd_boolean m32c_elf_relax_delete_bytes (bfd *, asection *, bfd_vma, int); -#ifdef DEBUG -char * m32c_get_reloc (long reloc); -void dump_symtab (bfd *, void *, void *); -#endif -static bfd_boolean m32c_elf_relax_section -(bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again); -static bfd_reloc_status_type m32c_apply_reloc_24 - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - - -static reloc_howto_type m32c_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_M32C_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GCC intentionally overflows these next two in order to work - around limitations in the addressing modes, so don't complain - about overflow. */ - HOWTO (R_M32C_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m32c_apply_reloc_24, /* special_function */ - "R_M32C_24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_8_PCREL, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_8_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_M32C_16_PCREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_M32C_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_LO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_HI8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_HI8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_HI16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_RL_JUMP, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_RL_JUMP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_RL_1ADDR, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_RL_1ADDR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32C_RL_2ADDR, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32C_RL_2ADDR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Map BFD reloc types to M32C ELF reloc types. */ - -struct m32c_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int m32c_reloc_val; -}; - -static const struct m32c_reloc_map m32c_reloc_map [] = -{ - { BFD_RELOC_NONE, R_M32C_NONE }, - { BFD_RELOC_16, R_M32C_16 }, - { BFD_RELOC_24, R_M32C_24 }, - { BFD_RELOC_32, R_M32C_32 }, - { BFD_RELOC_8_PCREL, R_M32C_8_PCREL }, - { BFD_RELOC_16_PCREL, R_M32C_16_PCREL }, - { BFD_RELOC_8, R_M32C_8 }, - { BFD_RELOC_LO16, R_M32C_LO16 }, - { BFD_RELOC_HI16, R_M32C_HI16 }, - { BFD_RELOC_M32C_HI8, R_M32C_HI8 }, - { BFD_RELOC_M32C_RL_JUMP, R_M32C_RL_JUMP }, - { BFD_RELOC_M32C_RL_1ADDR, R_M32C_RL_1ADDR }, - { BFD_RELOC_M32C_RL_2ADDR, R_M32C_RL_2ADDR } -}; - -static reloc_howto_type * -m32c_reloc_type_lookup - (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (m32c_reloc_map); i--;) - if (m32c_reloc_map [i].bfd_reloc_val == code) - return & m32c_elf_howto_table [m32c_reloc_map[i].m32c_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -m32c_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (m32c_elf_howto_table) / sizeof (m32c_elf_howto_table[0]); - i++) - if (m32c_elf_howto_table[i].name != NULL - && strcasecmp (m32c_elf_howto_table[i].name, r_name) == 0) - return &m32c_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an M32C ELF reloc. */ - -static void -m32c_info_to_howto_rela - (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_M32C_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid M32C reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & m32c_elf_howto_table [r_type]; -} - - - -/* Apply R_M32C_24 relocations. We have to do this because it's not a - power-of-two size, and the generic code may think it overruns the - section if it's right at the end. - - Must return something other than bfd_reloc_continue to avoid the - above problem. Typical return values include bfd_reloc_ok or - bfd_reloc_overflow. -*/ - -static bfd_reloc_status_type m32c_apply_reloc_24 (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void *vdata_start ATTRIBUTE_UNUSED, - asection *input_section, - bfd *ibfd ATTRIBUTE_UNUSED, - char **error_msg ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - bfd_reloc_status_type s; - - s = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, - vdata_start, - input_section, ibfd, error_msg); - if (s != bfd_reloc_continue) - return s; - - /* Get symbol value. (Common symbols are special.) */ - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_offset; - - /* Add in supplied addend. */ - relocation += reloc_entry->addend; - - reloc_entry->addend = relocation; - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -/* Relocate an M32C ELF section. - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -m32c_elf_relocate_section - (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - asection *splt; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - splt = elf_hash_table (info)->splt; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - - /* These are only used for relaxing; we don't actually relocate - anything with them, so skip them. */ - if (r_type == R_M32C_RL_JUMP - || r_type == R_M32C_RL_1ADDR - || r_type == R_M32C_RL_2ADDR) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = m32c_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - relocation = 0; - - 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); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (sym->st_name == 0) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - h = sym_hashes [r_symndx - symtab_hdr->sh_info]; - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - h = ((struct elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &h->root)); - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - name = h->root.root.string; - - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sec = h->root.u.def.section; - relocation = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else if (h->root.type == bfd_link_hash_undefweak) - ; - else if (!bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) (info, h->root.root.string, - input_bfd, input_section, - rel->r_offset, TRUE); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - continue; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_M32C_16: - { - bfd_vma *plt_offset; - - if (h != NULL) - plt_offset = &h->plt.offset; - else - plt_offset = elf_local_got_offsets (input_bfd) + r_symndx; - - /* printf("%s: rel %x plt %d\n", h ? h->root.root.string : "(none)", - relocation, *plt_offset);*/ - if (relocation <= 0xffff) - { - /* If the symbol is in range for a 16-bit address, we should - have deallocated the plt entry in relax_section. */ - BFD_ASSERT (*plt_offset == (bfd_vma) -1); - } - else - { - /* If the symbol is out of range for a 16-bit address, - we must have allocated a plt entry. */ - BFD_ASSERT (*plt_offset != (bfd_vma) -1); - - /* If this is the first time we've processed this symbol, - fill in the plt entry with the correct symbol address. */ - if ((*plt_offset & 1) == 0) - { - unsigned int x; - - x = 0x000000fc; /* jmpf */ - x |= (relocation << 8) & 0xffffff00; - bfd_put_32 (input_bfd, x, splt->contents + *plt_offset); - *plt_offset |= 1; - } - - relocation = (splt->output_section->vma - + splt->output_offset - + (*plt_offset & -2)); - if (name) - { - char *newname = bfd_malloc (strlen(name)+5); - strcpy (newname, name); - strcat(newname, ".plt"); - _bfd_generic_link_add_one_symbol (info, - input_bfd, - newname, - BSF_FUNCTION | BSF_WEAK, - splt, - (*plt_offset & -2), - 0, - 1, - 0, - 0); - } - } - } - break; - - case R_M32C_HI8: - case R_M32C_HI16: - relocation >>= 16; - break; - } - -#if 0 - printf ("relocate %s at %06lx relocation %06lx addend %ld ", - m32c_elf_howto_table[ELF32_R_TYPE(rel->r_info)].name, - rel->r_offset + input_section->output_section->vma + input_section->output_offset, - relocation, rel->r_addend); - { - int i; - for (i=0; i<4; i++) - printf (" %02x", contents[rel->r_offset+i]); - printf ("\n"); - } -#endif - switch (ELF32_R_TYPE(rel->r_info)) - { - case R_M32C_24: - /* Like m32c_apply_reloc_24, we must handle this one separately. */ - relocation += rel->r_addend; - - /* Sanity check the address. */ - if (rel->r_offset + 3 - > bfd_get_section_limit_octets (input_bfd, input_section)) - r = bfd_reloc_outofrange; - else - { - bfd_put_8 (input_bfd, relocation & 0xff, contents + rel->r_offset); - bfd_put_8 (input_bfd, (relocation >> 8) & 0xff, contents + rel->r_offset + 1); - bfd_put_8 (input_bfd, (relocation >> 16) & 0xff, contents + rel->r_offset + 2); - r = bfd_reloc_ok; - } - - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, relocation, - rel->r_addend); - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* We support 16-bit pointers to code above 64k by generating a thunk - below 64k containing a JMP instruction to the final address. */ - -static bfd_boolean -m32c_elf_check_relocs - (bfd * abfd, - struct bfd_link_info * info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - bfd_vma *local_plt_offsets; - asection *splt; - bfd *dynobj; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_plt_offsets = elf_local_got_offsets (abfd); - splt = NULL; - dynobj = elf_hash_table(info)->dynobj; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - bfd_vma *offset; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes a 16-bit pointer to a function. - We may need to allocate a thunk in low memory; reserve memory - for it now. */ - case R_M32C_16: - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - splt = elf_hash_table (info)->splt; - if (splt == NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED - | SEC_READONLY | SEC_CODE); - splt = bfd_make_section_anyway_with_flags (dynobj, ".plt", - flags); - elf_hash_table (info)->splt = splt; - if (splt == NULL - || ! bfd_set_section_alignment (dynobj, splt, 1)) - return FALSE; - } - - if (h != NULL) - offset = &h->plt.offset; - else - { - if (local_plt_offsets == NULL) - { - size_t size; - unsigned int i; - - size = symtab_hdr->sh_info * sizeof (bfd_vma); - local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size); - if (local_plt_offsets == NULL) - return FALSE; - elf_local_got_offsets (abfd) = local_plt_offsets; - - for (i = 0; i < symtab_hdr->sh_info; i++) - local_plt_offsets[i] = (bfd_vma) -1; - } - offset = &local_plt_offsets[r_symndx]; - } - - if (*offset == (bfd_vma) -1) - { - *offset = splt->size; - splt->size += 4; - } - break; - } - } - - return TRUE; -} - -/* This must exist if dynobj is ever set. */ - -static bfd_boolean -m32c_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj = elf_hash_table (info)->dynobj; - asection *splt = elf_hash_table (info)->splt; - - /* As an extra sanity check, verify that all plt entries have - been filled in. */ - - if (dynobj != NULL && splt != NULL) - { - bfd_byte *contents = splt->contents; - unsigned int i, size = splt->size; - for (i = 0; i < size; i += 4) - { - unsigned int x = bfd_get_32 (dynobj, contents + i); - BFD_ASSERT (x != 0); - } - } - - return TRUE; -} - -static bfd_boolean -m32c_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *splt; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - return TRUE; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size); - if (splt->contents == NULL) - return FALSE; - - return TRUE; -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -m32c_elf_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -m32c_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, old_partial; - flagword new_flags, new_partial; - bfd_boolean error = FALSE; - char new_opt[80]; - char old_opt[80]; - - new_opt[0] = old_opt[0] = '\0'; - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - -#ifdef DEBUG - _bfd_error_handler - ("old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s, filename = %s", - old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no", - bfd_get_filename (ibfd)); -#endif - - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - - else if (new_flags == old_flags) - /* Compatible flags are ok. */ - ; - - else /* Possibly incompatible flags. */ - { - /* Warn if different cpu is used (allow a specific cpu to override - the generic cpu). */ - new_partial = (new_flags & EF_M32C_CPU_MASK); - old_partial = (old_flags & EF_M32C_CPU_MASK); - if (new_partial == old_partial) - ; - - else - { - switch (new_partial) - { - default: strcat (new_opt, " -m16c"); break; - case EF_M32C_CPU_M16C: strcat (new_opt, " -m16c"); break; - case EF_M32C_CPU_M32C: strcat (new_opt, " -m32c"); break; - } - - switch (old_partial) - { - default: strcat (old_opt, " -m16c"); break; - case EF_M32C_CPU_M16C: strcat (old_opt, " -m16c"); break; - case EF_M32C_CPU_M32C: strcat (old_opt, " -m32c"); break; - } - } - - /* Print out any mismatches from above. */ - if (new_opt[0]) - { - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: compiled with %s and linked with modules compiled with %s"), - ibfd, new_opt, old_opt); - } - - new_flags &= ~ EF_M32C_ALL_FLAGS; - old_flags &= ~ EF_M32C_ALL_FLAGS; - - /* Warn about any other mismatches. */ - if (new_flags != old_flags) - { - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields" - " than previous modules (%#x)"), - ibfd, new_flags, old_flags); - } - } - - if (error) - bfd_set_error (bfd_error_bad_value); - - return !error; -} - - -static bfd_boolean -m32c_elf_print_private_bfd_data (bfd *abfd, void *ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (unsigned long) flags); - - switch (flags & EF_M32C_CPU_MASK) - { - default: break; - case EF_M32C_CPU_M16C: fprintf (file, " -m16c"); break; - case EF_M32C_CPU_M32C: fprintf (file, " -m32c"); break; - } - - fputc ('\n', file); - return TRUE; -} - -/* Return the MACH for an e_flags value. */ - -static int -elf32_m32c_machine (bfd *abfd) -{ - switch (elf_elfheader (abfd)->e_flags & EF_M32C_CPU_MASK) - { - case EF_M32C_CPU_M16C: return bfd_mach_m16c; - case EF_M32C_CPU_M32C: return bfd_mach_m32c; - } - - return bfd_mach_m16c; -} - -static bfd_boolean -m32c_elf_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_m32c, - elf32_m32c_machine (abfd)); - return TRUE; -} - - -#ifdef DEBUG -void -dump_symtab (bfd * abfd, void *internal_syms, void *external_syms) -{ - size_t locsymcount; - Elf_Internal_Sym *isymbuf; - Elf_Internal_Sym *isymend; - Elf_Internal_Sym *isym; - Elf_Internal_Shdr *symtab_hdr; - bfd_boolean free_internal = 0, free_external = 0; - char * st_info_str; - char * st_info_stb_str; - char * st_other_str; - char * st_shndx_str; - - if (! internal_syms) - { - internal_syms = bfd_malloc (1000); - free_internal = 1; - } - if (! external_syms) - { - external_syms = bfd_malloc (1000); - free_external = 1; - } - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_size / get_elf_backend_data(abfd)->s->sizeof_sym; - if (free_internal) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - internal_syms, external_syms, NULL); - else - isymbuf = internal_syms; - isymend = isymbuf + locsymcount; - - for (isym = isymbuf ; isym < isymend ; isym++) - { - switch (ELF_ST_TYPE (isym->st_info)) - { - case STT_FUNC: - st_info_str = "STT_FUNC"; - break; - - case STT_SECTION: - st_info_str = "STT_SECTION"; - break; - - case STT_FILE: - st_info_str = "STT_FILE"; - break; - - case STT_OBJECT: - st_info_str = "STT_OBJECT"; - break; - - case STT_TLS: - st_info_str = "STT_TLS"; - break; - - default: - st_info_str = ""; - } - - switch (ELF_ST_BIND (isym->st_info)) - { - case STB_LOCAL: - st_info_stb_str = "STB_LOCAL"; - break; - - case STB_GLOBAL: - st_info_stb_str = "STB_GLOBAL"; - break; - - default: - st_info_stb_str = ""; - } - - switch (ELF_ST_VISIBILITY (isym->st_other)) - { - case STV_DEFAULT: - st_other_str = "STV_DEFAULT"; - break; - - case STV_INTERNAL: - st_other_str = "STV_INTERNAL"; - break; - - case STV_PROTECTED: - st_other_str = "STV_PROTECTED"; - break; - - default: - st_other_str = ""; - } - - switch (isym->st_shndx) - { - case SHN_ABS: - st_shndx_str = "SHN_ABS"; - break; - - case SHN_COMMON: - st_shndx_str = "SHN_COMMON"; - break; - - case SHN_UNDEF: - st_shndx_str = "SHN_UNDEF"; - break; - - default: - st_shndx_str = ""; - } - - printf ("isym = %p st_value = %lx st_size = %lx st_name = (%lu) %s " - "st_info = (%d) %s %s st_other = (%d) %s st_shndx = (%d) %s\n", - isym, - (unsigned long) isym->st_value, - (unsigned long) isym->st_size, - isym->st_name, - bfd_elf_string_from_elf_section (abfd, symtab_hdr->sh_link, - isym->st_name), - isym->st_info, st_info_str, st_info_stb_str, - isym->st_other, st_other_str, - isym->st_shndx, st_shndx_str); - } - if (free_internal) - free (internal_syms); - if (free_external) - free (external_syms); -} - -char * -m32c_get_reloc (long reloc) -{ - if (0 <= reloc && reloc < R_M32C_max) - return m32c_elf_howto_table[reloc].name; - else - return ""; -} -#endif /* DEBUG */ - -/* Handle relaxing. */ - -/* A subroutine of m32c_elf_relax_section. If the global symbol H - is within the low 64k, remove any entry for it in the plt. */ - -struct relax_plt_data -{ - asection *splt; - bfd_boolean *again; -}; - -static bfd_boolean -m32c_relax_plt_check (struct elf_link_hash_entry *h, void * xdata) -{ - struct relax_plt_data *data = (struct relax_plt_data *) xdata; - - if (h->plt.offset != (bfd_vma) -1) - { - bfd_vma address; - - if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - address = 0; - else - address = (h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset - + h->root.u.def.value); - - if (address <= 0xffff) - { - h->plt.offset = -1; - data->splt->size -= 4; - *data->again = TRUE; - } - } - - return TRUE; -} - -/* A subroutine of m32c_elf_relax_section. If the global symbol H - previously had a plt entry, give it a new entry offset. */ - -static bfd_boolean -m32c_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata) -{ - bfd_vma *entry = (bfd_vma *) xdata; - - if (h->plt.offset != (bfd_vma) -1) - { - h->plt.offset = *entry; - *entry += 4; - } - - return TRUE; -} - -static bfd_boolean -m32c_elf_relax_plt_section (asection *splt, - struct bfd_link_info *info, - bfd_boolean *again) -{ - struct relax_plt_data relax_plt_data; - bfd *ibfd; - - /* Assume nothing changes. */ - *again = FALSE; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Quick check for an empty plt. */ - if (splt->size == 0) - return TRUE; - - /* Map across all global symbols; see which ones happen to - fall in the low 64k. */ - relax_plt_data.splt = splt; - relax_plt_data.again = again; - elf_link_hash_traverse (elf_hash_table (info), m32c_relax_plt_check, - &relax_plt_data); - - /* Likewise for local symbols, though that's somewhat less convenient - as we have to walk the list of input bfds and swap in symbol data. */ - for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next) - { - bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - unsigned int idx; - - if (! local_plt_offsets) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - for (idx = 0; idx < symtab_hdr->sh_info; ++idx) - { - Elf_Internal_Sym *isym; - asection *tsec; - bfd_vma address; - - if (local_plt_offsets[idx] == (bfd_vma) -1) - continue; - - isym = &isymbuf[idx]; - if (isym->st_shndx == SHN_UNDEF) - continue; - else if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else - tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx); - - address = (tsec->output_section->vma - + tsec->output_offset - + isym->st_value); - if (address <= 0xffff) - { - local_plt_offsets[idx] = -1; - splt->size -= 4; - *again = TRUE; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - } - - /* If we changed anything, walk the symbols again to reallocate - .plt entry addresses. */ - if (*again && splt->size > 0) - { - bfd_vma entry = 0; - - elf_link_hash_traverse (elf_hash_table (info), - m32c_relax_plt_realloc, &entry); - - for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next) - { - bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); - unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info; - unsigned int idx; - - if (! local_plt_offsets) - continue; - - for (idx = 0; idx < nlocals; ++idx) - if (local_plt_offsets[idx] != (bfd_vma) -1) - { - local_plt_offsets[idx] = entry; - entry += 4; - } - } - } - - return TRUE; -} - -static int -compare_reloc (const void *e1, const void *e2) -{ - const Elf_Internal_Rela *i1 = (const Elf_Internal_Rela *) e1; - const Elf_Internal_Rela *i2 = (const Elf_Internal_Rela *) e2; - - if (i1->r_offset == i2->r_offset) - return 0; - else - return i1->r_offset < i2->r_offset ? -1 : 1; -} - -#define OFFSET_FOR_RELOC(rel) m32c_offset_for_reloc (abfd, rel, symtab_hdr, shndx_buf, intsyms) -static bfd_vma -m32c_offset_for_reloc (bfd *abfd, - Elf_Internal_Rela *rel, - Elf_Internal_Shdr *symtab_hdr, - Elf_External_Sym_Shndx *shndx_buf ATTRIBUTE_UNUSED, - Elf_Internal_Sym *intsyms) -{ - bfd_vma symval; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (rel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *ssec; - - isym = intsyms + ELF32_R_SYM (rel->r_info); - ssec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - if (ssec) - symval += ssec->output_section->vma - + ssec->output_offset; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (rel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - return 0; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - return symval; -} - -static int bytes_saved = 0; - -static int bytes_to_reloc[] = { - R_M32C_NONE, - R_M32C_8, - R_M32C_16, - R_M32C_24, - R_M32C_32 -}; - -/* What we use the bits in a relax reloc addend (R_M32C_RL_*) for. */ - -/* Mask for the number of relocs associated with this insn. */ -#define RLA_RELOCS 0x0000000f -/* Number of bytes gas emitted (before gas's relaxing) */ -#define RLA_NBYTES 0x00000ff0 - -/* If the displacement is within the given range and the new encoding - differs from the old encoding (the index), then the insn can be - relaxed to the new encoding. */ -typedef struct { - int bytes; - unsigned int max_disp; - unsigned char new_encoding; -} EncodingTable; - -static EncodingTable m16c_addr_encodings[] = { - { 0, 0, 0 }, /* R0 */ - { 0, 0, 1 }, /* R1 */ - { 0, 0, 2 }, /* R2 */ - { 0, 0, 3 }, /* R3 */ - { 0, 0, 4 }, /* A0 */ - { 0, 0, 5 }, /* A1 */ - { 0, 0, 6 }, /* [A0] */ - { 0, 0, 7 }, /* [A1] */ - { 1, 0, 6 }, /* udsp:8[A0] */ - { 1, 0, 7 }, /* udsp:8[A1] */ - { 1, 0, 10 }, /* udsp:8[SB] */ - { 1, 0, 11 }, /* sdsp:8[FB] */ - { 2, 255, 8 }, /* udsp:16[A0] */ - { 2, 255, 9 }, /* udsp:16[A1] */ - { 2, 255, 10 }, /* udsp:16[SB] */ - { 2, 0, 15 }, /* abs:16 */ -}; - -static EncodingTable m16c_jmpaddr_encodings[] = { - { 0, 0, 0 }, /* R0 */ - { 0, 0, 1 }, /* R1 */ - { 0, 0, 2 }, /* R2 */ - { 0, 0, 3 }, /* R3 */ - { 0, 0, 4 }, /* A0 */ - { 0, 0, 5 }, /* A1 */ - { 0, 0, 6 }, /* [A0] */ - { 0, 0, 7 }, /* [A1] */ - { 1, 0, 6 }, /* udsp:8[A0] */ - { 1, 0, 7 }, /* udsp:8[A1] */ - { 1, 0, 10 }, /* udsp:8[SB] */ - { 1, 0, 11 }, /* sdsp:8[FB] */ - { 3, 255, 8 }, /* udsp:20[A0] */ - { 3, 255, 9 }, /* udsp:20[A1] */ - { 2, 255, 10 }, /* udsp:16[SB] */ - { 2, 0, 15 }, /* abs:16 */ -}; - -static EncodingTable m32c_addr_encodings[] = { - { 0, 0, 0 }, /* [A0] */ - { 0, 0, 1 }, /* [A1] */ - { 0, 0, 2 }, /* A0 */ - { 0, 0, 3 }, /* A1 */ - { 1, 0, 0 }, /* udsp:8[A0] */ - { 1, 0, 1 }, /* udsp:8[A1] */ - { 1, 0, 6 }, /* udsp:8[SB] */ - { 1, 0, 7 }, /* sdsp:8[FB] */ - { 2, 255, 4 }, /* udsp:16[A0] */ - { 2, 255, 5 }, /* udsp:16[A1] */ - { 2, 255, 6 }, /* udsp:16[SB] */ - { 2, 127, 7 }, /* sdsp:16[FB] */ - { 3, 65535, 8 }, /* udsp:24[A0] */ - { 3, 65535, 9 }, /* udsp:24[A1] */ - { 3, 65535, 15 }, /* abs24 */ - { 2, 0, 15 }, /* abs16 */ - { 0, 0, 16 }, /* R2 */ - { 0, 0, 17 }, /* R3 */ - { 0, 0, 18 }, /* R0 */ - { 0, 0, 19 }, /* R1 */ - { 0, 0, 20 }, /* */ - { 0, 0, 21 }, /* */ - { 0, 0, 22 }, /* */ - { 0, 0, 23 }, /* */ - { 0, 0, 24 }, /* */ - { 0, 0, 25 }, /* */ - { 0, 0, 26 }, /* */ - { 0, 0, 27 }, /* */ - { 0, 0, 28 }, /* */ - { 0, 0, 29 }, /* */ - { 0, 0, 30 }, /* */ - { 0, 0, 31 }, /* */ -}; - -static bfd_boolean -m32c_elf_relax_section - (bfd * abfd, - asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Shdr *shndx_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *free_relocs = NULL; - Elf_Internal_Rela *irel, *irelend, *srel; - bfd_byte * contents = NULL; - bfd_byte * free_contents = NULL; - Elf_Internal_Sym *intsyms = NULL; - Elf_Internal_Sym *free_intsyms = NULL; - Elf_External_Sym_Shndx *shndx_buf = NULL; - int machine; - - if (abfd == elf_hash_table (link_info)->dynobj - && (sec->flags & SEC_LINKER_CREATED) != 0 - && strcmp (sec->name, ".plt") == 0) - return m32c_elf_relax_plt_section (sec, link_info, again); - - /* Assume nothing changes. */ - *again = FALSE; - - machine = elf32_m32c_machine (abfd); - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = & elf_symtab_hdr (abfd); - if (elf_symtab_shndx_list (abfd)) - shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; - else - shndx_hdr = NULL; - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - - /* Read this BFD's symbols. */ - /* Get cached copy if it exists. */ - if (symtab_hdr->contents != NULL) - { - intsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - } - else - { - intsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, symtab_hdr->sh_info, 0, NULL, NULL, NULL); - symtab_hdr->contents = (bfd_byte *) intsyms; - } - - if (shndx_hdr && shndx_hdr->sh_size != 0) - { - bfd_size_type amt; - - amt = symtab_hdr->sh_info; - amt *= sizeof (Elf_External_Sym_Shndx); - shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); - if (shndx_buf == NULL) - goto error_return; - if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (shndx_buf, amt, abfd) != amt) - goto error_return; - shndx_hdr->contents = (bfd_byte *) shndx_buf; - } - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - if (! link_info->keep_memory) - free_relocs = internal_relocs; - - /* The RL_ relocs must be just before the operand relocs they go - with, so we must sort them to guarantee this. */ - qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), - compare_reloc); - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - unsigned char *insn, *gap, *einsn; - bfd_vma pc; - bfd_signed_vma pcrel; - int relax_relocs; - int gap_size; - int new_type; - int posn; - int enc; - EncodingTable *enctbl; - EncodingTable *e; - - if (ELF32_R_TYPE(irel->r_info) != R_M32C_RL_JUMP - && ELF32_R_TYPE(irel->r_info) != R_M32C_RL_1ADDR - && ELF32_R_TYPE(irel->r_info) != R_M32C_RL_2ADDR) - continue; - - srel = irel; - - /* There will always be room for the relaxed insn, since it is smaller - than the one it would replace. */ - BFD_ASSERT (irel->r_offset < sec->size); - - insn = contents + irel->r_offset; - relax_relocs = irel->r_addend % 16; - - /* Ok, we only have three relocs we care about, and they're all - fake. The lower four bits of the addend is always the number - of following relocs (hence the qsort above) that are assigned - to this opcode. The next 8 bits of the addend indicates the - number of bytes in the insn. We use the rest of them - ourselves as flags for the more expensive operations (defines - above). The three relocs are: - - RL_JUMP: This marks all direct jump insns. We check the - displacement and replace them with shorter jumps if - they're in range. We also use this to find JMP.S - insns and manually shorten them when we delete bytes. - We have to decode these insns to figure out what to - do. - - RL_1ADDR: This is a :G or :Q insn, which has a single - "standard" operand. We have to extract the type - field, see if it's a wide displacement, then figure - out if we can replace it with a narrow displacement. - We don't have to decode these insns. - - RL_2ADDR: Similarly, but two "standard" operands. Note that - r_addend may still be 1, as standard operands don't - always have displacements. Gas shouldn't give us one - with zero operands, but since we don't know which one - has the displacement, we check them both anyway. - - These all point to the beginning of the insn itself, not the - operands. - - Note that we only relax one step at a time, relying on the - linker to call us repeatedly. Thus, there is no code for - JMP.A->JMP.B although that will happen in two steps. - Likewise, for 2ADDR relaxes, we do one operand per cycle. - */ - - /* Get the value of the symbol referred to by the reloc. Just - in case this is the last reloc in the list, use the RL's - addend to choose between this reloc (no addend) or the next - (yes addend, which means at least one following reloc). */ - srel = irel + (relax_relocs ? 1 : 0); - symval = OFFSET_FOR_RELOC (srel); - - /* Setting gap_size nonzero is the flag which means "something - shrunk". */ - gap_size = 0; - gap = NULL; - new_type = ELF32_R_TYPE(srel->r_info); - - pc = sec->output_section->vma + sec->output_offset - + srel->r_offset; - pcrel = symval - pc + srel->r_addend; - - if (machine == bfd_mach_m16c) - { - /* R8C / M16C */ - - switch (ELF32_R_TYPE(irel->r_info)) - { - - case R_M32C_RL_JUMP: - switch (insn[0]) - { - case 0xfe: /* jmp.b */ - if (pcrel >= 2 && pcrel <= 9) - { - /* Relax JMP.B -> JMP.S. We need to get rid of - the following reloc though. */ - insn[0] = 0x60 | (pcrel - 2); - new_type = R_M32C_NONE; - irel->r_addend = 0x10; - gap_size = 1; - gap = insn + 1; - } - break; - - case 0xf4: /* jmp.w */ - /* 128 is allowed because it will be one byte closer - after relaxing. Likewise for all other pc-rel - jumps. */ - if (pcrel <= 128 && pcrel >= -128) - { - /* Relax JMP.W -> JMP.B */ - insn[0] = 0xfe; - insn[1] = 0; - new_type = R_M32C_8_PCREL; - gap_size = 1; - gap = insn + 2; - } - break; - - case 0xfc: /* jmp.a */ - if (pcrel <= 32768 && pcrel >= -32768) - { - /* Relax JMP.A -> JMP.W */ - insn[0] = 0xf4; - insn[1] = 0; - insn[2] = 0; - new_type = R_M32C_16_PCREL; - gap_size = 1; - gap = insn + 3; - } - break; - - case 0xfd: /* jsr.a */ - if (pcrel <= 32768 && pcrel >= -32768) - { - /* Relax JSR.A -> JSR.W */ - insn[0] = 0xf5; - insn[1] = 0; - insn[2] = 0; - new_type = R_M32C_16_PCREL; - gap_size = 1; - gap = insn + 3; - } - break; - } - break; - - case R_M32C_RL_2ADDR: - /* xxxx xxxx srce dest [src-disp] [dest-disp]*/ - - enctbl = m16c_addr_encodings; - posn = 2; - enc = (insn[1] >> 4) & 0x0f; - e = & enctbl[enc]; - - if (srel->r_offset == irel->r_offset + posn - && e->new_encoding != enc - && symval <= e->max_disp) - { - insn[1] &= 0x0f; - insn[1] |= e->new_encoding << 4; - gap_size = e->bytes - enctbl[e->new_encoding].bytes; - gap = insn + posn + enctbl[e->new_encoding].bytes; - new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; - break; - } - if (relax_relocs == 2) - srel ++; - posn += e->bytes; - - goto try_1addr_16; - - case R_M32C_RL_1ADDR: - /* xxxx xxxx xxxx dest [disp] */ - - enctbl = m16c_addr_encodings; - posn = 2; - - /* Check the opcode for jumps. We know it's safe to - do this because all 2ADDR insns are at least two - bytes long. */ - enc = insn[0] * 256 + insn[1]; - enc &= 0xfff0; - if (enc == 0x7d20 - || enc == 0x7d00 - || enc == 0x7d30 - || enc == 0x7d10) - { - enctbl = m16c_jmpaddr_encodings; - } - - try_1addr_16: - /* srel, posn, and enc must be set here. */ - - symval = OFFSET_FOR_RELOC (srel); - enc = insn[1] & 0x0f; - e = & enctbl[enc]; - - if (srel->r_offset == irel->r_offset + posn - && e->new_encoding != enc - && symval <= e->max_disp) - { - insn[1] &= 0xf0; - insn[1] |= e->new_encoding; - gap_size = e->bytes - enctbl[e->new_encoding].bytes; - gap = insn + posn + enctbl[e->new_encoding].bytes; - new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; - break; - } - - break; - - } /* Ends switch (reloc type) for m16c. */ - } - else /* machine == bfd_mach_m32c */ - { - /* M32CM / M32C */ - - switch (ELF32_R_TYPE(irel->r_info)) - { - - case R_M32C_RL_JUMP: - switch (insn[0]) - { - case 0xbb: /* jmp.b */ - if (pcrel >= 2 && pcrel <= 9) - { - int p = pcrel - 2; - /* Relax JMP.B -> JMP.S. We need to get rid of - the following reloc though. */ - insn[0] = 0x4a | ((p << 3) & 0x30) | (p & 1); - new_type = R_M32C_NONE; - irel->r_addend = 0x10; - gap_size = 1; - gap = insn + 1; - } - break; - - case 0xce: /* jmp.w */ - if (pcrel <= 128 && pcrel >= -128) - { - /* Relax JMP.W -> JMP.B */ - insn[0] = 0xbb; - insn[1] = 0; - new_type = R_M32C_8_PCREL; - gap_size = 1; - gap = insn + 2; - } - break; - - case 0xcc: /* jmp.a */ - if (pcrel <= 32768 && pcrel >= -32768) - { - /* Relax JMP.A -> JMP.W */ - insn[0] = 0xce; - insn[1] = 0; - insn[2] = 0; - new_type = R_M32C_16_PCREL; - gap_size = 1; - gap = insn + 3; - } - break; - - case 0xcd: /* jsr.a */ - if (pcrel <= 32768 && pcrel >= -32768) - { - /* Relax JSR.A -> JSR.W */ - insn[0] = 0xcf; - insn[1] = 0; - insn[2] = 0; - new_type = R_M32C_16_PCREL; - gap_size = 1; - gap = insn + 3; - } - break; - } - break; - - case R_M32C_RL_2ADDR: - /* xSSS DDDx DDSS xxxx [src-disp] [dest-disp]*/ - - einsn = insn; - posn = 2; - if (einsn[0] == 1) - { - /* prefix; remove it as far as the RL reloc is concerned. */ - einsn ++; - posn ++; - } - - enctbl = m32c_addr_encodings; - enc = ((einsn[0] & 0x70) >> 2) | ((einsn[1] & 0x30) >> 4); - e = & enctbl[enc]; - - if (srel->r_offset == irel->r_offset + posn - && e->new_encoding != enc - && symval <= e->max_disp) - { - einsn[0] &= 0x8f; - einsn[0] |= (e->new_encoding & 0x1c) << 2; - einsn[1] &= 0xcf; - einsn[1] |= (e->new_encoding & 0x03) << 4; - gap_size = e->bytes - enctbl[e->new_encoding].bytes; - gap = insn + posn + enctbl[e->new_encoding].bytes; - new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; - break; - } - if (relax_relocs == 2) - srel ++; - posn += e->bytes; - - goto try_1addr_32; - - case R_M32C_RL_1ADDR: - /* xxxx DDDx DDxx xxxx [disp] */ - - einsn = insn; - posn = 2; - if (einsn[0] == 1) - { - /* prefix; remove it as far as the RL reloc is concerned. */ - einsn ++; - posn ++; - } - - enctbl = m32c_addr_encodings; - - try_1addr_32: - /* srel, posn, and enc must be set here. */ - - symval = OFFSET_FOR_RELOC (srel); - enc = ((einsn[0] & 0x0e) << 1) | ((einsn[1] & 0xc0) >> 6); - e = & enctbl[enc]; - - if (srel->r_offset == irel->r_offset + posn - && e->new_encoding != enc - && symval <= e->max_disp) - { - einsn[0] &= 0xf1; - einsn[0] |= (e->new_encoding & 0x1c) >> 1; - einsn[1] &= 0x3f; - einsn[1] |= (e->new_encoding & 0x03) << 6; - gap_size = e->bytes - enctbl[e->new_encoding].bytes; - gap = insn + posn + enctbl[e->new_encoding].bytes; - new_type = bytes_to_reloc[enctbl[e->new_encoding].bytes]; - break; - } - - break; - - } /* Ends switch (reloc type) for m32c. */ - } - - if (gap_size == 0) - continue; - - *again = TRUE; - - srel->r_info = ELF32_R_INFO (ELF32_R_SYM (srel->r_info), new_type); - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - free_relocs = NULL; - - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; - - symtab_hdr->contents = (bfd_byte *) intsyms; - free_intsyms = NULL; - - bytes_saved += gap_size; - - if (! m32c_elf_relax_delete_bytes(abfd, sec, gap - contents, gap_size)) - goto error_return; - - } /* next relocation */ - - if (free_relocs != NULL) - { - free (free_relocs); - free_relocs = NULL; - } - - if (free_contents != NULL) - { - if (! link_info->keep_memory) - free (free_contents); - /* Cache the section contents for elf_link_input_bfd. */ - else - elf_section_data (sec)->this_hdr.contents = contents; - - free_contents = NULL; - } - - if (shndx_buf != NULL) - { - shndx_hdr->contents = NULL; - free (shndx_buf); - } - - if (free_intsyms != NULL) - { - if (! link_info->keep_memory) - free (free_intsyms); - /* Cache the symbols for elf_link_input_bfd. */ - else - { - symtab_hdr->contents = NULL /* (unsigned char *) intsyms*/; - } - - free_intsyms = NULL; - } - - return TRUE; - - error_return: - if (free_relocs != NULL) - free (free_relocs); - if (free_contents != NULL) - free (free_contents); - if (shndx_buf != NULL) - { - shndx_hdr->contents = NULL; - free (shndx_buf); - } - if (free_intsyms != NULL) - free (free_intsyms); - return FALSE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -m32c_elf_relax_delete_bytes - (bfd * abfd, - asection * sec, - bfd_vma addr, - int count) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Shdr *shndx_hdr; - int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - Elf_Internal_Sym *intsyms; - Elf_External_Sym_Shndx *shndx_buf; - Elf_External_Sym_Shndx *shndx; - struct elf_link_hash_entry ** sym_hashes; - struct elf_link_hash_entry ** end_hashes; - unsigned int symcount; - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel ++) - { - /* Get the new reloc address. */ - if (irel->r_offset > addr && irel->r_offset < toaddr) - irel->r_offset -= count; - - if (ELF32_R_TYPE(irel->r_info) == R_M32C_RL_JUMP - && irel->r_addend == 0x10 /* one byte insn, no relocs */ - && irel->r_offset + 1 < addr - && irel->r_offset + 7 > addr) - { - bfd_vma disp; - unsigned char *insn = &contents[irel->r_offset]; - disp = *insn; - /* This is a JMP.S, which we have to manually update. */ - if (elf32_m32c_machine (abfd) == bfd_mach_m16c) - { - if ((*insn & 0xf8) != 0x60) - continue; - disp = (disp & 7); - } - else - { - if ((*insn & 0xce) != 0x4a) - continue; - disp = ((disp & 0x30) >> 3) | (disp & 1); - } - if (irel->r_offset + disp + 2 >= addr+count) - { - disp -= count; - if (elf32_m32c_machine (abfd) == bfd_mach_m16c) - { - *insn = (*insn & 0xf8) | disp; - } - else - { - *insn = (*insn & 0xce) | ((disp & 6) << 3) | (disp & 1); - } - } - } - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - intsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - isym = intsyms; - isymend = isym + symtab_hdr->sh_info; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - if (elf_symtab_shndx_list (abfd)) - { - shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; - shndx_buf = (Elf_External_Sym_Shndx *) shndx_hdr->contents; - } - else - { - shndx_hdr = NULL; - shndx_buf = NULL; - } - shndx = shndx_buf; - - for (; isym < isymend; isym++, shndx = (shndx ? shndx + 1 : NULL)) - { - /* If the symbol is in the range of memory we just moved, we - have to adjust its value. */ - if ((int) isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - { - isym->st_value -= count; - } - /* If the symbol *spans* the bytes we just deleted (i.e. it's - *end* is in the moved bytes but it's *start* isn't), then we - must adjust its size. */ - if ((int) isym->st_shndx == sec_shndx - && isym->st_value < addr - && isym->st_value + isym->st_size > addr - && isym->st_value + isym->st_size < toaddr) - { - isym->st_size -= count; - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - // sym_hashes += symtab_hdr->sh_info; - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes ++) - { - struct elf_link_hash_entry * sym_hash = * sym_hashes; - - if (sym_hash && - (sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - if (sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - { - sym_hash->root.u.def.value -= count; - } - if (sym_hash->root.u.def.value < addr - && sym_hash->root.u.def.value + sym_hash->size > addr - && sym_hash->root.u.def.value + sym_hash->size < toaddr) - { - sym_hash->size -= count; - } - } - } - - return TRUE; -} - -/* This is for versions of gcc prior to 4.3. */ -static unsigned int -_bfd_m32c_elf_eh_frame_address_size (bfd *abfd, - const asection *sec ATTRIBUTE_UNUSED) -{ - if ((elf_elfheader (abfd)->e_flags & EF_M32C_CPU_MASK) == EF_M32C_CPU_M16C) - return 2; - return 4; -} - - - -#define ELF_ARCH bfd_arch_m32c -#define ELF_MACHINE_CODE EM_M32C -#define ELF_MACHINE_ALT1 EM_M32C_OLD -#define ELF_MAXPAGESIZE 0x100 - -#if 0 -#define TARGET_BIG_SYM m32c_elf32_vec -#define TARGET_BIG_NAME "elf32-m32c" -#else -#define TARGET_LITTLE_SYM m32c_elf32_vec -#define TARGET_LITTLE_NAME "elf32-m32c" -#endif - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto m32c_info_to_howto_rela -#define elf_backend_object_p m32c_elf_object_p -#define elf_backend_relocate_section m32c_elf_relocate_section -#define elf_backend_check_relocs m32c_elf_check_relocs -#define elf_backend_object_p m32c_elf_object_p -#define elf_symbol_leading_char ('_') -#define elf_backend_always_size_sections \ - m32c_elf_always_size_sections -#define elf_backend_finish_dynamic_sections \ - m32c_elf_finish_dynamic_sections - -#define elf_backend_can_gc_sections 1 -#define elf_backend_eh_frame_address_size _bfd_m32c_elf_eh_frame_address_size - -#define bfd_elf32_bfd_reloc_type_lookup m32c_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup m32c_reloc_name_lookup -#define bfd_elf32_bfd_relax_section m32c_elf_relax_section -#define bfd_elf32_bfd_set_private_flags m32c_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data m32c_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data m32c_elf_print_private_bfd_data - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-m32r.c b/sdcc/support/sdbinutils/bfd/elf32-m32r.c deleted file mode 100644 index 78d5e3966..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m32r.c +++ /dev/null @@ -1,3910 +0,0 @@ -/* M32R-specific support for 32-bit ELF. - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/m32r.h" - -#define NOP_INSN 0x7000 -#define MAKE_PARALLEL(insn) ((insn) | 0x8000) - -/* Use REL instead of RELA to save space. - This only saves space in libraries and object files, but perhaps - relocs will be put in ROM? All in all though, REL relocs are a pain - to work with. */ -/* #define USE_REL 1 - -#ifndef USE_REL -#define USE_REL 0 -#endif */ -/* Use RELA. But use REL to link old objects for backwords compatibility. */ - -/* Functions for the M32R ELF linker. */ - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" - -/* The nop opcode we use. */ - -#define M32R_NOP 0x7000f000 - -#define PLT_EMPTY 0x10101010 /* RIE -> RIE */ - -/* The size in bytes of an entry in the procedure linkage table. */ - -#define PLT_ENTRY_SIZE 20 -#define PLT_HEADER_SIZE 20 - -/* The first one entries in a procedure linkage table are reserved, - and the initial contents are unimportant (we zero them out). - Subsequent entries look like this. */ - -#define PLT0_ENTRY_WORD0 0xd6c00000 /* seth r6, #high(.got+4) */ -#define PLT0_ENTRY_WORD1 0x86e60000 /* or3 r6, r6, #low(.got)+4) */ -#define PLT0_ENTRY_WORD2 0x24e626c6 /* ld r4, @r6+ -> ld r6, @r6 */ -#define PLT0_ENTRY_WORD3 0x1fc6f000 /* jmp r6 || pnop */ -#define PLT0_ENTRY_WORD4 PLT_EMPTY /* RIE -> RIE */ - -#define PLT0_PIC_ENTRY_WORD0 0xa4cc0004 /* ld r4, @(4,r12) */ -#define PLT0_PIC_ENTRY_WORD1 0xa6cc0008 /* ld r6, @(8,r12) */ -#define PLT0_PIC_ENTRY_WORD2 0x1fc6f000 /* jmp r6 || nop */ -#define PLT0_PIC_ENTRY_WORD3 PLT_EMPTY /* RIE -> RIE */ -#define PLT0_PIC_ENTRY_WORD4 PLT_EMPTY /* RIE -> RIE */ - -#define PLT_ENTRY_WORD0 0xe6000000 /* ld24 r6, .name_in_GOT */ -#define PLT_ENTRY_WORD1 0x06acf000 /* add r6, r12 || nop */ -#define PLT_ENTRY_WORD0b 0xd6c00000 /* seth r6, #high(.name_in_GOT) */ -#define PLT_ENTRY_WORD1b 0x86e60000 /* or3 r6, r6, #low(.name_in_GOT) */ -#define PLT_ENTRY_WORD2 0x26c61fc6 /* ld r6, @r6 -> jmp r6 */ -#define PLT_ENTRY_WORD3 0xe5000000 /* ld24 r5, $offset */ -#define PLT_ENTRY_WORD4 0xff000000 /* bra .plt0. */ - - -/* Utility to actually perform an R_M32R_10_PCREL reloc. */ - -static bfd_reloc_status_type -m32r_elf_do_10_pcrel_reloc (bfd *abfd, - reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, - bfd_vma offset, - asection *symbol_section ATTRIBUTE_UNUSED, - bfd_vma symbol_value, - bfd_vma addend) -{ - bfd_signed_vma relocation; - unsigned long x; - bfd_reloc_status_type status; - - /* Sanity check the address (offset in section). */ - if (offset > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - relocation = symbol_value + addend; - /* Make it pc relative. */ - relocation -= (input_section->output_section->vma - + input_section->output_offset); - /* These jumps mask off the lower two bits of the current address - before doing pcrel calculations. */ - relocation -= (offset & -(bfd_vma) 4); - - if (relocation < -0x200 || relocation > 0x1ff) - status = bfd_reloc_overflow; - else - status = bfd_reloc_ok; - - x = bfd_get_16 (abfd, data + offset); - relocation >>= howto->rightshift; - relocation <<= howto->bitpos; - x = (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask); - bfd_put_16 (abfd, (bfd_vma) x, data + offset); - - return status; -} - -/* Handle the R_M32R_10_PCREL reloc. */ - -static bfd_reloc_status_type -m32r_elf_10_pcrel_reloc (bfd * abfd, - arelent * reloc_entry, - asymbol * symbol, - void * data, - asection * input_section, - bfd * output_bfd, - char ** error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return m32r_elf_do_10_pcrel_reloc (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - symbol->section, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -/* Do generic partial_inplace relocation. - This is a local replacement for bfd_elf_generic_reloc. */ - -static bfd_reloc_status_type -m32r_elf_generic_reloc (bfd *input_bfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - bfd_byte *inplace_address; - - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Now do the reloc in the usual way. - ??? It would be nice to call bfd_elf_generic_reloc here, - but we have partial_inplace set. bfd_elf_generic_reloc will - pass the handling back to bfd_install_relocation which will install - a section relative addend which is wrong. */ - - /* Sanity check the address (offset in section). */ - if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - ret = bfd_reloc_ok; - if (bfd_is_und_section (symbol->section) - && output_bfd == NULL) - ret = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section) - || output_bfd != NULL) - relocation = 0; - else - relocation = symbol->value; - - /* Only do this for a final link. */ - if (output_bfd == NULL) - { - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - } - - relocation += reloc_entry->addend; - inplace_address = (bfd_byte *) data + reloc_entry->address; - -#define DOIT(x) \ - x = ( (x & ~reloc_entry->howto->dst_mask) | \ - (((x & reloc_entry->howto->src_mask) + relocation) & \ - reloc_entry->howto->dst_mask)) - - switch (reloc_entry->howto->size) - { - case 1: - { - short x = bfd_get_16 (input_bfd, inplace_address); - DOIT (x); - bfd_put_16 (input_bfd, (bfd_vma) x, inplace_address); - } - break; - case 2: - { - unsigned long x = bfd_get_32 (input_bfd, inplace_address); - DOIT (x); - bfd_put_32 (input_bfd, (bfd_vma)x , inplace_address); - } - break; - default: - BFD_ASSERT (0); - } - - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - - return ret; -} - -/* Handle the R_M32R_SDA16 reloc. - This reloc is used to compute the address of objects in the small data area - and to perform loads and stores from that area. - The lower 16 bits are sign extended and added to the register specified - in the instruction, which is assumed to point to _SDA_BASE_. */ - -static bfd_reloc_status_type -m32r_elf_sda16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - /* FIXME: not sure what to do here yet. But then again, the linker - may never call us. */ - abort (); -} - - -/* Handle the R_M32R_HI16_[SU]LO relocs. - HI16_SLO is for the add3 and load/store with displacement instructions. - HI16_ULO is for the or3 instruction. - For R_M32R_HI16_SLO, the lower 16 bits are sign extended when added to - the high 16 bytes so if the lower 16 bits are negative (bit 15 == 1) then - we must add one to the high 16 bytes (which will get subtracted off when - the low 16 bits are added). - These relocs have to be done in combination with an R_M32R_LO16 reloc - because there is a carry from the LO16 to the HI16. Here we just save - the information we need; we do the actual relocation when we see the LO16. - This code is copied from the elf32-mips.c. We also support an arbitrary - number of HI16 relocs to be associated with a single LO16 reloc. The - assembler sorts the relocs to ensure each HI16 immediately precedes its - LO16. However if there are multiple copies, the assembler may not find - the real LO16 so it picks the first one it finds. */ - -struct m32r_hi16 -{ - struct m32r_hi16 *next; - bfd_byte *addr; - bfd_vma addend; -}; - -/* FIXME: This should not be a static variable. */ - -static struct m32r_hi16 *m32r_hi16_list; - -static bfd_reloc_status_type -m32r_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - struct m32r_hi16 *n; - - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Sanity check the address (offset in section). */ - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - ret = bfd_reloc_ok; - if (bfd_is_und_section (symbol->section) - && output_bfd == NULL) - ret = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - /* Save the information, and let LO16 do the actual relocation. */ - n = bfd_malloc ((bfd_size_type) sizeof *n); - if (n == NULL) - return bfd_reloc_outofrange; - n->addr = (bfd_byte *) data + reloc_entry->address; - n->addend = relocation; - n->next = m32r_hi16_list; - m32r_hi16_list = n; - - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - - return ret; -} - -/* Handle an M32R ELF HI16 reloc. */ - -static void -m32r_elf_relocate_hi16 (bfd *input_bfd, - int type, - Elf_Internal_Rela *relhi, - Elf_Internal_Rela *rello, - bfd_byte *contents, - bfd_vma addend) -{ - unsigned long insn; - bfd_vma addlo; - - insn = bfd_get_32 (input_bfd, contents + relhi->r_offset); - - addlo = bfd_get_32 (input_bfd, contents + rello->r_offset); - if (type == R_M32R_HI16_SLO) - addlo = ((addlo & 0xffff) ^ 0x8000) - 0x8000; - else - addlo &= 0xffff; - - addend += ((insn & 0xffff) << 16) + addlo; - - /* Reaccount for sign extension of low part. */ - if (type == R_M32R_HI16_SLO - && (addend & 0x8000) != 0) - addend += 0x10000; - - bfd_put_32 (input_bfd, - (insn & 0xffff0000) | ((addend >> 16) & 0xffff), - contents + relhi->r_offset); -} - -/* Do an R_M32R_LO16 relocation. This is a straightforward 16 bit - inplace relocation; this function exists in order to do the - R_M32R_HI16_[SU]LO relocation described above. */ - -static bfd_reloc_status_type -m32r_elf_lo16_reloc (bfd *input_bfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (m32r_hi16_list != NULL) - { - struct m32r_hi16 *l; - - l = m32r_hi16_list; - while (l != NULL) - { - unsigned long insn; - unsigned long val; - unsigned long vallo; - struct m32r_hi16 *next; - - /* Do the HI16 relocation. Note that we actually don't need - to know anything about the LO16 itself, except where to - find the low 16 bits of the addend needed by the LO16. */ - insn = bfd_get_32 (input_bfd, l->addr); - vallo = ((bfd_get_32 (input_bfd, (bfd_byte *) data + reloc_entry->address) - & 0xffff) ^ 0x8000) - 0x8000; - val = ((insn & 0xffff) << 16) + vallo; - val += l->addend; - - /* Reaccount for sign extension of low part. */ - if ((val & 0x8000) != 0) - val += 0x10000; - - insn = (insn &~ (bfd_vma) 0xffff) | ((val >> 16) & 0xffff); - bfd_put_32 (input_bfd, (bfd_vma) insn, l->addr); - - next = l->next; - free (l); - l = next; - } - - m32r_hi16_list = NULL; - } - - /* Now do the LO16 reloc in the usual way. - ??? It would be nice to call bfd_elf_generic_reloc here, - but we have partial_inplace set. bfd_elf_generic_reloc will - pass the handling back to bfd_install_relocation which will install - a section relative addend which is wrong. */ - return m32r_elf_generic_reloc (input_bfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - - -static reloc_howto_type m32r_elf_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_M32R_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_M32R_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - m32r_elf_generic_reloc,/* special_function */ - "R_M32R_16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_M32R_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - m32r_elf_generic_reloc,/* special_function */ - "R_M32R_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 24 bit address. */ - HOWTO (R_M32R_24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - m32r_elf_generic_reloc,/* special_function */ - "R_M32R_24", /* name */ - TRUE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An PC Relative 10-bit relocation, shifted by 2. - This reloc is complicated because relocations are relative to pc & -4. - i.e. branches in the right insn slot use the address of the left insn - slot for pc. */ - /* ??? It's not clear whether this should have partial_inplace set or not. - Branch relaxing in the assembler can store the addend in the insn, - and if bfd_install_relocation gets called the addend may get added - again. */ - HOWTO (R_M32R_10_PCREL, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - m32r_elf_10_pcrel_reloc, /* special_function */ - "R_M32R_10_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 18 bit relocation, right shifted by 2. */ - HOWTO (R_M32R_18_PCREL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_18_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 26 bit relocation, right shifted by 2. */ - /* ??? It's not clear whether this should have partial_inplace set or not. - Branch relaxing in the assembler can store the addend in the insn, - and if bfd_install_relocation gets called the addend may get added - again. */ - HOWTO (R_M32R_26_PCREL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_26_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* High 16 bits of address when lower 16 is or'd in. */ - HOWTO (R_M32R_HI16_ULO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m32r_elf_hi16_reloc, /* special_function */ - "R_M32R_HI16_ULO", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of address when lower 16 is added in. */ - HOWTO (R_M32R_HI16_SLO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m32r_elf_hi16_reloc, /* special_function */ - "R_M32R_HI16_SLO", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 16 bits of address. */ - HOWTO (R_M32R_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m32r_elf_lo16_reloc, /* special_function */ - "R_M32R_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 16 bits offset. */ - HOWTO (R_M32R_SDA16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - m32r_elf_sda16_reloc, /* special_function */ - "R_M32R_SDA16", /* name */ - TRUE, /* partial_inplace */ /* FIXME: correct? */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_M32R_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_M32R_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_M32R_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_M32R_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - EMPTY_HOWTO (16), - EMPTY_HOWTO (17), - EMPTY_HOWTO (18), - EMPTY_HOWTO (19), - EMPTY_HOWTO (20), - EMPTY_HOWTO (21), - EMPTY_HOWTO (22), - EMPTY_HOWTO (23), - EMPTY_HOWTO (24), - EMPTY_HOWTO (25), - EMPTY_HOWTO (26), - EMPTY_HOWTO (27), - EMPTY_HOWTO (28), - EMPTY_HOWTO (29), - EMPTY_HOWTO (30), - EMPTY_HOWTO (31), - EMPTY_HOWTO (32), - - /* A 16 bit absolute relocation. */ - HOWTO (R_M32R_16_RELA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_16_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_M32R_32_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc,/* special_function */ - "R_M32R_32_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 24 bit address. */ - HOWTO (R_M32R_24_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc,/* special_function */ - "R_M32R_24_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32R_10_PCREL_RELA, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - m32r_elf_10_pcrel_reloc, /* special_function */ - "R_M32R_10_PCREL_RELA",/* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 18 bit relocation, right shifted by 2. */ - HOWTO (R_M32R_18_PCREL_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_18_PCREL_RELA",/* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 26 bit relocation, right shifted by 2. */ - HOWTO (R_M32R_26_PCREL_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_26_PCREL_RELA",/* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* High 16 bits of address when lower 16 is or'd in. */ - HOWTO (R_M32R_HI16_ULO_RELA, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_HI16_ULO_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of address when lower 16 is added in. */ - HOWTO (R_M32R_HI16_SLO_RELA, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_HI16_SLO_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 16 bits of address. */ - HOWTO (R_M32R_LO16_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_LO16_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 16 bits offset. */ - HOWTO (R_M32R_SDA16_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_SDA16_RELA", /* name */ - TRUE, /* partial_inplace */ /* FIXME: correct? */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_M32R_RELA_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_M32R_RELA_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_M32R_RELA_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_elf_rel_vtable_reloc_fn, /* special_function */ - "R_M32R_RELA_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit PC relative relocation. */ - HOWTO (R_M32R_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc,/* special_function */ - "R_M32R_REL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (46), - EMPTY_HOWTO (47), - - /* Like R_M32R_24, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOT24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOT24", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_M32R_PCREL, but referring to the procedure linkage table - entry for the symbol. */ - HOWTO (R_M32R_26_PLTREL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_26_PLTREL", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_M32R_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_COPY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_M32R_24, but used when setting global offset table - entries. */ - HOWTO (R_M32R_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marks a procedure linkage table entry for a symbol. */ - HOWTO (R_M32R_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_M32R_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32R_GOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An PC Relative 24-bit relocation used when setting PIC offset - table register. */ - HOWTO (R_M32R_GOTPC24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTPC24", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_M32R_HI16_ULO, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOT16_HI_ULO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOT16_HI_ULO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_M32R_HI16_SLO, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOT16_HI_SLO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOT16_HI_SLO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_M32R_LO16, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOT16_LO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOT16_LO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An PC Relative relocation used when setting PIC offset table register. - Like R_M32R_HI16_ULO, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOTPC_HI_ULO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTPC_HI_ULO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* An PC Relative relocation used when setting PIC offset table register. - Like R_M32R_HI16_SLO, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOTPC_HI_SLO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTPC_HI_SLO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* An PC Relative relocation used when setting PIC offset table register. - Like R_M32R_LO16, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_M32R_GOTPC_LO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTPC_LO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_M32R_GOTOFF_HI_ULO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTOFF_HI_ULO",/* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32R_GOTOFF_HI_SLO, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTOFF_HI_SLO",/* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_M32R_GOTOFF_LO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M32R_GOTOFF_LO", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* Map BFD reloc types to M32R ELF reloc types. */ - -struct m32r_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -#ifdef USE_M32R_OLD_RELOC -static const struct m32r_reloc_map m32r_reloc_map_old[] = -{ - { BFD_RELOC_NONE, R_M32R_NONE }, - { BFD_RELOC_16, R_M32R_16 }, - { BFD_RELOC_32, R_M32R_32 }, - { BFD_RELOC_M32R_24, R_M32R_24 }, - { BFD_RELOC_M32R_10_PCREL, R_M32R_10_PCREL }, - { BFD_RELOC_M32R_18_PCREL, R_M32R_18_PCREL }, - { BFD_RELOC_M32R_26_PCREL, R_M32R_26_PCREL }, - { BFD_RELOC_M32R_HI16_ULO, R_M32R_HI16_ULO }, - { BFD_RELOC_M32R_HI16_SLO, R_M32R_HI16_SLO }, - { BFD_RELOC_M32R_LO16, R_M32R_LO16 }, - { BFD_RELOC_M32R_SDA16, R_M32R_SDA16 }, - { BFD_RELOC_VTABLE_INHERIT, R_M32R_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_M32R_GNU_VTENTRY }, -}; -#else -static const struct m32r_reloc_map m32r_reloc_map[] = -{ - { BFD_RELOC_NONE, R_M32R_NONE }, - { BFD_RELOC_16, R_M32R_16_RELA }, - { BFD_RELOC_32, R_M32R_32_RELA }, - { BFD_RELOC_M32R_24, R_M32R_24_RELA }, - { BFD_RELOC_M32R_10_PCREL, R_M32R_10_PCREL_RELA }, - { BFD_RELOC_M32R_18_PCREL, R_M32R_18_PCREL_RELA }, - { BFD_RELOC_M32R_26_PCREL, R_M32R_26_PCREL_RELA }, - { BFD_RELOC_M32R_HI16_ULO, R_M32R_HI16_ULO_RELA }, - { BFD_RELOC_M32R_HI16_SLO, R_M32R_HI16_SLO_RELA }, - { BFD_RELOC_M32R_LO16, R_M32R_LO16_RELA }, - { BFD_RELOC_M32R_SDA16, R_M32R_SDA16_RELA }, - { BFD_RELOC_VTABLE_INHERIT, R_M32R_RELA_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_M32R_RELA_GNU_VTENTRY }, - { BFD_RELOC_32_PCREL, R_M32R_REL32 }, - - { BFD_RELOC_M32R_GOT24, R_M32R_GOT24 }, - { BFD_RELOC_M32R_26_PLTREL, R_M32R_26_PLTREL }, - { BFD_RELOC_M32R_COPY, R_M32R_COPY }, - { BFD_RELOC_M32R_GLOB_DAT, R_M32R_GLOB_DAT }, - { BFD_RELOC_M32R_JMP_SLOT, R_M32R_JMP_SLOT }, - { BFD_RELOC_M32R_RELATIVE, R_M32R_RELATIVE }, - { BFD_RELOC_M32R_GOTOFF, R_M32R_GOTOFF }, - { BFD_RELOC_M32R_GOTPC24, R_M32R_GOTPC24 }, - { BFD_RELOC_M32R_GOT16_HI_ULO, R_M32R_GOT16_HI_ULO }, - { BFD_RELOC_M32R_GOT16_HI_SLO, R_M32R_GOT16_HI_SLO }, - { BFD_RELOC_M32R_GOT16_LO, R_M32R_GOT16_LO }, - { BFD_RELOC_M32R_GOTPC_HI_ULO, R_M32R_GOTPC_HI_ULO }, - { BFD_RELOC_M32R_GOTPC_HI_SLO, R_M32R_GOTPC_HI_SLO }, - { BFD_RELOC_M32R_GOTPC_LO, R_M32R_GOTPC_LO }, - { BFD_RELOC_M32R_GOTOFF_HI_ULO, R_M32R_GOTOFF_HI_ULO }, - { BFD_RELOC_M32R_GOTOFF_HI_SLO, R_M32R_GOTOFF_HI_SLO }, - { BFD_RELOC_M32R_GOTOFF_LO, R_M32R_GOTOFF_LO }, -}; -#endif - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - -#ifdef USE_M32R_OLD_RELOC - for (i = 0; - i < sizeof (m32r_reloc_map_old) / sizeof (struct m32r_reloc_map); - i++) - if (m32r_reloc_map_old[i].bfd_reloc_val == code) - return &m32r_elf_howto_table[m32r_reloc_map_old[i].elf_reloc_val]; - -#else /* ! USE_M32R_OLD_RELOC */ - - for (i = 0; - i < sizeof (m32r_reloc_map) / sizeof (struct m32r_reloc_map); - i++) - if (m32r_reloc_map[i].bfd_reloc_val == code) - return &m32r_elf_howto_table[m32r_reloc_map[i].elf_reloc_val]; -#endif - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (m32r_elf_howto_table) / sizeof (m32r_elf_howto_table[0]); - i++) - if (m32r_elf_howto_table[i].name != NULL - && strcasecmp (m32r_elf_howto_table[i].name, r_name) == 0) - return &m32r_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an M32R ELF reloc. */ - -static void -m32r_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type > (unsigned int) R_M32R_GNU_VTENTRY) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid M32R reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &m32r_elf_howto_table[r_type]; -} - -static void -m32r_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - BFD_ASSERT ((ELF32_R_TYPE(dst->r_info) == (unsigned int) R_M32R_NONE) - || ((ELF32_R_TYPE(dst->r_info) > (unsigned int) R_M32R_GNU_VTENTRY) - && (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_M32R_max))); - cache_ptr->howto = &m32r_elf_howto_table[ELF32_R_TYPE(dst->r_info)]; -} - - -/* Given a BFD section, try to locate the corresponding ELF section - index. */ - -static bfd_boolean -_bfd_m32r_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) - { - *retval = SHN_M32R_SCOMMON; - return TRUE; - } - return FALSE; -} - -/* M32R ELF uses two common sections. One is the usual one, and the other - is for small objects. All the small objects are kept together, and then - referenced via one register, which yields faster assembler code. It is - up to the compiler to emit an instruction to load the register with - _SDA_BASE. This is what we use for the small common section. This - approach is copied from elf32-mips.c. */ -static asection m32r_elf_scom_section; -static asymbol m32r_elf_scom_symbol; -static asymbol *m32r_elf_scom_symbol_ptr; - -/* Handle the special M32R section numbers that a symbol may use. */ - -static void -_bfd_m32r_elf_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_M32R_SCOMMON: - if (m32r_elf_scom_section.name == NULL) - { - /* Initialize the small common section. */ - m32r_elf_scom_section.name = ".scommon"; - m32r_elf_scom_section.flags = SEC_IS_COMMON; - m32r_elf_scom_section.output_section = &m32r_elf_scom_section; - m32r_elf_scom_section.symbol = &m32r_elf_scom_symbol; - m32r_elf_scom_section.symbol_ptr_ptr = &m32r_elf_scom_symbol_ptr; - m32r_elf_scom_symbol.name = ".scommon"; - m32r_elf_scom_symbol.flags = BSF_SECTION_SYM; - m32r_elf_scom_symbol.section = &m32r_elf_scom_section; - m32r_elf_scom_symbol_ptr = &m32r_elf_scom_symbol; - } - asym->section = &m32r_elf_scom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - } -} - -/* Hook called by the linker routine which adds symbols from an object - file. We must handle the special M32R section numbers here. - We also keep watching for whether we need to create the sdata special - linker sections. */ - -static bfd_boolean -m32r_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (! bfd_link_relocatable (info) - && (*namep)[0] == '_' && (*namep)[1] == 'S' - && strcmp (*namep, "_SDA_BASE_") == 0 - && is_elf_hash_table (info->hash)) - { - /* This is simpler than using _bfd_elf_create_linker_section - (our needs are simpler than ppc's needs). Also - _bfd_elf_create_linker_section currently has a bug where if a .sdata - section already exists a new one is created that follows it which - screws of _SDA_BASE_ address calcs because output_offset != 0. */ - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - asection *s = bfd_get_section_by_name (abfd, ".sdata"); - - /* The following code was cobbled from elf32-ppc.c and elflink.c. */ - if (s == NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - - s = bfd_make_section_anyway_with_flags (abfd, ".sdata", - flags); - if (s == NULL) - return FALSE; - if (! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - } - - bh = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", - FALSE, FALSE, FALSE); - - if ((bh == NULL || bh->type == bfd_link_hash_undefined) - && !(_bfd_generic_link_add_one_symbol (info, - abfd, - "_SDA_BASE_", - BSF_GLOBAL, - s, - (bfd_vma) 32768, - NULL, - FALSE, - get_elf_backend_data (abfd)->collect, - &bh))) - return FALSE; - h = (struct elf_link_hash_entry *) bh; - h->type = STT_OBJECT; - } - - switch (sym->st_shndx) - { - case SHN_M32R_SCOMMON: - *secp = bfd_make_section_old_way (abfd, ".scommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - -/* We have to figure out the SDA_BASE value, so that we can adjust the - symbol value correctly. We look up the symbol _SDA_BASE_ in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static bfd_reloc_status_type -m32r_elf_final_sda_base (bfd *output_bfd, - struct bfd_link_info *info, - const char **error_message, - bfd_vma *psb) -{ - if (elf_gp (output_bfd) == 0) - { - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", FALSE, FALSE, TRUE); - if (h != NULL && h->type == bfd_link_hash_defined) - elf_gp (output_bfd) = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - else - { - /* Only get the error once. */ - *psb = elf_gp (output_bfd) = 4; - *error_message = - (const char *) _("SDA relocation when _SDA_BASE_ not defined"); - return bfd_reloc_dangerous; - } - } - *psb = elf_gp (output_bfd); - return bfd_reloc_ok; -} - -/* Return size of a PLT entry. */ -#define elf_m32r_sizeof_plt(info) PLT_ENTRY_SIZE - -/* The m32r linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that - it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we - have copied for a given symbol. */ - -struct elf_m32r_pcrel_relocs_copied -{ - /* Next section. */ - struct elf_m32r_pcrel_relocs_copied *next; - /* A section in dynobj. */ - asection *section; - /* Number of relocs copied in this section. */ - bfd_size_type count; -}; - -/* m32r ELF linker hash entry. */ - -struct elf_m32r_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; -}; - -/* m32r ELF linker hash table. */ - -struct elf_m32r_link_hash_table -{ - struct elf_link_hash_table root; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sdynbss; - asection *srelbss; - - /* Small local sym cache. */ - struct sym_cache sym_cache; -}; - -/* Traverse an m32r ELF linker hash table. */ - -#define m32r_elf_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* Get the m32r ELF linker hash table from a link_info structure. */ - -#define m32r_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == M32R_ELF_DATA ? ((struct elf_m32r_link_hash_table *) ((p)->hash)) : NULL) - -/* Create an entry in an m32r ELF linker hash table. */ - -static struct bfd_hash_entry * -m32r_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_m32r_link_hash_entry *ret = - (struct elf_m32r_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, - sizeof (struct elf_m32r_link_hash_entry)); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_m32r_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != NULL) - { - struct elf_m32r_link_hash_entry *eh; - - eh = (struct elf_m32r_link_hash_entry *) ret; - eh->dyn_relocs = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an m32r ELF linker hash table. */ - -static struct bfd_link_hash_table * -m32r_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_m32r_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_m32r_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - m32r_elf_link_hash_newfunc, - sizeof (struct elf_m32r_link_hash_entry), - M32R_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -m32r_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_m32r_link_hash_table *htab; - flagword flags, pltflags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - int ptralign = 2; /* 32bit */ - - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - pltflags = flags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - htab->root.splt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - - if (bed->want_plt_sym) - { - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - struct bfd_link_hash_entry *bh = NULL; - struct elf_link_hash_entry *h; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, - (bfd_vma) 0, NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - htab->root.hplt = h; - - if (bfd_link_pic (info) - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = bfd_make_section_anyway_with_flags (abfd, - bed->default_use_rela_p - ? ".rela.plt" : ".rel.plt", - flags | SEC_READONLY); - htab->root.srelplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (htab->root.sgot == NULL - && !_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_anyway_with_flags (abfd, ".dynbss", - SEC_ALLOC | SEC_LINKER_CREATED); - htab->sdynbss = s; - 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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - htab->srelbss = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -m32r_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_m32r_link_hash_entry * edir; - struct elf_m32r_link_hash_entry * eind; - - edir = (struct elf_m32r_link_hash_entry *) dir; - eind = (struct elf_m32r_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - struct elf_m32r_link_hash_entry *eh = (struct elf_m32r_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) - return p->sec; - } - return NULL; -} - -/* 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 -m32r_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_m32r_link_hash_table *htab; - bfd *dynobj; - asection *s; - -#ifdef DEBUG_PIC - printf ("m32r_elf_adjust_dynamic_symbol()\n"); -#endif - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (! bfd_link_pic (info) - && !h->def_dynamic - && !h->ref_dynamic - && h->root.type != bfd_link_hash_undefweak - && h->root.type != bfd_link_hash_undefined) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a PCREL - reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - return TRUE; - } - else - h->plt.offset = (bfd_vma) -1; - - /* If this is a weak symbol, and there is a real definition, the - processor independent code will have arranged for us to see the - real definition first, and we can just use the same value. */ - if (h->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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 (0 && info->nocopyreloc) - { - h->non_got_ref = 0; - return TRUE; - } - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (0 && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - s = htab->sdynbss; - BFD_ASSERT (s != NULL); - - /* We must generate a R_M32R_COPY reloc to tell the dynamic linker - to copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - srel = htab->srelbss; - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info; - struct elf_m32r_link_hash_table *htab; - struct elf_m32r_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - eh = (struct elf_m32r_link_hash_entry *) h; - - if (htab->root.dynamic_sections_created - && h->plt.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->root.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 (! bfd_link_pic (info) - && !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->root.sgotplt->size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - - /* 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->root.sgot; - - h->got.offset = s->size; - s->size += 4; - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (h->def_regular - && (h->forced_local - || info->symbolic)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) - { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -m32r_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_m32r_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - -#ifdef DEBUG_PIC - printf ("m32r_elf_size_dynamic_sections()\n"); -#endif - - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - p != NULL; - p = p->next) - { - if (! bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - s = htab->root.sgot; - srel = htab->root.srelgot; - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += 4; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); - } - else - *local_got = (bfd_vma) -1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->root.splt - || s == htab->root.sgot - || s == htab->root.sgotplt - || s == htab->sdynbss) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 && s != htab->root.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - else - /* It's not one of our sections, so don't allocate space. */ - continue; - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is mostly to handle .rela.bss and - .rela.plt. We must create both sections in - create_dynamic_sections, because they must be created - before the linker maps input sections to output - sections. The linker does that before - adjust_dynamic_symbol is called, and it is that - function which decides whether anything needs to go - into these sections. */ - s->flags |= SEC_EXCLUDE; - continue; - } - - if ((s->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. We use bfd_zalloc - here in case unused entries are not reclaimed before the - section's contents are written out. This should not happen, - but this way if it does, we get a R_M32R_NONE reloc instead - of garbage. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (htab->root.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in m32r_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (! add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->root.splt->size != 0) - { - if (! add_dynamic_entry (DT_PLTGOT, 0) - || ! add_dynamic_entry (DT_PLTRELSZ, 0) - || ! add_dynamic_entry (DT_PLTREL, DT_RELA) - || ! add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (! add_dynamic_entry (DT_RELA, 0) - || ! add_dynamic_entry (DT_RELASZ, 0) - || ! add_dynamic_entry (DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (! add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Relocate an M32R/D ELF section. - There is some attempt to make this function usable for many architectures, - both for RELA and REL type relocs, if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjust the section contents as - necessary, and (if using Rela relocs and generating a - relocatable output file) adjusting the reloc addend as - necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -m32r_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - Elf_Internal_Rela *rel, *relend; - /* Assume success. */ - bfd_boolean ret = TRUE; - struct elf_m32r_link_hash_table *htab = m32r_elf_hash_table (info); - bfd_vma *local_got_offsets; - asection *sgot, *splt, *sreloc; - bfd_vma high_address = bfd_get_section_limit (input_bfd, input_section); - - if (htab == NULL) - return FALSE; - - local_got_offsets = elf_local_got_offsets (input_bfd); - - sgot = htab->root.sgot; - splt = htab->root.splt; - sreloc = NULL; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - /* We can't modify r_addend here as elf_link_input_bfd has an assert to - ensure it's zero (we use REL relocs, not RELA). Therefore this - should be assigning zero to `addend', but for clarity we use - `r_addend'. */ - bfd_vma addend = rel->r_addend; - bfd_vma offset = rel->r_offset; - bfd_vma relocation; - Elf_Internal_Sym *sym; - asection *sec; - const char *sym_name; - bfd_reloc_status_type r; - const char *errmsg = NULL; - bfd_boolean use_rel = FALSE; - - h = NULL; - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= (int) R_M32R_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - } - - if ( r_type == R_M32R_GNU_VTENTRY - || r_type == R_M32R_GNU_VTINHERIT - || r_type == R_M32R_NONE - || r_type == R_M32R_RELA_GNU_VTENTRY - || r_type == R_M32R_RELA_GNU_VTINHERIT) - continue; - - if (r_type <= R_M32R_GNU_VTENTRY) - use_rel = TRUE; - - howto = m32r_elf_howto_table + r_type; - r_symndx = ELF32_R_SYM (rel->r_info); - - sym = NULL; - sec = NULL; - h = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - sym_name = ""; - - if (!use_rel) - { - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - addend = rel->r_addend; - } - else - { - relocation = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - } - } - else - { - /* External symbol. */ - relocation = 0; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - h = ((struct elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &h->root)); - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - sym_name = h->root.root.string; - - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - bfd_boolean dyn; - sec = h->root.u.def.section; - - dyn = htab->root.dynamic_sections_created; - sec = h->root.u.def.section; - if (r_type == R_M32R_GOTPC24 - || (r_type == R_M32R_GOTPC_HI_ULO - || r_type == R_M32R_GOTPC_HI_SLO - || r_type == R_M32R_GOTPC_LO) - || (r_type == R_M32R_26_PLTREL - && h->plt.offset != (bfd_vma) -1) - || ((r_type == R_M32R_GOT24 - || r_type == R_M32R_GOT16_HI_ULO - || r_type == R_M32R_GOT16_HI_SLO - || r_type == R_M32R_GOT16_LO) - && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (! bfd_link_pic (info) - || (! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - || (bfd_link_pic (info) - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular) - && (((r_type == R_M32R_16_RELA - || r_type == R_M32R_32_RELA - || r_type == R_M32R_24_RELA - || r_type == R_M32R_HI16_ULO_RELA - || r_type == R_M32R_HI16_SLO_RELA - || r_type == R_M32R_LO16_RELA) - && !h->forced_local) - || r_type == R_M32R_REL32 - || r_type == R_M32R_10_PCREL_RELA - || r_type == R_M32R_18_PCREL_RELA - || r_type == R_M32R_26_PCREL_RELA) - && ((input_section->flags & SEC_ALLOC) != 0 - /* DWARF will emit R_M32R_16(24,32) relocations - in its sections against symbols defined - externally in shared libraries. We can't do - anything with them here. */ - || ((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic)))) - { - /* In these cases, we don't need the relocation - value. We check specially because in some - obscure cases sec->output_section will be NULL. */ - } - else if (sec->output_section != NULL) - relocation = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - else if (!bfd_link_relocatable (info) - && (_bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset) - != (bfd_vma) -1)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation " - "against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - } - } - 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 if (!bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, offset, - (info->unresolved_syms_in_objects == RM_GENERATE_ERROR - || ELF_ST_VISIBILITY (h->other))); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info) && !use_rel) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - continue; - } - - if (bfd_link_relocatable (info) && use_rel) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym == NULL || ELF_ST_TYPE (sym->st_info) != STT_SECTION) - continue; - - addend += sec->output_offset; - - /* If partial_inplace, we need to store any additional addend - back in the section. */ - if (! howto->partial_inplace) - continue; - /* ??? Here is a nice place to call a special_function - like handler. */ - if (r_type != R_M32R_HI16_SLO && r_type != R_M32R_HI16_ULO) - r = _bfd_relocate_contents (howto, input_bfd, - addend, contents + offset); - else - { - Elf_Internal_Rela *lorel; - - /* We allow an arbitrary number of HI16 relocs before the - LO16 reloc. This permits gcc to emit the HI and LO relocs - itself. */ - for (lorel = rel + 1; - (lorel < relend - && (ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_SLO - || ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_ULO)); - lorel++) - continue; - if (lorel < relend - && ELF32_R_TYPE (lorel->r_info) == R_M32R_LO16) - { - m32r_elf_relocate_hi16 (input_bfd, r_type, rel, lorel, - contents, addend); - r = bfd_reloc_ok; - } - else - r = _bfd_relocate_contents (howto, input_bfd, - addend, contents + offset); - } - } - else - { - /* Sanity check the address. */ - if (offset > high_address) - { - r = bfd_reloc_outofrange; - goto check_reloc; - } - - switch ((int) r_type) - { - case R_M32R_GOTOFF: - /* Relocation is relative to the start of the global offset - table (for ld24 rx, #uimm24). eg access at label+addend - - ld24 rx. #label@GOTOFF + addend - sub rx, r12. */ - - BFD_ASSERT (sgot != NULL); - - relocation = -(relocation - sgot->output_section->vma); - rel->r_addend = -rel->r_addend; - break; - - case R_M32R_GOTOFF_HI_ULO: - case R_M32R_GOTOFF_HI_SLO: - case R_M32R_GOTOFF_LO: - BFD_ASSERT (sgot != NULL); - - relocation -= sgot->output_section->vma; - - if ((r_type == R_M32R_GOTOFF_HI_SLO) - && ((relocation + rel->r_addend) & 0x8000)) - rel->r_addend += 0x10000; - break; - - case R_M32R_GOTPC24: - /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation - ld24 rx,#_GLOBAL_OFFSET_TABLE_ - */ - relocation = sgot->output_section->vma; - break; - - case R_M32R_GOTPC_HI_ULO: - case R_M32R_GOTPC_HI_SLO: - case R_M32R_GOTPC_LO: - { - /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation - bl .+4 - seth rx,#high(_GLOBAL_OFFSET_TABLE_) - or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) - or - bl .+4 - seth rx,#shigh(_GLOBAL_OFFSET_TABLE_) - add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) - */ - relocation = sgot->output_section->vma; - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - if ((r_type == R_M32R_GOTPC_HI_SLO) - && ((relocation + rel->r_addend) & 0x8000)) - rel->r_addend += 0x10000; - - break; - } - case R_M32R_GOT16_HI_ULO: - case R_M32R_GOT16_HI_SLO: - case R_M32R_GOT16_LO: - /* Fall through. */ - case R_M32R_GOT24: - /* Relocation is to the entry for this symbol in the global - offset table. */ - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - bfd_boolean dyn; - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - dyn = htab->root.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; - } - } - - relocation = sgot->output_offset + off; - } - else - { - bfd_vma off; - bfd_byte *loc; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_M32R_RELATIVE reloc - for the dynamic linker. */ - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_M32R_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc); - ++srelgot->reloc_count; - } - - local_got_offsets[r_symndx] |= 1; - } - - relocation = sgot->output_offset + off; - } - if ((r_type == R_M32R_GOT16_HI_SLO) - && ((relocation + rel->r_addend) & 0x8000)) - rel->r_addend += 0x10000; - - break; - - case R_M32R_26_PLTREL: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* The native assembler will generate a 26_PLTREL reloc - for a local symbol if you assemble a call from one - section to another when using -K pic. */ - if (h == NULL) - break; - - if (h->forced_local) - break; - - if (h->plt.offset == (bfd_vma) -1) - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - - relocation = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - break; - - case R_M32R_HI16_SLO_RELA: - if ((relocation + rel->r_addend) & 0x8000) - rel->r_addend += 0x10000; - /* Fall through. */ - - case R_M32R_16_RELA: - case R_M32R_24_RELA: - case R_M32R_32_RELA: - case R_M32R_REL32: - case R_M32R_10_PCREL_RELA: - case R_M32R_18_PCREL_RELA: - case R_M32R_26_PCREL_RELA: - case R_M32R_HI16_ULO_RELA: - case R_M32R_LO16_RELA: - if (bfd_link_pic (info) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0 - && (( r_type != R_M32R_10_PCREL_RELA - && r_type != R_M32R_18_PCREL_RELA - && r_type != R_M32R_26_PCREL_RELA - && r_type != R_M32R_REL32) - || (h != NULL - && h->dynindx != -1 - && (! info->symbolic - || !h->def_regular)))) - { - Elf_Internal_Rela outrel; - bfd_boolean skip, relocate; - bfd_byte *loc; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - 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 = relocate = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if ( r_type == R_M32R_10_PCREL_RELA - || r_type == R_M32R_18_PCREL_RELA - || r_type == R_M32R_26_PCREL_RELA - || r_type == R_M32R_REL32) - { - BFD_ASSERT (h != NULL && h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (h == NULL - || ((info->symbolic || h->dynindx == -1) - && h->def_regular)) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_M32R_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = relocation + rel->r_addend; - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc); - ++sreloc->reloc_count; - - /* If this reloc is against an external symbol, we do - not want to fiddle with the addend. Otherwise, we - need to include the symbol value so that it becomes - an addend for the dynamic reloc. */ - if (! relocate) - continue; - break; - } - else if (r_type != R_M32R_10_PCREL_RELA) - break; - /* Fall through. */ - - case (int) R_M32R_10_PCREL : - r = m32r_elf_do_10_pcrel_reloc (input_bfd, howto, input_section, - contents, offset, - sec, relocation, addend); - goto check_reloc; - - case (int) R_M32R_HI16_SLO : - case (int) R_M32R_HI16_ULO : - { - Elf_Internal_Rela *lorel; - - /* We allow an arbitrary number of HI16 relocs before the - LO16 reloc. This permits gcc to emit the HI and LO relocs - itself. */ - for (lorel = rel + 1; - (lorel < relend - && (ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_SLO - || ELF32_R_TYPE (lorel->r_info) == R_M32R_HI16_ULO)); - lorel++) - continue; - if (lorel < relend - && ELF32_R_TYPE (lorel->r_info) == R_M32R_LO16) - { - m32r_elf_relocate_hi16 (input_bfd, r_type, rel, lorel, - contents, relocation + addend); - r = bfd_reloc_ok; - } - else - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, offset, - relocation, addend); - } - - goto check_reloc; - - case (int) R_M32R_SDA16_RELA: - case (int) R_M32R_SDA16 : - { - const char *name; - - BFD_ASSERT (sec != NULL); - name = bfd_get_section_name (sec->owner, sec); - - if ( strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0 - || strcmp (name, ".scommon") == 0) - { - bfd_vma sda_base; - bfd *out_bfd = sec->output_section->owner; - - r = m32r_elf_final_sda_base (out_bfd, info, - &errmsg, - &sda_base); - if (r != bfd_reloc_ok) - { - ret = FALSE; - goto check_reloc; - } - - /* At this point `relocation' contains the object's - address. */ - relocation -= sda_base; - /* Now it contains the offset from _SDA_BASE_. */ - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: The target (%s) of an %s relocation is in the wrong section (%A)"), - input_bfd, - sym_name, - m32r_elf_howto_table[(int) r_type].name, - sec); - /*bfd_set_error (bfd_error_bad_value); ??? why? */ - ret = FALSE; - continue; - } - } - /* Fall through. */ - - default : /* OLD_M32R_RELOC */ - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, offset, - relocation, addend); - goto check_reloc; - } - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - } - - check_reloc: - - if (r != bfd_reloc_ok) - { - /* FIXME: This should be generic enough to go in a utility. */ - const char *name; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - if (errmsg != NULL) - goto common_error; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, offset, TRUE); - break; - - case bfd_reloc_outofrange: - errmsg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - errmsg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - errmsg = _("internal error: dangerous error"); - goto common_error; - - default: - errmsg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, errmsg, name, input_bfd, - input_section, offset); - break; - } - } - } - - return ret; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -m32r_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_m32r_link_hash_table *htab; - bfd_byte *loc; - -#ifdef DEBUG_PIC - printf ("m32r_elf_finish_dynamic_symbol()\n"); -#endif - - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgot; - asection *srela; - - bfd_vma plt_index; - bfd_vma got_offset; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srela = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; - - /* Get the offset into the .got table of the entry that - corresponds to this function. Each .got entry is 4 bytes. - The first three are reserved. */ - got_offset = (plt_index + 3) * 4; - - /* Fill in the entry in the procedure linkage table. */ - if (! bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, - (PLT_ENTRY_WORD0b - + (((sgot->output_section->vma - + sgot->output_offset - + got_offset) >> 16) & 0xffff)), - splt->contents + h->plt.offset); - bfd_put_32 (output_bfd, - (PLT_ENTRY_WORD1b - + ((sgot->output_section->vma - + sgot->output_offset - + got_offset) & 0xffff)), - splt->contents + h->plt.offset + 4); - bfd_put_32 (output_bfd, PLT_ENTRY_WORD2, - splt->contents + h->plt.offset + 8); - bfd_put_32 (output_bfd, - (PLT_ENTRY_WORD3 - + plt_index * sizeof (Elf32_External_Rela)), - splt->contents + h->plt.offset + 12); - bfd_put_32 (output_bfd, - (PLT_ENTRY_WORD4 - + (((unsigned int) ((- (h->plt.offset + 16)) >> 2)) & 0xffffff)), - splt->contents + h->plt.offset + 16); - } - else - { - bfd_put_32 (output_bfd, - PLT_ENTRY_WORD0 + got_offset, - splt->contents + h->plt.offset); - bfd_put_32 (output_bfd, PLT_ENTRY_WORD1, - splt->contents + h->plt.offset + 4); - bfd_put_32 (output_bfd, PLT_ENTRY_WORD2, - splt->contents + h->plt.offset + 8); - bfd_put_32 (output_bfd, - (PLT_ENTRY_WORD3 - + plt_index * sizeof (Elf32_External_Rela)), - splt->contents + h->plt.offset + 12); - bfd_put_32 (output_bfd, - (PLT_ENTRY_WORD4 - + (((unsigned int) ((- (h->plt.offset + 16)) >> 2)) & 0xffffff)), - splt->contents + h->plt.offset + 16); - } - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + 12), /* same offset */ - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_M32R_JMP_SLOT); - rela.r_addend = 0; - loc = srela->contents; - loc += plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (h->got.offset != (bfd_vma) -1) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset &~ 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular) - { - rela.r_info = ELF32_R_INFO (0, R_M32R_RELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - BFD_ASSERT ((h->got.offset & 1) == 0); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_M32R_GLOB_DAT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++srela->reloc_count; - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - - /* This symbols needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (htab->root.dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_M32R_COPY); - rela.r_addend = 0; - loc = s->contents; - loc += s->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++s->reloc_count; - } - - /* Mark some specially defined symbols as absolute. */ - if (h == htab->root.hdynamic || h == htab->root.hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - - -/* Finish up the dynamic sections. */ - -static bfd_boolean -m32r_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_m32r_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - asection *sgot; - -#ifdef DEBUG_PIC - printf ("m32r_elf_finish_dynamic_sections()\n"); -#endif - - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - sgot = htab->root.sgotplt; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sgot != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = htab->root.sgotplt; - goto get_vma; - case DT_JMPREL: - s = htab->root.srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; - if (splt && splt->size > 0) - { - if (bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD0, splt->contents); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD1, splt->contents + 4); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD2, splt->contents + 8); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD3, splt->contents + 12); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD4, splt->contents + 16); - } - else - { - unsigned long addr; - /* addr = .got + 4 */ - addr = sgot->output_section->vma + sgot->output_offset + 4; - bfd_put_32 (output_bfd, - PLT0_ENTRY_WORD0 | ((addr >> 16) & 0xffff), - splt->contents); - bfd_put_32 (output_bfd, - PLT0_ENTRY_WORD1 | (addr & 0xffff), - splt->contents + 4); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD2, splt->contents + 8); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD3, splt->contents + 12); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD4, splt->contents + 16); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot && sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - return TRUE; -} - - -/* Set the right machine number. */ - -static bfd_boolean -m32r_elf_object_p (bfd *abfd) -{ - switch (elf_elfheader (abfd)->e_flags & EF_M32R_ARCH) - { - default: - case E_M32R_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_m32r, bfd_mach_m32r); break; - case E_M32RX_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_m32r, bfd_mach_m32rx); break; - case E_M32R2_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_m32r, bfd_mach_m32r2); break; - } - return TRUE; -} - -/* Store the machine number in the flags field. */ - -static void -m32r_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_m32r: val = E_M32R_ARCH; break; - case bfd_mach_m32rx: val = E_M32RX_ARCH; break; - case bfd_mach_m32r2: val = E_M32R2_ARCH; break; - } - - elf_elfheader (abfd)->e_flags &=~ EF_M32R_ARCH; - elf_elfheader (abfd)->e_flags |= val; -} - -/* Function to keep M32R specific file flags. */ - -static bfd_boolean -m32r_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -m32r_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - /* If the input is the default architecture then do not - bother setting the flags for the output architecture, - instead allow future merges to do this. If no future - merges ever set these flags then they will retain their - unitialised values, which surprise surprise, correspond - to the default values. */ - if (bfd_get_arch_info (ibfd)->the_default) - return TRUE; - - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd)); - - return TRUE; - } - - /* Check flag compatibility. */ - if (in_flags == out_flags) - return TRUE; - - if ((in_flags & EF_M32R_ARCH) != (out_flags & EF_M32R_ARCH)) - { - if ( ((in_flags & EF_M32R_ARCH) != E_M32R_ARCH) - || ((out_flags & EF_M32R_ARCH) == E_M32R_ARCH) - || ((in_flags & EF_M32R_ARCH) == E_M32R2_ARCH)) - { - _bfd_error_handler - (_("%B: Instruction set mismatch with previous modules"), ibfd); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - return TRUE; -} - -/* Display the flags field. */ - -static bfd_boolean -m32r_elf_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - _bfd_elf_print_private_bfd_data (abfd, ptr); - - fprintf (file, _("private flags = %lx"), elf_elfheader (abfd)->e_flags); - - switch (elf_elfheader (abfd)->e_flags & EF_M32R_ARCH) - { - default: - case E_M32R_ARCH: fprintf (file, _(": m32r instructions")); break; - case E_M32RX_ARCH: fprintf (file, _(": m32rx instructions")); break; - case E_M32R2_ARCH: fprintf (file, _(": m32r2 instructions")); break; - } - - fputc ('\n', file); - - return TRUE; -} - -static asection * -m32r_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_M32R_GNU_VTINHERIT: - case R_M32R_GNU_VTENTRY: - case R_M32R_RELA_GNU_VTINHERIT: - case R_M32R_RELA_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -m32r_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - struct elf_m32r_link_hash_table *htab; - bfd *dynobj; - asection *sreloc; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - sreloc = NULL; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - htab = m32r_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - int r_type; - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - /* Some relocs require a global offset table. */ - if (htab->root.sgot == NULL) - { - switch (r_type) - { - case R_M32R_GOT16_HI_ULO: - case R_M32R_GOT16_HI_SLO: - case R_M32R_GOTOFF: - case R_M32R_GOTOFF_HI_ULO: - case R_M32R_GOTOFF_HI_SLO: - case R_M32R_GOTOFF_LO: - case R_M32R_GOT16_LO: - case R_M32R_GOTPC24: - case R_M32R_GOTPC_HI_ULO: - case R_M32R_GOTPC_HI_SLO: - case R_M32R_GOTPC_LO: - case R_M32R_GOT24: - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - break; - - default: - break; - } - } - - switch (r_type) - { - case R_M32R_GOT16_HI_ULO: - case R_M32R_GOT16_HI_SLO: - case R_M32R_GOT16_LO: - case R_M32R_GOT24: - - if (h != NULL) - h->got.refcount += 1; - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local - symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - local_got_refcounts[r_symndx] += 1; - } - break; - - case R_M32R_26_PLTREL: - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - if (h == NULL) - continue; - - if (h->forced_local) - break; - - h->needs_plt = 1; - h->plt.refcount += 1; - break; - - case R_M32R_16_RELA: - case R_M32R_24_RELA: - case R_M32R_32_RELA: - case R_M32R_REL32: - case R_M32R_HI16_ULO_RELA: - case R_M32R_HI16_SLO_RELA: - case R_M32R_LO16_RELA: - case R_M32R_SDA16_RELA: - case R_M32R_10_PCREL_RELA: - case R_M32R_18_PCREL_RELA: - case R_M32R_26_PCREL_RELA: - - if (h != NULL && !bfd_link_pic (info)) - { - h->non_got_ref = 1; - h->plt.refcount += 1; - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). We account for that - possibility below by storing information in the - dyn_relocs field of the hash table entry. A similar - situation occurs when creating shared libraries and symbol - visibility changes render the symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (( r_type != R_M32R_26_PCREL_RELA - && r_type != R_M32R_18_PCREL_RELA - && r_type != R_M32R_10_PCREL_RELA - && r_type != R_M32R_REL32) - || (h != NULL - && (! info->symbolic - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (!bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - - /* When creating a shared object, we must copy these - relocs into the output file. We create a reloc - section in dynobj and make room for the reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf_m32r_link_hash_entry *) h)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. */ - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof (*p); - - p = bfd_alloc (dynobj, amt); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - if ( ELF32_R_TYPE (rel->r_info) == R_M32R_26_PCREL_RELA - || ELF32_R_TYPE (rel->r_info) == R_M32R_18_PCREL_RELA - || ELF32_R_TYPE (rel->r_info) == R_M32R_10_PCREL_RELA - || ELF32_R_TYPE (rel->r_info) == R_M32R_REL32) - p->pc_count += 1; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_M32R_RELA_GNU_VTINHERIT: - case R_M32R_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_M32R_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - case R_M32R_RELA_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -static const struct bfd_elf_special_section m32r_elf_special_sections[] = -{ - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } -}; - -static enum elf_reloc_type_class -m32r_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_M32R_RELATIVE: return reloc_class_relative; - case R_M32R_JMP_SLOT: return reloc_class_plt; - case R_M32R_COPY: return reloc_class_copy; - default: return reloc_class_normal; - } -} - -#define ELF_ARCH bfd_arch_m32r -#define ELF_TARGET_ID M32R_ELF_DATA -#define ELF_MACHINE_CODE EM_M32R -#define ELF_MACHINE_ALT1 EM_CYGNUS_M32R -#define ELF_MAXPAGESIZE 0x1 /* Explicitly requested by Mitsubishi. */ - -#define TARGET_BIG_SYM m32r_elf32_vec -#define TARGET_BIG_NAME "elf32-m32r" -#define TARGET_LITTLE_SYM m32r_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-m32rle" - -#define elf_info_to_howto m32r_info_to_howto -#define elf_info_to_howto_rel m32r_info_to_howto_rel -#define elf_backend_section_from_bfd_section _bfd_m32r_elf_section_from_bfd_section -#define elf_backend_symbol_processing _bfd_m32r_elf_symbol_processing -#define elf_backend_add_symbol_hook m32r_elf_add_symbol_hook -#define elf_backend_relocate_section m32r_elf_relocate_section -#define elf_backend_gc_mark_hook m32r_elf_gc_mark_hook -#define elf_backend_check_relocs m32r_elf_check_relocs - -#define elf_backend_create_dynamic_sections m32r_elf_create_dynamic_sections -#define bfd_elf32_bfd_link_hash_table_create m32r_elf_link_hash_table_create -#define elf_backend_size_dynamic_sections m32r_elf_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_finish_dynamic_sections m32r_elf_finish_dynamic_sections -#define elf_backend_adjust_dynamic_symbol m32r_elf_adjust_dynamic_symbol -#define elf_backend_finish_dynamic_symbol m32r_elf_finish_dynamic_symbol -#define elf_backend_reloc_type_class m32r_elf_reloc_type_class -#define elf_backend_copy_indirect_symbol m32r_elf_copy_indirect_symbol - -#define elf_backend_can_gc_sections 1 -/*#if !USE_REL -#define elf_backend_rela_normal 1 -#endif*/ -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_may_use_rel_p 1 -#ifdef USE_M32R_OLD_RELOC -#define elf_backend_default_use_rela_p 0 -#define elf_backend_may_use_rela_p 0 -#else -#define elf_backend_default_use_rela_p 1 -#define elf_backend_may_use_rela_p 1 -#endif - -#define elf_backend_object_p m32r_elf_object_p -#define elf_backend_final_write_processing m32r_elf_final_write_processing -#define bfd_elf32_bfd_merge_private_bfd_data m32r_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags m32r_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data m32r_elf_print_private_bfd_data -#define elf_backend_special_sections m32r_elf_special_sections - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" - -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x1000 - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM m32r_elf32_linux_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-m32r-linux" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM m32r_elf32_linux_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-m32rle-linux" -#undef elf32_bed -#define elf32_bed elf32_m32r_lin_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-m68hc11.c b/sdcc/support/sdbinutils/bfd/elf32-m68hc11.c deleted file mode 100644 index 0283e93ec..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m68hc11.c +++ /dev/null @@ -1,1319 +0,0 @@ -/* Motorola 68HC11-specific support for 32-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - (Heavily copied from the D10V port by Martin Hunt (hunt@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf32-m68hc1x.h" -#include "elf/m68hc11.h" -#include "opcode/m68hc11.h" - -/* Relocation functions. */ -static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static void m68hc11_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); - -/* Trampoline generation. */ -static bfd_boolean m68hc11_elf_size_one_stub - (struct bfd_hash_entry *gen_entry, void *in_arg); -static bfd_boolean m68hc11_elf_build_one_stub - (struct bfd_hash_entry *gen_entry, void *in_arg); -static struct bfd_link_hash_table* m68hc11_elf_bfd_link_hash_table_create - (bfd* abfd); - -/* Linker relaxation. */ -static bfd_boolean m68hc11_elf_relax_section - (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); -static void m68hc11_elf_relax_delete_bytes - (bfd *, asection *, bfd_vma, int); -static void m68hc11_relax_group - (bfd *, asection *, bfd_byte *, unsigned, unsigned long, unsigned long); -static int compare_reloc (const void *, const void *); - -/* Use REL instead of RELA to save space */ -#define USE_REL 1 - -/* The Motorola 68HC11 microcontroller only addresses 64Kb but we also - support a memory bank switching mechanism similar to 68HC12. - We must handle 8 and 16-bit relocations. The 32-bit relocation - are used for debugging sections (DWARF2) to represent a virtual - address. - The 3-bit and 16-bit PC rel relocation is only used by 68HC12. */ -static reloc_howto_type elf_m68hc11_howto_table[] = { - /* This reloc does nothing. */ - HOWTO (R_M68HC11_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation */ - HOWTO (R_M68HC11_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (upper address) */ - HOWTO (R_M68HC11_HI8, /* type */ - 8, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_HI8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (upper address) */ - HOWTO (R_M68HC11_LO8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_LO8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit PC-rel relocation */ - HOWTO (R_M68HC11_PCREL_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_PCREL_8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation */ - HOWTO (R_M68HC11_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont /*bitfield */ , /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. This one is never used for the - code relocation. It's used by gas for -gstabs generation. */ - HOWTO (R_M68HC11_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 3 bit absolute relocation */ - HOWTO (R_M68HC11_3B, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 3, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_4B", /* name */ - FALSE, /* partial_inplace */ - 0x003, /* src_mask */ - 0x003, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit PC-rel relocation */ - HOWTO (R_M68HC11_PCREL_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_PCREL_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_M68HC11_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_M68HC11_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_M68HC11_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 1, /* 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_M68HC11_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 24 bit relocation */ - HOWTO (R_M68HC11_24, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_24", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16-bit low relocation */ - HOWTO (R_M68HC11_LO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_LO16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A page relocation */ - HOWTO (R_M68HC11_PAGE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC11_PAGE", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - EMPTY_HOWTO (16), - EMPTY_HOWTO (17), - EMPTY_HOWTO (18), - EMPTY_HOWTO (19), - - /* Mark beginning of a jump instruction (any form). */ - HOWTO (R_M68HC11_RL_JUMP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_ignore_reloc, /* special_function */ - "R_M68HC11_RL_JUMP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Mark beginning of Gcc relaxation group instruction. */ - HOWTO (R_M68HC11_RL_GROUP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_ignore_reloc, /* special_function */ - "R_M68HC11_RL_GROUP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* Map BFD reloc types to M68HC11 ELF reloc types. */ - -struct m68hc11_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct m68hc11_reloc_map m68hc11_reloc_map[] = { - {BFD_RELOC_NONE, R_M68HC11_NONE,}, - {BFD_RELOC_8, R_M68HC11_8}, - {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8}, - {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8}, - {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8}, - {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16}, - {BFD_RELOC_16, R_M68HC11_16}, - {BFD_RELOC_32, R_M68HC11_32}, - {BFD_RELOC_M68HC11_3B, R_M68HC11_3B}, - - {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY}, - - {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16}, - {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE}, - {BFD_RELOC_M68HC11_24, R_M68HC11_24}, - - {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP}, - {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP}, -}; - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map); - i++) - { - if (m68hc11_reloc_map[i].bfd_reloc_val == code) - return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf_m68hc11_howto_table) - / sizeof (elf_m68hc11_howto_table[0])); - i++) - if (elf_m68hc11_howto_table[i].name != NULL - && strcasecmp (elf_m68hc11_howto_table[i].name, r_name) == 0) - return &elf_m68hc11_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an M68HC11 ELF reloc. */ - -static void -m68hc11_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_M68HC11_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid M68HC11 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_m68hc11_howto_table[r_type]; -} - - -/* Far trampoline generation. */ - -/* Build a 68HC11 trampoline stub. */ -static bfd_boolean -m68hc11_elf_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) -{ - struct elf32_m68hc11_stub_hash_entry *stub_entry; - struct bfd_link_info *info; - struct m68hc11_elf_link_hash_table *htab; - asection *stub_sec; - bfd *stub_bfd; - bfd_byte *loc; - bfd_vma sym_value, phys_page, phys_addr; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry; - info = (struct bfd_link_info *) in_arg; - - htab = m68hc11_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - stub_sec = stub_entry->stub_sec; - - /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset = stub_sec->size; - stub_sec->size += 10; - loc = stub_sec->contents + stub_entry->stub_offset; - - stub_bfd = stub_sec->owner; - - /* Create the trampoline call stub: - - pshb - ldab #%page(symbol) - ldy #%addr(symbol) - jmp __trampoline - - */ - sym_value = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value); - phys_page = m68hc11_phys_page (&htab->pinfo, sym_value); - - /* pshb; ldab #%page(sym) */ - bfd_put_8 (stub_bfd, 0x37, loc); - bfd_put_8 (stub_bfd, 0xC6, loc + 1); - bfd_put_8 (stub_bfd, phys_page, loc + 2); - loc += 3; - - /* ldy #%addr(sym) */ - bfd_put_8 (stub_bfd, 0x18, loc); - bfd_put_8 (stub_bfd, 0xCE, loc + 1); - bfd_put_16 (stub_bfd, phys_addr, loc + 2); - loc += 4; - - /* jmp __trampoline */ - bfd_put_8 (stub_bfd, 0x7E, loc); - bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1); - - return TRUE; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ - -static bfd_boolean -m68hc11_elf_size_one_stub (struct bfd_hash_entry *gen_entry, - void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_m68hc11_stub_hash_entry *stub_entry; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry; - - stub_entry->stub_sec->size += 10; - return TRUE; -} - -/* Create a 68HC11 ELF linker hash table. */ - -static struct bfd_link_hash_table * -m68hc11_elf_bfd_link_hash_table_create (bfd *abfd) -{ - struct m68hc11_elf_link_hash_table *ret; - - ret = m68hc11_elf_hash_table_create (abfd); - if (ret == (struct m68hc11_elf_link_hash_table *) NULL) - return NULL; - - ret->size_one_stub = m68hc11_elf_size_one_stub; - ret->build_one_stub = m68hc11_elf_build_one_stub; - - return &ret->root.root; -} - - -/* 68HC11 Linker Relaxation. */ - -struct m68hc11_direct_relax -{ - const char *name; - unsigned char code; - unsigned char direct_code; -} m68hc11_direct_relax_table[] = { - { "adca", 0xB9, 0x99 }, - { "adcb", 0xF9, 0xD9 }, - { "adda", 0xBB, 0x9B }, - { "addb", 0xFB, 0xDB }, - { "addd", 0xF3, 0xD3 }, - { "anda", 0xB4, 0x94 }, - { "andb", 0xF4, 0xD4 }, - { "cmpa", 0xB1, 0x91 }, - { "cmpb", 0xF1, 0xD1 }, - { "cpd", 0xB3, 0x93 }, - { "cpxy", 0xBC, 0x9C }, -/* { "cpy", 0xBC, 0x9C }, */ - { "eora", 0xB8, 0x98 }, - { "eorb", 0xF8, 0xD8 }, - { "jsr", 0xBD, 0x9D }, - { "ldaa", 0xB6, 0x96 }, - { "ldab", 0xF6, 0xD6 }, - { "ldd", 0xFC, 0xDC }, - { "lds", 0xBE, 0x9E }, - { "ldxy", 0xFE, 0xDE }, - /* { "ldy", 0xFE, 0xDE },*/ - { "oraa", 0xBA, 0x9A }, - { "orab", 0xFA, 0xDA }, - { "sbca", 0xB2, 0x92 }, - { "sbcb", 0xF2, 0xD2 }, - { "staa", 0xB7, 0x97 }, - { "stab", 0xF7, 0xD7 }, - { "std", 0xFD, 0xDD }, - { "sts", 0xBF, 0x9F }, - { "stxy", 0xFF, 0xDF }, - /* { "sty", 0xFF, 0xDF },*/ - { "suba", 0xB0, 0x90 }, - { "subb", 0xF0, 0xD0 }, - { "subd", 0xB3, 0x93 }, - { 0, 0, 0 } -}; - -static struct m68hc11_direct_relax * -find_relaxable_insn (unsigned char code) -{ - int i; - - for (i = 0; m68hc11_direct_relax_table[i].name; i++) - if (m68hc11_direct_relax_table[i].code == code) - return &m68hc11_direct_relax_table[i]; - - return 0; -} - -static int -compare_reloc (const void *e1, const void *e2) -{ - const Elf_Internal_Rela *i1 = (const Elf_Internal_Rela *) e1; - const Elf_Internal_Rela *i2 = (const Elf_Internal_Rela *) e2; - - if (i1->r_offset == i2->r_offset) - return 0; - else - return i1->r_offset < i2->r_offset ? -1 : 1; -} - -#define M6811_OP_LDX_IMMEDIATE (0xCE) - -static void -m68hc11_relax_group (bfd *abfd, asection *sec, bfd_byte *contents, - unsigned value, unsigned long offset, - unsigned long end_group) -{ - unsigned char code; - unsigned long start_offset; - unsigned long ldx_offset = offset; - unsigned long ldx_size; - int can_delete_ldx; - int relax_ldy = 0; - - /* First instruction of the relax group must be a - LDX #value or LDY #value. If this is not the case, - ignore the relax group. */ - code = bfd_get_8 (abfd, contents + offset); - if (code == 0x18) - { - relax_ldy++; - offset++; - code = bfd_get_8 (abfd, contents + offset); - } - ldx_size = offset - ldx_offset + 3; - offset += 3; - if (code != M6811_OP_LDX_IMMEDIATE || offset >= end_group) - return; - - - /* We can remove the LDX/LDY only when all bset/brclr instructions - of the relax group have been converted to use direct addressing - mode. */ - can_delete_ldx = 1; - while (offset < end_group) - { - unsigned isize; - unsigned new_value; - int bset_use_y; - - bset_use_y = 0; - start_offset = offset; - code = bfd_get_8 (abfd, contents + offset); - if (code == 0x18) - { - bset_use_y++; - offset++; - code = bfd_get_8 (abfd, contents + offset); - } - - /* Check the instruction and translate to use direct addressing mode. */ - switch (code) - { - /* bset */ - case 0x1C: - code = 0x14; - isize = 3; - break; - - /* brclr */ - case 0x1F: - code = 0x13; - isize = 4; - break; - - /* brset */ - case 0x1E: - code = 0x12; - isize = 4; - break; - - /* bclr */ - case 0x1D: - code = 0x15; - isize = 3; - break; - - /* This instruction is not recognized and we are not - at end of the relax group. Ignore and don't remove - the first LDX (we don't know what it is used for...). */ - default: - return; - } - new_value = (unsigned) bfd_get_8 (abfd, contents + offset + 1); - new_value += value; - if ((new_value & 0xff00) == 0 && bset_use_y == relax_ldy) - { - bfd_put_8 (abfd, code, contents + offset); - bfd_put_8 (abfd, new_value, contents + offset + 1); - if (start_offset != offset) - { - m68hc11_elf_relax_delete_bytes (abfd, sec, start_offset, - offset - start_offset); - end_group--; - } - } - else - { - can_delete_ldx = 0; - } - offset = start_offset + isize; - } - if (can_delete_ldx) - { - /* Remove the move instruction (3 or 4 bytes win). */ - m68hc11_elf_relax_delete_bytes (abfd, sec, ldx_offset, ldx_size); - } -} - -/* This function handles relaxing for the 68HC11. - - - and somewhat more difficult to support. */ - -static bfd_boolean -m68hc11_elf_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *free_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - bfd_byte *free_contents = NULL; - Elf32_External_Sym *free_extsyms = NULL; - Elf_Internal_Rela *prev_insn_branch = NULL; - Elf_Internal_Rela *prev_insn_group = NULL; - unsigned insn_group_value = 0; - Elf_Internal_Sym *isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - if (! link_info->keep_memory) - free_relocs = internal_relocs; - - /* Checking for branch relaxation relies on the relocations to - be sorted on 'r_offset'. This is not guaranteed so we must sort. */ - qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), - compare_reloc); - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - bfd_vma value; - Elf_Internal_Sym *isym; - asection *sym_sec; - int is_far = 0; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_16 - && ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_RL_JUMP - && ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_RL_GROUP) - { - prev_insn_branch = 0; - prev_insn_group = 0; - continue; - } - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - /* Go get them off disk. */ - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Try to eliminate an unconditional 8 bit pc-relative branch - which immediately follows a conditional 8 bit pc-relative - branch around the unconditional branch. - - original: new: - bCC lab1 bCC' lab2 - bra lab2 - lab1: lab1: - - This happens when the bCC can't reach lab2 at assembly time, - but due to other relaxations it can reach at link time. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_JUMP) - { - Elf_Internal_Rela *nrel; - unsigned char code; - unsigned char roffset; - - prev_insn_branch = 0; - prev_insn_group = 0; - - /* Do nothing if this reloc is the last byte in the section. */ - if (irel->r_offset + 2 >= sec->size) - continue; - - /* See if the next instruction is an unconditional pc-relative - branch, more often than not this test will fail, so we - test it first to speed things up. */ - code = bfd_get_8 (abfd, contents + irel->r_offset + 2); - if (code != 0x7e) - continue; - - /* Also make sure the next relocation applies to the next - instruction and that it's a pc-relative 8 bit branch. */ - nrel = irel + 1; - if (nrel == irelend - || irel->r_offset + 3 != nrel->r_offset - || ELF32_R_TYPE (nrel->r_info) != (int) R_M68HC11_16) - continue; - - /* Make sure our destination immediately follows the - unconditional branch. */ - roffset = bfd_get_8 (abfd, contents + irel->r_offset + 1); - if (roffset != 3) - continue; - - prev_insn_branch = irel; - prev_insn_group = 0; - continue; - } - - /* Read this BFD's symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - is_far = isym->st_other & STO_M68HC12_FAR; - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - prev_insn_branch = 0; - prev_insn_group = 0; - continue; - } - - is_far = h->other & STO_M68HC12_FAR; - isym = 0; - sym_sec = h->root.u.def.section; - symval = (h->root.u.def.value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - - if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_GROUP) - { - prev_insn_branch = 0; - prev_insn_group = 0; - - /* Do nothing if this reloc is the last byte in the section. */ - if (irel->r_offset == sec->size) - continue; - - prev_insn_group = irel; - insn_group_value = isym->st_value; - continue; - } - - /* When we relax some bytes, the size of our section changes. - This affects the layout of next input sections that go in our - output section. When the symbol is part of another section that - will go in the same output section as the current one, it's - final address may now be incorrect (too far). We must let the - linker re-compute all section offsets before processing this - reloc. Code example: - - Initial Final - .sect .text section size = 6 section size = 4 - jmp foo - jmp bar - .sect .text.foo_bar output_offset = 6 output_offset = 4 - foo: rts - bar: rts - - If we process the reloc now, the jmp bar is replaced by a - relative branch to the initial bar address (output_offset 6). */ - if (*again && sym_sec != sec - && sym_sec->output_section == sec->output_section) - { - prev_insn_group = 0; - prev_insn_branch = 0; - continue; - } - - value = symval; - /* Try to turn a far branch to a near branch. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16 - && prev_insn_branch) - { - bfd_vma offset; - unsigned char code; - - offset = value - (prev_insn_branch->r_offset - + sec->output_section->vma - + sec->output_offset + 2); - - /* If the offset is still out of -128..+127 range, - leave that far branch unchanged. */ - if ((offset & 0xff80) != 0 && (offset & 0xff80) != 0xff80) - { - prev_insn_branch = 0; - continue; - } - - /* Shrink the branch. */ - code = bfd_get_8 (abfd, contents + prev_insn_branch->r_offset); - if (code == 0x7e) - { - code = 0x20; - bfd_put_8 (abfd, code, contents + prev_insn_branch->r_offset); - bfd_put_8 (abfd, 0xff, - contents + prev_insn_branch->r_offset + 1); - irel->r_offset = prev_insn_branch->r_offset + 1; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_M68HC11_PCREL_8); - m68hc11_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 1); - } - else - { - code ^= 0x1; - bfd_put_8 (abfd, code, contents + prev_insn_branch->r_offset); - bfd_put_8 (abfd, 0xff, - contents + prev_insn_branch->r_offset + 1); - irel->r_offset = prev_insn_branch->r_offset + 1; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_M68HC11_PCREL_8); - m68hc11_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 3); - } - prev_insn_branch = 0; - *again = TRUE; - } - - /* Try to turn a 16 bit address into a 8 bit page0 address. */ - else if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16 - && (value & 0xff00) == 0) - { - unsigned char code; - unsigned short offset; - struct m68hc11_direct_relax *rinfo; - - prev_insn_branch = 0; - offset = bfd_get_16 (abfd, contents + irel->r_offset); - offset += value; - if ((offset & 0xff00) != 0) - { - prev_insn_group = 0; - continue; - } - - if (prev_insn_group) - { - unsigned long old_sec_size = sec->size; - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - free_relocs = NULL; - - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; - - symtab_hdr->contents = (bfd_byte *) isymbuf; - free_extsyms = NULL; - - m68hc11_relax_group (abfd, sec, contents, offset, - prev_insn_group->r_offset, - insn_group_value); - irel = prev_insn_group; - prev_insn_group = 0; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_M68HC11_NONE); - if (sec->size != old_sec_size) - *again = TRUE; - continue; - } - - /* Get the opcode. */ - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - rinfo = find_relaxable_insn (code); - if (rinfo == 0) - { - prev_insn_group = 0; - continue; - } - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - free_relocs = NULL; - - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; - - symtab_hdr->contents = (bfd_byte *) isymbuf; - free_extsyms = NULL; - - /* Fix the opcode. */ - /* printf ("A relaxable case : 0x%02x (%s)\n", - code, rinfo->name); */ - bfd_put_8 (abfd, rinfo->direct_code, - contents + irel->r_offset - 1); - - /* Delete one byte of data (upper byte of address). */ - m68hc11_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 1); - - /* Fix the relocation's type. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_M68HC11_8); - - /* That will change things, so, we should relax again. */ - *again = TRUE; - } - else if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_16 && !is_far) - { - unsigned char code; - bfd_vma offset; - - prev_insn_branch = 0; - code = bfd_get_8 (abfd, contents + irel->r_offset - 1); - if (code == 0x7e || code == 0xbd) - { - offset = value - (irel->r_offset - + sec->output_section->vma - + sec->output_offset + 1); - offset += bfd_get_16 (abfd, contents + irel->r_offset); - - /* If the offset is still out of -128..+127 range, - leave that far branch unchanged. */ - if ((offset & 0xff80) == 0 || (offset & 0xff80) == 0xff80) - { - - /* Note that we've changed the relocation contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - free_relocs = NULL; - - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; - - symtab_hdr->contents = (bfd_byte *) isymbuf; - free_extsyms = NULL; - - /* Shrink the branch. */ - code = (code == 0x7e) ? 0x20 : 0x8d; - bfd_put_8 (abfd, code, - contents + irel->r_offset - 1); - bfd_put_8 (abfd, 0xff, - contents + irel->r_offset); - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_M68HC11_PCREL_8); - m68hc11_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 1, 1); - /* That will change things, so, we should relax again. */ - *again = TRUE; - } - } - } - prev_insn_branch = 0; - prev_insn_group = 0; - } - - if (free_relocs != NULL) - { - free (free_relocs); - free_relocs = NULL; - } - - if (free_contents != NULL) - { - if (! link_info->keep_memory) - free (free_contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - free_contents = NULL; - } - - if (free_extsyms != NULL) - { - if (! link_info->keep_memory) - free (free_extsyms); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - free_extsyms = NULL; - } - - return TRUE; - - error_return: - if (free_relocs != NULL) - free (free_relocs); - if (free_contents != NULL) - free (free_contents); - if (free_extsyms != NULL) - free (free_extsyms); - return FALSE; -} - -/* Delete some bytes from a section while relaxing. */ - -static void -m68hc11_elf_relax_delete_bytes (bfd *abfd, asection *sec, - bfd_vma addr, int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isymbuf, *isym, *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - - sec->size -= count; - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - unsigned char code; - unsigned char offset; - unsigned short raddr; - unsigned long old_offset; - int branch_pos; - - old_offset = irel->r_offset; - - /* See if this reloc was for the bytes we have deleted, in which - case we no longer care about it. Don't delete relocs which - represent addresses, though. */ - if (ELF32_R_TYPE (irel->r_info) != R_M68HC11_RL_JUMP - && irel->r_offset >= addr && irel->r_offset < addr + count) - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_M68HC11_NONE); - - if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_NONE) - continue; - - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset < toaddr)) - irel->r_offset -= count; - - /* If this is a PC relative reloc, see if the range it covers - includes the bytes we have deleted. */ - switch (ELF32_R_TYPE (irel->r_info)) - { - default: - break; - - case R_M68HC11_RL_JUMP: - code = bfd_get_8 (abfd, contents + irel->r_offset); - switch (code) - { - /* jsr and jmp instruction are also marked with RL_JUMP - relocs but no adjustment must be made. */ - case 0x7e: - case 0x9d: - case 0xbd: - continue; - - case 0x12: - case 0x13: - branch_pos = 3; - raddr = 4; - - /* Special case when we translate a brclr N,y into brclr * - In this case, the 0x18 page2 prefix is removed. - The reloc offset is not modified but the instruction - size is reduced by 1. */ - if (old_offset == addr) - raddr++; - break; - - case 0x1e: - case 0x1f: - branch_pos = 3; - raddr = 4; - break; - - case 0x18: - branch_pos = 4; - raddr = 5; - break; - - default: - branch_pos = 1; - raddr = 2; - break; - } - offset = bfd_get_8 (abfd, contents + irel->r_offset + branch_pos); - raddr += old_offset; - raddr += ((unsigned short) offset | ((offset & 0x80) ? 0xff00 : 0)); - if (irel->r_offset < addr && raddr > addr) - { - offset -= count; - bfd_put_8 (abfd, offset, contents + irel->r_offset + branch_pos); - } - else if (irel->r_offset >= addr && raddr <= addr) - { - offset += count; - bfd_put_8 (abfd, offset, contents + irel->r_offset + branch_pos); - } - else - { - /*printf ("Not adjusted 0x%04x [0x%4x 0x%4x]\n", raddr, - irel->r_offset, addr);*/ - } - - break; - } - } - - /* Adjust the local symbols defined in this section. */ - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value <= toaddr) - isym->st_value -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value <= toaddr) - { - sym_hash->root.u.def.value -= count; - } - } -} - -/* Specific sections: - - The .page0 is a data section that is mapped in [0x0000..0x00FF]. - Page0 accesses are faster on the M68HC11. Soft registers used by GCC-m6811 - are located in .page0. - - The .vectors is the section that represents the interrupt - vectors. */ -static const struct bfd_elf_special_section elf32_m68hc11_special_sections[] = -{ - { STRING_COMMA_LEN (".eeprom"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".page0"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".vectors"), 0, SHT_PROGBITS, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } -}; - -#define ELF_ARCH bfd_arch_m68hc11 -#define ELF_TARGET_ID M68HC11_ELF_DATA -#define ELF_MACHINE_CODE EM_68HC11 -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM m68hc11_elf32_vec -#define TARGET_BIG_NAME "elf32-m68hc11" - -#define elf_info_to_howto 0 -#define elf_info_to_howto_rel m68hc11_info_to_howto_rel -#define bfd_elf32_bfd_relax_section m68hc11_elf_relax_section -#define elf_backend_check_relocs elf32_m68hc11_check_relocs -#define elf_backend_relocate_section elf32_m68hc11_relocate_section -#define elf_backend_add_symbol_hook elf32_m68hc11_add_symbol_hook -#define elf_backend_object_p 0 -#define elf_backend_final_write_processing 0 -#define elf_backend_can_gc_sections 1 -#define elf_backend_special_sections elf32_m68hc11_special_sections -#define elf_backend_merge_symbol_attribute elf32_m68hc11_merge_symbol_attribute - -#define bfd_elf32_bfd_link_hash_table_create \ - m68hc11_elf_bfd_link_hash_table_create -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_m68hc11_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags _bfd_m68hc11_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - _bfd_m68hc11_elf_print_private_bfd_data - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-m68hc12.c b/sdcc/support/sdbinutils/bfd/elf32-m68hc12.c deleted file mode 100644 index 3fec99354..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m68hc12.c +++ /dev/null @@ -1,669 +0,0 @@ -/* Motorola 68HC12-specific support for 32-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - (Heavily copied from the D10V port by Martin Hunt (hunt@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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf32-m68hc1x.h" -#include "elf/m68hc11.h" -#include "opcode/m68hc11.h" - -/* Relocation functions. */ -static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static void m68hc11_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); - -/* Trampoline generation. */ - - -/* Use REL instead of RELA to save space */ -#define USE_REL 1 - -/* The 68HC12 microcontroler has a memory bank switching system - with a 16Kb window in the 64Kb address space. The extended memory - is mapped in the 16Kb window (at 0x8000). The page register controls - which 16Kb bank is mapped. The call/rtc instructions take care of - bank switching in function calls/returns. - - For GNU Binutils to work, we consider there is a physical memory - at 0..0x0ffff and a kind of virtual memory above that. Symbols - in virtual memory have their addresses treated in a special way - when disassembling and when linking. - - For the linker to work properly, we must always relocate the virtual - memory as if it is mapped at 0x8000. When a 16-bit relocation is - made in the virtual memory, we check that it does not cross the - memory bank where it is used. This would involve a page change - which would be wrong. The 24-bit relocation is for that and it - treats the address as a physical address + page number. - - - Banked - Address Space - | | Page n - +---------------+ 0x1010000 - | | - | jsr _foo | - | .. | Page 3 - | _foo: | - +---------------+ 0x100C000 - | | - | call _bar | - | .. | Page 2 - | _bar: | - +---------------+ 0x1008000 - /------>| | - | | call _foo | Page 1 - | | | - | +---------------+ 0x1004000 - Physical | | | - Address Space | | | Page 0 - | | | - +-----------+ 0x00FFFF | +---------------+ 0x1000000 - | | | - | call _foo | | - | | | - +-----------+ 0x00BFFF -+---/ - | | | - | | | - | | 16K | - | | | - +-----------+ 0x008000 -+ - | | - | | - = = - | | - | | - +-----------+ 0000 - - - The 'call _foo' must be relocated with page 3 and 16-bit address - mapped at 0x8000. - - The 3-bit and 16-bit PC rel relocation is only used by 68HC12. */ -static reloc_howto_type elf_m68hc11_howto_table[] = { - /* This reloc does nothing. */ - HOWTO (R_M68HC11_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation */ - HOWTO (R_M68HC11_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (upper address) */ - HOWTO (R_M68HC11_HI8, /* type */ - 8, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_HI8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (upper address) */ - HOWTO (R_M68HC11_LO8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_LO8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit PC-rel relocation */ - HOWTO (R_M68HC11_PCREL_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_PCREL_8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation */ - HOWTO (R_M68HC11_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont /*bitfield */ , /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. This one is never used for the - code relocation. It's used by gas for -gstabs generation. */ - HOWTO (R_M68HC11_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 3 bit absolute relocation */ - HOWTO (R_M68HC11_3B, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 3, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_4B", /* name */ - FALSE, /* partial_inplace */ - 0x003, /* src_mask */ - 0x003, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit PC-rel relocation */ - HOWTO (R_M68HC11_PCREL_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_PCREL_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_M68HC11_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_M68HC11_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_M68HC11_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 1, /* 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_M68HC11_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 24 bit relocation */ - HOWTO (R_M68HC11_24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_special_reloc, /* special_function */ - "R_M68HC12_24", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16-bit low relocation */ - HOWTO (R_M68HC11_LO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_special_reloc,/* special_function */ - "R_M68HC12_LO16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A page relocation */ - HOWTO (R_M68HC11_PAGE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_special_reloc,/* special_function */ - "R_M68HC12_PAGE", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (14), - - /* A 16 bit absolute relocation. */ - HOWTO (R_M68HC12_16B, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_16B", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 9 bit PC-rel relocation. */ - HOWTO (R_M68HC12_PCREL_9, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize (result is >>1) */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_PCREL_9", /* name */ - TRUE, /* partial_inplace */ - 0xfe00, /* src_mask */ - 0x01ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 10 bit PC-rel relocation. */ - HOWTO (R_M68HC12_PCREL_10, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize (result is >>1) */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_PCREL_10", /* name */ - TRUE, /* partial_inplace */ - 0xfc00, /* src_mask */ - 0x03ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (upper address). */ - HOWTO (R_M68HC12_HI8XG, /* type */ - 8, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_HI8XG", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (lower address). */ - HOWTO (R_M68HC12_LO8XG, /* type */ - 8, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_M68HC12_LO8XG", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Mark beginning of a jump instruction (any form). */ - HOWTO (R_M68HC11_RL_JUMP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_ignore_reloc, /* special_function */ - "R_M68HC12_RL_JUMP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Mark beginning of Gcc relaxation group instruction. */ - HOWTO (R_M68HC11_RL_GROUP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - m68hc11_elf_ignore_reloc, /* special_function */ - "R_M68HC12_RL_GROUP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* Map BFD reloc types to M68HC11 ELF reloc types. */ - -struct m68hc11_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct m68hc11_reloc_map m68hc11_reloc_map[] = -{ - {BFD_RELOC_NONE, R_M68HC11_NONE,}, - {BFD_RELOC_8, R_M68HC11_8}, - {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8}, - {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8}, - {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8}, - {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16}, - {BFD_RELOC_16, R_M68HC11_16}, - {BFD_RELOC_32, R_M68HC11_32}, - {BFD_RELOC_M68HC11_3B, R_M68HC11_3B}, - - {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY}, - - {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16}, - {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE}, - {BFD_RELOC_M68HC11_24, R_M68HC11_24}, - - {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP}, - {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP}, - - {BFD_RELOC_M68HC12_16B, R_M68HC12_16B}, - - {BFD_RELOC_M68HC12_9_PCREL, R_M68HC12_PCREL_9}, - {BFD_RELOC_M68HC12_10_PCREL, R_M68HC12_PCREL_10}, - {BFD_RELOC_M68HC12_HI8XG, R_M68HC12_HI8XG}, - {BFD_RELOC_M68HC12_LO8XG, R_M68HC12_LO8XG}, -}; - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map); - i++) - { - if (m68hc11_reloc_map[i].bfd_reloc_val == code) - return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf_m68hc11_howto_table) - / sizeof (elf_m68hc11_howto_table[0])); - i++) - if (elf_m68hc11_howto_table[i].name != NULL - && strcasecmp (elf_m68hc11_howto_table[i].name, r_name) == 0) - return &elf_m68hc11_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an M68HC11 ELF reloc. */ - -static void -m68hc11_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_M68HC11_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid M68HC12 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_m68hc11_howto_table[r_type]; -} - - -/* Far trampoline generation. */ - -/* Build a 68HC12 trampoline stub. */ -static bfd_boolean -m68hc12_elf_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) -{ - struct elf32_m68hc11_stub_hash_entry *stub_entry; - struct bfd_link_info *info; - struct m68hc11_elf_link_hash_table *htab; - asection *stub_sec; - bfd *stub_bfd; - bfd_byte *loc; - bfd_vma sym_value, phys_page, phys_addr; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry; - info = (struct bfd_link_info *) in_arg; - - htab = m68hc11_elf_hash_table (info); - - stub_sec = stub_entry->stub_sec; - - /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset = stub_sec->size; - stub_sec->size += 7; - loc = stub_sec->contents + stub_entry->stub_offset; - - stub_bfd = stub_sec->owner; - - /* Create the trampoline call stub: - - ldy #%addr(symbol) - call %page(symbol), __trampoline - - */ - sym_value = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value); - phys_page = m68hc11_phys_page (&htab->pinfo, sym_value); - - /* ldy #%page(sym) */ - bfd_put_8 (stub_bfd, 0xCD, loc); - bfd_put_16 (stub_bfd, phys_addr, loc + 1); - loc += 3; - - /* call %page(sym), __trampoline */ - bfd_put_8 (stub_bfd, 0x4a, loc); - bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1); - bfd_put_8 (stub_bfd, phys_page, loc + 3); - - return TRUE; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ - -static bfd_boolean -m68hc12_elf_size_one_stub (struct bfd_hash_entry *gen_entry, - void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_m68hc11_stub_hash_entry *stub_entry; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry; - - stub_entry->stub_sec->size += 7; - return TRUE; -} - -/* Create a 68HC12 ELF linker hash table. */ - -static struct bfd_link_hash_table * -m68hc12_elf_bfd_link_hash_table_create (bfd *abfd) -{ - struct m68hc11_elf_link_hash_table *ret; - - ret = m68hc11_elf_hash_table_create (abfd); - if (ret == (struct m68hc11_elf_link_hash_table *) NULL) - return NULL; - - ret->size_one_stub = m68hc12_elf_size_one_stub; - ret->build_one_stub = m68hc12_elf_build_one_stub; - - return &ret->root.root; -} - -static bfd_boolean -m68hc12_elf_set_mach_from_flags (bfd *abfd) -{ - flagword flags = elf_elfheader (abfd)->e_flags; - - switch (flags & EF_M68HC11_MACH_MASK) - { - case EF_M68HC12_MACH: - bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812); - break; - case EF_M68HCS12_MACH: - bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, bfd_mach_m6812s); - break; - case EF_M68HC11_GENERIC: - bfd_default_set_arch_mach (abfd, bfd_arch_m68hc12, - bfd_mach_m6812_default); - break; - default: - return FALSE; - } - return TRUE; -} - -/* Specific sections: - - The .page0 is a data section that is mapped in [0x0000..0x00FF]. - Page0 accesses are faster on the M68HC12. - - The .vectors is the section that represents the interrupt - vectors. */ -static const struct bfd_elf_special_section elf32_m68hc12_special_sections[] = -{ - { STRING_COMMA_LEN (".eeprom"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".page0"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".vectors"), 0, SHT_PROGBITS, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } -}; - -#define ELF_ARCH bfd_arch_m68hc12 -#define ELF_TARGET_ID M68HC11_ELF_DATA -#define ELF_MACHINE_CODE EM_68HC12 -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM m68hc12_elf32_vec -#define TARGET_BIG_NAME "elf32-m68hc12" - -#define elf_info_to_howto 0 -#define elf_info_to_howto_rel m68hc11_info_to_howto_rel -#define elf_backend_check_relocs elf32_m68hc11_check_relocs -#define elf_backend_relocate_section elf32_m68hc11_relocate_section -#define elf_backend_object_p m68hc12_elf_set_mach_from_flags -#define elf_backend_final_write_processing 0 -#define elf_backend_can_gc_sections 1 -#define elf_backend_special_sections elf32_m68hc12_special_sections -#define elf_backend_post_process_headers elf32_m68hc11_post_process_headers -#define elf_backend_add_symbol_hook elf32_m68hc11_add_symbol_hook -#define elf_backend_merge_symbol_attribute elf32_m68hc11_merge_symbol_attribute - -#define bfd_elf32_bfd_link_hash_table_create \ - m68hc12_elf_bfd_link_hash_table_create -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_m68hc11_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags _bfd_m68hc11_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - _bfd_m68hc11_elf_print_private_bfd_data - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-m68hc1x.c b/sdcc/support/sdbinutils/bfd/elf32-m68hc1x.c deleted file mode 100644 index dcdc357b2..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m68hc1x.c +++ /dev/null @@ -1,1479 +0,0 @@ -/* Motorola 68HC11/HC12-specific support for 32-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "alloca-conf.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf32-m68hc1x.h" -#include "elf/m68hc11.h" -#include "opcode/m68hc11.h" -#include "libiberty.h" - -#define m68hc12_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_m68hc11_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -static struct elf32_m68hc11_stub_hash_entry* m68hc12_add_stub - (const char *stub_name, - asection *section, - struct m68hc11_elf_link_hash_table *htab); - -static struct bfd_hash_entry *stub_hash_newfunc - (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); - -static void m68hc11_elf_set_symbol (bfd* abfd, struct bfd_link_info *info, - const char* name, bfd_vma value, - asection* sec); - -static bfd_boolean m68hc11_elf_export_one_stub - (struct bfd_hash_entry *gen_entry, void *in_arg); - -static void scan_sections_for_abi (bfd*, asection*, void *); - -struct m68hc11_scan_param -{ - struct m68hc11_page_info* pinfo; - bfd_boolean use_memory_banks; -}; - - -/* Destroy a 68HC11/68HC12 ELF linker hash table. */ - -static void -m68hc11_elf_bfd_link_hash_table_free (bfd *obfd) -{ - struct m68hc11_elf_link_hash_table *ret - = (struct m68hc11_elf_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (ret->stub_hash_table); - free (ret->stub_hash_table); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create a 68HC11/68HC12 ELF linker hash table. */ - -struct m68hc11_elf_link_hash_table* -m68hc11_elf_hash_table_create (bfd *abfd) -{ - struct m68hc11_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct m68hc11_elf_link_hash_table); - - ret = (struct m68hc11_elf_link_hash_table *) bfd_zmalloc (amt); - if (ret == (struct m68hc11_elf_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry), - M68HC11_ELF_DATA)) - { - free (ret); - return NULL; - } - - /* Init the stub hash table too. */ - amt = sizeof (struct bfd_hash_table); - ret->stub_hash_table = (struct bfd_hash_table*) bfd_malloc (amt); - if (ret->stub_hash_table == NULL) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc, - sizeof (struct elf32_m68hc11_stub_hash_entry))) - { - free (ret->stub_hash_table); - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - ret->root.root.hash_table_free = m68hc11_elf_bfd_link_hash_table_free; - - return ret; -} - -/* Assorted hash table functions. */ - -/* Initialize an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_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 elf32_m68hc11_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf32_m68hc11_stub_hash_entry *eh; - - /* Initialize the local fields. */ - eh = (struct elf32_m68hc11_stub_hash_entry *) entry; - eh->stub_sec = NULL; - eh->stub_offset = 0; - eh->target_value = 0; - eh->target_section = NULL; - } - - return entry; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ - -static struct elf32_m68hc11_stub_hash_entry * -m68hc12_add_stub (const char *stub_name, asection *section, - struct m68hc11_elf_link_hash_table *htab) -{ - struct elf32_m68hc11_stub_hash_entry *stub_entry; - - /* Enter this entry into the linker stub hash table. */ - stub_entry = m68hc12_stub_hash_lookup (htab->stub_hash_table, stub_name, - TRUE, FALSE); - if (stub_entry == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: cannot create stub entry %s"), - section->owner, stub_name); - return NULL; - } - - if (htab->stub_section == 0) - { - htab->stub_section = (*htab->add_stub_section) (".tramp", - htab->tramp_section); - } - - stub_entry->stub_sec = htab->stub_section; - stub_entry->stub_offset = 0; - return stub_entry; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it for identify far symbols and force a loading of - the trampoline handler. */ - -bfd_boolean -elf32_m68hc11_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp ATTRIBUTE_UNUSED, - bfd_vma *valp ATTRIBUTE_UNUSED) -{ - if (sym->st_other & STO_M68HC12_FAR) - { - struct elf_link_hash_entry *h; - - h = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (info->hash, "__far_trampoline", - FALSE, FALSE, FALSE); - if (h == NULL) - { - struct bfd_link_hash_entry* entry = NULL; - - _bfd_generic_link_add_one_symbol (info, abfd, - "__far_trampoline", - BSF_GLOBAL, - bfd_und_section_ptr, - (bfd_vma) 0, (const char*) NULL, - FALSE, FALSE, &entry); - } - - } - return TRUE; -} - -/* Merge non-visibility st_other attributes, STO_M68HC12_FAR and - STO_M68HC12_INTERRUPT. */ - -void -elf32_m68hc11_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic ATTRIBUTE_UNUSED) -{ - if (definition) - h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) - | ELF_ST_VISIBILITY (h->other)); -} - -/* External entry points for sizing and building linker stubs. */ - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ - -int -elf32_m68hc11_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - bfd_size_type amt; - asection *text_section; - struct m68hc11_elf_link_hash_table *htab; - - htab = m68hc11_elf_hash_table (info); - if (htab == NULL) - return -1; - - if (bfd_get_flavour (info->output_bfd) != bfd_target_elf_flavour) - return 0; - - /* Count the number of input BFDs and find the top input section id. - Also search for an existing ".tramp" section so that we know - where generated trampolines must go. Default to ".text" if we - can't find it. */ - htab->tramp_section = 0; - text_section = 0; - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - const char* name = bfd_get_section_name (input_bfd, section); - - if (!strcmp (name, ".tramp")) - htab->tramp_section = section; - - if (!strcmp (name, ".text")) - text_section = section; - - if (top_id < section->id) - top_id = section->id; - } - } - htab->bfd_count = bfd_count; - if (htab->tramp_section == 0) - htab->tramp_section = text_section; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = (asection **) bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - { - if ((section->flags & SEC_CODE) != 0) - input_list[section->index] = NULL; - } - - return 1; -} - -/* Determine and set the size of the stub section for a final link. - - The basic idea here is to examine all the relocations looking for - PC-relative calls to a target that is unreachable with a "bl" - instruction. */ - -bfd_boolean -elf32_m68hc11_size_stubs (bfd *output_bfd, bfd *stub_bfd, - struct bfd_link_info *info, - asection * (*add_stub_section) (const char*, asection*)) -{ - bfd *input_bfd; - asection *section; - Elf_Internal_Sym *local_syms, **all_local_syms; - unsigned int bfd_indx, bfd_count; - bfd_size_type amt; - asection *stub_sec; - struct m68hc11_elf_link_hash_table *htab = m68hc11_elf_hash_table (info); - - if (htab == NULL) - return FALSE; - - /* Stash our params away. */ - htab->stub_bfd = stub_bfd; - htab->add_stub_section = add_stub_section; - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - bfd_count += 1; - - /* We want to read in symbol extension records only once. To do this - we need to read in the local symbols in parallel and save them for - later use; so hold pointers to the local symbols in an array. */ - amt = sizeof (Elf_Internal_Sym *) * bfd_count; - all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt); - if (all_local_syms == NULL) - return FALSE; - - /* Walk over all the input BFDs, swapping in local symbols. */ - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* We need an array of the local symbols attached to the input bfd. */ - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - { - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - /* Cache them for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - if (local_syms == NULL) - { - free (all_local_syms); - return FALSE; - } - - all_local_syms[bfd_indx] = local_syms; - } - - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - - sym_hashes = elf_sym_hashes (input_bfd); - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - local_syms = all_local_syms[bfd_indx]; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, - (Elf_Internal_Rela *) NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - struct elf32_m68hc11_stub_hash_entry *stub_entry; - asection *sym_sec; - bfd_vma sym_value; - struct elf_link_hash_entry *hash; - const char *stub_name; - Elf_Internal_Sym *sym; - - r_type = ELF32_R_TYPE (irela->r_info); - - /* Only look at 16-bit relocs. */ - if (r_type != (unsigned int) R_M68HC11_16) - continue; - - /* Now determine the call target, its name, value, - section. */ - r_indx = ELF32_R_SYM (irela->r_info); - if (r_indx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - Elf_Internal_Shdr *hdr; - bfd_boolean is_far; - - sym = local_syms + r_indx; - is_far = (sym && (sym->st_other & STO_M68HC12_FAR)); - if (!is_far) - continue; - - if (sym->st_shndx >= elf_numsections (input_bfd)) - sym_sec = NULL; - else - { - hdr = elf_elfsections (input_bfd)[sym->st_shndx]; - sym_sec = hdr->bfd_section; - } - stub_name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, - sym->st_name)); - sym_value = sym->st_value; - hash = NULL; - } - else - { - /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hash = (struct elf_link_hash_entry *) - (sym_hashes[e_indx]); - - while (hash->root.type == bfd_link_hash_indirect - || hash->root.type == bfd_link_hash_warning) - hash = ((struct elf_link_hash_entry *) - hash->root.u.i.link); - - if (hash->root.type == bfd_link_hash_defined - || hash->root.type == bfd_link_hash_defweak - || hash->root.type == bfd_link_hash_new) - { - if (!(hash->other & STO_M68HC12_FAR)) - continue; - } - else if (hash->root.type == bfd_link_hash_undefweak) - { - continue; - } - else if (hash->root.type == bfd_link_hash_undefined) - { - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - sym_sec = hash->root.u.def.section; - sym_value = hash->root.u.def.value; - stub_name = hash->root.root.string; - } - - if (!stub_name) - goto error_ret_free_internal; - - stub_entry = m68hc12_stub_hash_lookup - (htab->stub_hash_table, - stub_name, - FALSE, FALSE); - if (stub_entry == NULL) - { - if (add_stub_section == 0) - continue; - - stub_entry = m68hc12_add_stub (stub_name, section, htab); - if (stub_entry == NULL) - { - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - goto error_ret_free_local; - } - } - - stub_entry->target_value = sym_value; - stub_entry->target_section = sym_sec; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - } - - if (add_stub_section) - { - /* OK, we've added some stubs. Find out the new size of the - stub sections. */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - stub_sec->size = 0; - } - - bfd_hash_traverse (htab->stub_hash_table, htab->size_one_stub, htab); - } - free (all_local_syms); - return TRUE; - - error_ret_free_local: - free (all_local_syms); - return FALSE; -} - -/* Export the trampoline addresses in the symbol table. */ -static bfd_boolean -m68hc11_elf_export_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) -{ - struct bfd_link_info *info; - struct m68hc11_elf_link_hash_table *htab; - struct elf32_m68hc11_stub_hash_entry *stub_entry; - char* name; - bfd_boolean result; - - info = (struct bfd_link_info *) in_arg; - htab = m68hc11_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Massage our args to the form they really have. */ - stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry; - - /* Generate the trampoline according to HC11 or HC12. */ - result = (* htab->build_one_stub) (gen_entry, in_arg); - - /* Make a printable name that does not conflict with the real function. */ - name = concat ("tramp.", stub_entry->root.string, NULL); - - /* Export the symbol for debugging/disassembling. */ - m68hc11_elf_set_symbol (htab->stub_bfd, info, name, - stub_entry->stub_offset, - stub_entry->stub_sec); - free (name); - return result; -} - -/* Export a symbol or set its value and section. */ -static void -m68hc11_elf_set_symbol (bfd *abfd, struct bfd_link_info *info, - const char *name, bfd_vma value, asection *sec) -{ - struct elf_link_hash_entry *h; - - h = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE); - if (h == NULL) - { - _bfd_generic_link_add_one_symbol (info, abfd, - name, - BSF_GLOBAL, - sec, - value, - (const char*) NULL, - TRUE, FALSE, NULL); - } - else - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.value = value; - h->root.u.def.section = sec; - } -} - - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. This function is called via m68hc12elf_finish in the - linker. */ - -bfd_boolean -elf32_m68hc11_build_stubs (bfd *abfd, struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - struct m68hc11_elf_link_hash_table *htab; - struct m68hc11_scan_param param; - - m68hc11_elf_get_bank_parameters (info); - htab = m68hc11_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - bfd_size_type size; - - /* Allocate memory to hold the linker stubs. */ - size = stub_sec->size; - stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size); - if (stub_sec->contents == NULL && size != 0) - return FALSE; - stub_sec->size = 0; - } - - /* Build the stubs as directed by the stub hash table. */ - table = htab->stub_hash_table; - bfd_hash_traverse (table, m68hc11_elf_export_one_stub, info); - - /* Scan the output sections to see if we use the memory banks. - If so, export the symbols that define how the memory banks - are mapped. This is used by gdb and the simulator to obtain - the information. It can be used by programs to burn the eprom - at the good addresses. */ - param.use_memory_banks = FALSE; - param.pinfo = &htab->pinfo; - bfd_map_over_sections (abfd, scan_sections_for_abi, ¶m); - if (param.use_memory_banks) - { - m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_START_NAME, - htab->pinfo.bank_physical, - bfd_abs_section_ptr); - m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_VIRTUAL_NAME, - htab->pinfo.bank_virtual, - bfd_abs_section_ptr); - m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_SIZE_NAME, - htab->pinfo.bank_size, - bfd_abs_section_ptr); - } - - return TRUE; -} - -void -m68hc11_elf_get_bank_parameters (struct bfd_link_info *info) -{ - unsigned i; - struct m68hc11_page_info *pinfo; - struct bfd_link_hash_entry *h; - struct m68hc11_elf_link_hash_table *htab; - - htab = m68hc11_elf_hash_table (info); - if (htab == NULL) - return; - - pinfo = & htab->pinfo; - if (pinfo->bank_param_initialized) - return; - - pinfo->bank_virtual = M68HC12_BANK_VIRT; - pinfo->bank_mask = M68HC12_BANK_MASK; - pinfo->bank_physical = M68HC12_BANK_BASE; - pinfo->bank_shift = M68HC12_BANK_SHIFT; - pinfo->bank_size = 1 << M68HC12_BANK_SHIFT; - - h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_START_NAME, - FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry*) NULL - && h->type == bfd_link_hash_defined) - pinfo->bank_physical = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_VIRTUAL_NAME, - FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry*) NULL - && h->type == bfd_link_hash_defined) - pinfo->bank_virtual = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_SIZE_NAME, - FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry*) NULL - && h->type == bfd_link_hash_defined) - pinfo->bank_size = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - pinfo->bank_shift = 0; - for (i = pinfo->bank_size; i != 0; i >>= 1) - pinfo->bank_shift++; - pinfo->bank_shift--; - pinfo->bank_mask = (1 << pinfo->bank_shift) - 1; - pinfo->bank_physical_end = pinfo->bank_physical + pinfo->bank_size; - pinfo->bank_param_initialized = 1; - - h = bfd_link_hash_lookup (info->hash, "__far_trampoline", FALSE, - FALSE, TRUE); - if (h != (struct bfd_link_hash_entry*) NULL - && h->type == bfd_link_hash_defined) - pinfo->trampoline_addr = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); -} - -/* Return 1 if the address is in banked memory. - This can be applied to a virtual address and to a physical address. */ -int -m68hc11_addr_is_banked (struct m68hc11_page_info *pinfo, bfd_vma addr) -{ - if (addr >= pinfo->bank_virtual) - return 1; - - if (addr >= pinfo->bank_physical && addr <= pinfo->bank_physical_end) - return 1; - - return 0; -} - -/* Return the physical address seen by the processor, taking - into account banked memory. */ -bfd_vma -m68hc11_phys_addr (struct m68hc11_page_info *pinfo, bfd_vma addr) -{ - if (addr < pinfo->bank_virtual) - return addr; - - /* Map the address to the memory bank. */ - addr -= pinfo->bank_virtual; - addr &= pinfo->bank_mask; - addr += pinfo->bank_physical; - return addr; -} - -/* Return the page number corresponding to an address in banked memory. */ -bfd_vma -m68hc11_phys_page (struct m68hc11_page_info *pinfo, bfd_vma addr) -{ - if (addr < pinfo->bank_virtual) - return 0; - - /* Map the address to the memory bank. */ - addr -= pinfo->bank_virtual; - addr >>= pinfo->bank_shift; - addr &= 0x0ff; - return addr; -} - -/* This function is used for relocs which are only used for relaxing, - which the linker should otherwise ignore. */ - -bfd_reloc_status_type -m68hc11_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -bfd_reloc_status_type -m68hc11_elf_special_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 != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc_entry->howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - return bfd_reloc_continue; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - abort(); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -bfd_boolean -elf32_m68hc11_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - rel_end = relocs + sec->reloc_count; - - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry * h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes [r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_M68HC11_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_M68HC11_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* Relocate a 68hc11/68hc12 ELF section. */ -bfd_boolean -elf32_m68hc11_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - const char *name = NULL; - struct m68hc11_page_info *pinfo; - const struct elf_backend_data * const ebd = get_elf_backend_data (input_bfd); - struct m68hc11_elf_link_hash_table *htab; - unsigned long e_flags; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - e_flags = elf_elfheader (input_bfd)->e_flags; - - htab = m68hc11_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Get memory bank parameters. */ - m68hc11_elf_get_bank_parameters (info); - - pinfo = & htab->pinfo; - rel = relocs; - relend = relocs + input_section->reloc_count; - - for (; rel < relend; rel++) - { - int r_type; - arelent arel; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - bfd_vma relocation = 0; - bfd_reloc_status_type r = bfd_reloc_undefined; - bfd_vma phys_page; - bfd_vma phys_addr; - bfd_vma insn_addr; - bfd_vma insn_page; - bfd_boolean is_far = FALSE; - bfd_boolean is_xgate_symbol = FALSE; - bfd_boolean is_section_symbol = FALSE; - struct elf_link_hash_entry *h; - bfd_vma val; - const char * msg; - char * buf; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_M68HC11_GNU_VTENTRY - || r_type == R_M68HC11_GNU_VTINHERIT) - continue; - - (*ebd->elf_info_to_howto_rel) (input_bfd, &arel, rel); - howto = arel.howto; - - h = NULL; - sym = NULL; - sec = NULL; - 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); - is_far = (sym && (sym->st_other & STO_M68HC12_FAR)); - is_xgate_symbol = (sym && (sym->st_target_internal)); - is_section_symbol = ELF_ST_TYPE (sym->st_info) & STT_SECTION; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, unresolved_reloc, - warned, ignored); - - is_far = (h && (h->other & STO_M68HC12_FAR)); - is_xgate_symbol = (h && (h->target_internal)); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - continue; - } - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - if (is_far && ELF32_R_TYPE (rel->r_info) == R_M68HC11_16) - { - struct elf32_m68hc11_stub_hash_entry* stub; - - stub = m68hc12_stub_hash_lookup (htab->stub_hash_table, - name, FALSE, FALSE); - if (stub) - { - relocation = stub->stub_offset - + stub->stub_sec->output_section->vma - + stub->stub_sec->output_offset; - is_far = FALSE; - } - } - - /* Do the memory bank mapping. */ - phys_addr = m68hc11_phys_addr (pinfo, relocation + rel->r_addend); - phys_page = m68hc11_phys_page (pinfo, relocation + rel->r_addend); - switch (r_type) - { - case R_M68HC12_LO8XG: - /* This relocation is specific to XGATE IMM16 calls and will precede - a HI8. tc-m68hc11 only generates them in pairs. - Leave the relocation to the HI8XG step. */ - r = bfd_reloc_ok; - r_type = R_M68HC11_NONE; - break; - - case R_M68HC12_HI8XG: - /* This relocation is specific to XGATE IMM16 calls and must follow - a LO8XG. Does not actually check that it was a LO8XG. - Adjusts high and low bytes. */ - relocation = phys_addr; - if ((e_flags & E_M68HC11_XGATE_RAMOFFSET) - && (relocation >= 0x2000)) - relocation += 0xc000; /* HARDCODED RAM offset for XGATE. */ - - /* Fetch 16 bit value including low byte in previous insn. */ - val = (bfd_get_8 (input_bfd, (bfd_byte*) contents + rel->r_offset) << 8) - | bfd_get_8 (input_bfd, (bfd_byte*) contents + rel->r_offset - 2); - - /* Add on value to preserve carry, then write zero to high byte. */ - relocation += val; - - /* Write out top byte. */ - bfd_put_8 (input_bfd, (relocation >> 8) & 0xff, - (bfd_byte*) contents + rel->r_offset); - - /* Write out low byte to previous instruction. */ - bfd_put_8 (input_bfd, relocation & 0xff, - (bfd_byte*) contents + rel->r_offset - 2); - - /* Mark as relocation completed. */ - r = bfd_reloc_ok; - r_type = R_M68HC11_NONE; - break; - - /* The HI8 and LO8 relocs are generated by %hi(expr) %lo(expr) - assembler directives. %hi does not support carry. */ - case R_M68HC11_HI8: - case R_M68HC11_LO8: - relocation = phys_addr; - break; - - case R_M68HC11_24: - /* Reloc used by 68HC12 call instruction. */ - bfd_put_16 (input_bfd, phys_addr, - (bfd_byte*) contents + rel->r_offset); - bfd_put_8 (input_bfd, phys_page, - (bfd_byte*) contents + rel->r_offset + 2); - r = bfd_reloc_ok; - r_type = R_M68HC11_NONE; - break; - - case R_M68HC11_NONE: - r = bfd_reloc_ok; - break; - - case R_M68HC11_LO16: - /* Reloc generated by %addr(expr) gas to obtain the - address as mapped in the memory bank window. */ - relocation = phys_addr; - break; - - case R_M68HC11_PAGE: - /* Reloc generated by %page(expr) gas to obtain the - page number associated with the address. */ - relocation = phys_page; - break; - - case R_M68HC11_16: - /* Get virtual address of instruction having the relocation. */ - if (is_far) - { - msg = _("Reference to the far symbol `%s' using a wrong " - "relocation may result in incorrect execution"); - buf = xmalloc (strlen (msg) + strlen (name) + 10); - sprintf (buf, msg, name); - - (*info->callbacks->warning) - (info, buf, name, input_bfd, NULL, rel->r_offset); - free (buf); - } - - /* Get virtual address of instruction having the relocation. */ - insn_addr = input_section->output_section->vma - + input_section->output_offset - + rel->r_offset; - - insn_page = m68hc11_phys_page (pinfo, insn_addr); - - /* If we are linking an S12 instruction against an XGATE symbol, we - need to change the offset of the symbol value so that it's correct - from the S12's perspective. */ - if (is_xgate_symbol) - { - /* The ram in the global space is mapped to 0x2000 in the 16-bit - address space for S12 and 0xE000 in the 16-bit address space - for XGATE. */ - if (relocation >= 0xE000) - { - /* We offset the address by the difference - between these two mappings. */ - relocation -= 0xC000; - break; - } - else - { - msg = _("XGATE address (%lx) is not within shared RAM" - "(0xE000-0xFFFF), therefore you must manually offset " - "the address, and possibly manage the page, in your " - "code."); - buf = xmalloc (strlen (msg) + 128); - sprintf (buf, msg, phys_addr); - (*info->callbacks->warning) (info, buf, name, input_bfd, - input_section, insn_addr); - free (buf); - break; - } - } - - if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend) - && m68hc11_addr_is_banked (pinfo, insn_addr) - && phys_page != insn_page && !(e_flags & E_M68HC11_NO_BANK_WARNING)) - { - /* xgettext:c-format */ - msg = _("banked address [%lx:%04lx] (%lx) is not in the same bank " - "as current banked address [%lx:%04lx] (%lx)"); - buf = xmalloc (strlen (msg) + 128); - sprintf (buf, msg, phys_page, phys_addr, - (long) (relocation + rel->r_addend), - insn_page, m68hc11_phys_addr (pinfo, insn_addr), - (long) (insn_addr)); - (*info->callbacks->warning) (info, buf, name, input_bfd, - input_section, rel->r_offset); - free (buf); - break; - } - - if (phys_page != 0 && insn_page == 0) - { - /* xgettext:c-format */ - msg = _("reference to a banked address [%lx:%04lx] in the " - "normal address space at %04lx"); - buf = xmalloc (strlen (msg) + 128); - sprintf (buf, msg, phys_page, phys_addr, insn_addr); - (*info->callbacks->warning) (info, buf, name, input_bfd, - input_section, insn_addr); - free (buf); - relocation = phys_addr; - break; - } - - /* If this is a banked address use the phys_addr so that - we stay in the banked window. */ - if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend)) - relocation = phys_addr; - break; - } - - /* If we are linking an XGATE instruction against an S12 symbol, we - need to change the offset of the symbol value so that it's correct - from the XGATE's perspective. */ - if (!strcmp (howto->name, "R_XGATE_IMM8_LO") - || !strcmp (howto->name, "R_XGATE_IMM8_HI")) - { - /* We can only offset S12 addresses that lie within the non-paged - area of RAM. */ - if (!is_xgate_symbol && !is_section_symbol) - { - /* The ram in the global space is mapped to 0x2000 and stops at - 0x4000 in the 16-bit address space for S12 and 0xE000 in the - 16-bit address space for XGATE. */ - if (relocation >= 0x2000 && relocation < 0x4000) - /* We offset the address by the difference - between these two mappings. */ - relocation += 0xC000; - else - { - /* Get virtual address of instruction having the relocation. */ - insn_addr = input_section->output_section->vma - + input_section->output_offset + rel->r_offset; - - msg = _("S12 address (%lx) is not within shared RAM" - "(0x2000-0x4000), therefore you must manually " - "offset the address in your code"); - buf = xmalloc (strlen (msg) + 128); - sprintf (buf, msg, phys_addr); - (*info->callbacks->warning) (info, buf, name, input_bfd, - input_section, insn_addr); - free (buf); - break; - } - } - } - - if (r_type != R_M68HC11_NONE) - { - if ((r_type == R_M68HC12_PCREL_9) || (r_type == R_M68HC12_PCREL_10)) - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation - 2, rel->r_addend); - else - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, NULL, name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _ ("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _ ("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _ ("internal error: dangerous error"); - goto common_error; - - default: - msg = _ ("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - - - -/* Set and control ELF flags in ELF header. */ - -bfd_boolean -_bfd_m68hc11_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -bfd_boolean -_bfd_m68hc11_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - bfd_boolean ok = TRUE; - - /* Check if we have the same endianness */ - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - new_flags = elf_elfheader (ibfd)->e_flags; - elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI; - old_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - elf_elfheader (obfd)->e_ident[EI_CLASS] - = elf_elfheader (ibfd)->e_ident[EI_CLASS]; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - { - if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd))) - return FALSE; - } - - return TRUE; - } - - /* Check ABI compatibility. */ - if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32)) - { - _bfd_error_handler - (_("%B: linking files compiled for 16-bit integers (-mshort) " - "and others for 32-bit integers"), ibfd); - ok = FALSE; - } - if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64)) - { - _bfd_error_handler - (_("%B: linking files compiled for 32-bit double (-fshort-double) " - "and others for 64-bit double"), ibfd); - ok = FALSE; - } - - /* Processor compatibility. */ - if (!EF_M68HC11_CAN_MERGE_MACH (new_flags, old_flags)) - { - _bfd_error_handler - (_("%B: linking files compiled for HCS12 with " - "others compiled for HC12"), ibfd); - ok = FALSE; - } - new_flags = ((new_flags & ~EF_M68HC11_MACH_MASK) - | (EF_M68HC11_MERGE_MACH (new_flags, old_flags))); - - elf_elfheader (obfd)->e_flags = new_flags; - - new_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK); - old_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK); - - /* Warn about any other mismatches */ - if (new_flags != old_flags) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields than previous modules (%#x)"), - ibfd, new_flags, old_flags); - ok = FALSE; - } - - if (! ok) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - return TRUE; -} - -bfd_boolean -_bfd_m68hc11_elf_print_private_bfd_data (bfd *abfd, void *ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32) - fprintf (file, _("[abi=32-bit int, ")); - else - fprintf (file, _("[abi=16-bit int, ")); - - if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64) - fprintf (file, _("64-bit double, ")); - else - fprintf (file, _("32-bit double, ")); - - if (strcmp (bfd_get_target (abfd), "elf32-m68hc11") == 0) - fprintf (file, _("cpu=HC11]")); - else if (elf_elfheader (abfd)->e_flags & EF_M68HCS12_MACH) - fprintf (file, _("cpu=HCS12]")); - else - fprintf (file, _("cpu=HC12]")); - - if (elf_elfheader (abfd)->e_flags & E_M68HC12_BANKS) - fprintf (file, _(" [memory=bank-model]")); - else - fprintf (file, _(" [memory=flat]")); - - if (elf_elfheader (abfd)->e_flags & E_M68HC11_XGATE_RAMOFFSET) - fprintf (file, _(" [XGATE RAM offsetting]")); - - fputc ('\n', file); - - return TRUE; -} - -static void scan_sections_for_abi (bfd *abfd ATTRIBUTE_UNUSED, - asection *asect, void *arg) -{ - struct m68hc11_scan_param* p = (struct m68hc11_scan_param*) arg; - - if (asect->vma >= p->pinfo->bank_virtual) - p->use_memory_banks = TRUE; -} - -/* Tweak the OSABI field of the elf header. */ - -void -elf32_m68hc11_post_process_headers (bfd *abfd, struct bfd_link_info *link_info) -{ - struct m68hc11_scan_param param; - struct m68hc11_elf_link_hash_table *htab; - - if (link_info == NULL) - return; - - htab = m68hc11_elf_hash_table (link_info); - if (htab == NULL) - return; - - m68hc11_elf_get_bank_parameters (link_info); - - param.use_memory_banks = FALSE; - param.pinfo = & htab->pinfo; - - bfd_map_over_sections (abfd, scan_sections_for_abi, ¶m); - - if (param.use_memory_banks) - { - Elf_Internal_Ehdr * i_ehdrp; - - i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_flags |= E_M68HC12_BANKS; - } -} diff --git a/sdcc/support/sdbinutils/bfd/elf32-m68hc1x.h b/sdcc/support/sdbinutils/bfd/elf32-m68hc1x.h deleted file mode 100644 index 5a0884dac..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m68hc1x.h +++ /dev/null @@ -1,193 +0,0 @@ -/* Motorola 68HC11/68HC12-specific support for 32-bit ELF - Copyright (C) 2003-2018 Free Software Foundation, Inc. - Contributed by Stephane Carrez (stcarrez@nerim.fr) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_M68HC1X_H -#define _ELF32_M68HC1X_H - -#include "elf-bfd.h" -#include "bfdlink.h" -#include "elf/m68hc11.h" - -/* Name of symbols exported by HC11/HC12 linker when there is a memory - bank window. */ -#define BFD_M68HC11_BANK_START_NAME "__bank_start" -#define BFD_M68HC11_BANK_SIZE_NAME "__bank_size" -#define BFD_M68HC11_BANK_VIRTUAL_NAME "__bank_virtual" - -/* Set and control ELF flags in ELF header. */ -extern bfd_boolean _bfd_m68hc11_elf_merge_private_bfd_data - (bfd *, struct bfd_link_info *); -extern bfd_boolean _bfd_m68hc11_elf_set_private_flags (bfd*,flagword); -extern bfd_boolean _bfd_m68hc11_elf_print_private_bfd_data (bfd*, void*); - -/* This hash entry is used to record a trampoline that must be generated - to call a far function using a normal calling convention ('jsr'). - The trampoline is used when a pointer to a far function is used. - It takes care of installing the proper memory bank as well as creating - the 'call/rtc' calling convention. */ -struct elf32_m68hc11_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; -}; - -/* Placeholder for the parameters to compute memory page and physical address. - The following formulas are used: - - sym > bank_virtual => - %addr(sym) = (((sym - bank_virtual) & bank_mask) + bank_physical - %page(sym) = (((sym - bank_virtual) >> bank_shift) % 256 - - sym < bank_virtual => - %addr(sym) = sym - %page(sym) = 0 - - - These parameters are obtained from the symbol table by looking - at the following: - - __bank_start Symbol marking the start of memory bank window - (bank_physical) - __bank_virtual Logical address of symbols for which the transformation - must be computed - __bank_page_size Size in bytes of page size (this is *NOT* the memory - bank window size and the window size is always - less or equal to the page size) - - For 68HC12, the window is at 0x8000 and the page size is 16K (full window). - For 68HC11 this is board specific (implemented by external hardware). */ - -struct m68hc11_page_info -{ - bfd_vma bank_virtual; - bfd_vma bank_physical; - bfd_vma bank_physical_end; - bfd_vma bank_mask; - bfd_vma bank_size; - int bank_shift; - int bank_param_initialized; - bfd_vma trampoline_addr; -}; - -struct m68hc11_elf_link_hash_table -{ - struct elf_link_hash_table root; - struct m68hc11_page_info pinfo; - - /* The stub hash table. */ - struct bfd_hash_table* stub_hash_table; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - asection* stub_section; - asection* tramp_section; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *); - - /* Assorted information used by elf32_hppa_size_stubs. */ - unsigned int bfd_count; - int top_index; - asection **input_list; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - bfd_boolean (* size_one_stub) (struct bfd_hash_entry*, void*); - bfd_boolean (* build_one_stub) (struct bfd_hash_entry*, void*); -}; - -/* Get the Sparc64 ELF linker hash table from a link_info structure. */ - -#define m68hc11_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == M68HC11_ELF_DATA ? ((struct m68hc11_elf_link_hash_table *) ((p)->hash)) : NULL) - -/* Create a 68HC11/68HC12 ELF linker hash table. */ - -extern struct m68hc11_elf_link_hash_table* m68hc11_elf_hash_table_create - (bfd*); - -extern void m68hc11_elf_get_bank_parameters (struct bfd_link_info*); - -/* Return 1 if the address is in banked memory. - This can be applied to a virtual address and to a physical address. */ -extern int m68hc11_addr_is_banked (struct m68hc11_page_info*, bfd_vma); - -/* Return the physical address seen by the processor, taking - into account banked memory. */ -extern bfd_vma m68hc11_phys_addr (struct m68hc11_page_info*, bfd_vma); - -/* Return the page number corresponding to an address in banked memory. */ -extern bfd_vma m68hc11_phys_page (struct m68hc11_page_info*, bfd_vma); - -bfd_reloc_status_type m68hc11_elf_ignore_reloc - (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, asection *input_section, - bfd *output_bfd, char **error_message); -bfd_reloc_status_type m68hc11_elf_special_reloc - (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, asection *input_section, - bfd *output_bfd, char **error_message); - -bfd_boolean elf32_m68hc11_check_relocs - (bfd * abfd, struct bfd_link_info * info, - asection * sec, const Elf_Internal_Rela * relocs); -bfd_boolean elf32_m68hc11_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); - -bfd_boolean elf32_m68hc11_add_symbol_hook - (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, const char **namep, - flagword *flagsp, asection **secp, - bfd_vma *valp); - -void elf32_m68hc11_merge_symbol_attribute - (struct elf_link_hash_entry *, const Elf_Internal_Sym *, - bfd_boolean, bfd_boolean); - -/* Tweak the OSABI field of the elf header. */ - -extern void elf32_m68hc11_post_process_headers (bfd*, struct bfd_link_info*); - -int elf32_m68hc11_setup_section_lists (bfd *, struct bfd_link_info *); - -bfd_boolean elf32_m68hc11_size_stubs - (bfd *, bfd *, struct bfd_link_info *, - asection * (*) (const char *, asection *)); - -bfd_boolean elf32_m68hc11_build_stubs (bfd* abfd, struct bfd_link_info *); -#endif diff --git a/sdcc/support/sdbinutils/bfd/elf32-m68k.c b/sdcc/support/sdbinutils/bfd/elf32-m68k.c deleted file mode 100644 index 112067bbe..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m68k.c +++ /dev/null @@ -1,4657 +0,0 @@ -/* Motorola 68k series support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/m68k.h" -#include "opcode/m68k.h" - -static bfd_boolean -elf_m68k_discard_copies (struct elf_link_hash_entry *, void *); - -static reloc_howto_type howto_table[] = -{ - HOWTO(R_68K_NONE, 0, 3, 0, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_NONE", FALSE, 0, 0x00000000,FALSE), - HOWTO(R_68K_32, 0, 2,32, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_32", FALSE, 0, 0xffffffff,FALSE), - HOWTO(R_68K_16, 0, 1,16, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_16", FALSE, 0, 0x0000ffff,FALSE), - HOWTO(R_68K_8, 0, 0, 8, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_8", FALSE, 0, 0x000000ff,FALSE), - HOWTO(R_68K_PC32, 0, 2,32, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_PC32", FALSE, 0, 0xffffffff,TRUE), - HOWTO(R_68K_PC16, 0, 1,16, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PC16", FALSE, 0, 0x0000ffff,TRUE), - HOWTO(R_68K_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PC8", FALSE, 0, 0x000000ff,TRUE), - HOWTO(R_68K_GOT32, 0, 2,32, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_GOT32", FALSE, 0, 0xffffffff,TRUE), - HOWTO(R_68K_GOT16, 0, 1,16, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT16", FALSE, 0, 0x0000ffff,TRUE), - HOWTO(R_68K_GOT8, 0, 0, 8, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT8", FALSE, 0, 0x000000ff,TRUE), - HOWTO(R_68K_GOT32O, 0, 2,32, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_GOT32O", FALSE, 0, 0xffffffff,FALSE), - HOWTO(R_68K_GOT16O, 0, 1,16, FALSE,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT16O", FALSE, 0, 0x0000ffff,FALSE), - HOWTO(R_68K_GOT8O, 0, 0, 8, FALSE,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_GOT8O", FALSE, 0, 0x000000ff,FALSE), - HOWTO(R_68K_PLT32, 0, 2,32, TRUE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_PLT32", FALSE, 0, 0xffffffff,TRUE), - HOWTO(R_68K_PLT16, 0, 1,16, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT16", FALSE, 0, 0x0000ffff,TRUE), - HOWTO(R_68K_PLT8, 0, 0, 8, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT8", FALSE, 0, 0x000000ff,TRUE), - HOWTO(R_68K_PLT32O, 0, 2,32, FALSE,0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_68K_PLT32O", FALSE, 0, 0xffffffff,FALSE), - HOWTO(R_68K_PLT16O, 0, 1,16, FALSE,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT16O", FALSE, 0, 0x0000ffff,FALSE), - HOWTO(R_68K_PLT8O, 0, 0, 8, FALSE,0, complain_overflow_signed, bfd_elf_generic_reloc, "R_68K_PLT8O", FALSE, 0, 0x000000ff,FALSE), - HOWTO(R_68K_COPY, 0, 0, 0, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_COPY", FALSE, 0, 0xffffffff,FALSE), - HOWTO(R_68K_GLOB_DAT, 0, 2,32, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_GLOB_DAT", FALSE, 0, 0xffffffff,FALSE), - HOWTO(R_68K_JMP_SLOT, 0, 2,32, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_JMP_SLOT", FALSE, 0, 0xffffffff,FALSE), - HOWTO(R_68K_RELATIVE, 0, 2,32, FALSE,0, complain_overflow_dont, bfd_elf_generic_reloc, "R_68K_RELATIVE", FALSE, 0, 0xffffffff,FALSE), - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_68K_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_68K_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_68K_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_68K_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), - - /* TLS general dynamic variable reference. */ - HOWTO (R_68K_TLS_GD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_GD32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_GD16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_GD16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_GD8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_GD8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_68K_TLS_LDM32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LDM32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LDM16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LDM16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LDM8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LDM8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LDO32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LDO32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LDO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LDO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LDO8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LDO8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS initial execution variable reference. */ - HOWTO (R_68K_TLS_IE32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_IE32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_IE16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_IE16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_IE8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_IE8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local execution variable reference. */ - HOWTO (R_68K_TLS_LE32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LE32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LE16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LE16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_LE8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_LE8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS GD/LD dynamic relocations. */ - HOWTO (R_68K_TLS_DTPMOD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_DTPMOD32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_DTPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_DTPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_68K_TLS_TPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_68K_TLS_TPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static void -rtype_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int indx = ELF32_R_TYPE (dst->r_info); - - if (indx >= (unsigned int) R_68K_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) indx); - indx = R_68K_NONE; - } - cache_ptr->howto = &howto_table[indx]; -} - -#define elf_info_to_howto rtype_to_howto - -static const struct -{ - bfd_reloc_code_real_type bfd_val; - int elf_val; -} - reloc_map[] = -{ - { BFD_RELOC_NONE, R_68K_NONE }, - { BFD_RELOC_32, R_68K_32 }, - { BFD_RELOC_16, R_68K_16 }, - { BFD_RELOC_8, R_68K_8 }, - { BFD_RELOC_32_PCREL, R_68K_PC32 }, - { BFD_RELOC_16_PCREL, R_68K_PC16 }, - { BFD_RELOC_8_PCREL, R_68K_PC8 }, - { BFD_RELOC_32_GOT_PCREL, R_68K_GOT32 }, - { BFD_RELOC_16_GOT_PCREL, R_68K_GOT16 }, - { BFD_RELOC_8_GOT_PCREL, R_68K_GOT8 }, - { BFD_RELOC_32_GOTOFF, R_68K_GOT32O }, - { BFD_RELOC_16_GOTOFF, R_68K_GOT16O }, - { BFD_RELOC_8_GOTOFF, R_68K_GOT8O }, - { BFD_RELOC_32_PLT_PCREL, R_68K_PLT32 }, - { BFD_RELOC_16_PLT_PCREL, R_68K_PLT16 }, - { BFD_RELOC_8_PLT_PCREL, R_68K_PLT8 }, - { BFD_RELOC_32_PLTOFF, R_68K_PLT32O }, - { BFD_RELOC_16_PLTOFF, R_68K_PLT16O }, - { BFD_RELOC_8_PLTOFF, R_68K_PLT8O }, - { BFD_RELOC_NONE, R_68K_COPY }, - { BFD_RELOC_68K_GLOB_DAT, R_68K_GLOB_DAT }, - { BFD_RELOC_68K_JMP_SLOT, R_68K_JMP_SLOT }, - { BFD_RELOC_68K_RELATIVE, R_68K_RELATIVE }, - { BFD_RELOC_CTOR, R_68K_32 }, - { BFD_RELOC_VTABLE_INHERIT, R_68K_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_68K_GNU_VTENTRY }, - { BFD_RELOC_68K_TLS_GD32, R_68K_TLS_GD32 }, - { BFD_RELOC_68K_TLS_GD16, R_68K_TLS_GD16 }, - { BFD_RELOC_68K_TLS_GD8, R_68K_TLS_GD8 }, - { BFD_RELOC_68K_TLS_LDM32, R_68K_TLS_LDM32 }, - { BFD_RELOC_68K_TLS_LDM16, R_68K_TLS_LDM16 }, - { BFD_RELOC_68K_TLS_LDM8, R_68K_TLS_LDM8 }, - { BFD_RELOC_68K_TLS_LDO32, R_68K_TLS_LDO32 }, - { BFD_RELOC_68K_TLS_LDO16, R_68K_TLS_LDO16 }, - { BFD_RELOC_68K_TLS_LDO8, R_68K_TLS_LDO8 }, - { BFD_RELOC_68K_TLS_IE32, R_68K_TLS_IE32 }, - { BFD_RELOC_68K_TLS_IE16, R_68K_TLS_IE16 }, - { BFD_RELOC_68K_TLS_IE8, R_68K_TLS_IE8 }, - { BFD_RELOC_68K_TLS_LE32, R_68K_TLS_LE32 }, - { BFD_RELOC_68K_TLS_LE16, R_68K_TLS_LE16 }, - { BFD_RELOC_68K_TLS_LE8, R_68K_TLS_LE8 }, -}; - -static reloc_howto_type * -reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - for (i = 0; i < sizeof (reloc_map) / sizeof (reloc_map[0]); i++) - { - if (reloc_map[i].bfd_val == code) - return &howto_table[reloc_map[i].elf_val]; - } - return 0; -} - -static reloc_howto_type * -reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) - if (howto_table[i].name != NULL - && strcasecmp (howto_table[i].name, r_name) == 0) - return &howto_table[i]; - - return NULL; -} - -#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup reloc_name_lookup -#define ELF_ARCH bfd_arch_m68k -#define ELF_TARGET_ID M68K_ELF_DATA - -/* Functions for the m68k ELF linker. */ - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" - -/* Describes one of the various PLT styles. */ - -struct elf_m68k_plt_info -{ - /* The size of each PLT entry. */ - bfd_vma size; - - /* The template for the first PLT entry. */ - const bfd_byte *plt0_entry; - - /* Offsets of fields in PLT0_ENTRY that require R_68K_PC32 relocations. - The comments by each member indicate the value that the relocation - is against. */ - struct { - unsigned int got4; /* .got + 4 */ - unsigned int got8; /* .got + 8 */ - } plt0_relocs; - - /* The template for a symbol's PLT entry. */ - const bfd_byte *symbol_entry; - - /* Offsets of fields in SYMBOL_ENTRY that require R_68K_PC32 relocations. - The comments by each member indicate the value that the relocation - is against. */ - struct { - unsigned int got; /* the symbol's .got.plt entry */ - unsigned int plt; /* .plt */ - } symbol_relocs; - - /* The offset of the resolver stub from the start of SYMBOL_ENTRY. - The stub starts with "move.l #relocoffset,%d0". */ - bfd_vma symbol_resolve_entry; -}; - -/* The size in bytes of an entry in the procedure linkage table. */ - -#define PLT_ENTRY_SIZE 20 - -/* The first entry in a procedure linkage table looks like this. See - the SVR4 ABI m68k supplement to see how this works. */ - -static const bfd_byte elf_m68k_plt0_entry[PLT_ENTRY_SIZE] = -{ - 0x2f, 0x3b, 0x01, 0x70, /* move.l (%pc,addr),-(%sp) */ - 0, 0, 0, 2, /* + (.got + 4) - . */ - 0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,addr]) */ - 0, 0, 0, 2, /* + (.got + 8) - . */ - 0, 0, 0, 0 /* pad out to 20 bytes. */ -}; - -/* Subsequent entries in a procedure linkage table look like this. */ - -static const bfd_byte elf_m68k_plt_entry[PLT_ENTRY_SIZE] = -{ - 0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,symbol@GOTPC]) */ - 0, 0, 0, 2, /* + (.got.plt entry) - . */ - 0x2f, 0x3c, /* move.l #offset,-(%sp) */ - 0, 0, 0, 0, /* + reloc index */ - 0x60, 0xff, /* bra.l .plt */ - 0, 0, 0, 0 /* + .plt - . */ -}; - -static const struct elf_m68k_plt_info elf_m68k_plt_info = -{ - PLT_ENTRY_SIZE, - elf_m68k_plt0_entry, { 4, 12 }, - elf_m68k_plt_entry, { 4, 16 }, 8 -}; - -#define ISAB_PLT_ENTRY_SIZE 24 - -static const bfd_byte elf_isab_plt0_entry[ISAB_PLT_ENTRY_SIZE] = -{ - 0x20, 0x3c, /* move.l #offset,%d0 */ - 0, 0, 0, 0, /* + (.got + 4) - . */ - 0x2f, 0x3b, 0x08, 0xfa, /* move.l (-6,%pc,%d0:l),-(%sp) */ - 0x20, 0x3c, /* move.l #offset,%d0 */ - 0, 0, 0, 0, /* + (.got + 8) - . */ - 0x20, 0x7b, 0x08, 0xfa, /* move.l (-6,%pc,%d0:l), %a0 */ - 0x4e, 0xd0, /* jmp (%a0) */ - 0x4e, 0x71 /* nop */ -}; - -/* Subsequent entries in a procedure linkage table look like this. */ - -static const bfd_byte elf_isab_plt_entry[ISAB_PLT_ENTRY_SIZE] = -{ - 0x20, 0x3c, /* move.l #offset,%d0 */ - 0, 0, 0, 0, /* + (.got.plt entry) - . */ - 0x20, 0x7b, 0x08, 0xfa, /* move.l (-6,%pc,%d0:l), %a0 */ - 0x4e, 0xd0, /* jmp (%a0) */ - 0x2f, 0x3c, /* move.l #offset,-(%sp) */ - 0, 0, 0, 0, /* + reloc index */ - 0x60, 0xff, /* bra.l .plt */ - 0, 0, 0, 0 /* + .plt - . */ -}; - -static const struct elf_m68k_plt_info elf_isab_plt_info = -{ - ISAB_PLT_ENTRY_SIZE, - elf_isab_plt0_entry, { 2, 12 }, - elf_isab_plt_entry, { 2, 20 }, 12 -}; - -#define ISAC_PLT_ENTRY_SIZE 24 - -static const bfd_byte elf_isac_plt0_entry[ISAC_PLT_ENTRY_SIZE] = -{ - 0x20, 0x3c, /* move.l #offset,%d0 */ - 0, 0, 0, 0, /* replaced with .got + 4 - . */ - 0x2e, 0xbb, 0x08, 0xfa, /* move.l (-6,%pc,%d0:l),(%sp) */ - 0x20, 0x3c, /* move.l #offset,%d0 */ - 0, 0, 0, 0, /* replaced with .got + 8 - . */ - 0x20, 0x7b, 0x08, 0xfa, /* move.l (-6,%pc,%d0:l), %a0 */ - 0x4e, 0xd0, /* jmp (%a0) */ - 0x4e, 0x71 /* nop */ -}; - -/* Subsequent entries in a procedure linkage table look like this. */ - -static const bfd_byte elf_isac_plt_entry[ISAC_PLT_ENTRY_SIZE] = -{ - 0x20, 0x3c, /* move.l #offset,%d0 */ - 0, 0, 0, 0, /* replaced with (.got entry) - . */ - 0x20, 0x7b, 0x08, 0xfa, /* move.l (-6,%pc,%d0:l), %a0 */ - 0x4e, 0xd0, /* jmp (%a0) */ - 0x2f, 0x3c, /* move.l #offset,-(%sp) */ - 0, 0, 0, 0, /* replaced with offset into relocation table */ - 0x61, 0xff, /* bsr.l .plt */ - 0, 0, 0, 0 /* replaced with .plt - . */ -}; - -static const struct elf_m68k_plt_info elf_isac_plt_info = -{ - ISAC_PLT_ENTRY_SIZE, - elf_isac_plt0_entry, { 2, 12}, - elf_isac_plt_entry, { 2, 20 }, 12 -}; - -#define CPU32_PLT_ENTRY_SIZE 24 -/* Procedure linkage table entries for the cpu32 */ -static const bfd_byte elf_cpu32_plt0_entry[CPU32_PLT_ENTRY_SIZE] = -{ - 0x2f, 0x3b, 0x01, 0x70, /* move.l (%pc,addr),-(%sp) */ - 0, 0, 0, 2, /* + (.got + 4) - . */ - 0x22, 0x7b, 0x01, 0x70, /* moveal %pc@(0xc), %a1 */ - 0, 0, 0, 2, /* + (.got + 8) - . */ - 0x4e, 0xd1, /* jmp %a1@ */ - 0, 0, 0, 0, /* pad out to 24 bytes. */ - 0, 0 -}; - -static const bfd_byte elf_cpu32_plt_entry[CPU32_PLT_ENTRY_SIZE] = -{ - 0x22, 0x7b, 0x01, 0x70, /* moveal %pc@(0xc), %a1 */ - 0, 0, 0, 2, /* + (.got.plt entry) - . */ - 0x4e, 0xd1, /* jmp %a1@ */ - 0x2f, 0x3c, /* move.l #offset,-(%sp) */ - 0, 0, 0, 0, /* + reloc index */ - 0x60, 0xff, /* bra.l .plt */ - 0, 0, 0, 0, /* + .plt - . */ - 0, 0 -}; - -static const struct elf_m68k_plt_info elf_cpu32_plt_info = -{ - CPU32_PLT_ENTRY_SIZE, - elf_cpu32_plt0_entry, { 4, 12 }, - elf_cpu32_plt_entry, { 4, 18 }, 10 -}; - -/* The m68k linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that it - can discard PC relative relocs if it doesn't need them when linking - with -Bsymbolic. We store the information in a field extending the - regular ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we have - copied for a given symbol. */ - -struct elf_m68k_pcrel_relocs_copied -{ - /* Next section. */ - struct elf_m68k_pcrel_relocs_copied *next; - /* A section in dynobj. */ - asection *section; - /* Number of relocs copied in this section. */ - bfd_size_type count; -}; - -/* Forward declaration. */ -struct elf_m68k_got_entry; - -/* m68k ELF linker hash entry. */ - -struct elf_m68k_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Number of PC relative relocs copied for this symbol. */ - struct elf_m68k_pcrel_relocs_copied *pcrel_relocs_copied; - - /* Key to got_entries. */ - unsigned long got_entry_key; - - /* List of GOT entries for this symbol. This list is build during - offset finalization and is used within elf_m68k_finish_dynamic_symbol - to traverse all GOT entries for a particular symbol. - - ??? We could've used root.got.glist field instead, but having - a separate field is cleaner. */ - struct elf_m68k_got_entry *glist; -}; - -#define elf_m68k_hash_entry(ent) ((struct elf_m68k_link_hash_entry *) (ent)) - -/* Key part of GOT entry in hashtable. */ -struct elf_m68k_got_entry_key -{ - /* BFD in which this symbol was defined. NULL for global symbols. */ - const bfd *bfd; - - /* Symbol index. Either local symbol index or h->got_entry_key. */ - unsigned long symndx; - - /* Type is one of R_68K_GOT{8, 16, 32}O, R_68K_TLS_GD{8, 16, 32}, - R_68K_TLS_LDM{8, 16, 32} or R_68K_TLS_IE{8, 16, 32}. - - From perspective of hashtable key, only elf_m68k_got_reloc_type (type) - matters. That is, we distinguish between, say, R_68K_GOT16O - and R_68K_GOT32O when allocating offsets, but they are considered to be - the same when searching got->entries. */ - enum elf_m68k_reloc_type type; -}; - -/* Size of the GOT offset suitable for relocation. */ -enum elf_m68k_got_offset_size { R_8, R_16, R_32, R_LAST }; - -/* Entry of the GOT. */ -struct elf_m68k_got_entry -{ - /* GOT entries are put into a got->entries hashtable. This is the key. */ - struct elf_m68k_got_entry_key key_; - - /* GOT entry data. We need s1 before offset finalization and s2 after. */ - union - { - struct - { - /* Number of times this entry is referenced. */ - bfd_vma refcount; - } s1; - - struct - { - /* Offset from the start of .got section. To calculate offset relative - to GOT pointer one should subtract got->offset from this value. */ - bfd_vma offset; - - /* Pointer to the next GOT entry for this global symbol. - Symbols have at most one entry in one GOT, but might - have entries in more than one GOT. - Root of this list is h->glist. - NULL for local symbols. */ - struct elf_m68k_got_entry *next; - } s2; - } u; -}; - -/* Return representative type for relocation R_TYPE. - This is used to avoid enumerating many relocations in comparisons, - switches etc. */ - -static enum elf_m68k_reloc_type -elf_m68k_reloc_got_type (enum elf_m68k_reloc_type r_type) -{ - switch (r_type) - { - /* In most cases R_68K_GOTx relocations require the very same - handling as R_68K_GOT32O relocation. In cases when we need - to distinguish between the two, we use explicitly compare against - r_type. */ - case R_68K_GOT32: - case R_68K_GOT16: - case R_68K_GOT8: - case R_68K_GOT32O: - case R_68K_GOT16O: - case R_68K_GOT8O: - return R_68K_GOT32O; - - case R_68K_TLS_GD32: - case R_68K_TLS_GD16: - case R_68K_TLS_GD8: - return R_68K_TLS_GD32; - - case R_68K_TLS_LDM32: - case R_68K_TLS_LDM16: - case R_68K_TLS_LDM8: - return R_68K_TLS_LDM32; - - case R_68K_TLS_IE32: - case R_68K_TLS_IE16: - case R_68K_TLS_IE8: - return R_68K_TLS_IE32; - - default: - BFD_ASSERT (FALSE); - return 0; - } -} - -/* Return size of the GOT entry offset for relocation R_TYPE. */ - -static enum elf_m68k_got_offset_size -elf_m68k_reloc_got_offset_size (enum elf_m68k_reloc_type r_type) -{ - switch (r_type) - { - case R_68K_GOT32: case R_68K_GOT16: case R_68K_GOT8: - case R_68K_GOT32O: case R_68K_TLS_GD32: case R_68K_TLS_LDM32: - case R_68K_TLS_IE32: - return R_32; - - case R_68K_GOT16O: case R_68K_TLS_GD16: case R_68K_TLS_LDM16: - case R_68K_TLS_IE16: - return R_16; - - case R_68K_GOT8O: case R_68K_TLS_GD8: case R_68K_TLS_LDM8: - case R_68K_TLS_IE8: - return R_8; - - default: - BFD_ASSERT (FALSE); - return 0; - } -} - -/* Return number of GOT entries we need to allocate in GOT for - relocation R_TYPE. */ - -static bfd_vma -elf_m68k_reloc_got_n_slots (enum elf_m68k_reloc_type r_type) -{ - switch (elf_m68k_reloc_got_type (r_type)) - { - case R_68K_GOT32O: - case R_68K_TLS_IE32: - return 1; - - case R_68K_TLS_GD32: - case R_68K_TLS_LDM32: - return 2; - - default: - BFD_ASSERT (FALSE); - return 0; - } -} - -/* Return TRUE if relocation R_TYPE is a TLS one. */ - -static bfd_boolean -elf_m68k_reloc_tls_p (enum elf_m68k_reloc_type r_type) -{ - switch (r_type) - { - case R_68K_TLS_GD32: case R_68K_TLS_GD16: case R_68K_TLS_GD8: - case R_68K_TLS_LDM32: case R_68K_TLS_LDM16: case R_68K_TLS_LDM8: - case R_68K_TLS_LDO32: case R_68K_TLS_LDO16: case R_68K_TLS_LDO8: - case R_68K_TLS_IE32: case R_68K_TLS_IE16: case R_68K_TLS_IE8: - case R_68K_TLS_LE32: case R_68K_TLS_LE16: case R_68K_TLS_LE8: - case R_68K_TLS_DTPMOD32: case R_68K_TLS_DTPREL32: case R_68K_TLS_TPREL32: - return TRUE; - - default: - return FALSE; - } -} - -/* Data structure representing a single GOT. */ -struct elf_m68k_got -{ - /* Hashtable of 'struct elf_m68k_got_entry's. - Starting size of this table is the maximum number of - R_68K_GOT8O entries. */ - htab_t entries; - - /* Number of R_x slots in this GOT. Some (e.g., TLS) entries require - several GOT slots. - - n_slots[R_8] is the count of R_8 slots in this GOT. - n_slots[R_16] is the cumulative count of R_8 and R_16 slots - in this GOT. - n_slots[R_32] is the cumulative count of R_8, R_16 and R_32 slots - in this GOT. This is the total number of slots. */ - bfd_vma n_slots[R_LAST]; - - /* Number of local (entry->key_.h == NULL) slots in this GOT. - This is only used to properly calculate size of .rela.got section; - see elf_m68k_partition_multi_got. */ - bfd_vma local_n_slots; - - /* Offset of this GOT relative to beginning of .got section. */ - bfd_vma offset; -}; - -/* BFD and its GOT. This is an entry in multi_got->bfd2got hashtable. */ -struct elf_m68k_bfd2got_entry -{ - /* BFD. */ - const bfd *bfd; - - /* Assigned GOT. Before partitioning multi-GOT each BFD has its own - GOT structure. After partitioning several BFD's might [and often do] - share a single GOT. */ - struct elf_m68k_got *got; -}; - -/* The main data structure holding all the pieces. */ -struct elf_m68k_multi_got -{ - /* Hashtable mapping each BFD to its GOT. If a BFD doesn't have an entry - here, then it doesn't need a GOT (this includes the case of a BFD - having an empty GOT). - - ??? This hashtable can be replaced by an array indexed by bfd->id. */ - htab_t bfd2got; - - /* Next symndx to assign a global symbol. - h->got_entry_key is initialized from this counter. */ - unsigned long global_symndx; -}; - -/* m68k ELF linker hash table. */ - -struct elf_m68k_link_hash_table -{ - struct elf_link_hash_table root; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* The PLT format used by this link, or NULL if the format has not - yet been chosen. */ - const struct elf_m68k_plt_info *plt_info; - - /* True, if GP is loaded within each function which uses it. - Set to TRUE when GOT negative offsets or multi-GOT is enabled. */ - bfd_boolean local_gp_p; - - /* Switch controlling use of negative offsets to double the size of GOTs. */ - bfd_boolean use_neg_got_offsets_p; - - /* Switch controlling generation of multiple GOTs. */ - bfd_boolean allow_multigot_p; - - /* Multi-GOT data structure. */ - struct elf_m68k_multi_got multi_got_; -}; - -/* Get the m68k ELF linker hash table from a link_info structure. */ - -#define elf_m68k_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == M68K_ELF_DATA ? ((struct elf_m68k_link_hash_table *) ((p)->hash)) : NULL) - -/* Shortcut to multi-GOT data. */ -#define elf_m68k_multi_got(INFO) (&elf_m68k_hash_table (INFO)->multi_got_) - -/* Create an entry in an m68k ELF linker hash table. */ - -static struct bfd_hash_entry * -elf_m68k_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct bfd_hash_entry *ret = entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, - sizeof (struct elf_m68k_link_hash_entry)); - if (ret == NULL) - return ret; - - /* Call the allocation method of the superclass. */ - ret = _bfd_elf_link_hash_newfunc (ret, table, string); - if (ret != NULL) - { - elf_m68k_hash_entry (ret)->pcrel_relocs_copied = NULL; - elf_m68k_hash_entry (ret)->got_entry_key = 0; - elf_m68k_hash_entry (ret)->glist = NULL; - } - - return ret; -} - -/* Destroy an m68k ELF linker hash table. */ - -static void -elf_m68k_link_hash_table_free (bfd *obfd) -{ - struct elf_m68k_link_hash_table *htab; - - htab = (struct elf_m68k_link_hash_table *) obfd->link.hash; - - if (htab->multi_got_.bfd2got != NULL) - { - htab_delete (htab->multi_got_.bfd2got); - htab->multi_got_.bfd2got = NULL; - } - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create an m68k ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf_m68k_link_hash_table_create (bfd *abfd) -{ - struct elf_m68k_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_m68k_link_hash_table); - - ret = (struct elf_m68k_link_hash_table *) bfd_zmalloc (amt); - if (ret == (struct elf_m68k_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - elf_m68k_link_hash_newfunc, - sizeof (struct elf_m68k_link_hash_entry), - M68K_ELF_DATA)) - { - free (ret); - return NULL; - } - ret->root.root.hash_table_free = elf_m68k_link_hash_table_free; - - ret->multi_got_.global_symndx = 1; - - return &ret->root.root; -} - -/* Set the right machine number. */ - -static bfd_boolean -elf32_m68k_object_p (bfd *abfd) -{ - unsigned int mach = 0; - unsigned features = 0; - flagword eflags = elf_elfheader (abfd)->e_flags; - - if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_M68000) - features |= m68000; - else if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32) - features |= cpu32; - else if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO) - features |= fido_a; - else - { - switch (eflags & EF_M68K_CF_ISA_MASK) - { - case EF_M68K_CF_ISA_A_NODIV: - features |= mcfisa_a; - break; - case EF_M68K_CF_ISA_A: - features |= mcfisa_a|mcfhwdiv; - break; - case EF_M68K_CF_ISA_A_PLUS: - features |= mcfisa_a|mcfisa_aa|mcfhwdiv|mcfusp; - break; - case EF_M68K_CF_ISA_B_NOUSP: - features |= mcfisa_a|mcfisa_b|mcfhwdiv; - break; - case EF_M68K_CF_ISA_B: - features |= mcfisa_a|mcfisa_b|mcfhwdiv|mcfusp; - break; - case EF_M68K_CF_ISA_C: - features |= mcfisa_a|mcfisa_c|mcfhwdiv|mcfusp; - break; - case EF_M68K_CF_ISA_C_NODIV: - features |= mcfisa_a|mcfisa_c|mcfusp; - break; - } - switch (eflags & EF_M68K_CF_MAC_MASK) - { - case EF_M68K_CF_MAC: - features |= mcfmac; - break; - case EF_M68K_CF_EMAC: - features |= mcfemac; - break; - } - if (eflags & EF_M68K_CF_FLOAT) - features |= cfloat; - } - - mach = bfd_m68k_features_to_mach (features); - bfd_default_set_arch_mach (abfd, bfd_arch_m68k, mach); - - return TRUE; -} - -/* Somewhat reverse of elf32_m68k_object_p, this sets the e_flag - field based on the machine number. */ - -static void -elf_m68k_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - int mach = bfd_get_mach (abfd); - unsigned long e_flags = elf_elfheader (abfd)->e_flags; - - if (!e_flags) - { - unsigned int arch_mask; - - arch_mask = bfd_m68k_mach_to_features (mach); - - if (arch_mask & m68000) - e_flags = EF_M68K_M68000; - else if (arch_mask & cpu32) - e_flags = EF_M68K_CPU32; - else if (arch_mask & fido_a) - e_flags = EF_M68K_FIDO; - else - { - switch (arch_mask - & (mcfisa_a | mcfisa_aa | mcfisa_b | mcfisa_c | mcfhwdiv | mcfusp)) - { - case mcfisa_a: - e_flags |= EF_M68K_CF_ISA_A_NODIV; - break; - case mcfisa_a | mcfhwdiv: - e_flags |= EF_M68K_CF_ISA_A; - break; - case mcfisa_a | mcfisa_aa | mcfhwdiv | mcfusp: - e_flags |= EF_M68K_CF_ISA_A_PLUS; - break; - case mcfisa_a | mcfisa_b | mcfhwdiv: - e_flags |= EF_M68K_CF_ISA_B_NOUSP; - break; - case mcfisa_a | mcfisa_b | mcfhwdiv | mcfusp: - e_flags |= EF_M68K_CF_ISA_B; - break; - case mcfisa_a | mcfisa_c | mcfhwdiv | mcfusp: - e_flags |= EF_M68K_CF_ISA_C; - break; - case mcfisa_a | mcfisa_c | mcfusp: - e_flags |= EF_M68K_CF_ISA_C_NODIV; - break; - } - if (arch_mask & mcfmac) - e_flags |= EF_M68K_CF_MAC; - else if (arch_mask & mcfemac) - e_flags |= EF_M68K_CF_EMAC; - if (arch_mask & cfloat) - e_flags |= EF_M68K_CF_FLOAT | EF_M68K_CFV4E; - } - elf_elfheader (abfd)->e_flags = e_flags; - } -} - -/* Keep m68k-specific flags in the ELF header. */ - -static bfd_boolean -elf32_m68k_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ -static bfd_boolean -elf32_m68k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - flagword out_isa; - flagword in_isa; - const bfd_arch_info_type *arch_info; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return FALSE; - - /* Get the merged machine. This checks for incompatibility between - Coldfire & non-Coldfire flags, incompability between different - Coldfire ISAs, and incompability between different MAC types. */ - arch_info = bfd_arch_get_compatible (ibfd, obfd, FALSE); - if (!arch_info) - return FALSE; - - bfd_set_arch_mach (obfd, bfd_arch_m68k, arch_info->mach); - - in_flags = elf_elfheader (ibfd)->e_flags; - if (!elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - out_flags = in_flags; - } - else - { - out_flags = elf_elfheader (obfd)->e_flags; - unsigned int variant_mask; - - if ((in_flags & EF_M68K_ARCH_MASK) == EF_M68K_M68000) - variant_mask = 0; - else if ((in_flags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32) - variant_mask = 0; - else if ((in_flags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO) - variant_mask = 0; - else - variant_mask = EF_M68K_CF_ISA_MASK; - - in_isa = (in_flags & variant_mask); - out_isa = (out_flags & variant_mask); - if (in_isa > out_isa) - out_flags ^= in_isa ^ out_isa; - if (((in_flags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32 - && (out_flags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO) - || ((in_flags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO - && (out_flags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32)) - out_flags = EF_M68K_FIDO; - else - out_flags |= in_flags ^ in_isa; - } - elf_elfheader (obfd)->e_flags = out_flags; - - return TRUE; -} - -/* Display the flags field. */ - -static bfd_boolean -elf32_m68k_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - flagword eflags = elf_elfheader (abfd)->e_flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* Ignore init flag - it may not be set, despite the flags field containing valid data. */ - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_M68000) - fprintf (file, " [m68000]"); - else if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32) - fprintf (file, " [cpu32]"); - else if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO) - fprintf (file, " [fido]"); - else - { - if ((eflags & EF_M68K_ARCH_MASK) == EF_M68K_CFV4E) - fprintf (file, " [cfv4e]"); - - if (eflags & EF_M68K_CF_ISA_MASK) - { - char const *isa = _("unknown"); - char const *mac = _("unknown"); - char const *additional = ""; - - switch (eflags & EF_M68K_CF_ISA_MASK) - { - case EF_M68K_CF_ISA_A_NODIV: - isa = "A"; - additional = " [nodiv]"; - break; - case EF_M68K_CF_ISA_A: - isa = "A"; - break; - case EF_M68K_CF_ISA_A_PLUS: - isa = "A+"; - break; - case EF_M68K_CF_ISA_B_NOUSP: - isa = "B"; - additional = " [nousp]"; - break; - case EF_M68K_CF_ISA_B: - isa = "B"; - break; - case EF_M68K_CF_ISA_C: - isa = "C"; - break; - case EF_M68K_CF_ISA_C_NODIV: - isa = "C"; - additional = " [nodiv]"; - break; - } - fprintf (file, " [isa %s]%s", isa, additional); - - if (eflags & EF_M68K_CF_FLOAT) - fprintf (file, " [float]"); - - switch (eflags & EF_M68K_CF_MAC_MASK) - { - case 0: - mac = NULL; - break; - case EF_M68K_CF_MAC: - mac = "mac"; - break; - case EF_M68K_CF_EMAC: - mac = "emac"; - break; - case EF_M68K_CF_EMAC_B: - mac = "emac_b"; - break; - } - if (mac) - fprintf (file, " [%s]", mac); - } - } - - fputc ('\n', file); - - return TRUE; -} - -/* Multi-GOT support implementation design: - - Multi-GOT starts in check_relocs hook. There we scan all - relocations of a BFD and build a local GOT (struct elf_m68k_got) - for it. If a single BFD appears to require too many GOT slots with - R_68K_GOT8O or R_68K_GOT16O relocations, we fail with notification - to user. - After check_relocs has been invoked for each input BFD, we have - constructed a GOT for each input BFD. - - To minimize total number of GOTs required for a particular output BFD - (as some environments support only 1 GOT per output object) we try - to merge some of the GOTs to share an offset space. Ideally [and in most - cases] we end up with a single GOT. In cases when there are too many - restricted relocations (e.g., R_68K_GOT16O relocations) we end up with - several GOTs, assuming the environment can handle them. - - Partitioning is done in elf_m68k_partition_multi_got. We start with - an empty GOT and traverse bfd2got hashtable putting got_entries from - local GOTs to the new 'big' one. We do that by constructing an - intermediate GOT holding all the entries the local GOT has and the big - GOT lacks. Then we check if there is room in the big GOT to accomodate - all the entries from diff. On success we add those entries to the big - GOT; on failure we start the new 'big' GOT and retry the adding of - entries from the local GOT. Note that this retry will always succeed as - each local GOT doesn't overflow the limits. After partitioning we - end up with each bfd assigned one of the big GOTs. GOT entries in the - big GOTs are initialized with GOT offsets. Note that big GOTs are - positioned consequently in program space and represent a single huge GOT - to the outside world. - - After that we get to elf_m68k_relocate_section. There we - adjust relocations of GOT pointer (_GLOBAL_OFFSET_TABLE_) and symbol - relocations to refer to appropriate [assigned to current input_bfd] - big GOT. - - Notes: - - GOT entry type: We have several types of GOT entries. - * R_8 type is used in entries for symbols that have at least one - R_68K_GOT8O or R_68K_TLS_*8 relocation. We can have at most 0x40 - such entries in one GOT. - * R_16 type is used in entries for symbols that have at least one - R_68K_GOT16O or R_68K_TLS_*16 relocation and no R_8 relocations. - We can have at most 0x4000 such entries in one GOT. - * R_32 type is used in all other cases. We can have as many - such entries in one GOT as we'd like. - When counting relocations we have to include the count of the smaller - ranged relocations in the counts of the larger ranged ones in order - to correctly detect overflow. - - Sorting the GOT: In each GOT starting offsets are assigned to - R_8 entries, which are followed by R_16 entries, and - R_32 entries go at the end. See finalize_got_offsets for details. - - Negative GOT offsets: To double usable offset range of GOTs we use - negative offsets. As we assign entries with GOT offsets relative to - start of .got section, the offset values are positive. They become - negative only in relocate_section where got->offset value is - subtracted from them. - - 3 special GOT entries: There are 3 special GOT entries used internally - by loader. These entries happen to be placed to .got.plt section, - so we don't do anything about them in multi-GOT support. - - Memory management: All data except for hashtables - multi_got->bfd2got and got->entries are allocated on - elf_hash_table (info)->dynobj bfd (for this reason we pass 'info' - to most functions), so we don't need to care to free them. At the - moment of allocation hashtables are being linked into main data - structure (multi_got), all pieces of which are reachable from - elf_m68k_multi_got (info). We deallocate them in - elf_m68k_link_hash_table_free. */ - -/* Initialize GOT. */ - -static void -elf_m68k_init_got (struct elf_m68k_got *got) -{ - got->entries = NULL; - got->n_slots[R_8] = 0; - got->n_slots[R_16] = 0; - got->n_slots[R_32] = 0; - got->local_n_slots = 0; - got->offset = (bfd_vma) -1; -} - -/* Destruct GOT. */ - -static void -elf_m68k_clear_got (struct elf_m68k_got *got) -{ - if (got->entries != NULL) - { - htab_delete (got->entries); - got->entries = NULL; - } -} - -/* Create and empty GOT structure. INFO is the context where memory - should be allocated. */ - -static struct elf_m68k_got * -elf_m68k_create_empty_got (struct bfd_link_info *info) -{ - struct elf_m68k_got *got; - - got = bfd_alloc (elf_hash_table (info)->dynobj, sizeof (*got)); - if (got == NULL) - return NULL; - - elf_m68k_init_got (got); - - return got; -} - -/* Initialize KEY. */ - -static void -elf_m68k_init_got_entry_key (struct elf_m68k_got_entry_key *key, - struct elf_link_hash_entry *h, - const bfd *abfd, unsigned long symndx, - enum elf_m68k_reloc_type reloc_type) -{ - if (elf_m68k_reloc_got_type (reloc_type) == R_68K_TLS_LDM32) - /* All TLS_LDM relocations share a single GOT entry. */ - { - key->bfd = NULL; - key->symndx = 0; - } - else if (h != NULL) - /* Global symbols are identified with their got_entry_key. */ - { - key->bfd = NULL; - key->symndx = elf_m68k_hash_entry (h)->got_entry_key; - BFD_ASSERT (key->symndx != 0); - } - else - /* Local symbols are identified by BFD they appear in and symndx. */ - { - key->bfd = abfd; - key->symndx = symndx; - } - - key->type = reloc_type; -} - -/* Calculate hash of got_entry. - ??? Is it good? */ - -static hashval_t -elf_m68k_got_entry_hash (const void *_entry) -{ - const struct elf_m68k_got_entry_key *key; - - key = &((const struct elf_m68k_got_entry *) _entry)->key_; - - return (key->symndx - + (key->bfd != NULL ? (int) key->bfd->id : -1) - + elf_m68k_reloc_got_type (key->type)); -} - -/* Check if two got entries are equal. */ - -static int -elf_m68k_got_entry_eq (const void *_entry1, const void *_entry2) -{ - const struct elf_m68k_got_entry_key *key1; - const struct elf_m68k_got_entry_key *key2; - - key1 = &((const struct elf_m68k_got_entry *) _entry1)->key_; - key2 = &((const struct elf_m68k_got_entry *) _entry2)->key_; - - return (key1->bfd == key2->bfd - && key1->symndx == key2->symndx - && (elf_m68k_reloc_got_type (key1->type) - == elf_m68k_reloc_got_type (key2->type))); -} - -/* When using negative offsets, we allocate one extra R_8, one extra R_16 - and one extra R_32 slots to simplify handling of 2-slot entries during - offset allocation -- hence -1 for R_8 slots and -2 for R_16 slots. */ - -/* Maximal number of R_8 slots in a single GOT. */ -#define ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT(INFO) \ - (elf_m68k_hash_table (INFO)->use_neg_got_offsets_p \ - ? (0x40 - 1) \ - : 0x20) - -/* Maximal number of R_8 and R_16 slots in a single GOT. */ -#define ELF_M68K_R_8_16_MAX_N_SLOTS_IN_GOT(INFO) \ - (elf_m68k_hash_table (INFO)->use_neg_got_offsets_p \ - ? (0x4000 - 2) \ - : 0x2000) - -/* SEARCH - simply search the hashtable, don't insert new entries or fail when - the entry cannot be found. - FIND_OR_CREATE - search for an existing entry, but create new if there's - no such. - MUST_FIND - search for an existing entry and assert that it exist. - MUST_CREATE - assert that there's no such entry and create new one. */ -enum elf_m68k_get_entry_howto - { - SEARCH, - FIND_OR_CREATE, - MUST_FIND, - MUST_CREATE - }; - -/* Get or create (depending on HOWTO) entry with KEY in GOT. - INFO is context in which memory should be allocated (can be NULL if - HOWTO is SEARCH or MUST_FIND). */ - -static struct elf_m68k_got_entry * -elf_m68k_get_got_entry (struct elf_m68k_got *got, - const struct elf_m68k_got_entry_key *key, - enum elf_m68k_get_entry_howto howto, - struct bfd_link_info *info) -{ - struct elf_m68k_got_entry entry_; - struct elf_m68k_got_entry *entry; - void **ptr; - - BFD_ASSERT ((info == NULL) == (howto == SEARCH || howto == MUST_FIND)); - - if (got->entries == NULL) - /* This is the first entry in ABFD. Initialize hashtable. */ - { - if (howto == SEARCH) - return NULL; - - got->entries = htab_try_create (ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT - (info), - elf_m68k_got_entry_hash, - elf_m68k_got_entry_eq, NULL); - if (got->entries == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - } - - entry_.key_ = *key; - ptr = htab_find_slot (got->entries, &entry_, (howto != SEARCH - ? INSERT : NO_INSERT)); - if (ptr == NULL) - { - if (howto == SEARCH) - /* Entry not found. */ - return NULL; - - /* We're out of memory. */ - bfd_set_error (bfd_error_no_memory); - return NULL; - } - - if (*ptr == NULL) - /* We didn't find the entry and we're asked to create a new one. */ - { - BFD_ASSERT (howto != MUST_FIND && howto != SEARCH); - - entry = bfd_alloc (elf_hash_table (info)->dynobj, sizeof (*entry)); - if (entry == NULL) - return NULL; - - /* Initialize new entry. */ - entry->key_ = *key; - - entry->u.s1.refcount = 0; - - /* Mark the entry as not initialized. */ - entry->key_.type = R_68K_max; - - *ptr = entry; - } - else - /* We found the entry. */ - { - BFD_ASSERT (howto != MUST_CREATE); - - entry = *ptr; - } - - return entry; -} - -/* Update GOT counters when merging entry of WAS type with entry of NEW type. - Return the value to which ENTRY's type should be set. */ - -static enum elf_m68k_reloc_type -elf_m68k_update_got_entry_type (struct elf_m68k_got *got, - enum elf_m68k_reloc_type was, - enum elf_m68k_reloc_type new_reloc) -{ - enum elf_m68k_got_offset_size was_size; - enum elf_m68k_got_offset_size new_size; - bfd_vma n_slots; - - if (was == R_68K_max) - /* The type of the entry is not initialized yet. */ - { - /* Update all got->n_slots counters, including n_slots[R_32]. */ - was_size = R_LAST; - - was = new_reloc; - } - else - { - /* !!! We, probably, should emit an error rather then fail on assert - in such a case. */ - BFD_ASSERT (elf_m68k_reloc_got_type (was) - == elf_m68k_reloc_got_type (new_reloc)); - - was_size = elf_m68k_reloc_got_offset_size (was); - } - - new_size = elf_m68k_reloc_got_offset_size (new_reloc); - n_slots = elf_m68k_reloc_got_n_slots (new_reloc); - - while (was_size > new_size) - { - --was_size; - got->n_slots[was_size] += n_slots; - } - - if (new_reloc > was) - /* Relocations are ordered from bigger got offset size to lesser, - so choose the relocation type with lesser offset size. */ - was = new_reloc; - - return was; -} - -/* Add new or update existing entry to GOT. - H, ABFD, TYPE and SYMNDX is data for the entry. - INFO is a context where memory should be allocated. */ - -static struct elf_m68k_got_entry * -elf_m68k_add_entry_to_got (struct elf_m68k_got *got, - struct elf_link_hash_entry *h, - const bfd *abfd, - enum elf_m68k_reloc_type reloc_type, - unsigned long symndx, - struct bfd_link_info *info) -{ - struct elf_m68k_got_entry_key key_; - struct elf_m68k_got_entry *entry; - - if (h != NULL && elf_m68k_hash_entry (h)->got_entry_key == 0) - elf_m68k_hash_entry (h)->got_entry_key - = elf_m68k_multi_got (info)->global_symndx++; - - elf_m68k_init_got_entry_key (&key_, h, abfd, symndx, reloc_type); - - entry = elf_m68k_get_got_entry (got, &key_, FIND_OR_CREATE, info); - if (entry == NULL) - return NULL; - - /* Determine entry's type and update got->n_slots counters. */ - entry->key_.type = elf_m68k_update_got_entry_type (got, - entry->key_.type, - reloc_type); - - /* Update refcount. */ - ++entry->u.s1.refcount; - - if (entry->u.s1.refcount == 1) - /* We see this entry for the first time. */ - { - if (entry->key_.bfd != NULL) - got->local_n_slots += elf_m68k_reloc_got_n_slots (entry->key_.type); - } - - BFD_ASSERT (got->n_slots[R_32] >= got->local_n_slots); - - if ((got->n_slots[R_8] - > ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT (info)) - || (got->n_slots[R_16] - > ELF_M68K_R_8_16_MAX_N_SLOTS_IN_GOT (info))) - /* This BFD has too many relocation. */ - { - if (got->n_slots[R_8] > ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT (info)) - /* xgettext:c-format */ - _bfd_error_handler (_("%B: GOT overflow: " - "Number of relocations with 8-bit " - "offset > %d"), - abfd, - ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT (info)); - else - /* xgettext:c-format */ - _bfd_error_handler (_("%B: GOT overflow: " - "Number of relocations with 8- or 16-bit " - "offset > %d"), - abfd, - ELF_M68K_R_8_16_MAX_N_SLOTS_IN_GOT (info)); - - return NULL; - } - - return entry; -} - -/* Compute the hash value of the bfd in a bfd2got hash entry. */ - -static hashval_t -elf_m68k_bfd2got_entry_hash (const void *entry) -{ - const struct elf_m68k_bfd2got_entry *e; - - e = (const struct elf_m68k_bfd2got_entry *) entry; - - return e->bfd->id; -} - -/* Check whether two hash entries have the same bfd. */ - -static int -elf_m68k_bfd2got_entry_eq (const void *entry1, const void *entry2) -{ - const struct elf_m68k_bfd2got_entry *e1; - const struct elf_m68k_bfd2got_entry *e2; - - e1 = (const struct elf_m68k_bfd2got_entry *) entry1; - e2 = (const struct elf_m68k_bfd2got_entry *) entry2; - - return e1->bfd == e2->bfd; -} - -/* Destruct a bfd2got entry. */ - -static void -elf_m68k_bfd2got_entry_del (void *_entry) -{ - struct elf_m68k_bfd2got_entry *entry; - - entry = (struct elf_m68k_bfd2got_entry *) _entry; - - BFD_ASSERT (entry->got != NULL); - elf_m68k_clear_got (entry->got); -} - -/* Find existing or create new (depending on HOWTO) bfd2got entry in - MULTI_GOT. ABFD is the bfd we need a GOT for. INFO is a context where - memory should be allocated. */ - -static struct elf_m68k_bfd2got_entry * -elf_m68k_get_bfd2got_entry (struct elf_m68k_multi_got *multi_got, - const bfd *abfd, - enum elf_m68k_get_entry_howto howto, - struct bfd_link_info *info) -{ - struct elf_m68k_bfd2got_entry entry_; - void **ptr; - struct elf_m68k_bfd2got_entry *entry; - - BFD_ASSERT ((info == NULL) == (howto == SEARCH || howto == MUST_FIND)); - - if (multi_got->bfd2got == NULL) - /* This is the first GOT. Initialize bfd2got. */ - { - if (howto == SEARCH) - return NULL; - - multi_got->bfd2got = htab_try_create (1, elf_m68k_bfd2got_entry_hash, - elf_m68k_bfd2got_entry_eq, - elf_m68k_bfd2got_entry_del); - if (multi_got->bfd2got == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - } - - entry_.bfd = abfd; - ptr = htab_find_slot (multi_got->bfd2got, &entry_, (howto != SEARCH - ? INSERT : NO_INSERT)); - if (ptr == NULL) - { - if (howto == SEARCH) - /* Entry not found. */ - return NULL; - - /* We're out of memory. */ - bfd_set_error (bfd_error_no_memory); - return NULL; - } - - if (*ptr == NULL) - /* Entry was not found. Create new one. */ - { - BFD_ASSERT (howto != MUST_FIND && howto != SEARCH); - - entry = ((struct elf_m68k_bfd2got_entry *) - bfd_alloc (elf_hash_table (info)->dynobj, sizeof (*entry))); - if (entry == NULL) - return NULL; - - entry->bfd = abfd; - - entry->got = elf_m68k_create_empty_got (info); - if (entry->got == NULL) - return NULL; - - *ptr = entry; - } - else - { - BFD_ASSERT (howto != MUST_CREATE); - - /* Return existing entry. */ - entry = *ptr; - } - - return entry; -} - -struct elf_m68k_can_merge_gots_arg -{ - /* A current_got that we constructing a DIFF against. */ - struct elf_m68k_got *big; - - /* GOT holding entries not present or that should be changed in - BIG. */ - struct elf_m68k_got *diff; - - /* Context where to allocate memory. */ - struct bfd_link_info *info; - - /* Error flag. */ - bfd_boolean error_p; -}; - -/* Process a single entry from the small GOT to see if it should be added - or updated in the big GOT. */ - -static int -elf_m68k_can_merge_gots_1 (void **_entry_ptr, void *_arg) -{ - const struct elf_m68k_got_entry *entry1; - struct elf_m68k_can_merge_gots_arg *arg; - const struct elf_m68k_got_entry *entry2; - enum elf_m68k_reloc_type type; - - entry1 = (const struct elf_m68k_got_entry *) *_entry_ptr; - arg = (struct elf_m68k_can_merge_gots_arg *) _arg; - - entry2 = elf_m68k_get_got_entry (arg->big, &entry1->key_, SEARCH, NULL); - - if (entry2 != NULL) - /* We found an existing entry. Check if we should update it. */ - { - type = elf_m68k_update_got_entry_type (arg->diff, - entry2->key_.type, - entry1->key_.type); - - if (type == entry2->key_.type) - /* ENTRY1 doesn't update data in ENTRY2. Skip it. - To skip creation of difference entry we use the type, - which we won't see in GOT entries for sure. */ - type = R_68K_max; - } - else - /* We didn't find the entry. Add entry1 to DIFF. */ - { - BFD_ASSERT (entry1->key_.type != R_68K_max); - - type = elf_m68k_update_got_entry_type (arg->diff, - R_68K_max, entry1->key_.type); - - if (entry1->key_.bfd != NULL) - arg->diff->local_n_slots += elf_m68k_reloc_got_n_slots (type); - } - - if (type != R_68K_max) - /* Create an entry in DIFF. */ - { - struct elf_m68k_got_entry *entry; - - entry = elf_m68k_get_got_entry (arg->diff, &entry1->key_, MUST_CREATE, - arg->info); - if (entry == NULL) - { - arg->error_p = TRUE; - return 0; - } - - entry->key_.type = type; - } - - return 1; -} - -/* Return TRUE if SMALL GOT can be added to BIG GOT without overflowing it. - Construct DIFF GOT holding the entries which should be added or updated - in BIG GOT to accumulate information from SMALL. - INFO is the context where memory should be allocated. */ - -static bfd_boolean -elf_m68k_can_merge_gots (struct elf_m68k_got *big, - const struct elf_m68k_got *small, - struct bfd_link_info *info, - struct elf_m68k_got *diff) -{ - struct elf_m68k_can_merge_gots_arg arg_; - - BFD_ASSERT (small->offset == (bfd_vma) -1); - - arg_.big = big; - arg_.diff = diff; - arg_.info = info; - arg_.error_p = FALSE; - htab_traverse_noresize (small->entries, elf_m68k_can_merge_gots_1, &arg_); - if (arg_.error_p) - { - diff->offset = 0; - return FALSE; - } - - /* Check for overflow. */ - if ((big->n_slots[R_8] + arg_.diff->n_slots[R_8] - > ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT (info)) - || (big->n_slots[R_16] + arg_.diff->n_slots[R_16] - > ELF_M68K_R_8_16_MAX_N_SLOTS_IN_GOT (info))) - return FALSE; - - return TRUE; -} - -struct elf_m68k_merge_gots_arg -{ - /* The BIG got. */ - struct elf_m68k_got *big; - - /* Context where memory should be allocated. */ - struct bfd_link_info *info; - - /* Error flag. */ - bfd_boolean error_p; -}; - -/* Process a single entry from DIFF got. Add or update corresponding - entry in the BIG got. */ - -static int -elf_m68k_merge_gots_1 (void **entry_ptr, void *_arg) -{ - const struct elf_m68k_got_entry *from; - struct elf_m68k_merge_gots_arg *arg; - struct elf_m68k_got_entry *to; - - from = (const struct elf_m68k_got_entry *) *entry_ptr; - arg = (struct elf_m68k_merge_gots_arg *) _arg; - - to = elf_m68k_get_got_entry (arg->big, &from->key_, FIND_OR_CREATE, - arg->info); - if (to == NULL) - { - arg->error_p = TRUE; - return 0; - } - - BFD_ASSERT (to->u.s1.refcount == 0); - /* All we need to merge is TYPE. */ - to->key_.type = from->key_.type; - - return 1; -} - -/* Merge data from DIFF to BIG. INFO is context where memory should be - allocated. */ - -static bfd_boolean -elf_m68k_merge_gots (struct elf_m68k_got *big, - struct elf_m68k_got *diff, - struct bfd_link_info *info) -{ - if (diff->entries != NULL) - /* DIFF is not empty. Merge it into BIG GOT. */ - { - struct elf_m68k_merge_gots_arg arg_; - - /* Merge entries. */ - arg_.big = big; - arg_.info = info; - arg_.error_p = FALSE; - htab_traverse_noresize (diff->entries, elf_m68k_merge_gots_1, &arg_); - if (arg_.error_p) - return FALSE; - - /* Merge counters. */ - big->n_slots[R_8] += diff->n_slots[R_8]; - big->n_slots[R_16] += diff->n_slots[R_16]; - big->n_slots[R_32] += diff->n_slots[R_32]; - big->local_n_slots += diff->local_n_slots; - } - else - /* DIFF is empty. */ - { - BFD_ASSERT (diff->n_slots[R_8] == 0); - BFD_ASSERT (diff->n_slots[R_16] == 0); - BFD_ASSERT (diff->n_slots[R_32] == 0); - BFD_ASSERT (diff->local_n_slots == 0); - } - - BFD_ASSERT (!elf_m68k_hash_table (info)->allow_multigot_p - || ((big->n_slots[R_8] - <= ELF_M68K_R_8_MAX_N_SLOTS_IN_GOT (info)) - && (big->n_slots[R_16] - <= ELF_M68K_R_8_16_MAX_N_SLOTS_IN_GOT (info)))); - - return TRUE; -} - -struct elf_m68k_finalize_got_offsets_arg -{ - /* Ranges of the offsets for GOT entries. - R_x entries receive offsets between offset1[R_x] and offset2[R_x]. - R_x is R_8, R_16 and R_32. */ - bfd_vma *offset1; - bfd_vma *offset2; - - /* Mapping from global symndx to global symbols. - This is used to build lists of got entries for global symbols. */ - struct elf_m68k_link_hash_entry **symndx2h; - - bfd_vma n_ldm_entries; -}; - -/* Assign ENTRY an offset. Build list of GOT entries for global symbols - along the way. */ - -static int -elf_m68k_finalize_got_offsets_1 (void **entry_ptr, void *_arg) -{ - struct elf_m68k_got_entry *entry; - struct elf_m68k_finalize_got_offsets_arg *arg; - - enum elf_m68k_got_offset_size got_offset_size; - bfd_vma entry_size; - - entry = (struct elf_m68k_got_entry *) *entry_ptr; - arg = (struct elf_m68k_finalize_got_offsets_arg *) _arg; - - /* This should be a fresh entry created in elf_m68k_can_merge_gots. */ - BFD_ASSERT (entry->u.s1.refcount == 0); - - /* Get GOT offset size for the entry . */ - got_offset_size = elf_m68k_reloc_got_offset_size (entry->key_.type); - - /* Calculate entry size in bytes. */ - entry_size = 4 * elf_m68k_reloc_got_n_slots (entry->key_.type); - - /* Check if we should switch to negative range of the offsets. */ - if (arg->offset1[got_offset_size] + entry_size - > arg->offset2[got_offset_size]) - { - /* Verify that this is the only switch to negative range for - got_offset_size. If this assertion fails, then we've miscalculated - range for got_offset_size entries in - elf_m68k_finalize_got_offsets. */ - BFD_ASSERT (arg->offset2[got_offset_size] - != arg->offset2[-(int) got_offset_size - 1]); - - /* Switch. */ - arg->offset1[got_offset_size] = arg->offset1[-(int) got_offset_size - 1]; - arg->offset2[got_offset_size] = arg->offset2[-(int) got_offset_size - 1]; - - /* Verify that now we have enough room for the entry. */ - BFD_ASSERT (arg->offset1[got_offset_size] + entry_size - <= arg->offset2[got_offset_size]); - } - - /* Assign offset to entry. */ - entry->u.s2.offset = arg->offset1[got_offset_size]; - arg->offset1[got_offset_size] += entry_size; - - if (entry->key_.bfd == NULL) - /* Hook up this entry into the list of got_entries of H. */ - { - struct elf_m68k_link_hash_entry *h; - - h = arg->symndx2h[entry->key_.symndx]; - if (h != NULL) - { - entry->u.s2.next = h->glist; - h->glist = entry; - } - else - /* This should be the entry for TLS_LDM relocation then. */ - { - BFD_ASSERT ((elf_m68k_reloc_got_type (entry->key_.type) - == R_68K_TLS_LDM32) - && entry->key_.symndx == 0); - - ++arg->n_ldm_entries; - } - } - else - /* This entry is for local symbol. */ - entry->u.s2.next = NULL; - - return 1; -} - -/* Assign offsets within GOT. USE_NEG_GOT_OFFSETS_P indicates if we - should use negative offsets. - Build list of GOT entries for global symbols along the way. - SYMNDX2H is mapping from global symbol indices to actual - global symbols. - Return offset at which next GOT should start. */ - -static void -elf_m68k_finalize_got_offsets (struct elf_m68k_got *got, - bfd_boolean use_neg_got_offsets_p, - struct elf_m68k_link_hash_entry **symndx2h, - bfd_vma *final_offset, bfd_vma *n_ldm_entries) -{ - struct elf_m68k_finalize_got_offsets_arg arg_; - bfd_vma offset1_[2 * R_LAST]; - bfd_vma offset2_[2 * R_LAST]; - int i; - bfd_vma start_offset; - - BFD_ASSERT (got->offset != (bfd_vma) -1); - - /* We set entry offsets relative to the .got section (and not the - start of a particular GOT), so that we can use them in - finish_dynamic_symbol without needing to know the GOT which they come - from. */ - - /* Put offset1 in the middle of offset1_, same for offset2. */ - arg_.offset1 = offset1_ + R_LAST; - arg_.offset2 = offset2_ + R_LAST; - - start_offset = got->offset; - - if (use_neg_got_offsets_p) - /* Setup both negative and positive ranges for R_8, R_16 and R_32. */ - i = -(int) R_32 - 1; - else - /* Setup positives ranges for R_8, R_16 and R_32. */ - i = (int) R_8; - - for (; i <= (int) R_32; ++i) - { - int j; - size_t n; - - /* Set beginning of the range of offsets I. */ - arg_.offset1[i] = start_offset; - - /* Calculate number of slots that require I offsets. */ - j = (i >= 0) ? i : -i - 1; - n = (j >= 1) ? got->n_slots[j - 1] : 0; - n = got->n_slots[j] - n; - - if (use_neg_got_offsets_p && n != 0) - { - if (i < 0) - /* We first fill the positive side of the range, so we might - end up with one empty slot at that side when we can't fit - whole 2-slot entry. Account for that at negative side of - the interval with one additional entry. */ - n = n / 2 + 1; - else - /* When the number of slots is odd, make positive side of the - range one entry bigger. */ - n = (n + 1) / 2; - } - - /* N is the number of slots that require I offsets. - Calculate length of the range for I offsets. */ - n = 4 * n; - - /* Set end of the range. */ - arg_.offset2[i] = start_offset + n; - - start_offset = arg_.offset2[i]; - } - - if (!use_neg_got_offsets_p) - /* Make sure that if we try to switch to negative offsets in - elf_m68k_finalize_got_offsets_1, the assert therein will catch - the bug. */ - for (i = R_8; i <= R_32; ++i) - arg_.offset2[-i - 1] = arg_.offset2[i]; - - /* Setup got->offset. offset1[R_8] is either in the middle or at the - beginning of GOT depending on use_neg_got_offsets_p. */ - got->offset = arg_.offset1[R_8]; - - arg_.symndx2h = symndx2h; - arg_.n_ldm_entries = 0; - - /* Assign offsets. */ - htab_traverse (got->entries, elf_m68k_finalize_got_offsets_1, &arg_); - - /* Check offset ranges we have actually assigned. */ - for (i = (int) R_8; i <= (int) R_32; ++i) - BFD_ASSERT (arg_.offset2[i] - arg_.offset1[i] <= 4); - - *final_offset = start_offset; - *n_ldm_entries = arg_.n_ldm_entries; -} - -struct elf_m68k_partition_multi_got_arg -{ - /* The GOT we are adding entries to. Aka big got. */ - struct elf_m68k_got *current_got; - - /* Offset to assign the next CURRENT_GOT. */ - bfd_vma offset; - - /* Context where memory should be allocated. */ - struct bfd_link_info *info; - - /* Total number of slots in the .got section. - This is used to calculate size of the .got and .rela.got sections. */ - bfd_vma n_slots; - - /* Difference in numbers of allocated slots in the .got section - and necessary relocations in the .rela.got section. - This is used to calculate size of the .rela.got section. */ - bfd_vma slots_relas_diff; - - /* Error flag. */ - bfd_boolean error_p; - - /* Mapping from global symndx to global symbols. - This is used to build lists of got entries for global symbols. */ - struct elf_m68k_link_hash_entry **symndx2h; -}; - -static void -elf_m68k_partition_multi_got_2 (struct elf_m68k_partition_multi_got_arg *arg) -{ - bfd_vma n_ldm_entries; - - elf_m68k_finalize_got_offsets (arg->current_got, - (elf_m68k_hash_table (arg->info) - ->use_neg_got_offsets_p), - arg->symndx2h, - &arg->offset, &n_ldm_entries); - - arg->n_slots += arg->current_got->n_slots[R_32]; - - if (!bfd_link_pic (arg->info)) - /* If we are generating a shared object, we need to - output a R_68K_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. Overwise we - don't need space in .rela.got for local symbols. */ - arg->slots_relas_diff += arg->current_got->local_n_slots; - - /* @LDM relocations require a 2-slot GOT entry, but only - one relocation. Account for that. */ - arg->slots_relas_diff += n_ldm_entries; - - BFD_ASSERT (arg->slots_relas_diff <= arg->n_slots); -} - - -/* Process a single BFD2GOT entry and either merge GOT to CURRENT_GOT - or start a new CURRENT_GOT. */ - -static int -elf_m68k_partition_multi_got_1 (void **_entry, void *_arg) -{ - struct elf_m68k_bfd2got_entry *entry; - struct elf_m68k_partition_multi_got_arg *arg; - struct elf_m68k_got *got; - struct elf_m68k_got diff_; - struct elf_m68k_got *diff; - - entry = (struct elf_m68k_bfd2got_entry *) *_entry; - arg = (struct elf_m68k_partition_multi_got_arg *) _arg; - - got = entry->got; - BFD_ASSERT (got != NULL); - BFD_ASSERT (got->offset == (bfd_vma) -1); - - diff = NULL; - - if (arg->current_got != NULL) - /* Construct diff. */ - { - diff = &diff_; - elf_m68k_init_got (diff); - - if (!elf_m68k_can_merge_gots (arg->current_got, got, arg->info, diff)) - { - if (diff->offset == 0) - /* Offset set to 0 in the diff_ indicates an error. */ - { - arg->error_p = TRUE; - goto final_return; - } - - if (elf_m68k_hash_table (arg->info)->allow_multigot_p) - { - elf_m68k_clear_got (diff); - /* Schedule to finish up current_got and start new one. */ - diff = NULL; - } - /* else - Merge GOTs no matter what. If big GOT overflows, - we'll fail in relocate_section due to truncated relocations. - - ??? May be fail earlier? E.g., in can_merge_gots. */ - } - } - else - /* Diff of got against empty current_got is got itself. */ - { - /* Create empty current_got to put subsequent GOTs to. */ - arg->current_got = elf_m68k_create_empty_got (arg->info); - if (arg->current_got == NULL) - { - arg->error_p = TRUE; - goto final_return; - } - - arg->current_got->offset = arg->offset; - - diff = got; - } - - if (diff != NULL) - { - if (!elf_m68k_merge_gots (arg->current_got, diff, arg->info)) - { - arg->error_p = TRUE; - goto final_return; - } - - /* Now we can free GOT. */ - elf_m68k_clear_got (got); - - entry->got = arg->current_got; - } - else - { - /* Finish up current_got. */ - elf_m68k_partition_multi_got_2 (arg); - - /* Schedule to start a new current_got. */ - arg->current_got = NULL; - - /* Retry. */ - if (!elf_m68k_partition_multi_got_1 (_entry, _arg)) - { - BFD_ASSERT (arg->error_p); - goto final_return; - } - } - - final_return: - if (diff != NULL) - elf_m68k_clear_got (diff); - - return !arg->error_p; -} - -/* Helper function to build symndx2h mapping. */ - -static bfd_boolean -elf_m68k_init_symndx2h_1 (struct elf_link_hash_entry *_h, - void *_arg) -{ - struct elf_m68k_link_hash_entry *h; - - h = elf_m68k_hash_entry (_h); - - if (h->got_entry_key != 0) - /* H has at least one entry in the GOT. */ - { - struct elf_m68k_partition_multi_got_arg *arg; - - arg = (struct elf_m68k_partition_multi_got_arg *) _arg; - - BFD_ASSERT (arg->symndx2h[h->got_entry_key] == NULL); - arg->symndx2h[h->got_entry_key] = h; - } - - return TRUE; -} - -/* Merge GOTs of some BFDs, assign offsets to GOT entries and build - lists of GOT entries for global symbols. - Calculate sizes of .got and .rela.got sections. */ - -static bfd_boolean -elf_m68k_partition_multi_got (struct bfd_link_info *info) -{ - struct elf_m68k_multi_got *multi_got; - struct elf_m68k_partition_multi_got_arg arg_; - - multi_got = elf_m68k_multi_got (info); - - arg_.current_got = NULL; - arg_.offset = 0; - arg_.info = info; - arg_.n_slots = 0; - arg_.slots_relas_diff = 0; - arg_.error_p = FALSE; - - if (multi_got->bfd2got != NULL) - { - /* Initialize symndx2h mapping. */ - { - arg_.symndx2h = bfd_zmalloc (multi_got->global_symndx - * sizeof (*arg_.symndx2h)); - if (arg_.symndx2h == NULL) - return FALSE; - - elf_link_hash_traverse (elf_hash_table (info), - elf_m68k_init_symndx2h_1, &arg_); - } - - /* Partition. */ - htab_traverse (multi_got->bfd2got, elf_m68k_partition_multi_got_1, - &arg_); - if (arg_.error_p) - { - free (arg_.symndx2h); - arg_.symndx2h = NULL; - - return FALSE; - } - - /* Finish up last current_got. */ - elf_m68k_partition_multi_got_2 (&arg_); - - free (arg_.symndx2h); - } - - if (elf_hash_table (info)->dynobj != NULL) - /* Set sizes of .got and .rela.got sections. */ - { - asection *s; - - s = elf_hash_table (info)->sgot; - if (s != NULL) - s->size = arg_.offset; - else - BFD_ASSERT (arg_.offset == 0); - - BFD_ASSERT (arg_.slots_relas_diff <= arg_.n_slots); - arg_.n_slots -= arg_.slots_relas_diff; - - s = elf_hash_table (info)->srelgot; - if (s != NULL) - s->size = arg_.n_slots * sizeof (Elf32_External_Rela); - else - BFD_ASSERT (arg_.n_slots == 0); - } - else - BFD_ASSERT (multi_got->bfd2got == NULL); - - return TRUE; -} - -/* 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. */ - -static void -elf_m68k_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *_dir, - struct elf_link_hash_entry *_ind) -{ - struct elf_m68k_link_hash_entry *dir; - struct elf_m68k_link_hash_entry *ind; - - _bfd_elf_link_hash_copy_indirect (info, _dir, _ind); - - if (_ind->root.type != bfd_link_hash_indirect) - return; - - dir = elf_m68k_hash_entry (_dir); - ind = elf_m68k_hash_entry (_ind); - - /* Any absolute non-dynamic relocations against an indirect or weak - definition will be against the target symbol. */ - _dir->non_got_ref |= _ind->non_got_ref; - - /* We might have a direct symbol already having entries in the GOTs. - Update its key only in case indirect symbol has GOT entries and - assert that both indirect and direct symbols don't have GOT entries - at the same time. */ - if (ind->got_entry_key != 0) - { - BFD_ASSERT (dir->got_entry_key == 0); - /* Assert that GOTs aren't partioned yet. */ - BFD_ASSERT (ind->glist == NULL); - - dir->got_entry_key = ind->got_entry_key; - ind->got_entry_key = 0; - } -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -elf_m68k_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - 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; - struct elf_m68k_got *got; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - sreloc = NULL; - - got = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_68K_GOT8: - case R_68K_GOT16: - case R_68K_GOT32: - if (h != NULL - && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - break; - /* Fall through. */ - - /* Relative GOT relocations. */ - case R_68K_GOT8O: - case R_68K_GOT16O: - case R_68K_GOT32O: - /* Fall through. */ - - /* TLS relocations. */ - case R_68K_TLS_GD8: - case R_68K_TLS_GD16: - case R_68K_TLS_GD32: - case R_68K_TLS_LDM8: - case R_68K_TLS_LDM16: - case R_68K_TLS_LDM32: - case R_68K_TLS_IE8: - case R_68K_TLS_IE16: - case R_68K_TLS_IE32: - - case R_68K_TLS_TPREL32: - case R_68K_TLS_DTPREL32: - - if (ELF32_R_TYPE (rel->r_info) == R_68K_TLS_TPREL32 - && bfd_link_pic (info)) - /* Do the special chorus for libraries with static TLS. */ - info->flags |= DF_STATIC_TLS; - - /* This symbol requires a global offset table entry. */ - - if (dynobj == NULL) - { - /* Create the .got section. */ - elf_hash_table (info)->dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - } - - if (got == NULL) - { - struct elf_m68k_bfd2got_entry *bfd2got_entry; - - bfd2got_entry - = elf_m68k_get_bfd2got_entry (elf_m68k_multi_got (info), - abfd, FIND_OR_CREATE, info); - if (bfd2got_entry == NULL) - return FALSE; - - got = bfd2got_entry->got; - BFD_ASSERT (got != NULL); - } - - { - struct elf_m68k_got_entry *got_entry; - - /* Add entry to got. */ - got_entry = elf_m68k_add_entry_to_got (got, h, abfd, - ELF32_R_TYPE (rel->r_info), - r_symndx, info); - if (got_entry == NULL) - return FALSE; - - if (got_entry->u.s1.refcount == 1) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (h != NULL - && h->dynindx == -1 - && !h->forced_local) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - - break; - - case R_68K_PLT8: - case R_68K_PLT16: - case R_68K_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++; - break; - - case R_68K_PLT8O: - case R_68K_PLT16O: - case R_68K_PLT32O: - /* This symbol requires a procedure linkage table entry. */ - - if (h == NULL) - { - /* It does not make sense to have this relocation for a - local symbol. FIXME: does it? How to handle it if - it does make sense? */ - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - h->needs_plt = 1; - h->plt.refcount++; - break; - - case R_68K_PC8: - case R_68K_PC16: - case R_68K_PC32: - /* If we are creating a shared library and this is not a local - symbol, we need to copy the reloc into the shared library. - However when linking with -Bsymbolic and this is a global - symbol which is defined in an object we are including in the - link (i.e., DEF_REGULAR is set), then we can resolve the - reloc directly. At this point we have not seen all the input - files, so it is possible that DEF_REGULAR is not set now but - will be set later (it is never cleared). We account for that - possibility below by storing information in the - pcrel_relocs_copied field of the hash table entry. */ - if (!(bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (!SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - if (h != NULL) - { - /* Make sure a plt entry is created for this symbol if - it turns out to be a function defined by a dynamic - object. */ - h->plt.refcount++; - } - break; - } - /* Fall through. */ - case R_68K_8: - case R_68K_16: - case R_68K_32: - /* We don't need to handle relocs into sections not going into - the "real" output. */ - if ((sec->flags & SEC_ALLOC) == 0) - break; - - if (h != NULL) - { - /* Make sure a plt entry is created for this symbol if it - turns out to be a function defined by a dynamic object. */ - h->plt.refcount++; - - if (bfd_link_executable (info)) - /* This symbol needs a non-GOT reference. */ - h->non_got_ref = 1; - } - - /* If we are creating a shared library, we need to copy the - reloc into the shared library. */ - if (bfd_link_pic (info) - && (h == NULL - || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) - { - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - if (sec->flags & SEC_READONLY - /* Don't set DF_TEXTREL yet for PC relative - relocations, they might be discarded later. */ - && !(ELF32_R_TYPE (rel->r_info) == R_68K_PC8 - || ELF32_R_TYPE (rel->r_info) == R_68K_PC16 - || ELF32_R_TYPE (rel->r_info) == R_68K_PC32)) - info->flags |= DF_TEXTREL; - - sreloc->size += sizeof (Elf32_External_Rela); - - /* We count the number of PC relative relocations we have - entered for this symbol, so that we can discard them - again if, in the -Bsymbolic case, the symbol is later - defined by a regular object, or, in the normal shared - case, the symbol is forced to be local. Note that this - function is only called if we are using an m68kelf linker - hash table, which means that h is really a pointer to an - elf_m68k_link_hash_entry. */ - if (ELF32_R_TYPE (rel->r_info) == R_68K_PC8 - || ELF32_R_TYPE (rel->r_info) == R_68K_PC16 - || ELF32_R_TYPE (rel->r_info) == R_68K_PC32) - { - struct elf_m68k_pcrel_relocs_copied *p; - struct elf_m68k_pcrel_relocs_copied **head; - - if (h != NULL) - { - struct elf_m68k_link_hash_entry *eh - = elf_m68k_hash_entry (h); - head = &eh->pcrel_relocs_copied; - } - else - { - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&elf_m68k_hash_table (info)->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_m68k_pcrel_relocs_copied **) vpp; - } - - for (p = *head; p != NULL; p = p->next) - if (p->section == sreloc) - break; - - if (p == NULL) - { - p = ((struct elf_m68k_pcrel_relocs_copied *) - bfd_alloc (dynobj, (bfd_size_type) sizeof *p)); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->section = sreloc; - p->count = 0; - } - - ++p->count; - } - } - - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_68K_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_68K_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !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 * -elf_m68k_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_68K_GNU_VTINHERIT: - case R_68K_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Return the type of PLT associated with OUTPUT_BFD. */ - -static const struct elf_m68k_plt_info * -elf_m68k_get_plt_info (bfd *output_bfd) -{ - unsigned int features; - - features = bfd_m68k_mach_to_features (bfd_get_mach (output_bfd)); - if (features & cpu32) - return &elf_cpu32_plt_info; - if (features & mcfisa_b) - return &elf_isab_plt_info; - if (features & mcfisa_c) - return &elf_isac_plt_info; - return &elf_m68k_plt_info; -} - -/* This function is called after all the input files have been read, - and the input sections have been assigned to output sections. - It's a convenient place to determine the PLT style. */ - -static bfd_boolean -elf_m68k_always_size_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - /* Bind input BFDs to GOTs and calculate sizes of .got and .rela.got - sections. */ - if (!elf_m68k_partition_multi_got (info)) - return FALSE; - - elf_m68k_hash_table (info)->plt_info = elf_m68k_get_plt_info (output_bfd); - 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_m68k_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_m68k_link_hash_table *htab; - bfd *dynobj; - asection *s; - - htab = elf_m68k_hash_table (info); - dynobj = htab->root.dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if ((h->plt.refcount <= 0 - || SYMBOL_CALLS_LOCAL (info, h) - || ((ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - && h->root.type == bfd_link_hash_undefweak)) - /* We must always create the plt entry if it was referenced - by a PLTxxO relocation. In this case we already recorded - it as a dynamic symbol. */ - && h->dynindx == -1) - { - /* This case can occur if we saw a PLTxx 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 PCxx reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - return TRUE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->root.splt; - BFD_ASSERT (s != NULL); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size = htab->plt_info->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 (!bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = s->size; - } - - h->plt.offset = s->size; - - /* Make room for this entry. */ - s->size += htab->plt_info->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. */ - s = htab->root.sgotplt; - BFD_ASSERT (s != NULL); - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - s = htab->root.srelplt; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - - return TRUE; - } - - /* Reinitialize the plt offset now that it is not used as a reference - count any more. */ - 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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; - - /* 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. */ - - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - /* We must generate a R_68K_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_m68k_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean plt; - bfd_boolean relocs; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = elf_hash_table (info)->srelgot; - if (s != NULL) - s->size = 0; - } - - /* If this is a -Bsymbolic shared link, then we need to discard all - PC relative relocs against symbols defined in a regular object. - For the normal shared case we discard the PC relative relocs - against symbols that have become local due to visibility changes. - We allocated space for them in the check_relocs routine, but we - will not fill them in in the relocate_section routine. */ - if (bfd_link_pic (info)) - elf_link_hash_traverse (elf_hash_table (info), - elf_m68k_discard_copies, - info); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - 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 if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".dynbss") != 0) - { - /* 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. */ - /* FIXME: This should be a call to bfd_alloc not bfd_zalloc. - Unused entries should be reclaimed before the section's contents - are written out, but at the moment this does not happen. Thus in - order to prevent writing out garbage, we initialise the section's - contents to zero. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf_m68k_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - } - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* This function is called via elf_link_hash_traverse if we are - creating a shared object. In the -Bsymbolic case it discards the - space allocated to copy PC relative relocs against symbols which - are defined in regular objects. For the normal shared case, it - discards space for pc-relative relocs that have become local due to - symbol visibility changes. We allocated space for them in the - check_relocs routine, but we won't fill them in in the - relocate_section routine. - - We also check whether any of the remaining relocations apply - against a readonly section, and set the DF_TEXTREL flag in this - case. */ - -static bfd_boolean -elf_m68k_discard_copies (struct elf_link_hash_entry *h, - void * inf) -{ - struct bfd_link_info *info = (struct bfd_link_info *) inf; - struct elf_m68k_pcrel_relocs_copied *s; - - if (!SYMBOL_CALLS_LOCAL (info, h)) - { - if ((info->flags & DF_TEXTREL) == 0) - { - /* Look for relocations against read-only sections. */ - for (s = elf_m68k_hash_entry (h)->pcrel_relocs_copied; - s != NULL; - s = s->next) - if ((s->section->flags & SEC_READONLY) != 0) - { - info->flags |= DF_TEXTREL; - break; - } - } - - /* Make sure undefined weak symbols are output as a dynamic symbol - in PIEs. */ - if (h->non_got_ref - && h->root.type == bfd_link_hash_undefweak - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - return TRUE; - } - - for (s = elf_m68k_hash_entry (h)->pcrel_relocs_copied; - s != NULL; - s = s->next) - s->section->size -= s->count * sizeof (Elf32_External_Rela); - - return TRUE; -} - - -/* Install relocation RELA. */ - -static void -elf_m68k_install_rela (bfd *output_bfd, - asection *srela, - Elf_Internal_Rela *rela) -{ - bfd_byte *loc; - - loc = srela->contents; - loc += srela->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, rela, loc); -} - -/* Find the base offsets for thread-local storage in this object, - for GD/LD and IE/LE respectively. */ - -#define DTP_OFFSET 0x8000 -#define TP_OFFSET 0x7000 - -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 + DTP_OFFSET; -} - -static bfd_vma -tpoff_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 + TP_OFFSET; -} - -/* Output necessary relocation to handle a symbol during static link. - This function is called from elf_m68k_relocate_section. */ - -static void -elf_m68k_init_got_entry_static (struct bfd_link_info *info, - bfd *output_bfd, - enum elf_m68k_reloc_type r_type, - asection *sgot, - bfd_vma got_entry_offset, - bfd_vma relocation) -{ - switch (elf_m68k_reloc_got_type (r_type)) - { - case R_68K_GOT32O: - bfd_put_32 (output_bfd, relocation, sgot->contents + got_entry_offset); - break; - - case R_68K_TLS_GD32: - /* We know the offset within the module, - put it into the second GOT slot. */ - bfd_put_32 (output_bfd, relocation - dtpoff_base (info), - sgot->contents + got_entry_offset + 4); - /* FALLTHRU */ - - case R_68K_TLS_LDM32: - /* Mark it as belonging to module 1, the executable. */ - bfd_put_32 (output_bfd, 1, sgot->contents + got_entry_offset); - break; - - case R_68K_TLS_IE32: - bfd_put_32 (output_bfd, relocation - tpoff_base (info), - sgot->contents + got_entry_offset); - break; - - default: - BFD_ASSERT (FALSE); - } -} - -/* Output necessary relocation to handle a local symbol - during dynamic link. - This function is called either from elf_m68k_relocate_section - or from elf_m68k_finish_dynamic_symbol. */ - -static void -elf_m68k_init_got_entry_local_shared (struct bfd_link_info *info, - bfd *output_bfd, - enum elf_m68k_reloc_type r_type, - asection *sgot, - bfd_vma got_entry_offset, - bfd_vma relocation, - asection *srela) -{ - Elf_Internal_Rela outrel; - - switch (elf_m68k_reloc_got_type (r_type)) - { - case R_68K_GOT32O: - /* Emit RELATIVE relocation to initialize GOT slot - at run-time. */ - outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); - outrel.r_addend = relocation; - break; - - case R_68K_TLS_GD32: - /* We know the offset within the module, - put it into the second GOT slot. */ - bfd_put_32 (output_bfd, relocation - dtpoff_base (info), - sgot->contents + got_entry_offset + 4); - /* FALLTHRU */ - - case R_68K_TLS_LDM32: - /* We don't know the module number, - create a relocation for it. */ - outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32); - outrel.r_addend = 0; - break; - - case R_68K_TLS_IE32: - /* Emit TPREL relocation to initialize GOT slot - at run-time. */ - outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32); - outrel.r_addend = relocation - elf_hash_table (info)->tls_sec->vma; - break; - - default: - BFD_ASSERT (FALSE); - } - - /* Offset of the GOT entry. */ - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_entry_offset); - - /* Install one of the above relocations. */ - elf_m68k_install_rela (output_bfd, srela, &outrel); - - bfd_put_32 (output_bfd, outrel.r_addend, sgot->contents + got_entry_offset); -} - -/* Relocate an M68K ELF section. */ - -static bfd_boolean -elf_m68k_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - asection *sgot; - asection *splt; - asection *sreloc; - asection *srela; - struct elf_m68k_got *got; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - sgot = NULL; - splt = NULL; - sreloc = NULL; - srela = NULL; - - got = NULL; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - 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 relocation; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - bfd_boolean resolved_to_zero; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= (int) R_68K_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - howto = howto_table + r_type; - - r_symndx = ELF32_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, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch (r_type) - { - case R_68K_GOT8: - case R_68K_GOT16: - case R_68K_GOT32: - /* Relocation is to the address of the entry for this symbol - in the global offset table. */ - if (h != NULL - && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - { - if (elf_m68k_hash_table (info)->local_gp_p) - { - bfd_vma sgot_output_offset; - bfd_vma got_offset; - - sgot = elf_hash_table (info)->sgot; - - if (sgot != NULL) - sgot_output_offset = sgot->output_offset; - else - /* In this case we have a reference to - _GLOBAL_OFFSET_TABLE_, but the GOT itself is - empty. - ??? Issue a warning? */ - sgot_output_offset = 0; - - if (got == NULL) - { - struct elf_m68k_bfd2got_entry *bfd2got_entry; - - bfd2got_entry - = elf_m68k_get_bfd2got_entry (elf_m68k_multi_got (info), - input_bfd, SEARCH, NULL); - - if (bfd2got_entry != NULL) - { - got = bfd2got_entry->got; - BFD_ASSERT (got != NULL); - - got_offset = got->offset; - } - else - /* In this case we have a reference to - _GLOBAL_OFFSET_TABLE_, but no other references - accessing any GOT entries. - ??? Issue a warning? */ - got_offset = 0; - } - else - got_offset = got->offset; - - /* Adjust GOT pointer to point to the GOT - assigned to input_bfd. */ - rel->r_addend += sgot_output_offset + got_offset; - } - else - BFD_ASSERT (got == NULL || got->offset == 0); - - break; - } - /* Fall through. */ - case R_68K_GOT8O: - case R_68K_GOT16O: - case R_68K_GOT32O: - - case R_68K_TLS_LDM32: - case R_68K_TLS_LDM16: - case R_68K_TLS_LDM8: - - case R_68K_TLS_GD8: - case R_68K_TLS_GD16: - case R_68K_TLS_GD32: - - case R_68K_TLS_IE8: - case R_68K_TLS_IE16: - case R_68K_TLS_IE32: - - /* Relocation is the offset of the entry for this symbol in - the global offset table. */ - - { - struct elf_m68k_got_entry_key key_; - bfd_vma *off_ptr; - bfd_vma off; - - sgot = elf_hash_table (info)->sgot; - BFD_ASSERT (sgot != NULL); - - if (got == NULL) - { - got = elf_m68k_get_bfd2got_entry (elf_m68k_multi_got (info), - input_bfd, MUST_FIND, - NULL)->got; - BFD_ASSERT (got != NULL); - } - - /* Get GOT offset for this symbol. */ - elf_m68k_init_got_entry_key (&key_, h, input_bfd, r_symndx, - r_type); - off_ptr = &elf_m68k_get_got_entry (got, &key_, MUST_FIND, - NULL)->u.s2.offset; - off = *off_ptr; - - /* 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 - { - if (h != NULL - /* @TLSLDM relocations are bounded to the module, in - which the symbol is defined -- not to the symbol - itself. */ - && elf_m68k_reloc_got_type (r_type) != R_68K_TLS_LDM32) - { - bfd_boolean dyn; - - dyn = elf_hash_table (info)->dynamic_sections_created; - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - || ((ELF_ST_VISIBILITY (h->other) - || resolved_to_zero) - && 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 .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - - elf_m68k_init_got_entry_static (info, - output_bfd, - r_type, - sgot, - off, - relocation); - - *off_ptr |= 1; - } - else - unresolved_reloc = FALSE; - } - else if (bfd_link_pic (info)) /* && h == NULL */ - /* Process local symbol during dynamic link. */ - { - srela = elf_hash_table (info)->srelgot; - BFD_ASSERT (srela != NULL); - - elf_m68k_init_got_entry_local_shared (info, - output_bfd, - r_type, - sgot, - off, - relocation, - srela); - - *off_ptr |= 1; - } - else /* h == NULL && !bfd_link_pic (info) */ - { - elf_m68k_init_got_entry_static (info, - output_bfd, - r_type, - sgot, - off, - relocation); - - *off_ptr |= 1; - } - } - - /* We don't use elf_m68k_reloc_got_type in the condition below - because this is the only place where difference between - R_68K_GOTx and R_68K_GOTxO relocations matters. */ - if (r_type == R_68K_GOT32O - || r_type == R_68K_GOT16O - || r_type == R_68K_GOT8O - || elf_m68k_reloc_got_type (r_type) == R_68K_TLS_GD32 - || elf_m68k_reloc_got_type (r_type) == R_68K_TLS_LDM32 - || elf_m68k_reloc_got_type (r_type) == R_68K_TLS_IE32) - { - /* GOT pointer is adjusted to point to the start/middle - of local GOT. Adjust the offset accordingly. */ - BFD_ASSERT (elf_m68k_hash_table (info)->use_neg_got_offsets_p - || off >= got->offset); - - if (elf_m68k_hash_table (info)->local_gp_p) - relocation = off - got->offset; - else - { - BFD_ASSERT (got->offset == 0); - relocation = sgot->output_offset + off; - } - - /* This relocation does not use the addend. */ - rel->r_addend = 0; - } - else - relocation = (sgot->output_section->vma + sgot->output_offset - + off); - } - break; - - case R_68K_TLS_LDO32: - case R_68K_TLS_LDO16: - case R_68K_TLS_LDO8: - relocation -= dtpoff_base (info); - break; - - case R_68K_TLS_LE32: - case R_68K_TLS_LE16: - case R_68K_TLS_LE8: - if (bfd_link_dll (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation not permitted in shared object"), - input_bfd, input_section, rel->r_offset, howto->name); - - return FALSE; - } - else - relocation -= tpoff_base (info); - - break; - - case R_68K_PLT8: - case R_68K_PLT16: - case R_68K_PLT32: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* Resolve a PLTxx reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL) - break; - - if (h->plt.offset == (bfd_vma) -1 - || !elf_hash_table (info)->dynamic_sections_created) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - relocation = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - unresolved_reloc = FALSE; - break; - - case R_68K_PLT8O: - case R_68K_PLT16O: - case R_68K_PLT32O: - /* Relocation is the offset of the entry for this symbol in - the procedure linkage table. */ - BFD_ASSERT (h != NULL && h->plt.offset != (bfd_vma) -1); - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - relocation = h->plt.offset; - unresolved_reloc = FALSE; - - /* This relocation does not use the addend. */ - rel->r_addend = 0; - - break; - - case R_68K_8: - case R_68K_16: - case R_68K_32: - case R_68K_PC8: - case R_68K_PC16: - case R_68K_PC32: - if (bfd_link_pic (info) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0 - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && ((r_type != R_68K_PC8 - && r_type != R_68K_PC16 - && r_type != R_68K_PC32) - || !SYMBOL_CALLS_LOCAL (info, h))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip, relocate; - - /* 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_68K_PC8 - || r_type == R_68K_PC16 - || r_type == R_68K_PC32 - || !bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !h->def_regular)) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* This symbol is local, or marked to become local. */ - outrel.r_addend = relocation + rel->r_addend; - - if (r_type == R_68K_32) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE); - } - else - { - long indx; - - if (bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. */ - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - if (indx == 0) - { - struct elf_link_hash_table *htab; - htab = elf_hash_table (info); - osec = htab->text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - } - } - - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - /* This reloc will be computed at runtime, so there's no - need to do anything now, except for R_68K_32 - relocations that have been turned into - R_68K_RELATIVE. */ - if (!relocate) - continue; - } - - break; - - case R_68K_GNU_VTINHERIT: - case R_68K_GNU_VTENTRY: - /* These are no-ops in the end. */ - continue; - - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - return FALSE; - } - - if (r_symndx != STN_UNDEF - && r_type != R_68K_NONE - && (h == NULL - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - char sym_type; - - sym_type = (sym != NULL) ? ELF32_ST_TYPE (sym->st_info) : h->type; - - if (elf_m68k_reloc_tls_p (r_type) != (sym_type == STT_TLS)) - { - const char *name; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - _bfd_error_handler - ((sym_type == STT_TLS - /* xgettext:c-format */ - ? _("%B(%A+%#Lx): %s used with TLS symbol %s") - /* xgettext:c-format */ - : _("%B(%A+%#Lx): %s used with non-TLS symbol %s")), - input_bfd, - input_section, - rel->r_offset, - howto->name, - name); - } - } - - 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) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), - input_bfd, input_section, - rel->r_offset, name, (int) r); - return FALSE; - } - } - } - - return TRUE; -} - -/* Install an M_68K_PC32 relocation against VALUE at offset OFFSET - into section SEC. */ - -static void -elf_m68k_install_pc32 (asection *sec, bfd_vma offset, bfd_vma value) -{ - /* Make VALUE PC-relative. */ - value -= sec->output_section->vma + offset; - - /* Apply any in-place addend. */ - value += bfd_get_32 (sec->owner, sec->contents + offset); - - bfd_put_32 (sec->owner, value, sec->contents + offset); -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_m68k_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - bfd *dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - if (h->plt.offset != (bfd_vma) -1) - { - const struct elf_m68k_plt_info *plt_info; - asection *splt; - asection *sgot; - asection *srela; - 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. */ - - BFD_ASSERT (h->dynindx != -1); - - plt_info = elf_m68k_hash_table (info)->plt_info; - splt = elf_hash_table (info)->splt; - sgot = elf_hash_table (info)->sgotplt; - srela = elf_hash_table (info)->srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = (h->plt.offset / plt_info->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; - - memcpy (splt->contents + h->plt.offset, - plt_info->symbol_entry, - plt_info->size); - - elf_m68k_install_pc32 (splt, h->plt.offset + plt_info->symbol_relocs.got, - (sgot->output_section->vma - + sgot->output_offset - + got_offset)); - - bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela), - splt->contents - + h->plt.offset - + plt_info->symbol_resolve_entry + 2); - - elf_m68k_install_pc32 (splt, h->plt.offset + plt_info->symbol_relocs.plt, - splt->output_section->vma); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + plt_info->symbol_resolve_entry), - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_JMP_SLOT); - rela.r_addend = 0; - loc = srela->contents + plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (elf_m68k_hash_entry (h)->glist != NULL) - { - asection *sgot; - asection *srela; - struct elf_m68k_got_entry *got_entry; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - sgot = elf_hash_table (info)->sgot; - srela = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - got_entry = elf_m68k_hash_entry (h)->glist; - - while (got_entry != NULL) - { - enum elf_m68k_reloc_type r_type; - bfd_vma got_entry_offset; - - r_type = got_entry->key_.type; - got_entry_offset = got_entry->u.s2.offset &~ (bfd_vma) 1; - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - { - bfd_vma relocation; - - relocation = bfd_get_signed_32 (output_bfd, - (sgot->contents - + got_entry_offset)); - - /* Undo TP bias. */ - switch (elf_m68k_reloc_got_type (r_type)) - { - case R_68K_GOT32O: - case R_68K_TLS_LDM32: - break; - - case R_68K_TLS_GD32: - /* The value for this relocation is actually put in - the second GOT slot. */ - relocation = bfd_get_signed_32 (output_bfd, - (sgot->contents - + got_entry_offset + 4)); - relocation += dtpoff_base (info); - break; - - case R_68K_TLS_IE32: - relocation += tpoff_base (info); - break; - - default: - BFD_ASSERT (FALSE); - } - - elf_m68k_init_got_entry_local_shared (info, - output_bfd, - r_type, - sgot, - got_entry_offset, - relocation, - srela); - } - else - { - Elf_Internal_Rela rela; - - /* Put zeros to GOT slots that will be initialized - at run-time. */ - { - bfd_vma n_slots; - - n_slots = elf_m68k_reloc_got_n_slots (got_entry->key_.type); - while (n_slots--) - bfd_put_32 (output_bfd, (bfd_vma) 0, - (sgot->contents + got_entry_offset - + 4 * n_slots)); - } - - rela.r_addend = 0; - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_entry_offset); - - switch (elf_m68k_reloc_got_type (r_type)) - { - case R_68K_GOT32O: - rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT); - elf_m68k_install_rela (output_bfd, srela, &rela); - break; - - case R_68K_TLS_GD32: - rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_TLS_DTPMOD32); - elf_m68k_install_rela (output_bfd, srela, &rela); - - rela.r_offset += 4; - rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_TLS_DTPREL32); - elf_m68k_install_rela (output_bfd, srela, &rela); - break; - - case R_68K_TLS_IE32: - rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_TLS_TPREL32); - elf_m68k_install_rela (output_bfd, srela, &rela); - break; - - default: - BFD_ASSERT (FALSE); - break; - } - } - - got_entry = got_entry->u.s2.next; - } - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_COPY); - rela.r_addend = 0; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf_m68k_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sgot; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - sgot = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgot != NULL); - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = elf_hash_table (info)->sgotplt; - goto get_vma; - case DT_JMPREL: - s = elf_hash_table (info)->srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = elf_hash_table (info)->srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - if (splt->size > 0) - { - const struct elf_m68k_plt_info *plt_info; - - plt_info = elf_m68k_hash_table (info)->plt_info; - memcpy (splt->contents, plt_info->plt0_entry, plt_info->size); - - elf_m68k_install_pc32 (splt, plt_info->plt0_relocs.got4, - (sgot->output_section->vma - + sgot->output_offset - + 4)); - - elf_m68k_install_pc32 (splt, plt_info->plt0_relocs.got8, - (sgot->output_section->vma - + sgot->output_offset - + 8)); - - elf_section_data (splt->output_section)->this_hdr.sh_entsize - = plt_info->size; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -/* Given a .data section and a .emreloc in-memory section, store - relocation information into the .emreloc section which can be - used at runtime to relocate the section. This is called by the - linker when the --embedded-relocs switch is used. This is called - after the add_symbols entry point has been called for all the - objects, and before the final_link entry point is called. */ - -bfd_boolean -bfd_m68k_elf32_create_embedded_relocs (bfd *abfd, struct bfd_link_info *info, - asection *datasec, asection *relsec, - char **errmsg) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *p; - bfd_size_type amt; - - BFD_ASSERT (! bfd_link_relocatable (info)); - - *errmsg = NULL; - - if (datasec->reloc_count == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, datasec, NULL, (Elf_Internal_Rela *) NULL, - info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - amt = (bfd_size_type) datasec->reloc_count * 12; - relsec->contents = (bfd_byte *) bfd_alloc (abfd, amt); - if (relsec->contents == NULL) - goto error_return; - - p = relsec->contents; - - irelend = internal_relocs + datasec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++, p += 12) - { - asection *targetsec; - - /* We are going to write a four byte longword into the runtime - reloc section. The longword will be the address in the data - section which must be relocated. It is followed by the name - of the target section NUL-padded or truncated to 8 - characters. */ - - /* We can only relocate absolute longword relocs at run time. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_68K_32) - { - *errmsg = _("unsupported reloc type"); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - - /* Get the target section referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - targetsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - targetsec = h->root.u.def.section; - else - targetsec = NULL; - } - - bfd_put_32 (abfd, irel->r_offset + datasec->output_offset, p); - memset (p + 4, 0, 8); - if (targetsec != NULL) - strncpy ((char *) p + 4, targetsec->output_section->name, 8); - } - - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (datasec)->relocs != internal_relocs) - free (internal_relocs); - return TRUE; - -error_return: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (datasec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -/* Set target options. */ - -void -bfd_elf_m68k_set_target_options (struct bfd_link_info *info, int got_handling) -{ - struct elf_m68k_link_hash_table *htab; - bfd_boolean use_neg_got_offsets_p; - bfd_boolean allow_multigot_p; - bfd_boolean local_gp_p; - - switch (got_handling) - { - case 0: - /* --got=single. */ - local_gp_p = FALSE; - use_neg_got_offsets_p = FALSE; - allow_multigot_p = FALSE; - break; - - case 1: - /* --got=negative. */ - local_gp_p = TRUE; - use_neg_got_offsets_p = TRUE; - allow_multigot_p = FALSE; - break; - - case 2: - /* --got=multigot. */ - local_gp_p = TRUE; - use_neg_got_offsets_p = TRUE; - allow_multigot_p = TRUE; - break; - - default: - BFD_ASSERT (FALSE); - return; - } - - htab = elf_m68k_hash_table (info); - if (htab != NULL) - { - htab->local_gp_p = local_gp_p; - htab->use_neg_got_offsets_p = use_neg_got_offsets_p; - htab->allow_multigot_p = allow_multigot_p; - } -} - -static enum elf_reloc_type_class -elf32_m68k_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_68K_RELATIVE: - return reloc_class_relative; - case R_68K_JMP_SLOT: - return reloc_class_plt; - case R_68K_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* 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_m68k_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + (i + 1) * elf_m68k_get_plt_info (plt->owner)->size; -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf_m68k_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 154: /* Linux/m68k */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 22); - - /* pr_reg */ - offset = 70; - size = 80; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf_m68k_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/m68k elf_prpsinfo. */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 12); - 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 (n > 0 && command[n - 1] == ' ') - command[n - 1] = '\0'; - } - - return TRUE; -} - -/* Hook called by the linker routine which adds symbols from an object - file. */ - -static bfd_boolean -elf_m68k_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp ATTRIBUTE_UNUSED, - bfd_vma *valp ATTRIBUTE_UNUSED) -{ - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - return TRUE; -} - -#define TARGET_BIG_SYM m68k_elf32_vec -#define TARGET_BIG_NAME "elf32-m68k" -#define ELF_MACHINE_CODE EM_68K -#define ELF_MAXPAGESIZE 0x2000 -#define elf_backend_create_dynamic_sections \ - _bfd_elf_create_dynamic_sections -#define bfd_elf32_bfd_link_hash_table_create \ - elf_m68k_link_hash_table_create -#define bfd_elf32_bfd_final_link bfd_elf_final_link - -#define elf_backend_check_relocs elf_m68k_check_relocs -#define elf_backend_always_size_sections \ - elf_m68k_always_size_sections -#define elf_backend_adjust_dynamic_symbol \ - elf_m68k_adjust_dynamic_symbol -#define elf_backend_size_dynamic_sections \ - elf_m68k_size_dynamic_sections -#define elf_backend_final_write_processing elf_m68k_final_write_processing -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_relocate_section elf_m68k_relocate_section -#define elf_backend_finish_dynamic_symbol \ - elf_m68k_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf_m68k_finish_dynamic_sections -#define elf_backend_gc_mark_hook elf_m68k_gc_mark_hook -#define elf_backend_copy_indirect_symbol elf_m68k_copy_indirect_symbol -#define bfd_elf32_bfd_merge_private_bfd_data \ - elf32_m68k_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags \ - elf32_m68k_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - elf32_m68k_print_private_bfd_data -#define elf_backend_reloc_type_class elf32_m68k_reloc_type_class -#define elf_backend_plt_sym_val elf_m68k_plt_sym_val -#define elf_backend_object_p elf32_m68k_object_p -#define elf_backend_grok_prstatus elf_m68k_grok_prstatus -#define elf_backend_grok_psinfo elf_m68k_grok_psinfo -#define elf_backend_add_symbol_hook elf_m68k_add_symbol_hook - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-m88k.c b/sdcc/support/sdbinutils/bfd/elf32-m88k.c deleted file mode 100644 index 36aacdc0d..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-m88k.c +++ /dev/null @@ -1,38 +0,0 @@ -/* Motorola 88k-specific support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -/* This does not include any relocations, but should be good enough - for GDB. */ - -#define TARGET_BIG_SYM m88k_elf32_vec -#define TARGET_BIG_NAME "elf32-m88k" -#define ELF_ARCH bfd_arch_m88k -#define ELF_MACHINE_CODE EM_88K -#define ELF_MAXPAGESIZE 1 /* FIXME: This number is wrong, It should be the page size in bytes. */ -#define bfd_elf32_bfd_reloc_type_lookup bfd_default_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup -#define elf_info_to_howto _bfd_elf_no_info_to_howto - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-mcore.c b/sdcc/support/sdbinutils/bfd/elf32-mcore.c deleted file mode 100644 index 9334b1d75..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-mcore.c +++ /dev/null @@ -1,673 +0,0 @@ -/* Motorola MCore specific support for 32-bit ELF - Copyright (C) 1994-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* This file is based on a preliminary RCE ELF ABI. The - information may not match the final RCE ELF ABI. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/mcore.h" -#include - -/* RELA relocs are used here... */ - -/* Function to set whether a module needs the -mrelocatable bit set. */ - -static bfd_boolean -mcore_elf_set_private_flags (bfd * abfd, flagword flags) -{ - BFD_ASSERT (! elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -mcore_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - - /* Check if we have the same endianness. */ - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - else if (new_flags == old_flags) - /* Compatible flags are OK. */ - ; - else - { - /* FIXME */ - } - - return TRUE; -} - -/* Don't pretend we can deal with unsupported relocs. */ - -static bfd_reloc_status_type -mcore_elf_unsupported_reloc (bfd * abfd, - arelent * reloc_entry, - asymbol * symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection * input_section ATTRIBUTE_UNUSED, - bfd * output_bfd ATTRIBUTE_UNUSED, - char ** error_message ATTRIBUTE_UNUSED) -{ - BFD_ASSERT (reloc_entry->howto != (reloc_howto_type *)0); - - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Relocation %s (%d) is not currently supported.\n"), - abfd, - reloc_entry->howto->name, - reloc_entry->howto->type); - - return bfd_reloc_notsupported; -} - -static reloc_howto_type * mcore_elf_howto_table [(int) R_MCORE_max]; - -static reloc_howto_type mcore_elf_howto_raw[] = -{ - /* This reloc does nothing. */ - HOWTO (R_MCORE_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_MCORE_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 32 bit relocation. */ - HOWTO (R_MCORE_ADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "ADDR32", /* name *//* For compatibility with coff/pe port. */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 8 bits + 2 zero bits; jmpi/jsri/lrw instructions. - Should not appear in object files. */ - HOWTO (R_MCORE_PCRELIMM8BY4, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mcore_elf_unsupported_reloc, /* special_function */ - "R_MCORE_PCRELIMM8BY4",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* bsr/bt/bf/br instructions; 11 bits + 1 zero bit - Span 2k instructions == 4k bytes. - Only useful pieces at the relocated address are the opcode (5 bits) */ - HOWTO (R_MCORE_PCRELIMM11BY2,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MCORE_PCRELIMM11BY2",/* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x7ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 4 bits + 1 zero bit; 'loopt' instruction only; unsupported. */ - HOWTO (R_MCORE_PCRELIMM4BY2, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 4, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mcore_elf_unsupported_reloc,/* special_function */ - "R_MCORE_PCRELIMM4BY2",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32-bit pc-relative. Eventually this will help support PIC code. */ - HOWTO (R_MCORE_PCREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MCORE_PCREL32", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like PCRELIMM11BY2, this relocation indicates that there is a - 'jsri' at the specified address. There is a separate relocation - entry for the literal pool entry that it references, but we - might be able to change the jsri to a bsr if the target turns out - to be close enough [even though we won't reclaim the literal pool - entry, we'll get some runtime efficiency back]. Note that this - is a relocation that we are allowed to safely ignore. */ - HOWTO (R_MCORE_PCRELJSR_IMM11BY2,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MCORE_PCRELJSR_IMM11BY2", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x7ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_MCORE_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_MCORE_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_MCORE_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_MCORE_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MCORE_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - NULL, /* special_function */ - "R_MCORE_RELATIVE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -#ifndef NUM_ELEM -#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) -#endif - -/* Initialize the mcore_elf_howto_table, so that linear accesses can be done. */ -static void -mcore_elf_howto_init (void) -{ - unsigned int i; - - for (i = NUM_ELEM (mcore_elf_howto_raw); i--;) - { - unsigned int type; - - type = mcore_elf_howto_raw[i].type; - - BFD_ASSERT (type < NUM_ELEM (mcore_elf_howto_table)); - - mcore_elf_howto_table [type] = & mcore_elf_howto_raw [i]; - } -} - -static reloc_howto_type * -mcore_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - enum elf_mcore_reloc_type mcore_reloc = R_MCORE_NONE; - - switch (code) - { - case BFD_RELOC_NONE: mcore_reloc = R_MCORE_NONE; break; - case BFD_RELOC_32: mcore_reloc = R_MCORE_ADDR32; break; - case BFD_RELOC_MCORE_PCREL_IMM8BY4: mcore_reloc = R_MCORE_PCRELIMM8BY4; break; - case BFD_RELOC_MCORE_PCREL_IMM11BY2: mcore_reloc = R_MCORE_PCRELIMM11BY2; break; - case BFD_RELOC_MCORE_PCREL_IMM4BY2: mcore_reloc = R_MCORE_PCRELIMM4BY2; break; - case BFD_RELOC_32_PCREL: mcore_reloc = R_MCORE_PCREL32; break; - case BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2: mcore_reloc = R_MCORE_PCRELJSR_IMM11BY2; break; - case BFD_RELOC_VTABLE_INHERIT: mcore_reloc = R_MCORE_GNU_VTINHERIT; break; - case BFD_RELOC_VTABLE_ENTRY: mcore_reloc = R_MCORE_GNU_VTENTRY; break; - case BFD_RELOC_RVA: mcore_reloc = R_MCORE_RELATIVE; break; - default: - return NULL; - } - - if (! mcore_elf_howto_table [R_MCORE_PCRELIMM8BY4]) - /* Initialize howto table if needed. */ - mcore_elf_howto_init (); - - return mcore_elf_howto_table [(int) mcore_reloc]; -}; - -static reloc_howto_type * -mcore_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (mcore_elf_howto_raw) / sizeof (mcore_elf_howto_raw[0]); - i++) - if (mcore_elf_howto_raw[i].name != NULL - && strcasecmp (mcore_elf_howto_raw[i].name, r_name) == 0) - return &mcore_elf_howto_raw[i]; - - return NULL; -} - -/* Set the howto pointer for a RCE ELF reloc. */ - -static void -mcore_elf_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - if (! mcore_elf_howto_table [R_MCORE_PCRELIMM8BY4]) - /* Initialize howto table if needed. */ - mcore_elf_howto_init (); - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_MCORE_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised MCore reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_MCORE_NONE; - } - - cache_ptr->howto = mcore_elf_howto_table [r_type]; -} - -/* 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. */ - -static bfd_boolean -mcore_elf_relocate_section (bfd * output_bfd, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - struct elf_link_hash_entry ** sym_hashes = elf_sym_hashes (input_bfd); - Elf_Internal_Rela * rel = relocs; - Elf_Internal_Rela * relend = relocs + input_section->reloc_count; - bfd_boolean ret = TRUE; - -#ifdef DEBUG - _bfd_error_handler - ("mcore_elf_relocate_section called for %B section %A, %u relocations%s", - input_bfd, - input_section, - input_section->reloc_count, - (bfd_link_relocatable (info)) ? " (relocatable)" : ""); -#endif - - if (! mcore_elf_howto_table [R_MCORE_PCRELIMM8BY4]) /* Initialize howto table if needed */ - mcore_elf_howto_init (); - - for (; rel < relend; rel++) - { - enum elf_mcore_reloc_type r_type = (enum elf_mcore_reloc_type) ELF32_R_TYPE (rel->r_info); - bfd_vma offset = rel->r_offset; - bfd_vma addend = rel->r_addend; - bfd_reloc_status_type r = bfd_reloc_other; - asection * sec = NULL; - reloc_howto_type * howto; - bfd_vma relocation; - Elf_Internal_Sym * sym = NULL; - unsigned long r_symndx; - struct elf_link_hash_entry * h = NULL; - unsigned short oldinst = 0; - - /* Unknown relocation handling. */ - if ((unsigned) r_type >= (unsigned) R_MCORE_max - || ! mcore_elf_howto_table [(int)r_type]) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Unknown relocation type %d\n"), - input_bfd, (int) r_type); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - } - - howto = mcore_elf_howto_table [(int) r_type]; - r_symndx = ELF32_R_SYM (rel->r_info); - - /* Complain about known relocation that are not yet supported. */ - if (howto->special_function == mcore_elf_unsupported_reloc) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Relocation %s (%d) is not currently supported.\n"), - input_bfd, - howto->name, - (int)r_type); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - } - - 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); - addend = rel->r_addend; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (r_type) - { - default: - break; - - case R_MCORE_PCRELJSR_IMM11BY2: - oldinst = bfd_get_16 (input_bfd, contents + offset); -#define MCORE_INST_BSR 0xF800 - bfd_put_16 (input_bfd, (bfd_vma) MCORE_INST_BSR, contents + offset); - break; - } - -#ifdef DEBUG - fprintf (stderr, "\ttype = %s (%d), symbol index = %ld, offset = %ld, addend = %ld\n", - howto->name, r_type, r_symndx, (long) offset, (long) addend); -#endif - - r = _bfd_final_link_relocate - (howto, input_bfd, input_section, contents, offset, relocation, addend); - - if (r != bfd_reloc_ok && r_type == R_MCORE_PCRELJSR_IMM11BY2) - { - /* Wasn't ok, back it out and give up. */ - bfd_put_16 (input_bfd, (bfd_vma) oldinst, contents + offset); - r = bfd_reloc_ok; - } - - if (r != bfd_reloc_ok) - { - ret = FALSE; - - switch (r) - { - default: - break; - - case bfd_reloc_overflow: - { - const char * name; - - if (h != NULL) - name = NULL; - else - { - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - - if (name == NULL) - break; - - if (* name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, offset); - } - break; - } - } - } - -#ifdef DEBUG - fprintf (stderr, "\n"); -#endif - - return ret; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -mcore_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_MCORE_GNU_VTINHERIT: - case R_MCORE_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -mcore_elf_check_relocs (bfd * abfd, - struct bfd_link_info * info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry * h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes [r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_MCORE_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_MCORE_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -static const struct bfd_elf_special_section mcore_elf_special_sections[]= -{ - { STRING_COMMA_LEN (".ctors"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".dtors"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } -}; - -#define TARGET_BIG_SYM mcore_elf32_be_vec -#define TARGET_BIG_NAME "elf32-mcore-big" -#define TARGET_LITTLE_SYM mcore_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-mcore-little" - -#define ELF_ARCH bfd_arch_mcore -#define ELF_MACHINE_CODE EM_MCORE -#define ELF_MAXPAGESIZE 0x1000 /* 4k, if we ever have 'em */ -#define elf_info_to_howto mcore_elf_info_to_howto -#define elf_info_to_howto_rel NULL - -#define bfd_elf32_bfd_merge_private_bfd_data mcore_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags mcore_elf_set_private_flags -#define bfd_elf32_bfd_reloc_type_lookup mcore_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup mcore_elf_reloc_name_lookup -#define elf_backend_relocate_section mcore_elf_relocate_section -#define elf_backend_gc_mark_hook mcore_elf_gc_mark_hook -#define elf_backend_check_relocs mcore_elf_check_relocs -#define elf_backend_special_sections mcore_elf_special_sections - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-mep.c b/sdcc/support/sdbinutils/bfd/elf32-mep.c deleted file mode 100644 index d9d457b3f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-mep.c +++ /dev/null @@ -1,761 +0,0 @@ -/* MeP-specific support for 32-bit ELF. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/mep.h" -#include "libiberty.h" - -/* Forward declarations. */ - -/* Private relocation functions. */ - -#define MEPREL(type, size, bits, right, left, pcrel, overflow, mask) \ - {(unsigned)type, right, size, bits, pcrel, left, overflow, bfd_elf_generic_reloc, #type, FALSE, 0, mask, 0 } - -#define N complain_overflow_dont -#define S complain_overflow_signed -#define U complain_overflow_unsigned - -static reloc_howto_type mep_elf_howto_table [] = -{ - /* type, size, bits, leftshift, rightshift, pcrel, OD/OS/OU, mask. */ - MEPREL (R_MEP_NONE, 3, 0, 0, 0, 0, N, 0), - MEPREL (R_RELC, 0, 0, 0, 0, 0, N, 0), - /* MEPRELOC:HOWTO */ - /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */ - MEPREL (R_MEP_8, 0, 8, 0, 0, 0, U, 0xff), - MEPREL (R_MEP_16, 1, 16, 0, 0, 0, U, 0xffff), - MEPREL (R_MEP_32, 2, 32, 0, 0, 0, U, 0xffffffff), - MEPREL (R_MEP_PCREL8A2, 1, 8, 1, 1, 1, S, 0x00fe), - MEPREL (R_MEP_PCREL12A2,1, 12, 1, 1, 1, S, 0x0ffe), - MEPREL (R_MEP_PCREL17A2,2, 17, 0, 1, 1, S, 0x0000ffff), - MEPREL (R_MEP_PCREL24A2,2, 24, 0, 1, 1, S, 0x07f0ffff), - MEPREL (R_MEP_PCABS24A2,2, 24, 0, 1, 0, U, 0x07f0ffff), - MEPREL (R_MEP_LOW16, 2, 16, 0, 0, 0, N, 0x0000ffff), - MEPREL (R_MEP_HI16U, 2, 32, 0,16, 0, N, 0x0000ffff), - MEPREL (R_MEP_HI16S, 2, 32, 0,16, 0, N, 0x0000ffff), - MEPREL (R_MEP_GPREL, 2, 16, 0, 0, 0, S, 0x0000ffff), - MEPREL (R_MEP_TPREL, 2, 16, 0, 0, 0, S, 0x0000ffff), - MEPREL (R_MEP_TPREL7, 1, 7, 0, 0, 0, U, 0x007f), - MEPREL (R_MEP_TPREL7A2, 1, 7, 1, 1, 0, U, 0x007e), - MEPREL (R_MEP_TPREL7A4, 1, 7, 2, 2, 0, U, 0x007c), - MEPREL (R_MEP_UIMM24, 2, 24, 0, 0, 0, U, 0x00ffffff), - MEPREL (R_MEP_ADDR24A4, 2, 24, 0, 2, 0, U, 0x00fcffff), - MEPREL (R_MEP_GNU_VTINHERIT,1, 0,16,32, 0, N, 0x0000), - MEPREL (R_MEP_GNU_VTENTRY,1, 0,16,32, 0, N, 0x0000), - /* MEPRELOC:END */ -}; - -#define VALID_MEP_RELOC(N) ((N) >= 0 \ - && (N) < ARRAY_SIZE (mep_elf_howto_table) - -#undef N -#undef S -#undef U - - -#define BFD_RELOC_MEP_NONE BFD_RELOC_NONE -#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) -#define MAP(n) case BFD_RELOC_MEP_##n: type = R_MEP_##n; break -#else -#define MAP(n) case BFD_RELOC_MEP_/**/n: type = R_MEP_/**/n; break -#endif - -static reloc_howto_type * -mep_reloc_type_lookup - (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int type = 0; - - switch (code) - { - MAP(NONE); - case BFD_RELOC_8: - type = R_MEP_8; - break; - case BFD_RELOC_16: - type = R_MEP_16; - break; - case BFD_RELOC_32: - type = R_MEP_32; - break; - case BFD_RELOC_VTABLE_ENTRY: - type = R_MEP_GNU_VTENTRY; - break; - case BFD_RELOC_VTABLE_INHERIT: - type = R_MEP_GNU_VTINHERIT; - break; - case BFD_RELOC_RELC: - type = R_RELC; - break; - - /* MEPRELOC:MAP */ - /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */ - MAP(8); - MAP(16); - MAP(32); - MAP(PCREL8A2); - MAP(PCREL12A2); - MAP(PCREL17A2); - MAP(PCREL24A2); - MAP(PCABS24A2); - MAP(LOW16); - MAP(HI16U); - MAP(HI16S); - MAP(GPREL); - MAP(TPREL); - MAP(TPREL7); - MAP(TPREL7A2); - MAP(TPREL7A4); - MAP(UIMM24); - MAP(ADDR24A4); - MAP(GNU_VTINHERIT); - MAP(GNU_VTENTRY); - /* MEPRELOC:END */ - - default: - /* Pacify gcc -Wall. */ - _bfd_error_handler (_("mep: no reloc for code %d"), code); - return NULL; - } - - if (mep_elf_howto_table[type].type != type) - { - /* xgettext:c-format */ - _bfd_error_handler (_("MeP: howto %d has type %d"), - type, mep_elf_howto_table[type].type); - abort (); - } - - return mep_elf_howto_table + type; -} - -#undef MAP - -static reloc_howto_type * -mep_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (mep_elf_howto_table) / sizeof (mep_elf_howto_table[0]); - i++) - if (mep_elf_howto_table[i].name != NULL - && strcasecmp (mep_elf_howto_table[i].name, r_name) == 0) - return &mep_elf_howto_table[i]; - - return NULL; -} - -/* Perform a single relocation. */ - -static struct bfd_link_info *mep_info; -static int warn_tp = 0, warn_sda = 0; - -static bfd_vma -mep_lookup_global - (char * name, - bfd_vma ofs, - bfd_vma * cache, - int * warn) -{ - struct bfd_link_hash_entry *h; - - if (*cache || *warn) - return *cache; - - h = bfd_link_hash_lookup (mep_info->hash, name, FALSE, FALSE, TRUE); - if (h == 0 || h->type != bfd_link_hash_defined) - { - *warn = ofs + 1; - return 0; - } - *cache = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - return *cache; -} - -static bfd_vma -mep_tpoff_base (bfd_vma ofs) -{ - static bfd_vma cache = 0; - return mep_lookup_global ("__tpbase", ofs, &cache, &warn_tp); -} - -static bfd_vma -mep_sdaoff_base (bfd_vma ofs) -{ - static bfd_vma cache = 0; - return mep_lookup_global ("__sdabase", ofs, &cache, &warn_sda); -} - -static bfd_reloc_status_type -mep_final_link_relocate - (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation) -{ - unsigned long u; - long s; - unsigned char *byte; - bfd_vma pc; - bfd_reloc_status_type r = bfd_reloc_ok; - int e2, e4; - - if (bfd_big_endian (input_bfd)) - { - e2 = 0; - e4 = 0; - } - else - { - e2 = 1; - e4 = 3; - } - - pc = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - s = relocation + rel->r_addend; - - byte = (unsigned char *)contents + rel->r_offset; - - if (howto->type == R_MEP_PCREL24A2 - && s == 0 - && pc >= 0x800000) - { - /* This is an unreachable branch to an undefined weak function. - Silently ignore it, since the opcode can't do that but should - never be executed anyway. */ - return bfd_reloc_ok; - } - - if (howto->pc_relative) - s -= pc; - - u = (unsigned long) s; - - switch (howto->type) - { - /* MEPRELOC:APPLY */ - /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h. */ - case R_MEP_8: /* 76543210 */ - if (u > 255) r = bfd_reloc_overflow; - byte[0] = (u & 0xff); - break; - case R_MEP_16: /* fedcba9876543210 */ - if (u > 65535) r = bfd_reloc_overflow; - byte[0^e2] = ((u >> 8) & 0xff); - byte[1^e2] = (u & 0xff); - break; - case R_MEP_32: /* vutsrqponmlkjihgfedcba9876543210 */ - byte[0^e4] = ((u >> 24) & 0xff); - byte[1^e4] = ((u >> 16) & 0xff); - byte[2^e4] = ((u >> 8) & 0xff); - byte[3^e4] = (u & 0xff); - break; - case R_MEP_PCREL8A2: /* --------7654321- */ - if (-128 > s || s > 127) r = bfd_reloc_overflow; - byte[1^e2] = (byte[1^e2] & 0x01) | (s & 0xfe); - break; - case R_MEP_PCREL12A2: /* ----ba987654321- */ - if (-2048 > s || s > 2047) r = bfd_reloc_overflow; - byte[0^e2] = (byte[0^e2] & 0xf0) | ((s >> 8) & 0x0f); - byte[1^e2] = (byte[1^e2] & 0x01) | (s & 0xfe); - break; - case R_MEP_PCREL17A2: /* ----------------gfedcba987654321 */ - if (-65536 > s || s > 65535) r = bfd_reloc_overflow; - byte[2^e2] = ((s >> 9) & 0xff); - byte[3^e2] = ((s >> 1) & 0xff); - break; - case R_MEP_PCREL24A2: /* -----7654321----nmlkjihgfedcba98 */ - if (-8388608 > s || s > 8388607) r = bfd_reloc_overflow; - byte[0^e2] = (byte[0^e2] & 0xf8) | ((s >> 5) & 0x07); - byte[1^e2] = (byte[1^e2] & 0x0f) | ((s << 3) & 0xf0); - byte[2^e2] = ((s >> 16) & 0xff); - byte[3^e2] = ((s >> 8) & 0xff); - break; - case R_MEP_PCABS24A2: /* -----7654321----nmlkjihgfedcba98 */ - if (u > 16777215) r = bfd_reloc_overflow; - byte[0^e2] = (byte[0^e2] & 0xf8) | ((u >> 5) & 0x07); - byte[1^e2] = (byte[1^e2] & 0x0f) | ((u << 3) & 0xf0); - byte[2^e2] = ((u >> 16) & 0xff); - byte[3^e2] = ((u >> 8) & 0xff); - break; - case R_MEP_LOW16: /* ----------------fedcba9876543210 */ - byte[2^e2] = ((u >> 8) & 0xff); - byte[3^e2] = (u & 0xff); - break; - case R_MEP_HI16U: /* ----------------vutsrqponmlkjihg */ - byte[2^e2] = ((u >> 24) & 0xff); - byte[3^e2] = ((u >> 16) & 0xff); - break; - case R_MEP_HI16S: /* ----------------vutsrqponmlkjihg */ - if (s & 0x8000) - s += 0x10000; - byte[2^e2] = ((s >> 24) & 0xff); - byte[3^e2] = ((s >> 16) & 0xff); - break; - case R_MEP_GPREL: /* ----------------fedcba9876543210 */ - s -= mep_sdaoff_base(rel->r_offset); - if (-32768 > s || s > 32767) r = bfd_reloc_overflow; - byte[2^e2] = ((s >> 8) & 0xff); - byte[3^e2] = (s & 0xff); - break; - case R_MEP_TPREL: /* ----------------fedcba9876543210 */ - s -= mep_tpoff_base(rel->r_offset); - if (-32768 > s || s > 32767) r = bfd_reloc_overflow; - byte[2^e2] = ((s >> 8) & 0xff); - byte[3^e2] = (s & 0xff); - break; - case R_MEP_TPREL7: /* ---------6543210 */ - u -= mep_tpoff_base(rel->r_offset); - if (u > 127) r = bfd_reloc_overflow; - byte[1^e2] = (byte[1^e2] & 0x80) | (u & 0x7f); - break; - case R_MEP_TPREL7A2: /* ---------654321- */ - u -= mep_tpoff_base(rel->r_offset); - if (u > 127) r = bfd_reloc_overflow; - byte[1^e2] = (byte[1^e2] & 0x81) | (u & 0x7e); - break; - case R_MEP_TPREL7A4: /* ---------65432-- */ - u -= mep_tpoff_base(rel->r_offset); - if (u > 127) r = bfd_reloc_overflow; - byte[1^e2] = (byte[1^e2] & 0x83) | (u & 0x7c); - break; - case R_MEP_UIMM24: /* --------76543210nmlkjihgfedcba98 */ - if (u > 16777215) r = bfd_reloc_overflow; - byte[1^e2] = (u & 0xff); - byte[2^e2] = ((u >> 16) & 0xff); - byte[3^e2] = ((u >> 8) & 0xff); - break; - case R_MEP_ADDR24A4: /* --------765432--nmlkjihgfedcba98 */ - if (u > 16777215) r = bfd_reloc_overflow; - byte[1^e2] = (byte[1^e2] & 0x03) | (u & 0xfc); - byte[2^e2] = ((u >> 16) & 0xff); - byte[3^e2] = ((u >> 8) & 0xff); - break; - case R_MEP_GNU_VTINHERIT: /* ---------------- */ - break; - case R_MEP_GNU_VTENTRY: /* ---------------- */ - break; - /* MEPRELOC:END */ - default: - abort (); - } - - return r; -} - -/* Set the howto pointer for a MEP ELF reloc. */ - -static void -mep_info_to_howto_rela - (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_MEP_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid MEP reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & mep_elf_howto_table [r_type]; -} - -/* Relocate a MEP ELF section. - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -mep_elf_relocate_section - (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - mep_info = info; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - howto = mep_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned, unresolved_reloc, ignored; - - RELOC_FOR_GLOBAL_SYMBOL(info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - if (r_type == R_RELC) - r = bfd_elf_perform_complex_relocation (input_bfd, input_section, - contents, rel, relocation); - else - r = mep_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - if (warn_tp) - info->callbacks->undefined_symbol - (info, "__tpbase", input_bfd, input_section, warn_tp-1, TRUE); - if (warn_sda) - info->callbacks->undefined_symbol - (info, "__sdabase", input_bfd, input_section, warn_sda-1, TRUE); - if (warn_sda || warn_tp) - return FALSE; - - return TRUE; -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -mep_elf_set_private_flags (bfd * abfd, - flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -mep_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - static bfd *last_ibfd = 0; - flagword old_flags, new_flags; - flagword old_partial, new_partial; - - /* Check if we have the same endianness. */ - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - -#ifdef DEBUG - _bfd_error_handler ("%B: old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s", - ibfd, old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no"); -#endif - - /* First call, no flags set. */ - if (!elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - old_flags = new_flags; - } - else if ((new_flags | old_flags) & EF_MEP_LIBRARY) - { - /* Non-library flags trump library flags. The choice doesn't really - matter if both OLD_FLAGS and NEW_FLAGS have EF_MEP_LIBRARY set. */ - if (old_flags & EF_MEP_LIBRARY) - old_flags = new_flags; - } - else - { - /* Make sure they're for the same mach. Allow upgrade from the "mep" - mach. */ - new_partial = (new_flags & EF_MEP_CPU_MASK); - old_partial = (old_flags & EF_MEP_CPU_MASK); - if (new_partial == old_partial) - ; - else if (new_partial == EF_MEP_CPU_MEP) - ; - else if (old_partial == EF_MEP_CPU_MEP) - old_flags = (old_flags & ~EF_MEP_CPU_MASK) | new_partial; - else - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B and %B are for different cores"), - last_ibfd, ibfd); - bfd_set_error (bfd_error_invalid_target); - return FALSE; - } - - /* Make sure they're for the same me_module. Allow basic config to - mix with any other. */ - new_partial = (new_flags & EF_MEP_INDEX_MASK); - old_partial = (old_flags & EF_MEP_INDEX_MASK); - if (new_partial == old_partial) - ; - else if (new_partial == 0) - ; - else if (old_partial == 0) - old_flags = (old_flags & ~EF_MEP_INDEX_MASK) | new_partial; - else - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B and %B are for different configurations"), - last_ibfd, ibfd); - bfd_set_error (bfd_error_invalid_target); - return FALSE; - } - } - - elf_elfheader (obfd)->e_flags = old_flags; - last_ibfd = ibfd; - return TRUE; -} - -/* This will be edited by the MeP configration tool. */ -static const char * config_names[] = -{ - "basic" - /* start-mepcfgtool */ - ,"default" - /* end-mepcfgtool */ -}; - -static const char * core_names[] = -{ - "MeP", "MeP-c2", "MeP-c3", "MeP-h1" -}; - -static bfd_boolean -mep_elf_print_private_bfd_data (bfd * abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - flagword flags, partial_flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx"), (unsigned long) flags); - - partial_flags = (flags & EF_MEP_CPU_MASK) >> 24; - if (partial_flags < ARRAY_SIZE (core_names)) - fprintf (file, " core: %s", core_names[(long)partial_flags]); - - partial_flags = flags & EF_MEP_INDEX_MASK; - if (partial_flags < ARRAY_SIZE (config_names)) - fprintf (file, " me_module: %s", config_names[(long)partial_flags]); - - fputc ('\n', file); - - return TRUE; -} - -/* Return the machine subcode from the ELF e_flags header. */ - -static int -elf32_mep_machine (bfd * abfd) -{ - switch (elf_elfheader (abfd)->e_flags & EF_MEP_CPU_MASK) - { - default: break; - case EF_MEP_CPU_C2: return bfd_mach_mep; - case EF_MEP_CPU_C3: return bfd_mach_mep; - case EF_MEP_CPU_C4: return bfd_mach_mep; - case EF_MEP_CPU_C5: return bfd_mach_mep_c5; - case EF_MEP_CPU_H1: return bfd_mach_mep_h1; - } - - return bfd_mach_mep; -} - -static bfd_boolean -mep_elf_object_p (bfd * abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_mep, elf32_mep_machine (abfd)); - return TRUE; -} - -static bfd_boolean -mep_elf_section_flags (flagword * flags, const Elf_Internal_Shdr * hdr) -{ - if (hdr->sh_flags & SHF_MEP_VLIW) - * flags |= SEC_MEP_VLIW; - return TRUE; -} - -static bfd_boolean -mep_elf_fake_sections (bfd * abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr * hdr, - asection * sec) -{ - if (sec->flags & SEC_MEP_VLIW) - hdr->sh_flags |= SHF_MEP_VLIW; - return TRUE; -} - - -#define ELF_ARCH bfd_arch_mep -#define ELF_MACHINE_CODE EM_CYGNUS_MEP -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM mep_elf32_vec -#define TARGET_BIG_NAME "elf32-mep" - -#define TARGET_LITTLE_SYM mep_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-mep-little" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto mep_info_to_howto_rela -#define elf_backend_relocate_section mep_elf_relocate_section -#define elf_backend_object_p mep_elf_object_p -#define elf_backend_section_flags mep_elf_section_flags -#define elf_backend_fake_sections mep_elf_fake_sections - -#define bfd_elf32_bfd_reloc_type_lookup mep_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup mep_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags mep_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data mep_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data mep_elf_print_private_bfd_data - -#define elf_backend_rela_normal 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-metag.c b/sdcc/support/sdbinutils/bfd/elf32-metag.c deleted file mode 100644 index b985fc0b0..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-metag.c +++ /dev/null @@ -1,4163 +0,0 @@ -/* Meta support for 32-bit ELF - Copyright (C) 2013-2018 Free Software Foundation, Inc. - Contributed by Imagination Technologies Ltd. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf32-metag.h" -#include "elf/metag.h" - -#define GOT_ENTRY_SIZE 4 -#define ELF_DYNAMIC_INTERPRETER "/lib/ld-uClibc.so.0" - -/* ABI version: - 0 - original - 1 - with GOT offset */ -#define METAG_ELF_ABI_VERSION 1 - -static const unsigned int plt0_entry[] = - { - 0x02000005, /* MOVT D0Re0, #HI(GOT+4) */ - 0x02000000, /* ADD D0Re0, D0Re0, #LO(GOT+4) */ - 0xb70001e3, /* SETL [A0StP++], D0Re0, D1Re0 */ - 0xc600012a, /* GETD PC, [D0Re0+#4] */ - 0xa0fffffe /* NOP */ - }; - -static const unsigned int plt0_pic_entry[] = - { - 0x82900001, /* ADDT A0.2, CPC0, #0 */ - 0x82100000, /* ADD A0.2, A0.2, #0 */ - 0xa3100c20, /* MOV D0Re0, A0.2 */ - 0xb70001e3, /* SETL [A0StP++], D0Re0, D1Re0 */ - 0xc600012a, /* GETD PC, [D0Re0+#4] */ - }; - -static const unsigned int plt_entry[] = - { - 0x82100005, /* MOVT A0.2, #HI(GOT+off) */ - 0x82100000, /* ADD A0.2, A0.2, #LO(GOT+off) */ - 0xc600806a, /* GETD PC, [A0.2] */ - 0x03000004, /* MOV D1Re0, #LO(offset) */ - 0xa0000000 /* B PLT0 */ - }; - -static const unsigned int plt_pic_entry[] = - { - 0x82900001, /* ADDT A0.2, CPC0, #HI(GOT+off) */ - 0x82100000, /* ADD A0.2, A0.2, #LO(GOT+off) */ - 0xc600806a, /* GETD PC, [A0.2] */ - 0x03000004, /* MOV D1Re0, #LO(offset) */ - 0xa0000000 /* B PLT0 */ - }; - -/* Variable names follow a coding style. - Please follow this (Apps Hungarian) style: - - Structure/Variable Prefix - elf_link_hash_table "etab" - elf_link_hash_entry "eh" - - elf_metag_link_hash_table "htab" - elf_metag_link_hash_entry "hh" - - bfd_link_hash_table "btab" - bfd_link_hash_entry "bh" - - bfd_hash_table containing stubs "bstab" - elf_metag_stub_hash_entry "hsh" - - Always remember to use GNU Coding Style. */ - -#define PLT_ENTRY_SIZE sizeof(plt_entry) - -static reloc_howto_type elf_metag_howto_table[] = -{ - /* High order 16 bit absolute. */ - HOWTO (R_METAG_HIADDR16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_HIADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low order 16 bit absolute. */ - HOWTO (R_METAG_LOADDR16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_LOADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute. */ - HOWTO (R_METAG_ADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_ADDR32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* No relocation. */ - HOWTO (R_METAG_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 19 bit pc relative */ - HOWTO (R_METAG_RELBRANCH, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 5, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_RELBRANCH", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00ffffe0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GET/SET offset */ - HOWTO (R_METAG_GETSETOFF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_GETSETOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (6), - EMPTY_HOWTO (7), - EMPTY_HOWTO (8), - EMPTY_HOWTO (9), - EMPTY_HOWTO (10), - EMPTY_HOWTO (11), - EMPTY_HOWTO (12), - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - EMPTY_HOWTO (16), - EMPTY_HOWTO (17), - EMPTY_HOWTO (18), - EMPTY_HOWTO (19), - EMPTY_HOWTO (20), - EMPTY_HOWTO (21), - EMPTY_HOWTO (22), - EMPTY_HOWTO (23), - EMPTY_HOWTO (24), - EMPTY_HOWTO (25), - EMPTY_HOWTO (26), - EMPTY_HOWTO (27), - EMPTY_HOWTO (28), - EMPTY_HOWTO (29), - - HOWTO (R_METAG_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_METAG_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_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_METAG_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High order 16 bit GOT offset */ - HOWTO (R_METAG_HI16_GOTOFF, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_HI16_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low order 16 bit GOT offset */ - HOWTO (R_METAG_LO16_GOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_LO16_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GET/SET GOT offset */ - HOWTO (R_METAG_GETSET_GOTOFF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_GETSET_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GET/SET GOT relative */ - HOWTO (R_METAG_GETSET_GOT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_GETSET_GOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High order 16 bit GOT reference */ - HOWTO (R_METAG_HI16_GOTPC, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_HI16_GOTPC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low order 16 bit GOT reference */ - HOWTO (R_METAG_LO16_GOTPC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_LO16_GOTPC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High order 16 bit PLT */ - HOWTO (R_METAG_HI16_PLT, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_HI16_PLT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low order 16 bit PLT */ - HOWTO (R_METAG_LO16_PLT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_LO16_PLT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_RELBRANCH_PLT, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 5, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_RELBRANCH_PLT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00ffffe0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Dummy relocs used by the linker internally. */ - HOWTO (R_METAG_GOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_PLT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_METAG_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_COPY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marks a procedure linkage table entry for a symbol. */ - HOWTO (R_METAG_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_METAG_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_GD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LDM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_LDO_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LDO_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_LDO_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LDO_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Dummy reloc used by the linker internally. */ - HOWTO (R_METAG_TLS_LDO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LDO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_IE, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_IE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007ff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Dummy reloc used by the linker internally. */ - HOWTO (R_METAG_TLS_IENONPIC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_IENONPIC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_IENONPIC_HI16,/* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_IENONPIC_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_IENONPIC_LO16,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_IENONPIC_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_TPOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_TPOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_DTPMOD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_DTPMOD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_DTPOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_DTPOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Dummy reloc used by the linker internally. */ - HOWTO (R_METAG_TLS_LE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_LE_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LE_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_METAG_TLS_LE_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 3, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_METAG_TLS_LE_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007fff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -#define BRANCH_BITS 19 - -/* The GOT is typically accessed using a [GS]ETD instruction. The size of the - immediate offset which can be used in such instructions therefore limits - the usable size of the GOT. If the base register for the [GS]ETD (A1LbP) - is pointing to the base of the GOT then the size is limited to the maximum - 11 bits unsigned dword offset, or 2^13 = 0x2000 bytes. However the offset - in a [GS]ETD instruction is signed, so by setting the base address register - to an offset of that 0x2000 byte maximum unsigned offset from the base of - the GOT we can use negative offsets in addition to positive. This - effectively doubles the usable GOT size to 0x4000 bytes. */ -#define GOT_REG_OFFSET 0x2000 - -struct metag_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int metag_reloc_val; -}; - -static const struct metag_reloc_map metag_reloc_map [] = - { - { BFD_RELOC_NONE, R_METAG_NONE }, - { BFD_RELOC_32, R_METAG_ADDR32 }, - { BFD_RELOC_METAG_HIADDR16, R_METAG_HIADDR16 }, - { BFD_RELOC_METAG_LOADDR16, R_METAG_LOADDR16 }, - { BFD_RELOC_METAG_RELBRANCH, R_METAG_RELBRANCH }, - { BFD_RELOC_METAG_GETSETOFF, R_METAG_GETSETOFF }, - { BFD_RELOC_VTABLE_INHERIT, R_METAG_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_METAG_GNU_VTENTRY }, - { BFD_RELOC_METAG_REL8, R_METAG_REL8 }, - { BFD_RELOC_METAG_REL16, R_METAG_REL16 }, - { BFD_RELOC_METAG_HI16_GOTOFF, R_METAG_HI16_GOTOFF }, - { BFD_RELOC_METAG_LO16_GOTOFF, R_METAG_LO16_GOTOFF }, - { BFD_RELOC_METAG_GETSET_GOTOFF, R_METAG_GETSET_GOTOFF }, - { BFD_RELOC_METAG_GETSET_GOT, R_METAG_GETSET_GOT }, - { BFD_RELOC_METAG_HI16_GOTPC, R_METAG_HI16_GOTPC }, - { BFD_RELOC_METAG_LO16_GOTPC, R_METAG_LO16_GOTPC }, - { BFD_RELOC_METAG_HI16_PLT, R_METAG_HI16_PLT }, - { BFD_RELOC_METAG_LO16_PLT, R_METAG_LO16_PLT }, - { BFD_RELOC_METAG_RELBRANCH_PLT, R_METAG_RELBRANCH_PLT }, - { BFD_RELOC_METAG_GOTOFF, R_METAG_GOTOFF }, - { BFD_RELOC_METAG_PLT, R_METAG_PLT }, - { BFD_RELOC_METAG_COPY, R_METAG_COPY }, - { BFD_RELOC_METAG_JMP_SLOT, R_METAG_JMP_SLOT }, - { BFD_RELOC_METAG_RELATIVE, R_METAG_RELATIVE }, - { BFD_RELOC_METAG_GLOB_DAT, R_METAG_GLOB_DAT }, - { BFD_RELOC_METAG_TLS_GD, R_METAG_TLS_GD }, - { BFD_RELOC_METAG_TLS_LDM, R_METAG_TLS_LDM }, - { BFD_RELOC_METAG_TLS_LDO_HI16, R_METAG_TLS_LDO_HI16 }, - { BFD_RELOC_METAG_TLS_LDO_LO16, R_METAG_TLS_LDO_LO16 }, - { BFD_RELOC_METAG_TLS_LDO, R_METAG_TLS_LDO }, - { BFD_RELOC_METAG_TLS_IE, R_METAG_TLS_IE }, - { BFD_RELOC_METAG_TLS_IENONPIC, R_METAG_TLS_IENONPIC }, - { BFD_RELOC_METAG_TLS_IENONPIC_HI16, R_METAG_TLS_IENONPIC_HI16 }, - { BFD_RELOC_METAG_TLS_IENONPIC_LO16, R_METAG_TLS_IENONPIC_LO16 }, - { BFD_RELOC_METAG_TLS_TPOFF, R_METAG_TLS_TPOFF }, - { BFD_RELOC_METAG_TLS_DTPMOD, R_METAG_TLS_DTPMOD }, - { BFD_RELOC_METAG_TLS_DTPOFF, R_METAG_TLS_DTPOFF }, - { BFD_RELOC_METAG_TLS_LE, R_METAG_TLS_LE }, - { BFD_RELOC_METAG_TLS_LE_HI16, R_METAG_TLS_LE_HI16 }, - { BFD_RELOC_METAG_TLS_LE_LO16, R_METAG_TLS_LE_LO16 }, - }; - -enum elf_metag_stub_type -{ - metag_stub_long_branch, - metag_stub_long_branch_shared, - metag_stub_none -}; - -struct elf_metag_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry bh_root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; - - enum elf_metag_stub_type stub_type; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf_metag_link_hash_entry *hh; - - /* And the reloc addend that this was derived from. */ - bfd_vma addend; - - /* Where this stub is being called from, or, in the case of combined - stub sections, the first input section in the group. */ - asection *id_sec; -}; - -struct elf_metag_link_hash_entry -{ - struct elf_link_hash_entry eh; - - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct elf_metag_stub_hash_entry *hsh_cache; - - /* Used to count relocations for delayed sizing of relocation - sections. */ - struct elf_dyn_relocs *dyn_relocs; - - enum - { - GOT_UNKNOWN = 0, GOT_NORMAL = 1, GOT_TLS_IE = 2, GOT_TLS_LDM = 4, GOT_TLS_GD = 8 - } tls_type; -}; - -struct elf_metag_link_hash_table -{ - /* The main hash table. */ - struct elf_link_hash_table etab; - - /* The stub hash table. */ - struct bfd_hash_table bstab; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *); - void (*layout_sections_again) (void); - - /* Array to keep track of which stub sections have been created, and - information on stub grouping. */ - struct map_stub - { - /* This is the section to which stubs in the group will be - attached. */ - asection *link_sec; - /* The stub section. */ - asection *stub_sec; - } *stub_group; - - /* Assorted information used by elf_metag_size_stubs. */ - unsigned int bfd_count; - unsigned int top_index; - asection **input_list; - Elf_Internal_Sym **all_local_syms; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* Data for LDM relocations. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; -}; - -/* Return the base vma address which should be subtracted from the - real address when resolving a 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 R_METAG_TLS_IE */ -static bfd_vma -tpoff (struct bfd_link_info *info, bfd_vma address) -{ - /* If tls_sec is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_sec == NULL) - return 0; - /* METAG TLS ABI is variant I and static TLS blocks start just after - tcbhead structure which has 2 pointer fields. */ - return (address - elf_hash_table (info)->tls_sec->vma - + align_power ((bfd_vma) 8, - elf_hash_table (info)->tls_sec->alignment_power)); -} - -static void -metag_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_METAG_MAX) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid METAG reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & elf_metag_howto_table [r_type]; -} - -static reloc_howto_type * -metag_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (metag_reloc_map) / sizeof (metag_reloc_map[0]); i++) - if (metag_reloc_map [i].bfd_reloc_val == code) - return & elf_metag_howto_table [metag_reloc_map[i].metag_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -metag_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_metag_howto_table) / sizeof (elf_metag_howto_table[0]); i++) - if (elf_metag_howto_table[i].name != NULL - && strcasecmp (elf_metag_howto_table[i].name, r_name) == 0) - return &elf_metag_howto_table[i]; - - return NULL; -} - -/* Various hash macros and functions. */ -#define metag_link_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == METAG_ELF_DATA ? ((struct elf_metag_link_hash_table *) ((p)->hash)) : NULL) - -#define metag_elf_hash_entry(ent) \ - ((struct elf_metag_link_hash_entry *)(ent)) - -#define metag_stub_hash_entry(ent) \ - ((struct elf_metag_stub_hash_entry *)(ent)) - -#define metag_stub_hash_lookup(table, string, create, copy) \ - ((struct elf_metag_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -#define metag_elf_local_got_tls_type(abfd) \ - ((char *)(elf_local_got_offsets (abfd) + (elf_tdata (abfd)->symtab_hdr.sh_info))) - -/* Assorted hash table functions. */ - -/* Initialize an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_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_metag_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf_metag_stub_hash_entry *hsh; - - /* Initialize the local fields. */ - hsh = (struct elf_metag_stub_hash_entry *) entry; - hsh->stub_sec = NULL; - hsh->stub_offset = 0; - hsh->target_value = 0; - hsh->target_section = NULL; - hsh->stub_type = metag_stub_long_branch; - hsh->hh = NULL; - hsh->id_sec = NULL; - } - - return entry; -} - -/* Initialize an entry in the link hash table. */ - -static struct bfd_hash_entry * -metag_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_metag_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_metag_link_hash_entry *hh; - - /* Initialize the local fields. */ - hh = (struct elf_metag_link_hash_entry *) entry; - hh->hsh_cache = NULL; - hh->dyn_relocs = NULL; - hh->tls_type = GOT_UNKNOWN; - } - - return entry; -} - -/* Free the derived linker hash table. */ - -static void -elf_metag_link_hash_table_free (bfd *obfd) -{ - struct elf_metag_link_hash_table *htab - = (struct elf_metag_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (&htab->bstab); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create the derived linker hash table. The Meta ELF port uses the derived - hash table to keep information specific to the Meta ELF linker (without - using static variables). */ - -static struct bfd_link_hash_table * -elf_metag_link_hash_table_create (bfd *abfd) -{ - struct elf_metag_link_hash_table *htab; - bfd_size_type amt = sizeof (*htab); - - htab = bfd_zmalloc (amt); - if (htab == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&htab->etab, abfd, - metag_link_hash_newfunc, - sizeof (struct elf_metag_link_hash_entry), - METAG_ELF_DATA)) - { - free (htab); - return NULL; - } - - /* Init the stub hash table too. */ - if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc, - sizeof (struct elf_metag_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - htab->etab.root.hash_table_free = elf_metag_link_hash_table_free; - - return &htab->etab.root; -} - -/* Section name for stubs is the associated section name plus this - string. */ -#define STUB_SUFFIX ".stub" - -/* Build a name for an entry in the stub hash table. */ - -static char * -metag_stub_name (const asection *input_section, - const asection *sym_sec, - const struct elf_metag_link_hash_entry *hh, - const Elf_Internal_Rela *rel) -{ - char *stub_name; - bfd_size_type len; - - if (hh) - { - len = 8 + 1 + strlen (hh->eh.root.root.string) + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - { - sprintf (stub_name, "%08x_%s+%x", - input_section->id & 0xffffffff, - hh->eh.root.root.string, - (int) rel->r_addend & 0xffffffff); - } - } - else - { - len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - { - sprintf (stub_name, "%08x_%x:%x+%x", - input_section->id & 0xffffffff, - sym_sec->id & 0xffffffff, - (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, - (int) rel->r_addend & 0xffffffff); - } - } - return stub_name; -} - -/* Look up an entry in the stub hash. Stub entries are cached because - creating the stub name takes a bit of time. */ - -static struct elf_metag_stub_hash_entry * -metag_get_stub_entry (const asection *input_section, - const asection *sym_sec, - struct elf_metag_link_hash_entry *hh, - const Elf_Internal_Rela *rel, - struct elf_metag_link_hash_table *htab) -{ - struct elf_metag_stub_hash_entry *hsh; - const asection *id_sec; - - /* If this input section is part of a group of sections sharing one - stub section, then use the id of the first section in the group. - Stub names need to include a section id, as there may well be - more than one stub used to reach say, printf, and we need to - distinguish between them. */ - id_sec = htab->stub_group[input_section->id].link_sec; - - if (hh != NULL && hh->hsh_cache != NULL - && hh->hsh_cache->hh == hh - && hh->hsh_cache->id_sec == id_sec) - { - hsh = hh->hsh_cache; - } - else - { - char *stub_name; - - stub_name = metag_stub_name (id_sec, sym_sec, hh, rel); - if (stub_name == NULL) - return NULL; - - hsh = metag_stub_hash_lookup (&htab->bstab, - stub_name, FALSE, FALSE); - - if (hh != NULL) - hh->hsh_cache = hsh; - - free (stub_name); - } - - return hsh; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ - -static struct elf_metag_stub_hash_entry * -metag_add_stub (const char *stub_name, - asection *section, - struct elf_metag_link_hash_table *htab) -{ - asection *link_sec; - asection *stub_sec; - struct elf_metag_stub_hash_entry *hsh; - - link_sec = htab->stub_group[section->id].link_sec; - stub_sec = htab->stub_group[section->id].stub_sec; - if (stub_sec == NULL) - { - stub_sec = htab->stub_group[link_sec->id].stub_sec; - if (stub_sec == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - - stub_sec = (*htab->add_stub_section) (s_name, link_sec); - if (stub_sec == NULL) - return NULL; - htab->stub_group[link_sec->id].stub_sec = stub_sec; - } - htab->stub_group[section->id].stub_sec = stub_sec; - } - - /* Enter this entry into the linker stub hash table. */ - hsh = metag_stub_hash_lookup (&htab->bstab, stub_name, - TRUE, FALSE); - if (hsh == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: cannot create stub entry %s"), - section->owner, stub_name); - return NULL; - } - - hsh->stub_sec = stub_sec; - hsh->stub_offset = 0; - hsh->id_sec = link_sec; - return hsh; -} - -/* Check a signed integer value can be represented in the given number - of bits. */ - -static bfd_boolean -within_signed_range (int value, unsigned int bits) -{ - int min_val = -(1 << (bits - 1)); - int max_val = (1 << (bits - 1)) - 1; - return (value <= max_val) && (value >= min_val); -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -metag_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - bfd_vma relocation, - struct elf_metag_link_hash_entry *hh, - struct elf_metag_link_hash_table *htab, - asection *sym_sec) -{ - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_byte *hit_data = contents + rel->r_offset; - int opcode, op_shift, op_extended, l1, l2; - bfd_signed_vma srel, addend = rel->r_addend; - struct elf_metag_stub_hash_entry *hsh = NULL; - bfd_vma location; - - /* Find out where we are and where we're going. */ - location = (rel->r_offset + - input_section->output_offset + - input_section->output_section->vma); - - switch (howto->type) - { - case R_METAG_RELBRANCH: - case R_METAG_RELBRANCH_PLT: - /* Make it a pc relative offset. */ - relocation -= location; - break; - case R_METAG_TLS_GD: - case R_METAG_TLS_IE: - relocation -= elf_gp (input_section->output_section->owner); - break; - default: - break; - } - - switch (howto->type) - { - case R_METAG_RELBRANCH_PLT: - case R_METAG_RELBRANCH: - opcode = bfd_get_32 (input_bfd, hit_data); - - srel = (bfd_signed_vma) relocation; - srel += addend; - - /* If the branch is out of reach, then redirect the - call to the local stub for this function. */ - if (srel > ((1 << (BRANCH_BITS + 1)) - 1) || - (srel < - (1 << (BRANCH_BITS + 1)))) - { - if (sym_sec == NULL) - break; - - hsh = metag_get_stub_entry (input_section, sym_sec, - hh, rel, htab); - if (hsh == NULL) - return bfd_reloc_undefined; - - /* Munge up the value and addend so that we call the stub - rather than the procedure directly. */ - srel = (hsh->stub_offset - + hsh->stub_sec->output_offset - + hsh->stub_sec->output_section->vma); - srel -= location; - } - - srel = srel >> 2; - - if (!within_signed_range (srel, BRANCH_BITS)) - { - if (hh && hh->eh.root.type == bfd_link_hash_undefweak) - srel = 0; - else - return bfd_reloc_overflow; - } - - opcode &= ~(0x7ffff << 5); - opcode |= ((srel & 0x7ffff) << 5); - - bfd_put_32 (input_bfd, opcode, hit_data); - break; - case R_METAG_GETSETOFF: - case R_METAG_GETSET_GOT: - case R_METAG_GETSET_GOTOFF: - opcode = bfd_get_32 (input_bfd, hit_data); - - srel = (bfd_signed_vma) relocation; - srel += addend; - - /* Is this a standard or extended GET/SET? */ - if ((opcode & 0xf0000000) == 0xa0000000) - { - /* Extended GET/SET. */ - l1 = opcode & 0x2; - l2 = opcode & 0x4; - op_extended = 1; - } - else - { - /* Standard GET/SET. */ - l1 = opcode & 0x01000000; - l2 = opcode & 0x04000000; - op_extended = 0; - } - - /* Calculate the width of the GET/SET and how much we need to - shift the result by. */ - if (l2) - if (l1) - op_shift = 3; - else - op_shift = 2; - else - if (l1) - op_shift = 1; - else - op_shift = 0; - - /* GET/SET offsets are scaled by the width of the transfer. */ - srel = srel >> op_shift; - - /* Extended GET/SET has signed 12 bits of offset, standard has - signed 6 bits. */ - if (op_extended) - { - if (!within_signed_range (srel, 12)) - { - if (hh && hh->eh.root.type == bfd_link_hash_undefweak) - srel = 0; - else - return bfd_reloc_overflow; - } - opcode &= ~(0xfff << 7); - opcode |= ((srel & 0xfff) << 7); - } - else - { - if (!within_signed_range (srel, 5)) - { - if (hh && hh->eh.root.type == bfd_link_hash_undefweak) - srel = 0; - else - return bfd_reloc_overflow; - } - opcode &= ~(0x3f << 8); - opcode |= ((srel & 0x3f) << 8); - } - - bfd_put_32 (input_bfd, opcode, hit_data); - break; - case R_METAG_TLS_GD: - case R_METAG_TLS_LDM: - opcode = bfd_get_32 (input_bfd, hit_data); - - if ((bfd_signed_vma)relocation < 0) - { - /* sign extend immediate */ - if ((opcode & 0xf2000001) == 0x02000000) - { - /* ADD De.e,Dx.r,#I16 */ - /* set SE bit */ - opcode |= (1 << 1); - } else - return bfd_reloc_overflow; - } - - bfd_put_32 (input_bfd, opcode, hit_data); - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - return r; -} - -/* This is defined because R_METAG_NONE != 0... - See RELOC_AGAINST_DISCARDED_SECTION for details. */ -#define METAG_RELOC_AGAINST_DISCARDED_SECTION(info, input_bfd, input_section, \ - rel, relend, howto, contents) \ - { \ - _bfd_clear_contents (howto, input_bfd, input_section, \ - contents + rel->r_offset); \ - \ - if (bfd_link_relocatable (info) \ - && (input_section->flags & SEC_DEBUGGING)) \ - { \ - /* Only remove relocations in debug sections since other \ - sections may require relocations. */ \ - Elf_Internal_Shdr *rel_hdr; \ - \ - rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); \ - \ - /* Avoid empty output section. */ \ - if (rel_hdr->sh_size > rel_hdr->sh_entsize) \ - { \ - rel_hdr->sh_size -= rel_hdr->sh_entsize; \ - rel_hdr = _bfd_elf_single_rel_hdr (input_section); \ - rel_hdr->sh_size -= rel_hdr->sh_entsize; \ - \ - memmove (rel, rel + 1, (relend - rel) * sizeof (*rel)); \ - \ - input_section->reloc_count--; \ - relend--; \ - rel--; \ - continue; \ - } \ - } \ - \ - rel->r_info = R_METAG_NONE; \ - rel->r_addend = 0; \ - continue; \ - } - -/* Relocate a META ELF section. - -The RELOCATE_SECTION function is called by the new ELF backend linker -to handle the relocations for a section. - -The relocs are always passed as Rela structures; if the section -actually uses Rel structures, the r_addend field will always be -zero. - -This function is responsible for adjusting the section contents as -necessary, and (if using Rela relocs and generating a relocatable -output file) adjusting the reloc addend as necessary. - -This function does not have to worry about setting the reloc -address or the reloc symbol index. - -LOCAL_SYMS is a pointer to the swapped in local symbols. - -LOCAL_SECTIONS is an array giving the section in the input file -corresponding to the st_shndx field of each local symbol. - -The global hash table entry for the global symbols can be found -via elf_sym_hashes (input_bfd). - -When generating relocatable output, this function must handle -STB_LOCAL/STT_SECTION symbols specially. The output symbol is -going to be the section symbol corresponding to the output -section, which means that the addend must be adjusted -accordingly. */ - -static bfd_boolean -elf_metag_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) -{ - bfd_vma *local_got_offsets; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **eh_syms; - struct elf_metag_link_hash_table *htab; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - asection *sreloc; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - eh_syms = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - htab = metag_link_hash_table (info); - local_got_offsets = elf_local_got_offsets (input_bfd); - - sreloc = NULL; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_metag_link_hash_entry *hh; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_METAG_GNU_VTINHERIT - || r_type == R_METAG_GNU_VTENTRY - || r_type == R_METAG_NONE) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = elf_metag_howto_table + ELF32_R_TYPE (rel->r_info); - hh = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - struct elf_link_hash_entry *eh; - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, eh_syms, - eh, sec, relocation, - unresolved_reloc, warned, ignored); - - name = eh->root.root.string; - hh = (struct elf_metag_link_hash_entry *) eh; - } - - if (sec != NULL && discarded_section (sec)) - METAG_RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, relend, howto, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (r_type) - { - case R_METAG_ADDR32: - case R_METAG_RELBRANCH: - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - if ((bfd_link_pic (info) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0 - && (r_type != R_METAG_RELBRANCH - || !SYMBOL_CALLS_LOCAL (info, &hh->eh))) - || (!bfd_link_pic (info) - && hh != NULL - && hh->eh.dynindx != -1 - && !hh->eh.non_got_ref - && ((hh->eh.def_dynamic - && !hh->eh.def_regular) - || hh->eh.root.type == bfd_link_hash_undefweak - || hh->eh.root.type == bfd_link_hash_undefined))) - { - Elf_Internal_Rela outrel; - bfd_boolean skip, relocate; - bfd_byte *loc; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - sreloc = elf_section_data (input_section)->sreloc; - BFD_ASSERT (sreloc != NULL); - - skip = FALSE; - relocate = FALSE; - - outrel.r_offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - { - memset (&outrel, 0, sizeof outrel); - outrel.r_info = ELF32_R_INFO (0, R_METAG_NONE); - } - else if (r_type == R_METAG_RELBRANCH) - { - BFD_ASSERT (hh != NULL && hh->eh.dynindx != -1); - outrel.r_info = ELF32_R_INFO (hh->eh.dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (hh == NULL - || ((info->symbolic || hh->eh.dynindx == -1) - && hh->eh.def_regular)) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_METAG_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - BFD_ASSERT (hh->eh.dynindx != -1); - outrel.r_info = ELF32_R_INFO (hh->eh.dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count * sizeof(Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc); - ++sreloc->reloc_count; - - /* If this reloc is against an external symbol, we do - not want to fiddle with the addend. Otherwise, we - need to include the symbol value so that it becomes - an addend for the dynamic reloc. */ - if (! relocate) - continue; - } - break; - - case R_METAG_RELBRANCH_PLT: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - if (hh == NULL) - break; - - if (hh->eh.forced_local) - break; - - if (hh->eh.plt.offset == (bfd_vma) -1 || htab->etab.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->etab.splt->output_section->vma - + htab->etab.splt->output_offset - + hh->eh.plt.offset); - break; - case R_METAG_HI16_GOTPC: - case R_METAG_LO16_GOTPC: - BFD_ASSERT (htab->etab.sgot != NULL); - - relocation = (htab->etab.sgot->output_section->vma + - htab->etab.sgot->output_offset); - relocation += GOT_REG_OFFSET; - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - break; - case R_METAG_HI16_GOTOFF: - case R_METAG_LO16_GOTOFF: - case R_METAG_GETSET_GOTOFF: - BFD_ASSERT (htab->etab.sgot != NULL); - - relocation -= (htab->etab.sgot->output_section->vma + - htab->etab.sgot->output_offset); - relocation -= GOT_REG_OFFSET; - break; - case R_METAG_GETSET_GOT: - { - bfd_vma off; - bfd_boolean do_got = 0; - - /* Relocation is to the entry for this symbol in the - global offset table. */ - if (hh != NULL) - { - bfd_boolean dyn; - - off = hh->eh.got.offset; - dyn = htab->etab.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - &hh->eh)) - { - /* If we aren't going to call finish_dynamic_symbol, - then we need to handle initialisation of the .got - entry and create needed relocs here. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialised it already. */ - if ((off & 1) != 0) - off &= ~1; - else - { - hh->eh.got.offset |= 1; - do_got = 1; - } - } - } - else - { - /* Local symbol case. */ - 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 - { - local_got_offsets[r_symndx] |= 1; - do_got = 1; - } - } - - if (do_got) - { - if (bfd_link_pic (info)) - { - /* Output a dynamic relocation for this GOT entry. - In this case it is relative to the base of the - object because the symbol index is zero. */ - Elf_Internal_Rela outrel; - bfd_byte *loc; - asection *s = htab->etab.srelgot; - - outrel.r_offset = (off - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - outrel.r_info = ELF32_R_INFO (0, R_METAG_RELATIVE); - outrel.r_addend = relocation; - loc = s->contents; - loc += s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - bfd_put_32 (output_bfd, relocation, - htab->etab.sgot->contents + off); - } - - if (off >= (bfd_vma) -2) - abort (); - - relocation = off - GOT_REG_OFFSET; - } - break; - case R_METAG_TLS_GD: - case R_METAG_TLS_IE: - { - /* XXXMJF There is room here for optimisations. For example - converting from GD->IE, etc. */ - bfd_vma off; - int indx; - char tls_type; - - if (htab->etab.sgot == NULL) - abort(); - - indx = 0; - if (hh != NULL) - { - bfd_boolean dyn; - dyn = htab->etab.dynamic_sections_created; - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - &hh->eh) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, &hh->eh))) - { - indx = hh->eh.dynindx; - } - off = hh->eh.got.offset; - tls_type = hh->tls_type; - } - else - { - /* Local symbol case. */ - if (local_got_offsets == NULL) - abort (); - - off = local_got_offsets[r_symndx]; - tls_type = metag_elf_local_got_tls_type (input_bfd) [r_symndx]; - } - - if (tls_type == GOT_UNKNOWN) - abort (); - - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_boolean need_relocs = FALSE; - Elf_Internal_Rela outrel; - bfd_byte *loc = NULL; - int cur_off = off; - - /* The GOT entries have not been initialized yet. Do it - now, and emit any relocations. If both an IE GOT and a - GD GOT are necessary, we emit the GD first. */ - - if ((bfd_link_pic (info) || indx != 0) - && (hh == NULL - || ELF_ST_VISIBILITY (hh->eh.other) == STV_DEFAULT - || hh->eh.root.type != bfd_link_hash_undefweak)) - { - need_relocs = TRUE; - loc = htab->etab.srelgot->contents; - /* FIXME (CAO): Should this be reloc_count++ ? */ - loc += htab->etab.srelgot->reloc_count * sizeof (Elf32_External_Rela); - } - - if (tls_type & GOT_TLS_GD) - { - if (need_relocs) - { - outrel.r_offset = (cur_off - + htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset); - outrel.r_info = ELF32_R_INFO (indx, R_METAG_TLS_DTPMOD); - outrel.r_addend = 0; - bfd_put_32 (output_bfd, 0, htab->etab.sgot->contents + cur_off); - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->etab.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - - if (indx == 0) - bfd_put_32 (output_bfd, 0, - htab->etab.sgot->contents + cur_off + 4); - else - { - bfd_put_32 (output_bfd, 0, - htab->etab.sgot->contents + cur_off + 4); - outrel.r_info = ELF32_R_INFO (indx, - R_METAG_TLS_DTPOFF); - outrel.r_offset += 4; - bfd_elf32_swap_reloca_out (output_bfd, - &outrel, loc); - htab->etab.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - } - } - else - { - /* We don't support changing the TLS model. */ - /* PR 20675 */ - if (bfd_link_pic (info)) - _bfd_error_handler (_("%B(%A): multiple TLS models are not supported"), - input_bfd, input_section); - else - _bfd_error_handler (_("%B(%A): shared library symbol %s encountered whilst performing a static link"), - input_bfd, input_section, name); - return FALSE; - } - - cur_off += 8; - } - - if (tls_type & GOT_TLS_IE) - { - if (need_relocs) - { - outrel.r_offset = (cur_off - + htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset); - outrel.r_info = ELF32_R_INFO (indx, R_METAG_TLS_TPOFF); - - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->etab.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - } - else - bfd_put_32 (output_bfd, tpoff (info, relocation), - htab->etab.sgot->contents + cur_off); - - cur_off += 4; - } - - if (hh != NULL) - hh->eh.got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - /* Add the base of the GOT to the relocation value. */ - relocation = off - GOT_REG_OFFSET; - - break; - } - - case R_METAG_TLS_IENONPIC_HI16: - case R_METAG_TLS_IENONPIC_LO16: - case R_METAG_TLS_LE_HI16: - case R_METAG_TLS_LE_LO16: - if (bfd_link_pic (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation not permitted in shared object"), - input_bfd, input_section, rel->r_offset, howto->name); - return FALSE; - } - else - relocation = tpoff (info, relocation); - break; - case R_METAG_TLS_LDO_HI16: - case R_METAG_TLS_LDO_LO16: - if (! bfd_link_pic (info)) - relocation = tpoff (info, relocation); - else - relocation -= dtpoff_base (info); - break; - case R_METAG_TLS_LDM: - { - bfd_vma off; - - if (htab->etab.sgot == NULL) - abort(); - off = htab->tls_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - outrel.r_offset = (off - + htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset); - - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (0, R_METAG_TLS_DTPMOD); - loc = htab->etab.srelgot->contents; - loc += htab->etab.srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->tls_ldm_got.offset |= 1; - } - - relocation = off - GOT_REG_OFFSET; - break; - } - default: - break; - } - - r = metag_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation, hh, htab, - sec); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (hh ? &hh->eh.root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Create the .plt and .got sections, and set up our hash table - short-cuts to various dynamic sections. */ - -static bfd_boolean -elf_metag_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_metag_link_hash_table *htab; - struct elf_link_hash_entry *eh; - struct bfd_link_hash_entry *bh; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - /* Don't try to create the .plt and .got twice. */ - htab = metag_link_hash_table (info); - if (htab->etab.splt != NULL) - return TRUE; - - /* Call the generic code to do most of the work. */ - if (! _bfd_elf_create_dynamic_sections (abfd, info)) - return FALSE; - - /* The header goes at the start of the dynamic .got section, which - is placed after the dynamic .got.plt section. ie. The header is - not necessarily at the start of the output .got section. */ - htab->etab.sgot->size += 12; - - /* Define the symbol __GLOBAL_OFFSET_TABLE__ on the header. */ - bh = NULL; - if (!(_bfd_generic_link_add_one_symbol - (info, abfd, "__GLOBAL_OFFSET_TABLE__", BSF_GLOBAL, htab->etab.sgot, - (bfd_vma) 0, NULL, FALSE, bed->collect, &bh))) - return FALSE; - eh = (struct elf_link_hash_entry *) bh; - eh->def_regular = 1; - eh->type = STT_OBJECT; - eh->other = STV_HIDDEN; - - if (! bfd_link_executable (info) - && ! bfd_elf_link_record_dynamic_symbol (info, eh)) - return FALSE; - - htab->etab.hgot = eh; - - return TRUE; -} - -/* 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. At this point we haven't - necessarily read all the input files. */ - -static bfd_boolean -elf_metag_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **eh_syms; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - struct elf_metag_link_hash_table *htab; - asection *sreloc; - bfd *dynobj; - int tls_type = GOT_UNKNOWN, old_tls_type = GOT_UNKNOWN; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = metag_link_hash_table (info); - dynobj = htab->etab.dynobj; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - eh_syms = elf_sym_hashes (abfd); - sreloc = NULL; - - if (htab == NULL) - return FALSE; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - int r_type; - struct elf_metag_link_hash_entry *hh; - Elf_Internal_Sym *isym; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - hh = NULL; - } - else - { - isym = NULL; - - hh = (struct elf_metag_link_hash_entry *) - eh_syms[r_symndx - symtab_hdr->sh_info]; - while (hh->eh.root.type == bfd_link_hash_indirect - || hh->eh.root.type == bfd_link_hash_warning) - hh = (struct elf_metag_link_hash_entry *) hh->eh.root.u.i.link; - } - - /* Some relocs require a global offset table. */ - if (htab->etab.sgot == NULL) - { - switch (r_type) - { - case R_METAG_TLS_GD: - case R_METAG_TLS_LDM: - case R_METAG_TLS_IE: - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - /* Fall through. */ - - case R_METAG_HI16_GOTOFF: - case R_METAG_LO16_GOTOFF: - case R_METAG_GETSET_GOTOFF: - case R_METAG_GETSET_GOT: - case R_METAG_HI16_GOTPC: - case R_METAG_LO16_GOTPC: - if (dynobj == NULL) - htab->etab.dynobj = dynobj = abfd; - if (!elf_metag_create_dynamic_sections (dynobj, info)) - return FALSE; - break; - - default: - break; - } - } - - switch (r_type) - { - case R_METAG_TLS_IE: - case R_METAG_TLS_GD: - case R_METAG_GETSET_GOT: - switch (r_type) - { - default: - tls_type = GOT_NORMAL; - break; - case R_METAG_TLS_IE: - tls_type = GOT_TLS_IE; - break; - case R_METAG_TLS_GD: - tls_type = GOT_TLS_GD; - break; - } - - if (hh != NULL) - { - hh->eh.got.refcount += 1; - old_tls_type = hh->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); - /* Add in space to store the local GOT TLS types. */ - size += symtab_hdr->sh_info; - 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; - memset (metag_elf_local_got_tls_type (abfd), - GOT_UNKNOWN, symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx] += 1; - old_tls_type = metag_elf_local_got_tls_type (abfd) [r_symndx]; - } - - if (old_tls_type != tls_type) - { - if (hh != NULL) - { - hh->tls_type = tls_type; - } - else - { - metag_elf_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - } - - break; - - case R_METAG_TLS_LDM: - metag_link_hash_table (info)->tls_ldm_got.refcount += 1; - break; - - case R_METAG_RELBRANCH_PLT: - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - if (hh == NULL) - continue; - - if (hh->eh.forced_local) - break; - - hh->eh.needs_plt = 1; - hh->eh.plt.refcount += 1; - break; - - case R_METAG_HIADDR16: - case R_METAG_LOADDR16: - /* 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 (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (sec->flags & SEC_READONLY) != 0) - { - const char *name; - - if (hh) - name = hh->eh.root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), - abfd, elf_metag_howto_table[r_type].name, name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Fall through. */ - case R_METAG_ADDR32: - case R_METAG_RELBRANCH: - case R_METAG_GETSETOFF: - if (hh != NULL && !bfd_link_pic (info)) - { - hh->eh.non_got_ref = 1; - hh->eh.plt.refcount += 1; - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). We account for that - possibility below by storing information in the - dyn_relocs field of the hash table entry. A similar - situation occurs when creating shared libraries and symbol - visibility changes render the symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (r_type != R_METAG_RELBRANCH - || (hh != NULL - && (! info->symbolic - || hh->eh.root.type == bfd_link_hash_defweak - || !hh->eh.def_regular)))) - || (!bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && hh != NULL - && (hh->eh.root.type == bfd_link_hash_defweak - || !hh->eh.def_regular))) - { - struct elf_dyn_relocs *hdh_p; - struct elf_dyn_relocs **hdh_head; - - if (dynobj == NULL) - htab->etab.dynobj = dynobj = abfd; - - /* When creating a shared object, we must copy these - relocs into the output file. We create a reloc - section in dynobj and make room for the reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->etab.dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - { - bfd_set_error (bfd_error_bad_value); - 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 (hh != NULL) - hdh_head = &((struct elf_metag_link_hash_entry *) hh)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. */ - asection *sr; - void *vpp; - - sr = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (sr == NULL) - sr = sec; - - vpp = &elf_section_data (sr)->local_dynrel; - hdh_head = (struct elf_dyn_relocs **) vpp; - } - - hdh_p = *hdh_head; - if (hdh_p == NULL || hdh_p->sec != sec) - { - hdh_p = ((struct elf_dyn_relocs *) - bfd_alloc (dynobj, sizeof *hdh_p)); - if (hdh_p == NULL) - return FALSE; - hdh_p->next = *hdh_head; - *hdh_head = hdh_p; - hdh_p->sec = sec; - hdh_p->count = 0; - hdh_p->pc_count = 0; - } - - hdh_p->count += 1; - if (ELF32_R_TYPE (rel->r_info) == R_METAG_RELBRANCH) - hdh_p->pc_count += 1; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_METAG_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, &hh->eh, - rel->r_offset)) - return FALSE; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_METAG_GNU_VTENTRY: - BFD_ASSERT (hh != NULL); - if (hh != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, &hh->eh, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf_metag_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *eh_dir, - struct elf_link_hash_entry *eh_ind) -{ - struct elf_metag_link_hash_entry *hh_dir, *hh_ind; - - hh_dir = metag_elf_hash_entry (eh_dir); - hh_ind = metag_elf_hash_entry (eh_ind); - - if (hh_ind->dyn_relocs != NULL) - { - if (hh_dir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **hdh_pp; - struct elf_dyn_relocs *hdh_p; - - if (eh_ind->root.type == bfd_link_hash_indirect) - abort (); - - /* Add reloc counts against the weak sym to the strong sym - list. Merge any entries against the same section. */ - for (hdh_pp = &hh_ind->dyn_relocs; (hdh_p = *hdh_pp) != NULL; ) - { - struct elf_dyn_relocs *hdh_q; - - for (hdh_q = hh_dir->dyn_relocs; hdh_q != NULL; - hdh_q = hdh_q->next) - if (hdh_q->sec == hdh_p->sec) - { - hdh_q->pc_count += hdh_p->pc_count; - hdh_q->count += hdh_p->count; - *hdh_pp = hdh_p->next; - break; - } - if (hdh_q == NULL) - hdh_pp = &hdh_p->next; - } - *hdh_pp = hh_dir->dyn_relocs; - } - - hh_dir->dyn_relocs = hh_ind->dyn_relocs; - hh_ind->dyn_relocs = NULL; - } - - if (eh_ind->root.type == bfd_link_hash_indirect - && eh_dir->got.refcount <= 0) - { - hh_dir->tls_type = hh_ind->tls_type; - hh_ind->tls_type = GOT_UNKNOWN; - } - - _bfd_elf_link_hash_copy_indirect (info, eh_dir, eh_ind); -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = metag_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* 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_metag_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *eh) -{ - struct elf_metag_link_hash_table *htab; - asection *s, *srel; - - /* 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 (eh->type == STT_FUNC - || eh->needs_plt) - { - if (eh->plt.refcount <= 0 - || SYMBOL_CALLS_LOCAL (info, eh) - || (ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT - && eh->root.type == bfd_link_hash_undefweak)) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a PCREL - reloc instead. */ - eh->plt.offset = (bfd_vma) -1; - eh->needs_plt = 0; - } - - return TRUE; - } - else - eh->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 (eh->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (eh); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - eh->root.u.def.section = def->root.u.def.section; - eh->root.u.def.value = def->root.u.def.value; - eh->non_got_ref = def->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 (bfd_link_pic (info)) - 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 (!eh->non_got_ref) - return TRUE; - - /* If -z nocopyreloc was given, we won't generate them either. */ - if (info->nocopyreloc) - { - eh->non_got_ref = 0; - return TRUE; - } - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (!readonly_dynrelocs (eh)) - { - eh->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = metag_link_hash_table (info); - - /* We must generate a COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. */ - if ((eh->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = htab->etab.sdynrelro; - srel = htab->etab.sreldynrelro; - } - else - { - s = htab->etab.sdynbss; - srel = htab->etab.srelbss; - } - if ((eh->root.u.def.section->flags & SEC_ALLOC) != 0 && eh->size != 0) - { - srel->size += sizeof (Elf32_External_Rela); - eh->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, eh, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - global syms. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf) -{ - struct bfd_link_info *info; - struct elf_metag_link_hash_table *htab; - struct elf_metag_link_hash_entry *hh; - struct elf_dyn_relocs *hdh_p; - - if (eh->root.type == bfd_link_hash_indirect) - return TRUE; - - if (eh->root.type == bfd_link_hash_warning) - eh = (struct elf_link_hash_entry *) eh->root.u.i.link; - - info = inf; - htab = metag_link_hash_table (info); - - if (htab->etab.dynamic_sections_created - && eh->plt.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (eh->dynindx == -1 - && !eh->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, eh)) - return FALSE; - } - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), eh)) - { - asection *s = htab->etab.splt; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += PLT_ENTRY_SIZE; - - eh->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 (! bfd_link_pic (info) - && !eh->def_regular) - { - eh->root.u.def.section = s; - eh->root.u.def.value = eh->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->etab.sgotplt->size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - htab->etab.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - eh->plt.offset = (bfd_vma) -1; - eh->needs_plt = 0; - } - } - else - { - eh->plt.offset = (bfd_vma) -1; - eh->needs_plt = 0; - } - - if (eh->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = metag_elf_hash_entry (eh)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (eh->dynindx == -1 - && !eh->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, eh)) - return FALSE; - } - - s = htab->etab.sgot; - - eh->got.offset = s->size; - s->size += 4; - /* R_METAG_TLS_GD needs 2 consecutive GOT slots. */ - if (tls_type == GOT_TLS_GD) - s->size += 4; - dyn = htab->etab.dynamic_sections_created; - /* R_METAG_TLS_IE needs one dynamic relocation if dynamic, - R_METAG_TLS_GD needs one if local symbol and two if global. */ - if ((tls_type == GOT_TLS_GD && eh->dynindx == -1) - || (tls_type == GOT_TLS_IE && dyn)) - htab->etab.srelgot->size += sizeof (Elf32_External_Rela); - else if (tls_type == GOT_TLS_GD) - htab->etab.srelgot->size += 2 * sizeof (Elf32_External_Rela); - else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - eh)) - htab->etab.srelgot->size += sizeof (Elf32_External_Rela); - } - else - eh->got.offset = (bfd_vma) -1; - - hh = (struct elf_metag_link_hash_entry *) eh; - if (hh->dyn_relocs == NULL) - return TRUE; - - /* If this is a -Bsymbolic shared link, then we need to discard all - space allocated for dynamic pc-relative relocs against symbols - defined in a regular object. For the normal shared case, discard - space for relocs that have become local due to symbol visibility - changes. */ - if (bfd_link_pic (info)) - { - if (SYMBOL_CALLS_LOCAL (info, eh)) - { - struct elf_dyn_relocs **hdh_pp; - - for (hdh_pp = &hh->dyn_relocs; (hdh_p = *hdh_pp) != NULL; ) - { - hdh_p->count -= hdh_p->pc_count; - hdh_p->pc_count = 0; - if (hdh_p->count == 0) - *hdh_pp = hdh_p->next; - else - hdh_pp = &hdh_p->next; - } - } - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (hh->dyn_relocs != NULL - && eh->root.type == bfd_link_hash_undefweak) - { - if (ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT) - hh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (eh->dynindx == -1 - && !eh->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, eh)) - return FALSE; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - if (!eh->non_got_ref - && ((eh->def_dynamic - && !eh->def_regular) - || (htab->etab.dynamic_sections_created - && (eh->root.type == bfd_link_hash_undefweak - || eh->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 (eh->dynindx == -1 - && !eh->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, eh)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (eh->dynindx != -1) - goto keep; - } - - hh->dyn_relocs = NULL; - return TRUE; - - keep: ; - } - - /* Finally, allocate space. */ - for (hdh_p = hh->dyn_relocs; hdh_p != NULL; hdh_p = hdh_p->next) - { - asection *sreloc = elf_section_data (hdh_p->sec)->sreloc; - sreloc->size += hdh_p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_metag_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_metag_link_hash_table *htab; - bfd *dynobj; - bfd *ibfd; - asection *s; - bfd_boolean relocs; - - htab = metag_link_hash_table (info); - dynobj = htab->etab.dynobj; - if (dynobj == NULL) - abort (); - - if (htab->etab.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (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; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - char *local_tls_type; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *hdh_p; - - for (hdh_p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - hdh_p != NULL; - hdh_p = hdh_p->next) - { - if (!bfd_is_abs_section (hdh_p->sec) - && bfd_is_abs_section (hdh_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 (hdh_p->count != 0) - { - srel = elf_section_data (hdh_p->sec)->sreloc; - srel->size += hdh_p->count * sizeof (Elf32_External_Rela); - if ((hdh_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 = metag_elf_local_got_tls_type (ibfd); - s = htab->etab.sgot; - srel = htab->etab.srelgot; - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += GOT_ENTRY_SIZE; - /* R_METAG_TLS_GD relocs need 2 consecutive GOT entries. */ - if (*local_tls_type == GOT_TLS_GD) - s->size += 4; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); - } - else - *local_got = (bfd_vma) -1; - ++local_tls_type; - } - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate 2 got entries and 1 dynamic reloc for R_METAG_TLS_LDM - reloc. */ - htab->tls_ldm_got.offset = htab->etab.sgot->size; - htab->etab.sgot->size += 8; - htab->etab.srelgot->size += sizeof (Elf32_External_Rela); - } - 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->etab, allocate_dynrelocs, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - bfd_boolean reloc_section = FALSE; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->etab.splt - || s == htab->etab.sgot - || s == htab->etab.sgotplt - || s == htab->etab.sdynbss - || s == htab->etab.sdynrelro) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 && s != htab->etab.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - reloc_section = TRUE; - } - 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. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - else if (reloc_section) - { - unsigned char *contents = s->contents; - Elf32_External_Rela reloc; - - /* Fill the reloc section with a R_METAG_NONE type reloc. */ - memset(&reloc, 0, sizeof(Elf32_External_Rela)); - reloc.r_info[0] = R_METAG_NONE; - for (; contents < (s->contents + s->size); - contents += sizeof(Elf32_External_Rela)) - { - memcpy(contents, &reloc, sizeof(Elf32_External_Rela)); - } - } - } - - if (htab->etab.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf_metag_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 (!add_dynamic_entry (DT_PLTGOT, 0)) - return FALSE; - - if (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->etab.srelplt->size != 0) - { - if (!add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->etab, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_metag_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *eh, - Elf_Internal_Sym *sym) -{ - struct elf_metag_link_hash_table *htab; - Elf_Internal_Rela rel; - bfd_byte *loc; - - htab = metag_link_hash_table (info); - - if (eh->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgot; - asection *srela; - - bfd_vma plt_index; - bfd_vma got_offset; - bfd_vma got_entry; - - if (eh->plt.offset & 1) - abort (); - - BFD_ASSERT (eh->dynindx != -1); - - splt = htab->etab.splt; - sgot = htab->etab.sgotplt; - srela = htab->etab.srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = eh->plt.offset / PLT_ENTRY_SIZE - 1; - - /* Get the offset into the .got.plt table of the entry that - corresponds to this function. */ - got_offset = plt_index * GOT_ENTRY_SIZE; - - BFD_ASSERT (got_offset < (1 << 16)); - - got_entry = sgot->output_section->vma - + sgot->output_offset - + got_offset; - - BFD_ASSERT (plt_index < (1 << 16)); - - /* Fill in the entry in the procedure linkage table. */ - if (! bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, - (plt_entry[0] - | (((got_entry >> 16) & 0xffff) << 3)), - splt->contents + eh->plt.offset); - bfd_put_32 (output_bfd, - (plt_entry[1] - | ((got_entry & 0xffff) << 3)), - splt->contents + eh->plt.offset + 4); - bfd_put_32 (output_bfd, plt_entry[2], - splt->contents + eh->plt.offset + 8); - bfd_put_32 (output_bfd, - (plt_entry[3] | (plt_index << 3)), - splt->contents + eh->plt.offset + 12); - bfd_put_32 (output_bfd, - (plt_entry[4] - | ((((unsigned int) ((- (eh->plt.offset + 16)) >> 2)) & 0x7ffff) << 5)), - splt->contents + eh->plt.offset + 16); - } - else - { - bfd_vma addr = got_entry - (splt->output_section->vma + - splt->output_offset + eh->plt.offset); - - bfd_put_32 (output_bfd, - plt_pic_entry[0] | (((addr >> 16) & 0xffff) << 3), - splt->contents + eh->plt.offset); - bfd_put_32 (output_bfd, - plt_pic_entry[1] | ((addr & 0xffff) << 3), - splt->contents + eh->plt.offset + 4); - bfd_put_32 (output_bfd, plt_pic_entry[2], - splt->contents + eh->plt.offset + 8); - bfd_put_32 (output_bfd, - (plt_pic_entry[3] | (plt_index << 3)), - splt->contents + eh->plt.offset + 12); - bfd_put_32 (output_bfd, - (plt_pic_entry[4] - + ((((unsigned int) ((- (eh->plt.offset + 16)) >> 2)) & 0x7ffff) << 5)), - splt->contents + eh->plt.offset + 16); - } - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + eh->plt.offset - + 12), /* offset within PLT entry */ - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rel.r_info = ELF32_R_INFO (eh->dynindx, R_METAG_JMP_SLOT); - rel.r_addend = 0; - loc = htab->etab.srelplt->contents; - loc += plt_index * sizeof(Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - - if (!eh->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (eh->got.offset != (bfd_vma) -1 - && (metag_elf_hash_entry (eh)->tls_type & GOT_TLS_GD) == 0 - && (metag_elf_hash_entry (eh)->tls_type & GOT_TLS_IE) == 0) - { - /* This symbol has an entry in the global offset table. Set it - up. */ - - rel.r_offset = ((eh->got.offset &~ (bfd_vma) 1) - + htab->etab.sgot->output_offset - + htab->etab.sgot->output_section->vma); - - /* If this 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 (bfd_link_pic (info) - && (info->symbolic || eh->dynindx == -1) - && eh->def_regular) - { - rel.r_info = ELF32_R_INFO (0, R_METAG_RELATIVE); - rel.r_addend = (eh->root.u.def.value - + eh->root.u.def.section->output_offset - + eh->root.u.def.section->output_section->vma); - } - else - { - if ((eh->got.offset & 1) != 0) - abort (); - bfd_put_32 (output_bfd, 0, htab->etab.sgot->contents + eh->got.offset); - rel.r_info = ELF32_R_INFO (eh->dynindx, R_METAG_GLOB_DAT); - rel.r_addend = 0; - } - - loc = htab->etab.srelgot->contents; - loc += htab->etab.srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } - - if (eh->needs_copy) - { - asection *s; - - /* This symbol needs a copy reloc. Set it up. */ - - if (! (eh->dynindx != -1 - && (eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak))) - abort (); - - rel.r_offset = (eh->root.u.def.value - + eh->root.u.def.section->output_offset - + eh->root.u.def.section->output_section->vma); - rel.r_addend = 0; - rel.r_info = ELF32_R_INFO (eh->dynindx, R_METAG_COPY); - if (eh->root.u.def.section == htab->etab.sdynrelro) - s = htab->etab.sreldynrelro; - else - s = htab->etab.srelbss; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (eh->root.root.string[0] == '_' - && (strcmp (eh->root.root.string, "_DYNAMIC") == 0 - || eh == htab->etab.hgot)) - { - sym->st_shndx = SHN_ABS; - } - - return TRUE; -} - -/* Set the Meta ELF ABI version. */ - -static void -elf_metag_post_process_headers (bfd * abfd, struct bfd_link_info * link_info) -{ - Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ - - _bfd_elf_post_process_headers (abfd, link_info); - i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_ident[EI_ABIVERSION] = METAG_ELF_ABI_VERSION; -} - -/* 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_metag_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_METAG_RELATIVE: - return reloc_class_relative; - case R_METAG_JMP_SLOT: - return reloc_class_plt; - case R_METAG_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf_metag_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - struct elf_metag_link_hash_table *htab; - asection *sdyn; - - htab = metag_link_hash_table (info); - dynobj = htab->etab.dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->etab.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - if (sdyn == 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->etab.sgot; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - s = htab->etab.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->etab.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->etab.splt; - if (splt && splt->size > 0) - { - unsigned long addr; - /* addr = .got + 4 */ - addr = (htab->etab.sgot->output_section->vma - + htab->etab.sgot->output_offset + 4); - if (bfd_link_pic (info)) - { - addr -= splt->output_section->vma + splt->output_offset; - bfd_put_32 (output_bfd, - plt0_pic_entry[0] | (((addr >> 16) & 0xffff) << 3), - splt->contents); - bfd_put_32 (output_bfd, - plt0_pic_entry[1] | ((addr & 0xffff) << 3), - splt->contents + 4); - bfd_put_32 (output_bfd, plt0_pic_entry[2], splt->contents + 8); - bfd_put_32 (output_bfd, plt0_pic_entry[3], splt->contents + 12); - bfd_put_32 (output_bfd, plt0_pic_entry[4], splt->contents + 16); - } - else - { - bfd_put_32 (output_bfd, - plt0_entry[0] | (((addr >> 16) & 0xffff) << 3), - splt->contents); - bfd_put_32 (output_bfd, - plt0_entry[1] | ((addr & 0xffff) << 3), - splt->contents + 4); - bfd_put_32 (output_bfd, plt0_entry[2], splt->contents + 8); - bfd_put_32 (output_bfd, plt0_entry[3], splt->contents + 12); - bfd_put_32 (output_bfd, plt0_entry[4], splt->contents + 16); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; - } - } - - if (htab->etab.sgot != NULL && htab->etab.sgot->size != 0) - { - /* Fill in the first entry in the global offset table. - We use it to point to our dynamic section, if we have one. */ - bfd_put_32 (output_bfd, - sdyn ? sdyn->output_section->vma + sdyn->output_offset : 0, - htab->etab.sgot->contents); - - /* The second entry is reserved for use by the dynamic linker. */ - memset (htab->etab.sgot->contents + GOT_ENTRY_SIZE, 0, GOT_ENTRY_SIZE); - - /* Set .got entry size. */ - elf_section_data (htab->etab.sgot->output_section) - ->this_hdr.sh_entsize = GOT_ENTRY_SIZE; - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -elf_metag_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rela, - struct elf_link_hash_entry *hh, - Elf_Internal_Sym *sym) -{ - if (hh != NULL) - switch ((unsigned int) ELF32_R_TYPE (rela->r_info)) - { - case R_METAG_GNU_VTINHERIT: - case R_METAG_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rela, hh, sym); -} - -/* Determine the type of stub needed, if any, for a call. */ - -static enum elf_metag_stub_type -metag_type_of_stub (asection *input_sec, - const Elf_Internal_Rela *rel, - struct elf_metag_link_hash_entry *hh, - bfd_vma destination, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - bfd_vma location; - bfd_vma branch_offset; - bfd_vma max_branch_offset; - - if (hh != NULL && - !(hh->eh.root.type == bfd_link_hash_defined - || hh->eh.root.type == bfd_link_hash_defweak)) - return metag_stub_none; - - /* Determine where the call point is. */ - location = (input_sec->output_offset - + input_sec->output_section->vma - + rel->r_offset); - - branch_offset = destination - location; - - /* Determine if a long branch stub is needed. Meta branch offsets - are signed 19 bits 4 byte aligned. */ - max_branch_offset = (1 << (BRANCH_BITS-1)) << 2; - - if (branch_offset + max_branch_offset >= 2*max_branch_offset) - { - if (bfd_link_pic (info)) - return metag_stub_long_branch_shared; - else - return metag_stub_long_branch; - } - - return metag_stub_none; -} - -#define MOVT_A0_3 0x82180005 -#define JUMP_A0_3 0xac180003 - -#define MOVT_A1LBP 0x83080005 -#define ADD_A1LBP 0x83080000 - -#define ADDT_A0_3_CPC 0x82980001 -#define ADD_A0_3_A0_3 0x82180000 -#define MOV_PC_A0_3 0xa3180ca0 - -static bfd_boolean -metag_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf_metag_stub_hash_entry *hsh; - asection *stub_sec; - bfd *stub_bfd; - bfd_byte *loc; - bfd_vma sym_value; - int size; - - /* Massage our args to the form they really have. */ - hsh = (struct elf_metag_stub_hash_entry *) gen_entry; - - stub_sec = hsh->stub_sec; - - /* Make a note of the offset within the stubs for this entry. */ - hsh->stub_offset = stub_sec->size; - loc = stub_sec->contents + hsh->stub_offset; - - stub_bfd = stub_sec->owner; - - switch (hsh->stub_type) - { - case metag_stub_long_branch_shared: - /* A PIC long branch stub is an ADDT and an ADD instruction used to - calculate the jump target using A0.3 as a temporary. Then a MOV - to PC carries out the jump. */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma - + hsh->addend); - - sym_value -= (hsh->stub_offset - + stub_sec->output_offset - + stub_sec->output_section->vma); - - bfd_put_32 (stub_bfd, ADDT_A0_3_CPC | (((sym_value >> 16) & 0xffff) << 3), - loc); - - bfd_put_32 (stub_bfd, ADD_A0_3_A0_3 | ((sym_value & 0xffff) << 3), - loc + 4); - - bfd_put_32 (stub_bfd, MOV_PC_A0_3, loc + 8); - - size = 12; - break; - case metag_stub_long_branch: - /* A standard long branch stub is a MOVT instruction followed by a - JUMP instruction using the A0.3 register as a temporary. This is - the same method used by the LDLK linker (patch.c). */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma - + hsh->addend); - - bfd_put_32 (stub_bfd, MOVT_A0_3 | (((sym_value >> 16) & 0xffff) << 3), - loc); - - bfd_put_32 (stub_bfd, JUMP_A0_3 | ((sym_value & 0xffff) << 3), loc + 4); - - size = 8; - break; - default: - BFD_FAIL (); - return FALSE; - } - - stub_sec->size += size; - return TRUE; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ - -static bfd_boolean -metag_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf_metag_stub_hash_entry *hsh; - int size = 0; - - /* Massage our args to the form they really have. */ - hsh = (struct elf_metag_stub_hash_entry *) gen_entry; - - if (hsh->stub_type == metag_stub_long_branch) - size = 8; - else if (hsh->stub_type == metag_stub_long_branch_shared) - size = 12; - - hsh->stub_sec->size += size; - return TRUE; -} - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ - -int -elf_metag_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - bfd_size_type amt; - struct elf_metag_link_hash_table *htab = metag_link_hash_table (info); - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - if (top_id < section->id) - top_id = section->id; - } - } - - htab->bfd_count = bfd_count; - - amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = bfd_zmalloc (amt); - if (htab->stub_group == NULL) - return -1; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - { - /* FIXME: This is a bit of hack. Currently our .ctors and .dtors - * have PC relative relocs in them but no code flag set. */ - if (((section->flags & SEC_CODE) != 0) || - strcmp(".ctors", section->name) || - strcmp(".dtors", section->name)) - input_list[section->index] = NULL; - } - - return 1; -} - -/* The linker repeatedly calls this function for each input section, - in the order that input sections are linked into output sections. - Build lists of input sections to determine groupings between which - we may insert linker stubs. */ - -void -elf_metag_next_input_section (struct bfd_link_info *info, asection *isec) -{ - struct elf_metag_link_hash_table *htab = metag_link_hash_table (info); - - if (isec->output_section->index <= htab->top_index) - { - asection **list = htab->input_list + isec->output_section->index; - if (*list != bfd_abs_section_ptr) - { - /* Steal the link_sec pointer for our list. */ -#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) - /* This happens to make the list in reverse order, - which is what we want. */ - PREV_SEC (isec) = *list; - *list = isec; - } - } -} - -/* See whether we can group stub sections together. Grouping stub - sections may result in fewer stubs. More importantly, we need to - put all .init* and .fini* stubs at the beginning of the .init or - .fini output sections respectively, because glibc splits the - _init and _fini functions into multiple parts. Putting a stub in - the middle of a function is not a good idea. */ - -static void -group_sections (struct elf_metag_link_hash_table *htab, - bfd_size_type stub_group_size, - bfd_boolean stubs_always_before_branch) -{ - asection **list = htab->input_list + htab->top_index; - do - { - asection *tail = *list; - if (tail == bfd_abs_section_ptr) - continue; - while (tail != NULL) - { - asection *curr; - asection *prev; - bfd_size_type total; - bfd_boolean big_sec; - - curr = tail; - total = tail->size; - big_sec = total >= stub_group_size; - - while ((prev = PREV_SEC (curr)) != NULL - && ((total += curr->output_offset - prev->output_offset) - < stub_group_size)) - curr = prev; - - /* OK, the size from the start of CURR to the end is less - than stub_group_size bytes and thus can be handled by one stub - section. (or the tail section is itself larger than - stub_group_size bytes, in which case we may be toast.) - We should really be keeping track of the total size of - stubs added here, as stubs contribute to the final output - section size. */ - do - { - prev = PREV_SEC (tail); - /* Set up this stub group. */ - htab->stub_group[tail->id].link_sec = curr; - } - while (tail != curr && (tail = prev) != NULL); - - /* But wait, there's more! Input sections up to stub_group_size - bytes before the stub section can be handled by it too. - Don't do this if we have a really large section after the - stubs, as adding more stubs increases the chance that - branches may not reach into the stub section. */ - if (!stubs_always_before_branch && !big_sec) - { - total = 0; - while (prev != NULL - && ((total += tail->output_offset - prev->output_offset) - < stub_group_size)) - { - tail = prev; - prev = PREV_SEC (tail); - htab->stub_group[tail->id].link_sec = curr; - } - } - tail = prev; - } - } - while (list-- != htab->input_list); - free (htab->input_list); -#undef PREV_SEC -} - -/* Read in all local syms for all input bfds. - Returns -1 on error, 0 otherwise. */ - -static int -get_local_syms (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *input_bfd, - struct bfd_link_info *info) -{ - unsigned int bfd_indx; - Elf_Internal_Sym *local_syms, **all_local_syms; - int stub_changed = 0; - struct elf_metag_link_hash_table *htab = metag_link_hash_table (info); - - /* We want to read in symbol extension records only once. To do this - we need to read in the local symbols in parallel and save them for - later use; so hold pointers to the local symbols in an array. */ - bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count; - all_local_syms = bfd_zmalloc (amt); - htab->all_local_syms = all_local_syms; - if (all_local_syms == NULL) - return -1; - - /* Walk over all the input BFDs, swapping in local symbols. */ - for (bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* We need an array of the local symbols attached to the input bfd. */ - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - { - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - /* Cache them for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - if (local_syms == NULL) - return -1; - - all_local_syms[bfd_indx] = local_syms; - } - - return stub_changed; -} - -/* Determine and set the size of the stub section for a final link. - -The basic idea here is to examine all the relocations looking for -PC-relative calls to a target that is unreachable with a "CALLR" -instruction. */ - -/* See elf32-hppa.c and elf64-ppc.c. */ - -bfd_boolean -elf_metag_size_stubs(bfd *output_bfd, bfd *stub_bfd, - struct bfd_link_info *info, - bfd_signed_vma group_size, - asection * (*add_stub_section) (const char *, asection *), - void (*layout_sections_again) (void)) -{ - bfd_size_type stub_group_size; - bfd_boolean stubs_always_before_branch; - bfd_boolean stub_changed; - struct elf_metag_link_hash_table *htab = metag_link_hash_table (info); - - /* Stash our params away. */ - htab->stub_bfd = stub_bfd; - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; - stubs_always_before_branch = group_size < 0; - if (group_size < 0) - stub_group_size = -group_size; - else - stub_group_size = group_size; - if (stub_group_size == 1) - { - /* Default values. */ - /* FIXME: not sure what these values should be */ - if (stubs_always_before_branch) - { - stub_group_size = (1 << BRANCH_BITS); - } - else - { - stub_group_size = (1 << BRANCH_BITS); - } - } - - group_sections (htab, stub_group_size, stubs_always_before_branch); - - switch (get_local_syms (output_bfd, info->input_bfds, info)) - { - default: - if (htab->all_local_syms) - goto error_ret_free_local; - return FALSE; - - case 0: - stub_changed = FALSE; - break; - - case 1: - stub_changed = TRUE; - break; - } - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - asection *stub_sec; - - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - local_syms = htab->all_local_syms[bfd_indx]; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - enum elf_metag_stub_type stub_type; - struct elf_metag_stub_hash_entry *hsh; - asection *sym_sec; - bfd_vma sym_value; - bfd_vma destination; - struct elf_metag_link_hash_entry *hh; - char *stub_name; - const asection *id_sec; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - if (r_type >= (unsigned int) R_METAG_MAX) - { - bfd_set_error (bfd_error_bad_value); - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - goto error_ret_free_local; - } - - /* Only look for stubs on CALLR and B instructions. */ - if (!(r_type == (unsigned int) R_METAG_RELBRANCH || - r_type == (unsigned int) R_METAG_RELBRANCH_PLT)) - continue; - - /* Now determine the call target, its name, value, - section. */ - sym_sec = NULL; - sym_value = 0; - destination = 0; - hh = NULL; - if (r_indx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - Elf_Internal_Sym *sym; - Elf_Internal_Shdr *hdr; - unsigned int shndx; - - sym = local_syms + r_indx; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - sym_value = sym->st_value; - shndx = sym->st_shndx; - if (shndx < elf_numsections (input_bfd)) - { - hdr = elf_elfsections (input_bfd)[shndx]; - sym_sec = hdr->bfd_section; - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - } - else - { - /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hh = ((struct elf_metag_link_hash_entry *) - elf_sym_hashes (input_bfd)[e_indx]); - - while (hh->eh.root.type == bfd_link_hash_indirect - || hh->eh.root.type == bfd_link_hash_warning) - hh = ((struct elf_metag_link_hash_entry *) - hh->eh.root.u.i.link); - - if (hh->eh.root.type == bfd_link_hash_defined - || hh->eh.root.type == bfd_link_hash_defweak) - { - sym_sec = hh->eh.root.u.def.section; - sym_value = hh->eh.root.u.def.value; - if (hh->eh.plt.offset != (bfd_vma) -1 - && hh->eh.dynindx != -1 - && r_type == (unsigned int) R_METAG_RELBRANCH_PLT) - { - sym_sec = htab->etab.splt; - sym_value = hh->eh.plt.offset; - } - - if (sym_sec->output_section != NULL) - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - else - continue; - } - else if (hh->eh.root.type == bfd_link_hash_undefweak) - { - if (! bfd_link_pic (info)) - continue; - } - else if (hh->eh.root.type == bfd_link_hash_undefined) - { - if (! (info->unresolved_syms_in_objects == RM_IGNORE - && (ELF_ST_VISIBILITY (hh->eh.other) - == STV_DEFAULT))) - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - } - - /* Determine what (if any) linker stub is needed. */ - stub_type = metag_type_of_stub (section, irela, hh, - destination, info); - if (stub_type == metag_stub_none) - continue; - - /* Support for grouping stub sections. */ - id_sec = htab->stub_group[section->id].link_sec; - - /* Get the name of this stub. */ - stub_name = metag_stub_name (id_sec, sym_sec, hh, irela); - if (!stub_name) - goto error_ret_free_internal; - - hsh = metag_stub_hash_lookup (&htab->bstab, - stub_name, - FALSE, FALSE); - if (hsh != NULL) - { - /* The proper stub has already been created. */ - free (stub_name); - continue; - } - - hsh = metag_add_stub (stub_name, section, htab); - if (hsh == NULL) - { - free (stub_name); - goto error_ret_free_internal; - } - hsh->target_value = sym_value; - hsh->target_section = sym_sec; - hsh->stub_type = stub_type; - hsh->hh = hh; - hsh->addend = irela->r_addend; - stub_changed = TRUE; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - } - - if (!stub_changed) - break; - - /* OK, we've added some stubs. Find out the new size of the - stub sections. */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - stub_sec->size = 0; - - bfd_hash_traverse (&htab->bstab, metag_size_one_stub, htab); - - /* Ask the linker to do its stuff. */ - (*htab->layout_sections_again) (); - stub_changed = FALSE; - } - - free (htab->all_local_syms); - return TRUE; - - error_ret_free_local: - free (htab->all_local_syms); - return FALSE; -} - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. This function is called via metagelf_finish in the linker. */ - -bfd_boolean -elf_metag_build_stubs (struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - struct elf_metag_link_hash_table *htab; - - htab = metag_link_hash_table (info); - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - { - bfd_size_type size; - - /* Allocate memory to hold the linker stubs. */ - size = stub_sec->size; - stub_sec->contents = bfd_zalloc (htab->stub_bfd, size); - if (stub_sec->contents == NULL && size != 0) - return FALSE; - stub_sec->size = 0; - } - - /* Build the stubs as directed by the stub hash table. */ - table = &htab->bstab; - bfd_hash_traverse (table, metag_build_one_stub, info); - - return TRUE; -} - -/* Return TRUE if SYM represents a local label symbol. */ - -static bfd_boolean -elf_metag_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - if (name[0] == '$' && name[1] == 'L') - return 1; - return _bfd_elf_is_local_label_name (abfd, name); -} - -/* 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_metag_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + (i + 1) * PLT_ENTRY_SIZE; -} - -#define ELF_ARCH bfd_arch_metag -#define ELF_TARGET_ID METAG_ELF_DATA -#define ELF_MACHINE_CODE EM_METAG -#define ELF_MINPAGESIZE 0x1000 -#define ELF_MAXPAGESIZE 0x4000 -#define ELF_COMMONPAGESIZE 0x1000 - -#define TARGET_LITTLE_SYM metag_elf32_vec -#define TARGET_LITTLE_NAME "elf32-metag" - -#define elf_symbol_leading_char '_' - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto metag_info_to_howto_rela - -#define bfd_elf32_bfd_is_local_label_name elf_metag_is_local_label_name -#define bfd_elf32_bfd_link_hash_table_create \ - elf_metag_link_hash_table_create -#define elf_backend_relocate_section elf_metag_relocate_section -#define elf_backend_gc_mark_hook elf_metag_gc_mark_hook -#define elf_backend_check_relocs elf_metag_check_relocs -#define elf_backend_create_dynamic_sections elf_metag_create_dynamic_sections -#define elf_backend_adjust_dynamic_symbol elf_metag_adjust_dynamic_symbol -#define elf_backend_finish_dynamic_symbol elf_metag_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections elf_metag_finish_dynamic_sections -#define elf_backend_size_dynamic_sections elf_metag_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_post_process_headers elf_metag_post_process_headers -#define elf_backend_reloc_type_class elf_metag_reloc_type_class -#define elf_backend_copy_indirect_symbol elf_metag_copy_indirect_symbol -#define elf_backend_plt_sym_val elf_metag_plt_sym_val - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_rela_normal 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_want_got_sym 0 -#define elf_backend_want_plt_sym 0 -#define elf_backend_plt_readonly 1 -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_want_dynrelro 1 - -#define bfd_elf32_bfd_reloc_type_lookup metag_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup metag_reloc_name_lookup - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-metag.h b/sdcc/support/sdbinutils/bfd/elf32-metag.h deleted file mode 100644 index 4836298e7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-metag.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Meta support for 32-bit ELF - Copyright (C) 2013-2018 Free Software Foundation, Inc. - Contributed by Imagination Technologies Ltd. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_METAG_H -#define _ELF32_METAG_H - -extern int elf_metag_setup_section_lists - (bfd *, struct bfd_link_info *); - -extern void elf_metag_next_input_section - (struct bfd_link_info *, asection *); - -extern bfd_boolean elf_metag_size_stubs - (bfd *, bfd *, struct bfd_link_info *, bfd_signed_vma, - asection * (*) (const char *, asection *), void (*) (void)); - -extern bfd_boolean elf_metag_build_stubs - (struct bfd_link_info *); - -#endif /* _ELF32_METAG_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-microblaze.c b/sdcc/support/sdbinutils/bfd/elf32-microblaze.c deleted file mode 100644 index f1808bc44..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-microblaze.c +++ /dev/null @@ -1,3462 +0,0 @@ -/* Xilinx MicroBlaze-specific support for 32-bit ELF - - Copyright (C) 2009-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - - -int dbg = 0; - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/microblaze.h" -#include - -#define USE_RELA /* Only USE_REL is actually significant, but this is - here are a reminder... */ -#define INST_WORD_SIZE 4 - -static int ro_small_data_pointer = 0; -static int rw_small_data_pointer = 0; - -static reloc_howto_type * microblaze_elf_howto_table [(int) R_MICROBLAZE_max]; - -static reloc_howto_type microblaze_elf_howto_raw[] = -{ - /* This reloc does nothing. */ - HOWTO (R_MICROBLAZE_NONE, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - NULL, /* Special Function. */ - "R_MICROBLAZE_NONE", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* A standard 32 bit relocation. */ - HOWTO (R_MICROBLAZE_32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_32", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0xffffffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* A standard PCREL 32 bit relocation. */ - HOWTO (R_MICROBLAZE_32_PCREL,/* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_32_PCREL", /* Name. */ - TRUE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0xffffffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* A 64 bit PCREL relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_64_PCREL,/* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_64_PCREL", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* The low half of a PCREL 32 bit relocation. */ - HOWTO (R_MICROBLAZE_32_PCREL_LO, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain on overflow. */ - bfd_elf_generic_reloc, /* Special Function. */ - "R_MICROBLAZE_32_PCREL_LO", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* A 64 bit relocation. Table entry not really used. */ - HOWTO (R_MICROBLAZE_64, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_64", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* The low half of a 32 bit relocation. */ - HOWTO (R_MICROBLAZE_32_LO, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_32_LO", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* Read-only small data section relocation. */ - HOWTO (R_MICROBLAZE_SRO32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_SRO32", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* Read-write small data area relocation. */ - HOWTO (R_MICROBLAZE_SRW32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_SRW32", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* This reloc does nothing. Used for relaxation. */ - HOWTO (R_MICROBLAZE_64_NONE, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - NULL, /* Special Function. */ - "R_MICROBLAZE_64_NONE",/* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* Symbol Op Symbol relocation. */ - HOWTO (R_MICROBLAZE_32_SYM_OP_SYM, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_32_SYM_OP_SYM", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0xffffffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_MICROBLAZE_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_MICROBLAZE_GNU_VTINHERIT", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_MICROBLAZE_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_MICROBLAZE_GNU_VTENTRY", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* A 64 bit GOTPC relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_GOTPC_64, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc, /* Special Function. */ - "R_MICROBLAZE_GOTPC_64", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* A 64 bit GOT relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_GOT_64, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_GOT_64",/* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* A 64 bit PLT relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_PLT_64, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_PLT_64",/* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* Table-entry not really used. */ - HOWTO (R_MICROBLAZE_REL, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_REL", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* Table-entry not really used. */ - HOWTO (R_MICROBLAZE_JUMP_SLOT,/* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_JUMP_SLOT", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* Table-entry not really used. */ - HOWTO (R_MICROBLAZE_GLOB_DAT,/* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_GLOB_DAT", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - /* A 64 bit GOT relative relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_GOTOFF_64, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_GOTOFF_64", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* A 32 bit GOT relative relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_GOTOFF_32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc, /* Special Function. */ - "R_MICROBLAZE_GOTOFF_32", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* COPY relocation. Table-entry not really used. */ - HOWTO (R_MICROBLAZE_COPY, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_MICROBLAZE_COPY", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x0000ffff, /* Dest Mask. */ - FALSE), /* PC relative offset? */ - - /* Marker relocs for TLS. */ - HOWTO (R_MICROBLAZE_TLS, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MICROBLAZE_TLSGD, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSGD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MICROBLAZE_TLSLD, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSLD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes the load module index of the load module that contains the - definition of its TLS sym. */ - HOWTO (R_MICROBLAZE_TLSDTPMOD32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSDTPMOD32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a dtv-relative displacement, the difference between the value - of sym+add and the base address of the thread-local storage block that - contains the definition of sym, minus 0x8000. Used for initializing GOT */ - HOWTO (R_MICROBLAZE_TLSDTPREL32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSDTPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a dtv-relative displacement, the difference between the value - of sym+add and the base address of the thread-local storage block that - contains the definition of sym, minus 0x8000. */ - HOWTO (R_MICROBLAZE_TLSDTPREL64, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSDTPREL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a tp-relative displacement, the difference between the value of - sym+add and the value of the thread pointer (r13). */ - HOWTO (R_MICROBLAZE_TLSGOTTPREL32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSGOTTPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a tp-relative displacement, the difference between the value of - sym+add and the value of the thread pointer (r13). */ - HOWTO (R_MICROBLAZE_TLSTPREL32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MICROBLAZE_TLSTPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -#ifndef NUM_ELEM -#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) -#endif - -/* Initialize the microblaze_elf_howto_table, so that linear accesses can be done. */ - -static void -microblaze_elf_howto_init (void) -{ - unsigned int i; - - for (i = NUM_ELEM (microblaze_elf_howto_raw); i--;) - { - unsigned int type; - - type = microblaze_elf_howto_raw[i].type; - - BFD_ASSERT (type < NUM_ELEM (microblaze_elf_howto_table)); - - microblaze_elf_howto_table [type] = & microblaze_elf_howto_raw [i]; - } -} - -static reloc_howto_type * -microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - enum elf_microblaze_reloc_type microblaze_reloc = R_MICROBLAZE_NONE; - - switch (code) - { - case BFD_RELOC_NONE: - microblaze_reloc = R_MICROBLAZE_NONE; - break; - case BFD_RELOC_MICROBLAZE_64_NONE: - microblaze_reloc = R_MICROBLAZE_64_NONE; - break; - case BFD_RELOC_32: - microblaze_reloc = R_MICROBLAZE_32; - break; - /* RVA is treated the same as 32 */ - case BFD_RELOC_RVA: - microblaze_reloc = R_MICROBLAZE_32; - break; - case BFD_RELOC_32_PCREL: - microblaze_reloc = R_MICROBLAZE_32_PCREL; - break; - case BFD_RELOC_64_PCREL: - microblaze_reloc = R_MICROBLAZE_64_PCREL; - break; - case BFD_RELOC_MICROBLAZE_32_LO_PCREL: - microblaze_reloc = R_MICROBLAZE_32_PCREL_LO; - break; - case BFD_RELOC_64: - microblaze_reloc = R_MICROBLAZE_64; - break; - case BFD_RELOC_MICROBLAZE_32_LO: - microblaze_reloc = R_MICROBLAZE_32_LO; - break; - case BFD_RELOC_MICROBLAZE_32_ROSDA: - microblaze_reloc = R_MICROBLAZE_SRO32; - break; - case BFD_RELOC_MICROBLAZE_32_RWSDA: - microblaze_reloc = R_MICROBLAZE_SRW32; - break; - case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM: - microblaze_reloc = R_MICROBLAZE_32_SYM_OP_SYM; - break; - case BFD_RELOC_VTABLE_INHERIT: - microblaze_reloc = R_MICROBLAZE_GNU_VTINHERIT; - break; - case BFD_RELOC_VTABLE_ENTRY: - microblaze_reloc = R_MICROBLAZE_GNU_VTENTRY; - break; - case BFD_RELOC_MICROBLAZE_64_GOTPC: - microblaze_reloc = R_MICROBLAZE_GOTPC_64; - break; - case BFD_RELOC_MICROBLAZE_64_GOT: - microblaze_reloc = R_MICROBLAZE_GOT_64; - break; - case BFD_RELOC_MICROBLAZE_64_PLT: - microblaze_reloc = R_MICROBLAZE_PLT_64; - break; - case BFD_RELOC_MICROBLAZE_64_GOTOFF: - microblaze_reloc = R_MICROBLAZE_GOTOFF_64; - break; - case BFD_RELOC_MICROBLAZE_32_GOTOFF: - microblaze_reloc = R_MICROBLAZE_GOTOFF_32; - break; - case BFD_RELOC_MICROBLAZE_64_TLSGD: - microblaze_reloc = R_MICROBLAZE_TLSGD; - break; - case BFD_RELOC_MICROBLAZE_64_TLSLD: - microblaze_reloc = R_MICROBLAZE_TLSLD; - break; - case BFD_RELOC_MICROBLAZE_32_TLSDTPREL: - microblaze_reloc = R_MICROBLAZE_TLSDTPREL32; - break; - case BFD_RELOC_MICROBLAZE_64_TLSDTPREL: - microblaze_reloc = R_MICROBLAZE_TLSDTPREL64; - break; - case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD: - microblaze_reloc = R_MICROBLAZE_TLSDTPMOD32; - break; - case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL: - microblaze_reloc = R_MICROBLAZE_TLSGOTTPREL32; - break; - case BFD_RELOC_MICROBLAZE_64_TLSTPREL: - microblaze_reloc = R_MICROBLAZE_TLSTPREL32; - break; - case BFD_RELOC_MICROBLAZE_COPY: - microblaze_reloc = R_MICROBLAZE_COPY; - break; - default: - return (reloc_howto_type *) NULL; - } - - if (!microblaze_elf_howto_table [R_MICROBLAZE_32]) - /* Initialize howto table if needed. */ - microblaze_elf_howto_init (); - - return microblaze_elf_howto_table [(int) microblaze_reloc]; -}; - -static reloc_howto_type * -microblaze_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < NUM_ELEM (microblaze_elf_howto_raw); i++) - if (microblaze_elf_howto_raw[i].name != NULL - && strcasecmp (microblaze_elf_howto_raw[i].name, r_name) == 0) - return µblaze_elf_howto_raw[i]; - - return NULL; -} - -/* Set the howto pointer for a RCE ELF reloc. */ - -static void -microblaze_elf_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - if (!microblaze_elf_howto_table [R_MICROBLAZE_32]) - /* Initialize howto table if needed. */ - microblaze_elf_howto_init (); - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_MICROBLAZE_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised MicroBlaze reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_MICROBLAZE_NONE; - } - - cache_ptr->howto = microblaze_elf_howto_table [r_type]; -} - -/* Microblaze ELF local labels start with 'L.' or '$L', not '.L'. */ - -static bfd_boolean -microblaze_elf_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == 'L' && name[1] == '.') - return TRUE; - - if (name[0] == '$' && name[1] == 'L') - return TRUE; - - /* With gcc, the labels go back to starting with '.', so we accept - the generic ELF local label syntax as well. */ - return _bfd_elf_is_local_label_name (abfd, name); -} - -/* ELF linker hash entry. */ - -struct elf32_mb_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* TLS Reference Types for the symbol; Updated by check_relocs */ -#define TLS_GD 1 /* GD reloc. */ -#define TLS_LD 2 /* LD reloc. */ -#define TLS_TPREL 4 /* TPREL reloc, => IE. */ -#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ -#define TLS_TLS 16 /* Any TLS reloc. */ - unsigned char tls_mask; - -}; - -#define IS_TLS_GD(x) (x == (TLS_TLS | TLS_GD)) -#define IS_TLS_LD(x) (x == (TLS_TLS | TLS_LD)) -#define IS_TLS_DTPREL(x) (x == (TLS_TLS | TLS_DTPREL)) -#define IS_TLS_NONE(x) (x == 0) - -#define elf32_mb_hash_entry(ent) ((struct elf32_mb_link_hash_entry *)(ent)) - -/* ELF linker hash table. */ - -struct elf32_mb_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Small local sym to section mapping cache. */ - struct sym_cache sym_sec; - - /* TLS Local Dynamic GOT Entry */ - union { - bfd_signed_vma refcount; - bfd_vma offset; - } tlsld_got; -}; - -/* Nonzero if this section has TLS related relocations. */ -#define has_tls_reloc sec_flg0 - -/* Get the ELF linker hash table from a link_info structure. */ - -#define elf32_mb_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == MICROBLAZE_ELF_DATA ? ((struct elf32_mb_link_hash_table *) ((p)->hash)) : NULL) - -/* Create an entry in a microblaze 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 elf32_mb_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 elf32_mb_link_hash_entry *eh; - - eh = (struct elf32_mb_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - eh->tls_mask = 0; - } - - return entry; -} - -/* Create a mb ELF linker hash table. */ - -static struct bfd_link_hash_table * -microblaze_elf_link_hash_table_create (bfd *abfd) -{ - struct elf32_mb_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf32_mb_link_hash_table); - - ret = (struct elf32_mb_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, - sizeof (struct elf32_mb_link_hash_entry), - MICROBLAZE_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->elf.root; -} - -/* Set the values of the small data pointers. */ - -static void -microblaze_elf_final_sdp (struct bfd_link_info *info) -{ - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (info->hash, RO_SDA_ANCHOR_NAME, FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry *) NULL - && h->type == bfd_link_hash_defined) - ro_small_data_pointer = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - h = bfd_link_hash_lookup (info->hash, RW_SDA_ANCHOR_NAME, FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry *) NULL - && h->type == bfd_link_hash_defined) - rw_small_data_pointer = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); -} - -static bfd_vma -dtprel_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; -} - -/* The size of the thread control block. */ -#define TCB_SIZE 8 - -/* Output a simple dynamic relocation into SRELOC. */ - -static void -microblaze_elf_output_dynamic_relocation (bfd *output_bfd, - asection *sreloc, - unsigned long reloc_index, - unsigned long indx, - int r_type, - bfd_vma offset, - bfd_vma addend) -{ - - Elf_Internal_Rela rel; - - rel.r_info = ELF32_R_INFO (indx, r_type); - rel.r_offset = offset; - rel.r_addend = addend; - - bfd_elf32_swap_reloca_out (output_bfd, &rel, - (sreloc->contents + reloc_index * sizeof (Elf32_External_Rela))); -} - -/* This code is taken from elf32-m32r.c - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjust the section contents as - necessary, and (if using Rela relocs and generating a - relocatable output file) adjusting the reloc addend as - necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -microblaze_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - struct elf32_mb_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - Elf_Internal_Rela *rel, *relend; - int endian = (bfd_little_endian (output_bfd)) ? 0 : 2; - /* Assume success. */ - bfd_boolean ret = TRUE; - asection *sreloc; - bfd_vma *local_got_offsets; - unsigned int tls_type; - - if (!microblaze_elf_howto_table[R_MICROBLAZE_max-1]) - microblaze_elf_howto_init (); - - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - local_got_offsets = elf_local_got_offsets (input_bfd); - - sreloc = elf_section_data (input_section)->sreloc; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - bfd_vma addend = rel->r_addend; - bfd_vma offset = rel->r_offset; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - asection *sec; - const char *sym_name; - bfd_reloc_status_type r = bfd_reloc_ok; - const char *errmsg = NULL; - bfd_boolean unresolved_reloc = FALSE; - - h = NULL; - r_type = ELF32_R_TYPE (rel->r_info); - tls_type = 0; - - if (r_type < 0 || r_type >= (int) R_MICROBLAZE_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - } - - howto = microblaze_elf_howto_table[r_type]; - r_symndx = ELF32_R_SYM (rel->r_info); - - if (bfd_link_relocatable (info)) - { - /* 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. */ - sec = NULL; - if (r_symndx >= symtab_hdr->sh_info) - /* External symbol. */ - continue; - - /* Local symbol. */ - sym = local_syms + r_symndx; - sym_name = ""; - /* STT_SECTION: symbol is associated with a section. */ - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - /* Symbol isn't associated with a section. Nothing to do. */ - continue; - - sec = local_sections[r_symndx]; - addend += sec->output_offset + sym->st_value; -#ifndef USE_REL - /* This can't be done for USE_REL because it doesn't mean anything - and elf_link_input_bfd asserts this stays zero. */ - /* rel->r_addend = addend; */ -#endif - -#ifndef USE_REL - /* Addends are stored with relocs. We're done. */ - continue; -#else /* USE_REL */ - /* If partial_inplace, we need to store any additional addend - back in the section. */ - if (!howto->partial_inplace) - continue; - /* ??? Here is a nice place to call a special_function like handler. */ - r = _bfd_relocate_contents (howto, input_bfd, addend, - contents + offset); -#endif /* USE_REL */ - } - else - { - bfd_vma relocation; - bfd_boolean resolved_to_zero; - - /* This is a final link. */ - sym = NULL; - sec = NULL; - unresolved_reloc = FALSE; - - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - if (sec == 0) - continue; - sym_name = ""; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - /* r_addend may have changed if the reference section was - a merge section. */ - addend = rel->r_addend; - } - else - { - /* External symbol. */ - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - sym_name = h->root.root.string; - } - - /* Sanity check the address. */ - if (offset > bfd_get_section_limit (input_bfd, input_section)) - { - r = bfd_reloc_outofrange; - goto check_reloc; - } - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch ((int) r_type) - { - case (int) R_MICROBLAZE_SRO32 : - { - const char *name; - - /* Only relocate if the symbol is defined. */ - if (sec) - { - name = bfd_get_section_name (sec->owner, sec); - - if (strcmp (name, ".sdata2") == 0 - || strcmp (name, ".sbss2") == 0) - { - if (ro_small_data_pointer == 0) - microblaze_elf_final_sdp (info); - if (ro_small_data_pointer == 0) - { - ret = FALSE; - r = bfd_reloc_undefined; - goto check_reloc; - } - - /* At this point `relocation' contains the object's - address. */ - relocation -= ro_small_data_pointer; - /* Now it contains the offset from _SDA2_BASE_. */ - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, - contents, offset, - relocation, addend); - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: The target (%s) of an %s relocation" - " is in the wrong section (%A)"), - input_bfd, - sym_name, - microblaze_elf_howto_table[(int) r_type]->name, - sec); - /*bfd_set_error (bfd_error_bad_value); ??? why? */ - ret = FALSE; - continue; - } - } - } - break; - - case (int) R_MICROBLAZE_SRW32 : - { - const char *name; - - /* Only relocate if the symbol is defined. */ - if (sec) - { - name = bfd_get_section_name (sec->owner, sec); - - if (strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0) - { - if (rw_small_data_pointer == 0) - microblaze_elf_final_sdp (info); - if (rw_small_data_pointer == 0) - { - ret = FALSE; - r = bfd_reloc_undefined; - goto check_reloc; - } - - /* At this point `relocation' contains the object's - address. */ - relocation -= rw_small_data_pointer; - /* Now it contains the offset from _SDA_BASE_. */ - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, - contents, offset, - relocation, addend); - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: The target (%s) of an %s relocation" - " is in the wrong section (%A)"), - input_bfd, - sym_name, - microblaze_elf_howto_table[(int) r_type]->name, - sec); - /*bfd_set_error (bfd_error_bad_value); ??? why? */ - ret = FALSE; - continue; - } - } - } - break; - - case (int) R_MICROBLAZE_32_SYM_OP_SYM: - break; /* Do nothing. */ - - case (int) R_MICROBLAZE_GOTPC_64: - relocation = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset); - relocation -= (input_section->output_section->vma - + input_section->output_offset - + offset + INST_WORD_SIZE); - relocation += addend; - bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, - contents + offset + endian); - bfd_put_16 (input_bfd, relocation & 0xffff, - contents + offset + endian + INST_WORD_SIZE); - break; - - case (int) R_MICROBLAZE_PLT_64: - { - bfd_vma immediate; - if (htab->elf.splt != NULL && h != NULL - && h->plt.offset != (bfd_vma) -1) - { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); - unresolved_reloc = FALSE; - immediate = relocation - (input_section->output_section->vma - + input_section->output_offset - + offset + INST_WORD_SIZE); - bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff, - contents + offset + endian); - bfd_put_16 (input_bfd, immediate & 0xffff, - contents + offset + endian + INST_WORD_SIZE); - } - else - { - relocation -= (input_section->output_section->vma - + input_section->output_offset - + offset + INST_WORD_SIZE); - immediate = relocation; - bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff, - contents + offset + endian); - bfd_put_16 (input_bfd, immediate & 0xffff, - contents + offset + endian + INST_WORD_SIZE); - } - break; - } - - case (int) R_MICROBLAZE_TLSGD: - tls_type = (TLS_TLS | TLS_GD); - goto dogot; - case (int) R_MICROBLAZE_TLSLD: - tls_type = (TLS_TLS | TLS_LD); - /* Fall through. */ - dogot: - case (int) R_MICROBLAZE_GOT_64: - { - bfd_vma *offp; - bfd_vma off, off2; - unsigned long indx; - bfd_vma static_value; - - bfd_boolean need_relocs = FALSE; - if (htab->elf.sgot == NULL) - abort (); - - indx = 0; - offp = NULL; - - /* 1. Identify GOT Offset; - 2. Compute Static Values - 3. Process Module Id, Process Offset - 4. Fixup Relocation with GOT offset value. */ - - /* 1. Determine GOT Offset to use : TLS_LD, global, local */ - if (IS_TLS_LD (tls_type)) - offp = &htab->tlsld_got.offset; - else if (h != NULL) - { - if (htab->elf.sgotplt != NULL - && h->got.offset != (bfd_vma) -1) - offp = &h->got.offset; - else - abort (); - } - else - { - if (local_got_offsets == NULL) - abort (); - offp = &local_got_offsets[r_symndx]; - } - - if (!offp) - abort (); - - off = (*offp) & ~1; - off2 = off; - - if (IS_TLS_LD(tls_type) || IS_TLS_GD(tls_type)) - off2 = off + 4; - - /* Symbol index to use for relocs */ - if (h != NULL) - { - bfd_boolean dyn = - elf_hash_table (info)->dynamic_sections_created; - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - indx = h->dynindx; - } - - /* Need to generate relocs ? */ - if ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak)) - need_relocs = TRUE; - - /* 2. Compute/Emit Static value of r-expression */ - static_value = relocation + addend; - - /* 3. Process module-id and offset */ - if (! ((*offp) & 1) ) - { - bfd_vma got_offset; - - got_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - - /* Process module-id */ - if (IS_TLS_LD(tls_type)) - { - if (! bfd_link_pic (info)) - bfd_put_32 (output_bfd, 1, - htab->elf.sgot->contents + off); - else - microblaze_elf_output_dynamic_relocation - (output_bfd, - htab->elf.srelgot, - htab->elf.srelgot->reloc_count++, - /* symindex= */ 0, R_MICROBLAZE_TLSDTPMOD32, - got_offset, 0); - } - else if (IS_TLS_GD(tls_type)) - { - if (! need_relocs) - bfd_put_32 (output_bfd, 1, - htab->elf.sgot->contents + off); - else - microblaze_elf_output_dynamic_relocation - (output_bfd, - htab->elf.srelgot, - htab->elf.srelgot->reloc_count++, - /* symindex= */ indx, R_MICROBLAZE_TLSDTPMOD32, - got_offset, indx ? 0 : static_value); - } - - /* Process Offset */ - if (htab->elf.srelgot == NULL) - abort (); - - got_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off2); - if (IS_TLS_LD(tls_type)) - { - /* For LD, offset should be 0 */ - *offp |= 1; - bfd_put_32 (output_bfd, 0, - htab->elf.sgot->contents + off2); - } - else if (IS_TLS_GD(tls_type)) - { - *offp |= 1; - static_value -= dtprel_base(info); - if (need_relocs) - microblaze_elf_output_dynamic_relocation - (output_bfd, - htab->elf.srelgot, - htab->elf.srelgot->reloc_count++, - /* symindex= */ indx, R_MICROBLAZE_TLSDTPREL32, - got_offset, indx ? 0 : static_value); - else - bfd_put_32 (output_bfd, static_value, - htab->elf.sgot->contents + off2); - } - else - { - bfd_put_32 (output_bfd, static_value, - htab->elf.sgot->contents + off2); - - /* Relocs for dyn symbols generated by - finish_dynamic_symbols */ - if (bfd_link_pic (info) && h == NULL) - { - *offp |= 1; - microblaze_elf_output_dynamic_relocation - (output_bfd, - htab->elf.srelgot, - htab->elf.srelgot->reloc_count++, - /* symindex= */ indx, R_MICROBLAZE_REL, - got_offset, static_value); - } - } - } - - /* 4. Fixup Relocation with GOT offset value - Compute relative address of GOT entry for applying - the current relocation */ - relocation = htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off - - htab->elf.sgotplt->output_section->vma - - htab->elf.sgotplt->output_offset; - - /* Apply Current Relocation */ - bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, - contents + offset + endian); - bfd_put_16 (input_bfd, relocation & 0xffff, - contents + offset + endian + INST_WORD_SIZE); - - unresolved_reloc = FALSE; - break; - } - - case (int) R_MICROBLAZE_GOTOFF_64: - { - bfd_vma immediate; - unsigned short lo, high; - relocation += addend; - relocation -= (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset); - /* Write this value into correct location. */ - immediate = relocation; - lo = immediate & 0x0000ffff; - high = (immediate >> 16) & 0x0000ffff; - bfd_put_16 (input_bfd, high, contents + offset + endian); - bfd_put_16 (input_bfd, lo, - contents + offset + INST_WORD_SIZE + endian); - break; - } - - case (int) R_MICROBLAZE_GOTOFF_32: - { - relocation += addend; - relocation -= (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset); - /* Write this value into correct location. */ - bfd_put_32 (input_bfd, relocation, contents + offset); - break; - } - - case (int) R_MICROBLAZE_TLSDTPREL64: - relocation += addend; - relocation -= dtprel_base(info); - bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, - contents + offset + 2); - bfd_put_16 (input_bfd, relocation & 0xffff, - contents + offset + 2 + INST_WORD_SIZE); - break; - case (int) R_MICROBLAZE_64_PCREL : - case (int) R_MICROBLAZE_64: - case (int) R_MICROBLAZE_32: - { - /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ - if (r_symndx == STN_UNDEF || (input_section->flags & SEC_ALLOC) == 0) - { - relocation += addend; - if (r_type == R_MICROBLAZE_32) - bfd_put_32 (input_bfd, relocation, contents + offset); - else - { - if (r_type == R_MICROBLAZE_64_PCREL) - relocation -= (input_section->output_section->vma - + input_section->output_offset - + offset + INST_WORD_SIZE); - bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, - contents + offset + endian); - bfd_put_16 (input_bfd, relocation & 0xffff, - contents + offset + endian + INST_WORD_SIZE); - } - break; - } - - if ((bfd_link_pic (info) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && (!howto->pc_relative - || (h != NULL - && h->dynindx != -1 - && (!info->symbolic - || !h->def_regular)))) - || (!bfd_link_pic (info) - && h != NULL - && h->dynindx != -1 - && !h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - BFD_ASSERT (sreloc != NULL); - - skip = FALSE; - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - /* h->dynindx may be -1 if the symbol was marked to - become local. */ - else if (h != NULL - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = addend; - } - else - { - if (r_type == R_MICROBLAZE_32) - { - outrel.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL); - outrel.r_addend = relocation + addend; - } - else - { - BFD_FAIL (); - _bfd_error_handler - (_("%B: probably compiled without -fPIC?"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - break; - } - else - { - relocation += addend; - if (r_type == R_MICROBLAZE_32) - bfd_put_32 (input_bfd, relocation, contents + offset); - else - { - if (r_type == R_MICROBLAZE_64_PCREL) - relocation -= (input_section->output_section->vma - + input_section->output_offset - + offset + INST_WORD_SIZE); - bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff, - contents + offset + endian); - bfd_put_16 (input_bfd, relocation & 0xffff, - contents + offset + endian + INST_WORD_SIZE); - } - break; - } - } - - default : - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, offset, - relocation, addend); - break; - } - } - - check_reloc: - - if (r != bfd_reloc_ok) - { - /* FIXME: This should be generic enough to go in a utility. */ - const char *name; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - if (errmsg != NULL) - goto common_error; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, offset, TRUE); - break; - - case bfd_reloc_outofrange: - errmsg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - errmsg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - errmsg = _("internal error: dangerous error"); - goto common_error; - - default: - errmsg = _("internal error: unknown error"); - /* Fall through. */ - common_error: - (*info->callbacks->warning) (info, errmsg, name, input_bfd, - input_section, offset); - break; - } - } - } - - return ret; -} - -/* Calculate fixup value for reference. */ - -static int -calc_fixup (bfd_vma start, bfd_vma size, asection *sec) -{ - bfd_vma end = start + size; - int i, fixup = 0; - - if (sec == NULL || sec->relax == NULL) - return 0; - - /* Look for addr in relax table, total fixup value. */ - for (i = 0; i < sec->relax_count; i++) - { - if (end <= sec->relax[i].addr) - break; - if ((end != start) && (start > sec->relax[i].addr)) - continue; - fixup += sec->relax[i].size; - } - return fixup; -} - -/* Read-modify-write into the bfd, an immediate value into appropriate fields of - a 32-bit instruction. */ -static void -microblaze_bfd_write_imm_value_32 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val) -{ - unsigned long instr = bfd_get_32 (abfd, bfd_addr); - instr &= ~0x0000ffff; - instr |= (val & 0x0000ffff); - bfd_put_32 (abfd, instr, bfd_addr); -} - -/* Read-modify-write into the bfd, an immediate value into appropriate fields of - two consecutive 32-bit instructions. */ -static void -microblaze_bfd_write_imm_value_64 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val) -{ - unsigned long instr_hi; - unsigned long instr_lo; - - instr_hi = bfd_get_32 (abfd, bfd_addr); - instr_hi &= ~0x0000ffff; - instr_hi |= ((val >> 16) & 0x0000ffff); - bfd_put_32 (abfd, instr_hi, bfd_addr); - - instr_lo = bfd_get_32 (abfd, bfd_addr + INST_WORD_SIZE); - instr_lo &= ~0x0000ffff; - instr_lo |= (val & 0x0000ffff); - bfd_put_32 (abfd, instr_lo, bfd_addr + INST_WORD_SIZE); -} - -static bfd_boolean -microblaze_elf_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *free_relocs = NULL; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - bfd_byte *free_contents = NULL; - int rel_count; - unsigned int shndx; - int i, sym_index; - asection *o; - struct elf_link_hash_entry *sym_hash; - Elf_Internal_Sym *isymbuf, *isymend; - Elf_Internal_Sym *isym; - int symcount; - int offset; - bfd_vma src, dest; - - /* We only do this once per section. We may be able to delete some code - by running multiple passes, but it is not worth it. */ - *again = FALSE; - - /* Only do this for a text section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || (sec->reloc_count == 0) - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - BFD_ASSERT ((sec->size > 0) || (sec->rawsize > 0)); - - /* If this is the first time we have been called for this section, - initialize the cooked size. */ - if (sec->size == 0) - sec->size = sec->rawsize; - - /* Get symbols for this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - symcount = symtab_hdr->sh_size / sizeof (Elf32_External_Sym); - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, symcount, - 0, NULL, NULL, NULL); - BFD_ASSERT (isymbuf != NULL); - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - if (! link_info->keep_memory) - free_relocs = internal_relocs; - - sec->relax = (struct relax_table *) bfd_malloc ((sec->reloc_count + 1) - * sizeof (struct relax_table)); - if (sec->relax == NULL) - goto error_return; - sec->relax_count = 0; - - irelend = internal_relocs + sec->reloc_count; - rel_count = 0; - for (irel = internal_relocs; irel < irelend; irel++, rel_count++) - { - bfd_vma symval; - if ((ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_64_PCREL) - && (ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_64 )) - continue; /* Can't delete this reloc. */ - - /* Get the section contents. */ - if (contents == NULL) - { - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - contents = (bfd_byte *) bfd_malloc (sec->size); - if (contents == NULL) - goto error_return; - free_contents = contents; - - if (!bfd_get_section_contents (abfd, sec, contents, - (file_ptr) 0, sec->size)) - goto error_return; - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* If this is a PC-relative reloc, subtract the instr offset from - the symbol value. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROBLAZE_64_PCREL) - { - symval = symval + irel->r_addend - - (irel->r_offset - + sec->output_section->vma - + sec->output_offset); - } - else - symval += irel->r_addend; - - if ((symval & 0xffff8000) == 0 - || (symval & 0xffff8000) == 0xffff8000) - { - /* We can delete this instruction. */ - sec->relax[sec->relax_count].addr = irel->r_offset; - sec->relax[sec->relax_count].size = INST_WORD_SIZE; - sec->relax_count++; - - /* Rewrite relocation type. */ - switch ((enum elf_microblaze_reloc_type) ELF32_R_TYPE (irel->r_info)) - { - case R_MICROBLAZE_64_PCREL: - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (int) R_MICROBLAZE_32_PCREL_LO); - break; - case R_MICROBLAZE_64: - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (int) R_MICROBLAZE_32_LO); - break; - default: - /* Cannot happen. */ - BFD_ASSERT (FALSE); - } - } - } /* Loop through all relocations. */ - - /* Loop through the relocs again, and see if anything needs to change. */ - if (sec->relax_count > 0) - { - shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - rel_count = 0; - sec->relax[sec->relax_count].addr = sec->size; - - for (irel = internal_relocs; irel < irelend; irel++, rel_count++) - { - bfd_vma nraddr; - - /* Get the new reloc address. */ - nraddr = irel->r_offset - calc_fixup (irel->r_offset, 0, sec); - switch ((enum elf_microblaze_reloc_type) ELF32_R_TYPE (irel->r_info)) - { - default: - break; - case R_MICROBLAZE_64_PCREL: - break; - case R_MICROBLAZE_64: - case R_MICROBLAZE_32_LO: - /* If this reloc is against a symbol defined in this - section, we must check the addend to see it will put the value in - range to be adjusted, and hence must be changed. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - isym = isymbuf + ELF32_R_SYM (irel->r_info); - /* Only handle relocs against .text. */ - if (isym->st_shndx == shndx - && ELF32_ST_TYPE (isym->st_info) == STT_SECTION) - irel->r_addend -= calc_fixup (irel->r_addend, 0, sec); - } - break; - case R_MICROBLAZE_NONE: - { - /* This was a PC-relative instruction that was - completely resolved. */ - int sfix, efix; - bfd_vma target_address; - target_address = irel->r_addend + irel->r_offset; - sfix = calc_fixup (irel->r_offset, 0, sec); - efix = calc_fixup (target_address, 0, sec); - irel->r_addend -= (efix - sfix); - /* Should use HOWTO. */ - microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset, - irel->r_addend); - } - break; - case R_MICROBLAZE_64_NONE: - { - /* This was a PC-relative 64-bit instruction that was - completely resolved. */ - int sfix, efix; - bfd_vma target_address; - target_address = irel->r_addend + irel->r_offset + INST_WORD_SIZE; - sfix = calc_fixup (irel->r_offset + INST_WORD_SIZE, 0, sec); - efix = calc_fixup (target_address, 0, sec); - irel->r_addend -= (efix - sfix); - microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset - + INST_WORD_SIZE, irel->r_addend); - } - break; - } - irel->r_offset = nraddr; - } /* Change all relocs in this section. */ - - /* Look through all other sections. */ - for (o = abfd->sections; o != NULL; o = o->next) - { - Elf_Internal_Rela *irelocs; - Elf_Internal_Rela *irelscan, *irelscanend; - bfd_byte *ocontents; - - if (o == sec - || (o->flags & SEC_RELOC) == 0 - || o->reloc_count == 0) - continue; - - /* We always cache the relocs. Perhaps, if info->keep_memory is - FALSE, we should free them, if we are permitted to. */ - - irelocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, TRUE); - if (irelocs == NULL) - goto error_return; - - ocontents = NULL; - irelscanend = irelocs + o->reloc_count; - for (irelscan = irelocs; irelscan < irelscanend; irelscan++) - { - if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32) - { - isym = isymbuf + ELF32_R_SYM (irelscan->r_info); - - /* Look at the reloc only if the value has been resolved. */ - if (isym->st_shndx == shndx - && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) - { - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to. */ - if (o->rawsize == 0) - o->rawsize = o->size; - ocontents = (bfd_byte *) bfd_malloc (o->rawsize); - if (ocontents == NULL) - goto error_return; - if (!bfd_get_section_contents (abfd, o, ocontents, - (file_ptr) 0, - o->rawsize)) - goto error_return; - elf_section_data (o)->this_hdr.contents = ocontents; - } - - } - irelscan->r_addend -= calc_fixup (irelscan->r_addend, 0, sec); - } - else if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_SYM_OP_SYM) - { - isym = isymbuf + ELF32_R_SYM (irelscan->r_info); - - /* Look at the reloc only if the value has been resolved. */ - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to. */ - - if (o->rawsize == 0) - o->rawsize = o->size; - ocontents = (bfd_byte *) bfd_malloc (o->rawsize); - if (ocontents == NULL) - goto error_return; - if (!bfd_get_section_contents (abfd, o, ocontents, - (file_ptr) 0, - o->rawsize)) - goto error_return; - elf_section_data (o)->this_hdr.contents = ocontents; - } - } - irelscan->r_addend -= calc_fixup (irel->r_addend - + isym->st_value, - 0, - sec); - } - } - else if ((ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_PCREL_LO) - || (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_LO)) - { - isym = isymbuf + ELF32_R_SYM (irelscan->r_info); - - /* Look at the reloc only if the value has been resolved. */ - if (isym->st_shndx == shndx - && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) - { - bfd_vma immediate; - bfd_vma target_address; - - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to. */ - if (o->rawsize == 0) - o->rawsize = o->size; - ocontents = (bfd_byte *) bfd_malloc (o->rawsize); - if (ocontents == NULL) - goto error_return; - if (!bfd_get_section_contents (abfd, o, ocontents, - (file_ptr) 0, - o->rawsize)) - goto error_return; - elf_section_data (o)->this_hdr.contents = ocontents; - } - } - - unsigned long instr = bfd_get_32 (abfd, ocontents + irelscan->r_offset); - immediate = instr & 0x0000ffff; - target_address = immediate; - offset = calc_fixup (target_address, 0, sec); - immediate -= offset; - irelscan->r_addend -= offset; - microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset, - irelscan->r_addend); - } - } - - if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_64) - { - isym = isymbuf + ELF32_R_SYM (irelscan->r_info); - - /* Look at the reloc only if the value has been resolved. */ - if (isym->st_shndx == shndx - && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) - { - bfd_vma immediate; - - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to. */ - - if (o->rawsize == 0) - o->rawsize = o->size; - ocontents = (bfd_byte *) bfd_malloc (o->rawsize); - if (ocontents == NULL) - goto error_return; - if (!bfd_get_section_contents (abfd, o, ocontents, - (file_ptr) 0, - o->rawsize)) - goto error_return; - elf_section_data (o)->this_hdr.contents = ocontents; - } - } - unsigned long instr_hi = bfd_get_32 (abfd, ocontents - + irelscan->r_offset); - unsigned long instr_lo = bfd_get_32 (abfd, ocontents - + irelscan->r_offset - + INST_WORD_SIZE); - immediate = (instr_hi & 0x0000ffff) << 16; - immediate |= (instr_lo & 0x0000ffff); - offset = calc_fixup (irelscan->r_addend, 0, sec); - immediate -= offset; - irelscan->r_addend -= offset; - } - } - else if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_64_PCREL) - { - isym = isymbuf + ELF32_R_SYM (irelscan->r_info); - - /* Look at the reloc only if the value has been resolved. */ - if (isym->st_shndx == shndx - && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION)) - { - bfd_vma immediate; - bfd_vma target_address; - - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to. */ - if (o->rawsize == 0) - o->rawsize = o->size; - ocontents = (bfd_byte *) bfd_malloc (o->rawsize); - if (ocontents == NULL) - goto error_return; - if (!bfd_get_section_contents (abfd, o, ocontents, - (file_ptr) 0, - o->rawsize)) - goto error_return; - elf_section_data (o)->this_hdr.contents = ocontents; - } - } - unsigned long instr_hi = bfd_get_32 (abfd, ocontents - + irelscan->r_offset); - unsigned long instr_lo = bfd_get_32 (abfd, ocontents - + irelscan->r_offset - + INST_WORD_SIZE); - immediate = (instr_hi & 0x0000ffff) << 16; - immediate |= (instr_lo & 0x0000ffff); - target_address = immediate; - offset = calc_fixup (target_address, 0, sec); - immediate -= offset; - irelscan->r_addend -= offset; - microblaze_bfd_write_imm_value_64 (abfd, ocontents - + irelscan->r_offset, immediate); - } - } - } - } - - /* Adjust the local symbols defined in this section. */ - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf; isym < isymend; isym++) - { - if (isym->st_shndx == shndx) - { - isym->st_value -= calc_fixup (isym->st_value, 0, sec); - if (isym->st_size) - isym->st_size -= calc_fixup (isym->st_value, isym->st_size, sec); - } - } - - /* Now adjust the global symbols defined in this section. */ - isym = isymbuf + symtab_hdr->sh_info; - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)) - symtab_hdr->sh_info; - for (sym_index = 0; sym_index < symcount; sym_index++) - { - sym_hash = elf_sym_hashes (abfd)[sym_index]; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - sym_hash->root.u.def.value -= calc_fixup (sym_hash->root.u.def.value, - 0, sec); - if (sym_hash->size) - sym_hash->size -= calc_fixup (sym_hash->root.u.def.value, - sym_hash->size, sec); - } - } - - /* Physically move the code and change the cooked size. */ - dest = sec->relax[0].addr; - for (i = 0; i < sec->relax_count; i++) - { - int len; - src = sec->relax[i].addr + sec->relax[i].size; - len = sec->relax[i+1].addr - sec->relax[i].addr - sec->relax[i].size; - - memmove (contents + dest, contents + src, len); - sec->size -= sec->relax[i].size; - dest += len; - } - - elf_section_data (sec)->relocs = internal_relocs; - free_relocs = NULL; - - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; - - symtab_hdr->contents = (bfd_byte *) isymbuf; - } - - if (free_relocs != NULL) - { - free (free_relocs); - free_relocs = NULL; - } - - if (free_contents != NULL) - { - if (!link_info->keep_memory) - free (free_contents); - else - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - free_contents = NULL; - } - - if (sec->relax_count == 0) - { - *again = FALSE; - free (sec->relax); - sec->relax = NULL; - } - else - *again = TRUE; - return TRUE; - - error_return: - if (free_relocs != NULL) - free (free_relocs); - if (free_contents != NULL) - free (free_contents); - if (sec->relax != NULL) - { - free (sec->relax); - sec->relax = NULL; - sec->relax_count = 0; - } - return FALSE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -microblaze_elf_gc_mark_hook (asection *sec, - struct bfd_link_info * info, - Elf_Internal_Rela * rel, - struct elf_link_hash_entry * h, - Elf_Internal_Sym * sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_MICROBLAZE_GNU_VTINHERIT: - case R_MICROBLAZE_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* PIC support. */ - -#define PLT_ENTRY_SIZE 16 - -#define PLT_ENTRY_WORD_0 0xb0000000 /* "imm 0". */ -#define PLT_ENTRY_WORD_1 0xe9940000 /* "lwi r12,r20,0" - relocated to lwi r12,r20,func@GOT. */ -#define PLT_ENTRY_WORD_1_NOPIC 0xe9800000 /* "lwi r12,r0,0" - non-PIC object. */ -#define PLT_ENTRY_WORD_2 0x98186000 /* "brad r12". */ -#define PLT_ENTRY_WORD_3 0x80000000 /* "nop". */ - -static bfd_boolean -update_local_sym_info (bfd *abfd, - Elf_Internal_Shdr *symtab_hdr, - unsigned long r_symndx, - unsigned int tls_type) -{ - bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); - unsigned char *local_got_tls_masks; - - if (local_got_refcounts == NULL) - { - bfd_size_type size = symtab_hdr->sh_info; - - size *= (sizeof (*local_got_refcounts) + sizeof (*local_got_tls_masks)); - local_got_refcounts = bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - - local_got_tls_masks = - (unsigned char *) (local_got_refcounts + symtab_hdr->sh_info); - local_got_tls_masks[r_symndx] |= tls_type; - local_got_refcounts[r_symndx] += 1; - - return TRUE; -} -/* Look through the relocs for a section during the first phase. */ - -static bfd_boolean -microblaze_elf_check_relocs (bfd * abfd, - struct bfd_link_info * info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - struct elf_link_hash_entry ** sym_hashes_end; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - struct elf32_mb_link_hash_table *htab; - asection *sreloc = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; - - rel_end = relocs + sec->reloc_count; - - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - struct elf_link_hash_entry * h; - unsigned long r_symndx; - unsigned char tls_type = 0; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes [r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (r_type) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_MICROBLAZE_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_MICROBLAZE_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - /* This relocation requires .plt entry. */ - case R_MICROBLAZE_PLT_64: - if (h != NULL) - { - h->needs_plt = 1; - h->plt.refcount += 1; - } - break; - - /* This relocation requires .got entry. */ - case R_MICROBLAZE_TLSGD: - tls_type |= (TLS_TLS | TLS_GD); - goto dogottls; - case R_MICROBLAZE_TLSLD: - tls_type |= (TLS_TLS | TLS_LD); - /* Fall through. */ - dogottls: - sec->has_tls_reloc = 1; - /* Fall through. */ - case R_MICROBLAZE_GOT_64: - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } - if (h != NULL) - { - h->got.refcount += 1; - elf32_mb_hash_entry (h)->tls_mask |= tls_type; - } - else - { - if (! update_local_sym_info(abfd, symtab_hdr, r_symndx, tls_type) ) - return FALSE; - } - break; - - case R_MICROBLAZE_GOTOFF_64: - case R_MICROBLAZE_GOTOFF_32: - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } - break; - - case R_MICROBLAZE_64: - case R_MICROBLAZE_64_PCREL: - case R_MICROBLAZE_32: - { - if (h != NULL && !bfd_link_pic (info)) - { - /* we may need a copy reloc. */ - h->non_got_ref = 1; - - /* we may also need a .plt entry. */ - h->plt.refcount += 1; - if (ELF32_R_TYPE (rel->r_info) != R_MICROBLAZE_64_PCREL) - 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 ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (r_type != R_MICROBLAZE_64_PCREL - || (h != NULL - && (! info->symbolic - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (!bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - /* When creating a shared object, we must copy these - relocs into the output file. We create a reloc - section in dynobj and make room for the reloc. */ - - if (sreloc == NULL) - { - bfd *dynobj; - - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - dynobj = htab->elf.dynobj; - - sreloc = _bfd_elf_make_dynamic_reloc_section (sec, dynobj, - 2, abfd, 1); - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf32_mb_link_hash_entry *) h)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - - asection *s; - Elf_Internal_Sym *isym; - void *vpp; - - isym = bfd_sym_from_r_symndx (&htab->sym_sec, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - return FALSE; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = ((struct elf_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_MICROBLAZE_64_PCREL) - p->pc_count += 1; - } - } - break; - } - } - - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -microblaze_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf32_mb_link_hash_entry *edir, *eind; - - edir = (struct elf32_mb_link_hash_entry *) dir; - eind = (struct elf32_mb_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - if (ind->root.type == bfd_link_hash_indirect) - abort (); - - /* Add reloc counts against the weak sym to the strong sym - list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) - { - struct elf_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; - } - - edir->tls_mask |= eind->tls_mask; - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = elf32_mb_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -static bfd_boolean -microblaze_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf32_mb_link_hash_table *htab; - asection *s, *srel; - unsigned int power_of_two; - - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - /* 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 PLT 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_MICROBLAZE_64_PCREL 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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 we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (!readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - /* We must generate a R_MICROBLAZE_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_READONLY) != 0) - { - s = htab->elf.sdynrelro; - srel = htab->elf.sreldynrelro; - } - else - { - s = htab->elf.sdynbss; - srel = htab->elf.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 3) - power_of_two = 3; - - /* Apply the required alignment. */ - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > s->alignment_power) - { - if (!bfd_set_section_alignment (s->owner, 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 * dat) -{ - struct bfd_link_info *info; - struct elf32_mb_link_hash_table *htab; - struct elf32_mb_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) dat; - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - 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 (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->elf.splt; - - /* The first entry in .plt is reserved. */ - 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 (! bfd_link_pic (info) - && !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->elf.sgotplt->size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - htab->elf.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - eh = (struct elf32_mb_link_hash_entry *) h; - if (h->got.refcount > 0) - { - unsigned int need; - asection *s; - - /* 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; - } - - need = 0; - if ((eh->tls_mask & TLS_TLS) != 0) - { - /* Handle TLS Symbol */ - if ((eh->tls_mask & TLS_LD) != 0) - { - if (!eh->elf.def_dynamic) - /* We'll just use htab->tlsld_got.offset. This should - always be the case. It's a little odd if we have - a local dynamic reloc against a non-local symbol. */ - htab->tlsld_got.refcount += 1; - else - need += 8; - } - if ((eh->tls_mask & TLS_GD) != 0) - need += 8; - } - else - { - /* Regular (non-TLS) symbol */ - need += 4; - } - if (need == 0) - { - h->got.offset = (bfd_vma) -1; - } - else - { - s = htab->elf.sgot; - h->got.offset = s->size; - s->size += need; - htab->elf.srelgot->size += need * (sizeof (Elf32_External_Rela) / 4); - } - } - 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 (bfd_link_pic (info)) - { - if (h->def_regular - && (h->forced_local - || info->symbolic)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->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_Rela); - } - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf32_mb_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd *ibfd; - - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->elf.dynobj; - BFD_ASSERT (dynobj != NULL); - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - unsigned char *lgot_masks; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - p != NULL; - p = p->next) - { - if (!bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - lgot_masks = (unsigned char *) end_local_got; - s = htab->elf.sgot; - srel = htab->elf.srelgot; - - for (; local_got < end_local_got; ++local_got, ++lgot_masks) - { - if (*local_got > 0) - { - unsigned int need = 0; - if ((*lgot_masks & TLS_TLS) != 0) - { - if ((*lgot_masks & TLS_GD) != 0) - need += 8; - if ((*lgot_masks & TLS_LD) != 0) - htab->tlsld_got.refcount += 1; - } - else - need += 4; - - if (need == 0) - { - *local_got = (bfd_vma) -1; - } - else - { - *local_got = s->size; - s->size += need; - if (bfd_link_pic (info)) - srel->size += need * (sizeof (Elf32_External_Rela) / 4); - } - } - else - *local_got = (bfd_vma) -1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); - - if (htab->tlsld_got.refcount > 0) - { - htab->tlsld_got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += 8; - if (bfd_link_pic (info)) - htab->elf.srelgot->size += sizeof (Elf32_External_Rela); - } - else - htab->tlsld_got.offset = (bfd_vma) -1; - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Make space for the trailing nop in .plt. */ - if (htab->elf.splt->size > 0) - htab->elf.splt->size += 4; - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - bfd_boolean strip = FALSE; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strncmp (name, ".rela", 5) == 0) - { - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is to handle .rela.bss and - .rela.plt. We must create it in - create_dynamic_sections, because it 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. */ - strip = TRUE; - } - else - { - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - } - else if (s != htab->elf.splt - && s != htab->elf.sgot - && s != htab->elf.sgotplt - && s != htab->elf.sdynbss - && s != htab->elf.sdynrelro) - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (strip) - { - s->flags |= SEC_EXCLUDE; - continue; - } - - /* Allocate memory for the section contents. */ - /* FIXME: This should be a call to bfd_alloc not bfd_zalloc. - Unused entries should be reclaimed before the section's contents - are written out, but at the moment this does not happen. Thus in - order to prevent writing out garbage, we initialise the section's - contents to zero. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL && s->size != 0) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in microblaze_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - - if (htab->elf.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0) - || !add_dynamic_entry (DT_BIND_NOW, 1)) - return FALSE; - } - - if (info->flags & DF_TEXTREL) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } -#undef add_dynamic_entry - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -microblaze_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf32_mb_link_hash_table *htab; - struct elf32_mb_link_hash_entry *eh = elf32_mb_hash_entry(h); - - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *srela; - asection *sgotplt; - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_vma plt_index; - bfd_vma got_offset; - bfd_vma got_addr; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - BFD_ASSERT (h->dynindx != -1); - - splt = htab->elf.splt; - srela = htab->elf.srelplt; - sgotplt = htab->elf.sgotplt; - BFD_ASSERT (splt != NULL && srela != NULL && sgotplt != NULL); - - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; /* first entry reserved. */ - got_offset = (plt_index + 3) * 4; /* 3 reserved ??? */ - got_addr = got_offset; - - /* For non-PIC objects we need absolute address of the GOT entry. */ - if (!bfd_link_pic (info)) - got_addr += sgotplt->output_section->vma + sgotplt->output_offset; - - /* Fill in the entry in the procedure linkage table. */ - bfd_put_32 (output_bfd, PLT_ENTRY_WORD_0 + ((got_addr >> 16) & 0xffff), - splt->contents + h->plt.offset); - if (bfd_link_pic (info)) - bfd_put_32 (output_bfd, PLT_ENTRY_WORD_1 + (got_addr & 0xffff), - splt->contents + h->plt.offset + 4); - else - bfd_put_32 (output_bfd, PLT_ENTRY_WORD_1_NOPIC + (got_addr & 0xffff), - splt->contents + h->plt.offset + 4); - bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD_2, - splt->contents + h->plt.offset + 8); - bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD_3, - splt->contents + h->plt.offset + 12); - - /* Any additions to the .got section??? */ - /* bfd_put_32 (output_bfd, - splt->output_section->vma + splt->output_offset + h->plt.offset + 4, - sgotplt->contents + got_offset); */ - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_JUMP_SLOT); - rela.r_addend = 0; - loc = srela->contents; - loc += plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Zero the value. */ - sym->st_shndx = SHN_UNDEF; - sym->st_value = 0; - } - } - - /* h->got.refcount to be checked ? */ - if (h->got.offset != (bfd_vma) -1 && - ! ((h->got.offset & 1) || - IS_TLS_LD(eh->tls_mask) || IS_TLS_GD(eh->tls_mask))) - { - asection *sgot; - asection *srela; - bfd_vma offset; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - sgot = htab->elf.sgot; - srela = htab->elf.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - offset = (sgot->output_section->vma + sgot->output_offset - + (h->got.offset &~ (bfd_vma) 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && ((info->symbolic && h->def_regular) - || h->dynindx == -1)) - { - asection *sec = h->root.u.def.section; - bfd_vma value; - - value = h->root.u.def.value; - if (sec->output_section != NULL) - /* PR 21180: If the output section is NULL, then the symbol is no - longer needed, and in theory the GOT entry is redundant. But - it is too late to change our minds now... */ - value += sec->output_section->vma + sec->output_offset; - - microblaze_elf_output_dynamic_relocation (output_bfd, - srela, srela->reloc_count++, - /* symindex= */ 0, - R_MICROBLAZE_REL, offset, - value); - } - else - { - microblaze_elf_output_dynamic_relocation (output_bfd, - srela, srela->reloc_count++, - h->dynindx, - R_MICROBLAZE_GLOB_DAT, - offset, 0); - } - - bfd_put_32 (output_bfd, (bfd_vma) 0, - sgot->contents + (h->got.offset &~ (bfd_vma) 1)); - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbols needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark some specially defined symbols as absolute. */ - if (h == htab->elf.hdynamic - || h == htab->elf.hgot - || h == htab->elf.hplt) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - - -/* Finish up the dynamic sections. */ - -static bfd_boolean -microblaze_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn, *sgot; - struct elf32_mb_link_hash_table *htab; - - htab = elf32_mb_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->elf.dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->elf.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - 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_boolean size; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_PLTGOT: - s = htab->elf.sgotplt; - size = FALSE; - break; - - case DT_PLTRELSZ: - s = htab->elf.srelplt; - size = TRUE; - break; - - case DT_JMPREL: - s = htab->elf.srelplt; - size = FALSE; - break; - - default: - continue; - } - - if (s == NULL) - dyn.d_un.d_val = 0; - else - { - if (!size) - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - else - dyn.d_un.d_val = s->size; - } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - splt = htab->elf.splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - /* Clear the first entry in the procedure linkage table, - and put a nop in the last four bytes. */ - if (splt->size > 0) - { - memset (splt->contents, 0, PLT_ENTRY_SIZE); - bfd_put_32 (output_bfd, (bfd_vma) 0x80000000 /* nop. */, - splt->contents + splt->size - 4); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; - } - - /* Set the first entry in the global offset table to the address of - the dynamic section. */ - sgot = htab->elf.sgotplt; - if (sgot && sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - if (htab->elf.sgot && htab->elf.sgot->size > 0) - elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it to put .comm items in .sbss, and not .bss. */ - -static bfd_boolean -microblaze_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && sym->st_size <= elf_gp_size (abfd)) - { - /* Common symbols less than or equal to -G nn bytes are automatically - put into .sbss. */ - *secp = bfd_make_section_old_way (abfd, ".sbss"); - if (*secp == NULL - || ! bfd_set_section_flags (abfd, *secp, SEC_IS_COMMON)) - return FALSE; - - *valp = sym->st_size; - } - - return TRUE; -} - -#define TARGET_LITTLE_SYM microblaze_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-microblazeel" - -#define TARGET_BIG_SYM microblaze_elf32_vec -#define TARGET_BIG_NAME "elf32-microblaze" - -#define ELF_ARCH bfd_arch_microblaze -#define ELF_TARGET_ID MICROBLAZE_ELF_DATA -#define ELF_MACHINE_CODE EM_MICROBLAZE -#define ELF_MACHINE_ALT1 EM_MICROBLAZE_OLD -#define ELF_MAXPAGESIZE 0x1000 -#define elf_info_to_howto microblaze_elf_info_to_howto -#define elf_info_to_howto_rel NULL - -#define bfd_elf32_bfd_reloc_type_lookup microblaze_elf_reloc_type_lookup -#define bfd_elf32_bfd_is_local_label_name microblaze_elf_is_local_label_name -#define elf_backend_relocate_section microblaze_elf_relocate_section -#define bfd_elf32_bfd_relax_section microblaze_elf_relax_section -#define bfd_elf32_bfd_merge_private_bfd_data _bfd_generic_verify_endian_match -#define bfd_elf32_bfd_reloc_name_lookup microblaze_elf_reloc_name_lookup - -#define elf_backend_gc_mark_hook microblaze_elf_gc_mark_hook -#define elf_backend_check_relocs microblaze_elf_check_relocs -#define elf_backend_copy_indirect_symbol microblaze_elf_copy_indirect_symbol -#define bfd_elf32_bfd_link_hash_table_create microblaze_elf_link_hash_table_create -#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_got_header_size 12 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_adjust_dynamic_symbol microblaze_elf_adjust_dynamic_symbol -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections microblaze_elf_finish_dynamic_sections -#define elf_backend_finish_dynamic_symbol microblaze_elf_finish_dynamic_symbol -#define elf_backend_size_dynamic_sections microblaze_elf_size_dynamic_sections -#define elf_backend_add_symbol_hook microblaze_elf_add_symbol_hook - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-mips.c b/sdcc/support/sdbinutils/bfd/elf32-mips.c deleted file mode 100644 index fa0cc15ab..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-mips.c +++ /dev/null @@ -1,2695 +0,0 @@ -/* MIPS-specific support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - Most of the information added by Ian Lance Taylor, Cygnus Support, - . - N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC. - - Traditional MIPS targets support added by Koundinya.K, Dansk Data - Elektronik & Operations Research Group. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* This file handles MIPS ELF targets. SGI Irix 5 uses a slightly - different MIPS ELF from other targets. This matters when linking. - This file supports both, switching at runtime. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "genlink.h" -#include "elf-bfd.h" -#include "elfxx-mips.h" -#include "elf/mips.h" -#include "elf-vxworks.h" - -/* Get the ECOFF swapping routines. */ -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/internal.h" -#include "coff/ecoff.h" -#include "coff/mips.h" -#define ECOFF_SIGNED_32 -#include "ecoffswap.h" - -static bfd_reloc_status_type gprel32_with_gp - (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma); -static bfd_reloc_status_type mips_elf_gprel32_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips32_64bit_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static reloc_howto_type *mips_elf32_rtype_to_howto - (unsigned int, bfd_boolean); -static void mips_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); -static void mips_info_to_howto_rela - (bfd *, arelent *, Elf_Internal_Rela *); -static bfd_boolean mips_elf_sym_is_global - (bfd *, asymbol *); -static bfd_boolean mips_elf32_object_p - (bfd *); -static bfd_boolean mips_elf_is_local_label_name - (bfd *, const char *); -static bfd_reloc_status_type mips16_gprel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips_elf_final_gp - (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *); -static bfd_boolean mips_elf_assign_gp - (bfd *, bfd_vma *); -static bfd_boolean elf32_mips_grok_prstatus - (bfd *, Elf_Internal_Note *); -static bfd_boolean elf32_mips_grok_psinfo - (bfd *, Elf_Internal_Note *); -static irix_compat_t elf32_mips_irix_compat - (bfd *); - -extern const bfd_target mips_elf32_be_vec; -extern const bfd_target mips_elf32_le_vec; - -/* Nonzero if ABFD is using the N32 ABI. */ -#define ABI_N32_P(abfd) \ - ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0) - -/* Whether we are trying to be compatible with IRIX at all. */ -#define SGI_COMPAT(abfd) \ - (elf32_mips_irix_compat (abfd) != ict_none) - -/* The number of local .got entries we reserve. */ -#define MIPS_RESERVED_GOTNO (2) - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -/* The relocation table used for SHT_REL sections. */ - -static reloc_howto_type elf_mips_howto_table_rel[] = -{ - /* No relocation. */ - HOWTO (R_MIPS_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit relocation. */ - HOWTO (R_MIPS_16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation. */ - HOWTO (R_MIPS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_MIPS_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 26 bit jump address. */ - HOWTO (R_MIPS_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC + 4. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_26", /* name */ - TRUE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MIPS_GPREL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MIPS_LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative reference. Note that the ABI document has a typo - and claims R_MIPS_PC16 to be not rightshifted, rendering it useless. - We do the right thing here. */ - HOWTO (R_MIPS_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_MIPS_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips_elf_gprel32_reloc, /* special_function */ - "R_MIPS_GPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The remaining relocs are defined on Irix 5, although they are - not defined by the ABI. */ - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - - /* A 5 bit shift field. */ - HOWTO (R_MIPS_SHIFT5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SHIFT5", /* name */ - TRUE, /* partial_inplace */ - 0x000007c0, /* src_mask */ - 0x000007c0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 6 bit shift field. */ - /* FIXME: This is not handled correctly; a special function is - needed to put the most significant bit in the right place. */ - HOWTO (R_MIPS_SHIFT6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SHIFT6", /* name */ - TRUE, /* partial_inplace */ - 0x000007c4, /* src_mask */ - 0x000007c4, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 64 bit relocation. */ - HOWTO (R_MIPS_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips32_64bit_reloc, /* special_function */ - "R_MIPS_64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement in the global offset table. */ - HOWTO (R_MIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_DISP", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_PAGE", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_OFST", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. Used in the N32 ABI. */ - HOWTO (R_MIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SUB", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used to cause the linker to insert and delete instructions? */ - EMPTY_HOWTO (R_MIPS_INSERT_A), - EMPTY_HOWTO (R_MIPS_INSERT_B), - EMPTY_HOWTO (R_MIPS_DELETE), - - /* Get the higher value of a 64 bit addend. */ - HOWTO (R_MIPS_HIGHER, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HIGHER", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the highest value of a 64 bit addend. */ - HOWTO (R_MIPS_HIGHEST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HIGHEST", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SCN_DISP", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_REL16), - EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE), - EMPTY_HOWTO (R_MIPS_PJUMP), - EMPTY_HOWTO (R_MIPS_RELGOT), - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS GD/LD dynamic relocations. */ - HOWTO (R_MIPS_TLS_DTPMOD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPMOD32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_TLS_DTPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), - EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), - - /* TLS general dynamic variable reference. */ - HOWTO (R_MIPS_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_MIPS_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS IE dynamic relocations. */ - HOWTO (R_MIPS_TLS_TPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_TLS_TPREL64), - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation with no addend. */ - HOWTO (R_MIPS_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - - HOWTO (R_MIPS_PC21_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC21_S2", /* name */ - TRUE, /* partial_inplace */ - 0x001fffff, /* src_mask */ - 0x001fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC26_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC26_S2", /* name */ - TRUE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC18_S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC18_S3", /* name */ - TRUE, /* partial_inplace */ - 0x0003ffff, /* src_mask */ - 0x0003ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC19_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC19_S2", /* name */ - TRUE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCHI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCHI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCLO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCLO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link. This - is a hack to make the linker think that we need 64 bit values. */ -static reloc_howto_type elf_mips_ctor64_howto = - HOWTO (R_MIPS_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips32_64bit_reloc, /* special_function */ - "R_MIPS_64", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -static reloc_howto_type elf_mips16_howto_table_rel[] = -{ - /* The reloc used for the mips16 jump instruction. */ - HOWTO (R_MIPS16_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_26", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The reloc used for the mips16 gprel instruction. */ - HOWTO (R_MIPS16_GPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips16_gprel_reloc, /* special_function */ - "R_MIPS16_GPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 reference to the global offset table. */ - HOWTO (R_MIPS16_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS16_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 call through the global offset table. */ - HOWTO (R_MIPS16_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 high 16 bits of symbol value. */ - HOWTO (R_MIPS16_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS16_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 low 16 bits of symbol value. */ - HOWTO (R_MIPS16_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS16_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS general dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 16-bit PC-relative branch offset. */ - HOWTO (R_MIPS16_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_PC16_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -static reloc_howto_type elf_micromips_howto_table_rel[] = -{ - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - - /* 26 bit jump address. */ - HOWTO (R_MICROMIPS_26_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_26_S1", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MICROMIPS_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MICROMIPS_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MICROMIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_GPREL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MICROMIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MICROMIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MICROMIPS_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is for microMIPS branches. */ - HOWTO (R_MICROMIPS_PC7_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC7_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000007f, /* src_mask */ - 0x0000007f, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC10_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC10_S1", /* name */ - TRUE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC16_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MICROMIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - - /* Displacement in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_DISP",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_PAGE",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_OFST",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_HI16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. Used in the N32 ABI. */ - HOWTO (R_MICROMIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SUB", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the higher value of a 64 bit addend. */ - HOWTO (R_MICROMIPS_HIGHER, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HIGHER", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the highest value of a 64 bit addend. */ - HOWTO (R_MICROMIPS_HIGHEST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HIGHEST", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_HI16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MICROMIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SCN_DISP",/* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MICROMIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. Note that the high 16 bits of symbol values - must be zero. This is used for relaxation. */ - HOWTO (R_MICROMIPS_HI0_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HI0_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (158), - EMPTY_HOWTO (159), - EMPTY_HOWTO (160), - EMPTY_HOWTO (161), - - /* TLS general dynamic variable reference. */ - HOWTO (R_MICROMIPS_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_MICROMIPS_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MICROMIPS_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MICROMIPS_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MICROMIPS_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (167), - EMPTY_HOWTO (168), - - /* TLS thread pointer offset. */ - HOWTO (R_MICROMIPS_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MICROMIPS_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (171), - - /* GP- and PC-relative relocations. */ - HOWTO (R_MICROMIPS_GPREL7_S2, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_GPREL7_S2", /* name */ - TRUE, /* partial_inplace */ - 0x0000007f, /* src_mask */ - 0x0000007f, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC23_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 23, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC23_S2", /* name */ - TRUE, /* partial_inplace */ - 0x007fffff, /* src_mask */ - 0x007fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* 16 bit offset for pc-relative branches. */ -static reloc_howto_type elf_mips_gnu_rel16_s2 = - HOWTO (R_MIPS_GNU_REL16_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GNU_REL16_S2", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - -/* 32 bit pc-relative. This was a GNU extension used by embedded-PIC. - It was co-opted by mips-linux for exception-handling data. GCC stopped - using it in May, 2004, then started using it again for compact unwind - tables. */ -static reloc_howto_type elf_mips_gnu_pcrel32 = - HOWTO (R_MIPS_PC32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - -/* GNU extension to record C++ vtable hierarchy */ -static reloc_howto_type elf_mips_gnu_vtinherit_howto = - HOWTO (R_MIPS_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_MIPS_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* GNU extension to record C++ vtable member usage */ -static reloc_howto_type elf_mips_gnu_vtentry_howto = - HOWTO (R_MIPS_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_MIPS_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Originally a VxWorks extension, but now used for other systems too. */ -static reloc_howto_type elf_mips_copy_howto = - HOWTO (R_MIPS_COPY, /* type */ - 0, /* rightshift */ - 0, /* this one is variable size */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_COPY", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Originally a VxWorks extension, but now used for other systems too. */ -static reloc_howto_type elf_mips_jump_slot_howto = - HOWTO (R_MIPS_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JUMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Used in EH tables. */ -static reloc_howto_type elf_mips_eh_howto = - HOWTO (R_MIPS_EH, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_EH", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ - -static bfd_boolean -mips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) -{ - unsigned int count; - asymbol **sym; - unsigned int i; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - /* The linker script will have created a symbol named `_gp' with the - appropriate value. */ - if (sym == NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - register const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - *pgp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, *pgp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - return TRUE; -} - -/* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static bfd_reloc_status_type -mips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, - char **error_message, bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) - && ! relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 - && (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma /*+ 0x4000*/; - _bfd_set_gp_value (output_bfd, *pgp); - } - else if (!mips_elf_assign_gp (output_bfd, pgp)) - { - *error_message = - (char *) _("GP relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must - become the offset from the gp register. This function also handles - R_MIPS_LITERAL relocations, although those can be handled more - cleverly because the entries in the .lit8 and .lit4 sections can be - merged. */ - -bfd_reloc_status_type -_bfd_mips_elf32_gprel16_reloc (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, - asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_byte *location; - bfd_vma gp; - - /* R_MIPS_LITERAL/R_MICROMIPS_LITERAL relocations are defined for local - symbols only. */ - if (literal_reloc_p (reloc_entry->howto->type) - && output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("literal relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - location = (bfd_byte *) data + reloc_entry->address; - _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE, - location); - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); - _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, !relocatable, - location); - - return ret; -} - -/* Do a R_MIPS_GPREL32 relocation. This is a 32 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -mips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* R_MIPS_GPREL32 relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("32bits gp relative relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, - error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - - return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, - relocatable, data, gp); -} - -static bfd_reloc_status_type -gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, - asection *input_section, bfd_boolean relocatable, - void *data, bfd_vma gp) -{ - bfd_vma relocation; - bfd_vma val; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Set val to the offset into the section or symbol. */ - val = reloc_entry->addend; - - if (reloc_entry->howto->partial_inplace) - val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - - /* Adjust val for the final section location and GP value. If we - are producing relocatable output, we don't want to do this for - an external symbol. */ - if (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0) - val += relocation - gp; - - if (reloc_entry->howto->partial_inplace) - bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); - else - reloc_entry->addend = val; - - if (relocatable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -/* Handle a 64 bit reloc in a 32 bit MIPS ELF file. These are - generated when addresses are 64 bits. The upper 32 bits are a simple - sign extension. */ - -static bfd_reloc_status_type -mips32_64bit_reloc (bfd *abfd, arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - bfd_reloc_status_type r; - arelent reloc32; - unsigned long val; - bfd_size_type addr; - - /* Do a normal 32 bit relocation on the lower 32 bits. */ - reloc32 = *reloc_entry; - if (bfd_big_endian (abfd)) - reloc32.address += 4; - reloc32.howto = &elf_mips_howto_table_rel[R_MIPS_32]; - r = bfd_perform_relocation (abfd, &reloc32, data, input_section, - output_bfd, error_message); - - /* Sign extend into the upper 32 bits. */ - val = bfd_get_32 (abfd, (bfd_byte *) data + reloc32.address); - if ((val & 0x80000000) != 0) - val = 0xffffffff; - else - val = 0; - addr = reloc_entry->address; - if (bfd_little_endian (abfd)) - addr += 4; - bfd_put_32 (abfd, val, (bfd_byte *) data + addr); - - return r; -} - -/* Handle a mips16 GP relative reloc. */ - -static bfd_reloc_status_type -mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_byte *location; - bfd_vma gp; - - /* If we're relocating, and this is an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - location = (bfd_byte *) data + reloc_entry->address; - _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE, - location); - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); - _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, !relocatable, - location); - - return ret; -} - -/* A mapping from BFD reloc types to MIPS ELF reloc types. */ - -struct elf_reloc_map { - bfd_reloc_code_real_type bfd_val; - enum elf_mips_reloc_type elf_val; -}; - -static const struct elf_reloc_map mips_reloc_map[] = -{ - { BFD_RELOC_NONE, R_MIPS_NONE }, - { BFD_RELOC_16, R_MIPS_16 }, - { BFD_RELOC_32, R_MIPS_32 }, - /* There is no BFD reloc for R_MIPS_REL32. */ - { BFD_RELOC_64, R_MIPS_64 }, - { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, - { BFD_RELOC_HI16_S, R_MIPS_HI16 }, - { BFD_RELOC_LO16, R_MIPS_LO16 }, - { BFD_RELOC_GPREL16, R_MIPS_GPREL16 }, - { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, - { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, - { BFD_RELOC_16_PCREL_S2, R_MIPS_PC16 }, - { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, - { BFD_RELOC_GPREL32, R_MIPS_GPREL32 }, - { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 }, - { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 }, - { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 }, - { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 }, - { BFD_RELOC_MIPS_SUB, R_MIPS_SUB }, - { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE }, - { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST }, - { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP }, - { BFD_RELOC_MIPS_JALR, R_MIPS_JALR }, - { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 }, - { BFD_RELOC_MIPS_TLS_DTPREL32, R_MIPS_TLS_DTPREL32 }, - { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 }, - { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 }, - { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD }, - { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM }, - { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 }, - { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL }, - { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, - { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, - { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }, - { BFD_RELOC_MIPS_21_PCREL_S2, R_MIPS_PC21_S2 }, - { BFD_RELOC_MIPS_26_PCREL_S2, R_MIPS_PC26_S2 }, - { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 }, - { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 }, - { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 }, - { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 } -}; - -static const struct elf_reloc_map mips16_reloc_map[] = -{ - { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min }, - { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_GD, R_MIPS16_TLS_GD - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_LDM, R_MIPS16_TLS_LDM - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_DTPREL_HI16, - R_MIPS16_TLS_DTPREL_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_DTPREL_LO16, - R_MIPS16_TLS_DTPREL_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_GOTTPREL, R_MIPS16_TLS_GOTTPREL - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_TPREL_HI16, R_MIPS16_TLS_TPREL_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_TPREL_LO16, R_MIPS16_TLS_TPREL_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_16_PCREL_S1, R_MIPS16_PC16_S1 - R_MIPS16_min } -}; - -static const struct elf_reloc_map micromips_reloc_map[] = -{ - { BFD_RELOC_MICROMIPS_JMP, R_MICROMIPS_26_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HI16_S, R_MICROMIPS_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_LO16, R_MICROMIPS_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GPREL16, R_MICROMIPS_GPREL16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_LITERAL, R_MICROMIPS_LITERAL - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT16, R_MICROMIPS_GOT16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_7_PCREL_S1, R_MICROMIPS_PC7_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_10_PCREL_S1, R_MICROMIPS_PC10_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_16_PCREL_S1, R_MICROMIPS_PC16_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL16, R_MICROMIPS_CALL16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_DISP, R_MICROMIPS_GOT_DISP - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_PAGE - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_OFST, R_MICROMIPS_GOT_OFST - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_LO16, R_MICROMIPS_GOT_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_SUB, R_MICROMIPS_SUB - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HIGHER, R_MICROMIPS_HIGHER - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HIGHEST, R_MICROMIPS_HIGHEST - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL_HI16, R_MICROMIPS_CALL_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL_LO16, R_MICROMIPS_CALL_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_SCN_DISP, R_MICROMIPS_SCN_DISP - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_JALR, R_MICROMIPS_JALR - R_MICROMIPS_min }, - /* There is no BFD reloc for R_MICROMIPS_HI0_LO16. */ - { BFD_RELOC_MICROMIPS_TLS_GD, R_MICROMIPS_TLS_GD - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_TLS_LDM, R_MICROMIPS_TLS_LDM - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_TLS_DTPREL_HI16, - R_MICROMIPS_TLS_DTPREL_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_TLS_DTPREL_LO16, - R_MICROMIPS_TLS_DTPREL_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_TLS_GOTTPREL, - R_MICROMIPS_TLS_GOTTPREL - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_TLS_TPREL_HI16, - R_MICROMIPS_TLS_TPREL_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_TLS_TPREL_LO16, - R_MICROMIPS_TLS_TPREL_LO16 - R_MICROMIPS_min }, - /* There is no BFD reloc for R_MICROMIPS_GPREL7_S2. */ - /* There is no BFD reloc for R_MICROMIPS_PC23_S2. */ -}; - -/* Given a BFD reloc type, return a howto structure. */ - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) -{ - unsigned int i; - reloc_howto_type *howto_table = elf_mips_howto_table_rel; - reloc_howto_type *howto16_table = elf_mips16_howto_table_rel; - reloc_howto_type *howto_micromips_table = elf_micromips_howto_table_rel; - - for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (mips_reloc_map[i].bfd_val == code) - return &howto_table[(int) mips_reloc_map[i].elf_val]; - } - - for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (mips16_reloc_map[i].bfd_val == code) - return &howto16_table[(int) mips16_reloc_map[i].elf_val]; - } - - for (i = 0; i < sizeof (micromips_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (micromips_reloc_map[i].bfd_val == code) - return &howto_micromips_table[(int) micromips_reloc_map[i].elf_val]; - } - - switch (code) - { - default: - bfd_set_error (bfd_error_bad_value); - return NULL; - - case BFD_RELOC_CTOR: - /* We need to handle BFD_RELOC_CTOR specially. - Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the - size of addresses of the ABI. */ - if ((elf_elfheader (abfd)->e_flags & (E_MIPS_ABI_O64 - | E_MIPS_ABI_EABI64)) != 0) - return &elf_mips_ctor64_howto; - else - return &howto_table[(int) R_MIPS_32]; - - case BFD_RELOC_VTABLE_INHERIT: - return &elf_mips_gnu_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &elf_mips_gnu_vtentry_howto; - case BFD_RELOC_32_PCREL: - return &elf_mips_gnu_pcrel32; - case BFD_RELOC_MIPS_COPY: - return &elf_mips_copy_howto; - case BFD_RELOC_MIPS_JUMP_SLOT: - return &elf_mips_jump_slot_howto; - case BFD_RELOC_MIPS_EH: - return &elf_mips_eh_howto; - } -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf_mips_howto_table_rel) - / sizeof (elf_mips_howto_table_rel[0])); - i++) - if (elf_mips_howto_table_rel[i].name != NULL - && strcasecmp (elf_mips_howto_table_rel[i].name, r_name) == 0) - return &elf_mips_howto_table_rel[i]; - - for (i = 0; - i < (sizeof (elf_mips16_howto_table_rel) - / sizeof (elf_mips16_howto_table_rel[0])); - i++) - if (elf_mips16_howto_table_rel[i].name != NULL - && strcasecmp (elf_mips16_howto_table_rel[i].name, r_name) == 0) - return &elf_mips16_howto_table_rel[i]; - - for (i = 0; - i < (sizeof (elf_micromips_howto_table_rel) - / sizeof (elf_micromips_howto_table_rel[0])); - i++) - if (elf_micromips_howto_table_rel[i].name != NULL - && strcasecmp (elf_micromips_howto_table_rel[i].name, r_name) == 0) - return &elf_micromips_howto_table_rel[i]; - - if (strcasecmp (elf_mips_gnu_pcrel32.name, r_name) == 0) - return &elf_mips_gnu_pcrel32; - if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0) - return &elf_mips_gnu_rel16_s2; - if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0) - return &elf_mips_gnu_vtinherit_howto; - if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0) - return &elf_mips_gnu_vtentry_howto; - if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0) - return &elf_mips_copy_howto; - if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0) - return &elf_mips_jump_slot_howto; - if (strcasecmp (elf_mips_eh_howto.name, r_name) == 0) - return &elf_mips_eh_howto; - - return NULL; -} - -/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure. */ - -static reloc_howto_type * -mips_elf32_rtype_to_howto (unsigned int r_type, - bfd_boolean rela_p ATTRIBUTE_UNUSED) -{ - switch (r_type) - { - case R_MIPS_GNU_VTINHERIT: - return &elf_mips_gnu_vtinherit_howto; - case R_MIPS_GNU_VTENTRY: - return &elf_mips_gnu_vtentry_howto; - case R_MIPS_GNU_REL16_S2: - return &elf_mips_gnu_rel16_s2; - case R_MIPS_PC32: - return &elf_mips_gnu_pcrel32; - case R_MIPS_COPY: - return &elf_mips_copy_howto; - case R_MIPS_JUMP_SLOT: - return &elf_mips_jump_slot_howto; - case R_MIPS_EH: - return &elf_mips_eh_howto; - default: - if (r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max) - return &elf_micromips_howto_table_rel[r_type - R_MICROMIPS_min]; - if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max) - return &elf_mips16_howto_table_rel[r_type - R_MIPS16_min]; - if (r_type >= (unsigned int) R_MIPS_max) - { - _bfd_error_handler (_("Unrecognised MIPS reloc number: %d"), r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_MIPS_NONE; - } - return &elf_mips_howto_table_rel[r_type]; - } -} - -/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure. */ - -static void -mips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - const struct elf_backend_data *bed; - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - bed = get_elf_backend_data (abfd); - cache_ptr->howto = bed->elf_backend_mips_rtype_to_howto (r_type, FALSE); - - /* The addend for a GPREL16 or LITERAL relocation comes from the GP - value for the object file. We get the addend now, rather than - when we do the relocation, because the symbol manipulations done - by the linker may cause us to lose track of the input BFD. */ - if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0 - && (gprel16_reloc_p (r_type) || literal_reloc_p (r_type))) - cache_ptr->addend = elf_gp (abfd); -} - -/* Given a MIPS Elf_Internal_Rela, fill in an arelent structure. */ - -static void -mips_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - mips_info_to_howto_rel (abfd, cache_ptr, dst); - - /* If we ever need to do any extra processing with dst->r_addend - (the field omitted in an Elf_Internal_Rel) we can do it here. */ -} - -/* Determine whether a symbol is global for the purposes of splitting - the symbol table into global symbols and local symbols. At least - on Irix 5, this split must be between section symbols and all other - symbols. On most ELF targets the split is between static symbols - and externally visible symbols. */ - -static bfd_boolean -mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) -{ - if (SGI_COMPAT (abfd)) - return (sym->flags & BSF_SECTION_SYM) == 0; - else - return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 - || bfd_is_und_section (bfd_get_section (sym)) - || bfd_is_com_section (bfd_get_section (sym))); -} - -/* Set the right machine number for a MIPS ELF file. */ - -static bfd_boolean -mips_elf32_object_p (bfd *abfd) -{ - unsigned long mach; - - if (ABI_N32_P (abfd)) - return FALSE; - - /* Irix 5 and 6 are broken. Object file symbol tables are not always - sorted correctly such that local symbols precede global symbols, - and the sh_info field in the symbol table is not always right. */ - if (SGI_COMPAT (abfd)) - elf_bad_symtab (abfd) = TRUE; - - mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags); - bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach); - return TRUE; -} - -/* MIPS ELF local labels start with '$', not 'L'. */ - -static bfd_boolean -mips_elf_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == '$') - return TRUE; - - /* On Irix 6, the labels go back to starting with '.', so we accept - the generic ELF local label syntax as well. */ - return _bfd_elf_is_local_label_name (abfd, name); -} - -/* Support for core dump NOTE sections. */ -static bfd_boolean -elf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 256: /* Linux/MIPS */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 180; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 128: /* Linux/MIPS elf_prpsinfo */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 16); - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 48, 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; -} - -/* Write Linux core PRSTATUS note into core file. */ - -static char * -elf32_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, - ...) -{ - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - BFD_FAIL (); - return NULL; - - case NT_PRSTATUS: - { - char data[256]; - va_list ap; - long pid; - int cursig; - const void *greg; - - va_start (ap, note_type); - memset (data, 0, 72); - pid = va_arg (ap, long); - bfd_put_32 (abfd, pid, data + 24); - cursig = va_arg (ap, int); - bfd_put_16 (abfd, cursig, data + 12); - greg = va_arg (ap, const void *); - memcpy (data + 72, greg, 180); - memset (data + 252, 0, 4); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - } -} - -/* Depending on the target vector we generate some version of Irix - executables or "normal" MIPS ELF ABI executables. */ -static irix_compat_t -elf32_mips_irix_compat (bfd *abfd) -{ - if ((abfd->xvec == &mips_elf32_be_vec) - || (abfd->xvec == &mips_elf32_le_vec)) - return ict_irix5; - else - return ict_none; -} - -/* ECOFF swapping routines. These are used when dealing with the - .mdebug section, which is in the ECOFF debugging format. */ -static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { - /* Symbol table magic number. */ - magicSym, - /* Alignment of debugging information. E.g., 4. */ - 4, - /* Sizes of external symbolic information. */ - sizeof (struct hdr_ext), - sizeof (struct dnr_ext), - sizeof (struct pdr_ext), - sizeof (struct sym_ext), - sizeof (struct opt_ext), - sizeof (struct fdr_ext), - sizeof (struct rfd_ext), - sizeof (struct ext_ext), - /* Functions to swap in external symbolic data. */ - ecoff_swap_hdr_in, - ecoff_swap_dnr_in, - ecoff_swap_pdr_in, - ecoff_swap_sym_in, - ecoff_swap_opt_in, - ecoff_swap_fdr_in, - ecoff_swap_rfd_in, - ecoff_swap_ext_in, - _bfd_ecoff_swap_tir_in, - _bfd_ecoff_swap_rndx_in, - /* Functions to swap out external symbolic data. */ - ecoff_swap_hdr_out, - ecoff_swap_dnr_out, - ecoff_swap_pdr_out, - ecoff_swap_sym_out, - ecoff_swap_opt_out, - ecoff_swap_fdr_out, - ecoff_swap_rfd_out, - ecoff_swap_ext_out, - _bfd_ecoff_swap_tir_out, - _bfd_ecoff_swap_rndx_out, - /* Function to read in symbolic data. */ - _bfd_mips_elf_read_ecoff_info -}; - -#define ELF_ARCH bfd_arch_mips -#define ELF_TARGET_ID MIPS_ELF_DATA -#define ELF_MACHINE_CODE EM_MIPS - -#define elf_backend_collect TRUE -#define elf_backend_type_change_ok TRUE -#define elf_backend_can_gc_sections TRUE -#define elf_backend_gc_mark_extra_sections \ - _bfd_mips_elf_gc_mark_extra_sections -#define elf_info_to_howto mips_info_to_howto_rela -#define elf_info_to_howto_rel mips_info_to_howto_rel -#define elf_backend_sym_is_global mips_elf_sym_is_global -#define elf_backend_object_p mips_elf32_object_p -#define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing -#define elf_backend_section_processing _bfd_mips_elf_section_processing -#define elf_backend_section_from_shdr _bfd_mips_elf_section_from_shdr -#define elf_backend_fake_sections _bfd_mips_elf_fake_sections -#define elf_backend_section_from_bfd_section \ - _bfd_mips_elf_section_from_bfd_section -#define elf_backend_add_symbol_hook _bfd_mips_elf_add_symbol_hook -#define elf_backend_link_output_symbol_hook \ - _bfd_mips_elf_link_output_symbol_hook -#define elf_backend_create_dynamic_sections \ - _bfd_mips_elf_create_dynamic_sections -#define elf_backend_check_relocs _bfd_mips_elf_check_relocs -#define elf_backend_merge_symbol_attribute \ - _bfd_mips_elf_merge_symbol_attribute -#define elf_backend_get_target_dtag _bfd_mips_elf_get_target_dtag -#define elf_backend_adjust_dynamic_symbol \ - _bfd_mips_elf_adjust_dynamic_symbol -#define elf_backend_always_size_sections \ - _bfd_mips_elf_always_size_sections -#define elf_backend_size_dynamic_sections \ - _bfd_mips_elf_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_relocate_section _bfd_mips_elf_relocate_section -#define elf_backend_finish_dynamic_symbol \ - _bfd_mips_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_mips_elf_finish_dynamic_sections -#define elf_backend_final_write_processing \ - _bfd_mips_elf_final_write_processing -#define elf_backend_additional_program_headers \ - _bfd_mips_elf_additional_program_headers -#define elf_backend_modify_segment_map _bfd_mips_elf_modify_segment_map -#define elf_backend_gc_mark_hook _bfd_mips_elf_gc_mark_hook -#define elf_backend_copy_indirect_symbol \ - _bfd_mips_elf_copy_indirect_symbol -#define elf_backend_grok_prstatus elf32_mips_grok_prstatus -#define elf_backend_grok_psinfo elf32_mips_grok_psinfo -#define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap - -#define elf_backend_got_header_size (4 * MIPS_RESERVED_GOTNO) -#define elf_backend_want_dynrelro 1 -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 0 -#define elf_backend_default_use_rela_p 0 -#define elf_backend_sign_extend_vma TRUE -#define elf_backend_plt_readonly 1 - -#define elf_backend_discard_info _bfd_mips_elf_discard_info -#define elf_backend_ignore_discarded_relocs \ - _bfd_mips_elf_ignore_discarded_relocs -#define elf_backend_write_section _bfd_mips_elf_write_section -#define elf_backend_mips_irix_compat elf32_mips_irix_compat -#define elf_backend_mips_rtype_to_howto mips_elf32_rtype_to_howto -#define elf_backend_sort_relocs_p _bfd_mips_elf_sort_relocs_p - -#define bfd_elf32_bfd_is_local_label_name \ - mips_elf_is_local_label_name -#define bfd_elf32_bfd_is_target_special_symbol \ - _bfd_mips_elf_is_target_special_symbol -#define bfd_elf32_get_synthetic_symtab _bfd_mips_elf_get_synthetic_symtab -#define bfd_elf32_find_nearest_line _bfd_mips_elf_find_nearest_line -#define bfd_elf32_find_inliner_info _bfd_mips_elf_find_inliner_info -#define bfd_elf32_new_section_hook _bfd_mips_elf_new_section_hook -#define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents -#define bfd_elf32_bfd_get_relocated_section_contents \ - _bfd_elf_mips_get_relocated_section_contents -#define bfd_elf32_bfd_link_hash_table_create \ - _bfd_mips_elf_link_hash_table_create -#define bfd_elf32_bfd_final_link _bfd_mips_elf_final_link -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_mips_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - _bfd_mips_elf_print_private_bfd_data -#define bfd_elf32_bfd_relax_section _bfd_mips_elf_relax_section -#define bfd_elf32_mkobject _bfd_mips_elf_mkobject - -/* Support for SGI-ish mips targets. */ -#define TARGET_LITTLE_SYM mips_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlemips" -#define TARGET_BIG_SYM mips_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bigmips" - -/* The SVR4 MIPS ABI says that this should be 0x10000, but Irix 5 uses - a value of 0x1000, and we are compatible. */ -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 - -#include "elf32-target.h" - -/* Support for traditional mips targets. */ -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#undef ELF_MAXPAGESIZE -#undef ELF_COMMONPAGESIZE - -#define TARGET_LITTLE_SYM mips_elf32_trad_le_vec -#define TARGET_LITTLE_NAME "elf32-tradlittlemips" -#define TARGET_BIG_SYM mips_elf32_trad_be_vec -#define TARGET_BIG_NAME "elf32-tradbigmips" - -/* The MIPS ABI says at Page 5-1: - Virtual addresses and file offsets for MIPS segments are congruent - modulo 64 KByte (0x10000) or larger powers of 2. Because 64 KBytes - is the maximum page size, the files are suitable for paging - regardless of physical page size. */ -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x1000 -#define elf32_bed elf32_tradbed - -#undef elf_backend_write_core_note -#define elf_backend_write_core_note elf32_mips_write_core_note - -/* Include the target file again for this target. */ -#include "elf32-target.h" - -/* FreeBSD support. */ - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#define TARGET_LITTLE_SYM mips_elf32_tradfbsd_le_vec -#define TARGET_LITTLE_NAME "elf32-tradlittlemips-freebsd" -#define TARGET_BIG_SYM mips_elf32_tradfbsd_be_vec -#define TARGET_BIG_NAME "elf32-tradbigmips-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf32_bed -#define elf32_bed elf32_fbsd_tradbed - -#undef elf_backend_write_core_note - -#include "elf32-target.h" -/* Implement elf_backend_final_write_processing for VxWorks. */ - -static void -mips_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) -{ - _bfd_mips_elf_final_write_processing (abfd, linker); - elf_vxworks_final_write_processing (abfd, linker); -} - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#undef ELF_MAXPAGESIZE -#undef ELF_COMMONPAGESIZE - -#define TARGET_LITTLE_SYM mips_elf32_vxworks_le_vec -#define TARGET_LITTLE_NAME "elf32-littlemips-vxworks" -#define TARGET_BIG_SYM mips_elf32_vxworks_be_vec -#define TARGET_BIG_NAME "elf32-bigmips-vxworks" -#undef ELF_OSABI - -#undef elf32_bed -#define elf32_bed elf32_mips_vxworks_bed - -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 - -#undef elf_backend_want_got_plt -#define elf_backend_want_got_plt 1 -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 1 -#undef elf_backend_may_use_rel_p -#define elf_backend_may_use_rel_p 0 -#undef elf_backend_may_use_rela_p -#define elf_backend_may_use_rela_p 1 -#undef elf_backend_default_use_rela_p -#define elf_backend_default_use_rela_p 1 -#undef elf_backend_got_header_size -#define elf_backend_got_header_size (4 * 3) -#undef elf_backend_dtrel_excludes_plt -#define elf_backend_dtrel_excludes_plt 1 - -#undef elf_backend_finish_dynamic_symbol -#define elf_backend_finish_dynamic_symbol \ - _bfd_mips_vxworks_finish_dynamic_symbol -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create \ - _bfd_mips_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 \ - mips_vxworks_final_write_processing - -#undef elf_backend_additional_program_headers -#undef elf_backend_modify_segment_map -#undef elf_backend_symbol_processing -/* NOTE: elf_backend_rela_normal is not defined for MIPS. */ - -#undef bfd_elf32_get_synthetic_symtab - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-moxie.c b/sdcc/support/sdbinutils/bfd/elf32-moxie.c deleted file mode 100644 index 8c7a378f4..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-moxie.c +++ /dev/null @@ -1,387 +0,0 @@ -/* moxie-specific support for 32-bit ELF. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - - Copied from elf32-fr30.c which is.. - Copyright (C) 1998-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/moxie.h" - -/* Forward declarations. */ - -static reloc_howto_type moxie_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_MOXIE_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MOXIE_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_MOXIE_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MOXIE_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 10 bit PC-relative relocation. */ - HOWTO (R_MOXIE_PCREL10, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 10, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_MOXIE_PCREL10", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0x000003FF, /* dst_mask. */ - TRUE), /* pcrel_offset. */ -}; - -/* Map BFD reloc types to MOXIE ELF reloc types. */ - -struct moxie_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int moxie_reloc_val; -}; - -static const struct moxie_reloc_map moxie_reloc_map [] = -{ - { BFD_RELOC_NONE, R_MOXIE_NONE }, - { BFD_RELOC_32, R_MOXIE_32 }, - { BFD_RELOC_MOXIE_10_PCREL, R_MOXIE_PCREL10 }, -}; - -static reloc_howto_type * -moxie_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = sizeof (moxie_reloc_map) / sizeof (moxie_reloc_map[0]); - i--;) - if (moxie_reloc_map [i].bfd_reloc_val == code) - return & moxie_elf_howto_table [moxie_reloc_map[i].moxie_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -moxie_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (moxie_elf_howto_table) / sizeof (moxie_elf_howto_table[0]); - i++) - if (moxie_elf_howto_table[i].name != NULL - && strcasecmp (moxie_elf_howto_table[i].name, r_name) == 0) - return &moxie_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an MOXIE ELF reloc. */ - -static void -moxie_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_MOXIE_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid Moxie reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & moxie_elf_howto_table [r_type]; -} - -/* Perform a single relocation. By default we use the standard BFD - routines, but a few relocs, we have to do them ourselves. */ - -static bfd_reloc_status_type -moxie_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - bfd_vma relocation) -{ - bfd_reloc_status_type r = bfd_reloc_ok; - - switch (howto->type) - { - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - return r; -} - -/* Relocate an MOXIE ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -moxie_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - howto = moxie_elf_howto_table + r_type; - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = moxie_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -moxie_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -moxie_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - } - - return TRUE; -} - -#define ELF_ARCH bfd_arch_moxie -#define ELF_MACHINE_CODE EM_MOXIE -#define ELF_MACHINE_ALT1 EM_MOXIE_OLD -#define ELF_MAXPAGESIZE 0x1 - -#define TARGET_BIG_SYM moxie_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bigmoxie" -#define TARGET_LITTLE_SYM moxie_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlemoxie" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto moxie_info_to_howto_rela -#define elf_backend_relocate_section moxie_elf_relocate_section -#define elf_backend_gc_mark_hook moxie_elf_gc_mark_hook -#define elf_backend_check_relocs moxie_elf_check_relocs - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_reloc_type_lookup moxie_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup moxie_reloc_name_lookup - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-msp430.c b/sdcc/support/sdbinutils/bfd/elf32-msp430.c deleted file mode 100644 index 5ee32c488..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-msp430.c +++ /dev/null @@ -1,2638 +0,0 @@ -/* MSP430-specific support for 32-bit ELF - Copyright (C) 2002-2018 Free Software Foundation, Inc. - Contributed by Dmitry Diky - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "libiberty.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/msp430.h" - -static bfd_reloc_status_type -rl78_sym_diff_handler (bfd * abfd, - arelent * reloc, - asymbol * sym ATTRIBUTE_UNUSED, - void * addr ATTRIBUTE_UNUSED, - asection * input_sec, - bfd * out_bfd ATTRIBUTE_UNUSED, - char ** error_message ATTRIBUTE_UNUSED) -{ - bfd_size_type octets; - octets = reloc->address * bfd_octets_per_byte (abfd); - - /* Catch the case where bfd_install_relocation would return - bfd_reloc_outofrange because the SYM_DIFF reloc is being used in a very - small section. It does not actually matter if this happens because all - that SYM_DIFF does is compute a (4-byte) value. A second reloc then uses - this value, and it is that reloc that must fit into the section. - - This happens in eg, gcc/testsuite/gcc.c-torture/compile/labels-3.c. */ - if ((octets + bfd_get_reloc_size (reloc->howto)) - > bfd_get_section_limit_octets (abfd, input_sec)) - return bfd_reloc_ok; - return bfd_reloc_continue; -} - -static reloc_howto_type elf_msp430_howto_table[] = -{ - HOWTO (R_MSP430_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MSP430_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 10 bit PC relative relocation. */ - HOWTO (R_MSP430_10_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_10_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x3ff, /* src_mask */ - 0x3ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_MSP430_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit PC relative relocation for command address. */ - HOWTO (R_MSP430_16_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation, byte operations. */ - HOWTO (R_MSP430_16_BYTE, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_16_BYTE", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation for command address. */ - HOWTO (R_MSP430_16_PCREL_BYTE,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_16_PCREL_BYTE",/* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 10 bit PC relative relocation for complicated polymorphs. */ - HOWTO (R_MSP430_2X_PCREL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_2X_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x3ff, /* src_mask */ - 0x3ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit relaxable relocation for command address. */ - HOWTO (R_MSP430_RL_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_RL_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE) /* pcrel_offset */ - - /* A 8-bit absolute relocation. */ - , HOWTO (R_MSP430_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Together with a following reloc, allows for the difference - between two symbols to be the real addend of the second reloc. */ - HOWTO (R_MSP430_SYM_DIFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - rl78_sym_diff_handler, /* special handler. */ - "R_MSP430_SYM_DIFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -static reloc_howto_type elf_msp430x_howto_table[] = -{ - HOWTO (R_MSP430_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MSP430_ABS32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_ABS32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MSP430_ABS16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MSP430_ABS8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_ABS8", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MSP430_PCR16, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_PCR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_PCR20_EXT_SRC,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_PCR20_EXT_SRC",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_PCR20_EXT_DST,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_PCR20_EXT_DST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_PCR20_EXT_ODST,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_PCR20_EXT_ODST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_ABS20_EXT_SRC,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_ABS20_EXT_SRC",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_ABS20_EXT_DST,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_ABS20_EXT_DST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_ABS20_EXT_ODST,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_ABS20_EXT_ODST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_ABS20_ADR_SRC,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_ABS20_ADR_SRC",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_ABS20_ADR_DST,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_ABS20_ADR_DST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_PCR16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_PCR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_PCR20_CALL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_PCR20_CALL",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430X_ABS16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430_ABS_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_ABS_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MSP430_PREL31, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_PREL31", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MSP430_EHTYPE), - - /* A 10 bit PC relative relocation. */ - HOWTO (R_MSP430X_10_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_10_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x3ff, /* src_mask */ - 0x3ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 10 bit PC relative relocation for complicated polymorphs. */ - HOWTO (R_MSP430X_2X_PCREL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MSP430X_2X_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x3ff, /* src_mask */ - 0x3ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Together with a following reloc, allows for the difference - between two symbols to be the real addend of the second reloc. */ - HOWTO (R_MSP430X_SYM_DIFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - rl78_sym_diff_handler, /* special handler. */ - "R_MSP430X_SYM_DIFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -/* Map BFD reloc types to MSP430 ELF reloc types. */ - -struct msp430_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int elf_reloc_val; -}; - -static const struct msp430_reloc_map msp430_reloc_map[] = -{ - {BFD_RELOC_NONE, R_MSP430_NONE}, - {BFD_RELOC_32, R_MSP430_32}, - {BFD_RELOC_MSP430_10_PCREL, R_MSP430_10_PCREL}, - {BFD_RELOC_16, R_MSP430_16_BYTE}, - {BFD_RELOC_MSP430_16_PCREL, R_MSP430_16_PCREL}, - {BFD_RELOC_MSP430_16, R_MSP430_16}, - {BFD_RELOC_MSP430_16_PCREL_BYTE, R_MSP430_16_PCREL_BYTE}, - {BFD_RELOC_MSP430_16_BYTE, R_MSP430_16_BYTE}, - {BFD_RELOC_MSP430_2X_PCREL, R_MSP430_2X_PCREL}, - {BFD_RELOC_MSP430_RL_PCREL, R_MSP430_RL_PCREL}, - {BFD_RELOC_8, R_MSP430_8}, - {BFD_RELOC_MSP430_SYM_DIFF, R_MSP430_SYM_DIFF} -}; - -static const struct msp430_reloc_map msp430x_reloc_map[] = -{ - {BFD_RELOC_NONE, R_MSP430_NONE}, - {BFD_RELOC_32, R_MSP430_ABS32}, - {BFD_RELOC_16, R_MSP430_ABS16}, - {BFD_RELOC_8, R_MSP430_ABS8}, - {BFD_RELOC_MSP430_ABS8, R_MSP430_ABS8}, - {BFD_RELOC_MSP430X_PCR20_EXT_SRC, R_MSP430X_PCR20_EXT_SRC}, - {BFD_RELOC_MSP430X_PCR20_EXT_DST, R_MSP430X_PCR20_EXT_DST}, - {BFD_RELOC_MSP430X_PCR20_EXT_ODST, R_MSP430X_PCR20_EXT_ODST}, - {BFD_RELOC_MSP430X_ABS20_EXT_SRC, R_MSP430X_ABS20_EXT_SRC}, - {BFD_RELOC_MSP430X_ABS20_EXT_DST, R_MSP430X_ABS20_EXT_DST}, - {BFD_RELOC_MSP430X_ABS20_EXT_ODST, R_MSP430X_ABS20_EXT_ODST}, - {BFD_RELOC_MSP430X_ABS20_ADR_SRC, R_MSP430X_ABS20_ADR_SRC}, - {BFD_RELOC_MSP430X_ABS20_ADR_DST, R_MSP430X_ABS20_ADR_DST}, - {BFD_RELOC_MSP430X_PCR16, R_MSP430X_PCR16}, - {BFD_RELOC_MSP430X_PCR20_CALL, R_MSP430X_PCR20_CALL}, - {BFD_RELOC_MSP430X_ABS16, R_MSP430X_ABS16}, - {BFD_RELOC_MSP430_ABS_HI16, R_MSP430_ABS_HI16}, - {BFD_RELOC_MSP430_PREL31, R_MSP430_PREL31}, - {BFD_RELOC_MSP430_10_PCREL, R_MSP430X_10_PCREL}, - {BFD_RELOC_MSP430_2X_PCREL, R_MSP430X_2X_PCREL}, - {BFD_RELOC_MSP430_RL_PCREL, R_MSP430X_PCR16}, - {BFD_RELOC_MSP430_SYM_DIFF, R_MSP430X_SYM_DIFF} -}; - -static inline bfd_boolean -uses_msp430x_relocs (bfd * abfd) -{ - extern const bfd_target msp430_elf32_ti_vec; - - return bfd_get_mach (abfd) == bfd_mach_msp430x - || abfd->xvec == & msp430_elf32_ti_vec; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - if (uses_msp430x_relocs (abfd)) - { - for (i = ARRAY_SIZE (msp430x_reloc_map); i--;) - if (msp430x_reloc_map[i].bfd_reloc_val == code) - return elf_msp430x_howto_table + msp430x_reloc_map[i].elf_reloc_val; - } - else - { - for (i = 0; i < ARRAY_SIZE (msp430_reloc_map); i++) - if (msp430_reloc_map[i].bfd_reloc_val == code) - return &elf_msp430_howto_table[msp430_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - if (uses_msp430x_relocs (abfd)) - { - for (i = ARRAY_SIZE (elf_msp430x_howto_table); i--;) - if (elf_msp430x_howto_table[i].name != NULL - && strcasecmp (elf_msp430x_howto_table[i].name, r_name) == 0) - return elf_msp430x_howto_table + i; - } - else - { - for (i = 0; - i < (sizeof (elf_msp430_howto_table) - / sizeof (elf_msp430_howto_table[0])); - i++) - if (elf_msp430_howto_table[i].name != NULL - && strcasecmp (elf_msp430_howto_table[i].name, r_name) == 0) - return &elf_msp430_howto_table[i]; - } - - return NULL; -} - -/* Set the howto pointer for an MSP430 ELF reloc. */ - -static void -msp430_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - - if (uses_msp430x_relocs (abfd)) - { - if (r_type >= (unsigned int) R_MSP430x_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid MSP430X reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = elf_msp430x_howto_table + r_type; - return; - } - - if (r_type >= (unsigned int) R_MSP430_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid MSP430 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_msp430_howto_table[r_type]; -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -elf32_msp430_check_relocs (bfd * abfd, struct bfd_link_info * info, - asection * sec, const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - } - - return TRUE; -} - -/* Perform a single relocation. By default we use the standard BFD - routines, but a few relocs, we have to do them ourselves. */ - -static bfd_reloc_status_type -msp430_final_link_relocate (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation, - struct bfd_link_info * info) -{ - static asection * sym_diff_section; - static bfd_vma sym_diff_value; - - struct bfd_elf_section_data * esd = elf_section_data (input_section); - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma x; - bfd_signed_vma srel; - bfd_boolean is_rel_reloc = FALSE; - - if (uses_msp430x_relocs (input_bfd)) - { - /* See if we have a REL type relocation. */ - is_rel_reloc = (esd->rel.hdr != NULL); - /* Sanity check - only one type of relocation per section. - FIXME: Theoretically it is possible to have both types, - but if that happens how can we distinguish between the two ? */ - BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr); - /* If we are using a REL relocation then the addend should be empty. */ - BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0); - } - - if (sym_diff_section != NULL) - { - BFD_ASSERT (sym_diff_section == input_section); - - if (uses_msp430x_relocs (input_bfd)) - switch (howto->type) - { - case R_MSP430_ABS32: - /* If we are computing a 32-bit value for the location lists - and the result is 0 then we add one to the value. A zero - value can result because of linker relaxation deleteing - prologue instructions and using a value of 1 (for the begin - and end offsets in the location list entry) results in a - nul entry which does not prevent the following entries from - being parsed. */ - if (relocation == sym_diff_value - && strcmp (input_section->name, ".debug_loc") == 0) - ++ relocation; - /* Fall through. */ - case R_MSP430_ABS16: - case R_MSP430X_ABS16: - case R_MSP430_ABS8: - BFD_ASSERT (! is_rel_reloc); - relocation -= sym_diff_value; - break; - - default: - return bfd_reloc_dangerous; - } - else - switch (howto->type) - { - case R_MSP430_32: - case R_MSP430_16: - case R_MSP430_16_BYTE: - case R_MSP430_8: - relocation -= sym_diff_value; - break; - - default: - return bfd_reloc_dangerous; - } - - sym_diff_section = NULL; - } - - if (uses_msp430x_relocs (input_bfd)) - switch (howto->type) - { - case R_MSP430X_SYM_DIFF: - /* Cache the input section and value. - The offset is unreliable, since relaxation may - have reduced the following reloc's offset. */ - BFD_ASSERT (! is_rel_reloc); - sym_diff_section = input_section; - sym_diff_value = relocation; - return bfd_reloc_ok; - - case R_MSP430_ABS16: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += bfd_get_16 (input_bfd, contents); - else - srel += rel->r_addend; - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430X_10_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += bfd_get_16 (input_bfd, contents) & 0x3ff; - else - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - if (srel & 1) - return bfd_reloc_outofrange; - - /* MSP430 addresses commands as words. */ - srel >>= 1; - - /* Check for an overflow. */ - if (srel < -512 || srel > 511) - { - if (info->disable_target_specific_optimizations < 0) - { - static bfd_boolean warned = FALSE; - if (! warned) - { - info->callbacks->warning - (info, - _("Try enabling relaxation to avoid relocation truncations"), - NULL, input_bfd, input_section, relocation); - warned = TRUE; - } - } - return bfd_reloc_overflow; - } - - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfc00) | (srel & 0x3ff); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_PCR20_EXT_ODST: - /* [0,4]+[48,16] = ---F ---- ---- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16; - addend |= bfd_get_16 (input_bfd, contents + 6); - srel += addend; - - } - else - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= (input_section->output_section->vma + - input_section->output_offset); - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 6); - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfff0) | ((srel >> 16) & 0xf); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_ABS20_EXT_SRC: - /* [7,4]+[32,16] = -78- ---- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = (bfd_get_16 (input_bfd, contents) & 0x0780) << 9; - addend |= bfd_get_16 (input_bfd, contents + 4); - srel += addend; - } - else - srel += rel->r_addend; - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf87f) | ((srel << 7) & 0x0780); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430_16_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += bfd_get_16 (input_bfd, contents); - else - srel += rel->r_addend; - srel -= rel->r_offset; - /* Only branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - if (srel & 1) - return bfd_reloc_outofrange; - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430X_PCR20_EXT_DST: - /* [0,4]+[32,16] = ---F ---- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16; - addend |= bfd_get_16 (input_bfd, contents + 4); - srel += addend; - } - else - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= (input_section->output_section->vma + - input_section->output_offset); - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfff0) | (srel & 0xf); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_PCR20_EXT_SRC: - /* [7,4]+[32,16] = -78- ---- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = ((bfd_get_16 (input_bfd, contents) & 0x0780) << 9); - addend |= bfd_get_16 (input_bfd, contents + 4); - srel += addend;; - } - else - srel += rel->r_addend; - srel -= rel->r_offset; - /* Only branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf87f) | ((srel << 7) & 0x0780); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430_ABS8: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += bfd_get_8 (input_bfd, contents); - else - srel += rel->r_addend; - bfd_put_8 (input_bfd, srel & 0xff, contents); - break; - - case R_MSP430X_ABS20_EXT_DST: - /* [0,4]+[32,16] = ---F ---- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16; - addend |= bfd_get_16 (input_bfd, contents + 4); - srel += addend; - } - else - srel += rel->r_addend; - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfff0) | (srel & 0xf); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_ABS20_EXT_ODST: - /* [0,4]+[48,16] = ---F ---- ---- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16; - addend |= bfd_get_16 (input_bfd, contents + 6); - srel += addend; - } - else - srel += rel->r_addend; - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 6); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfff0) | (srel & 0xf); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_ABS20_ADR_SRC: - /* [8,4]+[16,16] = -F-- FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - - addend = ((bfd_get_16 (input_bfd, contents) & 0xf00) << 8); - addend |= bfd_get_16 (input_bfd, contents + 2); - srel += addend; - } - else - srel += rel->r_addend; - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 2); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xf0ff) | ((srel << 8) & 0x0f00); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_ABS20_ADR_DST: - /* [0,4]+[16,16] = ---F FFFF */ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = ((bfd_get_16 (input_bfd, contents) & 0xf) << 16); - addend |= bfd_get_16 (input_bfd, contents + 2); - srel += addend; - } - else - srel += rel->r_addend; - bfd_put_16 (input_bfd, (srel & 0xffff), contents + 2); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfff0) | (srel & 0xf); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_ABS16: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += bfd_get_16 (input_bfd, contents); - else - srel += rel->r_addend; - x = srel; - if (x > 0xffff) - return bfd_reloc_overflow; - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430_ABS_HI16: - /* The EABI specifies that this must be a RELA reloc. */ - BFD_ASSERT (! is_rel_reloc); - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - bfd_put_16 (input_bfd, (srel >> 16) & 0xffff, contents); - break; - - case R_MSP430X_PCR20_CALL: - /* [0,4]+[16,16] = ---F FFFF*/ - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - { - bfd_vma addend; - addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16; - addend |= bfd_get_16 (input_bfd, contents + 2); - srel += addend; - } - else - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= (input_section->output_section->vma + - input_section->output_offset); - bfd_put_16 (input_bfd, srel & 0xffff, contents + 2); - srel >>= 16; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfff0) | (srel & 0xf); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430X_PCR16: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += bfd_get_16 (input_bfd, contents); - else - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= (input_section->output_section->vma + - input_section->output_offset); - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430_PREL31: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - if (is_rel_reloc) - srel += (bfd_get_32 (input_bfd, contents) & 0x7fffffff); - else - srel += rel->r_addend; - srel += rel->r_addend; - x = bfd_get_32 (input_bfd, contents); - x = (x & 0x80000000) | ((srel >> 31) & 0x7fffffff); - bfd_put_32 (input_bfd, x, contents); - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - else - switch (howto->type) - { - case R_MSP430_10_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - - /* MSP430 addresses commands as words. */ - srel >>= 1; - - /* Check for an overflow. */ - if (srel < -512 || srel > 511) - { - if (info->disable_target_specific_optimizations < 0) - { - static bfd_boolean warned = FALSE; - if (! warned) - { - info->callbacks->warning - (info, - _("Try enabling relaxation to avoid relocation truncations"), - NULL, input_bfd, input_section, relocation); - warned = TRUE; - } - } - return bfd_reloc_overflow; - } - - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfc00) | (srel & 0x3ff); - bfd_put_16 (input_bfd, x, contents); - break; - - case R_MSP430_2X_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - - /* MSP430 addresses commands as words. */ - srel >>= 1; - - /* Check for an overflow. */ - if (srel < -512 || srel > 511) - return bfd_reloc_overflow; - - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfc00) | (srel & 0x3ff); - bfd_put_16 (input_bfd, x, contents); - /* Handle second jump instruction. */ - x = bfd_get_16 (input_bfd, contents - 2); - srel += 1; - x = (x & 0xfc00) | (srel & 0x3ff); - bfd_put_16 (input_bfd, x, contents - 2); - break; - - case R_MSP430_RL_PCREL: - case R_MSP430_16_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - /* Only branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430_16_PCREL_BYTE: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - /* Only branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430_16_BYTE: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430_16: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - - if (srel & 1) - return bfd_reloc_notsupported; - - bfd_put_16 (input_bfd, srel & 0xffff, contents); - break; - - case R_MSP430_8: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - - bfd_put_8 (input_bfd, srel & 0xff, contents); - break; - - case R_MSP430_SYM_DIFF: - /* Cache the input section and value. - The offset is unreliable, since relaxation may - have reduced the following reloc's offset. */ - sym_diff_section = input_section; - sym_diff_value = relocation; - return bfd_reloc_ok; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - return r; -} - -/* Relocate an MSP430 ELF section. */ - -static bfd_boolean -elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - if (uses_msp430x_relocs (input_bfd)) - howto = elf_msp430x_howto_table + r_type; - else - howto = elf_msp430_howto_table + r_type; - - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL || * name == 0) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = msp430_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation, info); - - if (r != bfd_reloc_ok) - { - const char *msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: branch/jump to an odd address detected"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - - } - - return TRUE; -} - -/* The final processing done just before writing out a MSP430 ELF object - file. This gets the MSP430 architecture right based on the machine - number. */ - -static void -bfd_elf_msp430_final_write_processing (bfd * abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_msp110: val = E_MSP430_MACH_MSP430x11x1; break; - case bfd_mach_msp11: val = E_MSP430_MACH_MSP430x11; break; - case bfd_mach_msp12: val = E_MSP430_MACH_MSP430x12; break; - case bfd_mach_msp13: val = E_MSP430_MACH_MSP430x13; break; - case bfd_mach_msp14: val = E_MSP430_MACH_MSP430x14; break; - case bfd_mach_msp15: val = E_MSP430_MACH_MSP430x15; break; - case bfd_mach_msp16: val = E_MSP430_MACH_MSP430x16; break; - case bfd_mach_msp31: val = E_MSP430_MACH_MSP430x31; break; - case bfd_mach_msp32: val = E_MSP430_MACH_MSP430x32; break; - case bfd_mach_msp33: val = E_MSP430_MACH_MSP430x33; break; - case bfd_mach_msp41: val = E_MSP430_MACH_MSP430x41; break; - case bfd_mach_msp42: val = E_MSP430_MACH_MSP430x42; break; - case bfd_mach_msp43: val = E_MSP430_MACH_MSP430x43; break; - case bfd_mach_msp44: val = E_MSP430_MACH_MSP430x44; break; - case bfd_mach_msp20: val = E_MSP430_MACH_MSP430x20; break; - case bfd_mach_msp22: val = E_MSP430_MACH_MSP430x22; break; - case bfd_mach_msp23: val = E_MSP430_MACH_MSP430x23; break; - case bfd_mach_msp24: val = E_MSP430_MACH_MSP430x24; break; - case bfd_mach_msp26: val = E_MSP430_MACH_MSP430x26; break; - case bfd_mach_msp46: val = E_MSP430_MACH_MSP430x46; break; - case bfd_mach_msp47: val = E_MSP430_MACH_MSP430x47; break; - case bfd_mach_msp54: val = E_MSP430_MACH_MSP430x54; break; - case bfd_mach_msp430x: val = E_MSP430_MACH_MSP430X; break; - } - - elf_elfheader (abfd)->e_machine = EM_MSP430; - elf_elfheader (abfd)->e_flags &= ~EF_MSP430_MACH; - elf_elfheader (abfd)->e_flags |= val; -} - -/* Set the right machine number. */ - -static bfd_boolean -elf32_msp430_object_p (bfd * abfd) -{ - int e_set = bfd_mach_msp14; - - if (elf_elfheader (abfd)->e_machine == EM_MSP430 - || elf_elfheader (abfd)->e_machine == EM_MSP430_OLD) - { - int e_mach = elf_elfheader (abfd)->e_flags & EF_MSP430_MACH; - - switch (e_mach) - { - default: - case E_MSP430_MACH_MSP430x11: e_set = bfd_mach_msp11; break; - case E_MSP430_MACH_MSP430x11x1: e_set = bfd_mach_msp110; break; - case E_MSP430_MACH_MSP430x12: e_set = bfd_mach_msp12; break; - case E_MSP430_MACH_MSP430x13: e_set = bfd_mach_msp13; break; - case E_MSP430_MACH_MSP430x14: e_set = bfd_mach_msp14; break; - case E_MSP430_MACH_MSP430x15: e_set = bfd_mach_msp15; break; - case E_MSP430_MACH_MSP430x16: e_set = bfd_mach_msp16; break; - case E_MSP430_MACH_MSP430x31: e_set = bfd_mach_msp31; break; - case E_MSP430_MACH_MSP430x32: e_set = bfd_mach_msp32; break; - case E_MSP430_MACH_MSP430x33: e_set = bfd_mach_msp33; break; - case E_MSP430_MACH_MSP430x41: e_set = bfd_mach_msp41; break; - case E_MSP430_MACH_MSP430x42: e_set = bfd_mach_msp42; break; - case E_MSP430_MACH_MSP430x43: e_set = bfd_mach_msp43; break; - case E_MSP430_MACH_MSP430x44: e_set = bfd_mach_msp44; break; - case E_MSP430_MACH_MSP430x20: e_set = bfd_mach_msp20; break; - case E_MSP430_MACH_MSP430x22: e_set = bfd_mach_msp22; break; - case E_MSP430_MACH_MSP430x23: e_set = bfd_mach_msp23; break; - case E_MSP430_MACH_MSP430x24: e_set = bfd_mach_msp24; break; - case E_MSP430_MACH_MSP430x26: e_set = bfd_mach_msp26; break; - case E_MSP430_MACH_MSP430x46: e_set = bfd_mach_msp46; break; - case E_MSP430_MACH_MSP430x47: e_set = bfd_mach_msp47; break; - case E_MSP430_MACH_MSP430x54: e_set = bfd_mach_msp54; break; - case E_MSP430_MACH_MSP430X: e_set = bfd_mach_msp430x; break; - } - } - - return bfd_default_set_arch_mach (abfd, bfd_arch_msp430, e_set); -} - -/* These functions handle relaxing for the msp430. - Relaxation required only in two cases: - - Bad hand coding like jumps from one section to another or - from file to file. - - Sibling calls. This will affect only 'jump label' polymorph. Without - relaxing this enlarges code by 2 bytes. Sibcalls implemented but - do not work in gcc's port by the reason I do not know. - - To convert out of range conditional jump instructions (found inside - a function) into inverted jumps over an unconditional branch instruction. - Anyway, if a relaxation required, user should pass -relax option to the - linker. - - There are quite a few relaxing opportunities available on the msp430: - - ================================================================ - - 1. 3 words -> 1 word - - eq == jeq label jne +4; br lab - ne != jne label jeq +4; br lab - lt < jl label jge +4; br lab - ltu < jlo label lhs +4; br lab - ge >= jge label jl +4; br lab - geu >= jhs label jlo +4; br lab - - 2. 4 words -> 1 word - - ltn < jn jn +2; jmp +4; br lab - - 3. 4 words -> 2 words - - gt > jeq +2; jge label jeq +6; jl +4; br label - gtu > jeq +2; jhs label jeq +6; jlo +4; br label - - 4. 4 words -> 2 words and 2 labels - - leu <= jeq label; jlo label jeq +2; jhs +4; br label - le <= jeq label; jl label jeq +2; jge +4; br label - ================================================================= - - codemap for first cases is (labels masked ): - eq: 0x2002,0x4010,0x0000 -> 0x2400 - ne: 0x2402,0x4010,0x0000 -> 0x2000 - lt: 0x3402,0x4010,0x0000 -> 0x3800 - ltu: 0x2c02,0x4010,0x0000 -> 0x2800 - ge: 0x3802,0x4010,0x0000 -> 0x3400 - geu: 0x2802,0x4010,0x0000 -> 0x2c00 - - second case: - ltn: 0x3001,0x3c02,0x4010,0x0000 -> 0x3000 - - third case: - gt: 0x2403,0x3802,0x4010,0x0000 -> 0x2401,0x3400 - gtu: 0x2403,0x2802,0x4010,0x0000 -> 0x2401,0x2c00 - - fourth case: - leu: 0x2401,0x2c02,0x4010,0x0000 -> 0x2400,0x2800 - le: 0x2401,0x3402,0x4010,0x0000 -> 0x2400,0x3800 - - Unspecified case :) - jump: 0x4010,0x0000 -> 0x3c00. */ - -#define NUMB_RELAX_CODES 12 -static struct rcodes_s -{ - int f0, f1; /* From code. */ - int t0, t1; /* To code. */ - int labels; /* Position of labels: 1 - one label at first - word, 2 - one at second word, 3 - two - labels at both. */ - int cdx; /* Words to match. */ - int bs; /* Shrink bytes. */ - int off; /* Offset from old label for new code. */ - int ncl; /* New code length. */ -} rcode[] = -{/* lab,cdx,bs,off,ncl */ - { 0x0000, 0x0000, 0x3c00, 0x0000, 1, 0, 2, 2, 2}, /* jump */ - { 0x0000, 0x2002, 0x2400, 0x0000, 1, 1, 4, 4, 2}, /* eq */ - { 0x0000, 0x2402, 0x2000, 0x0000, 1, 1, 4, 4, 2}, /* ne */ - { 0x0000, 0x3402, 0x3800, 0x0000, 1, 1, 4, 4, 2}, /* lt */ - { 0x0000, 0x2c02, 0x2800, 0x0000, 1, 1, 4, 4, 2}, /* ltu */ - { 0x0000, 0x3802, 0x3400, 0x0000, 1, 1, 4, 4, 2}, /* ge */ - { 0x0000, 0x2802, 0x2c00, 0x0000, 1, 1, 4, 4, 2}, /* geu */ - { 0x3001, 0x3c02, 0x3000, 0x0000, 1, 2, 6, 6, 2}, /* ltn */ - { 0x2403, 0x3802, 0x2401, 0x3400, 2, 2, 4, 6, 4}, /* gt */ - { 0x2403, 0x2802, 0x2401, 0x2c00, 2, 2, 4, 6, 4}, /* gtu */ - { 0x2401, 0x2c02, 0x2400, 0x2800, 3, 2, 4, 6, 4}, /* leu , 2 labels */ - { 0x2401, 0x2c02, 0x2400, 0x2800, 3, 2, 4, 6, 4}, /* le , 2 labels */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; - -/* Return TRUE if a symbol exists at the given address. */ - -static bfd_boolean -msp430_elf_symbol_address_p (bfd * abfd, - asection * sec, - Elf_Internal_Sym * isym, - bfd_vma addr) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* Examine all the local symbols. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - if (isym->st_shndx == sec_shndx && isym->st_value == addr) - return TRUE; - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == addr) - return TRUE; - } - - return FALSE; -} - -/* Adjust all local symbols defined as '.section + 0xXXXX' (.section has - sec_shndx) referenced from current and other sections. */ - -static bfd_boolean -msp430_elf_relax_adjust_locals (bfd * abfd, asection * sec, bfd_vma addr, - int count, unsigned int sec_shndx, - bfd_vma toaddr) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Sym *isym; - - irel = elf_section_data (sec)->relocs; - if (irel == NULL) - return TRUE; - - irelend = irel + sec->reloc_count; - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - - for (;irel < irelend; irel++) - { - unsigned int sidx = ELF32_R_SYM(irel->r_info); - Elf_Internal_Sym *lsym = isym + sidx; - - /* Adjust symbols referenced by .sec+0xXX. */ - if (irel->r_addend > addr && irel->r_addend < toaddr - && sidx < symtab_hdr->sh_info - && lsym->st_shndx == sec_shndx) - irel->r_addend -= count; - } - - return TRUE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr, - int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - asection *p; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (; irel < irelend; irel++) - { - /* Get the new reloc address. */ - if ((irel->r_offset > addr && irel->r_offset < toaddr)) - irel->r_offset -= count; - } - - for (p = abfd->sections; p != NULL; p = p->next) - msp430_elf_relax_adjust_locals (abfd,p,addr,count,sec_shndx,toaddr); - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - const char * name; - - name = bfd_elf_string_from_elf_section - (abfd, symtab_hdr->sh_link, isym->st_name); - name = (name == NULL || * name == 0) ? bfd_section_name (abfd, sec) : name; - - if (isym->st_shndx != sec_shndx) - continue; - - if (isym->st_value > addr - && (isym->st_value < toaddr - /* We also adjust a symbol at the end of the section if its name is - on the list below. These symbols are used for debug info - generation and they refer to the end of the current section, not - the start of the next section. */ - || (isym->st_value == toaddr - && name != NULL - && (CONST_STRNEQ (name, ".Letext") - || CONST_STRNEQ (name, ".LFE"))))) - { - if (isym->st_value < addr + count) - isym->st_value = addr; - else - isym->st_value -= count; - } - /* Adjust the function symbol's size as well. */ - else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC - && isym->st_value + isym->st_size > addr - && isym->st_value + isym->st_size < toaddr) - isym->st_size -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - { - if (sym_hash->root.u.def.value < addr + count) - sym_hash->root.u.def.value = addr; - else - sym_hash->root.u.def.value -= count; - } - /* Adjust the function symbol's size as well. */ - else if (sym_hash->root.type == bfd_link_hash_defined - && sym_hash->root.u.def.section == sec - && sym_hash->type == STT_FUNC - && sym_hash->root.u.def.value + sym_hash->size > addr - && sym_hash->root.u.def.value + sym_hash->size < toaddr) - sym_hash->size -= count; - } - - return TRUE; -} - -/* Insert two words into a section whilst relaxing. */ - -static bfd_byte * -msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr, - int word1, int word2) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - bfd_vma sec_end; - asection *p; - - contents = elf_section_data (sec)->this_hdr.contents; - sec_end = sec->size; - - /* Make space for the new words. */ - contents = bfd_realloc (contents, sec_end + 4); - memmove (contents + addr + 4, contents + addr, sec_end - addr); - - /* Insert the new words. */ - bfd_put_16 (abfd, word1, contents + addr); - bfd_put_16 (abfd, word2, contents + addr + 2); - - /* Update the section information. */ - sec->size += 4; - elf_section_data (sec)->this_hdr.contents = contents; - - /* Adjust all the relocs. */ - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - for (; irel < irelend; irel++) - if ((irel->r_offset >= addr && irel->r_offset < sec_end)) - irel->r_offset += 4; - - /* Adjust the local symbols defined in this section. */ - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - for (p = abfd->sections; p != NULL; p = p->next) - msp430_elf_relax_adjust_locals (abfd, p, addr, -4, - sec_shndx, sec_end); - - /* Adjust the global symbols affected by the move. */ - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - if (isym->st_shndx == sec_shndx - && isym->st_value >= addr && isym->st_value < sec_end) - isym->st_value += 4; - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value >= addr - && sym_hash->root.u.def.value < sec_end) - sym_hash->root.u.def.value += 4; - } - - return contents; -} - -static bfd_boolean -msp430_elf_relax_section (bfd * abfd, asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * irelend; - bfd_byte * contents = NULL; - Elf_Internal_Sym * isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = - _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - - /* Do code size growing relocs first. */ - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (uses_msp430x_relocs (abfd) - && ELF32_R_TYPE (irel->r_info) == (int) R_MSP430X_10_PCREL) - ; - else if (! uses_msp430x_relocs (abfd) - && ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_10_PCREL) - ; - else - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - bfd_signed_vma value = symval; - int opcode; - - /* Compute the value that will be relocated. */ - value += irel->r_addend; - /* Convert to PC relative. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value -= 2; - /* Scale. */ - value >>= 1; - - /* If it is in range then no modifications are needed. */ - if (value >= -512 && value <= 511) - continue; - - /* Get the opcode. */ - opcode = bfd_get_16 (abfd, contents + irel->r_offset); - - /* Compute the new opcode. We are going to convert: - J label - into: - J 1f - BR[A] #label - 1: */ - switch (opcode & 0xfc00) - { - case 0x3800: opcode = 0x3402; break; /* Jl -> Jge +2 */ - case 0x3400: opcode = 0x3802; break; /* Jge -> Jl +2 */ - case 0x2c00: opcode = 0x2802; break; /* Jhs -> Jlo +2 */ - case 0x2800: opcode = 0x2c02; break; /* Jlo -> Jhs +2 */ - case 0x2400: opcode = 0x2002; break; /* Jeq -> Jne +2 */ - case 0x2000: opcode = 0x2402; break; /* jne -> Jeq +2 */ - case 0x3000: /* jn */ - /* There is no direct inverse of the Jn insn. - FIXME: we could do this as: - Jn 1f - br 2f - 1: br label - 2: */ - continue; - default: - /* Not a conditional branch instruction. */ - /* fprintf (stderr, "unrecog: %x\n", opcode); */ - continue; - } - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Install the new opcode. */ - bfd_put_16 (abfd, opcode, contents + irel->r_offset); - - /* Insert the new branch instruction. */ - if (uses_msp430x_relocs (abfd)) - { - /* Insert an absolute branch (aka MOVA) instruction. */ - contents = msp430_elf_relax_add_two_words - (abfd, sec, irel->r_offset + 2, 0x0080, 0x0000); - - /* Update the relocation to point to the inserted branch - instruction. Note - we are changing a PC-relative reloc - into an absolute reloc, but this is OK because we have - arranged with the assembler to have the reloc's value be - a (local) symbol, not a section+offset value. */ - irel->r_offset += 2; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430X_ABS20_ADR_SRC); - } - else - { - contents = msp430_elf_relax_add_two_words - (abfd, sec, irel->r_offset + 2, 0x4030, 0x0000); - - /* See comment above about converting a 10-bit PC-rel - relocation into a 16-bit absolute relocation. */ - irel->r_offset += 4; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430_16); - } - - /* Growing the section may mean that other - conditional branches need to be fixed. */ - *again = TRUE; - } - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Try to turn a 16bit pc-relative branch into a 10bit pc-relative - branch. */ - /* Paranoia? paranoia... */ - if (! uses_msp430x_relocs (abfd) - && ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_RL_PCREL) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 10 bits, note the high value is - 1016 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 1016 && (long) value > -1016) - { - int code0 = 0, code1 = 0, code2 = 0; - int i; - struct rcodes_s *rx; - - /* Get the opcode. */ - if (irel->r_offset >= 6) - code0 = bfd_get_16 (abfd, contents + irel->r_offset - 6); - - if (irel->r_offset >= 4) - code1 = bfd_get_16 (abfd, contents + irel->r_offset - 4); - - code2 = bfd_get_16 (abfd, contents + irel->r_offset - 2); - - if (code2 != 0x4010) - continue; - - /* Check r4 and r3. */ - for (i = NUMB_RELAX_CODES - 1; i >= 0; i--) - { - rx = &rcode[i]; - if (rx->cdx == 2 && rx->f0 == code0 && rx->f1 == code1) - break; - else if (rx->cdx == 1 && rx->f1 == code1) - break; - else if (rx->cdx == 0) /* This is an unconditional jump. */ - break; - } - - /* Check labels: - .Label0: ; we do not care about this label - jeq +6 - .Label1: ; make sure there is no label here - jl +4 - .Label2: ; make sure there is no label here - br .Label_dst - - So, if there is .Label1 or .Label2 we cannot relax this code. - This actually should not happen, cause for relaxable - instructions we use RL_PCREL reloc instead of 16_PCREL. - Will change this in the future. */ - - if (rx->cdx > 0 - && msp430_elf_symbol_address_p (abfd, sec, isymbuf, - irel->r_offset - 2)) - continue; - if (rx->cdx > 1 - && msp430_elf_symbol_address_p (abfd, sec, isymbuf, - irel->r_offset - 4)) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - if (uses_msp430x_relocs (abfd)) - { - if (rx->labels == 3) /* Handle special cases. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430X_2X_PCREL); - else - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430X_10_PCREL); - } - else - { - if (rx->labels == 3) /* Handle special cases. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430_2X_PCREL); - else - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430_10_PCREL); - } - - /* Fix the opcode right way. */ - bfd_put_16 (abfd, rx->t0, contents + irel->r_offset - rx->off); - if (rx->t1) - bfd_put_16 (abfd, rx->t1, - contents + irel->r_offset - rx->off + 2); - - /* Delete bytes. */ - if (!msp430_elf_relax_delete_bytes (abfd, sec, - irel->r_offset - rx->off + - rx->ncl, rx->bs)) - goto error_return; - - /* Handle unconditional jumps. */ - if (rx->cdx == 0) - irel->r_offset -= 2; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - - /* Try to turn a 16-bit absolute branch into a 10-bit pc-relative - branch. */ - if ((uses_msp430x_relocs (abfd) - && ELF32_R_TYPE (irel->r_info) == R_MSP430X_ABS16) - || (! uses_msp430x_relocs (abfd) - && ELF32_R_TYPE (irel->r_info) == R_MSP430_16)) - { - bfd_vma value = symval; - - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 10 bits, note the high value is - 1016 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 1016 && (long) value > -1016) - { - int code2; - - /* Get the opcode. */ - code2 = bfd_get_16 (abfd, contents + irel->r_offset - 2); - if (code2 != 0x4030) - continue; - /* FIXME: check r4 and r3 ? */ - /* FIXME: Handle 0x4010 as well ? */ - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - if (uses_msp430x_relocs (abfd)) - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430X_10_PCREL); - } - else - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430_10_PCREL); - } - - /* Fix the opcode right way. */ - bfd_put_16 (abfd, 0x3c00, contents + irel->r_offset - 2); - irel->r_offset -= 2; - - /* Delete bytes. */ - if (!msp430_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, 2)) - goto error_return; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - } - - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (!link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (!link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - -error_return: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* Handle an MSP430 specific section when reading an object file. - This is called when bfd_section_from_shdr finds a section with - an unknown type. */ - -static bfd_boolean -elf32_msp430_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr * hdr, - const char *name, - int shindex) -{ - switch (hdr->sh_type) - { - case SHT_MSP430_SEC_FLAGS: - case SHT_MSP430_SYM_ALIASES: - case SHT_MSP430_ATTRIBUTES: - return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); - default: - return FALSE; - } -} - -static bfd_boolean -elf32_msp430_obj_attrs_handle_unknown (bfd *abfd, int tag) -{ - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B: Unknown MSPABI object attribute %d"), - abfd, tag); - return TRUE; -} - -/* Determine whether an object attribute tag takes an integer, a - string or both. */ - -static int -elf32_msp430_obj_attrs_arg_type (int tag) -{ - if (tag == Tag_compatibility) - return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL; - - if (tag < 32) - return ATTR_TYPE_FLAG_INT_VAL; - - return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; -} - -static inline const char * -isa_type (int isa) -{ - switch (isa) - { - case 1: return "MSP430"; - case 2: return "MSP430X"; - default: return "unknown"; - } -} - -static inline const char * -code_model (int model) -{ - switch (model) - { - case 1: return "small"; - case 2: return "large"; - default: return "unknown"; - } -} - -static inline const char * -data_model (int model) -{ - switch (model) - { - case 1: return "small"; - case 2: return "large"; - case 3: return "restricted large"; - default: return "unknown"; - } -} - -/* Merge MSPABI object attributes from IBFD into OBFD. - Raise an error if there are conflicting attributes. */ - -static bfd_boolean -elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - obj_attribute *in_attr; - obj_attribute *out_attr; - bfd_boolean result = TRUE; - static bfd * first_input_bfd = NULL; - - /* Skip linker created files. */ - if (ibfd->flags & BFD_LINKER_CREATED) - return TRUE; - - /* If this is the first real object just copy the attributes. */ - if (!elf_known_obj_attributes_proc (obfd)[0].i) - { - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - out_attr = elf_known_obj_attributes_proc (obfd); - - /* Use the Tag_null value to indicate that - the attributes have been initialized. */ - out_attr[0].i = 1; - - first_input_bfd = ibfd; - return TRUE; - } - - in_attr = elf_known_obj_attributes_proc (ibfd); - out_attr = elf_known_obj_attributes_proc (obfd); - - /* The ISAs must be the same. */ - if (in_attr[OFBA_MSPABI_Tag_ISA].i != out_attr[OFBA_MSPABI_Tag_ISA].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses %s instructions but %B uses %s"), - ibfd, isa_type (in_attr[OFBA_MSPABI_Tag_ISA].i), - first_input_bfd, isa_type (out_attr[OFBA_MSPABI_Tag_ISA].i)); - result = FALSE; - } - - /* The code models must be the same. */ - if (in_attr[OFBA_MSPABI_Tag_Code_Model].i != - out_attr[OFBA_MSPABI_Tag_Code_Model].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses the %s code model whereas %B uses the %s code model"), - ibfd, code_model (in_attr[OFBA_MSPABI_Tag_Code_Model].i), - first_input_bfd, code_model (out_attr[OFBA_MSPABI_Tag_Code_Model].i)); - result = FALSE; - } - - /* The large code model is only supported by the MSP430X. */ - if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 2 - && out_attr[OFBA_MSPABI_Tag_ISA].i != 2) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses the large code model but %B uses MSP430 instructions"), - ibfd, first_input_bfd); - result = FALSE; - } - - /* The data models must be the same. */ - if (in_attr[OFBA_MSPABI_Tag_Data_Model].i != - out_attr[OFBA_MSPABI_Tag_Data_Model].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses the %s data model whereas %B uses the %s data model"), - ibfd, data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i), - first_input_bfd, data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i)); - result = FALSE; - } - - /* The small code model requires the use of the small data model. */ - if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 1 - && out_attr[OFBA_MSPABI_Tag_Data_Model].i != 1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses the small code model but %B uses the %s data model"), - ibfd, first_input_bfd, - data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i)); - result = FALSE; - } - - /* The large data models are only supported by the MSP430X. */ - if (in_attr[OFBA_MSPABI_Tag_Data_Model].i > 1 - && out_attr[OFBA_MSPABI_Tag_ISA].i != 2) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses the %s data model but %B only uses MSP430 instructions"), - ibfd, data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i), - first_input_bfd); - result = FALSE; - } - - return result; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf32_msp430_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - /* Make sure that the machine number reflects the most - advanced version of the MSP architecture required. */ -#define max(a,b) ((a) > (b) ? (a) : (b)) - if (bfd_get_mach (ibfd) != bfd_get_mach (obfd)) - bfd_default_set_arch_mach (obfd, bfd_get_arch (obfd), - max (bfd_get_mach (ibfd), bfd_get_mach (obfd))); -#undef max - - return elf32_msp430_merge_mspabi_attributes (ibfd, info); -} - -static bfd_boolean -msp430_elf_is_target_special_symbol (bfd *abfd, asymbol *sym) -{ - return _bfd_elf_is_local_label_name (abfd, sym->name); -} - -static bfd_boolean -uses_large_model (bfd *abfd) -{ - obj_attribute * attr; - - if (abfd->flags & BFD_LINKER_CREATED) - return FALSE; - - attr = elf_known_obj_attributes_proc (abfd); - if (attr == NULL) - return FALSE; - - return attr[OFBA_MSPABI_Tag_Code_Model].i == 2; -} - -static unsigned int -elf32_msp430_eh_frame_address_size (bfd *abfd, - const asection *sec ATTRIBUTE_UNUSED) -{ - return uses_large_model (abfd) ? 4 : 2; -} - -/* This is gross. The MSP430 EABI says that (sec 11.5): - - "An implementation may choose to use Rel or Rela - type relocations for other relocations." - - But it also says that: - - "Certain relocations are identified as Rela only. [snip] - Where Rela is specified, an implementation must honor - this requirement." - - There is one relocation marked as requiring RELA - R_MSP430_ABS_HI16 - but - to keep things simple we choose to use RELA relocations throughout. The - problem is that the TI compiler generates REL relocations, so we have to - be able to accept those as well. */ - -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_default_use_rela_p 1 - -#undef elf_backend_obj_attrs_vendor -#define elf_backend_obj_attrs_vendor "mspabi" -#undef elf_backend_obj_attrs_section -#define elf_backend_obj_attrs_section ".MSP430.attributes" -#undef elf_backend_obj_attrs_section_type -#define elf_backend_obj_attrs_section_type SHT_MSP430_ATTRIBUTES -#define elf_backend_section_from_shdr elf32_msp430_section_from_shdr -#define elf_backend_obj_attrs_handle_unknown elf32_msp430_obj_attrs_handle_unknown -#undef elf_backend_obj_attrs_arg_type -#define elf_backend_obj_attrs_arg_type elf32_msp430_obj_attrs_arg_type -#define bfd_elf32_bfd_merge_private_bfd_data elf32_msp430_merge_private_bfd_data -#define elf_backend_eh_frame_address_size elf32_msp430_eh_frame_address_size - -#define ELF_ARCH bfd_arch_msp430 -#define ELF_MACHINE_CODE EM_MSP430 -#define ELF_MACHINE_ALT1 EM_MSP430_OLD -#define ELF_MAXPAGESIZE 4 -#define ELF_OSABI ELFOSABI_STANDALONE - -#define TARGET_LITTLE_SYM msp430_elf32_vec -#define TARGET_LITTLE_NAME "elf32-msp430" - -#define elf_info_to_howto msp430_info_to_howto_rela -#define elf_info_to_howto_rel NULL -#define elf_backend_relocate_section elf32_msp430_relocate_section -#define elf_backend_check_relocs elf32_msp430_check_relocs -#define elf_backend_can_gc_sections 1 -#define elf_backend_final_write_processing bfd_elf_msp430_final_write_processing -#define elf_backend_object_p elf32_msp430_object_p -#define bfd_elf32_bfd_relax_section msp430_elf_relax_section -#define bfd_elf32_bfd_is_target_special_symbol msp430_elf_is_target_special_symbol - -#undef elf32_bed -#define elf32_bed elf32_msp430_bed - -#include "elf32-target.h" - -/* The TI compiler sets the OSABI field to ELFOSABI_NONE. */ -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM msp430_elf32_ti_vec - -#undef elf32_bed -#define elf32_bed elf32_msp430_ti_bed - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_NONE - -static const struct bfd_elf_special_section msp430_ti_elf_special_sections[] = -{ - /* prefix, prefix_length, suffix_len, type, attributes. */ - { STRING_COMMA_LEN (".TI.symbol.alias"), 0, SHT_MSP430_SYM_ALIASES, 0 }, - { STRING_COMMA_LEN (".TI.section.flags"), 0, SHT_MSP430_SEC_FLAGS, 0 }, - { STRING_COMMA_LEN ("_TI_build_attrib"), 0, SHT_MSP430_ATTRIBUTES, 0 }, - { NULL, 0, 0, 0, 0 } -}; - -#undef elf_backend_special_sections -#define elf_backend_special_sections msp430_ti_elf_special_sections - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-mt.c b/sdcc/support/sdbinutils/bfd/elf32-mt.c deleted file mode 100644 index b58394f50..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-mt.c +++ /dev/null @@ -1,601 +0,0 @@ -/* Morpho Technologies MT specific support for 32-bit ELF - Copyright (C) 2001-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/mt.h" - -/* Prototypes. */ -static reloc_howto_type * mt_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); - -static void mt_info_to_howto_rela - (bfd *, arelent *, Elf_Internal_Rela *); - -static bfd_reloc_status_type mt_elf_relocate_hi16 - (bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma); - -static bfd_reloc_status_type mt_final_link_relocate - (reloc_howto_type *, bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, bfd_vma); - -static bfd_boolean mt_elf_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); - -/* Relocation tables. */ -static reloc_howto_type mt_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_MT_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_NONE", /* name */ - FALSE, /* partial_inplace */ - 0 , /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_MT_16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_16", /* name */ - FALSE, /* partial_inplace */ - 0 , /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_MT_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_32", /* name */ - FALSE, /* partial_inplace */ - 0 , /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit pc-relative relocation. */ - HOWTO (R_MT_32_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_32_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0 , /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit pc-relative relocation. */ - HOWTO (R_MT_PC16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_PC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* high 16 bits of symbol value. */ - HOWTO (R_MT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MT_LO16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* Map BFD reloc types to MT ELF reloc types. */ - -static reloc_howto_type * -mt_reloc_type_lookup - (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - /* Note that the mt_elf_howto_table is indxed by the R_ - constants. Thus, the order that the howto records appear in the - table *must* match the order of the relocation types defined in - include/elf/mt.h. */ - - switch (code) - { - case BFD_RELOC_NONE: - return &mt_elf_howto_table[ (int) R_MT_NONE]; - case BFD_RELOC_16: - return &mt_elf_howto_table[ (int) R_MT_16]; - case BFD_RELOC_32: - return &mt_elf_howto_table[ (int) R_MT_32]; - case BFD_RELOC_32_PCREL: - return &mt_elf_howto_table[ (int) R_MT_32_PCREL]; - case BFD_RELOC_16_PCREL: - return &mt_elf_howto_table[ (int) R_MT_PC16]; - case BFD_RELOC_HI16: - return &mt_elf_howto_table[ (int) R_MT_HI16]; - case BFD_RELOC_LO16: - return &mt_elf_howto_table[ (int) R_MT_LO16]; - - default: - /* Pacify gcc -Wall. */ - return NULL; - } - return NULL; -} - -static reloc_howto_type * -mt_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (mt_elf_howto_table) / sizeof (mt_elf_howto_table[0]); - i++) - if (mt_elf_howto_table[i].name != NULL - && strcasecmp (mt_elf_howto_table[i].name, r_name) == 0) - return &mt_elf_howto_table[i]; - - return NULL; -} - -bfd_reloc_status_type -mt_elf_relocate_hi16 - (bfd * input_bfd, - Elf_Internal_Rela * relhi, - bfd_byte * contents, - bfd_vma value) -{ - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + relhi->r_offset); - - value += relhi->r_addend; - value >>= 16; - insn = ((insn & ~0xFFFF) | value); - - bfd_put_32 (input_bfd, insn, contents + relhi->r_offset); - return bfd_reloc_ok; -} - -/* XXX: The following code is the result of a cut&paste. This unfortunate - practice is very widespread in the various target back-end files. */ - -/* Set the howto pointer for a MT ELF reloc. */ - -static void -mt_info_to_howto_rela - (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_MT_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid MT reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & mt_elf_howto_table [r_type]; -} - -/* Perform a single relocation. By default we use the standard BFD - routines. */ - -static bfd_reloc_status_type -mt_final_link_relocate - (reloc_howto_type * howto, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * rel, - bfd_vma relocation) -{ - return _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); -} - -/* Relocate a MT ELF section. - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -mt_elf_relocate_section - (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = mt_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc; - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - /* Finally, the sole MT-specific part. */ - switch (r_type) - { - case R_MT_HI16: - r = mt_elf_relocate_hi16 (input_bfd, rel, contents, relocation); - break; - default: - r = mt_final_link_relocate (howto, input_bfd, input_section, - contents, rel, relocation); - break; - } - - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -mt_elf_check_relocs - (bfd * abfd, - struct bfd_link_info * info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - } - - return TRUE; -} - -/* Return the MACH for an e_flags value. */ - -static int -elf32_mt_machine (bfd *abfd) -{ - switch (elf_elfheader (abfd)->e_flags & EF_MT_CPU_MASK) - { - case EF_MT_CPU_MRISC: return bfd_mach_ms1; - case EF_MT_CPU_MRISC2: return bfd_mach_mrisc2; - case EF_MT_CPU_MS2: return bfd_mach_ms2; - } - - return bfd_mach_ms1; -} - -static bfd_boolean -mt_elf_object_p (bfd * abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_mt, elf32_mt_machine (abfd)); - - return TRUE; -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -mt_elf_set_private_flags (bfd * abfd, - flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -mt_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, new_flags; - bfd_boolean ok = TRUE; - - /* Check if we have the same endianness. */ - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - /* If they're not both mt, then merging is meaningless, so just - don't do it. */ - if (strcmp (ibfd->arch_info->arch_name, "mt") != 0) - return TRUE; - if (strcmp (obfd->arch_info->arch_name, "mt") != 0) - return TRUE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - -#ifdef DEBUG - _bfd_error_handler ("%B: old_flags = 0x%.8x, new_flags = 0x%.8x, init = %s", - ibfd, old_flags, new_flags, elf_flags_init (obfd) ? "yes" : "no"); -#endif - - if (!elf_flags_init (obfd)) - { - old_flags = new_flags; - elf_flags_init (obfd) = TRUE; - } - else if ((new_flags & EF_MT_CPU_MASK) != (old_flags & EF_MT_CPU_MASK)) - { - /* CPU has changed. This is invalid, because MRISC, MRISC2 and - MS2 are not subsets of each other. */ - ok = FALSE; - } - - if (ok) - { - obfd->arch_info = ibfd->arch_info; - elf_elfheader (obfd)->e_flags = old_flags; - } - - return ok; -} - -static bfd_boolean -mt_elf_print_private_bfd_data (bfd * abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (unsigned long) flags); - - switch (flags & EF_MT_CPU_MASK) - { - default: - case EF_MT_CPU_MRISC: fprintf (file, " ms1-16-002"); break; - case EF_MT_CPU_MRISC2: fprintf (file, " ms1-16-003"); break; - case EF_MT_CPU_MS2: fprintf (file, " ms2"); break; - } - - fputc ('\n', file); - - return TRUE; -} - - -#define TARGET_BIG_SYM mt_elf32_vec -#define TARGET_BIG_NAME "elf32-mt" - -#define ELF_ARCH bfd_arch_mt -#define ELF_MACHINE_CODE EM_MT -#define ELF_MAXPAGESIZE 1 /* No pages on the MT. */ - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto mt_info_to_howto_rela - -#define elf_backend_relocate_section mt_elf_relocate_section - -#define bfd_elf32_bfd_reloc_type_lookup mt_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup mt_reloc_name_lookup - -#define elf_backend_check_relocs mt_elf_check_relocs -#define elf_backend_object_p mt_elf_object_p -#define elf_backend_rela_normal 1 - -#define elf_backend_can_gc_sections 1 - -#define bfd_elf32_bfd_set_private_flags mt_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data mt_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data mt_elf_print_private_bfd_data - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-nds32.c b/sdcc/support/sdbinutils/bfd/elf32-nds32.c deleted file mode 100644 index 5ceb0a0b2..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-nds32.c +++ /dev/null @@ -1,15501 +0,0 @@ -/* NDS32-specific support for 32-bit ELF. - Copyright (C) 2012-2018 Free Software Foundation, Inc. - Contributed by Andes Technology Corporation. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - - -#include "sysdep.h" -#include "bfd.h" -#include "bfd_stdint.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "libiberty.h" -#include "bfd_stdint.h" -#include "elf/nds32.h" -#include "opcode/nds32.h" -#include "elf32-nds32.h" -#include "opcode/cgen.h" -#include "../opcodes/nds32-opc.h" - -/* Relocation HOWTO functions. */ -static bfd_reloc_status_type nds32_elf_ignore_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nds32_elf_9_pcrel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nds32_elf_hi20_reloc - (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_reloc_status_type nds32_elf_lo12_reloc - (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_reloc_status_type nds32_elf_generic_reloc - (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_reloc_status_type nds32_elf_sda15_reloc - (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -/* Helper functions for HOWTO. */ -static bfd_reloc_status_type nds32_elf_do_9_pcrel_reloc - (bfd *, reloc_howto_type *, asection *, bfd_byte *, bfd_vma, - asection *, bfd_vma, bfd_vma); - -/* Nds32 helper functions. */ -static bfd_vma calculate_memory_address -(bfd *, Elf_Internal_Rela *, Elf_Internal_Sym *, Elf_Internal_Shdr *); -static int nds32_get_section_contents (bfd *, asection *, - bfd_byte **, bfd_boolean); -static bfd_boolean nds32_elf_ex9_build_hash_table -(bfd *, asection *, struct bfd_link_info *); -static bfd_boolean nds32_elf_ex9_itb_base (struct bfd_link_info *); -static void nds32_elf_ex9_import_table (struct bfd_link_info *); -static void nds32_elf_ex9_finish (struct bfd_link_info *); -static void nds32_elf_ex9_reloc_jmp (struct bfd_link_info *); -static void nds32_elf_get_insn_with_reg - (Elf_Internal_Rela *, uint32_t, uint32_t *); -static int nds32_get_local_syms (bfd *, asection *ATTRIBUTE_UNUSED, - Elf_Internal_Sym **); -static bfd_boolean nds32_elf_ex9_replace_instruction - (struct bfd_link_info *, bfd *, asection *); -static bfd_boolean nds32_elf_ifc_calc (struct bfd_link_info *, bfd *, - asection *); -static bfd_boolean nds32_elf_ifc_finish (struct bfd_link_info *); -static bfd_boolean nds32_elf_ifc_replace (struct bfd_link_info *); -static bfd_boolean nds32_elf_ifc_reloc (void); -static bfd_boolean nds32_relax_fp_as_gp - (struct bfd_link_info *link_info, bfd *abfd, asection *sec, - Elf_Internal_Rela *internal_relocs, Elf_Internal_Rela *irelend, - Elf_Internal_Sym *isymbuf); -static bfd_boolean nds32_fag_remove_unused_fpbase - (bfd *abfd, asection *sec, Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend); - -enum -{ - MACH_V1 = bfd_mach_n1h, - MACH_V2 = bfd_mach_n1h_v2, - MACH_V3 = bfd_mach_n1h_v3, - MACH_V3M = bfd_mach_n1h_v3m -}; - -#define MIN(a, b) ((a) > (b) ? (b) : (a)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -/* The nop opcode we use. */ -#define NDS32_NOP32 0x40000009 -#define NDS32_NOP16 0x9200 - -/* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE 24 -#define PLT_HEADER_SIZE 24 - -/* The first entry in a procedure linkage table are reserved, - and the initial contents are unimportant (we zero them out). - Subsequent entries look like this. */ -#define PLT0_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(.got+4) */ -#define PLT0_ENTRY_WORD1 0x58f78000 /* ori r15, r25, LO12(.got+4) */ -#define PLT0_ENTRY_WORD2 0x05178000 /* lwi r17, [r15+0] */ -#define PLT0_ENTRY_WORD3 0x04f78001 /* lwi r15, [r15+4] */ -#define PLT0_ENTRY_WORD4 0x4a003c00 /* jr r15 */ - -/* $ta is change to $r15 (from $r25). */ -#define PLT0_PIC_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(got[1]@GOT) */ -#define PLT0_PIC_ENTRY_WORD1 0x58f78000 /* ori r15, r15, LO12(got[1]@GOT) */ -#define PLT0_PIC_ENTRY_WORD2 0x40f7f400 /* add r15, gp, r15 */ -#define PLT0_PIC_ENTRY_WORD3 0x05178000 /* lwi r17, [r15+0] */ -#define PLT0_PIC_ENTRY_WORD4 0x04f78001 /* lwi r15, [r15+4] */ -#define PLT0_PIC_ENTRY_WORD5 0x4a003c00 /* jr r15 */ - -#define PLT_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(&got[n+3]) */ -#define PLT_ENTRY_WORD1 0x04f78000 /* lwi r15, r15, LO12(&got[n+3]) */ -#define PLT_ENTRY_WORD2 0x4a003c00 /* jr r15 */ -#define PLT_ENTRY_WORD3 0x45000000 /* movi r16, sizeof(RELA) * n */ -#define PLT_ENTRY_WORD4 0x48000000 /* j .plt0. */ - -#define PLT_PIC_ENTRY_WORD0 0x46f00000 /* sethi r15, HI20(got[n+3]@GOT) */ -#define PLT_PIC_ENTRY_WORD1 0x58f78000 /* ori r15, r15, LO12(got[n+3]@GOT) */ -#define PLT_PIC_ENTRY_WORD2 0x38febc02 /* lw r15, [gp+r15] */ -#define PLT_PIC_ENTRY_WORD3 0x4a003c00 /* jr r15 */ -#define PLT_PIC_ENTRY_WORD4 0x45000000 /* movi r16, sizeof(RELA) * n */ -#define PLT_PIC_ENTRY_WORD5 0x48000000 /* j .plt0 */ - -/* These are macros used to get the relocation accurate value. */ -#define ACCURATE_8BIT_S1 (0x100) -#define ACCURATE_U9BIT_S1 (0x400) -#define ACCURATE_12BIT_S1 (0x2000) -#define ACCURATE_14BIT_S1 (0x4000) -#define ACCURATE_19BIT (0x40000) - -/* These are macros used to get the relocation conservative value. */ -#define CONSERVATIVE_8BIT_S1 (0x100 - 4) -#define CONSERVATIVE_14BIT_S1 (0x4000 - 4) -#define CONSERVATIVE_16BIT_S1 (0x10000 - 4) -#define CONSERVATIVE_24BIT_S1 (0x1000000 - 4) -/* These must be more conservative because the address may be in - different segment. */ -#define CONSERVATIVE_15BIT (0x4000 - 0x1000) -#define CONSERVATIVE_15BIT_S1 (0x8000 - 0x1000) -#define CONSERVATIVE_15BIT_S2 (0x10000 - 0x1000) -#define CONSERVATIVE_19BIT (0x40000 - 0x1000) -#define CONSERVATIVE_20BIT (0x80000 - 0x1000) - -/* Size of small data/bss sections, used to calculate SDA_BASE. */ -static long got_size = 0; -static int is_SDA_BASE_set = 0; -static int is_ITB_BASE_set = 0; - -/* Convert ELF-VER in eflags to string for debugging purpose. */ -static const char *const nds32_elfver_strtab[] = -{ - "ELF-1.2", - "ELF-1.3", - "ELF-1.4", -}; - -/* The nds32 linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that - it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we - have copied for a given symbol. */ - -struct elf_nds32_pcrel_relocs_copied -{ - /* Next section. */ - struct elf_nds32_pcrel_relocs_copied *next; - /* A section in dynobj. */ - asection *section; - /* Number of relocs copied in this section. */ - bfd_size_type count; -}; - -/* Nds32 ELF linker hash entry. */ - -struct elf_nds32_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* For checking relocation type. */ -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_IE 2 - unsigned int tls_type; -}; - -/* Get the nds32 ELF linker hash table from a link_info structure. */ - -#define FP_BASE_NAME "_FP_BASE_" -static int check_start_export_sym = 0; -static size_t ex9_relax_size = 0; /* Save ex9 predicted reducing size. */ - -/* The offset for executable tls relaxation. */ -#define TP_OFFSET 0x0 - -struct elf_nds32_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char *local_got_tls_type; -}; - -#define elf_nds32_tdata(bfd) \ - ((struct elf_nds32_obj_tdata *) (bfd)->tdata.any) - -#define elf32_nds32_local_got_tls_type(bfd) \ - (elf_nds32_tdata (bfd)->local_got_tls_type) - -#define elf32_nds32_hash_entry(ent) ((struct elf_nds32_link_hash_entry *)(ent)) - -static bfd_boolean -nds32_elf_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_nds32_obj_tdata), - NDS32_ELF_DATA); -} - -/* Relocations used for relocation. */ -static reloc_howto_type nds32_elf_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_NDS32_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_NDS32_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - nds32_elf_generic_reloc, /* special_function */ - "R_NDS32_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_NDS32_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - nds32_elf_generic_reloc, /* special_function */ - "R_NDS32_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 20 bit address. */ - HOWTO (R_NDS32_20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - nds32_elf_generic_reloc, /* special_function */ - "R_NDS32_20", /* name */ - FALSE, /* partial_inplace */ - 0xfffff, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An PC Relative 9-bit relocation, shifted by 2. - This reloc is complicated because relocations are relative to pc & -4. - i.e. branches in the right insn slot use the address of the left insn - slot for pc. */ - /* ??? It's not clear whether this should have partial_inplace set or not. - Branch relaxing in the assembler can store the addend in the insn, - and if bfd_install_relocation gets called the addend may get added - again. */ - HOWTO (R_NDS32_9_PCREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - nds32_elf_9_pcrel_reloc, /* special_function */ - "R_NDS32_9_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 15 bit relocation, right shifted by 1. */ - HOWTO (R_NDS32_15_PCREL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 14, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_15_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x3fff, /* src_mask */ - 0x3fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 17 bit relocation, right shifted by 1. */ - HOWTO (R_NDS32_17_PCREL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_17_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 25 bit relocation, right shifted by 1. */ - /* ??? It's not clear whether this should have partial_inplace set or not. - Branch relaxing in the assembler can store the addend in the insn, - and if bfd_install_relocation gets called the addend may get added - again. */ - HOWTO (R_NDS32_25_PCREL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_25_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* High 20 bits of address when lower 12 is or'd in. */ - HOWTO (R_NDS32_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_hi20_reloc, /* special_function */ - "R_NDS32_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_lo12_reloc, /* special_function */ - "R_NDS32_LO12S3", /* name */ - FALSE, /* partial_inplace */ - 0x000001ff, /* src_mask */ - 0x000001ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_lo12_reloc, /* special_function */ - "R_NDS32_LO12S2", /* name */ - FALSE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_lo12_reloc, /* special_function */ - "R_NDS32_LO12S1", /* name */ - FALSE, /* partial_inplace */ - 0x000007ff, /* src_mask */ - 0x000007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_lo12_reloc, /* special_function */ - "R_NDS32_LO12S0", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA15S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - nds32_elf_sda15_reloc, /* special_function */ - "R_NDS32_SDA15S3", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA15S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - nds32_elf_sda15_reloc, /* special_function */ - "R_NDS32_SDA15S2", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA15S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - nds32_elf_sda15_reloc, /* special_function */ - "R_NDS32_SDA15S1", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA15S0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - nds32_elf_sda15_reloc, /* special_function */ - "R_NDS32_SDA15S0", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_NDS32_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - NULL, /* special_function */ - "R_NDS32_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable member usage */ - HOWTO (R_NDS32_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - _bfd_elf_rel_vtable_reloc_fn, /* special_function */ - "R_NDS32_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_NDS32_16_RELA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_16_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_NDS32_32_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_32_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 20 bit address. */ - HOWTO (R_NDS32_20_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_20_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xfffff, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NDS32_9_PCREL_RELA, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_9_PCREL_RELA",/* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 15 bit relocation, right shifted by 1. */ - HOWTO (R_NDS32_15_PCREL_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 14, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_15_PCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x3fff, /* src_mask */ - 0x3fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 17 bit relocation, right shifted by 1. */ - HOWTO (R_NDS32_17_PCREL_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_17_PCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 25 bit relocation, right shifted by 2. */ - HOWTO (R_NDS32_25_PCREL_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_25_PCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* High 20 bits of address when lower 16 is or'd in. */ - HOWTO (R_NDS32_HI20_RELA, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_HI20_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S3_RELA, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S3_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x000001ff, /* src_mask */ - 0x000001ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S2_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S2_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S1_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S1_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x000007ff, /* src_mask */ - 0x000007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S0_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S0_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA15S3_RELA, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA15S3_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA15S2_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA15S2_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NDS32_SDA15S1_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA15S1_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NDS32_SDA15S0_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA15S0_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_NDS32_RELA_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - NULL, /* special_function */ - "R_NDS32_RELA_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable member usage */ - HOWTO (R_NDS32_RELA_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - _bfd_elf_rel_vtable_reloc_fn, /* special_function */ - "R_NDS32_RELA_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_NDS32_20, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_NDS32_GOT20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT20", /* name */ - FALSE, /* partial_inplace */ - 0xfffff, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_NDS32_PCREL, but referring to the procedure linkage table - entry for the symbol. */ - HOWTO (R_NDS32_25_PLTREL, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_25_PLTREL", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_NDS32_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_COPY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_NDS32_20, but used when setting global offset table - entries. */ - HOWTO (R_NDS32_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marks a procedure linkage table entry for a symbol. */ - HOWTO (R_NDS32_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_NDS32_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NDS32_GOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTOFF", /* name */ - FALSE, /* partial_inplace */ - 0xfffff, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An PC Relative 20-bit relocation used when setting PIC offset - table register. */ - HOWTO (R_NDS32_GOTPC20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTPC20", /* name */ - FALSE, /* partial_inplace */ - 0xfffff, /* src_mask */ - 0xfffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_NDS32_HI20, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_NDS32_GOT_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOT_LO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT_LO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An PC Relative relocation used when setting PIC offset table register. - Like R_NDS32_HI20, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_NDS32_GOTPC_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTPC_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_NDS32_GOTPC_LO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTPC_LO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_NDS32_GOTOFF_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTOFF_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOTOFF_LO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTOFF_LO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Alignment hint for relaxable instruction. This is used with - R_NDS32_LABEL as a pair. Relax this instruction from 4 bytes to 2 - in order to make next label aligned on word boundary. */ - HOWTO (R_NDS32_INSN16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_INSN16", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Alignment hint for label. */ - HOWTO (R_NDS32_LABEL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LABEL", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for unconditional call sequence */ - HOWTO (R_NDS32_LONGCALL1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LONGCALL1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional call sequence. */ - HOWTO (R_NDS32_LONGCALL2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LONGCALL2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional call sequence. */ - HOWTO (R_NDS32_LONGCALL3, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LONGCALL3", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for unconditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP1, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LONGJUMP1", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LONGJUMP2", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP3, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LONGJUMP3", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for load/store sequence. */ - HOWTO (R_NDS32_LOADSTORE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_LOADSTORE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for load/store sequence. */ - HOWTO (R_NDS32_9_FIXED_RELA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_9_FIXED_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for load/store sequence. */ - HOWTO (R_NDS32_15_FIXED_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_15_FIXED_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x00003fff, /* src_mask */ - 0x00003fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for load/store sequence. */ - HOWTO (R_NDS32_17_FIXED_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_17_FIXED_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for load/store sequence. */ - HOWTO (R_NDS32_25_FIXED_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_25_FIXED_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x00ffffff, /* src_mask */ - 0x00ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 20 bits of PLT symbol offset relative to PC. */ - HOWTO (R_NDS32_PLTREL_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLTREL_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 12 bits of PLT symbol offset relative to PC. */ - HOWTO (R_NDS32_PLTREL_LO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLTREL_LO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 20 bits of PLT symbol offset relative to GOT (GP). */ - HOWTO (R_NDS32_PLT_GOTREL_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLT_GOTREL_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 12 bits of PLT symbol offset relative to GOT (GP). */ - HOWTO (R_NDS32_PLT_GOTREL_LO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLT_GOTREL_LO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 12 bits offset. */ - HOWTO (R_NDS32_SDA12S2_DP_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA12S2_DP_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 12 bits offset. */ - HOWTO (R_NDS32_SDA12S2_SP_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA12S2_SP_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Lower 12 bits of address. */ - - HOWTO (R_NDS32_LO12S2_DP_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S2_DP_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 12 bits of address. */ - HOWTO (R_NDS32_LO12S2_SP_RELA,/* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S2_SP_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Lower 12 bits of address. Special identity for or case. */ - HOWTO (R_NDS32_LO12S0_ORI_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_LO12S0_ORI_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Small data area 19 bits offset. */ - HOWTO (R_NDS32_SDA16S3_RELA, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA16S3_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Small data area 15 bits offset. */ - HOWTO (R_NDS32_SDA17S2_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA17S2_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0001ffff, /* src_mask */ - 0x0001ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NDS32_SDA18S1_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA18S1_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0003ffff, /* src_mask */ - 0x0003ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NDS32_SDA19S0_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA19S0_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DWARF2_OP1_RELA, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DWARF2_OP1_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DWARF2_OP2_RELA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DWARF2_OP2_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DWARF2_LEB_RELA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DWARF2_LEB_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_UPDATE_TA_RELA,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_UPDATE_TA_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Like R_NDS32_PCREL, but referring to the procedure linkage table - entry for the symbol. */ - HOWTO (R_NDS32_9_PLTREL, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_9_PLTREL", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - /* Low 20 bits of PLT symbol offset relative to GOT (GP). */ - HOWTO (R_NDS32_PLT_GOTREL_LO20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLT_GOTREL_LO20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* low 15 bits of PLT symbol offset relative to GOT (GP) */ - HOWTO (R_NDS32_PLT_GOTREL_LO15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLT_GOTREL_LO15", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Low 19 bits of PLT symbol offset relative to GOT (GP). */ - HOWTO (R_NDS32_PLT_GOTREL_LO19, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_PLT_GOTREL_LO19", /* name */ - FALSE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOT_LO15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT_LO15", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOT_LO19, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT_LO19", /* name */ - FALSE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOTOFF_LO15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTOFF_LO15", /* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOTOFF_LO19, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOTOFF_LO19", /* name */ - FALSE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* GOT 15 bits offset. */ - HOWTO (R_NDS32_GOT15S2_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT15S2_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* GOT 17 bits offset. */ - HOWTO (R_NDS32_GOT17S2_RELA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_GOT17S2_RELA",/* name */ - FALSE, /* partial_inplace */ - 0x0001ffff, /* src_mask */ - 0x0001ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A 5 bit address. */ - HOWTO (R_NDS32_5_RELA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_5_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x1f, /* src_mask */ - 0x1f, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_10_UPCREL_RELA,/* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_10_UPCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x1ff, /* src_mask */ - 0x1ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_NDS32_SDA_FP7U2_RELA,/* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_SDA_FP7U2_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x0000007f, /* src_mask */ - 0x0000007f, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_WORD_9_PCREL_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_WORD_9_PCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_NDS32_25_ABS_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_25_ABS_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A relative 17 bit relocation for ifc, right shifted by 1. */ - HOWTO (R_NDS32_17IFC_PCREL_RELA, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_17IFC_PCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative unsigned 10 bit relocation for ifc, right shifted by 1. */ - HOWTO (R_NDS32_10IFCU_PCREL_RELA, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_10IFCU_PCREL_RELA", /* name */ - FALSE, /* partial_inplace */ - 0x1ff, /* src_mask */ - 0x1ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol. */ - HOWTO (R_NDS32_TLS_LE_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_LE_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_LE_LO12, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_LE_LO12", /* name */ - FALSE, /* partial_inplace */ - 0x00000fff, /* src_mask */ - 0x00000fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol. */ - HOWTO (R_NDS32_TLS_IE_HI20, /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_IE_HI20", /* name */ - FALSE, /* partial_inplace */ - 0x000fffff, /* src_mask */ - 0x000fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_IE_LO12S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_IE_LO12S2", /* name */ - FALSE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* Mark a TLS IE entry in GOT. */ - HOWTO (R_NDS32_TLS_TPOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_TPOFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - /* A 20 bit address. */ - HOWTO (R_NDS32_TLS_LE_20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_LE_20", /* name */ - FALSE, /* partial_inplace */ - 0xfffff, /* src_mask */ - 0xfffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_LE_15S0, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_LE_15S0", /* name */ - FALSE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_LE_15S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_LE_15S1", /* name */ - FALSE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_LE_15S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NDS32_TLS_LE_15S2", /* name */ - FALSE, /* partial_inplace */ - 0x7fff, /* src_mask */ - 0x7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for unconditional call sequence */ - HOWTO (R_NDS32_LONGCALL4, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGCALL4", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional call sequence. */ - HOWTO (R_NDS32_LONGCALL5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGCALL5", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional call sequence. */ - HOWTO (R_NDS32_LONGCALL6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGCALL6", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for unconditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP4, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGJUMP4", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGJUMP5", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGJUMP6", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relax hint for conditional branch sequence. */ - HOWTO (R_NDS32_LONGJUMP7, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_LONGJUMP7", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* Relocations used for relaxation. */ -static reloc_howto_type nds32_elf_relax_howto_table[] = -{ - HOWTO (R_NDS32_RELAX_ENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_RELAX_ENTRY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOT_SUFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_GOT_SUFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_GOTOFF_SUFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_GOTOFF_SUFF", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_PLT_GOT_SUFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_PLT_GOT_SUFF",/* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_MULCALL_SUFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_MULCALL_SUFF",/* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_PTR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_PTR", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_PTR_COUNT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_PTR_COUNT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_PTR_RESOLVED, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_PTR_RESOLVED",/* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_PLTBLOCK, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_PLTBLOCK", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_RELAX_REGION_BEGIN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_RELAX_REGION_BEGIN", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_RELAX_REGION_END, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_RELAX_REGION_END", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_MINUEND, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_MINUEND", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_SUBTRAHEND, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_SUBTRAHEND", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DIFF8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DIFF8", /* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DIFF16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DIFF16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DIFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DIFF32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DIFF_ULEB128, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DIFF_ULEB128",/* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_DATA, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_DATA", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TRAN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - nds32_elf_ignore_reloc,/* special_function */ - "R_NDS32_TRAN", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_LE_ADD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_TLS_LE_ADD", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_TLS_LE_LS, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_TLS_LE_LS", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_NDS32_EMPTY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - nds32_elf_ignore_reloc, /* special_function */ - "R_NDS32_EMPTY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - - -/* nds32_insertion_sort sorts an array with nmemb elements of size size. - This prototype is the same as qsort (). */ - -void -nds32_insertion_sort (void *base, size_t nmemb, size_t size, - int (*compar) (const void *lhs, const void *rhs)) -{ - char *ptr = (char *) base; - int i, j; - char *tmp = xmalloc (size); - - /* If i is less than j, i is inserted before j. - - |---- j ----- i --------------| - \ / \ / - sorted unsorted - */ - - for (i = 1; i < (int) nmemb; i++) - { - for (j = (i - 1); j >= 0; j--) - if (compar (ptr + i * size, ptr + j * size) >= 0) - break; - - j++; - - if (i == j) - continue; /* i is in order. */ - - memcpy (tmp, ptr + i * size, size); - memmove (ptr + (j + 1) * size, ptr + j * size, (i - j) * size); - memcpy (ptr + j * size, tmp, size); - } - free (tmp); -} - -/* Sort relocation by r_offset. - - We didn't use qsort () in stdlib, because quick-sort is not a stable sorting - algorithm. Relocations at the same r_offset must keep their order. - For example, RELAX_ENTRY must be the very first relocation entry. - - Currently, this function implements insertion-sort. - - FIXME: If we already sort them in assembler, why bother sort them - here again? */ - -static int -compar_reloc (const void *lhs, const void *rhs) -{ - const Elf_Internal_Rela *l = (const Elf_Internal_Rela *) lhs; - const Elf_Internal_Rela *r = (const Elf_Internal_Rela *) rhs; - - if (l->r_offset > r->r_offset) - return 1; - else if (l->r_offset == r->r_offset) - return 0; - else - return -1; -} - -/* Functions listed below are only used for old relocs. - * nds32_elf_9_pcrel_reloc - * nds32_elf_do_9_pcrel_reloc - * nds32_elf_hi20_reloc - * nds32_elf_relocate_hi20 - * nds32_elf_lo12_reloc - * nds32_elf_sda15_reloc - * nds32_elf_generic_reloc - */ - -/* Handle the R_NDS32_9_PCREL & R_NDS32_9_PCREL_RELA reloc. */ - -static bfd_reloc_status_type -nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - { - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - } - - return nds32_elf_do_9_pcrel_reloc (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - symbol->section, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -/* Utility to actually perform an R_NDS32_9_PCREL reloc. */ -#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1) - -static bfd_reloc_status_type -nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto, - asection *input_section, bfd_byte *data, - bfd_vma offset, - asection *symbol_section ATTRIBUTE_UNUSED, - bfd_vma symbol_value, bfd_vma addend) -{ - bfd_signed_vma relocation; - unsigned short x; - bfd_reloc_status_type status; - - /* Sanity check the address (offset in section). */ - if (offset > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - relocation = symbol_value + addend; - /* Make it pc relative. */ - relocation -= (input_section->output_section->vma - + input_section->output_offset); - /* These jumps mask off the lower two bits of the current address - before doing pcrel calculations. */ - relocation -= (offset & -(bfd_vma) 2); - - if (relocation < -ACCURATE_8BIT_S1 || relocation >= ACCURATE_8BIT_S1) - status = bfd_reloc_overflow; - else - status = bfd_reloc_ok; - - x = bfd_getb16 (data + offset); - - relocation >>= howto->rightshift; - relocation <<= howto->bitpos; - x = (x & ~howto->dst_mask) - | (((x & howto->src_mask) + relocation) & howto->dst_mask); - - bfd_putb16 ((bfd_vma) x, data + offset); - - return status; -} - -/* Handle the R_NDS32_HI20_[SU]LO relocs. - HI20_SLO is for the add3 and load/store with displacement instructions. - HI20 is for the or3 instruction. - For R_NDS32_HI20_SLO, the lower 16 bits are sign extended when added to - the high 16 bytes so if the lower 16 bits are negative (bit 15 == 1) then - we must add one to the high 16 bytes (which will get subtracted off when - the low 16 bits are added). - These relocs have to be done in combination with an R_NDS32_LO12 reloc - because there is a carry from the LO12 to the HI20. Here we just save - the information we need; we do the actual relocation when we see the LO12. - This code is copied from the elf32-mips.c. We also support an arbitrary - number of HI20 relocs to be associated with a single LO12 reloc. The - assembler sorts the relocs to ensure each HI20 immediately precedes its - LO12. However if there are multiple copies, the assembler may not find - the real LO12 so it picks the first one it finds. */ - -struct nds32_hi20 -{ - struct nds32_hi20 *next; - bfd_byte *addr; - bfd_vma addend; -}; - -static struct nds32_hi20 *nds32_hi20_list; - -static bfd_reloc_status_type -nds32_elf_hi20_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, - asymbol *symbol, void *data, asection *input_section, - bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - struct nds32_hi20 *n; - - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Sanity check the address (offset in section). */ - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - ret = bfd_reloc_ok; - if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) - ret = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - /* Save the information, and let LO12 do the actual relocation. */ - n = (struct nds32_hi20 *) bfd_malloc ((bfd_size_type) sizeof *n); - if (n == NULL) - return bfd_reloc_outofrange; - - n->addr = (bfd_byte *) data + reloc_entry->address; - n->addend = relocation; - n->next = nds32_hi20_list; - nds32_hi20_list = n; - - if (output_bfd != (bfd *) NULL) - reloc_entry->address += input_section->output_offset; - - return ret; -} - -/* Handle an NDS32 ELF HI20 reloc. */ - -static void -nds32_elf_relocate_hi20 (bfd *input_bfd ATTRIBUTE_UNUSED, - int type ATTRIBUTE_UNUSED, Elf_Internal_Rela *relhi, - Elf_Internal_Rela *rello, bfd_byte *contents, - bfd_vma addend) -{ - unsigned long insn; - bfd_vma addlo; - - insn = bfd_getb32 (contents + relhi->r_offset); - - addlo = bfd_getb32 (contents + rello->r_offset); - addlo &= 0xfff; - - addend += ((insn & 0xfffff) << 20) + addlo; - - insn = (insn & 0xfff00000) | ((addend >> 12) & 0xfffff); - bfd_putb32 (insn, contents + relhi->r_offset); -} - -/* Do an R_NDS32_LO12 relocation. This is a straightforward 12 bit - inplace relocation; this function exists in order to do the - R_NDS32_HI20_[SU]LO relocation described above. */ - -static bfd_reloc_status_type -nds32_elf_lo12_reloc (bfd *input_bfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (nds32_hi20_list != NULL) - { - struct nds32_hi20 *l; - - l = nds32_hi20_list; - while (l != NULL) - { - unsigned long insn; - unsigned long val; - unsigned long vallo; - struct nds32_hi20 *next; - - /* Do the HI20 relocation. Note that we actually don't need - to know anything about the LO12 itself, except where to - find the low 12 bits of the addend needed by the LO12. */ - insn = bfd_getb32 (l->addr); - vallo = bfd_getb32 ((bfd_byte *) data + reloc_entry->address); - vallo &= 0xfff; - switch (reloc_entry->howto->type) - { - case R_NDS32_LO12S3: - vallo <<= 3; - break; - - case R_NDS32_LO12S2: - vallo <<= 2; - break; - - case R_NDS32_LO12S1: - vallo <<= 1; - break; - - case R_NDS32_LO12S0: - vallo <<= 0; - break; - } - - val = ((insn & 0xfffff) << 12) + vallo; - val += l->addend; - - insn = (insn & ~(bfd_vma) 0xfffff) | ((val >> 12) & 0xfffff); - bfd_putb32 ((bfd_vma) insn, l->addr); - - next = l->next; - free (l); - l = next; - } - - nds32_hi20_list = NULL; - } - - /* Now do the LO12 reloc in the usual way. - ??? It would be nice to call bfd_elf_generic_reloc here, - but we have partial_inplace set. bfd_elf_generic_reloc will - pass the handling back to bfd_install_relocation which will install - a section relative addend which is wrong. */ - return nds32_elf_generic_reloc (input_bfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - -/* Do generic partial_inplace relocation. - This is a local replacement for bfd_elf_generic_reloc. */ - -static bfd_reloc_status_type -nds32_elf_generic_reloc (bfd *input_bfd, arelent *reloc_entry, - asymbol *symbol, void *data, asection *input_section, - bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - bfd_byte *inplace_address; - - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL && (symbol->flags & BSF_SECTION_SYM) == 0 - && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Now do the reloc in the usual way. - ??? It would be nice to call bfd_elf_generic_reloc here, - but we have partial_inplace set. bfd_elf_generic_reloc will - pass the handling back to bfd_install_relocation which will install - a section relative addend which is wrong. */ - - /* Sanity check the address (offset in section). */ - if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - ret = bfd_reloc_ok; - if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) - ret = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL) - relocation = 0; - else - relocation = symbol->value; - - /* Only do this for a final link. */ - if (output_bfd == (bfd *) NULL) - { - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - } - - relocation += reloc_entry->addend; - switch (reloc_entry->howto->type) - { - case R_NDS32_LO12S3: - relocation >>= 3; - break; - - case R_NDS32_LO12S2: - relocation >>= 2; - break; - - case R_NDS32_LO12S1: - relocation >>= 1; - break; - - case R_NDS32_LO12S0: - default: - relocation >>= 0; - break; - } - - inplace_address = (bfd_byte *) data + reloc_entry->address; - -#define DOIT(x) \ - x = ((x & ~reloc_entry->howto->dst_mask) | \ - (((x & reloc_entry->howto->src_mask) + relocation) & \ - reloc_entry->howto->dst_mask)) - - switch (reloc_entry->howto->size) - { - case 1: - { - short x = bfd_getb16 (inplace_address); - - DOIT (x); - bfd_putb16 ((bfd_vma) x, inplace_address); - } - break; - case 2: - { - unsigned long x = bfd_getb32 (inplace_address); - - DOIT (x); - bfd_putb32 ((bfd_vma) x, inplace_address); - } - break; - default: - BFD_ASSERT (0); - } - - if (output_bfd != (bfd *) NULL) - reloc_entry->address += input_section->output_offset; - - return ret; -} - -/* Handle the R_NDS32_SDA15 reloc. - This reloc is used to compute the address of objects in the small data area - and to perform loads and stores from that area. - The lower 15 bits are sign extended and added to the register specified - in the instruction, which is assumed to point to _SDA_BASE_. - - Since the lower 15 bits offset is left-shifted 0, 1 or 2 bits depending on - the access size, this must be taken care of. */ - -static bfd_reloc_status_type -nds32_elf_sda15_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, - asymbol *symbol, void *data ATTRIBUTE_UNUSED, - asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - { - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - } - - /* FIXME: not sure what to do here yet. But then again, the linker - may never call us. */ - abort (); -} - -/* nds32_elf_ignore_reloc is the special function for - relocation types which don't need to be relocated - like relaxation relocation types. - This function simply return bfd_reloc_ok when it is - invoked. */ - -static bfd_reloc_status_type -nds32_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, asection *input_section, - bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - - -/* Map BFD reloc types to NDS32 ELF reloc types. */ - -struct nds32_reloc_map_entry -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct nds32_reloc_map_entry nds32_reloc_map[] = -{ - {BFD_RELOC_NONE, R_NDS32_NONE}, - {BFD_RELOC_16, R_NDS32_16_RELA}, - {BFD_RELOC_32, R_NDS32_32_RELA}, - {BFD_RELOC_NDS32_20, R_NDS32_20_RELA}, - {BFD_RELOC_NDS32_5, R_NDS32_5_RELA}, - {BFD_RELOC_NDS32_9_PCREL, R_NDS32_9_PCREL_RELA}, - {BFD_RELOC_NDS32_WORD_9_PCREL, R_NDS32_WORD_9_PCREL_RELA}, - {BFD_RELOC_NDS32_15_PCREL, R_NDS32_15_PCREL_RELA}, - {BFD_RELOC_NDS32_17_PCREL, R_NDS32_17_PCREL_RELA}, - {BFD_RELOC_NDS32_25_PCREL, R_NDS32_25_PCREL_RELA}, - {BFD_RELOC_NDS32_10_UPCREL, R_NDS32_10_UPCREL_RELA}, - {BFD_RELOC_NDS32_HI20, R_NDS32_HI20_RELA}, - {BFD_RELOC_NDS32_LO12S3, R_NDS32_LO12S3_RELA}, - {BFD_RELOC_NDS32_LO12S2, R_NDS32_LO12S2_RELA}, - {BFD_RELOC_NDS32_LO12S1, R_NDS32_LO12S1_RELA}, - {BFD_RELOC_NDS32_LO12S0, R_NDS32_LO12S0_RELA}, - {BFD_RELOC_NDS32_LO12S0_ORI, R_NDS32_LO12S0_ORI_RELA}, - {BFD_RELOC_NDS32_SDA15S3, R_NDS32_SDA15S3_RELA}, - {BFD_RELOC_NDS32_SDA15S2, R_NDS32_SDA15S2_RELA}, - {BFD_RELOC_NDS32_SDA15S1, R_NDS32_SDA15S1_RELA}, - {BFD_RELOC_NDS32_SDA15S0, R_NDS32_SDA15S0_RELA}, - {BFD_RELOC_VTABLE_INHERIT, R_NDS32_RELA_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_NDS32_RELA_GNU_VTENTRY}, - - {BFD_RELOC_NDS32_GOT20, R_NDS32_GOT20}, - {BFD_RELOC_NDS32_9_PLTREL, R_NDS32_9_PLTREL}, - {BFD_RELOC_NDS32_25_PLTREL, R_NDS32_25_PLTREL}, - {BFD_RELOC_NDS32_COPY, R_NDS32_COPY}, - {BFD_RELOC_NDS32_GLOB_DAT, R_NDS32_GLOB_DAT}, - {BFD_RELOC_NDS32_JMP_SLOT, R_NDS32_JMP_SLOT}, - {BFD_RELOC_NDS32_RELATIVE, R_NDS32_RELATIVE}, - {BFD_RELOC_NDS32_GOTOFF, R_NDS32_GOTOFF}, - {BFD_RELOC_NDS32_GOTPC20, R_NDS32_GOTPC20}, - {BFD_RELOC_NDS32_GOT_HI20, R_NDS32_GOT_HI20}, - {BFD_RELOC_NDS32_GOT_LO12, R_NDS32_GOT_LO12}, - {BFD_RELOC_NDS32_GOT_LO15, R_NDS32_GOT_LO15}, - {BFD_RELOC_NDS32_GOT_LO19, R_NDS32_GOT_LO19}, - {BFD_RELOC_NDS32_GOTPC_HI20, R_NDS32_GOTPC_HI20}, - {BFD_RELOC_NDS32_GOTPC_LO12, R_NDS32_GOTPC_LO12}, - {BFD_RELOC_NDS32_GOTOFF_HI20, R_NDS32_GOTOFF_HI20}, - {BFD_RELOC_NDS32_GOTOFF_LO12, R_NDS32_GOTOFF_LO12}, - {BFD_RELOC_NDS32_GOTOFF_LO15, R_NDS32_GOTOFF_LO15}, - {BFD_RELOC_NDS32_GOTOFF_LO19, R_NDS32_GOTOFF_LO19}, - {BFD_RELOC_NDS32_INSN16, R_NDS32_INSN16}, - {BFD_RELOC_NDS32_LABEL, R_NDS32_LABEL}, - {BFD_RELOC_NDS32_LONGCALL1, R_NDS32_LONGCALL1}, - {BFD_RELOC_NDS32_LONGCALL2, R_NDS32_LONGCALL2}, - {BFD_RELOC_NDS32_LONGCALL3, R_NDS32_LONGCALL3}, - {BFD_RELOC_NDS32_LONGCALL4, R_NDS32_LONGCALL4}, - {BFD_RELOC_NDS32_LONGCALL5, R_NDS32_LONGCALL5}, - {BFD_RELOC_NDS32_LONGCALL6, R_NDS32_LONGCALL6}, - {BFD_RELOC_NDS32_LONGJUMP1, R_NDS32_LONGJUMP1}, - {BFD_RELOC_NDS32_LONGJUMP2, R_NDS32_LONGJUMP2}, - {BFD_RELOC_NDS32_LONGJUMP3, R_NDS32_LONGJUMP3}, - {BFD_RELOC_NDS32_LONGJUMP4, R_NDS32_LONGJUMP4}, - {BFD_RELOC_NDS32_LONGJUMP5, R_NDS32_LONGJUMP5}, - {BFD_RELOC_NDS32_LONGJUMP6, R_NDS32_LONGJUMP6}, - {BFD_RELOC_NDS32_LONGJUMP7, R_NDS32_LONGJUMP7}, - {BFD_RELOC_NDS32_LOADSTORE, R_NDS32_LOADSTORE}, - {BFD_RELOC_NDS32_9_FIXED, R_NDS32_9_FIXED_RELA}, - {BFD_RELOC_NDS32_15_FIXED, R_NDS32_15_FIXED_RELA}, - {BFD_RELOC_NDS32_17_FIXED, R_NDS32_17_FIXED_RELA}, - {BFD_RELOC_NDS32_25_FIXED, R_NDS32_25_FIXED_RELA}, - {BFD_RELOC_NDS32_PLTREL_HI20, R_NDS32_PLTREL_HI20}, - {BFD_RELOC_NDS32_PLTREL_LO12, R_NDS32_PLTREL_LO12}, - {BFD_RELOC_NDS32_PLT_GOTREL_HI20, R_NDS32_PLT_GOTREL_HI20}, - {BFD_RELOC_NDS32_PLT_GOTREL_LO12, R_NDS32_PLT_GOTREL_LO12}, - {BFD_RELOC_NDS32_PLT_GOTREL_LO15, R_NDS32_PLT_GOTREL_LO15}, - {BFD_RELOC_NDS32_PLT_GOTREL_LO19, R_NDS32_PLT_GOTREL_LO19}, - {BFD_RELOC_NDS32_PLT_GOTREL_LO20, R_NDS32_PLT_GOTREL_LO20}, - {BFD_RELOC_NDS32_SDA12S2_DP, R_NDS32_SDA12S2_DP_RELA}, - {BFD_RELOC_NDS32_SDA12S2_SP, R_NDS32_SDA12S2_SP_RELA}, - {BFD_RELOC_NDS32_LO12S2_DP, R_NDS32_LO12S2_DP_RELA}, - {BFD_RELOC_NDS32_LO12S2_SP, R_NDS32_LO12S2_SP_RELA}, - {BFD_RELOC_NDS32_SDA16S3, R_NDS32_SDA16S3_RELA}, - {BFD_RELOC_NDS32_SDA17S2, R_NDS32_SDA17S2_RELA}, - {BFD_RELOC_NDS32_SDA18S1, R_NDS32_SDA18S1_RELA}, - {BFD_RELOC_NDS32_SDA19S0, R_NDS32_SDA19S0_RELA}, - {BFD_RELOC_NDS32_SDA_FP7U2_RELA, R_NDS32_SDA_FP7U2_RELA}, - {BFD_RELOC_NDS32_DWARF2_OP1, R_NDS32_DWARF2_OP1_RELA}, - {BFD_RELOC_NDS32_DWARF2_OP2, R_NDS32_DWARF2_OP2_RELA}, - {BFD_RELOC_NDS32_DWARF2_LEB, R_NDS32_DWARF2_LEB_RELA}, - {BFD_RELOC_NDS32_UPDATE_TA, R_NDS32_UPDATE_TA_RELA}, - {BFD_RELOC_NDS32_GOT_SUFF, R_NDS32_GOT_SUFF}, - {BFD_RELOC_NDS32_GOTOFF_SUFF, R_NDS32_GOTOFF_SUFF}, - {BFD_RELOC_NDS32_GOT15S2, R_NDS32_GOT15S2_RELA}, - {BFD_RELOC_NDS32_GOT17S2, R_NDS32_GOT17S2_RELA}, - {BFD_RELOC_NDS32_PTR, R_NDS32_PTR}, - {BFD_RELOC_NDS32_PTR_COUNT, R_NDS32_PTR_COUNT}, - {BFD_RELOC_NDS32_PLT_GOT_SUFF, R_NDS32_PLT_GOT_SUFF}, - {BFD_RELOC_NDS32_PTR_RESOLVED, R_NDS32_PTR_RESOLVED}, - {BFD_RELOC_NDS32_RELAX_ENTRY, R_NDS32_RELAX_ENTRY}, - {BFD_RELOC_NDS32_MULCALL_SUFF, R_NDS32_MULCALL_SUFF}, - {BFD_RELOC_NDS32_PLTBLOCK, R_NDS32_PLTBLOCK}, - {BFD_RELOC_NDS32_RELAX_REGION_BEGIN, R_NDS32_RELAX_REGION_BEGIN}, - {BFD_RELOC_NDS32_RELAX_REGION_END, R_NDS32_RELAX_REGION_END}, - {BFD_RELOC_NDS32_MINUEND, R_NDS32_MINUEND}, - {BFD_RELOC_NDS32_SUBTRAHEND, R_NDS32_SUBTRAHEND}, - {BFD_RELOC_NDS32_EMPTY, R_NDS32_EMPTY}, - - {BFD_RELOC_NDS32_DIFF8, R_NDS32_DIFF8}, - {BFD_RELOC_NDS32_DIFF16, R_NDS32_DIFF16}, - {BFD_RELOC_NDS32_DIFF32, R_NDS32_DIFF32}, - {BFD_RELOC_NDS32_DIFF_ULEB128, R_NDS32_DIFF_ULEB128}, - {BFD_RELOC_NDS32_25_ABS, R_NDS32_25_ABS_RELA}, - {BFD_RELOC_NDS32_DATA, R_NDS32_DATA}, - {BFD_RELOC_NDS32_TRAN, R_NDS32_TRAN}, - {BFD_RELOC_NDS32_17IFC_PCREL, R_NDS32_17IFC_PCREL_RELA}, - {BFD_RELOC_NDS32_10IFCU_PCREL, R_NDS32_10IFCU_PCREL_RELA}, - {BFD_RELOC_NDS32_TLS_LE_HI20, R_NDS32_TLS_LE_HI20}, - {BFD_RELOC_NDS32_TLS_LE_LO12, R_NDS32_TLS_LE_LO12}, - {BFD_RELOC_NDS32_TLS_LE_ADD, R_NDS32_TLS_LE_ADD}, - {BFD_RELOC_NDS32_TLS_LE_LS, R_NDS32_TLS_LE_LS}, - {BFD_RELOC_NDS32_TLS_IE_HI20, R_NDS32_TLS_IE_HI20}, - {BFD_RELOC_NDS32_TLS_IE_LO12S2, R_NDS32_TLS_IE_LO12S2}, - {BFD_RELOC_NDS32_TLS_TPOFF, R_NDS32_TLS_TPOFF}, - {BFD_RELOC_NDS32_TLS_LE_20, R_NDS32_TLS_LE_20}, - {BFD_RELOC_NDS32_TLS_LE_15S0, R_NDS32_TLS_LE_15S0}, - {BFD_RELOC_NDS32_TLS_LE_15S1, R_NDS32_TLS_LE_15S1}, - {BFD_RELOC_NDS32_TLS_LE_15S2, R_NDS32_TLS_LE_15S2}, -}; - -/* Patch tag. */ - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (nds32_elf_howto_table); i++) - if (nds32_elf_howto_table[i].name != NULL - && strcasecmp (nds32_elf_howto_table[i].name, r_name) == 0) - return &nds32_elf_howto_table[i]; - - for (i = 0; i < ARRAY_SIZE (nds32_elf_relax_howto_table); i++) - if (nds32_elf_relax_howto_table[i].name != NULL - && strcasecmp (nds32_elf_relax_howto_table[i].name, r_name) == 0) - return &nds32_elf_relax_howto_table[i]; - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_table_lookup (enum elf_nds32_reloc_type code) -{ - if (code < R_NDS32_RELAX_ENTRY) - { - BFD_ASSERT (code < ARRAY_SIZE (nds32_elf_howto_table)); - return &nds32_elf_howto_table[code]; - } - else - { - BFD_ASSERT ((size_t) (code - R_NDS32_RELAX_ENTRY) - < ARRAY_SIZE (nds32_elf_relax_howto_table)); - return &nds32_elf_relax_howto_table[code - R_NDS32_RELAX_ENTRY]; - } -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (nds32_reloc_map); i++) - { - if (nds32_reloc_map[i].bfd_reloc_val == code) - return bfd_elf32_bfd_reloc_type_table_lookup - (nds32_reloc_map[i].elf_reloc_val); - } - - return NULL; -} - -/* Set the howto pointer for an NDS32 ELF reloc. */ - -static void -nds32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - enum elf_nds32_reloc_type r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type > R_NDS32_GNU_VTENTRY) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid NDS32 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type); -} - -static void -nds32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - BFD_ASSERT ((ELF32_R_TYPE (dst->r_info) == R_NDS32_NONE) - || ((ELF32_R_TYPE (dst->r_info) > R_NDS32_GNU_VTENTRY) - && (ELF32_R_TYPE (dst->r_info) < R_NDS32_max))); - cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (dst->r_info)); -} - -/* Support for core dump NOTE sections. - Reference to include/linux/elfcore.h in Linux. */ - -static bfd_boolean -nds32_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - case 0x114: - /* Linux/NDS32 32-bit, ABI1 */ - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 200; - break; - - case 0xfc: - /* Linux/NDS32 32-bit */ - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 176; - break; - - default: - return FALSE; - } - - /* Make a ".reg" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -nds32_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - case 124: - /* Linux/NDS32 */ - - /* __kernel_uid_t, __kernel_gid_t are short on NDS32 platform. */ - elf_tdata (abfd)->core->program = - _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); - elf_tdata (abfd)->core->command = - _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); - break; - - default: - return FALSE; - } - - /* Note that for some reason, a spurious space is tacked - onto the end of the args in some (at least one anyway) - implementations, so strip it off if it exists. */ - { - char *command = elf_tdata (abfd)->core->command; - int n = strlen (command); - - if (0 < n && command[n - 1] == ' ') - command[n - 1] = '\0'; - } - - return TRUE; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We must handle the special NDS32 section numbers here. - We also keep watching for whether we need to create the sdata special - linker sections. */ - -static bfd_boolean -nds32_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, bfd_vma *valp) -{ - switch (sym->st_shndx) - { - case SHN_COMMON: - /* Common symbols less than the GP size are automatically - treated as SHN_MIPS_SCOMMON symbols. */ - if (sym->st_size > elf_gp_size (abfd) - || ELF_ST_TYPE (sym->st_info) == STT_TLS) - break; - - /* st_value is the alignemnt constraint. - That might be its actual size if it is an array or structure. */ - switch (sym->st_value) - { - case 1: - *secp = bfd_make_section_old_way (abfd, ".scommon_b"); - break; - case 2: - *secp = bfd_make_section_old_way (abfd, ".scommon_h"); - break; - case 4: - *secp = bfd_make_section_old_way (abfd, ".scommon_w"); - break; - case 8: - *secp = bfd_make_section_old_way (abfd, ".scommon_d"); - break; - default: - return TRUE; - } - - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - - -/* This function can figure out the best location for a base register to access - data relative to this base register - INPUT: - sda_d0: size of first DOUBLE WORD data section - sda_w0: size of first WORD data section - sda_h0: size of first HALF WORD data section - sda_b : size of BYTE data section - sda_hi: size of second HALF WORD data section - sda_w1: size of second WORD data section - sda_d1: size of second DOUBLE WORD data section - OUTPUT: - offset (always positive) from the beginning of sda_d0 if OK - a negative error value if fail - NOTE: - these 7 sections have to be located back to back if exist - a pass in 0 value for non-existing section */ - -/* Due to the interpretation of simm15 field of load/store depending on - data accessing size, the organization of base register relative data shall - like the following figure - ------------------------------------------- - | DOUBLE WORD sized data (range +/- 128K) - ------------------------------------------- - | WORD sized data (range +/- 64K) - ------------------------------------------- - | HALF WORD sized data (range +/- 32K) - ------------------------------------------- - | BYTE sized data (range +/- 16K) - ------------------------------------------- - | HALF WORD sized data (range +/- 32K) - ------------------------------------------- - | WORD sized data (range +/- 64K) - ------------------------------------------- - | DOUBLE WORD sized data (range +/- 128K) - ------------------------------------------- - Its base register shall be set to access these data freely. */ - -/* We have to figure out the SDA_BASE value, so that we can adjust the - symbol value correctly. We look up the symbol _SDA_BASE_ in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static asection *sda_rela_sec = NULL; - -#define SDA_SECTION_NUM 10 - -static bfd_reloc_status_type -nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info, - bfd_vma *psb, bfd_boolean add_symbol) -{ - int relax_fp_as_gp; - struct elf_nds32_link_hash_table *table; - struct bfd_link_hash_entry *h, *h2; - long unsigned int total = 0; - - h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", FALSE, FALSE, TRUE); - if (!h || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)) - { - asection *first = NULL, *final = NULL, *temp; - bfd_vma sda_base; - /* The first section must be 4-byte aligned to promise _SDA_BASE_ being - 4 byte-aligned. Therefore, it has to set the first section ".data" - 4 byte-aligned. */ - static const char sec_name[SDA_SECTION_NUM][10] = - { - ".data", ".got", ".sdata_d", ".sdata_w", ".sdata_h", ".sdata_b", - ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d" - }; - size_t i = 0; - - if (output_bfd->sections == NULL) - { - *psb = elf_gp (output_bfd); - return bfd_reloc_ok; - } - - /* Get the first and final section. */ - while (i < sizeof (sec_name) / sizeof (sec_name [0])) - { - temp = bfd_get_section_by_name (output_bfd, sec_name[i]); - if (temp && !first && (temp->size != 0 || temp->rawsize != 0)) - first = temp; - if (temp && (temp->size != 0 || temp->rawsize != 0)) - final = temp; - - /* Summarize the sections in order to check if joining .bss. */ - if (temp && temp->size != 0) - total += temp->size; - else if (temp && temp->rawsize != 0) - total += temp->rawsize; - - i++; - } - - /* Check .bss size. */ - temp = bfd_get_section_by_name (output_bfd, ".bss"); - if (temp) - { - if (temp->size != 0) - total += temp->size; - else if (temp->rawsize != 0) - total += temp->rawsize; - - if (total < 0x80000) - { - if (!first && (temp->size != 0 || temp->rawsize != 0)) - first = temp; - if ((temp->size != 0 || temp->rawsize != 0)) - final = temp; - } - } - - if (first && final) - { - /* The middle of data region. */ - sda_base = final->vma / 2 + final->rawsize / 2 + first->vma / 2; - - /* Find the section sda_base located. */ - i = 0; - while (i < sizeof (sec_name) / sizeof (sec_name [0])) - { - final = bfd_get_section_by_name (output_bfd, sec_name[i]); - if (final && (final->size != 0 || final->rawsize != 0) - && sda_base >= final->vma) - { - first = final; - i++; - } - else - break; - } - } - else - { - /* There is not any data section in output bfd, and set _SDA_BASE_ in - first output section. */ - first = output_bfd->sections; - while (first && first->size == 0 && first->rawsize == 0) - first = first->next; - if (!first) - { - *psb = elf_gp (output_bfd); - return bfd_reloc_ok; - } - sda_base = first->vma + first->rawsize; - } - - sda_base -= first->vma; - sda_base = sda_base & (~7); - - if (!_bfd_generic_link_add_one_symbol - (info, output_bfd, "_SDA_BASE_", BSF_GLOBAL | BSF_WEAK, first, - (bfd_vma) sda_base, (const char *) NULL, FALSE, - get_elf_backend_data (output_bfd)->collect, &h)) - return FALSE; - - sda_rela_sec = first; - - table = nds32_elf_hash_table (info); - relax_fp_as_gp = table->relax_fp_as_gp; - if (relax_fp_as_gp) - { - h2 = bfd_link_hash_lookup (info->hash, FP_BASE_NAME, - FALSE, FALSE, FALSE); - /* Define a weak FP_BASE_NAME here to prevent the undefined symbol. - And set FP equal to SDA_BASE to do relaxation for - la $fp, _FP_BASE_. */ - if (!_bfd_generic_link_add_one_symbol - (info, output_bfd, FP_BASE_NAME, BSF_GLOBAL | BSF_WEAK, - first, (bfd_vma) sda_base, (const char *) NULL, - FALSE, get_elf_backend_data (output_bfd)->collect, &h2)) - return FALSE; - } - } - - if (add_symbol) - { - if (h) - { - /* Now set gp. */ - elf_gp (output_bfd) = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - } - else - { - _bfd_error_handler (_("error: Can't find symbol: _SDA_BASE_.")); - return bfd_reloc_dangerous; - } - } - - *psb = h->u.def.value + h->u.def.section->output_section->vma - + h->u.def.section->output_offset; - return bfd_reloc_ok; -} - - -/* Return size of a PLT entry. */ -#define elf_nds32_sizeof_plt(info) PLT_ENTRY_SIZE - - -/* Create an entry in an nds32 ELF linker hash table. */ - -static struct bfd_hash_entry * -nds32_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_nds32_link_hash_entry *ret; - - ret = (struct elf_nds32_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = (struct elf_nds32_link_hash_entry *) - bfd_hash_allocate (table, sizeof (struct elf_nds32_link_hash_entry)); - - if (ret == NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = (struct elf_nds32_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string); - - if (ret != NULL) - { - struct elf_nds32_link_hash_entry *eh; - - eh = (struct elf_nds32_link_hash_entry *) ret; - eh->dyn_relocs = NULL; - eh->tls_type = GOT_UNKNOWN; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an nds32 ELF linker hash table. */ - -static struct bfd_link_hash_table * -nds32_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_nds32_link_hash_table *ret; - - bfd_size_type amt = sizeof (struct elf_nds32_link_hash_table); - - ret = (struct elf_nds32_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - /* patch tag. */ - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - nds32_elf_link_hash_newfunc, - sizeof (struct elf_nds32_link_hash_entry), - NDS32_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_nds32_link_hash_table *htab; - flagword flags, pltflags; - register asection *s; - const struct elf_backend_data *bed; - int ptralign = 2; /* 32-bit */ - - bed = get_elf_backend_data (abfd); - - htab = nds32_elf_hash_table (info); - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - pltflags = flags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~(SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section (abfd, ".plt"); - htab->root.splt = s; - if (s == NULL - || !bfd_set_section_flags (abfd, s, pltflags) - || !bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - - if (bed->want_plt_sym) - { - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - struct bfd_link_hash_entry *bh = NULL; - struct elf_link_hash_entry *h; - - if (!(_bfd_generic_link_add_one_symbol - (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, - (bfd_vma) 0, (const char *) NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - - if (bfd_link_pic (info) && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = bfd_make_section (abfd, - bed->default_use_rela_p ? ".rela.plt" : ".rel.plt"); - htab->root.srelplt = s; - if (s == NULL - || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || !bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (htab->root.sgot == NULL && !_bfd_elf_create_got_section (abfd, info)) - return FALSE; - - { - const char *secname; - char *relname; - flagword secflags; - asection *sec; - - for (sec = abfd->sections; sec; sec = sec->next) - { - secflags = bfd_get_section_flags (abfd, sec); - if ((secflags & (SEC_DATA | SEC_LINKER_CREATED)) - || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS)) - continue; - secname = bfd_get_section_name (abfd, sec); - relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6); - strcpy (relname, ".rela"); - strcat (relname, secname); - if (bfd_get_section_by_name (abfd, secname)) - continue; - s = bfd_make_section (abfd, relname); - if (s == NULL - || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || !bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - if (bed->want_dynbss) - { - /* The .dynbss section is a place to put symbols which are defined - by dynamic objects, are referenced by regular objects, and are - not functions. We must allocate space for them in the process - image and use a R_*_COPY reloc to tell the dynamic linker to - initialize them at run time. The linker script puts the .dynbss - section into the .bss section of the final image. */ - s = bfd_make_section (abfd, ".dynbss"); - htab->sdynbss = s; - if (s == NULL - || !bfd_set_section_flags (abfd, s, SEC_ALLOC | SEC_LINKER_CREATED)) - return FALSE; - /* The .rel[a].bss section holds copy relocs. This section is not - normally needed. We need to create it here, though, so that the - linker will map it to an output section. We can't just create it - only if we need it, because we will not know whether we need it - until we have seen all the input files, and the first time the - main linker code calls BFD after examining all the input files - (size_dynamic_sections) the input sections have already been - mapped to the output sections. If the section turns out not to - be needed, we can discard it later. We will never need this - section when generating a shared object, since they do not use - copy relocs. */ - if (!bfd_link_pic (info)) - { - s = bfd_make_section (abfd, (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss")); - htab->srelbss = s; - if (s == NULL - || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || !bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ -static void -nds32_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_nds32_link_hash_entry *edir, *eind; - - edir = (struct elf_nds32_link_hash_entry *) dir; - eind = (struct elf_nds32_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - if (ind->root.type == bfd_link_hash_indirect) - abort (); - - /* Add reloc counts against the weak sym to the strong sym - list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL;) - { - struct elf_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = elf32_nds32_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* Adjust a symbol defined by a dynamic object and referenced by a - regular object. The current definition is in some section of the - dynamic object, but we're not including those sections. We have to - change the definition to something the rest of the link can - understand. */ - -static bfd_boolean -nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_nds32_link_hash_table *htab; - bfd *dynobj; - asection *s; - unsigned int power_of_two; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic && h->ref_regular && !h->def_regular))); - - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC || h->needs_plt) - { - if (!bfd_link_pic (info) - && !h->def_dynamic - && !h->ref_dynamic - && h->root.type != bfd_link_hash_undefweak - && h->root.type != bfd_link_hash_undefined) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a PCREL - reloc instead. */ - h->plt.offset = (bfd_vma) - 1; - h->needs_plt = 0; - } - - return TRUE; - } - else - h->plt.offset = (bfd_vma) - 1; - - /* If this is a weak symbol, and there is a real definition, the - processor independent code will have arranged for us to see the - real definition first, and we can just use the same value. */ - if (h->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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 (0 && info->nocopyreloc) - { - h->non_got_ref = 0; - return TRUE; - } - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (0 && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = nds32_elf_hash_table (info); - s = htab->sdynbss; - BFD_ASSERT (s != NULL); - - /* We must generate a R_NDS32_COPY reloc to tell the dynamic linker - to copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - asection *srel; - - srel = htab->srelbss; - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 3) - power_of_two = 3; - - /* Apply the required alignment. */ - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > bfd_get_section_alignment (dynobj, s)) - { - if (!bfd_set_section_alignment (dynobj, s, power_of_two)) - return FALSE; - } - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - - return TRUE; -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct elf_nds32_link_hash_table *htab; - struct elf_nds32_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - if (h->root.type == bfd_link_hash_warning) - /* When warning symbols are created, they **replace** the "real" - entry in the hash table, thus we never get to see the real - symbol in a hash traversal. So look at it now. */ - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - info = (struct bfd_link_info *) inf; - htab = nds32_elf_hash_table (info); - - eh = (struct elf_nds32_link_hash_entry *) h; - - if (htab->root.dynamic_sections_created && h->plt.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 && !h->forced_local) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->root.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 (!bfd_link_pic (info) && !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->root.sgotplt->size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) - 1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) - 1; - h->needs_plt = 0; - } - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = elf32_nds32_hash_entry (h)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 && !h->forced_local) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->root.sgot; - h->got.offset = s->size; - - if (tls_type == GOT_UNKNOWN) - abort (); - else if (tls_type == GOT_NORMAL - || tls_type == GOT_TLS_IE) - /* Need a GOT slot. */ - s->size += 4; - - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) - 1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (h->def_regular && (h->forced_local || info->symbolic)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 && !h->forced_local) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - - keep:; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_nds32_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = nds32_elf_hash_table (info); - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_section_by_name (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - p != NULL; p = p->next) - { - if (!bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - s = htab->root.sgot; - srel = htab->root.srelgot; - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += 4; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); - } - else - *local_got = (bfd_vma) - 1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (void *) info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->root.splt) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (s == htab->root.sgot) - { - got_size += s->size; - } - else if (s == htab->root.sgotplt) - { - got_size += s->size; - } - else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0) - { - if (s->size != 0 && s != htab->root.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - else - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is mostly to handle .rela.bss and - .rela.plt. We must create both sections in - create_dynamic_sections, because they must be created - before the linker maps input sections to output - sections. The linker does that before - adjust_dynamic_symbol is called, and it is that - function which decides whether anything needs to go - into these sections. */ - s->flags |= SEC_EXCLUDE; - continue; - } - - /* Allocate memory for the section contents. We use bfd_zalloc - here in case unused entries are not reclaimed before the - section's contents are written out. This should not happen, - but this way if it does, we get a R_NDS32_NONE reloc instead - of garbage. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - - if (htab->root.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in nds32_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (!bfd_link_pic (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->root.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, - (void *) info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -static bfd_reloc_status_type -nds32_relocate_contents (reloc_howto_type *howto, bfd *input_bfd, - bfd_vma relocation, bfd_byte *location) -{ - int size; - bfd_vma x = 0; - bfd_reloc_status_type flag; - unsigned int rightshift = howto->rightshift; - unsigned int bitpos = howto->bitpos; - - /* If the size is negative, negate RELOCATION. This isn't very - general. */ - if (howto->size < 0) - relocation = -relocation; - - /* Get the value we are going to relocate. */ - size = bfd_get_reloc_size (howto); - switch (size) - { - default: - abort (); - break; - case 0: - return bfd_reloc_ok; - case 2: - x = bfd_getb16 (location); - break; - case 4: - x = bfd_getb32 (location); - break; - } - - /* Check for overflow. FIXME: We may drop bits during the addition - which we don't check for. We must either check at every single - operation, which would be tedious, or we must do the computations - in a type larger than bfd_vma, which would be inefficient. */ - flag = bfd_reloc_ok; - if (howto->complain_on_overflow != complain_overflow_dont) - { - bfd_vma addrmask, fieldmask, signmask, ss; - bfd_vma a, b, sum; - - /* Get the values to be added together. For signed and unsigned - relocations, we assume that all values should be truncated to - the size of an address. For bitfields, all the bits matter. - See also bfd_check_overflow. */ - fieldmask = N_ONES (howto->bitsize); - signmask = ~fieldmask; - addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; - a = (relocation & addrmask) >> rightshift; - b = (x & howto->src_mask & addrmask) >> bitpos; - - switch (howto->complain_on_overflow) - { - case complain_overflow_signed: - /* If any sign bits are set, all sign bits must be set. - That is, A must be a valid negative address after - shifting. */ - signmask = ~(fieldmask >> 1); - /* Fall through. */ - - case complain_overflow_bitfield: - /* Much like the signed check, but for a field one bit - wider. We allow a bitfield to represent numbers in the - range -2**n to 2**n-1, where n is the number of bits in the - field. Note that when bfd_vma is 32 bits, a 32-bit reloc - can't overflow, which is exactly what we want. */ - ss = a & signmask; - if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) - flag = bfd_reloc_overflow; - - /* We only need this next bit of code if the sign bit of B - is below the sign bit of A. This would only happen if - SRC_MASK had fewer bits than BITSIZE. Note that if - SRC_MASK has more bits than BITSIZE, we can get into - trouble; we would need to verify that B is in range, as - we do for A above. */ - ss = ((~howto->src_mask) >> 1) & howto->src_mask; - ss >>= bitpos; - - /* Set all the bits above the sign bit. */ - b = (b ^ ss) - ss; - - /* Now we can do the addition. */ - sum = a + b; - - /* See if the result has the correct sign. Bits above the - sign bit are junk now; ignore them. If the sum is - positive, make sure we did not have all negative inputs; - if the sum is negative, make sure we did not have all - positive inputs. The test below looks only at the sign - bits, and it really just - SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM) - - We mask with addrmask here to explicitly allow an address - wrap-around. The Linux kernel relies on it, and it is - the only way to write assembler code which can run when - loaded at a location 0x80000000 away from the location at - which it is linked. */ - if (((~(a ^ b)) & (a ^ sum)) & signmask & addrmask) - flag = bfd_reloc_overflow; - - break; - - case complain_overflow_unsigned: - /* Checking for an unsigned overflow is relatively easy: - trim the addresses and add, and trim the result as well. - Overflow is normally indicated when the result does not - fit in the field. However, we also need to consider the - case when, e.g., fieldmask is 0x7fffffff or smaller, an - input is 0x80000000, and bfd_vma is only 32 bits; then we - will get sum == 0, but there is an overflow, since the - inputs did not fit in the field. Instead of doing a - separate test, we can check for this by or-ing in the - operands when testing for the sum overflowing its final - field. */ - sum = (a + b) & addrmask; - if ((a | b | sum) & signmask) - flag = bfd_reloc_overflow; - break; - - default: - abort (); - } - } - - /* Put RELOCATION in the right bits. */ - relocation >>= (bfd_vma) rightshift; - relocation <<= (bfd_vma) bitpos; - - /* Add RELOCATION to the right bits of X. */ - /* FIXME : 090616 - Because the relaxation may generate duplicate relocation at one address, - an addition to immediate in the instruction may cause the relocation added - several times. - This bug should be fixed in assembler, but a check is also needed here. */ - if (howto->partial_inplace) - x = ((x & ~howto->dst_mask) - | (((x & howto->src_mask) + relocation) & howto->dst_mask)); - else - x = ((x & ~howto->dst_mask) | ((relocation) & howto->dst_mask)); - - - /* Put the relocated value back in the object file. */ - switch (size) - { - default: - case 0: - case 1: - case 8: - abort (); - break; - case 2: - bfd_putb16 (x, location); - break; - case 4: - bfd_putb32 (x, location); - break; - } - - return flag; -} - -static bfd_reloc_status_type -nds32_elf_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd, - asection *input_section, bfd_byte *contents, - bfd_vma address, bfd_vma value, bfd_vma addend) -{ - bfd_vma relocation; - - /* Sanity check the address. */ - if (address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - /* This function assumes that we are dealing with a basic relocation - against a symbol. We want to compute the value of the symbol to - relocate to. This is just VALUE, the value of the symbol, plus - ADDEND, any addend associated with the reloc. */ - relocation = value + addend; - - /* If the relocation is PC relative, we want to set RELOCATION to - the distance between the symbol (currently in RELOCATION) and the - location we are relocating. Some targets (e.g., i386-aout) - arrange for the contents of the section to be the negative of the - offset of the location within the section; for such targets - pcrel_offset is FALSE. Other targets (e.g., m88kbcs or ELF) - simply leave the contents of the section as zero; for such - targets pcrel_offset is TRUE. If pcrel_offset is FALSE we do not - need to subtract out the offset of the location within the - section (which is just ADDRESS). */ - if (howto->pc_relative) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset); - if (howto->pcrel_offset) - relocation -= address; - } - - return nds32_relocate_contents (howto, input_bfd, relocation, - contents + address); -} - -static bfd_boolean -nds32_elf_output_symbol_hook (struct bfd_link_info *info, - const char *name, - Elf_Internal_Sym *elfsym ATTRIBUTE_UNUSED, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - const char *source; - FILE *sym_ld_script = NULL; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - sym_ld_script = table->sym_ld_script; - if (!sym_ld_script) - return TRUE; - - if (!h || !name || *name == '\0') - return TRUE; - - if (input_sec->flags & SEC_EXCLUDE) - return TRUE; - - if (!check_start_export_sym) - { - fprintf (sym_ld_script, "SECTIONS\n{\n"); - check_start_export_sym = 1; - } - - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - if (!h->root.u.def.section->output_section) - return TRUE; - - if (bfd_is_const_section (input_sec)) - source = input_sec->name; - else - source = input_sec->owner->filename; - - fprintf (sym_ld_script, "\t%s = 0x%08lx;\t /* %s */\n", - h->root.root.string, - (long) (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset), source); - } - - return TRUE; -} - -/* Relocate an NDS32/D ELF section. - There is some attempt to make this function usable for many architectures, - both for RELA and REL type relocs, if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjust the section contents as - necessary, and (if using Rela relocs and generating a - relocatable output file) adjusting the reloc addend as - necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_vma -dtpoff_base (struct bfd_link_info *info) -{ - /* If tls_sec is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_sec == NULL) - return 0; - return elf_hash_table (info)->tls_sec->vma; -} - -static bfd_boolean -nds32_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - bfd_boolean ret = TRUE; /* Assume success. */ - int align = 0; - bfd_reloc_status_type r; - const char *errmsg = NULL; - bfd_vma gp; - struct elf_nds32_link_hash_table *htab; - bfd *dynobj; - bfd_vma *local_got_offsets; - asection *sgot, *splt, *sreloc; - bfd_vma high_address; - struct elf_nds32_link_hash_table *table; - int eliminate_gc_relocs; - bfd_vma fpbase_addr; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - htab = nds32_elf_hash_table (info); - high_address = bfd_get_section_limit (input_bfd, input_section); - - dynobj = htab->root.dynobj; - local_got_offsets = elf_local_got_offsets (input_bfd); - - sgot = htab->root.sgot; - splt = htab->root.splt; - sreloc = NULL; - - rel = relocs; - relend = relocs + input_section->reloc_count; - - table = nds32_elf_hash_table (info); - eliminate_gc_relocs = table->eliminate_gc_relocs; - /* By this time, we can adjust the value of _SDA_BASE_. */ - if ((!bfd_link_relocatable (info))) - { - is_SDA_BASE_set = 1; - r = nds32_elf_final_sda_base (output_bfd, info, &gp, TRUE); - if (r != bfd_reloc_ok) - return FALSE; - } - - if (is_ITB_BASE_set == 0) - { - /* Set the _ITB_BASE_. */ - if (!nds32_elf_ex9_itb_base (info)) - { - _bfd_error_handler (_("%B: error: Cannot set _ITB_BASE_"), - output_bfd); - bfd_set_error (bfd_error_bad_value); - } - } - - if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) - if (!nds32_elf_ifc_reloc ()) - _bfd_error_handler (_("error: IFC relocation error.")); - - /* Relocation for .ex9.itable. */ - if (table->target_optimize & NDS32_RELAX_EX9_ON - || (table->ex9_import_file && table->update_ex9_table)) - nds32_elf_ex9_reloc_jmp (info); - - /* Use gp as fp to prevent truncated fit. Because in relaxation time - the fp value is set as gp, and it has be reverted for instruction - setting fp. */ - fpbase_addr = elf_gp (output_bfd); - - for (rel = relocs; rel < relend; rel++) - { - enum elf_nds32_reloc_type r_type; - reloc_howto_type *howto = NULL; - unsigned long r_symndx; - struct elf_link_hash_entry *h = NULL; - Elf_Internal_Sym *sym = NULL; - asection *sec; - bfd_vma relocation; - - /* We can't modify r_addend here as elf_link_input_bfd has an assert to - ensure it's zero (we use REL relocs, not RELA). Therefore this - should be assigning zero to `addend', but for clarity we use - `r_addend'. */ - - bfd_vma addend = rel->r_addend; - bfd_vma offset = rel->r_offset; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type >= R_NDS32_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: error: unknown relocation type %d."), - input_bfd, r_type); - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; - } - - if (r_type == R_NDS32_GNU_VTENTRY - || r_type == R_NDS32_GNU_VTINHERIT - || r_type == R_NDS32_NONE - || r_type == R_NDS32_RELA_GNU_VTENTRY - || r_type == R_NDS32_RELA_GNU_VTINHERIT - || (r_type >= R_NDS32_INSN16 && r_type <= R_NDS32_25_FIXED_RELA) - || r_type == R_NDS32_DATA - || r_type == R_NDS32_TRAN - || (r_type >= R_NDS32_LONGCALL4 && r_type <= R_NDS32_LONGJUMP7)) - continue; - - /* If we enter the fp-as-gp region. Resolve the address - of best fp-base. */ - if (ELF32_R_TYPE (rel->r_info) == R_NDS32_RELAX_REGION_BEGIN - && (rel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) - { - int dist; - - /* Distance to relocation of best fp-base is encoded in R_SYM. */ - dist = rel->r_addend >> 16; - fpbase_addr = calculate_memory_address (input_bfd, rel + dist, - local_syms, symtab_hdr); - } - else if (ELF32_R_TYPE (rel->r_info) == R_NDS32_RELAX_REGION_END - && (rel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) - { - fpbase_addr = elf_gp (output_bfd); - } - - if (((r_type >= R_NDS32_DWARF2_OP1_RELA - && r_type <= R_NDS32_DWARF2_LEB_RELA) - || r_type >= R_NDS32_RELAX_ENTRY) && !bfd_link_relocatable (info)) - continue; - - howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type); - r_symndx = ELF32_R_SYM (rel->r_info); - - /* This is a final link. */ - sym = NULL; - sec = NULL; - h = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - addend = rel->r_addend; - } - else - { - /* External symbol. */ - bfd_boolean warned, ignored, unresolved_reloc; - int symndx = r_symndx - symtab_hdr->sh_info; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, h, sec, - relocation, unresolved_reloc, warned, - ignored); - - /* la $fp, _FP_BASE_ is per-function (region). - Handle it specially. */ - switch ((int) r_type) - { - case R_NDS32_SDA19S0_RELA: - case R_NDS32_SDA15S0_RELA: - case R_NDS32_20_RELA: - if (strcmp (elf_sym_hashes (input_bfd)[symndx]->root.root.string, - FP_BASE_NAME) == 0) - { - relocation = fpbase_addr; - break; - } - } - - } - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset + sym->st_value; - - continue; - } - - /* Sanity check the address. */ - if (offset > high_address) - { - r = bfd_reloc_outofrange; - goto check_reloc; - } - - if ((r_type >= R_NDS32_DWARF2_OP1_RELA - && r_type <= R_NDS32_DWARF2_LEB_RELA) - || r_type >= R_NDS32_RELAX_ENTRY) - continue; - - switch ((int) r_type) - { - case R_NDS32_GOTOFF: - /* Relocation is relative to the start of the global offset - table (for ld24 rx, #uimm24), e.g. access at label+addend - - ld24 rx. #label@GOTOFF + addend - sub rx, r12. */ - case R_NDS32_GOTOFF_HI20: - case R_NDS32_GOTOFF_LO12: - case R_NDS32_GOTOFF_LO15: - case R_NDS32_GOTOFF_LO19: - BFD_ASSERT (sgot != NULL); - - relocation -= elf_gp (output_bfd); - break; - - case R_NDS32_9_PLTREL: - case R_NDS32_25_PLTREL: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* The native assembler will generate a 25_PLTREL reloc - for a local symbol if you assemble a call from one - section to another when using -K pic. */ - if (h == NULL) - break; - - if (h->forced_local) - break; - - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - if (h->plt.offset == (bfd_vma) - 1) - break; - - relocation = (splt->output_section->vma - + splt->output_offset + h->plt.offset); - break; - - case R_NDS32_PLT_GOTREL_HI20: - case R_NDS32_PLT_GOTREL_LO12: - case R_NDS32_PLT_GOTREL_LO15: - case R_NDS32_PLT_GOTREL_LO19: - case R_NDS32_PLT_GOTREL_LO20: - if (h == NULL || h->forced_local || h->plt.offset == (bfd_vma) - 1) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - relocation -= elf_gp (output_bfd); - break; - } - - relocation = (splt->output_section->vma - + splt->output_offset + h->plt.offset); - - relocation -= elf_gp (output_bfd); - break; - - case R_NDS32_PLTREL_HI20: - case R_NDS32_PLTREL_LO12: - - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* The native assembler will generate a 25_PLTREL reloc - for a local symbol if you assemble a call from one - section to another when using -K pic. */ - if (h == NULL) - break; - - if (h->forced_local) - break; - - if (h->plt.offset == (bfd_vma) - 1) - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - - if (splt == NULL) - break; - - relocation = (splt->output_section->vma - + splt->output_offset - + h->plt.offset + 4) - - (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - break; - - case R_NDS32_GOTPC20: - /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation - ld24 rx,#_GLOBAL_OFFSET_TABLE_ */ - relocation = elf_gp (output_bfd); - break; - - case R_NDS32_GOTPC_HI20: - case R_NDS32_GOTPC_LO12: - { - /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation - bl .+4 - seth rx,#high(_GLOBAL_OFFSET_TABLE_) - or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) - or - bl .+4 - seth rx,#shigh(_GLOBAL_OFFSET_TABLE_) - add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4) - */ - relocation = elf_gp (output_bfd); - relocation -= (input_section->output_section->vma - + input_section->output_offset + rel->r_offset); - break; - } - - case R_NDS32_GOT20: - /* Fall through. */ - case R_NDS32_GOT_HI20: - case R_NDS32_GOT_LO12: - case R_NDS32_GOT_LO15: - case R_NDS32_GOT_LO19: - /* Relocation is to the entry for this symbol in the global - offset table. */ - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - bfd_boolean dyn; - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) - 1); - dyn = htab->root.dynamic_sections_created; - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) && h->def_regular)) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - h->got.offset |= 1; - } - } - relocation = sgot->output_section->vma + sgot->output_offset + off - - elf_gp (output_bfd); - } - else - { - bfd_vma off; - bfd_byte *loc; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) - 1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_NDS32_RELATIVE reloc - for the dynamic linker. */ - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (elf_gp (output_bfd) - + sgot->output_offset + off); - outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += - srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - ++srelgot->reloc_count; - } - local_got_offsets[r_symndx] |= 1; - } - relocation = sgot->output_section->vma + sgot->output_offset + off - - elf_gp (output_bfd); - } - - break; - - case R_NDS32_16_RELA: - case R_NDS32_20_RELA: - case R_NDS32_5_RELA: - case R_NDS32_32_RELA: - case R_NDS32_9_PCREL_RELA: - case R_NDS32_WORD_9_PCREL_RELA: - case R_NDS32_10_UPCREL_RELA: - case R_NDS32_15_PCREL_RELA: - case R_NDS32_17_PCREL_RELA: - case R_NDS32_25_PCREL_RELA: - case R_NDS32_HI20_RELA: - case R_NDS32_LO12S3_RELA: - case R_NDS32_LO12S2_RELA: - case R_NDS32_LO12S2_DP_RELA: - case R_NDS32_LO12S2_SP_RELA: - case R_NDS32_LO12S1_RELA: - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S0_ORI_RELA: - if (bfd_link_pic (info) && r_symndx != 0 - && (input_section->flags & SEC_ALLOC) != 0 - && (eliminate_gc_relocs == 0 - || (sec && (sec->flags & SEC_EXCLUDE) == 0)) - && ((r_type != R_NDS32_9_PCREL_RELA - && r_type != R_NDS32_WORD_9_PCREL_RELA - && r_type != R_NDS32_10_UPCREL_RELA - && r_type != R_NDS32_15_PCREL_RELA - && r_type != R_NDS32_17_PCREL_RELA - && r_type != R_NDS32_25_PCREL_RELA - && !(r_type == R_NDS32_32_RELA - && strcmp (input_section->name, ".eh_frame") == 0)) - || (h != NULL && h->dynindx != -1 - && (!info->symbolic || !h->def_regular)))) - { - Elf_Internal_Rela outrel; - bfd_boolean skip, relocate; - bfd_byte *loc; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - if (sreloc == NULL) - { - const char *name; - - name = bfd_elf_string_from_elf_section - (input_bfd, elf_elfheader (input_bfd)->e_shstrndx, - elf_section_data (input_section)->rela.hdr->sh_name); - if (name == NULL) - return FALSE; - - BFD_ASSERT (strncmp (name, ".rela", 5) == 0 - && strcmp (bfd_get_section_name (input_bfd, - input_section), - name + 5) == 0); - - sreloc = bfd_get_section_by_name (dynobj, name); - BFD_ASSERT (sreloc != NULL); - } - - skip = FALSE; - relocate = FALSE; - - outrel.r_offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) - 1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) - 2) - skip = TRUE, relocate = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if (r_type == R_NDS32_17_PCREL_RELA - || r_type == R_NDS32_15_PCREL_RELA - || r_type == R_NDS32_25_PCREL_RELA) - { - BFD_ASSERT (h != NULL && h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (h == NULL - || ((info->symbolic || h->dynindx == -1) - && h->def_regular)) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - ++sreloc->reloc_count; - - /* If this reloc is against an external symbol, we do - not want to fiddle with the addend. Otherwise, we - need to include the symbol value so that it becomes - an addend for the dynamic reloc. */ - if (!relocate) - continue; - } - break; - - case R_NDS32_25_ABS_RELA: - if (bfd_link_pic (info)) - { - _bfd_error_handler - (_("%B: warning: cannot deal R_NDS32_25_ABS_RELA in shared " - "mode."), input_bfd); - return FALSE; - } - break; - - case R_NDS32_9_PCREL: - r = nds32_elf_do_9_pcrel_reloc (input_bfd, howto, input_section, - contents, offset, - sec, relocation, addend); - goto check_reloc; - - case R_NDS32_HI20: - { - Elf_Internal_Rela *lorel; - - /* We allow an arbitrary number of HI20 relocs before the - LO12 reloc. This permits gcc to emit the HI and LO relocs - itself. */ - for (lorel = rel + 1; - (lorel < relend - && ELF32_R_TYPE (lorel->r_info) == R_NDS32_HI20); lorel++) - continue; - if (lorel < relend - && (ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S3 - || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S2 - || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S1 - || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S0)) - { - nds32_elf_relocate_hi20 (input_bfd, r_type, rel, lorel, - contents, relocation + addend); - r = bfd_reloc_ok; - } - else - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, offset, relocation, - addend); - } - - goto check_reloc; - - case R_NDS32_GOT17S2_RELA: - case R_NDS32_GOT15S2_RELA: - { - bfd_vma off; - - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) - 1); - - dyn = htab->root.dynamic_sections_created; - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL - (dyn, bfd_link_pic (info), h) - || (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; - } - } - } - else - { - bfd_byte *loc; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) - 1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_NDS32_RELATIVE reloc - for the dynamic linker. */ - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (elf_gp (output_bfd) - + sgot->output_offset + off); - outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += - srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - ++srelgot->reloc_count; - } - local_got_offsets[r_symndx] |= 1; - } - } - relocation = sgot->output_section->vma + sgot->output_offset + off - - elf_gp (output_bfd); - } - if (relocation & align) - { - /* Incorrect alignment. */ - _bfd_error_handler - (_("%B: warning: unaligned access to GOT entry."), input_bfd); - ret = FALSE; - r = bfd_reloc_dangerous; - goto check_reloc; - } - break; - - case R_NDS32_SDA16S3_RELA: - case R_NDS32_SDA15S3_RELA: - case R_NDS32_SDA15S3: - align = 0x7; - goto handle_sda; - - case R_NDS32_SDA17S2_RELA: - case R_NDS32_SDA15S2_RELA: - case R_NDS32_SDA12S2_SP_RELA: - case R_NDS32_SDA12S2_DP_RELA: - case R_NDS32_SDA15S2: - case R_NDS32_SDA_FP7U2_RELA: - align = 0x3; - goto handle_sda; - - case R_NDS32_SDA18S1_RELA: - case R_NDS32_SDA15S1_RELA: - case R_NDS32_SDA15S1: - align = 0x1; - goto handle_sda; - - case R_NDS32_SDA19S0_RELA: - case R_NDS32_SDA15S0_RELA: - case R_NDS32_SDA15S0: - { - align = 0x0; -handle_sda: - BFD_ASSERT (sec != NULL); - - /* If the symbol is in the abs section, the out_bfd will be null. - This happens when the relocation has a symbol@GOTOFF. */ - r = nds32_elf_final_sda_base (output_bfd, info, &gp, FALSE); - if (r != bfd_reloc_ok) - { - _bfd_error_handler - (_("%B: warning: relocate SDA_BASE failed."), input_bfd); - ret = FALSE; - goto check_reloc; - } - - /* At this point `relocation' contains the object's - address. */ - if (r_type == R_NDS32_SDA_FP7U2_RELA) - { - relocation -= fpbase_addr; - } - else - relocation -= gp; - /* Now it contains the offset from _SDA_BASE_. */ - - /* Make sure alignment is correct. */ - - if (relocation & align) - { - /* Incorrect alignment. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A): warning: unaligned small data access of type %d."), - input_bfd, input_section, r_type); - ret = FALSE; - goto check_reloc; - } - } - - break; - case R_NDS32_17IFC_PCREL_RELA: - case R_NDS32_10IFCU_PCREL_RELA: - /* do nothing */ - break; - - case R_NDS32_TLS_LE_HI20: - case R_NDS32_TLS_LE_LO12: - case R_NDS32_TLS_LE_20: - case R_NDS32_TLS_LE_15S0: - case R_NDS32_TLS_LE_15S1: - case R_NDS32_TLS_LE_15S2: - if (elf_hash_table (info)->tls_sec != NULL) - relocation -= (elf_hash_table (info)->tls_sec->vma + TP_OFFSET); - break; - case R_NDS32_TLS_IE_HI20: - case R_NDS32_TLS_IE_LO12S2: - { - /* Relocation is to the entry for this symbol in the global - offset table. */ - unsigned int tls_type; - asection *srelgot; - Elf_Internal_Rela outrel; - bfd_vma off; - bfd_byte *loc; - int indx = 0; - - BFD_ASSERT (sgot != NULL); - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) - 1); - dyn = htab->root.dynamic_sections_created; - tls_type = ((struct elf_nds32_link_hash_entry *) h)->tls_type; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - indx = h->dynindx; - } - else - { - /* Never happen currently. */ - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) - 1); - - off = local_got_offsets[r_symndx]; - - tls_type = elf32_nds32_local_got_tls_type (input_bfd)[r_symndx]; - } - relocation = sgot->output_section->vma + sgot->output_offset + off; - - if (r_type == R_NDS32_TLS_IE_LO12S2) - break; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_boolean need_relocs = FALSE; - srelgot = htab->root.srelgot; - if ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - { - need_relocs = TRUE; - BFD_ASSERT (srelgot != NULL); - } - if (tls_type & GOT_TLS_IE) - { - if (need_relocs) - { - if (h->dynindx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = - ELF32_R_INFO (h->dynindx, R_NDS32_TLS_TPOFF); - - loc = srelgot->contents; - loc += - srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - ++srelgot->reloc_count; - } - else - bfd_put_32 (output_bfd, h->root.u.def.value - TP_OFFSET, - sgot->contents + off); - } - } - } - break; - - /* DON'T fall through. */ - - default: - /* OLD_NDS32_RELOC. */ - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, offset, relocation, addend); - goto check_reloc; - } - - switch ((int) r_type) - { - case R_NDS32_20_RELA: - case R_NDS32_5_RELA: - case R_NDS32_9_PCREL_RELA: - case R_NDS32_WORD_9_PCREL_RELA: - case R_NDS32_10_UPCREL_RELA: - case R_NDS32_15_PCREL_RELA: - case R_NDS32_17_PCREL_RELA: - case R_NDS32_25_PCREL_RELA: - case R_NDS32_25_ABS_RELA: - case R_NDS32_HI20_RELA: - case R_NDS32_LO12S3_RELA: - case R_NDS32_LO12S2_RELA: - case R_NDS32_LO12S2_DP_RELA: - case R_NDS32_LO12S2_SP_RELA: - case R_NDS32_LO12S1_RELA: - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S0_ORI_RELA: - case R_NDS32_SDA16S3_RELA: - case R_NDS32_SDA17S2_RELA: - case R_NDS32_SDA18S1_RELA: - case R_NDS32_SDA19S0_RELA: - case R_NDS32_SDA15S3_RELA: - case R_NDS32_SDA15S2_RELA: - case R_NDS32_SDA12S2_DP_RELA: - case R_NDS32_SDA12S2_SP_RELA: - case R_NDS32_SDA15S1_RELA: - case R_NDS32_SDA15S0_RELA: - case R_NDS32_SDA_FP7U2_RELA: - case R_NDS32_9_PLTREL: - case R_NDS32_25_PLTREL: - case R_NDS32_GOT20: - case R_NDS32_GOT_HI20: - case R_NDS32_GOT_LO12: - case R_NDS32_GOT_LO15: - case R_NDS32_GOT_LO19: - case R_NDS32_GOT15S2_RELA: - case R_NDS32_GOT17S2_RELA: - case R_NDS32_GOTPC20: - case R_NDS32_GOTPC_HI20: - case R_NDS32_GOTPC_LO12: - case R_NDS32_GOTOFF: - case R_NDS32_GOTOFF_HI20: - case R_NDS32_GOTOFF_LO12: - case R_NDS32_GOTOFF_LO15: - case R_NDS32_GOTOFF_LO19: - case R_NDS32_PLTREL_HI20: - case R_NDS32_PLTREL_LO12: - case R_NDS32_PLT_GOTREL_HI20: - case R_NDS32_PLT_GOTREL_LO12: - case R_NDS32_PLT_GOTREL_LO15: - case R_NDS32_PLT_GOTREL_LO19: - case R_NDS32_PLT_GOTREL_LO20: - case R_NDS32_17IFC_PCREL_RELA: - case R_NDS32_10IFCU_PCREL_RELA: - case R_NDS32_TLS_LE_HI20: - case R_NDS32_TLS_LE_LO12: - case R_NDS32_TLS_IE_HI20: - case R_NDS32_TLS_IE_LO12S2: - case R_NDS32_TLS_LE_20: - case R_NDS32_TLS_LE_15S0: - case R_NDS32_TLS_LE_15S1: - case R_NDS32_TLS_LE_15S2: - /* Instruction related relocs must handle endian properly. */ - /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER. */ - r = nds32_elf_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - - default: - /* All other relocs can use default handler. */ - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - } - -check_reloc: - - if (r != bfd_reloc_ok) - { - /* FIXME: This should be generic enough to go in a utility. */ - const char *name; - - if (h != NULL) - name = h->root.root.string; - else - { - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - if (errmsg != NULL) - goto common_error; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, offset, TRUE); - break; - - case bfd_reloc_outofrange: - errmsg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - errmsg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - errmsg = _("internal error: dangerous error"); - goto common_error; - - default: - errmsg = _("internal error: unknown error"); - /* Fall through. */ - - common_error: - (*info->callbacks->warning) (info, errmsg, name, input_bfd, - input_section, offset); - break; - } - } - } - - return ret; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, - struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) -{ - struct elf_nds32_link_hash_table *htab; - bfd_byte *loc; - - htab = nds32_elf_hash_table (info); - - if (h->plt.offset != (bfd_vma) - 1) - { - asection *splt; - asection *sgot; - asection *srela; - - bfd_vma plt_index; - bfd_vma got_offset; - bfd_vma local_plt_offset; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srela = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; - - /* Get the offset into the .got table of the entry that - corresponds to this function. Each .got entry is 4 bytes. - The first three are reserved. */ - got_offset = (plt_index + 3) * 4; - - /* Fill in the entry in the procedure linkage table. */ - if (!bfd_link_pic (info)) - { - unsigned long insn; - - insn = PLT_ENTRY_WORD0 + (((sgot->output_section->vma - + sgot->output_offset + got_offset) >> 12) - & 0xfffff); - bfd_putb32 (insn, splt->contents + h->plt.offset); - - insn = PLT_ENTRY_WORD1 + (((sgot->output_section->vma - + sgot->output_offset + got_offset) & 0x0fff) - >> 2); - bfd_putb32 (insn, splt->contents + h->plt.offset + 4); - - insn = PLT_ENTRY_WORD2; - bfd_putb32 (insn, splt->contents + h->plt.offset + 8); - - insn = PLT_ENTRY_WORD3 + (plt_index & 0x7ffff); - bfd_putb32 (insn, splt->contents + h->plt.offset + 12); - - insn = PLT_ENTRY_WORD4 - + (((unsigned int) ((-(h->plt.offset + 16)) >> 1)) & 0xffffff); - bfd_putb32 (insn, splt->contents + h->plt.offset + 16); - local_plt_offset = 12; - } - else - { - /* sda_base must be set at this time. */ - unsigned long insn; - long offset; - - /* FIXME, sda_base is 65536, it will damage opcode. */ - /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */ - offset = sgot->output_section->vma + sgot->output_offset + got_offset - - elf_gp (output_bfd); - insn = PLT_PIC_ENTRY_WORD0 + ((offset >> 12) & 0xfffff); - bfd_putb32 (insn, splt->contents + h->plt.offset); - - insn = PLT_PIC_ENTRY_WORD1 + (offset & 0xfff); - bfd_putb32 (insn, splt->contents + h->plt.offset + 4); - - insn = PLT_PIC_ENTRY_WORD2; - bfd_putb32 (insn, splt->contents + h->plt.offset + 8); - - insn = PLT_PIC_ENTRY_WORD3; - bfd_putb32 (insn, splt->contents + h->plt.offset + 12); - - insn = PLT_PIC_ENTRY_WORD4 + (plt_index & 0x7fffff); - bfd_putb32 (insn, splt->contents + h->plt.offset + 16); - - insn = PLT_PIC_ENTRY_WORD5 - + (((unsigned int) ((-(h->plt.offset + 20)) >> 1)) & 0xffffff); - bfd_putb32 (insn, splt->contents + h->plt.offset + 20); - - local_plt_offset = 16; - } - - /* Fill in the entry in the global offset table, - so it will fall through to the next instruction for the first time. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma + splt->output_offset - + h->plt.offset + local_plt_offset), - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_NDS32_JMP_SLOT); - rela.r_addend = 0; - loc = srela->contents; - loc += plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - if (!h->ref_regular_nonweak) - sym->st_value = 0; - } - } - - if (h->got.offset != (bfd_vma) - 1) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the global offset table. - Set it up. */ - - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset + (h->got.offset & ~1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic - || h->dynindx == -1 || h->forced_local) && h->def_regular) - { - rela.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - BFD_ASSERT ((h->got.offset & 1) == 0); - bfd_put_32 (output_bfd, (bfd_vma) 0, - sgot->contents + h->got.offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_NDS32_GLOB_DAT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++srela->reloc_count; - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - - /* This symbols needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_section_by_name (h->root.u.def.section->owner, ".rela.bss"); - BFD_ASSERT (s != NULL); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_NDS32_COPY); - rela.r_addend = 0; - loc = s->contents; - loc += s->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++s->reloc_count; - } - - /* Mark some specially defined symbols as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - - -/* Finish up the dynamic sections. */ - -static bfd_boolean -nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - struct elf_nds32_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - asection *sgot; - - htab = nds32_elf_hash_table (info); - dynobj = htab->root.dynobj; - - sgot = htab->root.sgotplt; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sgot != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = htab->root.sgotplt; - goto get_vma; - case DT_JMPREL: - s = htab->root.srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; - if (splt && splt->size > 0) - { - if (bfd_link_pic (info)) - { - unsigned long insn; - long offset; - - /* FIXME, sda_base is 65536, it will damage opcode. */ - /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */ - offset = sgot->output_section->vma + sgot->output_offset + 4 - - elf_gp (output_bfd); - insn = PLT0_PIC_ENTRY_WORD0 | ((offset >> 12) & 0xfffff); - bfd_putb32 (insn, splt->contents); - - /* insn = PLT0_PIC_ENTRY_WORD0 | (((8 - sda_base) >> 2) & 0x7fff) ; */ - /* here has a typo? */ - insn = PLT0_PIC_ENTRY_WORD1 | (offset & 0xfff); - bfd_putb32 (insn, splt->contents + 4); - - insn = PLT0_PIC_ENTRY_WORD2; - bfd_putb32 (insn, splt->contents + 8); - - insn = PLT0_PIC_ENTRY_WORD3; - bfd_putb32 (insn, splt->contents + 12); - - insn = PLT0_PIC_ENTRY_WORD4; - bfd_putb32 (insn, splt->contents + 16); - - insn = PLT0_PIC_ENTRY_WORD5; - bfd_putb32 (insn, splt->contents + 20); - } - else - { - unsigned long insn; - unsigned long addr; - - /* addr = .got + 4 */ - addr = sgot->output_section->vma + sgot->output_offset + 4; - insn = PLT0_ENTRY_WORD0 | ((addr >> 12) & 0xfffff); - bfd_putb32 (insn, splt->contents); - - insn = PLT0_ENTRY_WORD1 | (addr & 0x0fff); - bfd_putb32 (insn, splt->contents + 4); - - insn = PLT0_ENTRY_WORD2; - bfd_putb32 (insn, splt->contents + 8); - - insn = PLT0_ENTRY_WORD3; - bfd_putb32 (insn, splt->contents + 12); - - insn = PLT0_ENTRY_WORD4; - bfd_putb32 (insn, splt->contents + 16); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot && sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - return TRUE; -} - - -/* Set the right machine number. */ - -static bfd_boolean -nds32_elf_object_p (bfd *abfd) -{ - static unsigned int cur_arch = 0; - - if (E_N1_ARCH != (elf_elfheader (abfd)->e_flags & EF_NDS_ARCH)) - { - /* E_N1_ARCH is a wild card, so it is set only when no others exist. */ - cur_arch = (elf_elfheader (abfd)->e_flags & EF_NDS_ARCH); - } - - switch (cur_arch) - { - default: - case E_N1_ARCH: - bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1); - break; - case E_N1H_ARCH: - bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h); - break; - case E_NDS_ARCH_STAR_V2_0: - bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h_v2); - break; - case E_NDS_ARCH_STAR_V3_0: - bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h_v3); - break; - case E_NDS_ARCH_STAR_V3_M: - bfd_default_set_arch_mach (abfd, bfd_arch_nds32, bfd_mach_n1h_v3m); - break; - } - - return TRUE; -} - -/* Store the machine number in the flags field. */ - -static void -nds32_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - static unsigned int cur_mach = 0; - - if (bfd_mach_n1 != bfd_get_mach (abfd)) - { - cur_mach = bfd_get_mach (abfd); - } - - switch (cur_mach) - { - case bfd_mach_n1: - /* Only happen when object is empty, since the case is abandon. */ - val = E_N1_ARCH; - val |= E_NDS_ABI_AABI; - val |= E_NDS32_ELF_VER_1_4; - break; - case bfd_mach_n1h: - val = E_N1H_ARCH; - break; - case bfd_mach_n1h_v2: - val = E_NDS_ARCH_STAR_V2_0; - break; - case bfd_mach_n1h_v3: - val = E_NDS_ARCH_STAR_V3_0; - break; - case bfd_mach_n1h_v3m: - val = E_NDS_ARCH_STAR_V3_M; - break; - default: - val = 0; - break; - } - - elf_elfheader (abfd)->e_flags &= ~EF_NDS_ARCH; - elf_elfheader (abfd)->e_flags |= val; -} - -/* Function to keep NDS32 specific file flags. */ - -static bfd_boolean -nds32_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -static unsigned int -convert_e_flags (unsigned int e_flags, unsigned int arch) -{ - if ((e_flags & EF_NDS_ARCH) == E_NDS_ARCH_STAR_V0_9) - { - /* From 0.9 to 1.0. */ - e_flags = (e_flags & (~EF_NDS_ARCH)) | E_NDS_ARCH_STAR_V1_0; - - /* Invert E_NDS32_HAS_NO_MAC_INST. */ - e_flags ^= E_NDS32_HAS_NO_MAC_INST; - if (arch == E_NDS_ARCH_STAR_V1_0) - { - /* Done. */ - return e_flags; - } - } - - /* From 1.0 to 2.0. */ - e_flags = (e_flags & (~EF_NDS_ARCH)) | E_NDS_ARCH_STAR_V2_0; - - /* Clear E_NDS32_HAS_MFUSR_PC_INST. */ - e_flags &= ~E_NDS32_HAS_MFUSR_PC_INST; - - /* Invert E_NDS32_HAS_NO_MAC_INST. */ - e_flags ^= E_NDS32_HAS_NO_MAC_INST; - return e_flags; -} - -static bfd_boolean -nds32_check_vec_size (bfd *ibfd) -{ - static unsigned int nds32_vec_size = 0; - - asection *sec_t = NULL; - bfd_byte *contents = NULL; - - sec_t = bfd_get_section_by_name (ibfd, ".nds32_e_flags"); - - if (sec_t && sec_t->size >= 4) - { - /* Get vec_size in file. */ - unsigned int flag_t; - - nds32_get_section_contents (ibfd, sec_t, &contents, TRUE); - flag_t = bfd_get_32 (ibfd, contents); - - /* The value could only be 4 or 16. */ - - if (!nds32_vec_size) - /* Set if not set yet. */ - nds32_vec_size = (flag_t & 0x3); - else if (nds32_vec_size != (flag_t & 0x3)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: ISR vector size mismatch" - " with previous modules, previous %u-byte, current %u-byte"), - ibfd, - nds32_vec_size == 1 ? 4 : nds32_vec_size == 2 ? 16 : 0xffffffff, - (flag_t & 0x3) == 1 ? 4 : (flag_t & 0x3) == 2 ? 16 : 0xffffffff); - return FALSE; - } - else - /* Only keep the first vec_size section. */ - sec_t->flags |= SEC_EXCLUDE; - } - - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -nds32_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - flagword out_16regs; - flagword in_no_mac; - flagword out_no_mac; - flagword in_16regs; - flagword out_version; - flagword in_version; - flagword out_fpu_config; - flagword in_fpu_config; - - /* TODO: Revise to use object-attributes instead. */ - if (!nds32_check_vec_size (ibfd)) - return FALSE; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (bfd_little_endian (ibfd) != bfd_little_endian (obfd)) - { - _bfd_error_handler - (_("%B: warning: Endian mismatch with previous modules."), ibfd); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - in_version = elf_elfheader (ibfd)->e_flags & EF_NDS32_ELF_VERSION; - if (in_version == E_NDS32_ELF_VER_1_2) - { - _bfd_error_handler - (_("%B: warning: Older version of object file encountered, " - "Please recompile with current tool chain."), ibfd); - } - - /* We may need to merge V1 and V2 arch object files to V2. */ - if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH) - != (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)) - { - /* Need to convert version. */ - if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH) - == E_NDS_ARCH_STAR_RESERVED) - { - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - } - else if ((elf_elfheader (obfd)->e_flags & EF_NDS_ARCH) == E_NDS_ARCH_STAR_V0_9 - || (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH) - > (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)) - { - elf_elfheader (obfd)->e_flags = - convert_e_flags (elf_elfheader (obfd)->e_flags, - (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)); - } - else - { - elf_elfheader (ibfd)->e_flags = - convert_e_flags (elf_elfheader (ibfd)->e_flags, - (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)); - } - } - - /* Extract some flags. */ - in_flags = elf_elfheader (ibfd)->e_flags - & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION - | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF)); - - /* The following flags need special treatment. */ - in_16regs = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_REDUCED_REGS; - in_no_mac = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_NO_MAC_INST; - in_fpu_config = elf_elfheader (ibfd)->e_flags & E_NDS32_FPU_REG_CONF; - - /* Extract some flags. */ - out_flags = elf_elfheader (obfd)->e_flags - & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION - | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF)); - - /* The following flags need special treatment. */ - out_16regs = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_REDUCED_REGS; - out_no_mac = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_NO_MAC_INST; - out_fpu_config = elf_elfheader (obfd)->e_flags & E_NDS32_FPU_REG_CONF; - out_version = elf_elfheader (obfd)->e_flags & EF_NDS32_ELF_VERSION; - if (!elf_flags_init (obfd)) - { - /* If the input is the default architecture then do not - bother setting the flags for the output architecture, - instead allow future merges to do this. If no future - merges ever set these flags then they will retain their - unitialised values, which surprise surprise, correspond - to the default values. */ - if (bfd_get_arch_info (ibfd)->the_default) - return TRUE; - - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - { - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd)); - } - - return TRUE; - } - - /* Check flag compatibility. */ - if ((in_flags & EF_NDS_ABI) != (out_flags & EF_NDS_ABI)) - { - _bfd_error_handler - (_("%B: error: ABI mismatch with previous modules."), ibfd); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if ((in_flags & EF_NDS_ARCH) != (out_flags & EF_NDS_ARCH)) - { - if (((in_flags & EF_NDS_ARCH) != E_N1_ARCH)) - { - _bfd_error_handler - (_("%B: error: Instruction set mismatch with previous modules."), ibfd); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - /* When linking with V1.2 and V1.3 objects together the output is V1.2. - and perf ext1 and DIV are mergerd to perf ext1. */ - if (in_version == E_NDS32_ELF_VER_1_2 || out_version == E_NDS32_ELF_VER_1_2) - { - elf_elfheader (obfd)->e_flags = - (in_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) - | (out_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) - | (((in_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) - ? E_NDS32_HAS_EXT_INST : 0) - | (((out_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST))) - ? E_NDS32_HAS_EXT_INST : 0) - | (in_16regs & out_16regs) | (in_no_mac & out_no_mac) - | ((in_version > out_version) ? out_version : in_version); - } - else - { - if (in_version != out_version) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: Incompatible elf-versions %s and %s."), - ibfd, nds32_elfver_strtab[out_version], - nds32_elfver_strtab[in_version]); - - elf_elfheader (obfd)->e_flags = in_flags | out_flags - | (in_16regs & out_16regs) | (in_no_mac & out_no_mac) - | (in_fpu_config > out_fpu_config ? in_fpu_config : out_fpu_config) - | (in_version > out_version ? out_version : in_version); - } - - return TRUE; -} - -/* Display the flags field. */ - -static bfd_boolean -nds32_elf_print_private_bfd_data (bfd *abfd, void *ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - _bfd_elf_print_private_bfd_data (abfd, ptr); - - fprintf (file, _("private flags = %lx"), elf_elfheader (abfd)->e_flags); - - switch (elf_elfheader (abfd)->e_flags & EF_NDS_ARCH) - { - default: - case E_N1_ARCH: - fprintf (file, _(": n1 instructions")); - break; - case E_N1H_ARCH: - fprintf (file, _(": n1h instructions")); - break; - } - - fputc ('\n', file); - - return TRUE; -} - -static unsigned int -nds32_elf_action_discarded (asection *sec) -{ - - if (strncmp - (".gcc_except_table", sec->name, sizeof (".gcc_except_table") - 1) == 0) - return 0; - - return _bfd_elf_default_action_discarded (sec); -} - -static asection * -nds32_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, - Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_NDS32_GNU_VTINHERIT: - case R_NDS32_GNU_VTENTRY: - case R_NDS32_RELA_GNU_VTINHERIT: - case R_NDS32_RELA_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - struct elf_nds32_link_hash_table *htab; - bfd *dynobj; - asection *sreloc = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = - sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym); - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; - - htab = nds32_elf_hash_table (info); - dynobj = htab->root.dynobj; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - enum elf_nds32_reloc_type r_type; - struct elf_link_hash_entry *h; - unsigned long r_symndx; - int tls_type, old_tls_type; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - /* Some relocs require a global offset table. We create - got section here, since these relocation need got section - and it is not created yet. */ - if (htab->root.sgot == NULL) - { - switch (r_type) - { - case R_NDS32_GOT_HI20: - case R_NDS32_GOT_LO12: - case R_NDS32_GOT_LO15: - case R_NDS32_GOT_LO19: - case R_NDS32_GOT17S2_RELA: - case R_NDS32_GOT15S2_RELA: - case R_NDS32_GOTOFF: - case R_NDS32_GOTOFF_HI20: - case R_NDS32_GOTOFF_LO12: - case R_NDS32_GOTOFF_LO15: - case R_NDS32_GOTOFF_LO19: - case R_NDS32_GOTPC20: - case R_NDS32_GOTPC_HI20: - case R_NDS32_GOTPC_LO12: - case R_NDS32_GOT20: - case R_NDS32_TLS_IE_HI20: - case R_NDS32_TLS_IE_LO12S2: - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - break; - - default: - break; - } - } - - switch ((int) r_type) - { - case R_NDS32_GOT_HI20: - case R_NDS32_GOT_LO12: - case R_NDS32_GOT_LO15: - case R_NDS32_GOT_LO19: - case R_NDS32_GOT20: - case R_NDS32_TLS_IE_HI20: - case R_NDS32_TLS_IE_LO12S2: - switch (r_type) - { - case R_NDS32_TLS_IE_HI20: - case R_NDS32_TLS_IE_LO12S2: - tls_type = GOT_TLS_IE; - break; - default: - tls_type = GOT_NORMAL; - break; - } - if (h != NULL) - { - old_tls_type = elf32_nds32_hash_entry (h)->tls_type; - h->got.refcount += 1; - } - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local - symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = (bfd_signed_vma *) bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - local_got_refcounts[r_symndx] += 1; - old_tls_type = elf32_nds32_local_got_tls_type (abfd)[r_symndx]; - } - - /* We will already have issued an error message if there - is a TLS/non-TLS mismatch, based on the symbol - type. So just combine any TLS types needed. */ - if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL - && tls_type != GOT_NORMAL) - tls_type |= old_tls_type; - - if (old_tls_type != tls_type) - { - if (h != NULL) - elf32_nds32_hash_entry (h)->tls_type = tls_type; - else - elf32_nds32_local_got_tls_type (abfd)[r_symndx] = tls_type; - } - break; - case R_NDS32_9_PLTREL: - case R_NDS32_25_PLTREL: - case R_NDS32_PLTREL_HI20: - case R_NDS32_PLTREL_LO12: - case R_NDS32_PLT_GOTREL_HI20: - case R_NDS32_PLT_GOTREL_LO12: - case R_NDS32_PLT_GOTREL_LO15: - case R_NDS32_PLT_GOTREL_LO19: - case R_NDS32_PLT_GOTREL_LO20: - - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - if (h == NULL) - continue; - - if (h->forced_local) - break; - - elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL; - h->needs_plt = 1; - h->plt.refcount += 1; - break; - - case R_NDS32_16_RELA: - case R_NDS32_20_RELA: - case R_NDS32_5_RELA: - case R_NDS32_32_RELA: - case R_NDS32_HI20_RELA: - case R_NDS32_LO12S3_RELA: - case R_NDS32_LO12S2_RELA: - case R_NDS32_LO12S2_DP_RELA: - case R_NDS32_LO12S2_SP_RELA: - case R_NDS32_LO12S1_RELA: - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S0_ORI_RELA: - case R_NDS32_SDA16S3_RELA: - case R_NDS32_SDA17S2_RELA: - case R_NDS32_SDA18S1_RELA: - case R_NDS32_SDA19S0_RELA: - case R_NDS32_SDA15S3_RELA: - case R_NDS32_SDA15S2_RELA: - case R_NDS32_SDA12S2_DP_RELA: - case R_NDS32_SDA12S2_SP_RELA: - case R_NDS32_SDA15S1_RELA: - case R_NDS32_SDA15S0_RELA: - case R_NDS32_SDA_FP7U2_RELA: - case R_NDS32_15_PCREL_RELA: - case R_NDS32_17_PCREL_RELA: - case R_NDS32_25_PCREL_RELA: - - if (h != NULL && !bfd_link_pic (info)) - { - h->non_got_ref = 1; - h->plt.refcount += 1; - } - - /* If we are creating a shared library, and this is a reloc against - a global symbol, or a non PC relative reloc against a local - symbol, then we need to copy the reloc into the shared library. - However, if we are linking with -Bsymbolic, we do not need to - copy a reloc against a global symbol which is defined in an - object we are including in the link (i.e., DEF_REGULAR is set). - At this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set later - (it is never cleared). We account for that possibility below by - storing information in the dyn_relocs field of the hash table - entry. A similar situation occurs when creating shared libraries - and symbol visibility changes render the symbol local. - - If on the other hand, we are creating an executable, we may need - to keep relocations for symbols satisfied by a dynamic library - if we manage to avoid copy relocs for the symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && ((r_type != R_NDS32_25_PCREL_RELA - && r_type != R_NDS32_15_PCREL_RELA - && r_type != R_NDS32_17_PCREL_RELA - && !(r_type == R_NDS32_32_RELA - && strcmp (sec->name, ".eh_frame") == 0)) - || (h != NULL - && (!info->symbolic - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (!bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - - /* When creating a shared object, we must copy these - relocs into the output file. We create a reloc - section in dynobj and make room for the reloc. */ - if (sreloc == NULL) - { - const char *name; - - name = bfd_elf_string_from_elf_section - (abfd, elf_elfheader (abfd)->e_shstrndx, - elf_section_data (sec)->rela.hdr->sh_name); - if (name == NULL) - return FALSE; - - BFD_ASSERT (strncmp (name, ".rela", 5) == 0 - && strcmp (bfd_get_section_name (abfd, sec), - name + 5) == 0); - - sreloc = bfd_get_section_by_name (dynobj, name); - if (sreloc == NULL) - { - flagword flags; - - sreloc = bfd_make_section (dynobj, name); - flags = (SEC_HAS_CONTENTS | SEC_READONLY - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; - if (sreloc == NULL - || !bfd_set_section_flags (dynobj, sreloc, flags) - || !bfd_set_section_alignment (dynobj, sreloc, 2)) - return FALSE; - - elf_section_type (sreloc) = SHT_RELA; - } - elf_section_data (sec)->sreloc = sreloc; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf_nds32_link_hash_entry *) h)->dyn_relocs; - else - { - asection *s; - void *vpp; - - Elf_Internal_Sym *isym; - isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); - if (isym == NULL) - return FALSE; - - /* Track dynamic relocs needed for local syms too. */ - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - return FALSE; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof (*p); - p = (struct elf_dyn_relocs *) bfd_alloc (dynobj, amt); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - if (ELF32_R_TYPE (rel->r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (rel->r_info) == R_NDS32_15_PCREL_RELA - || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA) - p->pc_count += 1; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_NDS32_RELA_GNU_VTINHERIT: - case R_NDS32_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_NDS32_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - case R_NDS32_RELA_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* Write VAL in uleb128 format to P, returning a pointer to the - following byte. - This code is copied from elf-attr.c. */ - -static bfd_byte * -write_uleb128 (bfd_byte *p, unsigned int val) -{ - bfd_byte c; - do - { - c = val & 0x7f; - val >>= 7; - if (val) - c |= 0x80; - *(p++) = c; - } - while (val); - return p; -} - -static bfd_signed_vma -calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr, - int *pic_ext_target) -{ - bfd_signed_vma foff; - bfd_vma symval, addend; - asection *sym_sec; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isym; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value + sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - bfd *owner; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - return 0; - owner = h->root.u.def.section->owner; - if (owner && (elf_elfheader (owner)->e_flags & E_NDS32_HAS_PIC)) - *pic_ext_target = 1; - - if (h->root.u.def.section->flags & SEC_MERGE) - { - sym_sec = h->root.u.def.section; - symval = _bfd_merged_section_offset (abfd, &sym_sec, - elf_section_data (sym_sec)->sec_info, - h->root.u.def.value); - symval = symval + sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - addend = irel->r_addend; - - foff = (symval + addend - - (irel->r_offset + sec->output_section->vma + sec->output_offset)); - return foff; -} - -static bfd_vma -calculate_plt_memory_address (bfd *abfd, struct bfd_link_info *link_info, - Elf_Internal_Sym *isymbuf, - Elf_Internal_Rela *irel, - Elf_Internal_Shdr *symtab_hdr) -{ - bfd_vma symval; - - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isym; - asection *sym_sec; - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value + sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - struct elf_nds32_link_hash_table *htab; - asection *splt; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - htab = nds32_elf_hash_table (link_info); - splt = htab->root.splt; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->plt.offset == (bfd_vma) - 1) - { - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - * symbol. Just ignore it--it will be caught by the - * regular reloc processing. */ - return 0; - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - symval = splt->output_section->vma + h->plt.offset; - } - - return symval; -} - -static bfd_signed_vma -calculate_plt_offset (bfd *abfd, asection *sec, struct bfd_link_info *link_info, - Elf_Internal_Sym *isymbuf, Elf_Internal_Rela *irel, - Elf_Internal_Shdr *symtab_hdr) -{ - bfd_vma foff; - if ((foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel, - symtab_hdr)) == 0) - return 0; - else - return foff - (irel->r_offset - + sec->output_section->vma + sec->output_offset); -} - -/* Convert a 32-bit instruction to 16-bit one. - INSN is the input 32-bit instruction, INSN16 is the output 16-bit - instruction. If INSN_TYPE is not NULL, it the CGEN instruction - type of INSN16. Return 1 if successful. */ - -static int -nds32_convert_32_to_16_alu1 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, - int *pinsn_type) -{ - uint16_t insn16 = 0; - int insn_type = 0; - unsigned long mach = bfd_get_mach (abfd); - - if (N32_SH5 (insn) != 0) - return 0; - - switch (N32_SUB5 (insn)) - { - case N32_ALU1_ADD_SLLI: - case N32_ALU1_ADD_SRLI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IS_RB3 (insn)) - { - insn16 = N16_TYPE333 (ADD333, N32_RT5 (insn), N32_RA5 (insn), - N32_RB5 (insn)); - insn_type = NDS32_INSN_ADD333; - } - else if (N32_IS_RT4 (insn)) - { - if (N32_RT5 (insn) == N32_RA5 (insn)) - insn16 = N16_TYPE45 (ADD45, N32_RT54 (insn), N32_RB5 (insn)); - else if (N32_RT5 (insn) == N32_RB5 (insn)) - insn16 = N16_TYPE45 (ADD45, N32_RT54 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_ADD45; - } - break; - - case N32_ALU1_SUB_SLLI: - case N32_ALU1_SUB_SRLI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IS_RB3 (insn)) - { - insn16 = N16_TYPE333 (SUB333, N32_RT5 (insn), N32_RA5 (insn), - N32_RB5 (insn)); - insn_type = NDS32_INSN_SUB333; - } - else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)) - { - insn16 = N16_TYPE45 (SUB45, N32_RT54 (insn), N32_RB5 (insn)); - insn_type = NDS32_INSN_SUB45; - } - break; - - case N32_ALU1_AND_SLLI: - case N32_ALU1_AND_SRLI: - /* and $rt, $rt, $rb -> and33 for v3, v3m. */ - if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && N32_IS_RB3 (insn)) - { - if (N32_RT5 (insn) == N32_RA5 (insn)) - insn16 = N16_MISC33 (AND33, N32_RT5 (insn), N32_RB5 (insn)); - else if (N32_RT5 (insn) == N32_RB5 (insn)) - insn16 = N16_MISC33 (AND33, N32_RT5 (insn), N32_RA5 (insn)); - if (insn16) - insn_type = NDS32_INSN_AND33; - } - break; - - case N32_ALU1_XOR_SLLI: - case N32_ALU1_XOR_SRLI: - /* xor $rt, $rt, $rb -> xor33 for v3, v3m. */ - if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && N32_IS_RB3 (insn)) - { - if (N32_RT5 (insn) == N32_RA5 (insn)) - insn16 = N16_MISC33 (XOR33, N32_RT5 (insn), N32_RB5 (insn)); - else if (N32_RT5 (insn) == N32_RB5 (insn)) - insn16 = N16_MISC33 (XOR33, N32_RT5 (insn), N32_RA5 (insn)); - if (insn16) - insn_type = NDS32_INSN_XOR33; - } - break; - - case N32_ALU1_OR_SLLI: - case N32_ALU1_OR_SRLI: - /* or $rt, $rt, $rb -> or33 for v3, v3m. */ - if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && N32_IS_RB3 (insn)) - { - if (N32_RT5 (insn) == N32_RA5 (insn)) - insn16 = N16_MISC33 (OR33, N32_RT5 (insn), N32_RB5 (insn)); - else if (N32_RT5 (insn) == N32_RB5 (insn)) - insn16 = N16_MISC33 (OR33, N32_RT5 (insn), N32_RA5 (insn)); - if (insn16) - insn_type = NDS32_INSN_OR33; - } - break; - case N32_ALU1_NOR: - /* nor $rt, $ra, $ra -> not33 for v3, v3m. */ - if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RB3 (insn) - && N32_RA5 (insn) == N32_RB5 (insn)) - { - insn16 = N16_MISC33 (NOT33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_NOT33; - } - break; - case N32_ALU1_SRAI: - if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)) - { - insn16 = N16_TYPE45 (SRAI45, N32_RT54 (insn), N32_UB5 (insn)); - insn_type = NDS32_INSN_SRAI45; - } - break; - - case N32_ALU1_SRLI: - if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)) - { - insn16 = N16_TYPE45 (SRLI45, N32_RT54 (insn), N32_UB5 (insn)); - insn_type = NDS32_INSN_SRLI45; - } - break; - - case N32_ALU1_SLLI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_UB5 (insn) < 8) - { - insn16 = N16_TYPE333 (SLLI333, N32_RT5 (insn), N32_RA5 (insn), - N32_UB5 (insn)); - insn_type = NDS32_INSN_SLLI333; - } - break; - - case N32_ALU1_ZEH: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) - { - insn16 = N16_BFMI333 (ZEH33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_ZEH33; - } - break; - - case N32_ALU1_SEB: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) - { - insn16 = N16_BFMI333 (SEB33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_SEB33; - } - break; - - case N32_ALU1_SEH: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) - { - insn16 = N16_BFMI333 (SEH33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_SEH33; - } - break; - - case N32_ALU1_SLT: - if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn)) - { - /* Implicit r15. */ - insn16 = N16_TYPE45 (SLT45, N32_RA54 (insn), N32_RB5 (insn)); - insn_type = NDS32_INSN_SLT45; - } - break; - - case N32_ALU1_SLTS: - if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn)) - { - /* Implicit r15. */ - insn16 = N16_TYPE45 (SLTS45, N32_RA54 (insn), N32_RB5 (insn)); - insn_type = NDS32_INSN_SLTS45; - } - break; - } - - if ((insn16 & 0x8000) == 0) - return 0; - - if (pinsn16) - *pinsn16 = insn16; - if (pinsn_type) - *pinsn_type = insn_type; - return 1; -} - -static int -nds32_convert_32_to_16_alu2 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, - int *pinsn_type) -{ - uint16_t insn16 = 0; - int insn_type; - unsigned long mach = bfd_get_mach (abfd); - - /* TODO: bset, bclr, btgl, btst. */ - if (__GF (insn, 6, 4) != 0) - return 0; - - switch (N32_IMMU (insn, 6)) - { - case N32_ALU2_MUL: - if (mach >= MACH_V3 && N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && N32_IS_RB3 (insn)) - { - if (N32_RT5 (insn) == N32_RA5 (insn)) - insn16 = N16_MISC33 (MUL33, N32_RT5 (insn), N32_RB5 (insn)); - else if (N32_RT5 (insn) == N32_RB5 (insn)) - insn16 = N16_MISC33 (MUL33, N32_RT5 (insn), N32_RA5 (insn)); - if (insn16) - insn_type = NDS32_INSN_MUL33; - } - } - - if ((insn16 & 0x8000) == 0) - return 0; - - if (pinsn16) - *pinsn16 = insn16; - if (pinsn_type) - *pinsn_type = insn_type; - return 1; -} - -int -nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16, - int *pinsn_type) -{ - int op6; - uint16_t insn16 = 0; - int insn_type; - unsigned long mach = bfd_get_mach (abfd); - - /* Decode 32-bit instruction. */ - if (insn & 0x80000000) - { - /* Not 32-bit insn. */ - return 0; - } - - op6 = N32_OP6 (insn); - - /* Convert it to 16-bit instruction. */ - switch (op6) - { - case N32_OP6_MOVI: - if (IS_WITHIN_S (N32_IMM20S (insn), 5)) - { - insn16 = N16_TYPE55 (MOVI55, N32_RT5 (insn), N32_IMM20S (insn)); - insn_type = NDS32_INSN_MOVI55; - } - else if (mach >= MACH_V3 && N32_IMM20S (insn) >= 16 - && N32_IMM20S (insn) < 48 && N32_IS_RT4 (insn)) - { - insn16 = N16_TYPE45 (MOVPI45, N32_RT54 (insn), - N32_IMM20S (insn) - 16); - insn_type = NDS32_INSN_MOVPI45; - } - break; - - case N32_OP6_ADDI: - if (N32_IMM15S (insn) == 0) - { - /* Do not convert `addi $sp, $sp, 0' to `mov55 $sp, $sp', - because `mov55 $sp, $sp' is ifret16 in V3 ISA. */ - if (mach <= MACH_V2 - || N32_RT5 (insn) != REG_SP || N32_RA5 (insn) != REG_SP) - { - insn16 = N16_TYPE55 (MOV55, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_MOV55; - } - } - else if (N32_IMM15S (insn) > 0) - { - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IMM15S (insn) < 8) - { - insn16 = N16_TYPE333 (ADDI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_ADDI333; - } - else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn) - && N32_IMM15S (insn) < 32) - { - insn16 = N16_TYPE45 (ADDI45, N32_RT54 (insn), N32_IMM15S (insn)); - insn_type = NDS32_INSN_ADDI45; - } - else if (mach >= MACH_V2 && N32_RT5 (insn) == REG_SP - && N32_RT5 (insn) == N32_RA5 (insn) - && N32_IMM15S (insn) < 512) - { - insn16 = N16_TYPE10 (ADDI10S, N32_IMM15S (insn)); - insn_type = NDS32_INSN_ADDI10_SP; - } - else if (mach >= MACH_V3 && N32_IS_RT3 (insn) - && N32_RA5 (insn) == REG_SP && N32_IMM15S (insn) < 256 - && (N32_IMM15S (insn) % 4 == 0)) - { - insn16 = N16_TYPE36 (ADDRI36_SP, N32_RT5 (insn), - N32_IMM15S (insn) >> 2); - insn_type = NDS32_INSN_ADDRI36_SP; - } - } - else - { - /* Less than 0. */ - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) && N32_IMM15S (insn) > -8) - { - insn16 = N16_TYPE333 (SUBI333, N32_RT5 (insn), N32_RA5 (insn), - 0 - N32_IMM15S (insn)); - insn_type = NDS32_INSN_SUBI333; - } - else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn) - && N32_IMM15S (insn) > -32) - { - insn16 = N16_TYPE45 (SUBI45, N32_RT54 (insn), - 0 - N32_IMM15S (insn)); - insn_type = NDS32_INSN_SUBI45; - } - else if (mach >= MACH_V2 && N32_RT5 (insn) == REG_SP - && N32_RT5 (insn) == N32_RA5 (insn) - && N32_IMM15S (insn) >= -512) - { - insn16 = N16_TYPE10 (ADDI10S, N32_IMM15S (insn)); - insn_type = NDS32_INSN_ADDI10_SP; - } - } - break; - - case N32_OP6_ORI: - if (N32_IMM15S (insn) == 0) - { - /* Do not convert `ori $sp, $sp, 0' to `mov55 $sp, $sp', - because `mov55 $sp, $sp' is ifret16 in V3 ISA. */ - if (mach <= MACH_V2 - || N32_RT5 (insn) != REG_SP || N32_RA5 (insn) != REG_SP) - { - insn16 = N16_TYPE55 (MOV55, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_MOV55; - } - } - break; - - case N32_OP6_SUBRI: - if (mach >= MACH_V3 && N32_IS_RT3 (insn) - && N32_IS_RA3 (insn) && N32_IMM15S (insn) == 0) - { - insn16 = N16_MISC33 (NEG33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_NEG33; - } - break; - - case N32_OP6_ANDI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)) - { - if (N32_IMM15U (insn) == 1) - { - insn16 = N16_BFMI333 (XLSB33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_XLSB33; - } - else if (N32_IMM15U (insn) == 0x7ff) - { - insn16 = N16_BFMI333 (X11B33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_X11B33; - } - else if (N32_IMM15U (insn) == 0xff) - { - insn16 = N16_BFMI333 (ZEB33, N32_RT5 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_ZEB33; - } - else if (mach >= MACH_V3 && N32_RT5 (insn) == N32_RA5 (insn) - && N32_IMM15U (insn) < 256) - { - int imm15u = N32_IMM15U (insn); - - if (__builtin_popcount (imm15u) == 1) - { - /* BMSKI33 */ - int imm3u = __builtin_ctz (imm15u); - - insn16 = N16_BFMI333 (BMSKI33, N32_RT5 (insn), imm3u); - insn_type = NDS32_INSN_BMSKI33; - } - else if (imm15u != 0 && __builtin_popcount (imm15u + 1) == 1) - { - /* FEXTI33 */ - int imm3u = __builtin_ctz (imm15u + 1) - 1; - - insn16 = N16_BFMI333 (FEXTI33, N32_RT5 (insn), imm3u); - insn_type = NDS32_INSN_FEXTI33; - } - } - } - break; - - case N32_OP6_SLTI: - if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 5)) - { - insn16 = N16_TYPE45 (SLTI45, N32_RA54 (insn), N32_IMM15S (insn)); - insn_type = NDS32_INSN_SLTI45; - } - break; - - case N32_OP6_SLTSI: - if (N32_RT5 (insn) == REG_R15 && N32_IS_RA4 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 5)) - { - insn16 = N16_TYPE45 (SLTSI45, N32_RA54 (insn), N32_IMM15S (insn)); - insn_type = NDS32_INSN_SLTSI45; - } - break; - - case N32_OP6_LWI: - if (N32_IS_RT4 (insn) && N32_IMM15S (insn) == 0) - { - insn16 = N16_TYPE45 (LWI450, N32_RT54 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_LWI450; - } - else if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (LWI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_LWI333; - } - else if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_FP - && IS_WITHIN_U (N32_IMM15S (insn), 7)) - { - insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 0, N32_IMM15S (insn)); - insn_type = NDS32_INSN_LWI37; - } - else if (mach >= MACH_V2 && N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_SP - && IS_WITHIN_U (N32_IMM15S (insn), 7)) - { - insn16 = N16_TYPE37 (XWI37SP, N32_RT5 (insn), 0, N32_IMM15S (insn)); - insn_type = NDS32_INSN_LWI37_SP; - } - else if (mach >= MACH_V2 && N32_IS_RT4 (insn) && N32_RA5 (insn) == REG_R8 - && -32 <= N32_IMM15S (insn) && N32_IMM15S (insn) < 0) - { - insn16 = N16_TYPE45 (LWI45_FE, N32_RT54 (insn), - N32_IMM15S (insn) + 32); - insn_type = NDS32_INSN_LWI45_FE; - } - break; - - case N32_OP6_SWI: - if (N32_IS_RT4 (insn) && N32_IMM15S (insn) == 0) - { - insn16 = N16_TYPE45 (SWI450, N32_RT54 (insn), N32_RA5 (insn)); - insn_type = NDS32_INSN_SWI450; - } - else if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (SWI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_SWI333; - } - else if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_FP - && IS_WITHIN_U (N32_IMM15S (insn), 7)) - { - insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 1, N32_IMM15S (insn)); - insn_type = NDS32_INSN_SWI37; - } - else if (mach >= MACH_V2 && N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_SP - && IS_WITHIN_U (N32_IMM15S (insn), 7)) - { - insn16 = N16_TYPE37 (XWI37SP, N32_RT5 (insn), 1, N32_IMM15S (insn)); - insn_type = NDS32_INSN_SWI37_SP; - } - break; - - case N32_OP6_LWI_BI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (LWI333_BI, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_LWI333_BI; - } - break; - - case N32_OP6_SWI_BI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (SWI333_BI, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_SWI333_BI; - } - break; - - case N32_OP6_LHI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (LHI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_LHI333; - } - break; - - case N32_OP6_SHI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (SHI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_SHI333; - } - break; - - case N32_OP6_LBI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (LBI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_LBI333; - } - break; - - case N32_OP6_SBI: - if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn) - && IS_WITHIN_U (N32_IMM15S (insn), 3)) - { - insn16 = N16_TYPE333 (SBI333, N32_RT5 (insn), N32_RA5 (insn), - N32_IMM15S (insn)); - insn_type = NDS32_INSN_SBI333; - } - break; - - case N32_OP6_ALU1: - return nds32_convert_32_to_16_alu1 (abfd, insn, pinsn16, pinsn_type); - - case N32_OP6_ALU2: - return nds32_convert_32_to_16_alu2 (abfd, insn, pinsn16, pinsn_type); - - case N32_OP6_BR1: - if (!IS_WITHIN_S (N32_IMM14S (insn), 8)) - goto done; - - if ((insn & N32_BIT (14)) == 0) - { - /* N32_BR1_BEQ */ - if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5 - && N32_RT5 (insn) != REG_R5) - insn16 = N16_TYPE38 (BEQS38, N32_RT5 (insn), N32_IMM14S (insn)); - else if (N32_IS_RA3 (insn) && N32_RT5 (insn) == REG_R5 - && N32_RA5 (insn) != REG_R5) - insn16 = N16_TYPE38 (BEQS38, N32_RA5 (insn), N32_IMM14S (insn)); - insn_type = NDS32_INSN_BEQS38; - break; - } - else - { - /* N32_BR1_BNE */ - if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5 - && N32_RT5 (insn) != REG_R5) - insn16 = N16_TYPE38 (BNES38, N32_RT5 (insn), N32_IMM14S (insn)); - else if (N32_IS_RA3 (insn) && N32_RT5 (insn) == REG_R5 - && N32_RA5 (insn) != REG_R5) - insn16 = N16_TYPE38 (BNES38, N32_RA5 (insn), N32_IMM14S (insn)); - insn_type = NDS32_INSN_BNES38; - break; - } - break; - - case N32_OP6_BR2: - switch (N32_BR2_SUB (insn)) - { - case N32_BR2_BEQZ: - if (N32_IS_RT3 (insn) && IS_WITHIN_S (N32_IMM16S (insn), 8)) - { - insn16 = N16_TYPE38 (BEQZ38, N32_RT5 (insn), N32_IMM16S (insn)); - insn_type = NDS32_INSN_BEQZ38; - } - else if (N32_RT5 (insn) == REG_R15 - && IS_WITHIN_S (N32_IMM16S (insn), 8)) - { - insn16 = N16_TYPE8 (BEQZS8, N32_IMM16S (insn)); - insn_type = NDS32_INSN_BEQZS8; - } - break; - - case N32_BR2_BNEZ: - if (N32_IS_RT3 (insn) && IS_WITHIN_S (N32_IMM16S (insn), 8)) - { - insn16 = N16_TYPE38 (BNEZ38, N32_RT5 (insn), N32_IMM16S (insn)); - insn_type = NDS32_INSN_BNEZ38; - } - else if (N32_RT5 (insn) == REG_R15 - && IS_WITHIN_S (N32_IMM16S (insn), 8)) - { - insn16 = N16_TYPE8 (BNEZS8, N32_IMM16S (insn)); - insn_type = NDS32_INSN_BNEZS8; - } - break; - - case N32_BR2_IFCALL: - if (IS_WITHIN_U (N32_IMM16S (insn), 9)) - { - insn16 = N16_TYPE9 (IFCALL9, N32_IMM16S (insn)); - insn_type = NDS32_INSN_IFCALL9; - } - break; - } - break; - - case N32_OP6_JI: - if ((insn & N32_BIT (24)) == 0) - { - /* N32_JI_J */ - if (IS_WITHIN_S (N32_IMM24S (insn), 8)) - { - insn16 = N16_TYPE8 (J8, N32_IMM24S (insn)); - insn_type = NDS32_INSN_J8; - } - } - break; - - case N32_OP6_JREG: - if (__GF (insn, 8, 2) != 0) - goto done; - - switch (N32_IMMU (insn, 5)) - { - case N32_JREG_JR: - if (N32_JREG_HINT (insn) == 0) - { - /* jr */ - insn16 = N16_TYPE5 (JR5, N32_RB5 (insn)); - insn_type = NDS32_INSN_JR5; - } - else if (N32_JREG_HINT (insn) == 1) - { - /* ret */ - insn16 = N16_TYPE5 (RET5, N32_RB5 (insn)); - insn_type = NDS32_INSN_RET5; - } - else if (N32_JREG_HINT (insn) == 3) - { - /* ifret = mov55 $sp, $sp */ - insn16 = N16_TYPE55 (MOV55, REG_SP, REG_SP); - insn_type = NDS32_INSN_IFRET; - } - break; - - case N32_JREG_JRAL: - /* It's convertible when return rt5 is $lp and address - translation is kept. */ - if (N32_RT5 (insn) == REG_LP && N32_JREG_HINT (insn) == 0) - { - insn16 = N16_TYPE5 (JRAL5, N32_RB5 (insn)); - insn_type = NDS32_INSN_JRAL5; - } - break; - } - break; - - case N32_OP6_MISC: - if (N32_SUB5 (insn) == N32_MISC_BREAK && N32_SWID (insn) < 32) - { - /* For v3, swid above 31 are used for ex9.it. */ - insn16 = N16_TYPE5 (BREAK16, N32_SWID (insn)); - insn_type = NDS32_INSN_BREAK16; - } - break; - - default: - /* This instruction has no 16-bit variant. */ - goto done; - } - -done: - /* Bit-15 of insn16 should be set for a valid instruction. */ - if ((insn16 & 0x8000) == 0) - return 0; - - if (pinsn16) - *pinsn16 = insn16; - if (pinsn_type) - *pinsn_type = insn_type; - return 1; -} - -static int -special_convert_32_to_16 (unsigned long insn, uint16_t *pinsn16, - Elf_Internal_Rela *reloc) -{ - uint16_t insn16 = 0; - - if ((reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG) == 0 - || (ELF32_R_TYPE (reloc->r_info) != R_NDS32_INSN16)) - return 0; - - if (!N32_IS_RT3 (insn)) - return 0; - - switch (N32_OP6 (insn)) - { - case N32_OP6_LWI: - if (N32_RA5 (insn) == REG_GP && IS_WITHIN_U (N32_IMM15S (insn), 7)) - insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 0, N32_IMM15S (insn)); - break; - case N32_OP6_SWI: - if (N32_RA5 (insn) == REG_GP && IS_WITHIN_U (N32_IMM15S (insn), 7)) - insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 1, N32_IMM15S (insn)); - break; - case N32_OP6_HWGP: - if (!IS_WITHIN_U (N32_IMM17S (insn), 7)) - break; - - if (__GF (insn, 17, 3) == 6) - insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 0, N32_IMM17S (insn)); - else if (__GF (insn, 17, 3) == 7) - insn16 = N16_TYPE37 (XWI37, N32_RT5 (insn), 1, N32_IMM17S (insn)); - break; - } - - if ((insn16 & 0x8000) == 0) - return 0; - - *pinsn16 = insn16; - return 1; -} - -/* Convert a 16-bit instruction to 32-bit one. - INSN16 it the input and PINSN it the point to output. - Return non-zero on successful. Otherwise 0 is returned. */ - -int -nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn) -{ - uint32_t insn = 0xffffffff; - unsigned long mach = bfd_get_mach (abfd); - - /* NOTE: push25, pop25 and movd44 do not have 32-bit variants. */ - - switch (__GF (insn16, 9, 6)) - { - case 0x4: /* add45 */ - insn = N32_ALU1 (ADD, N16_RT4 (insn16), N16_RT4 (insn16), - N16_RA5 (insn16)); - goto done; - case 0x5: /* sub45 */ - insn = N32_ALU1 (SUB, N16_RT4 (insn16), N16_RT4 (insn16), - N16_RA5 (insn16)); - goto done; - case 0x6: /* addi45 */ - insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), - N16_IMM5U (insn16)); - goto done; - case 0x7: /* subi45 */ - insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), - -N16_IMM5U (insn16)); - goto done; - case 0x8: /* srai45 */ - insn = N32_ALU1 (SRAI, N16_RT4 (insn16), N16_RT4 (insn16), - N16_IMM5U (insn16)); - goto done; - case 0x9: /* srli45 */ - insn = N32_ALU1 (SRLI, N16_RT4 (insn16), N16_RT4 (insn16), - N16_IMM5U (insn16)); - goto done; - case 0xa: /* slli333 */ - insn = N32_ALU1 (SLLI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0xc: /* add333 */ - insn = N32_ALU1 (ADD, N16_RT3 (insn16), N16_RA3 (insn16), - N16_RB3 (insn16)); - goto done; - case 0xd: /* sub333 */ - insn = N32_ALU1 (SUB, N16_RT3 (insn16), N16_RA3 (insn16), - N16_RB3 (insn16)); - goto done; - case 0xe: /* addi333 */ - insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0xf: /* subi333 */ - insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), - -N16_IMM3U (insn16)); - goto done; - case 0x10: /* lwi333 */ - insn = N32_TYPE2 (LWI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x12: /* lhi333 */ - insn = N32_TYPE2 (LHI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x13: /* lbi333 */ - insn = N32_TYPE2 (LBI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x11: /* lwi333.bi */ - insn = N32_TYPE2 (LWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x14: /* swi333 */ - insn = N32_TYPE2 (SWI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x16: /* shi333 */ - insn = N32_TYPE2 (SHI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x17: /* sbi333 */ - insn = N32_TYPE2 (SBI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x15: /* swi333.bi */ - insn = N32_TYPE2 (SWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), - N16_IMM3U (insn16)); - goto done; - case 0x18: /* addri36.sp */ - insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), REG_SP, - N16_IMM6U (insn16) << 2); - goto done; - case 0x19: /* lwi45.fe */ - insn = N32_TYPE2 (LWI, N16_RT4 (insn16), REG_R8, - (N16_IMM5U (insn16) - 32)); - goto done; - case 0x1a: /* lwi450 */ - insn = N32_TYPE2 (LWI, N16_RT4 (insn16), N16_RA5 (insn16), 0); - goto done; - case 0x1b: /* swi450 */ - insn = N32_TYPE2 (SWI, N16_RT4 (insn16), N16_RA5 (insn16), 0); - goto done; - - /* These are r15 implied instructions. */ - case 0x30: /* slts45 */ - insn = N32_ALU1 (SLTS, REG_TA, N16_RT4 (insn16), N16_RA5 (insn16)); - goto done; - case 0x31: /* slt45 */ - insn = N32_ALU1 (SLT, REG_TA, N16_RT4 (insn16), N16_RA5 (insn16)); - goto done; - case 0x32: /* sltsi45 */ - insn = N32_TYPE2 (SLTSI, REG_TA, N16_RT4 (insn16), N16_IMM5U (insn16)); - goto done; - case 0x33: /* slti45 */ - insn = N32_TYPE2 (SLTI, REG_TA, N16_RT4 (insn16), N16_IMM5U (insn16)); - goto done; - case 0x34: /* beqzs8, bnezs8 */ - if (insn16 & N32_BIT (8)) - insn = N32_BR2 (BNEZ, REG_TA, N16_IMM8S (insn16)); - else - insn = N32_BR2 (BEQZ, REG_TA, N16_IMM8S (insn16)); - goto done; - - case 0x35: /* break16, ex9.it */ - /* Only consider range of v3 break16. */ - insn = N32_TYPE0 (MISC, (N16_IMM5U (insn16) << 5) | N32_MISC_BREAK); - goto done; - - case 0x3c: /* ifcall9 */ - insn = N32_BR2 (IFCALL, 0, N16_IMM9U (insn16)); - goto done; - case 0x3d: /* movpi45 */ - insn = N32_TYPE1 (MOVI, N16_RT4 (insn16), N16_IMM5U (insn16) + 16); - goto done; - - case 0x3f: /* MISC33 */ - switch (insn16 & 0x7) - { - case 2: /* neg33 */ - insn = N32_TYPE2 (SUBRI, N16_RT3 (insn16), N16_RA3 (insn16), 0); - break; - case 3: /* not33 */ - insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16), - N16_RA3 (insn16)); - break; - case 4: /* mul33 */ - insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16), - N16_RA3 (insn16)); - break; - case 5: /* xor33 */ - insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16), - N16_RA3 (insn16)); - break; - case 6: /* and33 */ - insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16), - N16_RA3 (insn16)); - break; - case 7: /* or33 */ - insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16), - N16_RA3 (insn16)); - break; - } - goto done; - - case 0xb: - switch (insn16 & 0x7) - { - case 0: /* zeb33 */ - insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RA3 (insn16), 0xff); - break; - case 1: /* zeh33 */ - insn = N32_ALU1 (ZEH, N16_RT3 (insn16), N16_RA3 (insn16), 0); - break; - case 2: /* seb33 */ - insn = N32_ALU1 (SEB, N16_RT3 (insn16), N16_RA3 (insn16), 0); - break; - case 3: /* seh33 */ - insn = N32_ALU1 (SEH, N16_RT3 (insn16), N16_RA3 (insn16), 0); - break; - case 4: /* xlsb33 */ - insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RA3 (insn16), 1); - break; - case 5: /* x11b33 */ - insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RA3 (insn16), 0x7ff); - break; - case 6: /* bmski33 */ - insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16), - 1 << __GF (insn16, 3, 3)); - break; - case 7: /* fexti33 */ - insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16), - (1 << (__GF (insn16, 3, 3) + 1)) - 1); - break; - } - goto done; - } - - switch (__GF (insn16, 10, 5)) - { - case 0x0: /* mov55 or ifret16 */ - if (mach >= MACH_V3 && N16_RT5 (insn16) == REG_SP - && N16_RT5 (insn16) == N16_RA5 (insn16)) - insn = N32_JREG (JR, 0, 0, 0, 3); - else - insn = N32_TYPE2 (ADDI, N16_RT5 (insn16), N16_RA5 (insn16), 0); - goto done; - case 0x1: /* movi55 */ - insn = N32_TYPE1 (MOVI, N16_RT5 (insn16), N16_IMM5S (insn16)); - goto done; - case 0x1b: /* addi10s (V2) */ - insn = N32_TYPE2 (ADDI, REG_SP, REG_SP, N16_IMM10S (insn16)); - goto done; - } - - switch (__GF (insn16, 11, 4)) - { - case 0x7: /* lwi37.fp/swi37.fp */ - if (insn16 & N32_BIT (7)) /* swi37.fp */ - insn = N32_TYPE2 (SWI, N16_RT38 (insn16), REG_FP, N16_IMM7U (insn16)); - else /* lwi37.fp */ - insn = N32_TYPE2 (LWI, N16_RT38 (insn16), REG_FP, N16_IMM7U (insn16)); - goto done; - case 0x8: /* beqz38 */ - insn = N32_BR2 (BEQZ, N16_RT38 (insn16), N16_IMM8S (insn16)); - goto done; - case 0x9: /* bnez38 */ - insn = N32_BR2 (BNEZ, N16_RT38 (insn16), N16_IMM8S (insn16)); - goto done; - case 0xa: /* beqs38/j8, implied r5 */ - if (N16_RT38 (insn16) == 5) - insn = N32_JI (J, N16_IMM8S (insn16)); - else - insn = N32_BR1 (BEQ, N16_RT38 (insn16), REG_R5, N16_IMM8S (insn16)); - goto done; - case 0xb: /* bnes38 and others */ - if (N16_RT38 (insn16) == 5) - { - switch (__GF (insn16, 5, 3)) - { - case 0: /* jr5 */ - insn = N32_JREG (JR, 0, N16_RA5 (insn16), 0, 0); - break; - case 4: /* ret5 */ - insn = N32_JREG (JR, 0, N16_RA5 (insn16), 0, 1); - break; - case 1: /* jral5 */ - insn = N32_JREG (JRAL, REG_LP, N16_RA5 (insn16), 0, 0); - break; - case 2: /* ex9.it imm5 */ - /* ex9.it had no 32-bit variantl. */ - break; - case 5: /* add5.pc */ - /* add5.pc had no 32-bit variantl. */ - break; - } - } - else /* bnes38 */ - insn = N32_BR1 (BNE, N16_RT38 (insn16), REG_R5, N16_IMM8S (insn16)); - goto done; - case 0xe: /* lwi37/swi37 */ - if (insn16 & (1 << 7)) /* swi37.sp */ - insn = N32_TYPE2 (SWI, N16_RT38 (insn16), REG_SP, N16_IMM7U (insn16)); - else /* lwi37.sp */ - insn = N32_TYPE2 (LWI, N16_RT38 (insn16), REG_SP, N16_IMM7U (insn16)); - goto done; - } - -done: - if (insn & 0x80000000) - return 0; - - if (pinsn) - *pinsn = insn; - return 1; -} - -static bfd_boolean -is_sda_access_insn (unsigned long insn) -{ - switch (N32_OP6 (insn)) - { - case N32_OP6_LWI: - case N32_OP6_LHI: - case N32_OP6_LHSI: - case N32_OP6_LBI: - case N32_OP6_LBSI: - case N32_OP6_SWI: - case N32_OP6_SHI: - case N32_OP6_SBI: - case N32_OP6_LWC: - case N32_OP6_LDC: - case N32_OP6_SWC: - case N32_OP6_SDC: - return TRUE; - default: - ; - } - return FALSE; -} - -static unsigned long -turn_insn_to_sda_access (uint32_t insn, bfd_signed_vma type, uint32_t *pinsn) -{ - uint32_t oinsn = 0; - - switch (type) - { - case R_NDS32_GOT_LO12: - case R_NDS32_GOTOFF_LO12: - case R_NDS32_PLTREL_LO12: - case R_NDS32_PLT_GOTREL_LO12: - case R_NDS32_LO12S0_RELA: - switch (N32_OP6 (insn)) - { - case N32_OP6_LBI: - /* lbi.gp */ - oinsn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0); - break; - case N32_OP6_LBSI: - /* lbsi.gp */ - oinsn = N32_TYPE1 (LBGP, N32_RT5 (insn), N32_BIT (19)); - break; - case N32_OP6_SBI: - /* sbi.gp */ - oinsn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0); - break; - case N32_OP6_ORI: - /* addi.gp */ - oinsn = N32_TYPE1 (SBGP, N32_RT5 (insn), N32_BIT (19)); - break; - } - break; - - case R_NDS32_LO12S1_RELA: - switch (N32_OP6 (insn)) - { - case N32_OP6_LHI: - /* lhi.gp */ - oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0); - break; - case N32_OP6_LHSI: - /* lhsi.gp */ - oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), N32_BIT (18)); - break; - case N32_OP6_SHI: - /* shi.gp */ - oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), N32_BIT (19)); - break; - } - break; - - case R_NDS32_LO12S2_RELA: - switch (N32_OP6 (insn)) - { - case N32_OP6_LWI: - /* lwi.gp */ - oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); - break; - case N32_OP6_SWI: - /* swi.gp */ - oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3)); - break; - } - break; - - case R_NDS32_LO12S2_DP_RELA: - case R_NDS32_LO12S2_SP_RELA: - oinsn = (insn & 0x7ff07000) | (REG_GP << 15); - break; - } - - if (oinsn) - *pinsn = oinsn; - - return oinsn != 0; -} - -/* Linker hasn't found the correct merge section for non-section symbol - in relax time, this work is left to the function elf_link_input_bfd(). - So for non-section symbol, _bfd_merged_section_offset is also needed - to find the correct symbol address. */ - -static bfd_vma -nds32_elf_rela_local_sym (bfd *abfd, Elf_Internal_Sym *sym, - asection **psec, Elf_Internal_Rela *rel) -{ - asection *sec = *psec; - bfd_vma relocation; - - relocation = (sec->output_section->vma - + sec->output_offset + sym->st_value); - if ((sec->flags & SEC_MERGE) && sec->sec_info_type == SEC_INFO_TYPE_MERGE) - { - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend = - _bfd_merged_section_offset (abfd, psec, - elf_section_data (sec)->sec_info, - sym->st_value + rel->r_addend); - else - rel->r_addend = - _bfd_merged_section_offset (abfd, psec, - elf_section_data (sec)->sec_info, - sym->st_value) + rel->r_addend; - - if (sec != *psec) - { - /* If we have changed the section, and our original section is - marked with SEC_EXCLUDE, it means that the original - SEC_MERGE section has been completely subsumed in some - other SEC_MERGE section. In this case, we need to leave - some info around for --emit-relocs. */ - if ((sec->flags & SEC_EXCLUDE) != 0) - sec->kept_section = *psec; - sec = *psec; - } - rel->r_addend -= relocation; - rel->r_addend += sec->output_section->vma + sec->output_offset; - } - return relocation; -} - -static bfd_vma -calculate_memory_address (bfd *abfd, Elf_Internal_Rela *irel, - Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - bfd_signed_vma foff; - bfd_vma symval, addend; - Elf_Internal_Rela irel_fn; - Elf_Internal_Sym *isym; - asection *sym_sec; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irel->r_info); - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - memcpy (&irel_fn, irel, sizeof (Elf_Internal_Rela)); - symval = nds32_elf_rela_local_sym (abfd, isym, &sym_sec, &irel_fn); - addend = irel_fn.r_addend; - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - return 0; - - if (h->root.u.def.section->flags & SEC_MERGE) - { - sym_sec = h->root.u.def.section; - symval = _bfd_merged_section_offset (abfd, &sym_sec, elf_section_data - (sym_sec)->sec_info, h->root.u.def.value); - symval = symval + sym_sec->output_section->vma - + sym_sec->output_offset; - } - else - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - addend = irel->r_addend; - } - - foff = symval + addend; - - return foff; -} - -static bfd_vma -calculate_got_memory_address (bfd *abfd, struct bfd_link_info *link_info, - Elf_Internal_Rela *irel, - Elf_Internal_Shdr *symtab_hdr) -{ - int symndx; - bfd_vma *local_got_offsets; - /* Get the value of the symbol referred to by the reloc. */ - struct elf_link_hash_entry *h; - struct elf_nds32_link_hash_table *htab = nds32_elf_hash_table (link_info); - - /* An external symbol. */ - symndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[symndx]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (symndx >= 0) - { - BFD_ASSERT (h != NULL); - return (htab->root.sgot->output_section->vma - + htab->root.sgot->output_offset - + h->got.offset); - } - else - { - local_got_offsets = elf_local_got_offsets (abfd); - BFD_ASSERT (local_got_offsets != NULL); - return (htab->root.sgot->output_section->vma - + htab->root.sgot->output_offset - + local_got_offsets[ELF32_R_SYM (irel->r_info)]); - } - - /* The _GLOBAL_OFFSET_TABLE_ may be undefweak(or should be?). */ - /* The check of h->root.type is passed. */ -} - -static int -is_16bit_NOP (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, Elf_Internal_Rela *rel) -{ - bfd_byte *contents; - unsigned short insn16; - - if (!(rel->r_addend & R_NDS32_INSN16_CONVERT_FLAG)) - return FALSE; - contents = elf_section_data (sec)->this_hdr.contents; - insn16 = bfd_getb16 (contents + rel->r_offset); - if (insn16 == NDS32_NOP16) - return TRUE; - return FALSE; -} - -/* It checks whether the instruction could be converted to - 16-bit form and returns the converted one. - - `internal_relocs' is supposed to be sorted. */ - -static int -is_convert_32_to_16 (bfd *abfd, asection *sec, - Elf_Internal_Rela *reloc, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend, - uint16_t *insn16) -{ -#define NORMAL_32_TO_16 (1 << 0) -#define SPECIAL_32_TO_16 (1 << 1) - bfd_byte *contents = NULL; - bfd_signed_vma off; - bfd_vma mem_addr; - uint32_t insn = 0; - Elf_Internal_Rela *pc_rel; - int pic_ext_target = 0; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - int convert_type; - bfd_vma offset; - - if (reloc->r_offset + 4 > sec->size) - return FALSE; - - offset = reloc->r_offset; - - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) - return FALSE; - insn = bfd_getb32 (contents + offset); - - if (nds32_convert_32_to_16 (abfd, insn, insn16, NULL)) - convert_type = NORMAL_32_TO_16; - else if (special_convert_32_to_16 (insn, insn16, reloc)) - convert_type = SPECIAL_32_TO_16; - else - return FALSE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - if (!nds32_get_local_syms (abfd, sec, &isymbuf)) - return FALSE; - - /* Find the first relocation of the same relocation-type, - so we iteratie them forward. */ - pc_rel = reloc; - while ((pc_rel - 1) >= internal_relocs && pc_rel[-1].r_offset == offset) - pc_rel--; - - for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++) - { - if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_15_PCREL_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17_PCREL_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PLTREL) - { - off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, - &pic_ext_target); - if (off >= ACCURATE_8BIT_S1 || off < -ACCURATE_8BIT_S1 - || off == 0) - return FALSE; - break; - } - else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA) - { - /* movi => movi55 */ - mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf, - symtab_hdr); - /* mem_addr is unsigned, but the value should - be between [-16, 15]. */ - if ((mem_addr + 0x10) >> 5) - return FALSE; - break; - } - else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_20) - || (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_LO12)) - { - /* It never happen movi to movi55 for R_NDS32_TLS_LE_20, - because it can be relaxed to addi for TLS_LE_ADD. */ - return FALSE; - } - else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA) - && (reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG) - && convert_type == SPECIAL_32_TO_16) - { - /* fp-as-gp - We've selected a best fp-base for this access, so we can - always resolve it anyway. Do nothing. */ - break; - } - else if ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_NONE - && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_RELA_GNU_VTINHERIT)) - || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_RELA_GNU_VTENTRY) - && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_INSN16)) - || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_LOADSTORE) - && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_DWARF2_OP1_RELA))) - { - /* Prevent unresolved addi instruction translate - to addi45 or addi333. */ - return FALSE; - } - else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) - { - off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr, - &pic_ext_target); - if (off >= ACCURATE_U9BIT_S1 || off <= 0) - return FALSE; - break; - } - } - - return TRUE; -} - -static void -nds32_elf_write_16 (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *contents, - Elf_Internal_Rela *reloc, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend, - unsigned short insn16) -{ - Elf_Internal_Rela *pc_rel; - bfd_vma offset; - - offset = reloc->r_offset; - bfd_putb16 (insn16, contents + offset); - /* Find the first relocation of the same relocation-type, - so we iteratie them forward. */ - pc_rel = reloc; - while ((pc_rel - 1) > internal_relocs && pc_rel[-1].r_offset == offset) - pc_rel--; - - for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++) - { - if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_15_PCREL_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17_PCREL_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PCREL_RELA) - { - pc_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_9_PCREL_RELA); - } - else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PLTREL) - pc_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_9_PLTREL); - else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA) - pc_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_5_RELA); - else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA - || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA) - pc_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_SDA_FP7U2_RELA); - else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA)) - pc_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_10IFCU_PCREL_RELA); - } -} - -/* Find a relocation of type specified by `reloc_type' - of the same r_offset with reloc. - If not found, return irelend. - - Assuming relocations are sorted by r_offset, - we find the relocation from `reloc' backward untill relocs, - or find it from `reloc' forward untill irelend. */ - -static Elf_Internal_Rela * -find_relocs_at_address (Elf_Internal_Rela *reloc, - Elf_Internal_Rela *relocs, - Elf_Internal_Rela *irelend, - enum elf_nds32_reloc_type reloc_type) -{ - Elf_Internal_Rela *rel_t; - - /* Find backward. */ - for (rel_t = reloc; - rel_t >= relocs && rel_t->r_offset == reloc->r_offset; - rel_t--) - if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) - return rel_t; - - /* We didn't find it backward. Try find it forward. */ - for (rel_t = reloc; - rel_t < irelend && rel_t->r_offset == reloc->r_offset; - rel_t++) - if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) - return rel_t; - - return irelend; -} - -/* Find a relocation of specified type and offset. - `reloc' is just a refence point to find a relocation at specified offset. - If not found, return irelend. - - Assuming relocations are sorted by r_offset, - we find the relocation from `reloc' backward untill relocs, - or find it from `reloc' forward untill irelend. */ - -static Elf_Internal_Rela * -find_relocs_at_address_addr (Elf_Internal_Rela *reloc, - Elf_Internal_Rela *relocs, - Elf_Internal_Rela *irelend, - enum elf_nds32_reloc_type reloc_type, - bfd_vma offset_p) -{ - Elf_Internal_Rela *rel_t = NULL; - - /* First, we try to find a relocation of offset `offset_p', - and then we use find_relocs_at_address to find specific type. */ - - if (reloc->r_offset > offset_p) - { - /* Find backward. */ - for (rel_t = reloc; - rel_t >= relocs && rel_t->r_offset > offset_p; rel_t--) - /* Do nothing. */; - } - else if (reloc->r_offset < offset_p) - { - /* Find forward. */ - for (rel_t = reloc; - rel_t < irelend && rel_t->r_offset < offset_p; rel_t++) - /* Do nothing. */; - } - else - rel_t = reloc; - - /* Not found? */ - if (rel_t < relocs || rel_t == irelend || rel_t->r_offset != offset_p) - return irelend; - - return find_relocs_at_address (rel_t, relocs, irelend, reloc_type); -} - -static bfd_boolean -nds32_elf_check_dup_relocs (Elf_Internal_Rela *reloc, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend, - unsigned char reloc_type) -{ - Elf_Internal_Rela *rel_t; - - for (rel_t = reloc; - rel_t >= internal_relocs && rel_t->r_offset == reloc->r_offset; - rel_t--) - if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) - { - if (ELF32_R_SYM (rel_t->r_info) == ELF32_R_SYM (reloc->r_info) - && rel_t->r_addend == reloc->r_addend) - continue; - return TRUE; - } - - for (rel_t = reloc; rel_t < irelend && rel_t->r_offset == reloc->r_offset; - rel_t++) - if (ELF32_R_TYPE (rel_t->r_info) == reloc_type) - { - if (ELF32_R_SYM (rel_t->r_info) == ELF32_R_SYM (reloc->r_info) - && rel_t->r_addend == reloc->r_addend) - continue; - return TRUE; - } - - return FALSE; -} - -typedef struct nds32_elf_blank nds32_elf_blank_t; -struct nds32_elf_blank -{ - /* Where the blank begins. */ - bfd_vma offset; - /* The size of the blank. */ - bfd_vma size; - /* The accumulative size before this blank. */ - bfd_vma total_size; - nds32_elf_blank_t *next; - nds32_elf_blank_t *prev; -}; - -static nds32_elf_blank_t *blank_free_list = NULL; - -static nds32_elf_blank_t * -create_nds32_elf_blank (bfd_vma offset_p, bfd_vma size_p) -{ - nds32_elf_blank_t *blank_t; - - if (blank_free_list) - { - blank_t = blank_free_list; - blank_free_list = blank_free_list->next; - } - else - blank_t = bfd_malloc (sizeof (nds32_elf_blank_t)); - - if (blank_t == NULL) - return NULL; - - blank_t->offset = offset_p; - blank_t->size = size_p; - blank_t->total_size = 0; - blank_t->next = NULL; - blank_t->prev = NULL; - - return blank_t; -} - -static void -remove_nds32_elf_blank (nds32_elf_blank_t *blank_p) -{ - if (blank_free_list) - { - blank_free_list->prev = blank_p; - blank_p->next = blank_free_list; - } - else - blank_p->next = NULL; - - blank_p->prev = NULL; - blank_free_list = blank_p; -} - -static void -clean_nds32_elf_blank (void) -{ - nds32_elf_blank_t *blank_t; - - while (blank_free_list) - { - blank_t = blank_free_list; - blank_free_list = blank_free_list->next; - free (blank_t); - } -} - -static nds32_elf_blank_t * -search_nds32_elf_blank (nds32_elf_blank_t *blank_p, bfd_vma addr) -{ - nds32_elf_blank_t *blank_t; - - if (!blank_p) - return NULL; - blank_t = blank_p; - - while (blank_t && addr < blank_t->offset) - blank_t = blank_t->prev; - while (blank_t && blank_t->next && addr >= blank_t->next->offset) - blank_t = blank_t->next; - - return blank_t; -} - -static bfd_vma -get_nds32_elf_blank_total (nds32_elf_blank_t **blank_p, bfd_vma addr, - int overwrite) -{ - nds32_elf_blank_t *blank_t; - - blank_t = search_nds32_elf_blank (*blank_p, addr); - if (!blank_t) - return 0; - - if (overwrite) - *blank_p = blank_t; - - if (addr < blank_t->offset + blank_t->size) - return blank_t->total_size + (addr - blank_t->offset); - else - return blank_t->total_size + blank_t->size; -} - -static bfd_boolean -insert_nds32_elf_blank (nds32_elf_blank_t **blank_p, bfd_vma addr, bfd_vma len) -{ - nds32_elf_blank_t *blank_t, *blank_t2; - - if (!*blank_p) - { - *blank_p = create_nds32_elf_blank (addr, len); - return *blank_p ? TRUE : FALSE; - } - - blank_t = search_nds32_elf_blank (*blank_p, addr); - - if (blank_t == NULL) - { - blank_t = create_nds32_elf_blank (addr, len); - if (!blank_t) - return FALSE; - while ((*blank_p)->prev != NULL) - *blank_p = (*blank_p)->prev; - blank_t->next = *blank_p; - (*blank_p)->prev = blank_t; - (*blank_p) = blank_t; - return TRUE; - } - - if (addr < blank_t->offset + blank_t->size) - { - if (addr > blank_t->offset + blank_t->size) - blank_t->size = addr - blank_t->offset; - } - else - { - blank_t2 = create_nds32_elf_blank (addr, len); - if (!blank_t2) - return FALSE; - if (blank_t->next) - { - blank_t->next->prev = blank_t2; - blank_t2->next = blank_t->next; - } - blank_t2->prev = blank_t; - blank_t->next = blank_t2; - *blank_p = blank_t2; - } - - return TRUE; -} - -static bfd_boolean -insert_nds32_elf_blank_recalc_total (nds32_elf_blank_t **blank_p, bfd_vma addr, - bfd_vma len) -{ - nds32_elf_blank_t *blank_t; - - if (!insert_nds32_elf_blank (blank_p, addr, len)) - return FALSE; - - blank_t = *blank_p; - - if (!blank_t->prev) - { - blank_t->total_size = 0; - blank_t = blank_t->next; - } - - while (blank_t) - { - blank_t->total_size = blank_t->prev->total_size + blank_t->prev->size; - blank_t = blank_t->next; - } - - return TRUE; -} - -static void -calc_nds32_blank_total (nds32_elf_blank_t *blank_p) -{ - nds32_elf_blank_t *blank_t; - bfd_vma total_size = 0; - - if (!blank_p) - return; - - blank_t = blank_p; - while (blank_t->prev) - blank_t = blank_t->prev; - while (blank_t) - { - blank_t->total_size = total_size; - total_size += blank_t->size; - blank_t = blank_t->next; - } -} - -static bfd_boolean -nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec, - nds32_elf_blank_t *blank_p) -{ - Elf_Internal_Shdr *symtab_hdr; /* Symbol table header of this bfd. */ - Elf_Internal_Sym *isym = NULL; /* Symbol table of this bfd. */ - Elf_Internal_Sym *isymend; /* Symbol entry iterator. */ - unsigned int sec_shndx; /* The section the be relaxed. */ - bfd_byte *contents; /* Contents data of iterating section. */ - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - asection *sect; - nds32_elf_blank_t *blank_t; - nds32_elf_blank_t *blank_t2; - nds32_elf_blank_t *blank_head; - - blank_head = blank_t = blank_p; - while (blank_head->prev != NULL) - blank_head = blank_head->prev; - while (blank_t->next != NULL) - blank_t = blank_t->next; - - if (blank_t->offset + blank_t->size <= sec->size) - { - blank_t->next = create_nds32_elf_blank (sec->size + 4, 0); - blank_t->next->prev = blank_t; - } - if (blank_head->offset > 0) - { - blank_head->prev = create_nds32_elf_blank (0, 0); - blank_head->prev->next = blank_head; - blank_head = blank_head->prev; - } - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* The deletion must stop at the next ALIGN reloc for an alignment - power larger than the number of bytes we are deleting. */ - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - if (!nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - - if (isym == NULL) - { - isym = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, NULL, NULL, NULL); - symtab_hdr->contents = (bfd_byte *) isym; - } - - if (isym == NULL || symtab_hdr->sh_info == 0) - return FALSE; - - blank_t = blank_head; - calc_nds32_blank_total (blank_head); - - for (sect = abfd->sections; sect != NULL; sect = sect->next) - { - /* Adjust all the relocs. */ - - /* Relocations MUST be kept in memory, because relaxation adjust them. */ - internal_relocs = _bfd_elf_link_read_relocs (abfd, sect, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + sect->reloc_count; - - blank_t = blank_head; - blank_t2 = blank_head; - - if (!(sect->flags & SEC_RELOC)) - continue; - - nds32_get_section_contents (abfd, sect, &contents, TRUE); - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma raddr; - - if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_DIFF8 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_DIFF32 - && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx) - { - unsigned long val = 0; - unsigned long mask; - long before, between; - long offset = 0; - - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_NDS32_DIFF8: - offset = bfd_get_8 (abfd, contents + irel->r_offset); - break; - case R_NDS32_DIFF16: - offset = bfd_get_16 (abfd, contents + irel->r_offset); - break; - case R_NDS32_DIFF32: - val = bfd_get_32 (abfd, contents + irel->r_offset); - /* Get the signed bit and mask for the high part. The - gcc will alarm when right shift 32-bit since the - type size of long may be 32-bit. */ - mask = 0 - (val >> 31); - if (mask) - offset = (val | (mask - 0xffffffff)); - else - offset = val; - break; - default: - BFD_ASSERT (0); - } - - /* DIFF value - 0 |encoded in location| - |------------|-------------------|--------- - sym+off(addend) - -- before ---| ***************** - --------------------- between ---| - - We only care how much data are relax between DIFF, - marked as ***. */ - - before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0); - between = get_nds32_elf_blank_total (&blank_t, - irel->r_addend + offset, 0); - if (between == before) - goto done_adjust_diff; - - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_NDS32_DIFF8: - bfd_put_8 (abfd, offset - (between - before), - contents + irel->r_offset); - break; - case R_NDS32_DIFF16: - bfd_put_16 (abfd, offset - (between - before), - contents + irel->r_offset); - break; - case R_NDS32_DIFF32: - bfd_put_32 (abfd, offset - (between - before), - contents + irel->r_offset); - break; - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_DIFF_ULEB128 - && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx) - { - bfd_vma val = 0; - unsigned int len = 0; - unsigned long before, between; - bfd_byte *endp, *p; - - val = _bfd_read_unsigned_leb128 (abfd, contents + irel->r_offset, - &len); - - before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0); - between = get_nds32_elf_blank_total (&blank_t, - irel->r_addend + val, 0); - if (between == before) - goto done_adjust_diff; - - p = contents + irel->r_offset; - endp = p + len -1; - memset (p, 0x80, len); - *(endp) = 0; - p = write_uleb128 (p, val - (between - before)) - 1; - if (p < endp) - *p |= 0x80; - } -done_adjust_diff: - - if (sec == sect) - { - raddr = irel->r_offset; - irel->r_offset -= get_nds32_elf_blank_total (&blank_t2, - irel->r_offset, 1); - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) - continue; - if (blank_t2 && blank_t2->next - && (blank_t2->offset > raddr - || blank_t2->next->offset <= raddr)) - _bfd_error_handler - (_("%B: Error: search_nds32_elf_blank reports wrong node\n"), abfd); - - /* Mark reloc in deleted portion as NONE. - For some relocs like R_NDS32_LABEL that doesn't modify the - content in the section. R_NDS32_LABEL doesn't belong to the - instruction in the section, so we should preserve it. */ - if (raddr >= blank_t2->offset - && raddr < blank_t2->offset + blank_t2->size - && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL - && ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_BEGIN - && ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_END - && ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - && ELF32_R_TYPE (irel->r_info) != R_NDS32_SUBTRAHEND - && ELF32_R_TYPE (irel->r_info) != R_NDS32_MINUEND) - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_NONE); - continue; - } - } - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) - continue; - - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info - && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx - && ELF_ST_TYPE (isym[ELF32_R_SYM (irel->r_info)].st_info) == STT_SECTION) - { - if (irel->r_addend <= sec->size) - irel->r_addend -= - get_nds32_elf_blank_total (&blank_t, irel->r_addend, 1); - } - } - } - - /* Adjust the local symbols defined in this section. */ - blank_t = blank_head; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx) - { - if (isym->st_value <= sec->size) - { - bfd_vma ahead; - bfd_vma orig_addr = isym->st_value; - - ahead = get_nds32_elf_blank_total (&blank_t, isym->st_value, 1); - isym->st_value -= ahead; - - /* Adjust function size. */ - if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC - && isym->st_size > 0) - isym->st_size -= - get_nds32_elf_blank_total - (&blank_t, orig_addr + isym->st_size, 0) - ahead; - } - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - blank_t = blank_head; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - if (sym_hash->root.u.def.value <= sec->size) - { - bfd_vma ahead; - bfd_vma orig_addr = sym_hash->root.u.def.value; - - ahead = get_nds32_elf_blank_total (&blank_t, sym_hash->root.u.def.value, 1); - sym_hash->root.u.def.value -= ahead; - - /* Adjust function size. */ - if (sym_hash->type == STT_FUNC) - sym_hash->size -= - get_nds32_elf_blank_total - (&blank_t, orig_addr + sym_hash->size, 0) - ahead; - - } - } - } - - contents = elf_section_data (sec)->this_hdr.contents; - blank_t = blank_head; - while (blank_t->next) - { - /* Actually delete the bytes. */ - - /* If current blank is the last blank overlap with current section, - go to finish process. */ - if (sec->size <= (blank_t->next->offset)) - break; - - memmove (contents + blank_t->offset - blank_t->total_size, - contents + blank_t->offset + blank_t->size, - blank_t->next->offset - (blank_t->offset + blank_t->size)); - - blank_t = blank_t->next; - } - - if (sec->size > (blank_t->offset + blank_t->size)) - { - /* There are remaining code between blank and section boundary. - Move the remaining code to appropriate location. */ - memmove (contents + blank_t->offset - blank_t->total_size, - contents + blank_t->offset + blank_t->size, - sec->size - (blank_t->offset + blank_t->size)); - sec->size -= blank_t->total_size + blank_t->size; - } - else - /* This blank is not entirely included in the section, - reduce the section size by only part of the blank size. */ - sec->size -= blank_t->total_size + (sec->size - blank_t->offset); - - while (blank_head) - { - blank_t = blank_head; - blank_head = blank_head->next; - remove_nds32_elf_blank (blank_t); - } - - return TRUE; -} - -/* Get the contents of a section. */ - -static int -nds32_get_section_contents (bfd *abfd, asection *sec, - bfd_byte **contents_p, bfd_boolean cache) -{ - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - *contents_p = elf_section_data (sec)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, contents_p)) - return FALSE; - if (cache) - elf_section_data (sec)->this_hdr.contents = *contents_p; - } - - return TRUE; -} - -/* Get the contents of the internal symbol of abfd. */ - -static int -nds32_get_local_syms (bfd *abfd, asection *sec ATTRIBUTE_UNUSED, - Elf_Internal_Sym **isymbuf_p) -{ - Elf_Internal_Shdr *symtab_hdr; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Read this BFD's local symbols if we haven't done so already. */ - if (*isymbuf_p == NULL && symtab_hdr->sh_info != 0) - { - *isymbuf_p = (Elf_Internal_Sym *) symtab_hdr->contents; - if (*isymbuf_p == NULL) - { - *isymbuf_p = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (*isymbuf_p == NULL) - return FALSE; - } - } - symtab_hdr->contents = (bfd_byte *) (*isymbuf_p); - - return TRUE; -} - -/* Range of small data. */ -static bfd_vma sdata_range[2][2]; -static bfd_vma const sdata_init_range[2] = -{ ACCURATE_12BIT_S1, ACCURATE_19BIT }; - -static int -nds32_elf_insn_size (bfd *abfd ATTRIBUTE_UNUSED, - bfd_byte *contents, bfd_vma addr) -{ - unsigned long insn = bfd_getb32 (contents + addr); - - if (insn & 0x80000000) - return 2; - - return 4; -} - -/* Set the gp relax range. We have to measure the safe range - to do gp relaxation. */ - -static void -relax_range_measurement (bfd *abfd) -{ - asection *sec_f, *sec_b; - /* For upper bound. */ - bfd_vma maxpgsz = get_elf_backend_data (abfd)->maxpagesize; - bfd_vma align; - static int decide_relax_range = 0; - int i; - int range_number = sizeof (sdata_init_range) / sizeof (sdata_init_range[0]); - - if (decide_relax_range) - return; - decide_relax_range = 1; - - if (sda_rela_sec == NULL) - { - /* Since there is no data sections, we assume the range is page size. */ - for (i = 0; i < range_number; i++) - { - sdata_range[i][0] = sdata_init_range[i] - 0x1000; - sdata_range[i][1] = sdata_init_range[i] - 0x1000; - } - return; - } - - /* Get the biggest alignment power after the gp located section. */ - sec_f = sda_rela_sec->output_section; - sec_b = sec_f->next; - align = 0; - while (sec_b != NULL) - { - if ((unsigned)(1 << sec_b->alignment_power) > align) - align = (1 << sec_b->alignment_power); - sec_b = sec_b->next; - } - - /* I guess we can not determine the section before - gp located section, so we assume the align is max page size. */ - for (i = 0; i < range_number; i++) - { - sdata_range[i][1] = sdata_init_range[i] - align; - BFD_ASSERT (sdata_range[i][1] <= sdata_init_range[i]); - sdata_range[i][0] = sdata_init_range[i] - maxpgsz; - BFD_ASSERT (sdata_range[i][0] <= sdata_init_range[i]); - } -} - -/* These are macros used to check flags encoded in r_addend. - They are only used by nds32_elf_relax_section (). */ -#define GET_SEQ_LEN(addend) ((addend) & 0x000000ff) -#define IS_1ST_CONVERT(addend) ((addend) & 0x80000000) -#define IS_OPTIMIZE(addend) ((addend) & 0x40000000) -#define IS_16BIT_ON(addend) ((addend) & 0x20000000) - -static const char * unrecognized_reloc_msg = - /* xgettext:c-format */ - N_("%B: warning: %s points to unrecognized reloc at %#Lx"); - -/* Relax LONGCALL1 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longcall1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 3 variations for LONGCALL1 - case 4-4-2; 16-bit on, optimize off or optimize for space - sethi ta, hi20(symbol) ; LONGCALL1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral5 ta ; - - case 4-4-4; 16-bit off, optimize don't care - sethi ta, hi20(symbol) ; LONGCALL1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; - - case 4-4-4; 16-bit on, optimize for speed - sethi ta, hi20(symbol) ; LONGCALL1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; - Check code for -mlong-calls output. */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - bfd_vma laddr; - int seq_len; /* Original length of instruction sequence. */ - uint32_t insn; - Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - uint16_t insn16; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr); - lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, - laddr + 4); - - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL1", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - - /* This condition only happened when symbol is undefined. */ - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 - || foff >= CONSERVATIVE_24BIT_S1) - return FALSE; - - /* Relax to: jal symbol; 25_PCREL */ - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Replace the long call with a jal. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_25_PCREL_RELA); - irel->r_addend = hi_irelfn->r_addend; - - /* We don't resolve this here but resolve it in relocate_section. */ - insn = INSN_JAL; - bfd_putb32 (insn, contents + irel->r_offset); - - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - *insn_len = 4; - - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - *insn_len += 2; - } - return TRUE; -} - -#define CONVERT_CONDITION_CALL(insn) (((insn) & 0xffff0000) ^ 0x90000) -/* Relax LONGCALL2 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* bltz rt, .L1 ; LONGCALL2 - jal symbol ; 25_PCREL - .L1: */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - bfd_vma laddr; - uint32_t insn; - Elf_Internal_Rela *i1_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - i1_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_25_PCREL_RELA, laddr + 4); - - if (i1_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL2", - irel->r_offset); - return FALSE; - } - - insn = bfd_getb32 (contents + laddr); - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - - if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 - || foff >= CONSERVATIVE_16BIT_S1) - return FALSE; - - /* Relax to bgezal rt, label ; 17_PCREL - or bltzal rt, label ; 17_PCREL */ - - /* Convert to complimentary conditional call. */ - insn = CONVERT_CONDITION_CALL (insn); - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Clean unnessary relocations. */ - i1_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE); - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_17_PCREL_RELA, laddr); - if (cond_irelfn != irelend) - cond_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), R_NDS32_NONE); - - /* Replace the long call with a bgezal. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), - R_NDS32_17_PCREL_RELA); - irel->r_addend = i1_irelfn->r_addend; - - bfd_putb32 (insn, contents + irel->r_offset); - - *insn_len = 4; - return TRUE; -} - -/* Relax LONGCALL3 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 3 variations for LONGCALL3 - case 4-4-4-2; 16-bit on, optimize off or optimize for space - bltz rt, $1 ; LONGCALL3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral5 ta ; - $1 - - case 4-4-4-4; 16-bit off, optimize don't care - bltz rt, $1 ; LONGCALL3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; - $1 - - case 4-4-4-4; 16-bit on, optimize for speed - bltz rt, $1 ; LONGCALL3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jral ta ; - $1 */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - bfd_vma laddr; - int seq_len; /* Original length of instruction sequence. */ - uint32_t insn; - Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - uint16_t insn16; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr + 4); - lo_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, laddr + 8); - - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL3", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 - || foff >= CONSERVATIVE_24BIT_S1) - return FALSE; - - insn = bfd_getb32 (contents + laddr); - if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) - { - /* Relax to bgezal rt, label ; 17_PCREL - or bltzal rt, label ; 17_PCREL */ - - /* Convert to complimentary conditional call. */ - insn = CONVERT_CONDITION_CALL (insn); - bfd_putb32 (insn, contents + irel->r_offset); - - *insn_len = 4; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_17_PCREL_RELA, laddr); - if (cond_irelfn != irelend) - { - cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_17_PCREL_RELA); - cond_irelfn->r_addend = hi_irelfn->r_addend; - } - - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); - hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_INSN16); - hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1) - { - /* Relax to the following instruction sequence - bltz rt, $1 ; LONGCALL2 - jal symbol ; 25_PCREL - $1 */ - *insn_len = 8; - insn = INSN_JAL; - bfd_putb32 (insn, contents + hi_irelfn->r_offset); - - hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_25_PCREL_RELA); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2); - - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - - if (seq_len & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - insn_len += 2; - } - } - return TRUE; -} - -/* Relax LONGJUMP1 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 3 variations for LONGJUMP1 - case 4-4-2; 16-bit bit on, optimize off or optimize for space - sethi ta, hi20(symbol) ; LONGJUMP1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - - case 4-4-4; 16-bit off, optimize don't care - sethi ta, hi20(symbol) ; LONGJUMP1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; - - case 4-4-4; 16-bit on, optimize for speed - sethi ta, hi20(symbol) ; LONGJUMP1/HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - bfd_vma laddr; - int seq_len; /* Original length of instruction sequence. */ - int insn16_on; /* 16-bit on/off. */ - uint32_t insn; - Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - uint16_t insn16; - unsigned long reloc; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - insn16_on = IS_16BIT_ON (irel->r_addend); - - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr); - lo_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, laddr + 4); - if (hi_irelfn == irelend || lo_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP1", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 - || foff < -CONSERVATIVE_24BIT_S1) - return FALSE; - - if (insn16_on && foff >= -ACCURATE_8BIT_S1 - && foff < ACCURATE_8BIT_S1 && (seq_len & 0x2)) - { - /* j8 label */ - /* 16-bit on, but not optimized for speed. */ - reloc = R_NDS32_9_PCREL_RELA; - insn16 = INSN_J8; - bfd_putb16 (insn16, contents + irel->r_offset); - *insn_len = 2; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - } - else - { - /* j label */ - reloc = R_NDS32_25_PCREL_RELA; - insn = INSN_J; - bfd_putb32 (insn, contents + irel->r_offset); - *insn_len = 4; - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16); - irel->r_addend = 0; - } - - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE); - - if ((seq_len & 0x2) && ((*insn_len & 2) == 0)) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - *insn_len += 2; - } - return TRUE; -} - -/* Revert condition branch. This function does not check if the input - instruction is condition branch or not. */ - -static void -nds32_elf_convert_branch (uint16_t insn16, uint32_t insn, - uint16_t *re_insn16, uint32_t *re_insn) -{ - uint32_t comp_insn = 0; - uint16_t comp_insn16 = 0; - - if (insn) - { - if (N32_OP6 (insn) == N32_OP6_BR1) - { - /* beqs label. */ - comp_insn = (insn ^ 0x4000) & 0xffffc000; - if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5) - { - /* Insn can be contracted to 16-bit implied r5. */ - comp_insn16 = - (comp_insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38; - comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; - } - } - else if (N32_OP6 (insn) == N32_OP6_BR3) - { - /* bnec $ta, imm11, label. */ - comp_insn = (insn ^ 0x80000) & 0xffffff00; - } - else - { - comp_insn = (insn ^ 0x10000) & 0xffffc000; - if (N32_BR2_SUB (insn) == N32_BR2_BEQZ - || N32_BR2_SUB (insn) == N32_BR2_BNEZ) - { - if (N32_IS_RT3 (insn)) - { - /* Insn can be contracted to 16-bit. */ - comp_insn16 = - (comp_insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38; - comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8; - } - else if (N32_RT5 (insn) == REG_R15) - { - /* Insn can be contracted to 16-bit. */ - comp_insn16 = - (comp_insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38; - } - } - } - } - else - { - switch ((insn16 & 0xf000) >> 12) - { - case 0xc: - /* beqz38 or bnez38 */ - comp_insn16 = (insn16 ^ 0x0800) & 0xff00; - comp_insn = (comp_insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ; - comp_insn |= ((comp_insn16 & 0x0700) >> 8) << 20; - break; - - case 0xd: - /* beqs38 or bnes38 */ - comp_insn16 = (insn16 ^ 0x0800) & 0xff00; - comp_insn = (comp_insn16 & 0x0800) ? INSN_BNE : INSN_BEQ; - comp_insn |= (((comp_insn16 & 0x0700) >> 8) << 20) - | (REG_R5 << 15); - break; - - case 0xe: - /* beqzS8 or bnezS8 */ - comp_insn16 = (insn16 ^ 0x0100) & 0xff00; - comp_insn = (comp_insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ; - comp_insn |= REG_R15 << 20; - break; - - default: - break; - } - } - if (comp_insn && re_insn) - *re_insn = comp_insn; - if (comp_insn16 && re_insn16) - *re_insn16 = comp_insn16; -} - -/* Relax LONGJUMP2 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 3 variations for LONGJUMP2 - case 2-4; 1st insn convertible, 16-bit on, - optimize off or optimize for space - bnes38 rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1: - - case 4-4; 1st insn not convertible - bne rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1: - - case 4-4; 1st insn convertible, 16-bit on, optimize for speed - bne rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1: */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - bfd_vma laddr; - int seq_len; /* Original length of instruction sequence. */ - Elf_Internal_Rela *i2_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0, first_size; - unsigned int i; - bfd_signed_vma foff; - uint32_t insn, re_insn = 0; - uint16_t insn16, re_insn16 = 0; - unsigned long reloc, cond_reloc; - - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - first_size = (seq_len == 6) ? 2 : 4; - - i2_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, - irelend, R_NDS32_25_PCREL_RELA, - laddr + first_size); - - for (i = 0; i < sizeof (checked_types) / sizeof(checked_types[0]); i++) - { - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (cond_irelfn != irelend) - break; - } - - if (i2_irelfn == irelend || cond_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP2", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 - || foff >= CONSERVATIVE_16BIT_S1) - return FALSE; - - /* Get the all corresponding instructions. */ - if (first_size == 4) - { - insn = bfd_getb32 (contents + laddr); - nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); - } - else - { - insn16 = bfd_getb16 (contents + laddr); - nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); - } - - if (re_insn16 && foff >= -(ACCURATE_8BIT_S1 - first_size) - && foff < ACCURATE_8BIT_S1 - first_size) - { - if (first_size == 4) - { - /* Don't convert it to 16-bit now, keep this as relaxable for - ``label reloc; INSN16''. */ - - /* Save comp_insn32 to buffer. */ - bfd_putb32 (re_insn, contents + irel->r_offset); - *insn_len = 4; - reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ? - R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; - cond_reloc = R_NDS32_INSN16; - } - else - { - bfd_putb16 (re_insn16, contents + irel->r_offset); - *insn_len = 2; - reloc = R_NDS32_9_PCREL_RELA; - cond_reloc = R_NDS32_NONE; - } - } - else if (N32_OP6 (re_insn) == N32_OP6_BR1 - && (foff >= -(ACCURATE_14BIT_S1 - first_size) - && foff < ACCURATE_14BIT_S1 - first_size)) - { - /* beqs label ; 15_PCREL */ - bfd_putb32 (re_insn, contents + irel->r_offset); - *insn_len = 4; - reloc = R_NDS32_15_PCREL_RELA; - cond_reloc = R_NDS32_NONE; - } - else if (N32_OP6 (re_insn) == N32_OP6_BR2 - && foff >= -CONSERVATIVE_16BIT_S1 - && foff < CONSERVATIVE_16BIT_S1) - { - /* beqz label ; 17_PCREL */ - bfd_putb32 (re_insn, contents + irel->r_offset); - *insn_len = 4; - reloc = R_NDS32_17_PCREL_RELA; - cond_reloc = R_NDS32_NONE; - } - else - return FALSE; - - /* Set all relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc); - irel->r_addend = i2_irelfn->r_addend; - - cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), - cond_reloc); - cond_irelfn->r_addend = 0; - - if ((seq_len ^ *insn_len ) & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + 4); - i2_irelfn->r_offset = 4; - i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_INSN16); - i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - *insn_len += 2; - } - else - i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), - R_NDS32_NONE); - return TRUE; -} - -/* Relax LONGJUMP3 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 5 variations for LONGJUMP3 - case 1: 2-4-4-2; 1st insn convertible, 16-bit on, - optimize off or optimize for space - bnes38 rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - $1: ; - - case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed - bnes38 rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - $1: ; LABEL - - case 3: 4-4-4-2; 1st insn not convertible, 16-bit on, - optimize off or optimize for space - bne rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr5 ta ; - $1: ; - - case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care - 16-bit off if no INSN16 - bne rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; - $1: ; - - case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed - 16-bit off if no INSN16 - bne rt, ra, $1 ; LONGJUMP3 - sethi ta, hi20(symbol) ; HI20 - ori ta, ta, lo12(symbol) ; LO12S0 - jr ta ; - $1: ; LABEL */ - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA }; - - int reloc_off = 0, cond_removed = 0, convertible; - bfd_vma laddr; - int seq_len; /* Original length of instruction sequence. */ - Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend; - int pic_ext_target = 0, first_size; - unsigned int i; - bfd_signed_vma foff; - uint32_t insn, re_insn = 0; - uint16_t insn16, re_insn16 = 0; - unsigned long reloc, cond_reloc; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - - convertible = IS_1ST_CONVERT (irel->r_addend); - - if (convertible) - first_size = 2; - else - first_size = 4; - - /* Get all needed relocations. */ - hi_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr + first_size); - lo_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LO12S0_ORI_RELA, - laddr + first_size + 4); - - for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) - { - cond_irelfn = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (cond_irelfn != irelend) - break; - } - - if (hi_irelfn == irelend || lo_irelfn == irelend || cond_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP3", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 - || foff >= CONSERVATIVE_24BIT_S1) - return FALSE; - - /* Get the all corresponding instructions. */ - if (first_size == 4) - { - insn = bfd_getb32 (contents + laddr); - nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); - } - else - { - insn16 = bfd_getb16 (contents + laddr); - nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - if (re_insn16 && foff >= -ACCURATE_8BIT_S1 - first_size - && foff < ACCURATE_8BIT_S1 - first_size) - { - if (!(seq_len & 0x2)) - { - /* Don't convert it to 16-bit now, keep this as relaxable - for ``label reloc; INSN1a''6. */ - /* Save comp_insn32 to buffer. */ - bfd_putb32 (re_insn, contents + irel->r_offset); - *insn_len = 4; - reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ? - R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA; - cond_reloc = R_NDS32_INSN16; - } - else - { - /* Not optimize for speed; convert sequence to 16-bit. */ - /* Save comp_insn16 to buffer. */ - bfd_putb16 (re_insn16, contents + irel->r_offset); - *insn_len = 2; - reloc = R_NDS32_9_PCREL_RELA; - cond_reloc = R_NDS32_NONE; - } - cond_removed = 1; - } - else if (N32_OP6 (re_insn) == N32_OP6_BR1 - && (foff >= -(ACCURATE_14BIT_S1 - first_size) - && foff < ACCURATE_14BIT_S1 - first_size)) - { - /* beqs label ; 15_PCREL */ - bfd_putb32 (re_insn, contents + irel->r_offset); - *insn_len = 4; - reloc = R_NDS32_15_PCREL_RELA; - cond_reloc = R_NDS32_NONE; - cond_removed = 1; - } - else if (N32_OP6 (re_insn) == N32_OP6_BR2 - && foff >= -CONSERVATIVE_16BIT_S1 - && foff < CONSERVATIVE_16BIT_S1) - { - /* beqz label ; 17_PCREL */ - bfd_putb32 (re_insn, contents + irel->r_offset); - *insn_len = 4; - reloc = R_NDS32_17_PCREL_RELA; - cond_reloc = R_NDS32_NONE; - cond_removed = 1; - } - else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off - && foff < CONSERVATIVE_24BIT_S1 - reloc_off) - { - /* Relax to one of the following 3 variations - - case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize - for space - bnes38 rt, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1 - - case 4-4; 1st insn not convertible, others don't care - bne rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1 - - case 4-4; 1st insn convertible, 16-bit on, optimize for speed - bne rt, ra, $1 ; LONGJUMP2 - j label ; 25_PCREL - $1 */ - - /* Offset for first instruction. */ - - /* Use j label as second instruction. */ - *insn_len = 4 + first_size; - insn = INSN_J; - bfd_putb32 (insn, contents + hi_irelfn->r_offset); - reloc = R_NDS32_LONGJUMP2; - cond_reloc = R_NDS32_25_PLTREL; - } - else - return FALSE; - - if (cond_removed == 1) - { - /* Set all relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc); - irel->r_addend = hi_irelfn->r_addend; - - cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), - cond_reloc); - cond_irelfn->r_addend = 0; - hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - R_NDS32_NONE); - } - else - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - irel->r_addend = irel->r_addend; - hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), - cond_reloc); - } - - if ((seq_len ^ *insn_len ) & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + irel->r_offset + *insn_len); - lo_irelfn->r_offset = *insn_len; - lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_INSN16); - lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - *insn_len += 2; - } - else - lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), - R_NDS32_NONE); - return TRUE; -} - -/* Relax LONGCALL4 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* The pattern for LONGCALL4. Support for function cse. - sethi ta, hi20(symbol) ; LONGCALL4/HI20 - ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR - jral ta ; PTR_RES/EMPTY/INSN16 */ - - bfd_vma laddr; - uint32_t insn; - Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel; - Elf_Internal_Rela *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr); - - if (hi_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL4", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - /* This condition only happened when symbol is undefined. */ - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 - || foff >= CONSERVATIVE_24BIT_S1) - return FALSE; - - /* Relax to: jal symbol; 25_PCREL */ - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, irel->r_addend); - em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_EMPTY, irel->r_addend); - - if (ptr_irel == irelend || em_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL4", - irel->r_offset); - return FALSE; - } - /* Check these is enough space to insert jal in R_NDS32_EMPTY. */ - insn = bfd_getb32 (contents + irel->r_addend); - if (insn & 0x80000000) - return FALSE; - - /* Replace the long call with a jal. */ - em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), - R_NDS32_25_PCREL_RELA); - ptr_irel->r_addend = 1; - - /* We don't resolve this here but resolve it in relocate_section. */ - insn = INSN_JAL; - bfd_putb32 (insn, contents + em_irel->r_offset); - - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - /* If there is function cse, HI20 can not remove now. */ - call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LONGCALL4, laddr); - if (call_irel == irelend) - { - *insn_len = 0; - hi_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE); - } - - insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, irel->r_addend); - if (insn_irel != irelend) - insn_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - return TRUE; -} - -/* Relax LONGCALL5 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* The pattern for LONGCALL5. - bltz rt, .L1 ; LONGCALL5/17_PCREL - jal symbol ; 25_PCREL - .L1: */ - - bfd_vma laddr; - uint32_t insn; - Elf_Internal_Rela *cond_irel, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_25_PCREL_RELA, irel->r_addend); - if (cond_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL5", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1 - || foff >= CONSERVATIVE_16BIT_S1) - return FALSE; - - /* Relax to bgezal rt, label ; 17_PCREL - or bltzal rt, label ; 17_PCREL */ - - /* Convert to complimentary conditional call. */ - insn = CONVERT_CONDITION_CALL (insn); - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Modify relocation and contents. */ - cond_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_17_PCREL_RELA); - - /* Replace the long call with a bgezal. */ - bfd_putb32 (insn, contents + cond_irel->r_offset); - *insn_len = 0; - - /* Clean unnessary relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_17_PCREL_RELA, laddr); - cond_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - - return TRUE; -} - -/* Relax LONGCALL6 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* The pattern for LONGCALL6. - bltz rt, .L1 ; LONGCALL6/17_PCREL - sethi ta, hi20(symbol) ; HI20/PTR - ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR - jral ta ; PTR_RES/EMPTY/INSN16 - .L1 */ - - bfd_vma laddr; - uint32_t insn; - Elf_Internal_Rela *em_irel, *cond_irel, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_EMPTY, irel->r_addend); - - if (em_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL6", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 - || foff >= CONSERVATIVE_24BIT_S1) - return FALSE; - - /* Check these is enough space to insert jal in R_NDS32_EMPTY. */ - insn = bfd_getb32 (contents + irel->r_addend); - if (insn & 0x80000000) - return FALSE; - - insn = bfd_getb32 (contents + laddr); - if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) - { - /* Relax to bgezal rt, label ; 17_PCREL - or bltzal rt, label ; 17_PCREL */ - - /* Convert to complimentary conditional call. */ - *insn_len = 0; - insn = CONVERT_CONDITION_CALL (insn); - bfd_putb32 (insn, contents + em_irel->r_offset); - - em_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_17_PCREL_RELA); - - /* Set resolved relocation. */ - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, irel->r_addend); - if (cond_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, - "R_NDS32_LONGCALL6", irel->r_offset); - return FALSE; - } - cond_irel->r_addend = 1; - - /* Clear relocations. */ - - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_17_PCREL_RELA, laddr); - if (cond_irel != irelend) - cond_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, irel->r_addend); - if (cond_irel != irelend) - cond_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - - } - else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1) - { - /* Relax to the following instruction sequence - bltz rt, .L1 ; LONGCALL2/17_PCREL - jal symbol ; 25_PCREL/PTR_RES - .L1 */ - *insn_len = 4; - /* Convert instruction. */ - insn = INSN_JAL; - bfd_putb32 (insn, contents + em_irel->r_offset); - - /* Convert relocations. */ - em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), - R_NDS32_25_PCREL_RELA); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL5); - - /* Set resolved relocation. */ - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, irel->r_addend); - if (cond_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, - "R_NDS32_LONGCALL6", irel->r_offset); - return FALSE; - } - cond_irel->r_addend = 1; - - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, irel->r_addend); - if (cond_irel != irelend) - cond_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - } - return TRUE; -} - -/* Relax LONGJUMP4 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* The pattern for LONGJUMP4. - sethi ta, hi20(symbol) ; LONGJUMP4/HI20 - ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR - jr ta ; PTR_RES/INSN16/EMPTY */ - - bfd_vma laddr; - int seq_len; /* Original length of instruction sequence. */ - uint32_t insn; - Elf_Internal_Rela *hi_irel, *ptr_irel, *em_irel, *call_irel, *irelend; - int pic_ext_target = 0; - bfd_signed_vma foff; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_HI20_RELA, laddr); - - if (hi_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP4", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1 - || foff < -CONSERVATIVE_24BIT_S1) - return FALSE; - - /* Convert it to "j label", it may be converted to j8 in the final - pass of relaxation. Therefore, we do not consider this currently. */ - ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, irel->r_addend); - em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_EMPTY, irel->r_addend); - - if (ptr_irel == irelend || em_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP4", - irel->r_offset); - return FALSE; - } - - em_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_25_PCREL_RELA); - ptr_irel->r_addend = 1; - - /* Write instruction. */ - insn = INSN_J; - bfd_putb32 (insn, contents + em_irel->r_offset); - - /* Clear relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - /* If there is function cse, HI20 can not remove now. */ - call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_LONGJUMP4, laddr); - if (call_irel == irelend) - { - *insn_len = 0; - hi_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE); - } - - return TRUE; -} - -/* Relax LONGJUMP5 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - int *seq_len, bfd_byte *contents, - Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 2 variations for LONGJUMP5 - case 2-4; 1st insn convertible, 16-bit on. - bnes38 rt, ra, .L1 ; LONGJUMP5/9_PCREL/INSN16 - j label ; 25_PCREL/INSN16 - $1: - - case 4-4; 1st insn not convertible - bne rt, ra, .L1 ; LONGJUMP5/15_PCREL/INSN16 - j label ; 25_PCREL/INSN16 - .L1: */ - - bfd_vma laddr; - Elf_Internal_Rela *cond_irel, *irelend; - int pic_ext_target = 0; - unsigned int i; - bfd_signed_vma foff; - uint32_t insn, re_insn = 0; - uint16_t insn16, re_insn16 = 0; - unsigned long reloc; - - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA, - R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 }; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_25_PCREL_RELA, irel->r_addend); - if (cond_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP5", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1 - || foff >= CONSERVATIVE_16BIT_S1) - return FALSE; - - /* Get the all corresponding instructions. */ - insn = bfd_getb32 (contents + laddr); - /* Check instruction size. */ - if (insn & 0x80000000) - { - *seq_len = 0; - insn16 = insn >> 16; - nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); - } - else - nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); - - if (N32_OP6 (re_insn) == N32_OP6_BR1 - && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1)) - { - /* beqs label ; 15_PCREL. */ - bfd_putb32 (re_insn, contents + cond_irel->r_offset); - reloc = R_NDS32_15_PCREL_RELA; - } - else if (N32_OP6 (re_insn) == N32_OP6_BR2 - && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) - { - /* beqz label ; 17_PCREL. */ - bfd_putb32 (re_insn, contents + cond_irel->r_offset); - reloc = R_NDS32_17_PCREL_RELA; - } - else if ( N32_OP6 (re_insn) == N32_OP6_BR3 - && foff >= -CONSERVATIVE_8BIT_S1 && foff < CONSERVATIVE_8BIT_S1) - { - /* beqc label ; 9_PCREL. */ - bfd_putb32 (re_insn, contents + cond_irel->r_offset); - reloc = R_NDS32_WORD_9_PCREL_RELA; - } - else - return FALSE; - - /* Set all relocations. */ - cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), reloc); - - /* Clean relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) - { - cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (cond_irel != irelend) - { - if (*seq_len == 0 - && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16)) - { - /* If the branch instruction is 2 byte, it cannot remove - directly. Only convert it to nop16 and remove it after - checking alignment issue. */ - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + laddr); - cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - } - else - cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), - R_NDS32_NONE); - } - } - *insn_len = 0; - - return TRUE; -} - -/* Relax LONGJUMP6 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - int *seq_len, bfd_byte *contents, - Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 5 variations for LONGJUMP6 - case : 2-4-4-4; 1st insn convertible, 16-bit on. - bnes38 rt, ra, .L1 ; LONGJUMP6/15_PCREL/INSN16 - sethi ta, hi20(symbol) ; HI20/PTR - ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR - jr ta ; PTR_RES/INSN16/EMPTY - .L1: - - case : 4-4-4-4; 1st insn not convertible, 16-bit on. - bne rt, ra, .L1 ; LONGJUMP6/15_PCREL/INSN16 - sethi ta, hi20(symbol) ; HI20/PTR - ori ta, ta, lo12(symbol) ; LO12S0_ORI/PTR - jr ta ; PTR_RES/INSN16/EMPTY - .L1: */ - - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA, - R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 }; - - int reloc_off = 0, cond_removed = 0; - bfd_vma laddr; - Elf_Internal_Rela *cond_irel, *em_irel, *irelend, *insn_irel; - int pic_ext_target = 0; - unsigned int i; - bfd_signed_vma foff; - uint32_t insn, re_insn = 0; - uint16_t insn16, re_insn16 = 0; - unsigned long reloc; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_EMPTY, irel->r_addend); - - if (em_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP6", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1 - || foff >= CONSERVATIVE_24BIT_S1) - return FALSE; - - insn = bfd_getb32 (contents + laddr); - /* Check instruction size. */ - if (insn & 0x80000000) - { - *seq_len = 0; - insn16 = insn >> 16; - nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn); - } - else - nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn); - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - if (N32_OP6 (re_insn) == N32_OP6_BR1 - && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1)) - { - /* beqs label ; 15_PCREL */ - bfd_putb32 (re_insn, contents + em_irel->r_offset); - reloc = R_NDS32_15_PCREL_RELA; - cond_removed = 1; - } - else if (N32_OP6 (re_insn) == N32_OP6_BR2 - && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1) - { - /* beqz label ; 17_PCREL */ - bfd_putb32 (re_insn, contents + em_irel->r_offset); - reloc = R_NDS32_17_PCREL_RELA; - cond_removed = 1; - } - else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off - && foff < CONSERVATIVE_24BIT_S1 - reloc_off) - { - /* Relax to one of the following 2 variations - - case 2-4; 1st insn convertible, 16-bit on. - bnes38 rt, ra, .L1 ; LONGJUMP5/9_PCREL/INSN16 - j label ; 25_PCREL/INSN16 - $1: - - case 4-4; 1st insn not convertible - bne rt, ra, .L1 ; LONGJUMP5/15_PCREL/INSN16 - j label ; 25_PCREL/INSN16 - .L1: */ - - /* Use j label as second instruction. */ - insn = INSN_J; - reloc = R_NDS32_25_PCREL_RELA; - bfd_putb32 (insn, contents + em_irel->r_offset); - } - else - return FALSE; - - /* Set all relocations. */ - em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), reloc); - - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, em_irel->r_offset); - cond_irel->r_addend = 1; - - /* Use INSN16 of first branch instruction to distinguish if keeping - INSN16 of final instruction or not. */ - insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, irel->r_offset); - if (insn_irel == irelend) - { - /* Clean the final INSN16. */ - insn_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, em_irel->r_offset); - insn_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), - R_NDS32_NONE); - } - - if (cond_removed == 1) - { - *insn_len = 0; - - /* Clear relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++) - { - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (cond_irel != irelend) - { - if (*seq_len == 0 - && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16)) - { - /* If the branch instruction is 2 byte, it cannot remove - directly. Only convert it to nop16 and remove it after - checking alignment issue. */ - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + laddr); - cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - } - else - cond_irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE); - } - } - } - else - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_LONGJUMP5); - } - - return TRUE; -} - -/* Relax LONGJUMP7 relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - int *seq_len, bfd_byte *contents, - Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - /* There are 2 variations for LONGJUMP5 - case 2-4; 1st insn convertible, 16-bit on. - movi55 ta, imm11 ; LONGJUMP7/INSN16 - beq rt, ta, label ; 15_PCREL - - case 4-4; 1st insn not convertible - movi55 ta, imm11 ; LONGJUMP7/INSN16 - beq rt, ta, label ; 15_PCREL */ - - bfd_vma laddr; - Elf_Internal_Rela *cond_irel, *irelend, *insn_irel; - int pic_ext_target = 0; - bfd_signed_vma foff; - uint32_t insn, re_insn = 0; - uint16_t insn16; - uint32_t imm11; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - cond_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_15_PCREL_RELA, irel->r_addend); - if (cond_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP7", - irel->r_offset); - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr, - &pic_ext_target); - - if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_8BIT_S1 - || foff >= CONSERVATIVE_8BIT_S1) - return FALSE; - - /* Get the first instruction for its size. */ - insn = bfd_getb32 (contents + laddr); - if (insn & 0x80000000) - { - *seq_len = 0; - /* Get the immediate from movi55. */ - imm11 = N16_IMM5S (insn >> 16); - } - else - { - /* Get the immediate from movi. */ - imm11 = N32_IMM20S (insn); - } - - /* Get the branch instruction. */ - insn = bfd_getb32 (contents + irel->r_addend); - /* Convert instruction to BR3. */ - if ((insn >> 14) & 0x1) - re_insn = N32_BR3 (BNEC, N32_RT5 (insn), imm11, 0); - else - re_insn = N32_BR3 (BEQC, N32_RT5 (insn), imm11, 0); - - bfd_putb32 (re_insn, contents + cond_irel->r_offset); - - /* Set all relocations. */ - cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), - R_NDS32_WORD_9_PCREL_RELA); - - /* Clean relocations. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_INSN16, irel->r_offset); - if (insn_irel != irelend) - { - if (*seq_len == 0) - { - /* If the first insntruction is 16bit, convert it to nop16. */ - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + laddr); - insn_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG; - } - else - cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), - R_NDS32_NONE); - } - *insn_len = 0; - - return TRUE; -} - -#define GET_LOADSTORE_RANGE(addend) (((addend) >> 8) & 0x3f) - -/* Relax LOADSTORE relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_loadstore (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr, int load_store_relax) -{ - int eliminate_sethi = 0, range_type; - unsigned int i; - bfd_vma local_sda, laddr; - int seq_len; /* Original length of instruction sequence. */ - uint32_t insn; - Elf_Internal_Rela *hi_irelfn = NULL, *irelend; - bfd_vma access_addr = 0; - bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ - enum elf_nds32_reloc_type checked_types[] = - { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20, - R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20, - R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20, - R_NDS32_TLS_LE_HI20 - }; - - irelend = internal_relocs + sec->reloc_count; - seq_len = GET_SEQ_LEN (irel->r_addend); - laddr = irel->r_offset; - *insn_len = seq_len; - - /* Get the high part relocation. */ - for (i = 0; i < ARRAY_SIZE (checked_types); i++) - { - hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend, - checked_types[i], laddr); - if (hi_irelfn != irelend) - break; - } - - if (hi_irelfn == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LOADSTORE", - irel->r_offset); - return FALSE; - } - - range_type = GET_LOADSTORE_RANGE (irel->r_addend); - nds32_elf_final_sda_base (sec->output_section->owner, - link_info, &local_sda, FALSE); - - switch (ELF32_R_TYPE (hi_irelfn->r_info)) - { - case R_NDS32_HI20_RELA: - insn = bfd_getb32 (contents + laddr); - access_addr = - calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); - - if (range_type == NDS32_LOADSTORE_IMM) - { - struct elf_link_hash_entry *h = NULL; - int indx; - - if (ELF32_R_SYM (hi_irelfn->r_info) >= symtab_hdr->sh_info) - { - indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - } - - if ((access_addr < CONSERVATIVE_20BIT) - && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0))) - { - eliminate_sethi = 1; - break; - } - - /* This is avoid to relax symbol address which is fixed - relocations. Ex: _stack. */ - if (h && bfd_is_abs_section (h->root.u.def.section)) - return FALSE; - } - - if (!load_store_relax) - return FALSE; - - /* Case for set gp register. */ - if (N32_RT5 (insn) == REG_GP) - break; - - if (range_type == NDS32_LOADSTORE_FLOAT_S - || range_type == NDS32_LOADSTORE_FLOAT_D) - { - range_l = sdata_range[0][0]; - range_h = sdata_range[0][1]; - } - else - { - range_l = sdata_range[1][0]; - range_h = sdata_range[1][1]; - } - break; - - case R_NDS32_GOT_HI20: - access_addr = - calculate_got_memory_address (abfd, link_info, hi_irelfn, symtab_hdr); - - /* If this symbol is not in .got, the return value will be -1. - Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE, - a negative offset is allowed. */ - if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT - && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) - eliminate_sethi = 1; - break; - - case R_NDS32_PLT_GOTREL_HI20: - access_addr = calculate_plt_memory_address (abfd, link_info, isymbuf, - hi_irelfn, symtab_hdr); - - if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT - && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) - eliminate_sethi = 1; - break; - - case R_NDS32_GOTOFF_HI20: - access_addr = - calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); - - if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT - && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT) - eliminate_sethi = 1; - break; - - case R_NDS32_GOTPC_HI20: - /* The access_addr must consider r_addend of hi_irel. */ - access_addr = sec->output_section->vma + sec->output_offset - + irel->r_offset + hi_irelfn->r_addend; - - if ((bfd_signed_vma) (local_sda - access_addr) < CONSERVATIVE_20BIT - && (bfd_signed_vma) (local_sda - access_addr) >= -CONSERVATIVE_20BIT) - eliminate_sethi = 1; - break; - - case R_NDS32_TLS_LE_HI20: - access_addr = - calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr); - BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); - access_addr -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); - if ((range_type == NDS32_LOADSTORE_IMM) - && (bfd_signed_vma) (access_addr) < CONSERVATIVE_20BIT - && (bfd_signed_vma) (access_addr) >= -CONSERVATIVE_20BIT) - eliminate_sethi = 1; - break; - - default: - return FALSE; - } - - /* Delete sethi instruction. */ - if (eliminate_sethi == 1 - || (local_sda <= access_addr && (access_addr - local_sda) < range_h) - || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) - { - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - *insn_len = 0; - } - return TRUE; -} - -/* Relax LO12 relocation for nds32_elf_relax_section. */ - -static void -nds32_elf_relax_lo12 (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, bfd_byte *contents, - Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr) -{ - uint32_t insn; - bfd_vma local_sda, laddr; - unsigned long reloc; - bfd_vma access_addr; - bfd_vma range_l = 0, range_h = 0; /* Upper/lower bound. */ - Elf_Internal_Rela *irelfn = NULL, *irelend; - struct elf_link_hash_entry *h = NULL; - int indx; - - /* For SDA base relative relaxation. */ - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - - if (!is_sda_access_insn (insn) && N32_OP6 (insn) != N32_OP6_ORI) - return; - - access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - - if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info) - { - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - } - - if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < CONSERVATIVE_20BIT - && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0))) - { - reloc = R_NDS32_20_RELA; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + laddr); - } - /* This is avoid to relax symbol address which is fixed - relocations. Ex: _stack. */ - else if (N32_OP6 (insn) == N32_OP6_ORI - && h && bfd_is_abs_section (h->root.u.def.section)) - return; - else - { - range_l = sdata_range[1][0]; - range_h = sdata_range[1][1]; - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_NDS32_LO12S0_RELA: - reloc = R_NDS32_SDA19S0_RELA; - break; - case R_NDS32_LO12S1_RELA: - reloc = R_NDS32_SDA18S1_RELA; - break; - case R_NDS32_LO12S2_RELA: - reloc = R_NDS32_SDA17S2_RELA; - break; - case R_NDS32_LO12S2_DP_RELA: - range_l = sdata_range[0][0]; - range_h = sdata_range[0][1]; - reloc = R_NDS32_SDA12S2_DP_RELA; - break; - case R_NDS32_LO12S2_SP_RELA: - range_l = sdata_range[0][0]; - range_h = sdata_range[0][1]; - reloc = R_NDS32_SDA12S2_SP_RELA; - break; - default: - return; - } - - /* There are range_h and range_l because linker has to promise - all sections move cross one page together. */ - if ((local_sda <= access_addr && (access_addr - local_sda) < range_h) - || (local_sda > access_addr && (local_sda - access_addr) <= range_l)) - { - if (N32_OP6 (insn) == N32_OP6_ORI && N32_RT5 (insn) == REG_GP) - { - /* Maybe we should add R_NDS32_INSN16 reloc type here - or manually do some optimization. sethi can't be - eliminated when updating $gp so the relative ori - needs to be preserved. */ - return; - } - if (!turn_insn_to_sda_access (insn, ELF32_R_TYPE (irel->r_info), - &insn)) - return; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - bfd_putb32 (insn, contents + laddr); - - irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_INSN16); - /* SDA17 must keep INSN16 for converting fp_as_gp. */ - if (irelfn != irelend && reloc != R_NDS32_SDA17S2_RELA) - irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_NDS32_NONE); - - } - } - return; -} - -/* Relax low part of PIC instruction pattern. */ - -static void -nds32_elf_relax_piclo12 (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - uint32_t insn; - bfd_vma local_sda, laddr; - bfd_signed_vma foff; - unsigned long reloc; - - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - - if (N32_OP6 (insn) != N32_OP6_ORI) - return; - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12) - { - foff = calculate_got_memory_address (abfd, link_info, irel, - symtab_hdr) - local_sda; - reloc = R_NDS32_GOT20; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12) - { - foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel, - symtab_hdr) - local_sda; - reloc = R_NDS32_PLT_GOTREL_LO20; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12) - { - foff = calculate_memory_address (abfd, irel, isymbuf, - symtab_hdr) - local_sda; - reloc = R_NDS32_GOTOFF; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12) - { - foff = local_sda - sec->output_section->vma + sec->output_offset - + irel->r_offset + irel->r_addend; - reloc = R_NDS32_GOTPC20; - } - else - return; - - if ((foff < CONSERVATIVE_20BIT) && (foff >= -CONSERVATIVE_20BIT)) - { - /* Turn into MOVI. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + laddr); - } -} - -/* Relax low part of LE TLS instruction pattern. */ - -static void -nds32_elf_relax_letlslo12 (struct bfd_link_info *link_info, bfd *abfd, - Elf_Internal_Rela *irel, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr) -{ - uint32_t insn; - bfd_vma laddr; - bfd_signed_vma foff; - unsigned long reloc; - - laddr = irel->r_offset; - foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); - foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); - insn = bfd_getb32 (contents + laddr); - - if ( (bfd_signed_vma) (foff) < CONSERVATIVE_20BIT - && (bfd_signed_vma) (foff) >= -CONSERVATIVE_20BIT) - { - /* Pattern sethi-ori transform to movi. */ - reloc = R_NDS32_TLS_LE_20; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc); - insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0); - bfd_putb32 (insn, contents + laddr); - } -} - -/* Relax LE TLS calculate address instruction pattern. */ - -static void -nds32_elf_relax_letlsadd (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) -{ - /* Local TLS non-pic - sethi ta, hi20(symbol@tpoff) ; TLS_LE_HI20 - ori ta, ta, lo12(symbol@tpoff) ; TLS_LE_LO12 - add ra, ta, tp ; TLS_LE_ADD */ - - uint32_t insn; - bfd_vma laddr; - bfd_signed_vma foff; - Elf_Internal_Rela *i1_irelfn, *irelend; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); - foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); - - /* The range is +/-16k. */ - if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT - && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT) - { - /* Transform add to addi. */ - insn = N32_TYPE2 (ADDI, N32_RT5 (insn), N32_RB5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0); - - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } - } -} - -/* Relax LE TLS load store instruction pattern. */ - -static void -nds32_elf_relax_letlsls (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) -{ - - uint32_t insn; - bfd_vma laddr; - bfd_signed_vma foff; - Elf_Internal_Rela *i1_irelfn, *irelend; - int success = 0; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL); - foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET); - - switch ((N32_OP6 (insn) << 8) | (insn & 0xff)) - { - case (N32_OP6_MEM << 8) | N32_MEM_LB: - case (N32_OP6_MEM << 8) | N32_MEM_SB: - case (N32_OP6_MEM << 8) | N32_MEM_LBS: - /* The range is +/-16k. */ - if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT - && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT) - { - insn = - ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0); - success = 1; - break; - } - /* Fall through. */ - case (N32_OP6_MEM << 8) | N32_MEM_LH: - case (N32_OP6_MEM << 8) | N32_MEM_SH: - case (N32_OP6_MEM << 8) | N32_MEM_LHS: - /* The range is +/-32k. */ - if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S1 - && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S1) - { - insn = - ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S1); - success = 1; - break; - } - /* Fall through. */ - case (N32_OP6_MEM << 8) | N32_MEM_LW: - case (N32_OP6_MEM << 8) | N32_MEM_SW: - /* The range is +/-64k. */ - if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S2 - && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S2) - { - insn = - ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S2); - success = 1; - break; - } - /* Fall through. */ - default: - break; - } - - if (success) - { - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } - } -} - -/* Relax PTR relocation for nds32_elf_relax_section. */ - -static bfd_boolean -nds32_elf_relax_ptr (bfd *abfd, asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, int *insn_len, - int *seq_len, bfd_byte *contents) -{ - Elf_Internal_Rela *ptr_irel, *irelend, *count_irel, *re_irel; - - irelend = internal_relocs + sec->reloc_count; - - re_irel = - find_relocs_at_address_addr (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED, irel->r_addend); - - if (re_irel == irelend) - { - _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_PTR", - irel->r_offset); - return FALSE; - } - - if (re_irel->r_addend != 1) - return FALSE; - - /* Pointed target is relaxed and no longer needs this void *, - change the type to NONE. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - - /* Find PTR_COUNT to decide remove it or not. If PTR_COUNT does - not exist, it means only count 1 and remove it directly. */ - /* TODO: I hope we can obsolate R_NDS32_COUNT in the future. */ - count_irel = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_COUNT); - ptr_irel = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR); - if (count_irel != irelend) - { - if (--count_irel->r_addend > 0) - return FALSE; - } - - if (ptr_irel != irelend) - return FALSE; - - /* If the PTR_COUNT is already 0, remove current instruction. */ - *seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset); - *insn_len = 0; - return TRUE; -} - -/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section. */ - -static void -nds32_elf_relax_pltgot_suff (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) -{ - uint32_t insn; - bfd_signed_vma foff; - Elf_Internal_Rela *i1_irelfn, *irelend; - bfd_vma local_sda, laddr; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - - /* FIXME: It's a little trouble to turn JRAL5 to JAL since - we need additional space. It might be help if we could - borrow some space from instructions to be eliminated - such as sethi, ori, add. */ - if (insn & 0x80000000) - return; - - if (nds32_elf_check_dup_relocs - (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF)) - return; - - i1_irelfn = - find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - - /* FIXIT 090606 - The boundary should be reduced since the .plt section hasn't - been created and the address of specific entry is still unknown - Maybe the range between the function call and the begin of the - .text section can be used to decide if the .plt is in the range - of function call. */ - - if (N32_OP6 (insn) == N32_OP6_ALU1 - && N32_SUB5 (insn) == N32_ALU1_ADD) - { - /* Get the value of the symbol referred to by the reloc. */ - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - foff = (bfd_signed_vma) (calculate_plt_memory_address - (abfd, link_info, isymbuf, irel, - symtab_hdr) - local_sda); - /* This condition only happened when symbol is undefined. */ - if (foff == 0) - return; - - if (foff < -CONSERVATIVE_19BIT || foff >= CONSERVATIVE_19BIT) - return; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_PLT_GOTREL_LO19); - /* addi.gp */ - insn = N32_TYPE1 (SBGP, N32_RT5 (insn), N32_BIT (19)); - } - else if (N32_OP6 (insn) == N32_OP6_JREG - && N32_SUB5 (insn) == N32_JREG_JRAL) - { - /* Get the value of the symbol referred to by the reloc. */ - foff = - calculate_plt_offset (abfd, sec, link_info, isymbuf, irel, symtab_hdr); - /* This condition only happened when symbol is undefined. */ - if (foff == 0) - return; - if (foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1) - return; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL); - insn = INSN_JAL; - } - else - return; - - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } -} - -/* Relax GOT_SUFF relocation for nds32_elf_relax_section. */ - -static void -nds32_elf_relax_got_suff (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents, Elf_Internal_Shdr *symtab_hdr, - bfd_boolean *again) -{ - uint32_t insn; - bfd_signed_vma foff; - Elf_Internal_Rela *i1_irelfn, *irelend; - bfd_vma local_sda, laddr; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - if (insn & 0x80000000) - return; - - if (nds32_elf_check_dup_relocs - (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF)) - return; - - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - foff = calculate_got_memory_address (abfd, link_info, irel, - symtab_hdr) - local_sda; - - if (foff < CONSERVATIVE_19BIT && foff >= -CONSERVATIVE_19BIT) - { - /* Turn LW to LWI.GP. Change relocation type to R_NDS32_GOT_REL. */ - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA); - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } - } -} - -/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section. */ - -static void -nds32_elf_relax_gotoff_suff (struct bfd_link_info *link_info, bfd *abfd, - asection *sec, Elf_Internal_Rela *irel, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents, Elf_Internal_Sym *isymbuf, - Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again) -{ - int opc_insn_gotoff; - uint32_t insn; - bfd_signed_vma foff; - Elf_Internal_Rela *i1_irelfn, *i2_irelfn, *irelend; - bfd_vma local_sda, laddr; - - irelend = internal_relocs + sec->reloc_count; - laddr = irel->r_offset; - insn = bfd_getb32 (contents + laddr); - - if (insn & 0x80000000) - return; - - if (nds32_elf_check_dup_relocs - (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF)) - return; - - i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_PTR_RESOLVED); - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &local_sda, FALSE); - foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - foff = foff - local_sda; - - if (foff >= CONSERVATIVE_19BIT || foff < -CONSERVATIVE_19BIT) - return; - - /* Concatenate opcode and sub-opcode for switch case. - It may be MEM or ALU1. */ - opc_insn_gotoff = (N32_OP6 (insn) << 8) | (insn & 0xff); - switch (opc_insn_gotoff) - { - case (N32_OP6_MEM << 8) | N32_MEM_LW: - /* 4-byte aligned. */ - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_SW: - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LH: - /* 2-byte aligned. */ - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LHS: - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), N32_BIT (18)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_SH: - insn = N32_TYPE1 (HWGP, N32_RT5 (insn), N32_BIT (19)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LB: - /* 1-byte aligned. */ - insn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_LBS: - insn = N32_TYPE1 (LBGP, N32_RT5 (insn), N32_BIT (19)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - case (N32_OP6_MEM << 8) | N32_MEM_SB: - insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD: - insn = N32_TYPE1 (SBGP, N32_RT5 (insn), N32_BIT (19)); - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA); - break; - default: - return; - } - - bfd_putb32 (insn, contents + laddr); - if (i1_irelfn != irelend) - { - i1_irelfn->r_addend |= 1; - *again = TRUE; - } - if ((i2_irelfn = find_relocs_at_address (irel, internal_relocs, irelend, - R_NDS32_INSN16)) != irelend) - i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - -} - -static bfd_boolean -nds32_relax_adjust_label (bfd *abfd, asection *sec, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents, - nds32_elf_blank_t **relax_blank_list, - int optimize, int opt_size) -{ - /* This code block is used to adjust 4-byte alignment by relax a pair - of instruction a time. - - It recognizes three types of relocations. - 1. R_NDS32_LABEL - a alignment. - 2. R_NDS32_INSN16 - relax a 32-bit instruction to 16-bit. - 3. is_16bit_NOP () - remove a 16-bit instruction. */ - - /* TODO: It seems currently implementation only support 4-byte alignment. - We should handle any-alignment. */ - - Elf_Internal_Rela *insn_rel = NULL, *label_rel = NULL, *irel; - Elf_Internal_Rela *tmp_rel, *tmp2_rel = NULL; - Elf_Internal_Rela rel_temp; - Elf_Internal_Rela *irelend; - bfd_vma address; - uint16_t insn16; - - /* Checking for branch relaxation relies on the relocations to - be sorted on 'r_offset'. This is not guaranteed so we must sort. */ - nds32_insertion_sort (internal_relocs, sec->reloc_count, - sizeof (Elf_Internal_Rela), compar_reloc); - - irelend = internal_relocs + sec->reloc_count; - - /* Force R_NDS32_LABEL before R_NDS32_INSN16. */ - /* FIXME: Can we generate the right order in assembler? - So we don't have to swapping them here. */ - - for (label_rel = internal_relocs, insn_rel = internal_relocs; - label_rel < irelend; label_rel++) - { - if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL) - continue; - - /* Find the first reloc has the same offset with label_rel. */ - while (insn_rel < irelend && insn_rel->r_offset < label_rel->r_offset) - insn_rel++; - - for (;insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset; - insn_rel++) - /* Check if there were R_NDS32_INSN16 and R_NDS32_LABEL at the same - address. */ - if (ELF32_R_TYPE (insn_rel->r_info) == R_NDS32_INSN16) - break; - - if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset - && insn_rel < label_rel) - { - /* Swap the two reloc if the R_NDS32_INSN16 is - before R_NDS32_LABEL. */ - memcpy (&rel_temp, insn_rel, sizeof (Elf_Internal_Rela)); - memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela)); - memcpy (label_rel, &rel_temp, sizeof (Elf_Internal_Rela)); - } - } - - label_rel = NULL; - insn_rel = NULL; - /* If there were a sequence of R_NDS32_LABEL end up with .align 2 - or higher, remove other R_NDS32_LABEL with lower alignment. - If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted, - then the R_NDS32_LABEL sequence is broke. */ - for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++) - { - if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL) - { - if (label_rel == NULL) - { - if (tmp_rel->r_addend < 2) - label_rel = tmp_rel; - continue; - } - else if (tmp_rel->r_addend > 1) - { - /* Remove all LABEL relocation from label_rel to tmp_rel - including relocations with same offset as tmp_rel. */ - for (tmp2_rel = label_rel; tmp2_rel < tmp_rel - || tmp2_rel->r_offset == tmp_rel->r_offset; tmp2_rel++) - { - if (ELF32_R_TYPE (tmp2_rel->r_info) == R_NDS32_LABEL - && tmp2_rel->r_addend < 2) - tmp2_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (tmp2_rel->r_info), - R_NDS32_NONE); - } - label_rel = NULL; - } - } - else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 && label_rel) - { - /* A new INSN16 which can be converted, so clear label_rel. */ - if (is_convert_32_to_16 (abfd, sec, tmp_rel, internal_relocs, - irelend, &insn16) - || is_16bit_NOP (abfd, sec, tmp_rel)) - label_rel = NULL; - } - } - - label_rel = NULL; - insn_rel = NULL; - /* Optimized for speed and nothing has not been relaxed. - It's time to align labels. - We may convert a 16-bit instruction right before a label to - 32-bit, in order to align the label if necessary - all reloc entries has been sorted by r_offset. */ - for (irel = internal_relocs; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16 - && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL) - continue; - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16) - { - /* A new INSN16 found, resize the old one. */ - if (is_convert_32_to_16 - (abfd, sec, irel, internal_relocs, irelend, &insn16) - || is_16bit_NOP (abfd, sec, irel)) - { - if (insn_rel) - { - /* Previous INSN16 reloc exists, reduce its - size to 16-bit. */ - if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs, - irelend, &insn16)) - { - nds32_elf_write_16 (abfd, contents, insn_rel, - internal_relocs, irelend, insn16); - - if (!insert_nds32_elf_blank_recalc_total - (relax_blank_list, insn_rel->r_offset + 2, 2)) - return FALSE; - } - else if (is_16bit_NOP (abfd, sec, insn_rel)) - { - if (!insert_nds32_elf_blank_recalc_total - (relax_blank_list, insn_rel->r_offset, 2)) - return FALSE; - } - insn_rel->r_info = - ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), R_NDS32_NONE); - } - /* Save the new one for later use. */ - insn_rel = irel; - } - else - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_NDS32_NONE); - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL) - { - /* Search for label. */ - int force_relax = 0; - - /* Label on 16-bit instruction or optimization - needless, just reset this reloc. */ - insn16 = bfd_getb16 (contents + irel->r_offset); - if ((irel->r_addend & 0x1f) < 2 && (!optimize || (insn16 & 0x8000))) - { - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE); - continue; - } - - address = - irel->r_offset - get_nds32_elf_blank_total (relax_blank_list, - irel->r_offset, 1); - - if (!insn_rel) - { - /* Check if there is case which can not be aligned. */ - if (irel->r_addend == 2 && address & 0x2) - return FALSE; - continue; - } - - /* Try to align this label. */ - - if ((irel->r_addend & 0x1f) < 2) - { - /* Check if there is a INSN16 at the same address. - Label_rel always seats before insn_rel after - our sort. */ - - /* Search for INSN16 at LABEL location. If INSN16 is at - same location and this LABEL alignment is lower than 2, - the INSN16 can be converted to 2-byte. */ - for (tmp_rel = irel; - tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset; - tmp_rel++) - { - if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 - && (is_convert_32_to_16 - (abfd, sec, tmp_rel, internal_relocs, - irelend, &insn16) - || is_16bit_NOP (abfd, sec, tmp_rel))) - { - force_relax = 1; - break; - } - } - } - - if (force_relax || irel->r_addend == 1 || address & 0x2) - { - /* Label not aligned. */ - /* Previous reloc exists, reduce its size to 16-bit. */ - if (is_convert_32_to_16 (abfd, sec, insn_rel, - internal_relocs, irelend, &insn16)) - { - nds32_elf_write_16 (abfd, contents, insn_rel, - internal_relocs, irelend, insn16); - - if (!insert_nds32_elf_blank_recalc_total - (relax_blank_list, insn_rel->r_offset + 2, 2)) - return FALSE; - } - else if (is_16bit_NOP (abfd, sec, insn_rel)) - { - if (!insert_nds32_elf_blank_recalc_total - (relax_blank_list, insn_rel->r_offset, 2)) - return FALSE; - } - - } - /* INSN16 reloc is used. */ - insn_rel = NULL; - } - } - - address = - sec->size - get_nds32_elf_blank_total (relax_blank_list, sec->size, 0); - if (insn_rel && (address & 0x2 || opt_size)) - { - if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs, - irelend, &insn16)) - { - nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs, - irelend, insn16); - if (!insert_nds32_elf_blank_recalc_total - (relax_blank_list, insn_rel->r_offset + 2, 2)) - return FALSE; - insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), - R_NDS32_NONE); - } - else if (is_16bit_NOP (abfd, sec, insn_rel)) - { - if (!insert_nds32_elf_blank_recalc_total - (relax_blank_list, insn_rel->r_offset, 2)) - return FALSE; - insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), - R_NDS32_NONE); - } - } - insn_rel = NULL; - return TRUE; -} - -/* Pick relaxation round. */ - -static int -nds32_elf_pick_relax (bfd_boolean init, asection *sec, bfd_boolean *again, - struct elf_nds32_link_hash_table *table, - struct bfd_link_info *link_info) -{ - static asection *final_sec, *first_sec = NULL; - static bfd_boolean normal_again = FALSE; - static bfd_boolean set = FALSE; - static bfd_boolean first = TRUE; - int round_table[] = { - NDS32_RELAX_NORMAL_ROUND, - NDS32_RELAX_JUMP_IFC_ROUND, - NDS32_RELAX_EX9_BUILD_ROUND, - NDS32_RELAX_EX9_REPLACE_ROUND, - }; - static int pass = 0; - static int relax_round; - - /* The new round. */ - if (init && first_sec == sec) - { - set = TRUE; - normal_again = FALSE; - } - - if (first) - { - /* Run an empty run to get the final section. */ - relax_round = NDS32_RELAX_EMPTY_ROUND; - - /* It has to enter relax again because we can - not make sure what the final turn is. */ - *again = TRUE; - - first = FALSE; - first_sec = sec; - } - - if (!set) - { - /* Not reenter yet. */ - final_sec = sec; - return relax_round; - } - - relax_round = round_table[pass]; - - if (!init && relax_round == NDS32_RELAX_NORMAL_ROUND && *again) - normal_again = TRUE; - - if (!init && final_sec == sec) - { - switch (relax_round) - { - case NDS32_RELAX_NORMAL_ROUND: - if (!normal_again) - { - /* Normal relaxation done. */ - if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) - { - pass++; - *again = TRUE; - } - else if (table->target_optimize & NDS32_RELAX_EX9_ON) - { - pass += 2; /* NDS32_RELAX_EX9_BUILD_ROUND */ - *again = TRUE; - } - else if (table->ex9_import_file) - { - /* Import ex9 table. */ - if (table->update_ex9_table) - pass += 2; /* NDS32_RELAX_EX9_BUILD_ROUND */ - else - pass += 3; /* NDS32_RELAX_EX9_REPLACE_ROUND */ - nds32_elf_ex9_import_table (link_info); - *again = TRUE; - } - } - break; - case NDS32_RELAX_JUMP_IFC_ROUND: - if (!nds32_elf_ifc_finish (link_info)) - _bfd_error_handler (_("error: Jump IFC Fail.")); - if (table->target_optimize & NDS32_RELAX_EX9_ON) - { - pass++; - *again = TRUE; - } - break; - case NDS32_RELAX_EX9_BUILD_ROUND: - nds32_elf_ex9_finish (link_info); - pass++; - *again = TRUE; - break; - case NDS32_RELAX_EX9_REPLACE_ROUND: - if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON) - { - /* Do jump IFC optimization again. */ - if (!nds32_elf_ifc_finish (link_info)) - _bfd_error_handler (_("error: Jump IFC Fail.")); - } - break; - default: - break; - } - } - - return relax_round; -} - -static bfd_boolean -nds32_elf_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - nds32_elf_blank_t *relax_blank_list = NULL; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Sym *isymbuf = NULL; - bfd_byte *contents = NULL; - bfd_boolean result = TRUE; - int optimize = 0; - int opt_size = 0; - uint32_t insn; - uint16_t insn16; - - /* Target dependnet option. */ - struct elf_nds32_link_hash_table *table; - int load_store_relax; - int relax_round; - - relax_blank_list = NULL; - - *again = FALSE; - - /* Nothing to do for - * relocatable link or - * non-relocatable section or - * non-code section or - * empty content or - * no reloc entry. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || (sec->flags & SEC_EXCLUDE) != 0 - || (sec->flags & SEC_CODE) == 0 - || sec->size == 0) - return TRUE; - - /* 09.12.11 Workaround. */ - /* We have to adjust align for R_NDS32_LABEL if needed. - The adjust approach only can fix 2-byte align once. */ - if (sec->alignment_power > 2) - return TRUE; - - /* The optimization type to do. */ - - table = nds32_elf_hash_table (link_info); - relax_round = nds32_elf_pick_relax (TRUE, sec, again, table, link_info); - switch (relax_round) - { - case NDS32_RELAX_JUMP_IFC_ROUND: - /* Here is the entrance of ifc jump relaxation. */ - if (!nds32_elf_ifc_calc (link_info, abfd, sec)) - return FALSE; - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - - case NDS32_RELAX_EX9_BUILD_ROUND: - /* Here is the entrance of ex9 relaxation. There are two pass of - ex9 relaxation. The one is to traverse all instructions and build - the hash table. The other one is to compare instructions and replace - it by ex9.it. */ - if (!nds32_elf_ex9_build_hash_table (abfd, sec, link_info)) - return FALSE; - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - - case NDS32_RELAX_EX9_REPLACE_ROUND: - if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec)) - return FALSE; - return TRUE; - - case NDS32_RELAX_EMPTY_ROUND: - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - - case NDS32_RELAX_NORMAL_ROUND: - default: - if (sec->reloc_count == 0) - return TRUE; - break; - } - - /* The begining of general relaxation. */ - - if (is_SDA_BASE_set == 0) - { - bfd_vma gp; - is_SDA_BASE_set = 1; - nds32_elf_final_sda_base (sec->output_section->owner, link_info, - &gp, FALSE); - relax_range_measurement (abfd); - } - - if (is_ITB_BASE_set == 0) - { - /* Set the _ITB_BASE_. */ - if (!nds32_elf_ex9_itb_base (link_info)) - { - _bfd_error_handler (_("%B: error: Cannot set _ITB_BASE_"), abfd); - bfd_set_error (bfd_error_bad_value); - } - } - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - /* Relocations MUST be kept in memory, because relaxation adjust them. */ - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - TRUE /* keep_memory */); - if (internal_relocs == NULL) - goto error_return; - - irelend = internal_relocs + sec->reloc_count; - irel = find_relocs_at_address (internal_relocs, internal_relocs, - irelend, R_NDS32_RELAX_ENTRY); - - if (irel == irelend) - return TRUE; - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY) - { - if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG) - { - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - return TRUE; - } - - if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG) - optimize = 1; - - if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG) - opt_size = 1; - } - - load_store_relax = table->load_store_relax; - - /* Get symbol table and section content. */ - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) - || !nds32_get_local_syms (abfd, sec, &isymbuf)) - goto error_return; - - /* Do relax loop only when finalize is not done. - Take care of relaxable relocs except INSN16. */ - for (irel = internal_relocs; irel < irelend; irel++) - { - int seq_len; /* Original length of instruction sequence. */ - int insn_len = 0; /* Final length of instruction sequence. */ - bfd_boolean removed; - - insn = 0; - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) >= 2) - optimize = 1; - - /* Relocation Types - R_NDS32_LONGCALL1 53 - R_NDS32_LONGCALL2 54 - R_NDS32_LONGCALL3 55 - R_NDS32_LONGJUMP1 56 - R_NDS32_LONGJUMP2 57 - R_NDS32_LONGJUMP3 58 - R_NDS32_LOADSTORE 59 */ - if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE) - seq_len = GET_SEQ_LEN (irel->r_addend); - - /* Relocation Types - R_NDS32_LONGCALL4 107 - R_NDS32_LONGCALL5 108 - R_NDS32_LONGCALL6 109 - R_NDS32_LONGJUMP4 110 - R_NDS32_LONGJUMP5 111 - R_NDS32_LONGJUMP6 112 - R_NDS32_LONGJUMP7 113 */ - else if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL4 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP7) - seq_len = 4; - - /* Relocation Types - R_NDS32_LO12S0_RELA 30 - R_NDS32_LO12S1_RELA 29 - R_NDS32_LO12S2_RELA 28 - R_NDS32_LO12S2_SP_RELA 71 - R_NDS32_LO12S2_DP_RELA 70 - R_NDS32_GOT_LO12 46 - R_NDS32_GOTOFF_LO12 50 - R_NDS32_PLTREL_LO12 65 - R_NDS32_PLT_GOTREL_LO12 67 - R_NDS32_17IFC_PCREL_RELA 96 - R_NDS32_GOT_SUFF 193 - R_NDS32_GOTOFF_SUFF 194 - R_NDS32_PLT_GOT_SUFF 195 - R_NDS32_MULCALL_SUFF 196 - R_NDS32_PTR 197 */ - else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA - && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA) - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12 - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR) - || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LO12 - || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_ADD - || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LS) - seq_len = 0; - else - continue; - - insn_len = seq_len; - removed = FALSE; - - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_NDS32_LONGCALL1: - removed = nds32_elf_relax_longcall1 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGCALL2: - removed = nds32_elf_relax_longcall2 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGCALL3: - removed = nds32_elf_relax_longcall3 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGJUMP1: - removed = nds32_elf_relax_longjump1 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGJUMP2: - removed = nds32_elf_relax_longjump2 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGJUMP3: - removed = nds32_elf_relax_longjump3 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGCALL4: - removed = nds32_elf_relax_longcall4 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGCALL5: - removed = nds32_elf_relax_longcall5 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGCALL6: - removed = nds32_elf_relax_longcall6 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGJUMP4: - removed = nds32_elf_relax_longjump4 (abfd, sec, irel, internal_relocs, - &insn_len, contents, isymbuf, - symtab_hdr); - break; - case R_NDS32_LONGJUMP5: - removed = nds32_elf_relax_longjump5 (abfd, sec, irel, internal_relocs, - &insn_len, &seq_len, contents, - isymbuf, symtab_hdr); - break; - case R_NDS32_LONGJUMP6: - removed = nds32_elf_relax_longjump6 (abfd, sec, irel, internal_relocs, - &insn_len, &seq_len, contents, - isymbuf, symtab_hdr); - break; - case R_NDS32_LONGJUMP7: - removed = nds32_elf_relax_longjump7 (abfd, sec, irel, internal_relocs, - &insn_len, &seq_len, contents, - isymbuf, symtab_hdr); - break; - case R_NDS32_LOADSTORE: - removed = nds32_elf_relax_loadstore (link_info, abfd, sec, irel, - internal_relocs, &insn_len, - contents, isymbuf, symtab_hdr, - load_store_relax); - break; - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S1_RELA: - case R_NDS32_LO12S2_DP_RELA: - case R_NDS32_LO12S2_SP_RELA: - case R_NDS32_LO12S2_RELA: - /* Relax for low part. */ - nds32_elf_relax_lo12 (link_info, abfd, sec, irel, internal_relocs, - contents, isymbuf, symtab_hdr); - - /* It is impossible to delete blank, so just continue. */ - continue; - case R_NDS32_GOT_LO12: - case R_NDS32_GOTOFF_LO12: - case R_NDS32_PLTREL_LO12: - case R_NDS32_PLT_GOTREL_LO12: - case R_NDS32_GOTPC_LO12: - /* Relax for PIC gp-relative low part. */ - nds32_elf_relax_piclo12 (link_info, abfd, sec, irel, contents, - isymbuf, symtab_hdr); - - /* It is impossible to delete blank, so just continue. */ - continue; - case R_NDS32_TLS_LE_LO12: - /* Relax for LE TLS low part. */ - nds32_elf_relax_letlslo12 (link_info, abfd, irel, contents, - isymbuf, symtab_hdr); - - /* It is impossible to delete blank, so just continue. */ - continue; - case R_NDS32_TLS_LE_ADD: - nds32_elf_relax_letlsadd (link_info, abfd, sec, irel, internal_relocs, - contents, isymbuf, symtab_hdr, again); - /* It is impossible to delete blank, so just continue. */ - continue; - case R_NDS32_TLS_LE_LS: - nds32_elf_relax_letlsls (link_info, abfd, sec, irel, internal_relocs, - contents, isymbuf, symtab_hdr, again); - continue; - case R_NDS32_PTR: - removed = nds32_elf_relax_ptr (abfd, sec, irel, internal_relocs, - &insn_len, &seq_len, contents); - break; - case R_NDS32_PLT_GOT_SUFF: - nds32_elf_relax_pltgot_suff (link_info, abfd, sec, irel, - internal_relocs, contents, - isymbuf, symtab_hdr, again); - /* It is impossible to delete blank, so just continue. */ - continue; - case R_NDS32_GOT_SUFF: - nds32_elf_relax_got_suff (link_info, abfd, sec, irel, - internal_relocs, contents, - symtab_hdr, again); - /* It is impossible to delete blank, so just continue. */ - continue; - case R_NDS32_GOTOFF_SUFF: - nds32_elf_relax_gotoff_suff (link_info, abfd, sec, irel, - internal_relocs, contents, - isymbuf, symtab_hdr, again); - /* It is impossible to delete blank, so just continue. */ - continue; - default: - continue; - - } - if (removed && seq_len - insn_len > 0) - { - if (!insert_nds32_elf_blank - (&relax_blank_list, irel->r_offset + insn_len, - seq_len - insn_len)) - goto error_return; - *again = TRUE; - } - } - - calc_nds32_blank_total (relax_blank_list); - - if (table->relax_fp_as_gp) - { - if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs, - irelend, isymbuf)) - goto error_return; - - if (!*again) - { - if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs, - irelend)) - goto error_return; - } - } - - nds32_elf_pick_relax (FALSE, sec, again, table, link_info); - - if (!*again) - { - if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents, - &relax_blank_list, optimize, opt_size)) - goto error_return; - } - - /* It doesn't matter optimize_for_space_no_align anymore. - If object file is assembled with flag '-Os', - the we don't adjust jump-destination on 4-byte boundary. */ - - if (relax_blank_list) - { - nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); - relax_blank_list = NULL; - } - - if (!*again) - { - /* Closing the section, so we don't relax it anymore. */ - bfd_vma sec_size_align; - Elf_Internal_Rela *tmp_rel; - - /* Pad to alignment boundary. Only handle current section alignment. */ - sec_size_align = (sec->size + (~((-1U) << sec->alignment_power))) - & ((-1U) << sec->alignment_power); - if ((sec_size_align - sec->size) & 0x2) - { - insn16 = NDS32_NOP16; - bfd_putb16 (insn16, contents + sec->size); - sec->size += 2; - } - - while (sec_size_align != sec->size) - { - insn = NDS32_NOP32; - bfd_putb32 (insn, contents + sec->size); - sec->size += 4; - } - - tmp_rel = find_relocs_at_address (internal_relocs, internal_relocs, - irelend, R_NDS32_RELAX_ENTRY); - if (tmp_rel != irelend) - tmp_rel->r_addend |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG; - - clean_nds32_elf_blank (); - } - -finish: - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - - if (isymbuf != NULL && symtab_hdr->contents != (bfd_byte *) isymbuf) - free (isymbuf); - - return result; - -error_return: - result = FALSE; - goto finish; -} - -static struct bfd_elf_special_section const nds32_elf_special_sections[] = -{ - {".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE}, - {".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE}, - {NULL, 0, 0, 0, 0} -}; - -static bfd_boolean -nds32_elf_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - void *finfo ATTRIBUTE_UNUSED, - bfd_boolean (*func) (void *, const char *, - Elf_Internal_Sym *, - asection *, - struct elf_link_hash_entry *) - ATTRIBUTE_UNUSED) -{ - FILE *sym_ld_script = NULL; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - sym_ld_script = table->sym_ld_script; - - if (check_start_export_sym) - fprintf (sym_ld_script, "}\n"); - - return TRUE; -} - -static enum elf_reloc_type_class -nds32_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_NDS32_RELATIVE: - return reloc_class_relative; - case R_NDS32_JMP_SLOT: - return reloc_class_plt; - case R_NDS32_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Put target dependent option into info hash table. */ -void -bfd_elf32_nds32_set_target_option (struct bfd_link_info *link_info, - int relax_fp_as_gp, - int eliminate_gc_relocs, - FILE * sym_ld_script, int load_store_relax, - int target_optimize, int relax_status, - int relax_round, FILE * ex9_export_file, - FILE * ex9_import_file, - int update_ex9_table, int ex9_limit, - bfd_boolean ex9_loop_aware, - bfd_boolean ifc_loop_aware) -{ - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (link_info); - if (table == NULL) - return; - - table->relax_fp_as_gp = relax_fp_as_gp; - table->eliminate_gc_relocs = eliminate_gc_relocs; - table->sym_ld_script = sym_ld_script; - table ->load_store_relax = load_store_relax; - table->target_optimize = target_optimize; - table->relax_status = relax_status; - table->relax_round = relax_round; - table->ex9_export_file = ex9_export_file; - table->ex9_import_file = ex9_import_file; - table->update_ex9_table = update_ex9_table; - table->ex9_limit = ex9_limit; - table->ex9_loop_aware = ex9_loop_aware; - table->ifc_loop_aware = ifc_loop_aware; -} - -/* These functions and data-structures are used for fp-as-gp - optimization. */ - -#define FAG_THRESHOLD 3 /* At least 3 gp-access. */ -/* lwi37.fp covers 508 bytes, but there may be 32-byte padding between - the read-only section and read-write section. */ -#define FAG_WINDOW (508 - 32) - -/* An nds32_fag represent a gp-relative access. - We find best fp-base by using a sliding window - to find a base address which can cover most gp-access. */ -struct nds32_fag -{ - struct nds32_fag *next; /* NULL-teminated linked list. */ - bfd_vma addr; /* The address of this fag. */ - Elf_Internal_Rela **relas; /* The relocations associated with this fag. - It is used for applying FP7U2_FLAG. */ - int count; /* How many times this address is referred. - There should be exactly `count' relocations - in relas. */ - int relas_capcity; /* The buffer size of relas. - We use an array instead of linked-list, - and realloc is used to adjust buffer size. */ -}; - -static void -nds32_fag_init (struct nds32_fag *head) -{ - memset (head, 0, sizeof (struct nds32_fag)); -} - -static void -nds32_fag_verify (struct nds32_fag *head) -{ - struct nds32_fag *iter; - struct nds32_fag *prev; - - prev = NULL; - iter = head->next; - while (iter) - { - if (prev && prev->addr >= iter->addr) - puts ("Bug in fp-as-gp insertion."); - prev = iter; - iter = iter->next; - } -} - -/* Insert a fag in ascending order. - If a fag of the same address already exists, - they are chained by relas array. */ - -static void -nds32_fag_insert (struct nds32_fag *head, bfd_vma addr, - Elf_Internal_Rela * rel) -{ - struct nds32_fag *iter; - struct nds32_fag *new_fag; - const int INIT_RELAS_CAP = 4; - - for (iter = head; - iter->next && iter->next->addr <= addr; - iter = iter->next) - /* Find somewhere to insert. */ ; - - /* `iter' will be equal to `head' if the list is empty. */ - if (iter != head && iter->addr == addr) - { - /* The address exists in the list. - Insert `rel' into relocation list, relas. */ - - /* Check whether relas is big enough. */ - if (iter->count >= iter->relas_capcity) - { - iter->relas_capcity *= 2; - iter->relas = bfd_realloc - (iter->relas, iter->relas_capcity * sizeof (void *)); - } - iter->relas[iter->count++] = rel; - return; - } - - /* This is a new address. Create a fag node for it. */ - new_fag = bfd_malloc (sizeof (struct nds32_fag)); - memset (new_fag, 0, sizeof (*new_fag)); - new_fag->addr = addr; - new_fag->count = 1; - new_fag->next = iter->next; - new_fag->relas_capcity = INIT_RELAS_CAP; - new_fag->relas = (Elf_Internal_Rela **) - bfd_malloc (new_fag->relas_capcity * sizeof (void *)); - new_fag->relas[0] = rel; - iter->next = new_fag; - - nds32_fag_verify (head); -} - -static void -nds32_fag_free_list (struct nds32_fag *head) -{ - struct nds32_fag *iter; - - iter = head->next; - while (iter) - { - struct nds32_fag *tmp = iter; - iter = iter->next; - free (tmp->relas); - tmp->relas = NULL; - free (tmp); - } -} - -/* Find the best fp-base address. - The relocation associated with that address is returned, - so we can track the symbol instead of a fixed address. - - When relaxation, the address of an datum may change, - because a text section is shrinked, so the data section - moves forward. If the aligments of text and data section - are different, their distance may change too. - Therefore, tracking a fixed address is not appriate. */ - -static int -nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp) -{ - struct nds32_fag *base; /* First fag in the window. */ - struct nds32_fag *last; /* First fag outside the window. */ - int accu = 0; /* Usage accumulation. */ - struct nds32_fag *best; /* Best fag. */ - int baccu = 0; /* Best accumulation. */ - - /* Use first fag for initial, and find the last fag in the window. - - In each iteration, we could simply subtract previous fag - and accumulate following fags which are inside the window, - untill we each the end. */ - - if (head->next == NULL) - { - *bestpp = NULL; - return 0; - } - - /* Initialize base. */ - base = head->next; - best = base; - for (last = base; - last && last->addr < base->addr + FAG_WINDOW; - last = last->next) - accu += last->count; - - baccu = accu; - - /* Record the best base in each iteration. */ - while (base->next) - { - accu -= base->count; - base = base->next; - /* Account fags in window. */ - for (/* Nothing. */; - last && last->addr < base->addr + FAG_WINDOW; - last = last->next) - accu += last->count; - - /* A better fp-base? */ - if (accu > baccu) - { - best = base; - baccu = accu; - } - } - - if (bestpp) - *bestpp = best; - return baccu; -} - -/* Apply R_NDS32_INSN16_FP7U2_FLAG on gp-relative accesses, - so we can convert it fo fp-relative access later. - `best_fag' is the best fp-base. Only those inside the window - of best_fag is applied the flag. */ - -static bfd_boolean -nds32_fag_mark_relax (struct bfd_link_info *link_info, - bfd *abfd, struct nds32_fag *best_fag, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend) -{ - struct nds32_fag *ifag; - bfd_vma best_fpbase, gp; - bfd *output_bfd; - - output_bfd = abfd->sections->output_section->owner; - nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - best_fpbase = best_fag->addr; - - if (best_fpbase > gp + sdata_range[1][1] - || best_fpbase < gp - sdata_range[1][0]) - return FALSE; - - /* Mark these inside the window R_NDS32_INSN16_FP7U2_FLAG flag, - so we know they can be converted to lwi37.fp. */ - for (ifag = best_fag; - ifag && ifag->addr < best_fpbase + FAG_WINDOW; ifag = ifag->next) - { - int i; - - for (i = 0; i < ifag->count; i++) - { - Elf_Internal_Rela *insn16_rel; - Elf_Internal_Rela *fag_rel; - - fag_rel = ifag->relas[i]; - - /* Only if this is within the WINDOWS, FP7U2_FLAG - is applied. */ - - insn16_rel = find_relocs_at_address - (fag_rel, internal_relocs, irelend, R_NDS32_INSN16); - - if (insn16_rel != irelend) - insn16_rel->r_addend = R_NDS32_INSN16_FP7U2_FLAG; - } - } - return TRUE; -} - -/* Reset INSN16 to clean fp as gp. */ - -static void -nds32_fag_unmark_relax (struct nds32_fag *fag, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend) -{ - struct nds32_fag *ifag; - int i; - Elf_Internal_Rela *insn16_rel; - Elf_Internal_Rela *fag_rel; - - for (ifag = fag; ifag; ifag = ifag->next) - { - for (i = 0; i < ifag->count; i++) - { - fag_rel = ifag->relas[i]; - - /* Restore the INSN16 relocation. */ - insn16_rel = find_relocs_at_address - (fag_rel, internal_relocs, irelend, R_NDS32_INSN16); - - if (insn16_rel != irelend) - insn16_rel->r_addend &= ~R_NDS32_INSN16_FP7U2_FLAG; - } - } -} - -/* This is the main function of fp-as-gp optimization. - It should be called by relax_section. */ - -static bfd_boolean -nds32_relax_fp_as_gp (struct bfd_link_info *link_info, - bfd *abfd, asection *sec, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend, - Elf_Internal_Sym *isymbuf) -{ - Elf_Internal_Rela *begin_rel = NULL; - Elf_Internal_Rela *irel; - struct nds32_fag fag_head; - Elf_Internal_Shdr *symtab_hdr; - bfd_byte *contents; - bfd_boolean ifc_inside = FALSE; - - /* FIXME: Can we bfd_elf_link_read_relocs for the relocs? */ - - /* Per-function fp-base selection. - 1. Create a list for all the gp-relative access. - 2. Base on those gp-relative address, - find a fp-base which can cover most access. - 3. Use the fp-base for fp-as-gp relaxation. - - NOTE: If fp-as-gp is not worth to do, (e.g., less than 3 times), - we should - 1. delete the `la $fp, _FP_BASE_' instruction and - 2. not convert lwi.gp to lwi37.fp. - - To delete the _FP_BASE_ instruction, we simply apply - R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG flag in the r_addend to disable it. - - To suppress the conversion, we simply NOT to apply - R_NDS32_INSN16_FP7U2_FLAG flag. */ - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) - || !nds32_get_local_syms (abfd, sec, &isymbuf)) - return FALSE; - - /* Check whether it is worth for fp-as-gp optimization, - i.e., at least 3 gp-load. - - Set R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG if we should NOT - apply this optimization. */ - - for (irel = internal_relocs; irel < irelend; irel++) - { - /* We recognize R_NDS32_RELAX_REGION_BEGIN/_END for the region. - One we enter the begin of the region, we track all the LW/ST - instructions, so when we leave the region, we try to find - the best fp-base address for those LW/ST instructions. */ - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN - && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) - { - /* Begin of the region. */ - if (begin_rel) - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Nested OMIT_FP in %A."), abfd, sec); - - begin_rel = irel; - nds32_fag_init (&fag_head); - ifc_inside = FALSE; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END - && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG)) - { - int accu; - struct nds32_fag *best_fag, *tmp_fag; - int dist; - - /* End of the region. - Check whether it is worth to do fp-as-gp. */ - - if (begin_rel == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Unmatched OMIT_FP in %A."), abfd, sec); - continue; - } - - accu = nds32_fag_find_base (&fag_head, &best_fag); - - /* Clean FP7U2_FLAG because they may set ever. */ - tmp_fag = fag_head.next; - nds32_fag_unmark_relax (tmp_fag, internal_relocs, irelend); - - /* Check if it is worth, and FP_BASE is near enough to SDA_BASE. */ - if (accu < FAG_THRESHOLD - || !nds32_fag_mark_relax (link_info, abfd, best_fag, - internal_relocs, irelend)) - { - /* Not worth to do fp-as-gp. */ - begin_rel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG; - begin_rel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG; - irel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG; - irel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG; - nds32_fag_free_list (&fag_head); - begin_rel = NULL; - continue; - } - - /* R_SYM of R_NDS32_RELAX_REGION_BEGIN is not used by assembler, - so we use it to record the distance to the reloction of best - fp-base. */ - dist = best_fag->relas[0] - begin_rel; - BFD_ASSERT (dist > 0 && dist < 0xffffff); - /* Use high 16 bits of addend to record the _FP_BASE_ matched - relocation. And get the base value when relocating. */ - begin_rel->r_addend &= (0x1 << 16) - 1; - begin_rel->r_addend |= dist << 16; - - nds32_fag_free_list (&fag_head); - begin_rel = NULL; - } - - if (begin_rel == NULL || ifc_inside) - /* Skip if we are not in the region of fp-as-gp. */ - continue; - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S2_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA17S2_RELA) - { - bfd_vma addr; - uint32_t insn; - - /* A gp-relative access is found. Insert it to the fag-list. */ - - /* Rt is necessary an RT3, so it can be converted to lwi37.fp. */ - insn = bfd_getb32 (contents + irel->r_offset); - if (!N32_IS_RT3 (insn)) - continue; - - addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr); - nds32_fag_insert (&fag_head, addr, irel); - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA_FP7U2_RELA) - { - begin_rel = NULL; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) - { - /* Suppress fp as gp when encounter ifc. */ - ifc_inside = TRUE; - } - } - - return TRUE; -} - -/* Remove unused `la $fp, _FD_BASE_' instruction. */ - -static bfd_boolean -nds32_fag_remove_unused_fpbase (bfd *abfd, asection *sec, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irelend) -{ - Elf_Internal_Rela *irel; - Elf_Internal_Shdr *symtab_hdr; - bfd_byte *contents = NULL; - nds32_elf_blank_t *relax_blank_list = NULL; - bfd_boolean result = TRUE; - bfd_boolean unused_region = FALSE; - - /* - NOTE: Disable fp-as-gp if we encounter ifcall relocations. - * R_NDS32_17IFC_PCREL_RELA - * R_NDS32_10IFCU_PCREL_RELA - - CASE?????????????? - */ - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - nds32_get_section_contents (abfd, sec, &contents, TRUE); - - for (irel = internal_relocs; irel < irelend; irel++) - { - /* To remove unused fp-base, we simply find the REGION_NOT_OMIT_FP - we marked to in previous pass. - DO NOT scan relocations again, since we've alreadly decided it - and set the flag. */ - const char *syname; - int syndx; - uint32_t insn; - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN - && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG)) - unused_region = TRUE; - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END - && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG)) - unused_region = FALSE; - - /* We're not in the region. */ - if (!unused_region) - continue; - - /* _FP_BASE_ must be a GLOBAL symbol. */ - syndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - continue; - - /* The symbol name must be _FP_BASE_. */ - syname = elf_sym_hashes (abfd)[syndx]->root.root.string; - if (strcmp (syname, FP_BASE_NAME) != 0) - continue; - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA19S0_RELA) - { - /* addi.gp $fp, -256 */ - insn = bfd_getb32 (contents + irel->r_offset); - if (insn != INSN_ADDIGP_TO_FP) - continue; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S0_RELA) - { - /* addi $fp, $gp, -256 */ - insn = bfd_getb32 (contents + irel->r_offset); - if (insn != INSN_ADDI_GP_TO_FP) - continue; - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_20_RELA) - { - /* movi $fp, FP_BASE */ - insn = bfd_getb32 (contents + irel->r_offset); - if (insn != INSN_MOVI_TO_FP) - continue; - } - else - continue; - - /* We got here because a FP_BASE instruction is found. */ - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel->r_offset, 4)) - goto error_return; - } - -finish: - if (relax_blank_list) - { - nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); - relax_blank_list = NULL; - } - return result; - -error_return: - result = FALSE; - goto finish; -} - -/* This is a version of bfd_generic_get_relocated_section_contents. - We need this variety because relaxation will modify the dwarf - infomation. When there is undefined symbol reference error mesage, - linker need to dump line number where the symbol be used. However - the address is be relaxed, it can not get the original dwarf contents. - The variety only modify function call for reading in the section. */ - -static bfd_byte * -nds32_elf_get_relocated_section_contents (bfd *abfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - bfd *input_bfd = link_order->u.indirect.section->owner; - asection *input_section = link_order->u.indirect.section; - long reloc_size; - arelent **reloc_vector; - long reloc_count; - - reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); - if (reloc_size < 0) - return NULL; - - /* Read in the section. */ - if (!nds32_get_section_contents (input_bfd, input_section, &data, FALSE)) - return NULL; - - if (reloc_size == 0) - return data; - - reloc_vector = (arelent **) bfd_malloc (reloc_size); - if (reloc_vector == NULL) - return NULL; - - reloc_count = bfd_canonicalize_reloc (input_bfd, input_section, - reloc_vector, symbols); - if (reloc_count < 0) - goto error_return; - - if (reloc_count > 0) - { - arelent **parent; - for (parent = reloc_vector; *parent != NULL; parent++) - { - char *error_message = NULL; - asymbol *symbol; - bfd_reloc_status_type r; - - symbol = *(*parent)->sym_ptr_ptr; - if (symbol->section && discarded_section (symbol->section)) - { - bfd_byte *p; - static reloc_howto_type none_howto - = HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, - "unused", FALSE, 0, 0, FALSE); - - p = data + (*parent)->address * bfd_octets_per_byte (input_bfd); - _bfd_clear_contents ((*parent)->howto, input_bfd, input_section, - p); - (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - (*parent)->addend = 0; - (*parent)->howto = &none_howto; - r = bfd_reloc_ok; - } - else - r = bfd_perform_relocation (input_bfd, *parent, data, - input_section, - relocatable ? abfd : NULL, - &error_message); - - if (relocatable) - { - asection *os = input_section->output_section; - - /* A partial link, so keep the relocs. */ - os->orelocation[os->reloc_count] = *parent; - os->reloc_count++; - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - case bfd_reloc_undefined: - (*link_info->callbacks->undefined_symbol) - (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), - input_bfd, input_section, (*parent)->address, TRUE); - break; - case bfd_reloc_dangerous: - BFD_ASSERT (error_message != NULL); - (*link_info->callbacks->reloc_dangerous) - (link_info, error_message, - input_bfd, input_section, (*parent)->address); - break; - case bfd_reloc_overflow: - (*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); - break; - case bfd_reloc_outofrange: - /* PR ld/13730: - This error can result when processing some partially - complete binaries. Do not abort, but issue an error - message instead. */ - link_info->callbacks->einfo - /* xgettext:c-format */ - (_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"), - abfd, input_section, * parent); - goto error_return; - - default: - abort (); - break; - } - } - } - } - - free (reloc_vector); - return data; - -error_return: - free (reloc_vector); - return NULL; -} - -/* Link-time IFC relaxation. - In this optimization, we chains jump instructions - of the same destination with ifcall. */ - - -/* List to save jal and j relocation. */ -struct elf_nds32_ifc_symbol_entry -{ - asection *sec; - struct elf_link_hash_entry *h; - struct elf_nds32_ifc_irel_list *irel_head; - unsigned long insn; - int times; - int enable; /* Apply ifc. */ - int ex9_enable; /* Apply ifc after ex9. */ - struct elf_nds32_ifc_symbol_entry *next; -}; - -struct elf_nds32_ifc_irel_list -{ - Elf_Internal_Rela *irel; - asection *sec; - bfd_vma addr; - /* If this is set, then it is the last instruction for - ifc-chain, so it must be keep for the actual branching. */ - int keep; - struct elf_nds32_ifc_irel_list *next; -}; - -static struct elf_nds32_ifc_symbol_entry *ifc_symbol_head = NULL; - -/* Insert symbol of jal and j for ifc. */ - -static void -nds32_elf_ifc_insert_symbol (asection *sec, - struct elf_link_hash_entry *h, - Elf_Internal_Rela *irel, - unsigned long insn) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - - /* Check there is target of existing entry the same as the new one. */ - while (ptr != NULL) - { - if (((h == NULL && ptr->sec == sec - && ELF32_R_SYM (ptr->irel_head->irel->r_info) == ELF32_R_SYM (irel->r_info) - && ptr->irel_head->irel->r_addend == irel->r_addend) - || h != NULL) - && ptr->h == h - && ptr->insn == insn) - { - /* The same target exist, so insert into list. */ - struct elf_nds32_ifc_irel_list *irel_list = ptr->irel_head; - - while (irel_list->next != NULL) - irel_list = irel_list->next; - irel_list->next = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list)); - irel_list = irel_list->next; - irel_list->irel = irel; - irel_list->keep = 1; - - if (h == NULL) - irel_list->sec = NULL; - else - irel_list->sec = sec; - irel_list->next = NULL; - return; - } - if (ptr->next == NULL) - break; - ptr = ptr->next; - } - - /* There is no same target entry, so build a new one. */ - if (ifc_symbol_head == NULL) - { - ifc_symbol_head = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry)); - ptr = ifc_symbol_head; - } - else - { - ptr->next = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry)); - ptr = ptr->next; - } - - ptr->h = h; - ptr->irel_head = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list)); - ptr->irel_head->irel = irel; - ptr->insn = insn; - ptr->irel_head->keep = 1; - - if (h == NULL) - { - /* Local symbols. */ - ptr->sec = sec; - ptr->irel_head->sec = NULL; - } - else - { - /* Global symbol. */ - ptr->sec = NULL; - ptr->irel_head->sec = sec; - } - - ptr->irel_head->next = NULL; - ptr->times = 0; - ptr->enable = 0; - ptr->ex9_enable = 0; - ptr->next = NULL; -} - -/* Gather all jal and j instructions. */ - -static bfd_boolean -nds32_elf_ifc_calc (struct bfd_link_info *info, - bfd *abfd, asection *sec) -{ - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irelend; - Elf_Internal_Rela *irel; - Elf_Internal_Shdr *symtab_hdr; - bfd_byte *contents = NULL; - uint32_t insn, insn_with_reg; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); - struct elf_nds32_link_hash_table *table; - bfd_boolean ifc_loop_aware; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + sec->reloc_count; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Check if the object enable ifc. */ - irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, - R_NDS32_RELAX_ENTRY); - - if (irel == NULL - || irel >= irelend - || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY - && !(irel->r_addend & R_NDS32_RELAX_ENTRY_IFC_FLAG))) - return TRUE; - - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) - return FALSE; - - table = nds32_elf_hash_table (info); - ifc_loop_aware = table->ifc_loop_aware; - while (irel != NULL && irel < irelend) - { - /* Traverse all relocation and gather all of them to build the list. */ - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN) - { - if (ifc_loop_aware == 1 - && (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0) - { - /* Check the region if loop or not. If it is true and - ifc-loop-aware is true, ignore the region till region end. */ - while (irel != NULL - && irel < irelend - && (ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_END - || (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0)) - irel++; - } - } - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA) - { - insn = bfd_getb32 (contents + irel->r_offset); - nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - nds32_elf_ifc_insert_symbol (sec, NULL, irel, insn_with_reg); - } - else - { - /* External symbol. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - nds32_elf_ifc_insert_symbol (sec, h, irel, insn_with_reg); - } - } - irel++; - } - return TRUE; -} - -/* Determine whether j and jal should be substituted. */ - -static void -nds32_elf_ifc_filter (struct bfd_link_info *info) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - struct elf_nds32_ifc_irel_list *irel_keeper = NULL; - struct elf_nds32_link_hash_table *table; - int target_optimize; - bfd_vma address; - - table = nds32_elf_hash_table (info); - target_optimize = table->target_optimize; - while (ptr) - { - irel_ptr = ptr->irel_head; - if (ptr->h == NULL) - { - /* Local symbol. */ - irel_keeper = irel_ptr; - while (irel_ptr && irel_ptr->next) - { - /* Check there is jump target can be used. */ - if ((irel_ptr->next->irel->r_offset - - irel_keeper->irel->r_offset) > 1022) - irel_keeper = irel_ptr->next; - else - { - ptr->enable = 1; - irel_ptr->keep = 0; - } - irel_ptr = irel_ptr->next; - } - } - else - { - /* Global symbol. */ - /* We have to get the absolute address and decide - whether to keep it or not. */ - while (irel_ptr) - { - address = (irel_ptr->irel->r_offset - + irel_ptr->sec->output_section->vma - + irel_ptr->sec->output_offset); - irel_ptr->addr = address; - irel_ptr = irel_ptr->next; - } - - irel_ptr = ptr->irel_head; - while (irel_ptr) - { - /* Sort by address. */ - struct elf_nds32_ifc_irel_list *irel_dest = irel_ptr; - struct elf_nds32_ifc_irel_list *irel_temp = irel_ptr; - struct elf_nds32_ifc_irel_list *irel_ptr_prev = NULL; - struct elf_nds32_ifc_irel_list *irel_dest_prev = NULL; - - /* Get the smallest one. */ - while (irel_temp->next) - { - if (irel_temp->next->addr < irel_dest->addr) - { - irel_dest_prev = irel_temp; - irel_dest = irel_temp->next; - } - irel_temp = irel_temp->next; - } - - if (irel_dest != irel_ptr) - { - if (irel_ptr_prev) - irel_ptr_prev->next = irel_dest; - if (irel_dest_prev) - irel_dest_prev->next = irel_ptr; - irel_temp = irel_ptr->next; - irel_ptr->next = irel_dest->next; - irel_dest->next = irel_temp; - } - irel_ptr_prev = irel_ptr; - irel_ptr = irel_ptr->next; - } - - irel_ptr = ptr->irel_head; - irel_keeper = irel_ptr; - while (irel_ptr && irel_ptr->next) - { - if ((irel_ptr->next->addr - irel_keeper->addr) > 1022) - irel_keeper = irel_ptr->next; - else - { - ptr->enable = 1; - irel_ptr->keep = 0; - } - irel_ptr = irel_ptr->next; - } - } - - /* Ex9 enable. Reserve it for ex9. */ - if ((target_optimize & NDS32_RELAX_EX9_ON) - && ptr->irel_head != irel_keeper) - ptr->enable = 0; - ptr = ptr->next; - } -} - -/* Determine whether j and jal should be substituted after ex9 done. */ - -static void -nds32_elf_ifc_filter_after_ex9 (void) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - - while (ptr) - { - if (ptr->enable == 0) - { - /* Check whether ifc is applied or not. */ - irel_ptr = ptr->irel_head; - ptr->ex9_enable = 1; - while (irel_ptr) - { - if (ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN) - { - /* Ex9 already. */ - ptr->ex9_enable = 0; - break; - } - irel_ptr = irel_ptr->next; - } - } - ptr = ptr->next; - } -} - -/* Wrapper to do ifc relaxation. */ - -bfd_boolean -nds32_elf_ifc_finish (struct bfd_link_info *info) -{ - int relax_status; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - relax_status = table->relax_status; - - if (!(relax_status & NDS32_RELAX_JUMP_IFC_DONE)) - nds32_elf_ifc_filter (info); - else - nds32_elf_ifc_filter_after_ex9 (); - - if (!nds32_elf_ifc_replace (info)) - return FALSE; - - if (table) - table->relax_status |= NDS32_RELAX_JUMP_IFC_DONE; - return TRUE; -} - -/* Traverse the result of ifc filter and replace it with ifcall9. */ - -static bfd_boolean -nds32_elf_ifc_replace (struct bfd_link_info *info) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - nds32_elf_blank_t *relax_blank_list = NULL; - bfd_byte *contents = NULL; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - unsigned short insn16 = INSN_IFCALL9; - struct elf_nds32_link_hash_table *table; - int relax_status; - - table = nds32_elf_hash_table (info); - relax_status = table->relax_status; - - while (ptr) - { - /* Traverse the ifc gather list, and replace the - filter entries by ifcall9. */ - if ((!(relax_status & NDS32_RELAX_JUMP_IFC_DONE) && ptr->enable == 1) - || ((relax_status & NDS32_RELAX_JUMP_IFC_DONE) - && ptr->ex9_enable == 1)) - { - irel_ptr = ptr->irel_head; - if (ptr->h == NULL) - { - /* Local symbol. */ - internal_relocs = _bfd_elf_link_read_relocs - (ptr->sec->owner, ptr->sec, NULL, NULL, TRUE /* keep_memory */); - irelend = internal_relocs + ptr->sec->reloc_count; - - if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, - &contents, TRUE)) - return FALSE; - - while (irel_ptr) - { - if (irel_ptr->keep == 0 && irel_ptr->next) - { - /* The one can be replaced. We have to check whether - there is any alignment point in the region. */ - irel = irel_ptr->irel; - while (((irel_ptr->next->keep == 0 - && irel < irel_ptr->next->irel) - || (irel_ptr->next->keep == 1 && irel < irelend)) - && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2)) - irel++; - if (irel >= irelend - || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2 - && ((irel->r_offset - get_nds32_elf_blank_total - (&relax_blank_list, irel->r_offset, 1)) - & 0x02) == 0)) - { - /* Replace by ifcall9. */ - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2)) - return FALSE; - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_10IFCU_PCREL_RELA); - } - } - irel_ptr = irel_ptr->next; - } - - /* Delete the redundant code. */ - if (relax_blank_list) - { - nds32_elf_relax_delete_blanks (ptr->sec->owner, ptr->sec, - relax_blank_list); - relax_blank_list = NULL; - } - } - else - { - /* Global symbol. */ - while (irel_ptr) - { - if (irel_ptr->keep == 0 && irel_ptr->next) - { - /* The one can be replaced, and we have to check - whether there is any alignment point in the region. */ - internal_relocs = _bfd_elf_link_read_relocs - (irel_ptr->sec->owner, irel_ptr->sec, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + irel_ptr->sec->reloc_count; - if (!nds32_get_section_contents (irel_ptr->sec->owner, - irel_ptr->sec, &contents, - TRUE)) - return FALSE; - - irel = irel_ptr->irel; - while (((irel_ptr->sec == irel_ptr->next->sec - && irel_ptr->next->keep == 0 - && irel < irel_ptr->next->irel) - || ((irel_ptr->sec != irel_ptr->next->sec - || irel_ptr->next->keep == 1) - && irel < irelend)) - && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2)) - irel++; - if (irel >= irelend - || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL - && (irel->r_addend & 0x1f) == 2 - && ((irel->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - irel->r_offset, 1)) & 0x02) == 0)) - { - /* Replace by ifcall9. */ - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - if (!insert_nds32_elf_blank_recalc_total - (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2)) - return FALSE; - - /* Delete the redundant code, and clear the relocation. */ - nds32_elf_relax_delete_blanks (irel_ptr->sec->owner, - irel_ptr->sec, - relax_blank_list); - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_10IFCU_PCREL_RELA); - relax_blank_list = NULL; - } - } - - irel_ptr = irel_ptr->next; - } - } - } - ptr = ptr->next; - } - - return TRUE; -} - -/* Relocate ifcall. */ - -static bfd_boolean -nds32_elf_ifc_reloc (void) -{ - struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - struct elf_nds32_ifc_irel_list *irel_keeper = NULL; - bfd_vma relocation, address; - unsigned short insn16; - bfd_byte *contents = NULL; - static bfd_boolean done = FALSE; - - if (done) - return TRUE; - - done = TRUE; - - while (ptr) - { - /* Check the entry is enable ifcall. */ - if (ptr->enable == 1 || ptr->ex9_enable == 1) - { - /* Get the reserve jump. */ - irel_ptr = ptr->irel_head; - while (irel_ptr) - { - if (irel_ptr->keep == 1) - { - irel_keeper = irel_ptr; - break; - } - irel_ptr = irel_ptr->next; - } - - irel_ptr = ptr->irel_head; - if (ptr->h == NULL) - { - /* Local symbol. */ - if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, - &contents, TRUE)) - return FALSE; - - while (irel_ptr) - { - if (irel_ptr->keep == 0 - && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) - { - relocation = irel_keeper->irel->r_offset; - relocation = relocation - irel_ptr->irel->r_offset; - while (irel_keeper && relocation > 1022) - { - irel_keeper = irel_keeper->next; - if (irel_keeper && irel_keeper->keep == 1) - { - relocation = irel_keeper->irel->r_offset; - relocation = relocation - irel_ptr->irel->r_offset; - } - } - if (relocation > 1022) - { - /* Double check. */ - irel_keeper = ptr->irel_head; - while (irel_keeper) - { - if (irel_keeper->keep == 1) - { - relocation = irel_keeper->irel->r_offset; - relocation = relocation - irel_ptr->irel->r_offset; - } - if (relocation <= 1022) - break; - irel_keeper = irel_keeper->next; - } - if (!irel_keeper) - return FALSE; - } - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_NONE); - insn16 = INSN_IFCALL9 | (relocation >> 1); - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - } - irel_ptr = irel_ptr->next; - } - } - else - { - /* Global symbol. */ - while (irel_ptr) - { - if (irel_ptr->keep == 0 - && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA) - { - /* Get the distance between ifcall and jump. */ - relocation = (irel_keeper->irel->r_offset - + irel_keeper->sec->output_section->vma - + irel_keeper->sec->output_offset); - address = (irel_ptr->irel->r_offset - + irel_ptr->sec->output_section->vma - + irel_ptr->sec->output_offset); - relocation = relocation - address; - - /* The distance is over ragne, find callee again. */ - while (irel_keeper && relocation > 1022) - { - irel_keeper = irel_keeper->next; - if (irel_keeper && irel_keeper->keep ==1) - { - relocation = (irel_keeper->irel->r_offset - + irel_keeper->sec->output_section->vma - + irel_keeper->sec->output_offset); - relocation = relocation - address; - } - } - - if (relocation > 1022) - { - /* Double check. */ - irel_keeper = ptr->irel_head; - while (irel_keeper) - { - if (irel_keeper->keep == 1) - { - - relocation = (irel_keeper->irel->r_offset - + irel_keeper->sec->output_section->vma - + irel_keeper->sec->output_offset); - relocation = relocation - address; - } - if (relocation <= 1022) - break; - irel_keeper = irel_keeper->next; - } - if (!irel_keeper) - return FALSE; - } - if (!nds32_get_section_contents - (irel_ptr->sec->owner, irel_ptr->sec, &contents, TRUE)) - return FALSE; - insn16 = INSN_IFCALL9 | (relocation >> 1); - bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset); - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), - R_NDS32_NONE); - } - irel_ptr =irel_ptr->next; - } - } - } - ptr = ptr->next; - } - - return TRUE; -} - -/* End of IFC relaxation. */ - -/* EX9 Instruction Table Relaxation. */ - -/* Global hash list. */ -struct elf_link_hash_entry_list -{ - struct elf_link_hash_entry *h; - struct elf_link_hash_entry_list *next; -}; - -/* Save different destination but same insn. */ -struct elf_link_hash_entry_mul_list -{ - /* Global symbol times. */ - int times; - /* Save relocation for each global symbol but useful?? */ - Elf_Internal_Rela *irel; - /* For sethi, two sethi may have the same high-part but different low-parts. */ - Elf_Internal_Rela rel_backup; - struct elf_link_hash_entry_list *h_list; - struct elf_link_hash_entry_mul_list *next; -}; - -/* Instruction hash table. */ -struct elf_nds32_code_hash_entry -{ - struct bfd_hash_entry root; - int times; - /* For insn that can use relocation or constant ex: sethi. */ - int const_insn; - asection *sec; - struct elf_link_hash_entry_mul_list *m_list; - /* Using r_addend. */ - Elf_Internal_Rela *irel; - /* Using r_info. */ - Elf_Internal_Rela rel_backup; -}; - -/* Instruction count list. */ -struct elf_nds32_insn_times_entry -{ - const char *string; - int times; - int order; - asection *sec; - struct elf_link_hash_entry_mul_list *m_list; - Elf_Internal_Rela *irel; - Elf_Internal_Rela rel_backup; - struct elf_nds32_insn_times_entry *next; -}; - -/* J and JAL symbol list. */ -struct elf_nds32_symbol_entry -{ - char *string; - unsigned long insn; - struct elf_nds32_symbol_entry *next; -}; - -/* Relocation list. */ -struct elf_nds32_irel_entry -{ - Elf_Internal_Rela *irel; - struct elf_nds32_irel_entry *next; -}; - -/* ex9.it insn need to be fixed. */ -struct elf_nds32_ex9_refix -{ - Elf_Internal_Rela *irel; - asection *sec; - struct elf_link_hash_entry *h; - int order; - struct elf_nds32_ex9_refix *next; -}; - -static struct bfd_hash_table ex9_code_table; -static struct elf_nds32_insn_times_entry *ex9_insn_head = NULL; -static struct elf_nds32_ex9_refix *ex9_refix_head = NULL; - -/* EX9 hash function. */ - -static struct bfd_hash_entry * -nds32_elf_code_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_nds32_code_hash_entry *ret; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (entry == NULL) - { - entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, sizeof (*ret)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry == NULL) - return entry; - - ret = (struct elf_nds32_code_hash_entry*) entry; - ret->times = 0; - ret->const_insn = 0; - ret->m_list = NULL; - ret->sec = NULL; - ret->irel = NULL; - return &ret->root; -} - -/* Insert ex9 entry - this insert must be stable sorted by times. */ - -static void -nds32_elf_ex9_insert_entry (struct elf_nds32_insn_times_entry *ptr) -{ - struct elf_nds32_insn_times_entry *temp; - struct elf_nds32_insn_times_entry *temp2; - - if (ex9_insn_head == NULL) - { - ex9_insn_head = ptr; - ptr->next = NULL; - } - else - { - temp = ex9_insn_head; - temp2 = ex9_insn_head; - while (temp->next && - (temp->next->times >= ptr->times - || temp->times == -1)) - { - if (temp->times == -1) - temp2 = temp; - temp = temp->next; - } - if (ptr->times > temp->times && temp->times != -1) - { - ptr->next = temp; - if (temp2->times == -1) - temp2->next = ptr; - else - ex9_insn_head = ptr; - } - else if (temp->next == NULL) - { - temp->next = ptr; - ptr->next = NULL; - } - else - { - ptr->next = temp->next; - temp->next = ptr; - } - } -} - -/* Examine each insn times in hash table. - Handle multi-link hash entry. - - TODO: This function doesn't assign so much info since it is fake. */ - -static int -nds32_elf_examine_insn_times (struct elf_nds32_code_hash_entry *h) -{ - struct elf_nds32_insn_times_entry *ptr; - int times; - - if (h->m_list == NULL) - { - /* Local symbol insn or insn without relocation. */ - if (h->times < 3) - return TRUE; - - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = h->sec; - ptr->irel = h->irel; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - else - { - /* Global symbol insn. */ - /* Only sethi insn has multiple m_list. */ - struct elf_link_hash_entry_mul_list *m_list = h->m_list; - - times = 0; - while (m_list) - { - times += m_list->times; - m_list = m_list->next; - } - if (times >= 3) - { - m_list = h->m_list; - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = times; /* Use the total times. */ - ptr->string = h->root.string; - ptr->m_list = m_list; - ptr->sec = h->sec; - ptr->irel = m_list->irel; - ptr->rel_backup = m_list->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - if (h->const_insn == 1) - { - /* sethi with constant value. */ - if (h->times < 3) - return TRUE; - - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = NULL; - ptr->irel = NULL; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - return TRUE; -} - -/* Count each insn times in hash table. - Handle multi-link hash entry. */ - -static int -nds32_elf_count_insn_times (struct elf_nds32_code_hash_entry *h) -{ - int reservation, times; - unsigned long relocation, min_relocation; - struct elf_nds32_insn_times_entry *ptr; - - if (h->m_list == NULL) - { - /* Local symbol insn or insn without relocation. */ - if (h->times < 3) - return TRUE; - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = h->sec; - ptr->irel = h->irel; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - else - { - /* Global symbol insn. */ - /* Only sethi insn has multiple m_list. */ - struct elf_link_hash_entry_mul_list *m_list = h->m_list; - - if (ELF32_R_TYPE (m_list->rel_backup.r_info) == R_NDS32_HI20_RELA - && m_list->next != NULL) - { - /* Sethi insn has different symbol or addend but has same hi20. */ - times = 0; - reservation = 1; - relocation = 0; - min_relocation = 0xffffffff; - while (m_list) - { - /* Get the minimum sethi address - and calculate how many entry the sethi-list have to use. */ - if ((m_list->h_list->h->root.type == bfd_link_hash_defined - || m_list->h_list->h->root.type == bfd_link_hash_defweak) - && (m_list->h_list->h->root.u.def.section != NULL - && m_list->h_list->h->root.u.def.section->output_section != NULL)) - { - relocation = (m_list->h_list->h->root.u.def.value + - m_list->h_list->h->root.u.def.section->output_section->vma + - m_list->h_list->h->root.u.def.section->output_offset); - relocation += m_list->irel->r_addend; - } - else - relocation = 0; - if (relocation < min_relocation) - min_relocation = relocation; - times += m_list->times; - m_list = m_list->next; - } - if (min_relocation < ex9_relax_size) - reservation = (min_relocation >> 12) + 1; - else - reservation = (min_relocation >> 12) - - ((min_relocation - ex9_relax_size) >> 12) + 1; - if (reservation < (times / 3)) - { - /* Efficient enough to use ex9. */ - int i; - - for (i = reservation ; i > 0; i--) - { - /* Allocate number of reservation ex9 entry. */ - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->m_list->times / reservation; - ptr->string = h->root.string; - ptr->m_list = h->m_list; - ptr->sec = h->sec; - ptr->irel = h->m_list->irel; - ptr->rel_backup = h->m_list->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - } - else - { - /* Normal global symbol that means no different address symbol - using same ex9 entry. */ - if (m_list->times >= 3) - { - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = m_list->times; - ptr->string = h->root.string; - ptr->m_list = h->m_list; - ptr->sec = h->sec; - ptr->irel = h->m_list->irel; - ptr->rel_backup = h->m_list->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - - if (h->const_insn == 1) - { - /* sethi with constant value. */ - if (h->times < 3) - return TRUE; - - ptr = (struct elf_nds32_insn_times_entry *) - bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->times = h->times; - ptr->string = h->root.string; - ptr->m_list = NULL; - ptr->sec = NULL; - ptr->irel = NULL; - ptr->rel_backup = h->rel_backup; - nds32_elf_ex9_insert_entry (ptr); - } - } - - return TRUE; -} - -/* Hash table traverse function. */ - -static void -nds32_elf_code_hash_traverse (int (*func) (struct elf_nds32_code_hash_entry*)) -{ - unsigned int i; - - ex9_code_table.frozen = 1; - for (i = 0; i < ex9_code_table.size; i++) - { - struct bfd_hash_entry *p; - - for (p = ex9_code_table.table[i]; p != NULL; p = p->next) - if (!func ((struct elf_nds32_code_hash_entry *) p)) - goto out; - } -out: - ex9_code_table.frozen = 0; -} - - -/* Give order number to insn list. */ - -static void -nds32_elf_order_insn_times (struct bfd_link_info *info) -{ - struct elf_nds32_insn_times_entry *ex9_insn; - struct elf_nds32_insn_times_entry *temp = NULL; - struct elf_nds32_link_hash_table *table; - int ex9_limit; - int number = 0; - - if (ex9_insn_head == NULL) - return; - -/* The max number of entries is 512. */ - ex9_insn = ex9_insn_head; - table = nds32_elf_hash_table (info); - ex9_limit = table->ex9_limit; - - ex9_insn = ex9_insn_head; - - while (ex9_insn != NULL && number < ex9_limit) - { - ex9_insn->order = number; - number++; - temp = ex9_insn; - ex9_insn = ex9_insn->next; - } - - if (ex9_insn && temp) - temp->next = NULL; - - while (ex9_insn != NULL) - { - /* Free useless entry. */ - temp = ex9_insn; - ex9_insn = ex9_insn->next; - free (temp); - } -} - -/* Build .ex9.itable section. */ - -static void -nds32_elf_ex9_build_itable (struct bfd_link_info *link_info) -{ - asection *table_sec; - struct elf_nds32_insn_times_entry *ptr; - bfd *it_abfd; - int number = 0; - bfd_byte *contents = NULL; - - for (it_abfd = link_info->input_bfds; it_abfd != NULL; - it_abfd = it_abfd->link.next) - { - /* Find the section .ex9.itable, and put all entries into it. */ - table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable"); - if (table_sec != NULL) - { - if (!nds32_get_section_contents (it_abfd, table_sec, &contents, TRUE)) - return; - - for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next) - number++; - - table_sec->size = number * 4; - - if (number == 0) - return; - - elf_elfheader (link_info->output_bfd)->e_flags |= E_NDS32_HAS_EX9_INST; - number = 0; - for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next) - { - long val; - - val = strtol (ptr->string, NULL, 16); - bfd_putb32 ((bfd_vma) val, (char *) contents + (number * 4)); - number++; - } - break; - } - } -} - -/* Get insn with regs according to relocation type. */ - -static void -nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel, - uint32_t insn, uint32_t *insn_with_reg) -{ - reloc_howto_type *howto = NULL; - - if (irel == NULL - || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table) - && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY) - >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table))) - { - *insn_with_reg = insn; - return; - } - - howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); - *insn_with_reg = insn & (0xffffffff ^ howto->dst_mask); -} - -/* Mask number of address bits according to relocation. */ - -static unsigned long -nds32_elf_irel_mask (Elf_Internal_Rela *irel) -{ - reloc_howto_type *howto = NULL; - - if (irel == NULL - || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table) - && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY) - >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table))) - return 0; - - howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); - return howto->dst_mask; -} - -static void -nds32_elf_insert_irel_entry (struct elf_nds32_irel_entry **irel_list, - struct elf_nds32_irel_entry *irel_ptr) -{ - if (*irel_list == NULL) - { - *irel_list = irel_ptr; - irel_ptr->next = NULL; - } - else - { - irel_ptr->next = *irel_list; - *irel_list = irel_ptr; - } -} - -static void -nds32_elf_ex9_insert_fix (asection * sec, Elf_Internal_Rela * irel, - struct elf_link_hash_entry *h, int order) -{ - struct elf_nds32_ex9_refix *ptr; - - ptr = bfd_malloc (sizeof (struct elf_nds32_ex9_refix)); - ptr->sec = sec; - ptr->irel = irel; - ptr->h = h; - ptr->order = order; - ptr->next = NULL; - - if (ex9_refix_head == NULL) - ex9_refix_head = ptr; - else - { - struct elf_nds32_ex9_refix *temp = ex9_refix_head; - - while (temp->next != NULL) - temp = temp->next; - temp->next = ptr; - } -} - -enum -{ - DATA_EXIST = 1, - CLEAN_PRE = 1 << 1, - PUSH_PRE = 1 << 2 -}; - -/* Check relocation type if supporting for ex9. */ - -static int -nds32_elf_ex9_relocation_check (struct bfd_link_info *info, - Elf_Internal_Rela **irel, - Elf_Internal_Rela *irelend, - nds32_elf_blank_t *relax_blank_list, - asection *sec,bfd_vma *off, - bfd_byte *contents) -{ - /* Suppress ex9 if `.no_relax ex9' or inner loop. */ - bfd_boolean nested_ex9, nested_loop; - bfd_boolean ex9_loop_aware; - /* We use the highest 1 byte of result to record - how many bytes location counter has to move. */ - int result = 0; - Elf_Internal_Rela *irel_save = NULL; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - ex9_loop_aware = table->ex9_loop_aware; - - while ((*irel) != NULL && (*irel) < irelend && *off == (*irel)->r_offset) - { - switch (ELF32_R_TYPE ((*irel)->r_info)) - { - case R_NDS32_RELAX_REGION_BEGIN: - /* Ignore code block. */ - nested_ex9 = FALSE; - nested_loop = FALSE; - if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) - || (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG))) - { - /* Check the region if loop or not. If it is true and - ex9-loop-aware is true, ignore the region till region end. */ - /* To save the status for in .no_relax ex9 region and - loop region to conform the block can do ex9 relaxation. */ - nested_ex9 = ((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG); - nested_loop = (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)); - while ((*irel) && (*irel) < irelend && (nested_ex9 || nested_loop)) - { - (*irel)++; - if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_BEGIN) - { - /* There may be nested region. */ - if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0) - nested_ex9 = TRUE; - else if (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) - nested_loop = TRUE; - } - else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_END) - { - /* The end of region. */ - if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0) - nested_ex9 = FALSE; - else if (ex9_loop_aware - && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)) - nested_loop = FALSE; - } - else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL - && ((*irel)->r_addend & 0x1f) == 2) - { - /* Alignment exist in the region. */ - result |= CLEAN_PRE; - if (((*irel)->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - (*irel)->r_offset, 0)) & 0x02) - result |= PUSH_PRE; - } - } - if ((*irel) >= irelend) - *off = sec->size; - else - *off = (*irel)->r_offset; - - /* The final instruction in the region, regard this one as data to ignore it. */ - result |= DATA_EXIST; - return result; - } - break; - - case R_NDS32_LABEL: - if (((*irel)->r_addend & 0x1f) == 2) - { - /* Check this point is align and decide to do ex9 or not. */ - result |= CLEAN_PRE; - if (((*irel)->r_offset - - get_nds32_elf_blank_total (&relax_blank_list, - (*irel)->r_offset, 0)) & 0x02) - result |= PUSH_PRE; - } - break; - case R_NDS32_32_RELA: - /* Data. */ - result |= (4 << 24); - result |= DATA_EXIST; - break; - case R_NDS32_16_RELA: - /* Data. */ - result |= (2 << 24); - result |= DATA_EXIST; - break; - case R_NDS32_DATA: - /* Data. */ - /* The least code alignment is 2. If the data is only one byte, - we have to shift one more byte. */ - if ((*irel)->r_addend == 1) - result |= ((*irel)->r_addend << 25) ; - else - result |= ((*irel)->r_addend << 24) ; - - result |= DATA_EXIST; - break; - - case R_NDS32_25_PCREL_RELA: - case R_NDS32_SDA16S3_RELA: - case R_NDS32_SDA15S3_RELA: - case R_NDS32_SDA15S3: - case R_NDS32_SDA17S2_RELA: - case R_NDS32_SDA15S2_RELA: - case R_NDS32_SDA12S2_SP_RELA: - case R_NDS32_SDA12S2_DP_RELA: - case R_NDS32_SDA15S2: - case R_NDS32_SDA18S1_RELA: - case R_NDS32_SDA15S1_RELA: - case R_NDS32_SDA15S1: - case R_NDS32_SDA19S0_RELA: - case R_NDS32_SDA15S0_RELA: - case R_NDS32_SDA15S0: - case R_NDS32_HI20_RELA: - case R_NDS32_LO12S0_ORI_RELA: - case R_NDS32_LO12S0_RELA: - case R_NDS32_LO12S1_RELA: - case R_NDS32_LO12S2_RELA: - /* These relocation is supported ex9 relaxation currently. */ - /* We have to save the relocation for using later, since we have - to check there is any alignment in the same address. */ - irel_save = *irel; - break; - default: - /* Not support relocations. */ - if (ELF32_R_TYPE ((*irel)->r_info) < ARRAY_SIZE (nds32_elf_howto_table) - && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_NONE - && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_INSN16) - { - /* Note: To optimize aggressively, it maybe can ignore R_NDS32_INSN16 here. - But we have to consider if there is any side-effect. */ - if (!(result & DATA_EXIST)) - { - /* We have to confirm there is no data relocation in the - same address. In general case, this won't happen. */ - /* We have to do ex9 conservative, for those relocation not - considerd we ignore instruction. */ - result |= DATA_EXIST; - if (*(contents + *off) & 0x80) - result |= (2 << 24); - else - result |= (4 << 24); - break; - } - } - } - if ((*irel) < irelend - && ((*irel) + 1) < irelend - && (*irel)->r_offset == ((*irel) + 1)->r_offset) - /* There are relocations pointing to the same address, we have to - check all of them. */ - (*irel)++; - else - { - if (irel_save) - *irel = irel_save; - return result; - } - } - return result; -} - -/* Replace with ex9 instruction. */ - -static bfd_boolean -nds32_elf_ex9_push_insn (uint16_t insn16, bfd_byte *contents, bfd_vma pre_off, - nds32_elf_blank_t **relax_blank_list, - struct elf_nds32_irel_entry *pre_irel_ptr, - struct elf_nds32_irel_entry **irel_list) -{ - if (insn16 != 0) - { - /* Implement the ex9 relaxation. */ - bfd_putb16 (insn16, contents + pre_off); - if (!insert_nds32_elf_blank_recalc_total (relax_blank_list, - pre_off + 2, 2)) - return FALSE; - if (pre_irel_ptr != NULL) - nds32_elf_insert_irel_entry (irel_list, pre_irel_ptr); - } - return TRUE; -} - -/* Replace input file instruction which is in ex9 itable. */ - -static bfd_boolean -nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asection *sec) -{ - struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; - bfd_byte *contents = NULL; - bfd_vma off; - uint16_t insn16, insn_ex9; - /* `pre_*' are used to track previous instruction that can use ex9.it. */ - bfd_vma pre_off = -1; - uint16_t pre_insn16 = 0; - struct elf_nds32_irel_entry *pre_irel_ptr = NULL; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isym = NULL; - nds32_elf_blank_t *relax_blank_list = NULL; - uint32_t insn = 0; - uint32_t insn_with_reg = 0; - uint32_t it_insn; - uint32_t it_insn_with_reg; - unsigned long r_symndx; - asection *isec; - struct elf_nds32_irel_entry *irel_list = NULL; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd); - int data_flag, do_replace, save_irel; - struct elf_link_hash_entry_list *h_list; - - - /* Load section instructions, relocations, and symbol table. */ - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE) - || !nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - internal_relocs = - _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, TRUE /* keep_memory */); - irelend = internal_relocs + sec->reloc_count; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - off = 0; - - /* Check if the object enable ex9. */ - irel = find_relocs_at_address (internal_relocs, internal_relocs, - irelend, R_NDS32_RELAX_ENTRY); - - /* Check this section trigger ex9 relaxation. */ - if (irel == NULL - || irel >= irelend - || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY - && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG))) - return TRUE; - - irel = internal_relocs; - - /* Check alignment and fetch proper relocation. */ - while (off < sec->size) - { - struct elf_link_hash_entry *h = NULL; - struct elf_nds32_irel_entry *irel_ptr = NULL; - - /* Syn the instruction and the relocation. */ - while (irel != NULL && irel < irelend && irel->r_offset < off) - irel++; - - data_flag = nds32_elf_ex9_relocation_check (info, &irel, irelend, - relax_blank_list, sec, - &off, contents); - if (data_flag & PUSH_PRE) - if (!nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, - &relax_blank_list, pre_irel_ptr, - &irel_list)) - return FALSE; - - if (data_flag & CLEAN_PRE) - { - pre_off = 0; - pre_insn16 = 0; - pre_irel_ptr = NULL; - } - if (data_flag & DATA_EXIST) - { - /* We save the move offset in the highest byte. */ - off += (data_flag >> 24); - continue; - } - - if (*(contents + off) & 0x80) - { - /* 2-byte instruction. */ - off += 2; - continue; - } - - /* Load the instruction and its opcode with register for comparing. */ - ex9_insn = ex9_insn_head; - insn = bfd_getb32 (contents + off); - insn_with_reg = 0; - while (ex9_insn) - { - it_insn = strtol (ex9_insn->string, NULL, 16); - it_insn_with_reg = 0; - do_replace = 0; - save_irel = 0; - - if (irel != NULL && irel < irelend && irel->r_offset == off) - { - /* Insn with relocation. */ - nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); - - if (ex9_insn->irel != NULL) - nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn, - &it_insn_with_reg); - - if (ex9_insn->irel != NULL - && (ELF32_R_TYPE (irel->r_info) == - ELF32_R_TYPE (ex9_insn->irel->r_info)) - && (insn_with_reg == it_insn_with_reg)) - { - /* Insn relocation and format is the same as table entry. */ - - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (irel->r_info) <= - R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) - { - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - int shndx = isym[r_symndx].st_shndx; - - isec = elf_elfsections (abfd)[shndx]->bfd_section; - if (ex9_insn->sec == isec - && ex9_insn->irel->r_addend == irel->r_addend - && ex9_insn->irel->r_info == irel->r_info) - { - do_replace = 1; - save_irel = 1; - } - } - else - { - /* External symbol. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (ex9_insn->m_list) - { - h_list = ex9_insn->m_list->h_list; - while (h_list) - { - if (h == h_list->h - && (ex9_insn->m_list->irel->r_addend == - irel->r_addend)) - { - do_replace = 1; - save_irel = 1; - break; - } - h_list = h_list->next; - } - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA) - { - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbols. Compare its base symbol and offset. */ - int shndx = isym[r_symndx].st_shndx; - - isec = elf_elfsections (abfd)[shndx]->bfd_section; - if (ex9_insn->sec == isec - && ex9_insn->irel->r_addend == irel->r_addend - && ex9_insn->irel->r_info == irel->r_info) - { - do_replace = 1; - save_irel = 1; - } - } - else - { - /* External symbol. */ - struct elf_link_hash_entry_mul_list *m_list; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - m_list = ex9_insn->m_list; - - while (m_list) - { - h_list = m_list->h_list; - - while (h_list) - { - if (h == h_list->h - && (m_list->irel->r_addend - == irel->r_addend)) - { - do_replace = 1; - save_irel = 1; - if (ex9_insn->next - && ex9_insn->m_list - && ex9_insn->m_list == ex9_insn->next->m_list) - { - /* sethi multiple entry must be fixed */ - nds32_elf_ex9_insert_fix (sec, irel, - h, ex9_insn->order); - } - break; - } - h_list = h_list->next; - } - m_list = m_list->next; - } - } - } - } - - /* Import table: Check the symbol hash table and the - jump target. Only R_NDS32_25_PCREL_RELA now. */ - else if (ex9_insn->times == -1 - && ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA) - { - nds32_elf_get_insn_with_reg (irel, it_insn, &it_insn_with_reg); - if (insn_with_reg == it_insn_with_reg) - { - char code[10]; - bfd_vma relocation; - - r_symndx = ELF32_R_SYM (irel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section != NULL - && h->root.u.def.section->output_section != NULL - && h->root.u.def.section->gc_mark == 1 - && bfd_is_abs_section (h->root.u.def.section) - && h->root.u.def.value > sec->size) - { - relocation = h->root.u.def.value + - h->root.u.def.section->output_section->vma + - h->root.u.def.section->output_offset; - relocation += irel->r_addend; - insn = insn_with_reg - | ((relocation >> 1) & 0xffffff); - snprintf (code, sizeof (code), "%08x", insn); - if (strcmp (code, ex9_insn->string) == 0) - { - do_replace = 1; - save_irel = 1; - } - } - } - } - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN - || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END - || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) - { - /* These relocations do not have to relocate contens, so it can - be regard as instruction without relocation. */ - if (insn == it_insn && ex9_insn->irel == NULL) - do_replace = 1; - } - } - else - { - /* Instruction without relocation, we only - have to compare their byte code. */ - if (insn == it_insn && ex9_insn->irel == NULL) - do_replace = 1; - } - - /* Insntruction match so replacing the code here. */ - if (do_replace == 1) - { - /* There are two formats of ex9 instruction. */ - if (ex9_insn->order < 32) - insn_ex9 = INSN_EX9_IT_2; - else - insn_ex9 = INSN_EX9_IT_1; - insn16 = insn_ex9 | ex9_insn->order; - - /* Insert ex9 instruction. */ - nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, - &relax_blank_list, pre_irel_ptr, - &irel_list); - pre_off = off; - pre_insn16 = insn16; - - if (save_irel) - { - /* For instuction with relocation do relax. */ - irel_ptr = (struct elf_nds32_irel_entry *) - bfd_malloc (sizeof (struct elf_nds32_irel_entry)); - irel_ptr->irel = irel; - irel_ptr->next = NULL; - pre_irel_ptr = irel_ptr; - } - else - pre_irel_ptr = NULL; - break; - } - ex9_insn = ex9_insn->next; - } - off += 4; - } - - /* Insert ex9 instruction. */ - nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off, - &relax_blank_list, pre_irel_ptr, - &irel_list); - - /* Delete the redundant code. */ - if (relax_blank_list) - { - nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list); - relax_blank_list = NULL; - } - - /* Clear the relocation that is replaced by ex9. */ - while (irel_list) - { - struct elf_nds32_irel_entry *irel_ptr; - - irel_ptr = irel_list; - irel_list = irel_ptr->next; - irel_ptr->irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN); - free (irel_ptr); - } - return TRUE; -} - -/* Initialize ex9 hash table. */ - -int -nds32_elf_ex9_init (void) -{ - if (!bfd_hash_table_init_n (&ex9_code_table, nds32_elf_code_hash_newfunc, - sizeof (struct elf_nds32_code_hash_entry), - 1023)) - { - _bfd_error_handler (_("Linker: cannot init ex9 hash table error \n")); - return FALSE; - } - return TRUE; -} - -/* Predict how many bytes will be relaxed with ex9 and ifc. */ - -static void -nds32_elf_ex9_total_relax (struct bfd_link_info *info) -{ - struct elf_nds32_insn_times_entry *ex9_insn; - struct elf_nds32_insn_times_entry *temp; - int target_optimize; - struct elf_nds32_link_hash_table *table; - - if (ex9_insn_head == NULL) - return; - - table = nds32_elf_hash_table (info); - target_optimize = table->target_optimize; - ex9_insn = ex9_insn_head; - while (ex9_insn) - { - ex9_relax_size = ex9_insn->times * 2 + ex9_relax_size; - temp = ex9_insn; - ex9_insn = ex9_insn->next; - free (temp); - } - ex9_insn_head = NULL; - - if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON)) - { - /* Examine ifc reduce size. */ - struct elf_nds32_ifc_symbol_entry *ifc_ent = ifc_symbol_head; - struct elf_nds32_ifc_irel_list *irel_ptr = NULL; - int size = 0; - - while (ifc_ent) - { - if (ifc_ent->enable == 0) - { - /* Not ifc yet. */ - irel_ptr = ifc_ent->irel_head; - while (irel_ptr) - { - size += 2; - irel_ptr = irel_ptr->next; - } - } - size -= 2; - ifc_ent = ifc_ent->next; - } - ex9_relax_size += size; - } -} - -/* Finish ex9 table. */ - -void -nds32_elf_ex9_finish (struct bfd_link_info *link_info) -{ - nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); - nds32_elf_order_insn_times (link_info); - nds32_elf_ex9_total_relax (link_info); - /* Traverse the hash table and count its times. */ - nds32_elf_code_hash_traverse (nds32_elf_count_insn_times); - nds32_elf_order_insn_times (link_info); - nds32_elf_ex9_build_itable (link_info); -} - -/* Relocate the entries in ex9 table. */ - -static bfd_vma -nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr, - struct bfd_link_info *link_info) -{ - Elf_Internal_Sym *isym = NULL; - bfd_vma relocation = -1; - struct elf_link_hash_entry *h; - - if (ptr->m_list != NULL) - { - /* Global symbol. */ - h = ptr->m_list->h_list->h; - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section != NULL - && h->root.u.def.section->output_section != NULL) - { - - relocation = h->root.u.def.value + - h->root.u.def.section->output_section->vma + - h->root.u.def.section->output_offset; - relocation += ptr->m_list->irel->r_addend; - } - else - relocation = 0; - } - else if (ptr->sec !=NULL) - { - /* Local symbol. */ - Elf_Internal_Sym sym; - asection *sec = NULL; - asection isec; - asection *isec_ptr = &isec; - Elf_Internal_Rela irel_backup = *(ptr->irel); - asection *sec_backup = ptr->sec; - bfd *abfd = ptr->sec->owner; - - if (!nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - isym = isym + ELF32_R_SYM (ptr->irel->r_info); - - sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (sec != NULL) - *isec_ptr = *sec; - sym = *isym; - - /* The purpose is same as elf_link_input_bfd. */ - if (isec_ptr != NULL - && isec_ptr->sec_info_type == SEC_INFO_TYPE_MERGE - && ELF_ST_TYPE (isym->st_info) != STT_SECTION) - { - sym.st_value = - _bfd_merged_section_offset (ptr->sec->output_section->owner, &isec_ptr, - elf_section_data (isec_ptr)->sec_info, - isym->st_value); - } - relocation = _bfd_elf_rela_local_sym (link_info->output_bfd, &sym, - &ptr->sec, ptr->irel); - if (ptr->irel != NULL) - relocation += ptr->irel->r_addend; - - /* Restore origin value since there may be some insntructions that - could not be replaced with ex9.it. */ - *(ptr->irel) = irel_backup; - ptr->sec = sec_backup; - } - - return relocation; -} - -/* Import ex9 table and build list. */ - -void -nds32_elf_ex9_import_table (struct bfd_link_info *info) -{ - int num = 0; - bfd_byte *contents; - FILE *ex9_import_file; - int update_ex9_table; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - ex9_import_file = table->ex9_import_file; - rewind (table->ex9_import_file); - - contents = bfd_malloc (sizeof (bfd_byte) * 4); - - /* Read instructions from the input file and build the list. */ - while (!feof (ex9_import_file)) - { - unsigned long insn; - char *code; - struct elf_nds32_insn_times_entry *ptr; - size_t nread; - - nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file); - /* Ignore the final byte 0x0a. */ - if (nread < 1) - break; - insn = bfd_getb32 (contents); - code = bfd_malloc (sizeof (char) * 9); - snprintf (code, 9, "%08lx", (insn & 0xffffffff)); - ptr = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry)); - ptr->string = code; - ptr->order = num; - ptr->times = -1; - ptr->sec = NULL; - ptr->m_list = NULL; - ptr->rel_backup.r_offset = 0; - ptr->rel_backup.r_info = 0; - ptr->rel_backup.r_addend = 0; - ptr->irel = NULL; - ptr->next = NULL; - nds32_elf_ex9_insert_entry (ptr); - num++; - } - - update_ex9_table = table->update_ex9_table; - if (update_ex9_table == 1) - { - /* It has to consider of sethi need to use multiple page - but it not be done yet. */ - nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times); - nds32_elf_order_insn_times (info); - } -} - -/* Export ex9 table. */ - -static void -nds32_elf_ex9_export (struct bfd_link_info *info, - bfd_byte *contents, int size) -{ - FILE *ex9_export_file; - struct elf_nds32_link_hash_table *table; - - table = nds32_elf_hash_table (info); - ex9_export_file = table->ex9_export_file; - fwrite (contents, sizeof (bfd_byte), size, ex9_export_file); - fclose (ex9_export_file); -} - -/* Adjust relocations of J and JAL in ex9.itable. - Export ex9 table. */ - -static void -nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info) -{ - asection *table_sec = NULL; - struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head; - struct elf_nds32_insn_times_entry *temp_ptr, *temp_ptr2; - bfd *it_abfd; - uint32_t insn, insn_with_reg, source_insn; - bfd_byte *contents = NULL, *source_contents = NULL; - int size = 0; - bfd_vma gp; - int shift, update_ex9_table, offset = 0; - reloc_howto_type *howto = NULL; - Elf_Internal_Rela rel_backup; - unsigned short insn_ex9; - struct elf_nds32_link_hash_table *table; - FILE *ex9_export_file; - static bfd_boolean done = FALSE; - - if (done) - return; - - done = TRUE; - - table = nds32_elf_hash_table (link_info); - if (table) - table->relax_status |= NDS32_RELAX_EX9_DONE; - - - update_ex9_table = table->update_ex9_table; - /* Generated ex9.itable exactly. */ - if (update_ex9_table == 0) - { - for (it_abfd = link_info->input_bfds; it_abfd != NULL; - it_abfd = it_abfd->link.next) - { - table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable"); - if (table_sec != NULL) - break; - } - - if (table_sec != NULL) - { - bfd *output_bfd; - - output_bfd = table_sec->output_section->owner; - nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - if (table_sec->size == 0) - return; - - if (!nds32_get_section_contents (it_abfd, table_sec, &contents, TRUE)) - return; - } - } - else - { - /* Set gp. */ - bfd *output_bfd; - - output_bfd = link_info->input_bfds->sections->output_section->owner; - nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - contents = bfd_malloc (sizeof (bfd_byte) * 2048); - } - - /* Relocate instruction. */ - while (ex9_insn) - { - bfd_vma relocation, min_relocation = 0xffffffff; - - insn = strtol (ex9_insn->string, NULL, 16); - insn_with_reg = 0; - if (ex9_insn->m_list != NULL || ex9_insn->sec != NULL) - { - if (ex9_insn->m_list) - rel_backup = ex9_insn->m_list->rel_backup; - else - rel_backup = ex9_insn->rel_backup; - - nds32_elf_get_insn_with_reg (&rel_backup, insn, &insn_with_reg); - howto = - bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE - (rel_backup.r_info)); - shift = howto->rightshift; - if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_ORI_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S1_RELA - || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S2_RELA) - { - relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); - insn = - insn_with_reg | ((relocation >> shift) & - nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - else if ((ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA19S0_RELA)) - { - relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); - insn = - insn_with_reg | (((relocation - gp) >> shift) & - nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - else if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_HI20_RELA) - { - /* Sethi may be multiple entry for one insn. */ - if (ex9_insn->next && ex9_insn->m_list - && ex9_insn->m_list == ex9_insn->next->m_list) - { - struct elf_link_hash_entry_mul_list *m_list; - struct elf_nds32_ex9_refix *fix_ptr; - struct elf_link_hash_entry *h; - - temp_ptr = ex9_insn; - temp_ptr2 = ex9_insn; - m_list = ex9_insn->m_list; - while (m_list) - { - h = m_list->h_list->h; - relocation = h->root.u.def.value + - h->root.u.def.section->output_section->vma + - h->root.u.def.section->output_offset; - relocation += m_list->irel->r_addend; - - if (relocation < min_relocation) - min_relocation = relocation; - m_list = m_list->next; - } - relocation = min_relocation; - - /* Put insntruction into ex9 table. */ - insn = insn_with_reg - | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - relocation = relocation + 0x1000; /* hi20 */ - - while (ex9_insn->next && ex9_insn->m_list - && ex9_insn->m_list == ex9_insn->next->m_list) - { - /* Multiple sethi. */ - ex9_insn = ex9_insn->next; - size += 4; - insn = - insn_with_reg | ((relocation >> shift) & - nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - relocation = relocation + 0x1000; /* hi20 */ - } - - fix_ptr = ex9_refix_head; - while (fix_ptr) - { - /* Fix ex9 insn. */ - /* temp_ptr2 points to the head of multiple sethi. */ - temp_ptr = temp_ptr2; - while (fix_ptr->order != temp_ptr->order && fix_ptr->next) - { - fix_ptr = fix_ptr->next; - } - if (fix_ptr->order != temp_ptr->order) - break; - - /* Set source insn. */ - relocation = - fix_ptr->h->root.u.def.value + - fix_ptr->h->root.u.def.section->output_section->vma + - fix_ptr->h->root.u.def.section->output_offset; - relocation += fix_ptr->irel->r_addend; - /* sethi imm is imm20s. */ - source_insn = insn_with_reg | ((relocation >> shift) & 0xfffff); - - while (temp_ptr) - { - /* Match entry and source code. */ - insn = bfd_getb32 (contents + (temp_ptr->order) * 4 + offset); - if (insn == source_insn) - { - /* Fix the ex9 insn. */ - if (temp_ptr->order != fix_ptr->order) - { - if (!nds32_get_section_contents - (fix_ptr->sec->owner, fix_ptr->sec, - &source_contents, TRUE)) - _bfd_error_handler - (_("Linker: error cannot fixed ex9 relocation \n")); - if (temp_ptr->order < 32) - insn_ex9 = INSN_EX9_IT_2; - else - insn_ex9 = INSN_EX9_IT_1; - insn_ex9 = insn_ex9 | temp_ptr->order; - bfd_putb16 (insn_ex9, source_contents + fix_ptr->irel->r_offset); - } - break; - } - else - { - if (!temp_ptr->next || temp_ptr->m_list != temp_ptr->next->m_list) - _bfd_error_handler - (_("Linker: error cannot fixed ex9 relocation \n")); - else - temp_ptr = temp_ptr->next; - } - } - fix_ptr = fix_ptr->next; - } - } - else - { - relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info); - insn = insn_with_reg - | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup)); - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - } - } - else - { - /* Insn without relocation does not have to be fixed - if need to update export table. */ - if (update_ex9_table == 1) - bfd_putb32 (insn, contents + (ex9_insn->order) * 4); - } - ex9_insn = ex9_insn->next; - size += 4; - } - - ex9_export_file = table->ex9_export_file; - if (ex9_export_file != NULL) - nds32_elf_ex9_export (link_info, contents, table_sec->size); - else if (update_ex9_table == 1) - { - table->ex9_export_file = table->ex9_import_file; - rewind (table->ex9_export_file); - nds32_elf_ex9_export (link_info, contents, size); - } -} - -/* Generate ex9 hash table. */ - -static bfd_boolean -nds32_elf_ex9_build_hash_table (bfd *abfd, asection *sec, - struct bfd_link_info *link_info) -{ - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irelend; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *jrel; - Elf_Internal_Rela rel_backup; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isym = NULL; - asection *isec; - struct elf_link_hash_entry **sym_hashes; - bfd_byte *contents = NULL; - bfd_vma off = 0; - unsigned long r_symndx; - uint32_t insn, insn_with_reg; - struct elf_link_hash_entry *h; - int data_flag, shift, align; - bfd_vma relocation; - /* Suppress ex9 if `.no_relax ex9' or inner loop. */ - reloc_howto_type *howto = NULL; - - sym_hashes = elf_sym_hashes (abfd); - /* Load section instructions, relocations, and symbol table. */ - if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)) - return FALSE; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - TRUE /* keep_memory */); - irelend = internal_relocs + sec->reloc_count; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - if (!nds32_get_local_syms (abfd, sec, &isym)) - return FALSE; - - /* Check the object if enable ex9. */ - irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend, - R_NDS32_RELAX_ENTRY); - - /* Check this section trigger ex9 relaxation. */ - if (irel == NULL - || irel >= irelend - || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY - || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY - && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG))) - return TRUE; - - irel = internal_relocs; - - /* Push each insn into hash table. */ - while (off < sec->size) - { - char code[10]; - struct elf_nds32_code_hash_entry *entry; - - while (irel != NULL && irel < irelend && irel->r_offset < off) - irel++; - - data_flag = nds32_elf_ex9_relocation_check (link_info, &irel, irelend, - NULL, sec, &off, contents); - if (data_flag & DATA_EXIST) - { - /* We save the move offset in the highest byte. */ - off += (data_flag >> 24); - continue; - } - - if (*(contents + off) & 0x80) - { - off += 2; - } - else - { - h = NULL; - isec = NULL; - jrel = NULL; - rel_backup.r_info = 0; - rel_backup.r_offset = 0; - rel_backup.r_addend = 0; - /* Load the instruction and its opcode with register for comparing. */ - insn = bfd_getb32 (contents + off); - insn_with_reg = 0; - if (irel != NULL && irel < irelend && irel->r_offset == off) - { - nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg); - howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info)); - shift = howto->rightshift; - align = (1 << shift) - 1; - if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA - || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA - ||(ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) - { - r_symndx = ELF32_R_SYM (irel->r_info); - jrel = irel; - rel_backup = *irel; - if (r_symndx < symtab_hdr->sh_info) - { - /* Local symbol. */ - int shndx = isym[r_symndx].st_shndx; - - bfd_vma st_value = (isym + r_symndx)->st_value; - isec = elf_elfsections (abfd)[shndx]->bfd_section; - relocation = (isec->output_section->vma + isec->output_offset - + st_value + irel->r_addend); - } - else - { - /* External symbol. */ - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED; - asection *sym_sec; - - /* Maybe there is a better way to get h and relocation */ - RELOC_FOR_GLOBAL_SYMBOL (link_info, abfd, sec, irel, - r_symndx, symtab_hdr, sym_hashes, - h, sym_sec, relocation, - unresolved_reloc, warned, ignored); - relocation += irel->r_addend; - if ((h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - || strcmp (h->root.root.string, "_FP_BASE_") == 0) - { - off += 4; - continue; - } - } - - /* Check for gp relative instruction alignment. */ - if ((ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3 - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA) - || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA - && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA)) - { - bfd_vma gp; - bfd *output_bfd = sec->output_section->owner; - bfd_reloc_status_type r; - - /* If the symbol is in the abs section, the out_bfd will be null. - This happens when the relocation has a symbol@GOTOFF. */ - r = nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE); - if (r != bfd_reloc_ok) - { - off += 4; - continue; - } - - relocation -= gp; - - /* Make sure alignment is correct. */ - if (relocation & align) - { - /* Incorrect alignment. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: unaligned small data access " - "for entry: {%Ld, %Ld, %Ld}, addr = %#Lx, align = %#x"), - abfd, irel->r_offset, - irel->r_info, irel->r_addend, relocation, align); - off += 4; - continue; - } - } - - insn = insn_with_reg - | ((relocation >> shift) & nds32_elf_irel_mask (irel)); - } - else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN - || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END - || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE) - { - /* These relocations do not have to relocate contens, so it can - be regard as instruction without relocation. */ - } - else - { - off += 4; - continue; - } - } - - snprintf (code, sizeof (code), "%08x", insn); - /* Copy "code". */ - entry = (struct elf_nds32_code_hash_entry*) - bfd_hash_lookup (&ex9_code_table, code, TRUE, TRUE); - if (entry == NULL) - { - _bfd_error_handler - (_("failed creating ex9.it %s hash table entry"), code); - return FALSE; - } - if (h) - { - if (h->root.type == bfd_link_hash_undefined) - return TRUE; - /* Global symbol. */ - /* In order to do sethi with different symbol but same value. */ - if (entry->m_list == NULL) - { - struct elf_link_hash_entry_mul_list *m_list_new; - struct elf_link_hash_entry_list *h_list_new; - - m_list_new = (struct elf_link_hash_entry_mul_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list)); - h_list_new = (struct elf_link_hash_entry_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_list)); - entry->m_list = m_list_new; - m_list_new->h_list = h_list_new; - m_list_new->rel_backup = rel_backup; - m_list_new->times = 1; - m_list_new->irel = jrel; - m_list_new->next = NULL; - h_list_new->h = h; - h_list_new->next = NULL; - } - else - { - struct elf_link_hash_entry_mul_list *m_list = entry->m_list; - struct elf_link_hash_entry_list *h_list; - - while (m_list) - { - /* Build the different symbols that point to the same address. */ - h_list = m_list->h_list; - if (h_list->h->root.u.def.value == h->root.u.def.value - && h_list->h->root.u.def.section->output_section->vma - == h->root.u.def.section->output_section->vma - && h_list->h->root.u.def.section->output_offset - == h->root.u.def.section->output_offset - && m_list->rel_backup.r_addend == rel_backup.r_addend) - { - m_list->times++; - m_list->irel = jrel; - while (h_list->h != h && h_list->next) - h_list = h_list->next; - if (h_list->h != h) - { - struct elf_link_hash_entry_list *h_list_new; - - h_list_new = (struct elf_link_hash_entry_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_list)); - h_list->next = h_list_new; - h_list_new->h = h; - h_list_new->next = NULL; - } - break; - } - /* The sethi case may have different address but the - hi20 is the same. */ - else if (ELF32_R_TYPE (jrel->r_info) == R_NDS32_HI20_RELA - && m_list->next == NULL) - { - struct elf_link_hash_entry_mul_list *m_list_new; - struct elf_link_hash_entry_list *h_list_new; - - m_list_new = (struct elf_link_hash_entry_mul_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list)); - h_list_new = (struct elf_link_hash_entry_list *) - bfd_malloc (sizeof (struct elf_link_hash_entry_list)); - m_list->next = m_list_new; - m_list_new->h_list = h_list_new; - m_list_new->rel_backup = rel_backup; - m_list_new->times = 1; - m_list_new->irel = jrel; - m_list_new->next = NULL; - h_list_new->h = h; - h_list_new->next = NULL; - break; - } - m_list = m_list->next; - } - if (!m_list) - { - off += 4; - continue; - } - } - } - else - { - /* Local symbol and insn without relocation*/ - entry->times++; - entry->rel_backup = rel_backup; - } - - /* Use in sethi insn with constant and global symbol in same format. */ - if (!jrel) - entry->const_insn = 1; - else - entry->irel = jrel; - entry->sec = isec; - off += 4; - } - } - return TRUE; -} - -/* Set the _ITB_BASE, and point it to ex9 table. */ - -bfd_boolean -nds32_elf_ex9_itb_base (struct bfd_link_info *link_info) -{ - bfd *abfd; - asection *sec; - bfd *output_bfd = NULL; - struct bfd_link_hash_entry *bh = NULL; - - if (is_ITB_BASE_set == 1) - return TRUE; - - is_ITB_BASE_set = 1; - - bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", FALSE, FALSE, TRUE); - - if (bh && (bh->type == bfd_link_hash_defined - || bh->type == bfd_link_hash_defweak)) - return TRUE; - - for (abfd = link_info->input_bfds; abfd != NULL; - abfd = abfd->link.next) - { - sec = bfd_get_section_by_name (abfd, ".ex9.itable"); - if (sec != NULL) - { - output_bfd = sec->output_section->owner; - break; - } - } - if (output_bfd == NULL) - { - output_bfd = link_info->output_bfd; - if (output_bfd->sections == NULL) - return TRUE; - else - sec = bfd_abs_section_ptr; - } - bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", - FALSE, FALSE, TRUE); - return (_bfd_generic_link_add_one_symbol - (link_info, output_bfd, "_ITB_BASE_", - BSF_GLOBAL | BSF_WEAK, sec, 0, - (const char *) NULL, FALSE, get_elf_backend_data - (output_bfd)->collect, &bh)); -} /* End EX9.IT */ - - -#define ELF_ARCH bfd_arch_nds32 -#define ELF_MACHINE_CODE EM_NDS32 -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_TARGET_ID NDS32_ELF_DATA - -#define TARGET_BIG_SYM nds32_elf32_be_vec -#define TARGET_BIG_NAME "elf32-nds32be" -#define TARGET_LITTLE_SYM nds32_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-nds32le" - -#define elf_info_to_howto nds32_info_to_howto -#define elf_info_to_howto_rel nds32_info_to_howto_rel - -#define bfd_elf32_bfd_link_hash_table_create nds32_elf_link_hash_table_create -#define bfd_elf32_bfd_merge_private_bfd_data nds32_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data nds32_elf_print_private_bfd_data -#define bfd_elf32_bfd_relax_section nds32_elf_relax_section -#define bfd_elf32_bfd_set_private_flags nds32_elf_set_private_flags - -#define bfd_elf32_mkobject nds32_elf_mkobject -#define elf_backend_action_discarded nds32_elf_action_discarded -#define elf_backend_add_symbol_hook nds32_elf_add_symbol_hook -#define elf_backend_check_relocs nds32_elf_check_relocs -#define elf_backend_adjust_dynamic_symbol nds32_elf_adjust_dynamic_symbol -#define elf_backend_create_dynamic_sections nds32_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections nds32_elf_finish_dynamic_sections -#define elf_backend_finish_dynamic_symbol nds32_elf_finish_dynamic_symbol -#define elf_backend_size_dynamic_sections nds32_elf_size_dynamic_sections -#define elf_backend_relocate_section nds32_elf_relocate_section -#define elf_backend_gc_mark_hook nds32_elf_gc_mark_hook -#define elf_backend_grok_prstatus nds32_elf_grok_prstatus -#define elf_backend_grok_psinfo nds32_elf_grok_psinfo -#define elf_backend_reloc_type_class nds32_elf_reloc_type_class -#define elf_backend_copy_indirect_symbol nds32_elf_copy_indirect_symbol -#define elf_backend_link_output_symbol_hook nds32_elf_output_symbol_hook -#define elf_backend_output_arch_syms nds32_elf_output_arch_syms -#define elf_backend_object_p nds32_elf_object_p -#define elf_backend_final_write_processing nds32_elf_final_write_processing -#define elf_backend_special_sections nds32_elf_special_sections -#define bfd_elf32_bfd_get_relocated_section_contents \ - nds32_elf_get_relocated_section_contents - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_may_use_rel_p 1 -#define elf_backend_default_use_rela_p 1 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_dtrel_excludes_plt 1 - -#include "elf32-target.h" - -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x2000 - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM nds32_elf32_linux_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-nds32be-linux" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM nds32_elf32_linux_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-nds32le-linux" -#undef elf32_bed -#define elf32_bed elf32_nds32_lin_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-nds32.h b/sdcc/support/sdbinutils/bfd/elf32-nds32.h deleted file mode 100644 index 7e09e01a3..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-nds32.h +++ /dev/null @@ -1,159 +0,0 @@ -/* NDS32-specific support for 32-bit ELF. - Copyright (C) 2012-2018 Free Software Foundation, Inc. - Contributed by Andes Technology Corporation. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA.*/ - -#ifndef ELF32_NDS32_H -#define ELF32_NDS32_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Relocation flags encoded in r_addend. */ - -/* Relocation flags for R_NDS32_ERLAX_ENTRY. */ - -/* Set if relax on this section is done or disabled. */ -#define R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG (1 << 31) -/* Optimize for performance. */ -#define R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG (1 << 30) -/* Optimize for size. Branch destination 4-byte adjustment - may be disabled. */ -#define R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG (1 << 29) -/* To distinguish the assembly code generated by compiler - or written manually. */ -#define R_NDS32_RELAX_ENTRY_VERBATIM_FLAG (1 << 28) -/* EX9 and link-time IFC must be explicitly enabled, so we - won't mess up handcraft assembly code. */ -/* Enable EX9 optimization for this section. */ -#define R_NDS32_RELAX_ENTRY_EX9_FLAG (1 << 2) -/* Enable IFC optimization for this section. */ -#define R_NDS32_RELAX_ENTRY_IFC_FLAG (1 << 3) - - -/* Relocation flags for R_NDS32_INSN16. */ - -/* Tag the nop16 can be removed. */ -#define R_NDS32_INSN16_CONVERT_FLAG (1 << 0) -/* Convert a gp-relative access (e.g., lwi.gp) - to fp-as-gp access (lwi37.fp). - This value is used by linker internally only. - It's fine to change the vlaue. */ -#define R_NDS32_INSN16_FP7U2_FLAG (1 << 1) - -/* Relocation flags for R_NDS32_RELAX_REGION_OMIT_FP_START/END. */ - -/* OMIT_FP_FLAG marks the region for applying fp-as-gp - optimization. */ -#define R_NDS32_RELAX_REGION_OMIT_FP_FLAG (1 << 0) -/* NOT_OMIT_FP_FLAG is set if this region is not worth - for fp-as-gp. */ -#define R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG (1 << 1) -/* Suppress EX9 optimization in the region. */ -#define R_NDS32_RELAX_REGION_NO_EX9_FLAG (1 << 2) -/* A Innermost loop region. Some optimizations is suppressed - in this region due to performance drop. */ -#define R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG (1 << 4) - -/* Tag range for LOADSTORE relocation. */ -enum -{ - NDS32_LOADSTORE_NONE = 0x0, - NDS32_LOADSTORE_BYTE = 0x1, - NDS32_LOADSTORE_HALF = 0x2, - NDS32_LOADSTORE_WORD = 0x4, - NDS32_LOADSTORE_FLOAT_S = 0x8, - NDS32_LOADSTORE_FLOAT_D = 0x10, - NDS32_LOADSTORE_IMM = 0x20 -}; - -/* Relax tag for nds32_elf_relax_section, we have to specify which - optimization do in this round. */ -enum -{ - NDS32_RELAX_NONE_ROUND = 0, - NDS32_RELAX_NORMAL_ROUND, - NDS32_RELAX_JUMP_IFC_ROUND, - NDS32_RELAX_EX9_BUILD_ROUND, - NDS32_RELAX_EX9_REPLACE_ROUND, - NDS32_RELAX_EMPTY_ROUND -}; - -/* Optimization status mask. */ -#define NDS32_RELAX_JUMP_IFC_DONE (1 << 0) -#define NDS32_RELAX_EX9_DONE (1 << 1) - -/* Optimization turn on mask. */ -#define NDS32_RELAX_JUMP_IFC_ON (1 << 0) -#define NDS32_RELAX_EX9_ON (1 << 1) - -extern void nds32_insertion_sort - (void *, size_t, size_t, int (*) (const void *, const void *)); - -extern int nds32_elf_ex9_init (void); -extern int nds32_convert_32_to_16 (bfd *, uint32_t, uint16_t *, int *); -extern int nds32_convert_16_to_32 (bfd *, uint16_t, uint32_t *); -extern void bfd_elf32_nds32_set_target_option (struct bfd_link_info *, - int, int, FILE *, int, - int, int, int, FILE *, - FILE *, int, int, - bfd_boolean, bfd_boolean); - -#define nds32_elf_hash_table(info) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \ - == NDS32_ELF_DATA ? \ - ((struct elf_nds32_link_hash_table *) ((info)->hash)) : NULL) - -/* Hash table structure for target nds32. There are some members to - save target options passed from nds32elf.em to bfd. */ - -struct elf_nds32_link_hash_table -{ - struct elf_link_hash_table root; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sdynbss; - asection *srelbss; - - /* Small local sym to section mapping cache. */ - struct sym_cache sym_cache; - - /* Target dependent options. */ - int relax_fp_as_gp; /* --mrelax-omit-fp */ - int eliminate_gc_relocs; /* --meliminate-gc-relocs */ - FILE *sym_ld_script; /* --mgen-symbol-ld-script= */ - /* Disable if linking a dynamically linked executable. */ - int load_store_relax; - int target_optimize; /* Switch optimization. */ - int relax_status; /* Finished optimization. */ - int relax_round; /* Going optimization. */ - FILE *ex9_export_file; /* --mexport-ex9= */ - FILE *ex9_import_file; /* --mimport-ex9= */ - int update_ex9_table; /* --mupdate-ex9. */ - int ex9_limit; - bfd_boolean ex9_loop_aware; /* Ignore ex9 if inside a loop. */ - bfd_boolean ifc_loop_aware; /* Ignore ifc if inside a loop. */ -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sdcc/support/sdbinutils/bfd/elf32-nios2.c b/sdcc/support/sdbinutils/bfd/elf32-nios2.c deleted file mode 100644 index aad4bd0f5..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-nios2.c +++ /dev/null @@ -1,6133 +0,0 @@ -/* 32-bit ELF support for Nios II. - Copyright (C) 2012-2018 Free Software Foundation, Inc. - Contributed by Nigel Gray (ngray@altera.com). - Contributed by Mentor Graphics, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* This file handles Altera Nios II ELF targets. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "genlink.h" -#include "elf-bfd.h" -#include "elf/nios2.h" -#include "opcode/nios2.h" -#include "elf32-nios2.h" - -/* Use RELA relocations. */ -#ifndef USE_RELA -#define USE_RELA -#endif - -#ifdef USE_REL -#undef USE_REL -#endif - -/* Forward declarations. */ -static bfd_reloc_status_type nios2_elf32_ignore_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_hi16_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_lo16_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_hiadj16_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_pcrel_lo16_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_pcrel_hiadj16_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_pcrel16_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_call26_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_gprel_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_ujmp_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_cjmp_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type nios2_elf32_callr_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -/* Target vector. */ -extern const bfd_target nios2_elf32_le_vec; -extern const bfd_target nios2_elf32_be_vec; - -/* Offset of tp and dtp pointers from start of TLS block. */ -#define TP_OFFSET 0x7000 -#define DTP_OFFSET 0x8000 - -/* The relocation tables used for SHT_REL sections. There are separate - tables for R1 and R2 encodings. */ -static reloc_howto_type elf_nios2_r1_howto_table_rel[] = { - /* No relocation. */ - HOWTO (R_NIOS2_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NIOS2_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit signed immediate relocation. */ - HOWTO (R_NIOS2_S16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_signed, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_NIOS2_S16", /* name */ - FALSE, /* partial_inplace */ - 0x003fffc0, /* src_mask */ - 0x003fffc0, /* dest_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit unsigned immediate relocation. */ - HOWTO (R_NIOS2_U16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_unsigned, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_NIOS2_U16", /* name */ - FALSE, /* partial_inplace */ - 0x003fffc0, /* src_mask */ - 0x003fffc0, /* dest_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NIOS2_PCREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_signed, /* complain on overflow */ - nios2_elf32_pcrel16_relocate, /* special function */ - "R_NIOS2_PCREL16", /* name */ - FALSE, /* partial_inplace */ - 0x003fffc0, /* src_mask */ - 0x003fffc0, /* dest_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_NIOS2_CALL26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain on overflow */ - nios2_elf32_call26_relocate, /* special function */ - "R_NIOS2_CALL26", /* name */ - FALSE, /* partial_inplace */ - 0xffffffc0, /* src_mask */ - 0xffffffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NIOS2_IMM5, - 0, - 2, - 5, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM5", - FALSE, - 0x000007c0, - 0x000007c0, - FALSE), - - HOWTO (R_NIOS2_CACHE_OPX, - 0, - 2, - 5, - FALSE, - 22, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CACHE_OPX", - FALSE, - 0x07c00000, - 0x07c00000, - FALSE), - - HOWTO (R_NIOS2_IMM6, - 0, - 2, - 6, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM6", - FALSE, - 0x00000fc0, - 0x00000fc0, - FALSE), - - HOWTO (R_NIOS2_IMM8, - 0, - 2, - 8, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM8", - FALSE, - 0x00003fc0, - 0x00003fc0, - FALSE), - - HOWTO (R_NIOS2_HI16, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_hi16_relocate, - "R_NIOS2_HI16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_LO16, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_lo16_relocate, - "R_NIOS2_LO16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_HIADJ16, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_hiadj16_relocate, - "R_NIOS2_HIADJ16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_BFD_RELOC_32, - 0, - 2, /* long */ - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC32", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_BFD_RELOC_16, - 0, - 1, /* short */ - 16, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC16", - FALSE, - 0x0000ffff, - 0x0000ffff, - FALSE), - - HOWTO (R_NIOS2_BFD_RELOC_8, - 0, - 0, /* byte */ - 8, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC8", - FALSE, - 0x000000ff, - 0x000000ff, - FALSE), - - HOWTO (R_NIOS2_GPREL, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_gprel_relocate, - "R_NIOS2_GPREL", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_GNU_VTINHERIT, - 0, - 2, /* short */ - 0, - FALSE, - 0, - complain_overflow_dont, - NULL, - "R_NIOS2_GNU_VTINHERIT", - FALSE, - 0, - 0, - FALSE), - - HOWTO (R_NIOS2_GNU_VTENTRY, - 0, - 2, /* byte */ - 0, - FALSE, - 0, - complain_overflow_dont, - _bfd_elf_rel_vtable_reloc_fn, - "R_NIOS2_GNU_VTENTRY", - FALSE, - 0, - 0, - FALSE), - - HOWTO (R_NIOS2_UJMP, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_ujmp_relocate, - "R_NIOS2_UJMP", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_CJMP, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_cjmp_relocate, - "R_NIOS2_CJMP", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_CALLR, - 0, - 2, - 32, - FALSE, - 6, - complain_overflow_dont, - nios2_elf32_callr_relocate, - "R_NIOS2_CALLR", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_ALIGN, - 0, - 2, - 0, - FALSE, - 0, - complain_overflow_dont, - nios2_elf32_ignore_reloc, - "R_NIOS2_ALIGN", - FALSE, - 0, - 0, - TRUE), - - - HOWTO (R_NIOS2_GOT16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_GOT16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_CALL16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CALL16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_GOTOFF_LO, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_LO", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_GOTOFF_HA, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_HA", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_PCREL_LO, - 0, - 2, - 16, - TRUE, - 6, - complain_overflow_dont, - nios2_elf32_pcrel_lo16_relocate, - "R_NIOS2_PCREL_LO", - FALSE, - 0x003fffc0, - 0x003fffc0, - TRUE), - - HOWTO (R_NIOS2_PCREL_HA, - 0, - 2, - 16, - FALSE, /* This is a PC-relative relocation, but we need to subtract - PC ourselves before the HIADJ. */ - 6, - complain_overflow_dont, - nios2_elf32_pcrel_hiadj16_relocate, - "R_NIOS2_PCREL_HA", - FALSE, - 0x003fffc0, - 0x003fffc0, - TRUE), - - HOWTO (R_NIOS2_TLS_GD16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_GD16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_TLS_LDM16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDM16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_TLS_LDO16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDO16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_TLS_IE16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_IE16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_TLS_LE16, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LE16", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_TLS_DTPMOD, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPMOD", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_TLS_DTPREL, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPREL", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_TLS_TPREL, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_TPREL", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_COPY, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_COPY", - FALSE, - 0, - 0, - FALSE), - - HOWTO (R_NIOS2_GLOB_DAT, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GLOB_DAT", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_JUMP_SLOT, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_JUMP_SLOT", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_RELATIVE, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_RELATIVE", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_GOTOFF, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_CALL26_NOAT, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain on overflow */ - nios2_elf32_call26_relocate, /* special function */ - "R_NIOS2_CALL26_NOAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffc0, /* src_mask */ - 0xffffffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NIOS2_GOT_LO, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_LO", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_GOT_HA, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_HA", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_CALL_LO, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_LO", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - - HOWTO (R_NIOS2_CALL_HA, - 0, - 2, - 16, - FALSE, - 6, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_HA", - FALSE, - 0x003fffc0, - 0x003fffc0, - FALSE), - -/* Add other relocations here. */ -}; - -static reloc_howto_type elf_nios2_r2_howto_table_rel[] = { - /* No relocation. */ - HOWTO (R_NIOS2_NONE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_NIOS2_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit signed immediate relocation. */ - HOWTO (R_NIOS2_S16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_NIOS2_S16", /* name */ - FALSE, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dest_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit unsigned immediate relocation. */ - HOWTO (R_NIOS2_U16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_unsigned, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_NIOS2_U16", /* name */ - FALSE, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dest_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NIOS2_PCREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed, /* complain on overflow */ - nios2_elf32_pcrel16_relocate, /* special function */ - "R_NIOS2_PCREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff0000, /* src_mask */ - 0xffff0000, /* dest_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_NIOS2_CALL26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain on overflow */ - nios2_elf32_call26_relocate, /* special function */ - "R_NIOS2_CALL26", /* name */ - FALSE, /* partial_inplace */ - 0xffffffc0, /* src_mask */ - 0xffffffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NIOS2_IMM5, - 0, - 2, - 5, - FALSE, - 21, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM5", - FALSE, - 0x03e00000, - 0x03e00000, - FALSE), - - HOWTO (R_NIOS2_CACHE_OPX, - 0, - 2, - 5, - FALSE, - 11, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CACHE_OPX", - FALSE, - 0x0000f800, - 0x0000f800, - FALSE), - - HOWTO (R_NIOS2_IMM6, - 0, - 2, - 6, - FALSE, - 26, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM6", - FALSE, - 0xfc000000, - 0xfc000000, - FALSE), - - HOWTO (R_NIOS2_IMM8, - 0, - 2, - 8, - FALSE, - 24, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_IMM8", - FALSE, - 0xff000000, - 0xff000000, - FALSE), - - HOWTO (R_NIOS2_HI16, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_hi16_relocate, - "R_NIOS2_HI16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_LO16, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_lo16_relocate, - "R_NIOS2_LO16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_HIADJ16, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_hiadj16_relocate, - "R_NIOS2_HIADJ16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_BFD_RELOC_32, - 0, - 2, /* long */ - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC32", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_BFD_RELOC_16, - 0, - 1, /* short */ - 16, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC16", - FALSE, - 0x0000ffff, - 0x0000ffff, - FALSE), - - HOWTO (R_NIOS2_BFD_RELOC_8, - 0, - 0, /* byte */ - 8, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_BFD_RELOC8", - FALSE, - 0x000000ff, - 0x000000ff, - FALSE), - - HOWTO (R_NIOS2_GPREL, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_gprel_relocate, - "R_NIOS2_GPREL", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_GNU_VTINHERIT, - 0, - 2, /* short */ - 0, - FALSE, - 0, - complain_overflow_dont, - NULL, - "R_NIOS2_GNU_VTINHERIT", - FALSE, - 0, - 0, - FALSE), - - HOWTO (R_NIOS2_GNU_VTENTRY, - 0, - 2, /* byte */ - 0, - FALSE, - 0, - complain_overflow_dont, - _bfd_elf_rel_vtable_reloc_fn, - "R_NIOS2_GNU_VTENTRY", - FALSE, - 0, - 0, - FALSE), - - HOWTO (R_NIOS2_UJMP, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_ujmp_relocate, - "R_NIOS2_UJMP", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_CJMP, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_cjmp_relocate, - "R_NIOS2_CJMP", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_CALLR, - 0, - 2, - 32, - FALSE, - 16, - complain_overflow_dont, - nios2_elf32_callr_relocate, - "R_NIOS2_CALLR", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_ALIGN, - 0, - 2, - 0, - FALSE, - 0, - complain_overflow_dont, - nios2_elf32_ignore_reloc, - "R_NIOS2_ALIGN", - FALSE, - 0, - 0, - TRUE), - - HOWTO (R_NIOS2_GOT16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_GOT16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_CALL16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_CALL16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_GOTOFF_LO, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_LO", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_GOTOFF_HA, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF_HA", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_PCREL_LO, - 0, - 2, - 16, - TRUE, - 16, - complain_overflow_dont, - nios2_elf32_pcrel_lo16_relocate, - "R_NIOS2_PCREL_LO", - FALSE, - 0xffff0000, - 0xffff0000, - TRUE), - - HOWTO (R_NIOS2_PCREL_HA, - 0, - 2, - 16, - FALSE, /* This is a PC-relative relocation, but we need to subtract - PC ourselves before the HIADJ. */ - 16, - complain_overflow_dont, - nios2_elf32_pcrel_hiadj16_relocate, - "R_NIOS2_PCREL_HA", - FALSE, - 0xffff0000, - 0xffff0000, - TRUE), - - HOWTO (R_NIOS2_TLS_GD16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_GD16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_TLS_LDM16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDM16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_TLS_LDO16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LDO16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_TLS_IE16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_IE16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_TLS_LE16, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_LE16", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_TLS_DTPMOD, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPMOD", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_TLS_DTPREL, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_DTPREL", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_TLS_TPREL, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_TLS_TPREL", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_COPY, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_COPY", - FALSE, - 0, - 0, - FALSE), - - HOWTO (R_NIOS2_GLOB_DAT, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GLOB_DAT", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_JUMP_SLOT, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_JUMP_SLOT", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_RELATIVE, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_RELATIVE", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_GOTOFF, - 0, - 2, - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOTOFF", - FALSE, - 0xffffffff, - 0xffffffff, - FALSE), - - HOWTO (R_NIOS2_CALL26_NOAT, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_dont, /* complain on overflow */ - nios2_elf32_call26_relocate, /* special function */ - "R_NIOS2_CALL26_NOAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffc0, /* src_mask */ - 0xffffffc0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_NIOS2_GOT_LO, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_LO", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_GOT_HA, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_GOT_HA", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_CALL_LO, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_LO", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_CALL_HA, - 0, - 2, - 16, - FALSE, - 16, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_NIOS2_CALL_HA", - FALSE, - 0xffff0000, - 0xffff0000, - FALSE), - - HOWTO (R_NIOS2_R2_S12, - 0, - 2, - 12, - FALSE, - 16, - complain_overflow_signed, - bfd_elf_generic_reloc, - "R_NIOS2_R2_S12", - FALSE, - 0x0fff0000, - 0x0fff0000, - FALSE), - - HOWTO (R_NIOS2_R2_I10_1_PCREL, - 1, - 1, - 10, - TRUE, - 6, - complain_overflow_signed, - bfd_elf_generic_reloc, /* FIXME? */ - "R_NIOS2_R2_I10_1_PCREL", - FALSE, - 0xffc0, - 0xffc0, - TRUE), - - HOWTO (R_NIOS2_R2_T1I7_1_PCREL, - 1, - 1, - 7, - TRUE, - 9, - complain_overflow_signed, - bfd_elf_generic_reloc, /* FIXME? */ - "R_NIOS2_R2_T1I7_1_PCREL", - FALSE, - 0xfe00, - 0xfe00, - TRUE), - - HOWTO (R_NIOS2_R2_T1I7_2, - 2, - 1, - 7, - FALSE, - 9, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T1I7_2", - FALSE, - 0xfe00, - 0xfe00, - FALSE), - - HOWTO (R_NIOS2_R2_T2I4, - 0, - 1, - 4, - FALSE, - 12, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T2I4", - FALSE, - 0xf000, - 0xf000, - FALSE), - - HOWTO (R_NIOS2_R2_T2I4_1, - 1, - 1, - 4, - FALSE, - 12, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T2I4_1", - FALSE, - 0xf000, - 0xf000, - FALSE), - - HOWTO (R_NIOS2_R2_T2I4_2, - 2, - 1, - 4, - FALSE, - 12, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T2I4_2", - FALSE, - 0xf000, - 0xf000, - FALSE), - - HOWTO (R_NIOS2_R2_X1I7_2, - 2, - 1, - 7, - FALSE, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_X1I7_2", - FALSE, - 0x1fc0, - 0x1fc0, - FALSE), - - HOWTO (R_NIOS2_R2_X2L5, - 0, - 1, - 5, - FALSE, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_X2L5", - FALSE, - 0x07c0, - 0x07c0, - FALSE), - - HOWTO (R_NIOS2_R2_F1I5_2, - 2, - 1, - 5, - FALSE, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_F1L5_2", - FALSE, - 0x07c0, - 0x07c0, - FALSE), - - HOWTO (R_NIOS2_R2_L5I4X1, - 2, - 1, - 4, - FALSE, - 6, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_L5I4X1", - FALSE, - 0x03c0, - 0x03c0, - FALSE), - - HOWTO (R_NIOS2_R2_T1X1I6, - 0, - 1, - 6, - FALSE, - 9, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T1X1I6", - FALSE, - 0x7e00, - 0x7e00, - FALSE), - - HOWTO (R_NIOS2_R2_T1X1I6_2, - 2, - 2, - 6, - FALSE, - 9, - complain_overflow_unsigned, - bfd_elf_generic_reloc, - "R_NIOS2_R2_T1I1X6_2", - FALSE, - 0x7e00, - 0x7e00, - FALSE), - -/* Add other relocations here. */ -}; - -static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1]; - - -/* Return true if producing output for a R2 BFD. */ -#define BFD_IS_R2(abfd) (bfd_get_mach (abfd) == bfd_mach_nios2r2) - -/* Return the howto for relocation RTYPE. */ -static reloc_howto_type * -lookup_howto (unsigned int rtype, bfd *abfd) -{ - static int initialized = 0; - int i; - /* R2 relocations are a superset of R1, so use that for the lookup - table. */ - int r1_howto_tbl_size = (int) (sizeof (elf_nios2_r1_howto_table_rel) - / sizeof (elf_nios2_r1_howto_table_rel[0])); - int r2_howto_tbl_size = (int) (sizeof (elf_nios2_r2_howto_table_rel) - / sizeof (elf_nios2_r2_howto_table_rel[0])); - - if (!initialized) - { - initialized = 1; - memset (elf_code_to_howto_index, 0xff, - sizeof (elf_code_to_howto_index)); - for (i = 0; i < r2_howto_tbl_size; i++) - { - elf_code_to_howto_index[elf_nios2_r2_howto_table_rel[i].type] = i; - if (i < r1_howto_tbl_size) - BFD_ASSERT (elf_nios2_r2_howto_table_rel[i].type - == elf_nios2_r1_howto_table_rel[i].type); - } - } - - BFD_ASSERT (rtype <= R_NIOS2_ILLEGAL); - i = elf_code_to_howto_index[rtype]; - if (BFD_IS_R2 (abfd)) - { - if (i >= r2_howto_tbl_size) - return 0; - return elf_nios2_r2_howto_table_rel + i; - } - else - { - if (i >= r1_howto_tbl_size) - return 0; - return elf_nios2_r1_howto_table_rel + i; - } -} - -/* Map for converting BFD reloc types to Nios II reloc types. */ -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_val; - enum elf_nios2_reloc_type elf_val; -}; - -static const struct elf_reloc_map nios2_reloc_map[] = { - {BFD_RELOC_NONE, R_NIOS2_NONE}, - {BFD_RELOC_NIOS2_S16, R_NIOS2_S16}, - {BFD_RELOC_NIOS2_U16, R_NIOS2_U16}, - {BFD_RELOC_16_PCREL, R_NIOS2_PCREL16}, - {BFD_RELOC_NIOS2_CALL26, R_NIOS2_CALL26}, - {BFD_RELOC_NIOS2_IMM5, R_NIOS2_IMM5}, - {BFD_RELOC_NIOS2_CACHE_OPX, R_NIOS2_CACHE_OPX}, - {BFD_RELOC_NIOS2_IMM6, R_NIOS2_IMM6}, - {BFD_RELOC_NIOS2_IMM8, R_NIOS2_IMM8}, - {BFD_RELOC_NIOS2_HI16, R_NIOS2_HI16}, - {BFD_RELOC_NIOS2_LO16, R_NIOS2_LO16}, - {BFD_RELOC_NIOS2_HIADJ16, R_NIOS2_HIADJ16}, - {BFD_RELOC_32, R_NIOS2_BFD_RELOC_32}, - {BFD_RELOC_16, R_NIOS2_BFD_RELOC_16}, - {BFD_RELOC_8, R_NIOS2_BFD_RELOC_8}, - {BFD_RELOC_NIOS2_GPREL, R_NIOS2_GPREL}, - {BFD_RELOC_VTABLE_INHERIT, R_NIOS2_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_NIOS2_GNU_VTENTRY}, - {BFD_RELOC_NIOS2_UJMP, R_NIOS2_UJMP}, - {BFD_RELOC_NIOS2_CJMP, R_NIOS2_CJMP}, - {BFD_RELOC_NIOS2_CALLR, R_NIOS2_CALLR}, - {BFD_RELOC_NIOS2_ALIGN, R_NIOS2_ALIGN}, - {BFD_RELOC_NIOS2_GOT16, R_NIOS2_GOT16}, - {BFD_RELOC_NIOS2_CALL16, R_NIOS2_CALL16}, - {BFD_RELOC_NIOS2_GOTOFF_LO, R_NIOS2_GOTOFF_LO}, - {BFD_RELOC_NIOS2_GOTOFF_HA, R_NIOS2_GOTOFF_HA}, - {BFD_RELOC_NIOS2_PCREL_LO, R_NIOS2_PCREL_LO}, - {BFD_RELOC_NIOS2_PCREL_HA, R_NIOS2_PCREL_HA}, - {BFD_RELOC_NIOS2_TLS_GD16, R_NIOS2_TLS_GD16}, - {BFD_RELOC_NIOS2_TLS_LDM16, R_NIOS2_TLS_LDM16}, - {BFD_RELOC_NIOS2_TLS_LDO16, R_NIOS2_TLS_LDO16}, - {BFD_RELOC_NIOS2_TLS_IE16, R_NIOS2_TLS_IE16}, - {BFD_RELOC_NIOS2_TLS_LE16, R_NIOS2_TLS_LE16}, - {BFD_RELOC_NIOS2_TLS_DTPMOD, R_NIOS2_TLS_DTPMOD}, - {BFD_RELOC_NIOS2_TLS_DTPREL, R_NIOS2_TLS_DTPREL}, - {BFD_RELOC_NIOS2_TLS_TPREL, R_NIOS2_TLS_TPREL}, - {BFD_RELOC_NIOS2_COPY, R_NIOS2_COPY}, - {BFD_RELOC_NIOS2_GLOB_DAT, R_NIOS2_GLOB_DAT}, - {BFD_RELOC_NIOS2_JUMP_SLOT, R_NIOS2_JUMP_SLOT}, - {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE}, - {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF}, - {BFD_RELOC_NIOS2_CALL26_NOAT, R_NIOS2_CALL26_NOAT}, - {BFD_RELOC_NIOS2_GOT_LO, R_NIOS2_GOT_LO}, - {BFD_RELOC_NIOS2_GOT_HA, R_NIOS2_GOT_HA}, - {BFD_RELOC_NIOS2_CALL_LO, R_NIOS2_CALL_LO}, - {BFD_RELOC_NIOS2_CALL_HA, R_NIOS2_CALL_HA}, - {BFD_RELOC_NIOS2_R2_S12, R_NIOS2_R2_S12}, - {BFD_RELOC_NIOS2_R2_I10_1_PCREL, R_NIOS2_R2_I10_1_PCREL}, - {BFD_RELOC_NIOS2_R2_T1I7_1_PCREL, R_NIOS2_R2_T1I7_1_PCREL}, - {BFD_RELOC_NIOS2_R2_T1I7_2, R_NIOS2_R2_T1I7_2}, - {BFD_RELOC_NIOS2_R2_T2I4, R_NIOS2_R2_T2I4}, - {BFD_RELOC_NIOS2_R2_T2I4_1, R_NIOS2_R2_T2I4_1}, - {BFD_RELOC_NIOS2_R2_T2I4_2, R_NIOS2_R2_T2I4_2}, - {BFD_RELOC_NIOS2_R2_X1I7_2, R_NIOS2_R2_X1I7_2}, - {BFD_RELOC_NIOS2_R2_X2L5, R_NIOS2_R2_X2L5}, - {BFD_RELOC_NIOS2_R2_F1I5_2, R_NIOS2_R2_F1I5_2}, - {BFD_RELOC_NIOS2_R2_L5I4X1, R_NIOS2_R2_L5I4X1}, - {BFD_RELOC_NIOS2_R2_T1X1I6, R_NIOS2_R2_T1X1I6}, - {BFD_RELOC_NIOS2_R2_T1X1I6_2, R_NIOS2_R2_T1X1I6_2}, -}; - -enum elf32_nios2_stub_type -{ - nios2_stub_call26_before, - nios2_stub_call26_after, - nios2_stub_none -}; - -struct elf32_nios2_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry bh_root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; - - enum elf32_nios2_stub_type stub_type; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf32_nios2_link_hash_entry *hh; - - /* And the reloc addend that this was derived from. */ - bfd_vma addend; - - /* Where this stub is being called from, or, in the case of combined - stub sections, the first input section in the group. */ - asection *id_sec; -}; - -#define nios2_stub_hash_entry(ent) \ - ((struct elf32_nios2_stub_hash_entry *)(ent)) - -#define nios2_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_nios2_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - - -/* Nios II ELF linker hash entry. */ - -struct elf32_nios2_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct elf32_nios2_stub_hash_entry *hsh_cache; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_IE 4 - unsigned char tls_type; - - /* We need to detect and take special action for symbols which are only - referenced with %call() and not with %got(). Such symbols do not need - a dynamic GOT reloc in shared objects, only a dynamic PLT reloc. Lazy - linking will not work if the dynamic GOT reloc exists. - To check for this condition efficiently, we compare got_types_used against - CALL_USED, meaning - (got_types_used & (GOT_USED | CALL_USED)) == CALL_USED. - */ -#define GOT_USED 1 -#define CALL_USED 2 - unsigned char got_types_used; -}; - -#define elf32_nios2_hash_entry(ent) \ - ((struct elf32_nios2_link_hash_entry *) (ent)) - -/* Get the Nios II elf linker hash table from a link_info structure. */ -#define elf32_nios2_hash_table(info) \ - ((struct elf32_nios2_link_hash_table *) ((info)->hash)) - -/* Nios II ELF linker hash table. */ -struct elf32_nios2_link_hash_table - { - /* The main hash table. */ - struct elf_link_hash_table root; - - /* The stub hash table. */ - struct bfd_hash_table bstab; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *, bfd_boolean); - void (*layout_sections_again) (void); - - /* Array to keep track of which stub sections have been created, and - information on stub grouping. */ - struct map_stub - { - /* These are the section to which stubs in the group will be - attached. */ - asection *first_sec, *last_sec; - /* The stub sections. There might be stubs inserted either before - or after the real section.*/ - asection *first_stub_sec, *last_stub_sec; - } *stub_group; - - /* Assorted information used by nios2_elf32_size_stubs. */ - unsigned int bfd_count; - unsigned int top_index; - asection **input_list; - Elf_Internal_Sym **all_local_syms; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sbss; - - /* GOT pointer symbol _gp_got. */ - struct elf_link_hash_entry *h_gp_got; - - union { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - bfd_vma res_n_size; - }; - -struct nios2_elf32_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char *local_got_tls_type; - - /* TRUE if TLS GD relocs have been seen for this object. */ - bfd_boolean has_tlsgd; -}; - -#define elf32_nios2_tdata(abfd) \ - ((struct nios2_elf32_obj_tdata *) (abfd)->tdata.any) - -#define elf32_nios2_local_got_tls_type(abfd) \ - (elf32_nios2_tdata (abfd)->local_got_tls_type) - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -/* PLT implementation for position-dependent code. */ -static const bfd_vma nios2_plt_entry[] = { /* .PLTn: */ - 0x03c00034, /* movhi r15, %hiadj(plt_got_slot_address) */ - 0x7bc00017, /* ldw r15, %lo(plt_got_slot_address)(r15) */ - 0x7800683a /* jmp r15 */ -}; - -static const bfd_vma nios2_plt0_entry[] = { /* .PLTresolve */ - 0x03800034, /* movhi r14, %hiadj(res_0) */ - 0x73800004, /* addi r14, r14, %lo(res_0) */ - 0x7b9fc83a, /* sub r15, r15, r14 */ - 0x03400034, /* movhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) */ - 0x6b800017, /* ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) */ - 0x6b400017, /* ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) */ - 0x6800683a /* jmp r13 */ -}; - -/* PLT implementation for position-independent code. */ -static const bfd_vma nios2_so_plt_entry[] = { /* .PLTn */ - 0x03c00034, /* movhi r15, %hiadj(index * 4) */ - 0x7bc00004, /* addi r15, r15, %lo(index * 4) */ - 0x00000006 /* br .PLTresolve */ -}; - -static const bfd_vma nios2_so_plt0_entry[] = { /* .PLTresolve */ - 0x001ce03a, /* nextpc r14 */ - 0x03400034, /* movhi r13, %hiadj(_GLOBAL_OFFSET_TABLE_) */ - 0x6b9b883a, /* add r13, r13, r14 */ - 0x6b800017, /* ldw r14, %lo(_GLOBAL_OFFSET_TABLE_+4)(r13) */ - 0x6b400017, /* ldw r13, %lo(_GLOBAL_OFFSET_TABLE_+8)(r13) */ - 0x6800683a /* jmp r13 */ -}; - -/* CALL26 stub. */ -static const bfd_vma nios2_call26_stub_entry[] = { - 0x00400034, /* orhi at, r0, %hiadj(dest) */ - 0x08400004, /* addi at, at, %lo(dest) */ - 0x0800683a /* jmp at */ -}; - -/* Install 16-bit immediate value VALUE at offset OFFSET into section SEC. */ -static void -nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value) -{ - bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset); - - BFD_ASSERT (value <= 0xffff || ((bfd_signed_vma) value) >= -0xffff); - - bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6), - sec->contents + offset); -} - -/* Install COUNT 32-bit values DATA starting at offset OFFSET into - section SEC. */ -static void -nios2_elf32_install_data (asection *sec, const bfd_vma *data, bfd_vma offset, - int count) -{ - while (count--) - { - bfd_put_32 (sec->owner, *data, sec->contents + offset); - offset += 4; - ++data; - } -} - -/* The usual way of loading a 32-bit constant into a Nios II register is to - load the high 16 bits in one instruction and then add the low 16 bits with - a signed add. This means that the high halfword needs to be adjusted to - compensate for the sign bit of the low halfword. This function returns the - adjusted high halfword for a given 32-bit constant. */ -static -bfd_vma hiadj (bfd_vma symbol_value) -{ - return ((symbol_value + 0x8000) >> 16) & 0xffff; -} - -/* Implement elf_backend_grok_prstatus: - Support for core dump NOTE sections. */ -static bfd_boolean -nios2_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 212: /* Linux/Nios II */ - /* 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 = 136; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -/* Implement elf_backend_grok_psinfo. */ -static bfd_boolean -nios2_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/Nios II 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; -} - -/* Assorted hash table functions. */ - -/* Initialize an entry in the stub hash table. */ -static struct bfd_hash_entry * -stub_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 elf32_nios2_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf32_nios2_stub_hash_entry *hsh; - - /* Initialize the local fields. */ - hsh = (struct elf32_nios2_stub_hash_entry *) entry; - hsh->stub_sec = NULL; - hsh->stub_offset = 0; - hsh->target_value = 0; - hsh->target_section = NULL; - hsh->stub_type = nios2_stub_none; - hsh->hh = NULL; - hsh->id_sec = NULL; - } - - return entry; -} - -/* Create an entry in a Nios II 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 elf32_nios2_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) - { - struct elf32_nios2_link_hash_entry *eh; - - eh = (struct elf32_nios2_link_hash_entry *) entry; - eh->hsh_cache = NULL; - eh->dyn_relocs = NULL; - eh->tls_type = GOT_UNKNOWN; - eh->got_types_used = 0; - } - - return entry; -} - -/* Section name for stubs is the associated section name plus this - string. */ -#define STUB_SUFFIX ".stub" - -/* Build a name for an entry in the stub hash table. */ -static char * -nios2_stub_name (const asection *input_section, - const asection *sym_sec, - const struct elf32_nios2_link_hash_entry *hh, - const Elf_Internal_Rela *rel, - enum elf32_nios2_stub_type stub_type) -{ - char *stub_name; - bfd_size_type len; - char stubpos = (stub_type == nios2_stub_call26_before) ? 'b' : 'a'; - - if (hh) - { - len = 8 + 1 + 1 + 1+ strlen (hh->root.root.root.string) + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - { - sprintf (stub_name, "%08x_%c_%s+%x", - input_section->id & 0xffffffff, - stubpos, - hh->root.root.root.string, - (int) rel->r_addend & 0xffffffff); - } - } - else - { - len = 8 + 1 + 1 + 1+ 8 + 1 + 8 + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name != NULL) - { - sprintf (stub_name, "%08x_%c_%x:%x+%x", - input_section->id & 0xffffffff, - stubpos, - sym_sec->id & 0xffffffff, - (int) ELF32_R_SYM (rel->r_info) & 0xffffffff, - (int) rel->r_addend & 0xffffffff); - } - } - return stub_name; -} - -/* Look up an entry in the stub hash. Stub entries are cached because - creating the stub name takes a bit of time. */ -static struct elf32_nios2_stub_hash_entry * -nios2_get_stub_entry (const asection *input_section, - const asection *sym_sec, - struct elf32_nios2_link_hash_entry *hh, - const Elf_Internal_Rela *rel, - struct elf32_nios2_link_hash_table *htab, - enum elf32_nios2_stub_type stub_type) -{ - struct elf32_nios2_stub_hash_entry *hsh; - const asection *id_sec; - - /* If this input section is part of a group of sections sharing one - stub section, then use the id of the first/last section in the group, - depending on the stub section placement relative to the group. - Stub names need to include a section id, as there may well be - more than one stub used to reach say, printf, and we need to - distinguish between them. */ - if (stub_type == nios2_stub_call26_before) - id_sec = htab->stub_group[input_section->id].first_sec; - else - id_sec = htab->stub_group[input_section->id].last_sec; - - if (hh != NULL && hh->hsh_cache != NULL - && hh->hsh_cache->hh == hh - && hh->hsh_cache->id_sec == id_sec - && hh->hsh_cache->stub_type == stub_type) - { - hsh = hh->hsh_cache; - } - else - { - char *stub_name; - - stub_name = nios2_stub_name (id_sec, sym_sec, hh, rel, stub_type); - if (stub_name == NULL) - return NULL; - - hsh = nios2_stub_hash_lookup (&htab->bstab, - stub_name, FALSE, FALSE); - - if (hh != NULL) - hh->hsh_cache = hsh; - - free (stub_name); - } - - return hsh; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ -static struct elf32_nios2_stub_hash_entry * -nios2_add_stub (const char *stub_name, - asection *section, - struct elf32_nios2_link_hash_table *htab, - enum elf32_nios2_stub_type stub_type) -{ - asection *link_sec; - asection *stub_sec; - asection **secptr, **linkptr; - struct elf32_nios2_stub_hash_entry *hsh; - bfd_boolean afterp; - - if (stub_type == nios2_stub_call26_before) - { - link_sec = htab->stub_group[section->id].first_sec; - secptr = &(htab->stub_group[section->id].first_stub_sec); - linkptr = &(htab->stub_group[link_sec->id].first_stub_sec); - afterp = FALSE; - } - else - { - link_sec = htab->stub_group[section->id].last_sec; - secptr = &(htab->stub_group[section->id].last_stub_sec); - linkptr = &(htab->stub_group[link_sec->id].last_stub_sec); - afterp = TRUE; - } - stub_sec = *secptr; - if (stub_sec == NULL) - { - stub_sec = *linkptr; - if (stub_sec == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - - stub_sec = (*htab->add_stub_section) (s_name, link_sec, afterp); - if (stub_sec == NULL) - return NULL; - *linkptr = stub_sec; - } - *secptr = stub_sec; - } - - /* Enter this entry into the linker stub hash table. */ - hsh = nios2_stub_hash_lookup (&htab->bstab, stub_name, - TRUE, FALSE); - if (hsh == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: cannot create stub entry %s"), - section->owner, - stub_name); - return NULL; - } - - hsh->stub_sec = stub_sec; - hsh->stub_offset = 0; - hsh->id_sec = link_sec; - return hsh; -} - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ -int -nios2_elf32_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *input_bfd; - unsigned int bfd_count; - unsigned int top_id, top_index; - asection *section; - asection **input_list, **list; - bfd_size_type amt; - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - /* Count the number of input BFDs and find the top input section id. */ - for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next) - { - bfd_count += 1; - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - if (top_id < section->id) - top_id = section->id; - } - } - - htab->bfd_count = bfd_count; - - amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = bfd_zmalloc (amt); - if (htab->stub_group == NULL) - return -1; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_malloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; - - /* For sections we aren't interested in, mark their entries with a - value we can check later. */ - list = input_list + top_index; - do - *list = bfd_abs_section_ptr; - while (list-- != input_list); - - for (section = output_bfd->sections; - section != NULL; - section = section->next) - { - /* FIXME: This is a bit of hack. Currently our .ctors and .dtors - * have PC relative relocs in them but no code flag set. */ - if (((section->flags & SEC_CODE) != 0) || - strcmp(".ctors", section->name) || - strcmp(".dtors", section->name)) - input_list[section->index] = NULL; - } - - return 1; -} - -/* The linker repeatedly calls this function for each input section, - in the order that input sections are linked into output sections. - Build lists of input sections to determine groupings between which - we may insert linker stubs. */ -void -nios2_elf32_next_input_section (struct bfd_link_info *info, asection *isec) -{ - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - if (isec->output_section->index <= htab->top_index) - { - asection **list = htab->input_list + isec->output_section->index; - if (*list != bfd_abs_section_ptr) - { - /* Steal the last_sec pointer for our list. - This happens to make the list in reverse order, - which is what we want. */ - htab->stub_group[isec->id].last_sec = *list; - *list = isec; - } - } -} - -/* Segment mask for CALL26 relocation relaxation. */ -#define CALL26_SEGMENT(x) ((x) & 0xf0000000) - -/* Fudge factor for approximate maximum size of all stubs that might - be inserted by the linker. This does not actually limit the number - of stubs that might be inserted, and only affects strategy for grouping - and placement of stubs. Perhaps this should be computed based on number - of relocations seen, or be specifiable on the command line. */ -#define MAX_STUB_SECTION_SIZE 0xffff - -/* See whether we can group stub sections together. Grouping stub - sections may result in fewer stubs. More importantly, we need to - put all .init* and .fini* stubs at the end of the .init or - .fini output sections respectively, because glibc splits the - _init and _fini functions into multiple parts. Putting a stub in - the middle of a function is not a good idea. - Rather than computing groups of a maximum fixed size, for Nios II - CALL26 relaxation it makes more sense to compute the groups based on - sections that fit within a 256MB address segment. Also do not allow - a group to span more than one output section, since different output - sections might correspond to different memory banks on a bare-metal - target, etc. */ -static void -group_sections (struct elf32_nios2_link_hash_table *htab) -{ - asection **list = htab->input_list + htab->top_index; - do - { - /* The list is in reverse order so we'll search backwards looking - for the first section that begins in the same memory segment, - marking sections along the way to point at the tail for this - group. */ - asection *tail = *list; - if (tail == bfd_abs_section_ptr) - continue; - while (tail != NULL) - { - bfd_vma start = tail->output_section->vma + tail->output_offset; - bfd_vma end = start + tail->size; - bfd_vma segment = CALL26_SEGMENT (end); - asection *prev; - - if (segment != CALL26_SEGMENT (start) - || segment != CALL26_SEGMENT (end + MAX_STUB_SECTION_SIZE)) - /* This section spans more than one memory segment, or is - close enough to the end of the segment that adding stub - sections before it might cause it to move so that it - spans memory segments, or that stubs added at the end of - this group might overflow into the next memory segment. - Put it in a group by itself to localize the effects. */ - { - prev = htab->stub_group[tail->id].last_sec; - htab->stub_group[tail->id].last_sec = tail; - htab->stub_group[tail->id].first_sec = tail; - } - else - /* Collect more sections for this group. */ - { - asection *curr, *first; - for (curr = tail; ; curr = prev) - { - prev = htab->stub_group[curr->id].last_sec; - if (!prev - || tail->output_section != prev->output_section - || (CALL26_SEGMENT (prev->output_section->vma - + prev->output_offset) - != segment)) - break; - } - first = curr; - for (curr = tail; ; curr = prev) - { - prev = htab->stub_group[curr->id].last_sec; - htab->stub_group[curr->id].last_sec = tail; - htab->stub_group[curr->id].first_sec = first; - if (curr == first) - break; - } - } - - /* Reset tail for the next group. */ - tail = prev; - } - } - while (list-- != htab->input_list); - free (htab->input_list); -} - -/* Determine the type of stub needed, if any, for a call. */ -static enum elf32_nios2_stub_type -nios2_type_of_stub (asection *input_sec, - const Elf_Internal_Rela *rel, - struct elf32_nios2_link_hash_entry *hh, - struct elf32_nios2_link_hash_table *htab, - bfd_vma destination, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - bfd_vma location, segment, start, end; - asection *s0, *s1, *s; - - if (hh != NULL && - !(hh->root.root.type == bfd_link_hash_defined - || hh->root.root.type == bfd_link_hash_defweak)) - return nios2_stub_none; - - /* Determine where the call point is. */ - location = (input_sec->output_section->vma - + input_sec->output_offset + rel->r_offset); - segment = CALL26_SEGMENT (location); - - /* Nios II CALL and JMPI instructions can transfer control to addresses - within the same 256MB segment as the PC. */ - if (segment == CALL26_SEGMENT (destination)) - return nios2_stub_none; - - /* Find the start and end addresses of the stub group. Also account for - any already-created stub sections for this group. Note that for stubs - in the end section, only the first instruction of the last stub - (12 bytes long) needs to be within range. */ - s0 = htab->stub_group[input_sec->id].first_sec; - s = htab->stub_group[s0->id].first_stub_sec; - if (s != NULL && s->size > 0) - start = s->output_section->vma + s->output_offset; - else - start = s0->output_section->vma + s0->output_offset; - - s1 = htab->stub_group[input_sec->id].last_sec; - s = htab->stub_group[s1->id].last_stub_sec; - if (s != NULL && s->size > 0) - end = s->output_section->vma + s->output_offset + s->size - 8; - else - end = s1->output_section->vma + s1->output_offset + s1->size; - - BFD_ASSERT (start < end); - BFD_ASSERT (start <= location); - BFD_ASSERT (location < end); - - /* Put stubs at the end of the group unless that is not a valid - location and the beginning of the group is. It might be that - neither the beginning nor end works if we have an input section - so large that it spans multiple segment boundaries. In that - case, punt; the end result will be a relocation overflow error no - matter what we do here. - - Note that adding stubs pushes up the addresses of all subsequent - sections, so that stubs allocated on one pass through the - relaxation loop may not be valid on the next pass. (E.g., we may - allocate a stub at the beginning of the section on one pass and - find that the call site has been bumped into the next memory - segment on the next pass.) The important thing to note is that - we never try to reclaim the space allocated to such unused stubs, - so code size and section addresses can only increase with each - iteration. Accounting for the start and end addresses of the - already-created stub sections ensures that when the algorithm - converges, it converges accurately, with the entire appropriate - stub section accessible from the call site and not just the - address at the start or end of the stub group proper. */ - - if (segment == CALL26_SEGMENT (end)) - return nios2_stub_call26_after; - else if (segment == CALL26_SEGMENT (start)) - return nios2_stub_call26_before; - else - /* Perhaps this should be a dedicated error code. */ - return nios2_stub_none; -} - -static bfd_boolean -nios2_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_nios2_stub_hash_entry *hsh - = (struct elf32_nios2_stub_hash_entry *) gen_entry; - asection *stub_sec = hsh->stub_sec; - bfd_vma sym_value; - - /* Make a note of the offset within the stubs for this entry. */ - hsh->stub_offset = stub_sec->size; - - switch (hsh->stub_type) - { - case nios2_stub_call26_before: - case nios2_stub_call26_after: - /* A call26 stub looks like: - orhi at, %hiadj(dest) - addi at, at, %lo(dest) - jmp at - Note that call/jmpi instructions can't be used in PIC code - so there is no reason for the stub to be PIC, either. */ - sym_value = (hsh->target_value - + hsh->target_section->output_offset - + hsh->target_section->output_section->vma - + hsh->addend); - - nios2_elf32_install_data (stub_sec, nios2_call26_stub_entry, - hsh->stub_offset, 3); - nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset, - hiadj (sym_value)); - nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset + 4, - (sym_value & 0xffff)); - stub_sec->size += 12; - break; - default: - BFD_FAIL (); - return FALSE; - } - - return TRUE; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes. */ -static bfd_boolean -nios2_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_UNUSED) -{ - struct elf32_nios2_stub_hash_entry *hsh - = (struct elf32_nios2_stub_hash_entry *) gen_entry; - - switch (hsh->stub_type) - { - case nios2_stub_call26_before: - case nios2_stub_call26_after: - hsh->stub_sec->size += 12; - break; - default: - BFD_FAIL (); - return FALSE; - } - return TRUE; -} - -/* Read in all local syms for all input bfds. - Returns -1 on error, 0 otherwise. */ - -static int -get_local_syms (bfd *output_bfd ATTRIBUTE_UNUSED, bfd *input_bfd, - struct bfd_link_info *info) -{ - unsigned int bfd_indx; - Elf_Internal_Sym *local_syms, **all_local_syms; - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - /* We want to read in symbol extension records only once. To do this - we need to read in the local symbols in parallel and save them for - later use; so hold pointers to the local symbols in an array. */ - bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count; - all_local_syms = bfd_zmalloc (amt); - htab->all_local_syms = all_local_syms; - if (all_local_syms == NULL) - return -1; - - /* Walk over all the input BFDs, swapping in local symbols. */ - for (bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* We need an array of the local symbols attached to the input bfd. */ - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - { - local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - /* Cache them for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - if (local_syms == NULL) - return -1; - - all_local_syms[bfd_indx] = local_syms; - } - - return 0; -} - -/* Determine and set the size of the stub section for a final link. */ -bfd_boolean -nios2_elf32_size_stubs (bfd *output_bfd, bfd *stub_bfd, - struct bfd_link_info *info, - asection *(*add_stub_section) (const char *, - asection *, bfd_boolean), - void (*layout_sections_again) (void)) -{ - bfd_boolean stub_changed = FALSE; - struct elf32_nios2_link_hash_table *htab = elf32_nios2_hash_table (info); - - /* Stash our params away. */ - htab->stub_bfd = stub_bfd; - htab->add_stub_section = add_stub_section; - htab->layout_sections_again = layout_sections_again; - - /* FIXME: We only compute the section groups once. This could cause - problems if adding a large stub section causes following sections, - or parts of them, to move into another segment. However, this seems - to be consistent with the way other back ends handle this.... */ - group_sections (htab); - - if (get_local_syms (output_bfd, info->input_bfds, info)) - { - if (htab->all_local_syms) - goto error_ret_free_local; - return FALSE; - } - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - asection *stub_sec; - - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - local_syms = htab->all_local_syms[bfd_indx]; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - unsigned int r_type, r_indx; - enum elf32_nios2_stub_type stub_type; - struct elf32_nios2_stub_hash_entry *hsh; - asection *sym_sec; - bfd_vma sym_value; - bfd_vma destination; - struct elf32_nios2_link_hash_entry *hh; - char *stub_name; - const asection *id_sec; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - if (r_type >= (unsigned int) R_NIOS2_ILLEGAL) - { - bfd_set_error (bfd_error_bad_value); - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - goto error_ret_free_local; - } - - /* Only look for stubs on CALL and JMPI instructions. */ - if (r_type != (unsigned int) R_NIOS2_CALL26) - continue; - - /* Now determine the call target, its name, value, - section. */ - sym_sec = NULL; - sym_value = 0; - destination = 0; - hh = NULL; - if (r_indx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - Elf_Internal_Sym *sym; - Elf_Internal_Shdr *hdr; - unsigned int shndx; - - sym = local_syms + r_indx; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - sym_value = sym->st_value; - shndx = sym->st_shndx; - if (shndx < elf_numsections (input_bfd)) - { - hdr = elf_elfsections (input_bfd)[shndx]; - sym_sec = hdr->bfd_section; - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - } - } - else - { - /* It's an external symbol. */ - int e_indx; - - e_indx = r_indx - symtab_hdr->sh_info; - hh = ((struct elf32_nios2_link_hash_entry *) - elf_sym_hashes (input_bfd)[e_indx]); - - while (hh->root.root.type == bfd_link_hash_indirect - || hh->root.root.type == bfd_link_hash_warning) - hh = ((struct elf32_nios2_link_hash_entry *) - hh->root.root.u.i.link); - - if (hh->root.root.type == bfd_link_hash_defined - || hh->root.root.type == bfd_link_hash_defweak) - { - sym_sec = hh->root.root.u.def.section; - sym_value = hh->root.root.u.def.value; - - if (sym_sec->output_section != NULL) - destination = (sym_value + irela->r_addend - + sym_sec->output_offset - + sym_sec->output_section->vma); - else - continue; - } - else if (hh->root.root.type == bfd_link_hash_undefweak) - { - if (! bfd_link_pic (info)) - continue; - } - else if (hh->root.root.type == bfd_link_hash_undefined) - { - if (! (info->unresolved_syms_in_objects == RM_IGNORE - && (ELF_ST_VISIBILITY (hh->root.other) - == STV_DEFAULT))) - continue; - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - } - - /* Determine what (if any) linker stub is needed. */ - stub_type = nios2_type_of_stub (section, irela, hh, htab, - destination, info); - if (stub_type == nios2_stub_none) - continue; - - /* Support for grouping stub sections. */ - if (stub_type == nios2_stub_call26_before) - id_sec = htab->stub_group[section->id].first_sec; - else - id_sec = htab->stub_group[section->id].last_sec; - - /* Get the name of this stub. */ - stub_name = nios2_stub_name (id_sec, sym_sec, hh, irela, - stub_type); - if (!stub_name) - goto error_ret_free_internal; - - hsh = nios2_stub_hash_lookup (&htab->bstab, - stub_name, - FALSE, FALSE); - if (hsh != NULL) - { - /* The proper stub has already been created. */ - free (stub_name); - continue; - } - - hsh = nios2_add_stub (stub_name, section, htab, stub_type); - if (hsh == NULL) - { - free (stub_name); - goto error_ret_free_internal; - } - hsh->target_value = sym_value; - hsh->target_section = sym_sec; - hsh->stub_type = stub_type; - hsh->hh = hh; - hsh->addend = irela->r_addend; - stub_changed = TRUE; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - } - } - - if (!stub_changed) - break; - - /* OK, we've added some stubs. Find out the new size of the - stub sections. */ - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - stub_sec->size = 0; - - bfd_hash_traverse (&htab->bstab, nios2_size_one_stub, htab); - - /* Ask the linker to do its stuff. */ - (*htab->layout_sections_again) (); - stub_changed = FALSE; - } - - free (htab->all_local_syms); - return TRUE; - - error_ret_free_local: - free (htab->all_local_syms); - return FALSE; -} - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. This function is called via nios2elf_finish in the linker. */ -bfd_boolean -nios2_elf32_build_stubs (struct bfd_link_info *info) -{ - asection *stub_sec; - struct bfd_hash_table *table; - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - - for (stub_sec = htab->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - /* The stub_bfd may contain non-stub sections if it is also the - dynobj. Any such non-stub sections are created with the - SEC_LINKER_CREATED flag set, while stub sections do not - have that flag. Ignore any non-stub sections here. */ - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - { - bfd_size_type size; - - /* Allocate memory to hold the linker stubs. */ - size = stub_sec->size; - stub_sec->contents = bfd_zalloc (htab->stub_bfd, size); - if (stub_sec->contents == NULL && size != 0) - return FALSE; - stub_sec->size = 0; - } - - /* Build the stubs as directed by the stub hash table. */ - table = &htab->bstab; - bfd_hash_traverse (table, nios2_build_one_stub, info); - - return TRUE; -} - - -#define is_nios2_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_object_id (bfd) == NIOS2_ELF_DATA) - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -nios2_elf32_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - - if (!is_nios2_elf (ibfd) || !is_nios2_elf (obfd)) - return TRUE; - - /* Check if we have the same endianness. */ - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - - switch (new_flags) - { - default: - case EF_NIOS2_ARCH_R1: - bfd_default_set_arch_mach (obfd, bfd_arch_nios2, bfd_mach_nios2r1); - break; - case EF_NIOS2_ARCH_R2: - if (bfd_big_endian (ibfd)) - { - _bfd_error_handler - (_("error: %B: Big-endian R2 is not supported."), ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - bfd_default_set_arch_mach (obfd, bfd_arch_nios2, bfd_mach_nios2r2); - break; - } - } - - /* Incompatible flags. */ - else if (new_flags != old_flags) - { - /* So far, the only incompatible flags denote incompatible - architectures. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B: Conflicting CPU architectures %d/%d"), - ibfd, new_flags, old_flags); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - _bfd_elf_merge_object_attributes (ibfd, info); - - return TRUE; -} - - -/* Implement bfd_elf32_bfd_reloc_type_lookup: - Given a BFD reloc type, return a howto structure. */ -static reloc_howto_type * -nios2_elf32_bfd_reloc_type_lookup (bfd *abfd, - bfd_reloc_code_real_type code) -{ - int i; - - for (i = 0; - i < (int) (sizeof (nios2_reloc_map) / sizeof (struct elf_reloc_map)); - ++i) - if (nios2_reloc_map[i].bfd_val == code) - return lookup_howto (nios2_reloc_map[i].elf_val, abfd); - return NULL; -} - -/* Implement bfd_elf32_bfd_reloc_name_lookup: - Given a reloc name, return a howto structure. */ -static reloc_howto_type * -nios2_elf32_bfd_reloc_name_lookup (bfd *abfd, - const char *r_name) -{ - int i; - reloc_howto_type *howto_tbl; - int howto_tbl_size; - - if (BFD_IS_R2 (abfd)) - { - howto_tbl = elf_nios2_r2_howto_table_rel; - howto_tbl_size = (int) (sizeof (elf_nios2_r2_howto_table_rel) - / sizeof (elf_nios2_r2_howto_table_rel[0])); - } - else - { - howto_tbl = elf_nios2_r1_howto_table_rel; - howto_tbl_size = (int) (sizeof (elf_nios2_r1_howto_table_rel) - / sizeof (elf_nios2_r1_howto_table_rel[0])); - } - - for (i = 0; i < howto_tbl_size; i++) - if (howto_tbl[i].name && strcasecmp (howto_tbl[i].name, r_name) == 0) - return howto_tbl + i; - return NULL; -} - -/* Implement elf_info_to_howto: - Given a ELF32 relocation, fill in a arelent structure. */ -static void -nios2_elf32_info_to_howto (bfd *abfd, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - cache_ptr->howto = lookup_howto (r_type, abfd); -} - -/* 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 address - htab->tls_sec->vma; -} - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ -static bfd_boolean -nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info) -{ - - bfd_boolean gp_found; - struct bfd_hash_entry *h; - struct bfd_link_hash_entry *lh; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - h = bfd_hash_lookup (&info->hash->table, "_gp", FALSE, FALSE); - lh = (struct bfd_link_hash_entry *) h; -lookup: - if (lh) - { - switch (lh->type) - { - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - case bfd_link_hash_common: - gp_found = FALSE; - break; - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - gp_found = TRUE; - { - asection *sym_sec = lh->u.def.section; - bfd_vma sym_value = lh->u.def.value; - - if (sym_sec->output_section) - sym_value = (sym_value + sym_sec->output_offset - + sym_sec->output_section->vma); - *pgp = sym_value; - } - break; - case bfd_link_hash_indirect: - case bfd_link_hash_warning: - lh = lh->u.i.link; - /* @@FIXME ignoring warning for now */ - goto lookup; - case bfd_link_hash_new: - default: - abort (); - } - } - else - gp_found = FALSE; - - if (!gp_found) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - _bfd_set_gp_value (output_bfd, *pgp); - - return TRUE; -} - -/* Retrieve the previously cached _gp pointer, returning bfd_reloc_dangerous - if it's not available as we don't have a link_info pointer available here - to look it up in the output symbol table. We don't need to adjust the - symbol value for an external symbol if we are producing relocatable - output. */ -static bfd_reloc_status_type -nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, - char **error_message, bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) && !relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 && (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma + 0x4000; - _bfd_set_gp_value (output_bfd, *pgp); - } - else - { - *error_message - = (char *) _("global pointer relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -/* Do the relocations that require special handling. */ -static bfd_reloc_status_type -nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - symbol_value = symbol_value + addend; - addend = 0; - symbol_value = (symbol_value >> 16) & 0xffff; - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_lo16_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - symbol_value = symbol_value + addend; - addend = 0; - symbol_value = symbol_value & 0xffff; - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - symbol_value = symbol_value + addend; - addend = 0; - symbol_value = hiadj(symbol_value); - return _bfd_final_link_relocate (howto, abfd, input_section, data, offset, - symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_pcrel_lo16_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - symbol_value = symbol_value + addend; - addend = 0; - symbol_value = symbol_value & 0xffff; - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_pcrel_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - symbol_value = symbol_value + addend; - symbol_value -= (input_section->output_section->vma - + input_section->output_offset); - symbol_value -= offset; - addend = 0; - symbol_value = hiadj(symbol_value); - return _bfd_final_link_relocate (howto, abfd, input_section, data, offset, - symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_pcrel16_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - /* NIOS2 pc relative relocations are relative to the next 32-bit instruction - so we need to subtract 4 before doing a final_link_relocate. */ - symbol_value = symbol_value + addend - 4; - addend = 0; - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - /* Check that the relocation is in the same page as the current address. */ - if (CALL26_SEGMENT (symbol_value + addend) - != CALL26_SEGMENT (input_section->output_section->vma - + input_section->output_offset - + offset)) - return bfd_reloc_overflow; - - /* Check that the target address is correctly aligned on a 4-byte - boundary. */ - if ((symbol_value + addend) & 0x3) - return bfd_reloc_overflow; - - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_gprel_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - /* Because we need the output_bfd, the special handling is done - in nios2_elf32_relocate_section or in nios2_elf32_gprel_relocate. */ - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -static bfd_reloc_status_type -nios2_elf32_do_ujmp_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - bfd_vma symbol_lo16, symbol_hi16; - bfd_reloc_status_type r; - symbol_value = symbol_value + addend; - addend = 0; - symbol_hi16 = (symbol_value >> 16) & 0xffff; - symbol_lo16 = symbol_value & 0xffff; - - r = _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_hi16, addend); - - if (r == bfd_reloc_ok) - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset + 4, symbol_lo16, addend); - - return r; -} - -static bfd_reloc_status_type -nios2_elf32_do_cjmp_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - bfd_vma symbol_lo16, symbol_hi16; - bfd_reloc_status_type r; - symbol_value = symbol_value + addend; - addend = 0; - symbol_hi16 = (symbol_value >> 16) & 0xffff; - symbol_lo16 = symbol_value & 0xffff; - - r = _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_hi16, addend); - - if (r == bfd_reloc_ok) - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset + 4, symbol_lo16, addend); - - return r; -} - -static bfd_reloc_status_type -nios2_elf32_do_callr_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - bfd_vma symbol_lo16, symbol_hi16; - bfd_reloc_status_type r; - symbol_value = symbol_value + addend; - addend = 0; - symbol_hi16 = (symbol_value >> 16) & 0xffff; - symbol_lo16 = symbol_value & 0xffff; - - r = _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_hi16, addend); - - if (r == bfd_reloc_ok) - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset + 4, symbol_lo16, addend); - - return r; -} - -/* HOWTO handlers for relocations that require special handling. */ - -/* This is for relocations used only when relaxing to ensure - changes in size of section don't screw up .align. */ -static bfd_reloc_status_type -nios2_elf32_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -nios2_elf32_hi16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_hi16_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_lo16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_lo16_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_hiadj16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_hiadj16_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_pcrel_lo16_relocate (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, - asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_pcrel_lo16_relocate ( - abfd, reloc_entry->howto, input_section, data, reloc_entry->address, - (symbol->value + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_pcrel_hiadj16_relocate (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, - asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_pcrel_hiadj16_relocate ( - abfd, reloc_entry->howto, input_section, data, reloc_entry->address, - (symbol->value + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_pcrel16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_pcrel16_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_call26_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_call26_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_gprel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **msg) -{ - bfd_vma relocation; - bfd_vma gp; - bfd_reloc_status_type r; - - - /* This part is from bfd_elf_generic_reloc. */ - 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; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - relocation = (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset); - - /* This assumes we've already cached the _gp symbol. */ - r = nios2_elf_final_gp (abfd, symbol, FALSE, msg, &gp); - if (r == bfd_reloc_ok) - { - relocation = relocation + reloc_entry->addend - gp; - reloc_entry->addend = 0; - if ((signed) relocation < -32768 || (signed) relocation > 32767) - { - *msg = _("global pointer relative address out of range"); - r = bfd_reloc_outofrange; - } - else - r = nios2_elf32_do_gprel_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - relocation, reloc_entry->addend); - } - - return r; -} - -static bfd_reloc_status_type -nios2_elf32_ujmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - 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; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_ujmp_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_cjmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - 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; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_cjmp_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -nios2_elf32_callr_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) -{ - /* This part is from bfd_elf_generic_reloc. */ - 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; - } - - if (output_bfd != NULL) - /* FIXME: See bfd_perform_relocation. Is this right? */ - return bfd_reloc_continue; - - return nios2_elf32_do_callr_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - - -/* Implement elf_backend_relocate_section. */ -static bfd_boolean -nios2_elf32_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - struct elf32_nios2_link_hash_table *htab; - asection *sgot; - asection *splt; - asection *sreloc = NULL; - bfd_vma *local_got_offsets; - bfd_vma got_base; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - htab = elf32_nios2_hash_table (info); - sgot = htab->root.sgot; - splt = htab->root.splt; - local_got_offsets = elf_local_got_offsets (input_bfd); - - if (htab->h_gp_got == NULL) - got_base = 0; - else - got_base = htab->h_gp_got->root.u.def.value; - - for (rel = relocs; rel < relend; rel++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - struct elf32_nios2_link_hash_entry *eh; - bfd_vma relocation; - bfd_vma gp; - bfd_reloc_status_type r = bfd_reloc_ok; - const char *name = NULL; - int r_type; - const char *format; - char msgbuf[256]; - const char* msg = (const char*) NULL; - bfd_boolean unresolved_reloc; - bfd_vma off; - int use_plt; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info), output_bfd); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - /* Nothing more to do unless this is a final link. */ - if (bfd_link_relocatable (info)) - continue; - - if (howto) - { - bfd_boolean resolved_to_zero; - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - switch (howto->type) - { - case R_NIOS2_HI16: - r = nios2_elf32_do_hi16_relocate (input_bfd, howto, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - case R_NIOS2_LO16: - r = nios2_elf32_do_lo16_relocate (input_bfd, howto, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - case R_NIOS2_PCREL_LO: - r = nios2_elf32_do_pcrel_lo16_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - case R_NIOS2_HIADJ16: - r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_PCREL_HA: - r = nios2_elf32_do_pcrel_hiadj16_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - case R_NIOS2_PCREL16: - r = nios2_elf32_do_pcrel16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_GPREL: - /* Turns an absolute address into a gp-relative address. */ - if (!nios2_elf_assign_gp (output_bfd, &gp, info)) - { - bfd_vma reloc_address; - - if (sec && sec->output_section) - reloc_address = (sec->output_section->vma - + sec->output_offset - + rel->r_offset); - else - reloc_address = 0; - - format = _("global pointer relative relocation at address " - "0x%08x when _gp not defined\n"); - sprintf (msgbuf, format, reloc_address); - msg = msgbuf; - r = bfd_reloc_dangerous; - } - else - { - bfd_vma symbol_address = rel->r_addend + relocation; - relocation = symbol_address - gp; - rel->r_addend = 0; - if (((signed) relocation < -32768 - || (signed) relocation > 32767) - && (!h - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - { - if (h) - name = h->root.root.string; - /* xgettext:c-format */ - format = _("Unable to reach %s (at 0x%08x) from the " - "global pointer (at 0x%08x) because the " - "offset (%d) is out of the allowed range, " - "-32678 to 32767.\n" ); - sprintf (msgbuf, format, name, symbol_address, gp, - (signed)relocation); - msg = msgbuf; - r = bfd_reloc_outofrange; - } - else - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - } - break; - case R_NIOS2_UJMP: - r = nios2_elf32_do_ujmp_relocate (input_bfd, howto, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - case R_NIOS2_CJMP: - r = nios2_elf32_do_cjmp_relocate (input_bfd, howto, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - case R_NIOS2_CALLR: - r = nios2_elf32_do_callr_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_CALL26: - case R_NIOS2_CALL26_NOAT: - /* If we have a call to an undefined weak symbol, we just want - to stuff a zero in the bits of the call instruction and - bypass the normal call26 relocation handling, because it'll - diagnose an overflow error if address 0 isn't in the same - 256MB segment as the call site. Presumably the call - should be guarded by a null check anyway. */ - if (h != NULL && h->root.type == bfd_link_hash_undefweak) - { - BFD_ASSERT (relocation == 0 && rel->r_addend == 0); - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - } - /* Handle relocations which should use the PLT entry. - NIOS2_BFD_RELOC_32 relocations will use the symbol's value, - which may point to a PLT entry, but we don't need to handle - that here. If we created a PLT entry, all branches in this - object should go to it. */ - if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1) - { - /* If we've created a .plt section, and assigned a PLT entry - to this function, it should not be known to bind locally. - If it were, we would have cleared the PLT entry. */ - BFD_ASSERT (!SYMBOL_CALLS_LOCAL (info, h)); - - relocation = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - - unresolved_reloc = FALSE; - } - /* Detect R_NIOS2_CALL26 relocations that would overflow the - 256MB segment. Replace the target with a reference to a - trampoline instead. - Note that htab->stub_group is null if relaxation has been - disabled by the --no-relax linker command-line option, so - we can use that to skip this processing entirely. */ - if (howto->type == R_NIOS2_CALL26 && htab->stub_group) - { - bfd_vma dest = relocation + rel->r_addend; - enum elf32_nios2_stub_type stub_type; - - eh = (struct elf32_nios2_link_hash_entry *)h; - stub_type = nios2_type_of_stub (input_section, rel, eh, - htab, dest, NULL); - - if (stub_type != nios2_stub_none) - { - struct elf32_nios2_stub_hash_entry *hsh; - - hsh = nios2_get_stub_entry (input_section, sec, - eh, rel, htab, stub_type); - if (hsh == NULL) - { - r = bfd_reloc_undefined; - break; - } - - dest = (hsh->stub_offset - + hsh->stub_sec->output_offset - + hsh->stub_sec->output_section->vma); - r = nios2_elf32_do_call26_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - dest, 0); - break; - } - } - - /* Normal case. */ - r = nios2_elf32_do_call26_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_ALIGN: - r = bfd_reloc_ok; - /* For symmetry this would be - r = nios2_elf32_do_ignore_reloc (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - but do_ignore_reloc would do no more than return - bfd_reloc_ok. */ - break; - - case R_NIOS2_GOT16: - case R_NIOS2_CALL16: - case R_NIOS2_GOT_LO: - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL_LO: - case R_NIOS2_CALL_HA: - /* Relocation is to the entry for this symbol in the - global offset table. */ - if (sgot == NULL) - { - r = bfd_reloc_notsupported; - break; - } - - use_plt = 0; - - if (h != NULL) - { - bfd_boolean dyn; - - eh = (struct elf32_nios2_link_hash_entry *)h; - use_plt = (eh->got_types_used == CALL_USED - && h->plt.offset != (bfd_vma) -1); - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - dyn = htab->root.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - || ((ELF_ST_VISIBILITY (h->other) - || resolved_to_zero) - && 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. We must - initialize this entry in the global offset table. - Since the offset must always be a multiple of 4, we - use the least significant bit to record whether we - have initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This is - done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - h->got.offset |= 1; - } - } - else - unresolved_reloc = FALSE; - } - else - { - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use the - least significant bit to record whether we have already - generated the necessary reloc. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - bfd_byte *loc; - - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_addend = relocation; - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE); - loc = srelgot->contents; - loc += (srelgot->reloc_count++ * - sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - - local_got_offsets[r_symndx] |= 1; - } - } - - if (use_plt && bfd_link_pic (info)) - { - off = ((h->plt.offset - 24) / 12 + 3) * 4; - relocation = (htab->root.sgotplt->output_offset + off - - got_base); - } - else - relocation = sgot->output_offset + off - got_base; - - /* This relocation does not use the addend. */ - rel->r_addend = 0; - - switch (howto->type) - { - case R_NIOS2_GOT_LO: - case R_NIOS2_CALL_LO: - r = nios2_elf32_do_lo16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL_HA: - r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - default: - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - } - break; - - case R_NIOS2_GOTOFF_LO: - case R_NIOS2_GOTOFF_HA: - case R_NIOS2_GOTOFF: - /* Relocation is relative to the global offset table pointer. */ - - BFD_ASSERT (sgot != NULL); - if (sgot == NULL) - { - r = bfd_reloc_notsupported; - break; - } - - /* Note that sgot->output_offset is not involved in this - calculation. We always want the start of .got. */ - relocation -= sgot->output_section->vma; - - /* Now we adjust the relocation to be relative to the GOT pointer - (the _gp_got symbol), which possibly contains the 0x8000 bias. */ - relocation -= got_base; - - switch (howto->type) - { - case R_NIOS2_GOTOFF_LO: - r = nios2_elf32_do_lo16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - case R_NIOS2_GOTOFF_HA: - r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto, - input_section, contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - default: - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - } - break; - - case R_NIOS2_TLS_LDO16: - relocation -= dtpoff_base (info) + DTP_OFFSET; - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - case R_NIOS2_TLS_LDM16: - if (htab->root.sgot == NULL) - abort (); - - off = htab->tls_ldm_got.offset; - - if ((off & 1) != 0) - off &= ~1; - else - { - /* If we don't know the module number, create a relocation - for it. */ - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - if (htab->root.srelgot == NULL) - abort (); - - outrel.r_addend = 0; - outrel.r_offset = (htab->root.sgot->output_section->vma - + htab->root.sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_NIOS2_TLS_DTPMOD); - - loc = htab->root.srelgot->contents; - loc += (htab->root.srelgot->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - bfd_put_32 (output_bfd, 1, - htab->root.sgot->contents + off); - - htab->tls_ldm_got.offset |= 1; - } - - relocation = htab->root.sgot->output_offset + off - got_base; - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - break; - case R_NIOS2_TLS_GD16: - case R_NIOS2_TLS_IE16: - { - int indx; - char tls_type; - - if (htab->root.sgot == NULL) - abort (); - - indx = 0; - if (h != NULL) - { - bfd_boolean dyn; - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - { - unresolved_reloc = FALSE; - indx = h->dynindx; - } - off = h->got.offset; - tls_type = (((struct elf32_nios2_link_hash_entry *) h) - ->tls_type); - } - else - { - if (local_got_offsets == NULL) - abort (); - off = local_got_offsets[r_symndx]; - tls_type = (elf32_nios2_local_got_tls_type (input_bfd) - [r_symndx]); - } - - if (tls_type == GOT_UNKNOWN) - abort (); - - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_boolean need_relocs = FALSE; - Elf_Internal_Rela outrel; - bfd_byte *loc = NULL; - int cur_off = off; - - /* The GOT entries have not been initialized yet. Do it - now, and emit any relocations. If both an IE GOT and a - GD GOT are necessary, we emit the GD first. */ - - if ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak)) - { - need_relocs = TRUE; - if (htab->root.srelgot == NULL) - abort (); - loc = htab->root.srelgot->contents; - loc += (htab->root.srelgot->reloc_count * - sizeof (Elf32_External_Rela)); - } - - if (tls_type & GOT_TLS_GD) - { - if (need_relocs) - { - outrel.r_addend = 0; - outrel.r_offset = (htab->root.sgot->output_section->vma - + htab->root.sgot->output_offset - + cur_off); - outrel.r_info = ELF32_R_INFO (indx, - R_NIOS2_TLS_DTPMOD); - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - loc); - htab->root.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - - if (indx == 0) - bfd_put_32 (output_bfd, - (relocation - dtpoff_base (info) - - DTP_OFFSET), - htab->root.sgot->contents + cur_off + 4); - else - { - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (indx, - R_NIOS2_TLS_DTPREL); - outrel.r_offset += 4; - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - loc); - htab->root.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - } - } - else - { - /* If we are not emitting relocations for a - general dynamic reference, then we must be in a - static link or an executable link with the - symbol binding locally. Mark it as belonging - to module 1, the executable. */ - bfd_put_32 (output_bfd, 1, - htab->root.sgot->contents + cur_off); - bfd_put_32 (output_bfd, (relocation - - dtpoff_base (info) - - DTP_OFFSET), - htab->root.sgot->contents + cur_off + 4); - } - - cur_off += 8; - } - - if (tls_type & GOT_TLS_IE) - { - if (need_relocs) - { - if (indx == 0) - outrel.r_addend = (relocation - - dtpoff_base (info)); - else - outrel.r_addend = 0; - outrel.r_offset = (htab->root.sgot->output_section->vma - + htab->root.sgot->output_offset - + cur_off); - outrel.r_info = ELF32_R_INFO (indx, - R_NIOS2_TLS_TPREL); - - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - loc); - htab->root.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - } - else - bfd_put_32 (output_bfd, (tpoff (info, relocation) - - TP_OFFSET), - htab->root.sgot->contents + cur_off); - cur_off += 4; - } - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - if ((tls_type & GOT_TLS_GD) && r_type != R_NIOS2_TLS_GD16) - off += 8; - relocation = htab->root.sgot->output_offset + off - got_base; - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - - break; - case R_NIOS2_TLS_LE16: - if (bfd_link_dll (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation not " - "permitted in shared object"), - input_bfd, input_section, - rel->r_offset, howto->name); - return FALSE; - } - else - relocation = tpoff (info, relocation) - TP_OFFSET; - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - - case R_NIOS2_BFD_RELOC_32: - if (bfd_link_pic (info) - && (input_section->flags & SEC_ALLOC) != 0 - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak)) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip, relocate; - - /* 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 - && (!bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !h->def_regular)) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* This symbol is local, or marked to become local. */ - outrel.r_addend = relocation + rel->r_addend; - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE); - } - - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - /* This reloc will be computed at runtime, so there's no - need to do anything now, except for R_NIOS2_BFD_RELOC_32 - relocations that have been turned into - R_NIOS2_RELATIVE. */ - if (!relocate) - break; - } - - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - - case R_NIOS2_TLS_DTPREL: - relocation -= dtpoff_base (info); - /* Fall through. */ - - default: - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - } - } - else - r = bfd_reloc_notsupported; - - if (r != bfd_reloc_ok) - { - if (h != NULL) - name = h->root.root.string; - else - { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) (info, NULL, name, - howto->name, (bfd_vma) 0, - input_bfd, input_section, - rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) (info, name, input_bfd, - input_section, - rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - if (msg == NULL) - msg = _("relocation out of range"); - break; - - case bfd_reloc_notsupported: - if (msg == NULL) - msg = _("unsupported relocation"); - break; - - case bfd_reloc_dangerous: - if (msg == NULL) - msg = _("dangerous relocation"); - break; - - default: - if (msg == NULL) - msg = _("unknown error"); - break; - } - - if (msg) - { - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - return FALSE; - } - } - } - return TRUE; -} - -/* Implement elf-backend_section_flags: - Convert NIOS2 specific section flags to bfd internal section flags. */ -static bfd_boolean -nios2_elf32_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr) -{ - if (hdr->sh_flags & SHF_NIOS2_GPREL) - *flags |= SEC_SMALL_DATA; - - return TRUE; -} - -/* Implement elf_backend_fake_sections: - Set the correct type for an NIOS2 ELF section. We do this by the - section name, which is a hack, but ought to work. */ -static bfd_boolean -nios2_elf32_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, asection *sec) -{ - register const char *name = bfd_get_section_name (abfd, sec); - - if ((sec->flags & SEC_SMALL_DATA) - || strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0 - || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0) - hdr->sh_flags |= SHF_NIOS2_GPREL; - - return TRUE; -} - -/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up - shortcuts to them in our hash table. */ -static bfd_boolean -create_got_section (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf32_nios2_link_hash_table *htab; - struct elf_link_hash_entry *h; - - htab = elf32_nios2_hash_table (info); - - if (! _bfd_elf_create_got_section (dynobj, info)) - return FALSE; - - /* In order for the two loads in .PLTresolve to share the same %hiadj, - _GLOBAL_OFFSET_TABLE_ must be aligned to a 16-byte boundary. */ - if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt, 4)) - return FALSE; - - /* The Nios II ABI specifies that GOT-relative relocations are relative - to the linker-created symbol _gp_got, rather than using - _GLOBAL_OFFSET_TABLE_ directly. In particular, the latter always - points to the base of the GOT while _gp_got may include a bias. */ - h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.sgotplt, - "_gp_got"); - htab->h_gp_got = h; - if (h == NULL) - return FALSE; - - return TRUE; -} - -/* Implement elf_backend_create_dynamic_sections: - 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 -nios2_elf32_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - if (!htab->root.sgot && !create_got_section (dynobj, info)) - return FALSE; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - /* In order for the two loads in a shared object .PLTresolve to share the - same %hiadj, the start of the PLT (as well as the GOT) must be aligned - to a 16-byte boundary. This is because the addresses for these loads - include the -(.plt+4) PIC correction. */ - return bfd_set_section_alignment (dynobj, htab->root.splt, 4); -} - -/* Implement elf_backend_copy_indirect_symbol: - Copy the extra info we tack onto an elf_link_hash_entry. */ -static void -nios2_elf32_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf32_nios2_link_hash_entry *edir, *eind; - - edir = (struct elf32_nios2_link_hash_entry *) dir; - eind = (struct elf32_nios2_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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; - } - - edir->got_types_used |= eind->got_types_used; - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Set the right machine number for a NIOS2 ELF file. */ - -static bfd_boolean -nios2_elf32_object_p (bfd *abfd) -{ - unsigned long mach; - - mach = elf_elfheader (abfd)->e_flags; - - switch (mach) - { - default: - case EF_NIOS2_ARCH_R1: - bfd_default_set_arch_mach (abfd, bfd_arch_nios2, bfd_mach_nios2r1); - break; - case EF_NIOS2_ARCH_R2: - bfd_default_set_arch_mach (abfd, bfd_arch_nios2, bfd_mach_nios2r2); - break; - } - - return TRUE; -} - -/* Implement elf_backend_check_relocs: - Look through the relocs for a section during the first phase. */ -static bfd_boolean -nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - struct elf32_nios2_link_hash_table *htab; - asection *sreloc = NULL; - bfd_signed_vma *local_got_refcounts; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - sym_hashes_end = (sym_hashes - + symtab_hdr->sh_size / sizeof (Elf32_External_Sym)); - if (!elf_bad_symtab (abfd)) - sym_hashes_end -= symtab_hdr->sh_info; - local_got_refcounts = elf_local_got_refcounts (abfd); - - htab = elf32_nios2_hash_table (info); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - r_type = ELF32_R_TYPE (rel->r_info); - - switch (r_type) - { - case R_NIOS2_GOT16: - case R_NIOS2_GOT_LO: - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL16: - case R_NIOS2_CALL_LO: - case R_NIOS2_CALL_HA: - case R_NIOS2_TLS_GD16: - case R_NIOS2_TLS_IE16: - /* This symbol requires a global offset table entry. */ - { - int tls_type, old_tls_type; - - switch (r_type) - { - default: - case R_NIOS2_GOT16: - case R_NIOS2_GOT_LO: - case R_NIOS2_GOT_HA: - case R_NIOS2_CALL16: - case R_NIOS2_CALL_LO: - case R_NIOS2_CALL_HA: - tls_type = GOT_NORMAL; - break; - case R_NIOS2_TLS_GD16: - tls_type = GOT_TLS_GD; - break; - case R_NIOS2_TLS_IE16: - tls_type = GOT_TLS_IE; - break; - } - - if (h != NULL) - { - struct elf32_nios2_link_hash_entry *eh - = (struct elf32_nios2_link_hash_entry *)h; - h->got.refcount++; - old_tls_type = elf32_nios2_hash_entry(h)->tls_type; - if (r_type == R_NIOS2_CALL16 - || r_type == R_NIOS2_CALL_LO - || r_type == R_NIOS2_CALL_HA) - { - /* Make sure a plt entry is created for this symbol if - it turns out to be a function defined by a dynamic - object. */ - h->plt.refcount++; - h->needs_plt = 1; - h->type = STT_FUNC; - eh->got_types_used |= CALL_USED; - } - else - eh->got_types_used |= GOT_USED; - } - else - { - /* This is a global offset table entry for a local symbol. */ - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= (sizeof (bfd_signed_vma) + sizeof (char)); - local_got_refcounts - = ((bfd_signed_vma *) bfd_zalloc (abfd, size)); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - elf32_nios2_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx]++; - old_tls_type = elf32_nios2_local_got_tls_type (abfd) [r_symndx]; - } - - /* We will already have issued an error message if there is a - TLS / non-TLS mismatch, based on the symbol type. We don't - support any linker relaxations. So just combine any TLS - types needed. */ - if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL - && tls_type != GOT_NORMAL) - tls_type |= old_tls_type; - - if (old_tls_type != tls_type) - { - if (h != NULL) - elf32_nios2_hash_entry (h)->tls_type = tls_type; - else - elf32_nios2_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - } - make_got: - if (htab->root.sgot == NULL) - { - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - if (!create_got_section (htab->root.dynobj, info)) - return FALSE; - } - break; - - case R_NIOS2_TLS_LDM16: - htab->tls_ldm_got.refcount++; - goto make_got; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_NIOS2_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_NIOS2_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_NIOS2_BFD_RELOC_32: - case R_NIOS2_CALL26: - case R_NIOS2_CALL26_NOAT: - case R_NIOS2_HIADJ16: - case R_NIOS2_LO16: - - if (h != NULL) - { - /* 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. */ - if (!bfd_link_pic (info)) - h->non_got_ref = 1; - - /* Make sure a plt entry is created for this symbol if it - turns out to be a function defined by a dynamic object. */ - h->plt.refcount++; - - if (r_type == R_NIOS2_CALL26 || r_type == R_NIOS2_CALL26_NOAT) - h->needs_plt = 1; - } - - /* If we are creating a shared library, we need to copy the - reloc into the shared library. */ - if (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (r_type == R_NIOS2_BFD_RELOC_32 - || (h != NULL && ! h->needs_plt - && (! SYMBOLIC_BIND (info, h) || ! h->def_regular)))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->root.dynobj, 2, abfd, TRUE); - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf32_nios2_link_hash_entry *) h)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = ((struct elf_dyn_relocs *) - bfd_alloc (htab->root.dynobj, amt)); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - - } - break; - } - } - - return TRUE; -} - - -/* Implement elf_backend_gc_mark_hook: - Return the section that should be marked against GC for a given - relocation. */ -static asection * -nios2_elf32_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_NIOS2_GNU_VTINHERIT: - case R_NIOS2_GNU_VTENTRY: - return NULL; - } - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Implement elf_backend_finish_dynamic_symbols: - Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ -static bfd_boolean -nios2_elf32_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf32_nios2_link_hash_table *htab; - struct elf32_nios2_link_hash_entry *eh - = (struct elf32_nios2_link_hash_entry *)h; - int use_plt; - - htab = elf32_nios2_hash_table (info); - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgotplt; - asection *srela; - bfd_vma plt_index; - bfd_vma got_offset; - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_vma got_address; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - BFD_ASSERT (h->dynindx != -1); - splt = htab->root.splt; - sgotplt = htab->root.sgotplt; - srela = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgotplt != NULL && srela != NULL); - - /* Emit the PLT entry. */ - if (bfd_link_pic (info)) - { - nios2_elf32_install_data (splt, nios2_so_plt_entry, h->plt.offset, - 3); - plt_index = (h->plt.offset - 24) / 12; - got_offset = (plt_index + 3) * 4; - nios2_elf32_install_imm16 (splt, h->plt.offset, - hiadj(plt_index * 4)); - nios2_elf32_install_imm16 (splt, h->plt.offset + 4, - (plt_index * 4) & 0xffff); - nios2_elf32_install_imm16 (splt, h->plt.offset + 8, - 0xfff4 - h->plt.offset); - got_address = (sgotplt->output_section->vma + sgotplt->output_offset - + got_offset); - - /* Fill in the entry in the global offset table. There are no - res_n slots for a shared object PLT, instead the .got.plt entries - point to the PLT entries. */ - bfd_put_32 (output_bfd, - splt->output_section->vma + splt->output_offset - + h->plt.offset, sgotplt->contents + got_offset); - } - else - { - plt_index = (h->plt.offset - 28 - htab->res_n_size) / 12; - got_offset = (plt_index + 3) * 4; - - nios2_elf32_install_data (splt, nios2_plt_entry, h->plt.offset, 3); - got_address = (sgotplt->output_section->vma + sgotplt->output_offset - + got_offset); - nios2_elf32_install_imm16 (splt, h->plt.offset, hiadj(got_address)); - nios2_elf32_install_imm16 (splt, h->plt.offset + 4, - got_address & 0xffff); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - splt->output_section->vma + splt->output_offset - + plt_index * 4, sgotplt->contents + got_offset); - } - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = got_address; - rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_JUMP_SLOT); - rela.r_addend = 0; - loc = srela->contents + plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - /* If the symbol is weak, we do need to clear the value. - Otherwise, the PLT entry would provide a definition for - the symbol even if the symbol wasn't defined anywhere, - and so the symbol would never be NULL. */ - if (!h->ref_regular_nonweak) - sym->st_value = 0; - } - } - - use_plt = (eh->got_types_used == CALL_USED - && h->plt.offset != (bfd_vma) -1); - - if (!use_plt && h->got.offset != (bfd_vma) -1 - && (elf32_nios2_hash_entry (h)->tls_type & GOT_TLS_GD) == 0 - && (elf32_nios2_hash_entry (h)->tls_type & GOT_TLS_IE) == 0) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_vma offset; - - /* This symbol has an entry in the global offset table. Set it - up. */ - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - offset = (h->got.offset & ~(bfd_vma) 1); - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset + offset); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - - if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h)) - { - rela.r_info = ELF32_R_INFO (0, R_NIOS2_RELATIVE); - rela.r_addend = bfd_get_signed_32 (output_bfd, - (sgot->contents + offset)); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset); - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, - sgot->contents + offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_GLOB_DAT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - if (use_plt && h->got.offset != (bfd_vma) -1) - { - bfd_vma offset = (h->got.offset & ~(bfd_vma) 1); - asection *sgot = htab->root.sgot; - asection *splt = htab->root.splt; - bfd_put_32 (output_bfd, (splt->output_section->vma + splt->output_offset - + h->plt.offset), - sgot->contents + offset); - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_NIOS2_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->root.sdynrelro) - s = htab->root.sreldynrelro; - else - s = htab->root.srelbss; - BFD_ASSERT (s != NULL); - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark _DYNAMIC, _GLOBAL_OFFSET_TABLE_, and _gp_got as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || h == htab->root.hgot - || h == htab->h_gp_got) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Implement elf_backend_finish_dynamic_sections. */ -static bfd_boolean -nios2_elf32_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *sgotplt; - asection *sdyn; - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - sgotplt = htab->root.sgotplt; - sdyn = NULL; - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = htab->root.splt; - sdyn = bfd_get_linker_section (htab->root.dynobj, ".dynamic"); - BFD_ASSERT (splt != NULL && sdyn != NULL && sgotplt != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (htab->root.dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = htab->root.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - s = htab->root.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_NIOS2_GP: - s = htab->root.sgotplt; - dyn.d_un.d_ptr - = s->output_section->vma + s->output_offset + 0x7ff0; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - if (splt->size > 0) - { - bfd_vma got_address = (sgotplt->output_section->vma - + sgotplt->output_offset); - if (bfd_link_pic (info)) - { - bfd_vma got_pcrel = got_address - (splt->output_section->vma - + splt->output_offset); - /* Both GOT and PLT must be aligned to a 16-byte boundary - for the two loads to share the %hiadj part. The 4-byte - offset for nextpc is accounted for in the %lo offsets - on the loads. */ - BFD_ASSERT ((got_pcrel & 0xf) == 0); - nios2_elf32_install_data (splt, nios2_so_plt0_entry, 0, 6); - nios2_elf32_install_imm16 (splt, 4, hiadj (got_pcrel)); - nios2_elf32_install_imm16 (splt, 12, got_pcrel & 0xffff); - nios2_elf32_install_imm16 (splt, 16, (got_pcrel + 4) & 0xffff); - } - else - { - /* Divide by 4 here, not 3 because we already corrected for the - res_N branches. */ - bfd_vma res_size = (splt->size - 28) / 4; - bfd_vma res_start = (splt->output_section->vma - + splt->output_offset); - bfd_vma res_offset; - - for (res_offset = 0; res_offset < res_size; res_offset += 4) - bfd_put_32 (output_bfd, - 6 | ((res_size - (res_offset + 4)) << 6), - splt->contents + res_offset); - - /* The GOT must be aligned to a 16-byte boundary for the - two loads to share the same %hiadj part. */ - BFD_ASSERT ((got_address & 0xf) == 0); - - nios2_elf32_install_data (splt, nios2_plt0_entry, res_size, 7); - nios2_elf32_install_imm16 (splt, res_size, hiadj (res_start)); - nios2_elf32_install_imm16 (splt, res_size + 4, - res_start & 0xffff); - nios2_elf32_install_imm16 (splt, res_size + 12, - hiadj (got_address)); - nios2_elf32_install_imm16 (splt, res_size + 16, - (got_address + 4) & 0xffff); - nios2_elf32_install_imm16 (splt, res_size + 20, - (got_address + 8) & 0xffff); - } - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgotplt != NULL && sgotplt->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgotplt->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8); - - if (sgotplt->output_section != bfd_abs_section_ptr) - elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4; - } - - return TRUE; -} - -/* Implement elf_backend_adjust_dynamic_symbol: - 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 -nios2_elf32_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf32_nios2_link_hash_table *htab; - bfd *dynobj; - asection *s, *srel; - unsigned align2; - - htab = elf32_nios2_hash_table (info); - dynobj = htab->root.dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC || h->needs_plt) - { - if (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 PLT 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 PCREL reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - return TRUE; - } - - /* Reinitialize the plt offset now that it is not used as a reference - count any more. */ - 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* If there are no non-GOT references, we do not need a copy - relocation. */ - if (!h->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 (bfd_link_pic (info)) - 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_NIOS2_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = htab->root.sdynrelro; - srel = htab->root.sreldynrelro; - } - else - { - s = htab->root.sdynbss; - srel = htab->root.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) - { - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - align2 = bfd_log2 (h->size); - if (align2 > h->root.u.def.section->alignment_power) - align2 = h->root.u.def.section->alignment_power; - - /* Align dynbss. */ - s->size = BFD_ALIGN (s->size, (bfd_size_type)1 << align2); - if (align2 > bfd_get_section_alignment (dynobj, s) - && !bfd_set_section_alignment (dynobj, s, align2)) - 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; -} - -/* Worker function for nios2_elf32_size_dynamic_sections. */ -static bfd_boolean -adjust_dynrelocs (struct elf_link_hash_entry *h, PTR inf) -{ - struct bfd_link_info *info; - struct elf32_nios2_link_hash_table *htab; - - 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 = elf32_nios2_hash_table (info); - - if (h->plt.offset != (bfd_vma)-1) - h->plt.offset += htab->res_n_size; - if (htab->root.splt == h->root.u.def.section) - h->root.u.def.value += htab->res_n_size; - - return TRUE; -} - -/* Another worker function for nios2_elf32_size_dynamic_sections. - Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) -{ - struct bfd_link_info *info; - struct elf32_nios2_link_hash_table *htab; - struct elf32_nios2_link_hash_entry *eh; - struct elf_dyn_relocs *p; - int use_plt; - - 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 = elf32_nios2_hash_table (info); - - if (htab->root.dynamic_sections_created - && h->plt.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->root.splt; - - /* Allocate room for the header. */ - if (s->size == 0) - { - if (bfd_link_pic (info)) - s->size = 24; - else - s->size = 28; - } - - 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 (! bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; - } - - /* Make room for this entry. */ - s->size += 12; - - /* We also need to make an entry in the .rela.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); - - /* And the .got.plt section. */ - htab->root.sgotplt->size += 4; - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - eh = (struct elf32_nios2_link_hash_entry *) h; - use_plt = (eh->got_types_used == CALL_USED - && h->plt.offset != (bfd_vma) -1); - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = eh->tls_type; - int indx; - - /* 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 - && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - s = htab->root.sgot; - h->got.offset = s->size; - - if (tls_type == GOT_UNKNOWN) - abort (); - - if (tls_type == GOT_NORMAL) - /* Non-TLS symbols need one GOT slot. */ - s->size += 4; - else - { - if (tls_type & GOT_TLS_GD) - /* R_NIOS2_TLS_GD16 needs 2 consecutive GOT slots. */ - s->size += 8; - if (tls_type & GOT_TLS_IE) - /* R_NIOS2_TLS_IE16 needs one GOT slot. */ - s->size += 4; - } - - dyn = htab->root.dynamic_sections_created; - - indx = 0; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - indx = h->dynindx; - - if (tls_type != GOT_NORMAL - && (bfd_link_pic (info) || indx != 0) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - { - if (tls_type & GOT_TLS_IE) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - - if (tls_type & GOT_TLS_GD) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - - if ((tls_type & GOT_TLS_GD) && indx != 0) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak) - && !use_plt - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (h->def_regular - && (h->forced_local || SYMBOLIC_BIND (info, h))) - { - struct elf_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 - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && !h->forced_local - && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Implement elf_backend_size_dynamic_sections: - Set the sizes of the dynamic sections. */ -static bfd_boolean -nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - htab->res_n_size = 0; - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = htab->root.srelgot; - if (s != NULL) - s->size = 0; - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - char *local_tls_type; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next) - { - if (!bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - local_tls_type = elf32_nios2_local_got_tls_type (ibfd); - s = htab->root.sgot; - srel = htab->root.srelgot; - for (; local_got < end_local_got; ++local_got, ++local_tls_type) - { - if (*local_got > 0) - { - *local_got = s->size; - if (*local_tls_type & GOT_TLS_GD) - /* TLS_GD relocs need an 8-byte structure in the GOT. */ - s->size += 8; - if (*local_tls_type & GOT_TLS_IE) - s->size += 4; - if (*local_tls_type == GOT_NORMAL) - s->size += 4; - - if (bfd_link_pic (info) || *local_tls_type == GOT_TLS_GD) - srel->size += sizeof (Elf32_External_Rela); - } - else - *local_got = (bfd_vma) -1; - } - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate two GOT entries and one dynamic relocation (if necessary) - for R_NIOS2_TLS_LDM16 relocations. */ - htab->tls_ldm_got.offset = htab->root.sgot->size; - htab->root.sgot->size += 8; - if (bfd_link_pic (info)) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - 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->root, allocate_dynrelocs, info); - - if (htab->root.dynamic_sections_created) - { - /* If the .got section is more than 0x8000 bytes, we add - 0x8000 to the value of _gp_got, so that 16-bit relocations - have a greater chance of working. */ - if (htab->root.sgot->size >= 0x8000 - && htab->h_gp_got->root.u.def.value == 0) - htab->h_gp_got->root.u.def.value = 0x8000; - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - if (s != htab->root.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - } - else if (s == htab->root.splt) - { - /* Correct for the number of res_N branches. */ - if (s->size != 0 && !bfd_link_pic (info)) - { - htab->res_n_size = (s->size - 28) / 3; - s->size += htab->res_n_size; - } - } - else if (s != htab->sbss - && s != htab->root.sgot - && s != htab->root.sgotplt - && s != htab->root.sdynbss - && s != htab->root.sdynrelro) - /* It's not one of our sections, so don't allocate space. */ - continue; - - if (s->size == 0) - { - s->flags |= SEC_EXCLUDE; - continue; - } - - if ((s->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - /* Adjust dynamic symbols that point to the plt to account for the - now-known number of resN slots. */ - if (htab->res_n_size) - elf_link_hash_traverse (& htab->root, adjust_dynrelocs, info); - - if (htab->root.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf_nios2_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 (!bfd_link_pic (info) && !add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - - if (htab->root.sgotplt->size != 0 - && !add_dynamic_entry (DT_PLTGOT, 0)) - return FALSE; - - if (htab->root.splt->size != 0 - && (!add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0))) - return FALSE; - - if (relocs - && (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))) - return FALSE; - - if (!bfd_link_pic (info) && !add_dynamic_entry (DT_NIOS2_GP, 0)) - return FALSE; - - if ((info->flags & DF_TEXTREL) != 0 - && !add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Free the derived linker hash table. */ -static void -nios2_elf32_link_hash_table_free (bfd *obfd) -{ - struct elf32_nios2_link_hash_table *htab - = (struct elf32_nios2_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (&htab->bstab); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Implement bfd_elf32_bfd_link_hash_table_create. */ -static struct bfd_link_hash_table * -nios2_elf32_link_hash_table_create (bfd *abfd) -{ - struct elf32_nios2_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf32_nios2_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - link_hash_newfunc, - sizeof (struct - elf32_nios2_link_hash_entry), - NIOS2_ELF_DATA)) - { - free (ret); - return NULL; - } - - /* Init the stub hash table too. */ - if (!bfd_hash_table_init (&ret->bstab, stub_hash_newfunc, - sizeof (struct elf32_nios2_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - ret->root.root.hash_table_free = nios2_elf32_link_hash_table_free; - - return &ret->root.root; -} - -/* Implement elf_backend_reloc_type_class. */ -static enum elf_reloc_type_class -nios2_elf32_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_NIOS2_RELATIVE: - return reloc_class_relative; - case R_NIOS2_JUMP_SLOT: - return reloc_class_plt; - case R_NIOS2_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Return 1 if target is one of ours. */ -static bfd_boolean -is_nios2_elf_target (const struct bfd_target *targ) -{ - return (targ == &nios2_elf32_le_vec - || targ == &nios2_elf32_be_vec); -} - -/* Implement elf_backend_add_symbol_hook. - This hook is called by the linker when adding symbols from an object - file. We use it to put .comm items in .sbss, and not .bss. */ -static bfd_boolean -nios2_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && sym->st_size <= elf_gp_size (abfd) - && is_nios2_elf_target (info->output_bfd->xvec)) - { - /* Common symbols less than or equal to -G nn bytes are automatically - put into .sbss. */ - struct elf32_nios2_link_hash_table *htab; - - htab = elf32_nios2_hash_table (info); - if (htab->sbss == NULL) - { - flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; - - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - - htab->sbss = bfd_make_section_anyway_with_flags (htab->root.dynobj, - ".sbss", flags); - if (htab->sbss == NULL) - return FALSE; - } - - *secp = htab->sbss; - *valp = sym->st_size; - } - - return TRUE; -} - -/* Implement elf_backend_can_make_relative_eh_frame: - Decide whether to attempt to turn absptr or lsda encodings in - shared libraries into pcrel within the given input section. */ -static bfd_boolean -nios2_elf32_can_make_relative_eh_frame (bfd *input_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info - ATTRIBUTE_UNUSED, - asection *eh_frame_section - ATTRIBUTE_UNUSED) -{ - /* We can't use PC-relative encodings in the .eh_frame section. */ - return FALSE; -} - -/* Implement elf_backend_special_sections. */ -const struct bfd_elf_special_section elf32_nios2_special_sections[] = -{ - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, - SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, - SHF_ALLOC + SHF_WRITE + SHF_NIOS2_GPREL }, - { NULL, 0, 0, 0, 0 } -}; - -#define ELF_ARCH bfd_arch_nios2 -#define ELF_TARGET_ID NIOS2_ELF_DATA -#define ELF_MACHINE_CODE EM_ALTERA_NIOS2 - -/* The Nios II MMU uses a 4K page size. */ - -#define ELF_MAXPAGESIZE 0x1000 - -#define bfd_elf32_bfd_link_hash_table_create \ - nios2_elf32_link_hash_table_create - -#define bfd_elf32_bfd_merge_private_bfd_data \ - nios2_elf32_merge_private_bfd_data - -/* Relocation table lookup macros. */ - -#define bfd_elf32_bfd_reloc_type_lookup nios2_elf32_bfd_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup nios2_elf32_bfd_reloc_name_lookup - -/* JUMP_TABLE_LINK macros. */ - -/* elf_info_to_howto (using RELA relocations). */ - -#define elf_info_to_howto nios2_elf32_info_to_howto - -/* elf backend functions. */ - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_relocate_section nios2_elf32_relocate_section -#define elf_backend_section_flags nios2_elf32_section_flags -#define elf_backend_fake_sections nios2_elf32_fake_sections -#define elf_backend_check_relocs nios2_elf32_check_relocs - -#define elf_backend_gc_mark_hook nios2_elf32_gc_mark_hook -#define elf_backend_create_dynamic_sections \ - nios2_elf32_create_dynamic_sections -#define elf_backend_finish_dynamic_symbol nios2_elf32_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - nios2_elf32_finish_dynamic_sections -#define elf_backend_adjust_dynamic_symbol nios2_elf32_adjust_dynamic_symbol -#define elf_backend_reloc_type_class nios2_elf32_reloc_type_class -#define elf_backend_size_dynamic_sections nios2_elf32_size_dynamic_sections -#define elf_backend_add_symbol_hook nios2_elf_add_symbol_hook -#define elf_backend_copy_indirect_symbol nios2_elf32_copy_indirect_symbol -#define elf_backend_object_p nios2_elf32_object_p - -#define elf_backend_grok_prstatus nios2_grok_prstatus -#define elf_backend_grok_psinfo nios2_grok_psinfo - -#undef elf_backend_can_make_relative_eh_frame -#define elf_backend_can_make_relative_eh_frame \ - nios2_elf32_can_make_relative_eh_frame - -#define elf_backend_special_sections elf32_nios2_special_sections - -#define TARGET_LITTLE_SYM nios2_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlenios2" -#define TARGET_BIG_SYM nios2_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bignios2" - -#define elf_backend_got_header_size 12 -#define elf_backend_default_execstack 0 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-nios2.h b/sdcc/support/sdbinutils/bfd/elf32-nios2.h deleted file mode 100644 index 5a6327e58..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-nios2.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Nios II support for 32-bit ELF - Copyright (C) 2013-2018 Free Software Foundation, Inc. - Contributed by Mentor Graphics - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_NIOS2_H -#define _ELF32_NIOS2_H - -extern int nios2_elf32_setup_section_lists - (bfd *, struct bfd_link_info *); - -extern void nios2_elf32_next_input_section - (struct bfd_link_info *, asection *); - -extern bfd_boolean nios2_elf32_size_stubs - (bfd *, bfd *, struct bfd_link_info *, - asection * (*) (const char *, asection *, bfd_boolean), void (*) (void)); - -extern bfd_boolean nios2_elf32_build_stubs - (struct bfd_link_info *); - -#endif /* _ELF32_NIOS2_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-or1k.c b/sdcc/support/sdbinutils/bfd/elf32-or1k.c deleted file mode 100644 index c3a2a8fe0..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-or1k.c +++ /dev/null @@ -1,2694 +0,0 @@ -/* Or1k-specific support for 32-bit ELF. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - Contributed for OR32 by Johan Rydberg, jrydberg@opencores.org - - PIC parts added by Stefan Kristiansson, stefan.kristiansson@saunalahti.fi, - largely based on elf32-m32r.c and elf32-microblaze.c. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/or1k.h" -#include "libiberty.h" - -#define PLT_ENTRY_SIZE 20 - -#define PLT0_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(.got+4) */ -#define PLT0_ENTRY_WORD1 0xa98c0000 /* l.ori r12, r12, 0 <- lo(.got+4) */ -#define PLT0_ENTRY_WORD2 0x85ec0004 /* l.lwz r15, 4(r12) <- *(.got+8)*/ -#define PLT0_ENTRY_WORD3 0x44007800 /* l.jr r15 */ -#define PLT0_ENTRY_WORD4 0x858c0000 /* l.lwz r12, 0(r12) */ - -#define PLT0_PIC_ENTRY_WORD0 0x85900004 /* l.lwz r12, 4(r16) */ -#define PLT0_PIC_ENTRY_WORD1 0x85f00008 /* l.lwz r15, 8(r16) */ -#define PLT0_PIC_ENTRY_WORD2 0x44007800 /* l.jr r15 */ -#define PLT0_PIC_ENTRY_WORD3 0x15000000 /* l.nop */ -#define PLT0_PIC_ENTRY_WORD4 0x15000000 /* l.nop */ - -#define PLT_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(got idx addr) */ -#define PLT_ENTRY_WORD1 0xa98c0000 /* l.ori r12, r12, 0 <- lo(got idx addr) */ -#define PLT_ENTRY_WORD2 0x858c0000 /* l.lwz r12, 0(r12) */ -#define PLT_ENTRY_WORD3 0x44006000 /* l.jr r12 */ -#define PLT_ENTRY_WORD4 0xa9600000 /* l.ori r11, r0, 0 <- reloc offset */ - -#define PLT_PIC_ENTRY_WORD0 0x85900000 /* l.lwz r12, 0(r16) <- index in got */ -#define PLT_PIC_ENTRY_WORD1 0xa9600000 /* l.ori r11, r0, 0 <- reloc offset */ -#define PLT_PIC_ENTRY_WORD2 0x44006000 /* l.jr r12 */ -#define PLT_PIC_ENTRY_WORD3 0x15000000 /* l.nop */ -#define PLT_PIC_ENTRY_WORD4 0x15000000 /* l.nop */ - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -static reloc_howto_type or1k_elf_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_OR1K_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_8, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_LO_16_IN_INSN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_LO_16_IN_INSN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_HI_16_IN_INSN, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_HI_16_IN_INSN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A PC relative 26 bit relocation, right shifted by 2. */ - HOWTO (R_OR1K_INSN_REL_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_INSN_REL_26", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_OR1K_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_OR1K_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_OR1K_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_elf_rel_vtable_reloc_fn, /* special_function */ - "R_OR1K_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_32_PCREL, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_32_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_OR1K_16_PCREL, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_OR1K_8_PCREL, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_8_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_OR1K_GOTPC_HI16, /* Type. */ - 16, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc, /* Special Function. */ - "R_OR1K_GOTPC_HI16", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0xffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - HOWTO (R_OR1K_GOTPC_LO16, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc, /* Special Function. */ - "R_OR1K_GOTPC_LO16", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0xffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - HOWTO (R_OR1K_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 26 bit PLT relocation. Shifted by 2. */ - HOWTO (R_OR1K_PLT26, /* Type. */ - 2, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 26, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain on overflow. */ - bfd_elf_generic_reloc,/* Special Function. */ - "R_OR1K_PLT26", /* Name. */ - FALSE, /* Partial Inplace. */ - 0, /* Source Mask. */ - 0x03ffffff, /* Dest Mask. */ - TRUE), /* PC relative offset? */ - - HOWTO (R_OR1K_GOTOFF_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_GOTOFF_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_GOTOFF_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_GOTOFF_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_COPY", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_GD_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_GD_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_GD_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_GD_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_LDM_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_LDM_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_LDM_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_LDM_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_LDO_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_LDO_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_LDO_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_LDO_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_IE_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_IE_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_IE_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_IE_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_LE_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_LE_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_OR1K_TLS_LE_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_OR1K_TLS_LE_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Map BFD reloc types to Or1k ELF reloc types. */ - -struct or1k_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int or1k_reloc_val; -}; - -static const struct or1k_reloc_map or1k_reloc_map[] = -{ - { BFD_RELOC_NONE, R_OR1K_NONE }, - { BFD_RELOC_32, R_OR1K_32 }, - { BFD_RELOC_16, R_OR1K_16 }, - { BFD_RELOC_8, R_OR1K_8 }, - { BFD_RELOC_LO16, R_OR1K_LO_16_IN_INSN }, - { BFD_RELOC_HI16, R_OR1K_HI_16_IN_INSN }, - { BFD_RELOC_OR1K_REL_26, R_OR1K_INSN_REL_26 }, - { BFD_RELOC_VTABLE_ENTRY, R_OR1K_GNU_VTENTRY }, - { BFD_RELOC_VTABLE_INHERIT, R_OR1K_GNU_VTINHERIT }, - { BFD_RELOC_32_PCREL, R_OR1K_32_PCREL }, - { BFD_RELOC_16_PCREL, R_OR1K_16_PCREL }, - { BFD_RELOC_8_PCREL, R_OR1K_8_PCREL }, - { BFD_RELOC_OR1K_GOTPC_HI16, R_OR1K_GOTPC_HI16 }, - { BFD_RELOC_OR1K_GOTPC_LO16, R_OR1K_GOTPC_LO16 }, - { BFD_RELOC_OR1K_GOT16, R_OR1K_GOT16 }, - { BFD_RELOC_OR1K_PLT26, R_OR1K_PLT26 }, - { BFD_RELOC_OR1K_GOTOFF_HI16, R_OR1K_GOTOFF_HI16 }, - { BFD_RELOC_OR1K_GOTOFF_LO16, R_OR1K_GOTOFF_LO16 }, - { BFD_RELOC_OR1K_GLOB_DAT, R_OR1K_GLOB_DAT }, - { BFD_RELOC_OR1K_COPY, R_OR1K_COPY }, - { BFD_RELOC_OR1K_JMP_SLOT, R_OR1K_JMP_SLOT }, - { BFD_RELOC_OR1K_RELATIVE, R_OR1K_RELATIVE }, - { BFD_RELOC_OR1K_TLS_GD_HI16, R_OR1K_TLS_GD_HI16 }, - { BFD_RELOC_OR1K_TLS_GD_LO16, R_OR1K_TLS_GD_LO16 }, - { BFD_RELOC_OR1K_TLS_LDM_HI16, R_OR1K_TLS_LDM_HI16 }, - { BFD_RELOC_OR1K_TLS_LDM_LO16, R_OR1K_TLS_LDM_LO16 }, - { BFD_RELOC_OR1K_TLS_LDO_HI16, R_OR1K_TLS_LDO_HI16 }, - { BFD_RELOC_OR1K_TLS_LDO_LO16, R_OR1K_TLS_LDO_LO16 }, - { BFD_RELOC_OR1K_TLS_IE_HI16, R_OR1K_TLS_IE_HI16 }, - { BFD_RELOC_OR1K_TLS_IE_LO16, R_OR1K_TLS_IE_LO16 }, - { BFD_RELOC_OR1K_TLS_LE_HI16, R_OR1K_TLS_LE_HI16 }, - { BFD_RELOC_OR1K_TLS_LE_LO16, R_OR1K_TLS_LE_LO16 }, -}; - -#define TLS_UNKNOWN 0 -#define TLS_NONE 1 -#define TLS_GD 2 -#define TLS_LD 3 -#define TLS_IE 4 -#define TLS_LE 5 - -/* ELF linker hash entry. */ -struct elf_or1k_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* Track type of TLS access. */ - unsigned char tls_type; -}; - -/* ELF object data. */ -struct elf_or1k_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - unsigned char *local_tls_type; -}; - -#define elf_or1k_tdata(abfd) \ - ((struct elf_or1k_obj_tdata *) (abfd)->tdata.any) - -#define elf_or1k_local_tls_type(abfd) \ - (elf_or1k_tdata (abfd)->local_tls_type) - -/* ELF linker hash table. */ -struct elf_or1k_link_hash_table -{ - struct elf_link_hash_table root; - - /* Small local sym to section mapping cache. */ - struct sym_cache sym_sec; -}; - -/* Get the ELF linker hash table from a link_info structure. */ -#define or1k_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == OR1K_ELF_DATA ? ((struct elf_or1k_link_hash_table *) ((p)->hash)) : NULL) - -static bfd_boolean -elf_or1k_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_or1k_obj_tdata), - OR1K_ELF_DATA); -} - -/* Create an entry in an or1k ELF linker hash table. */ - -static struct bfd_hash_entry * -or1k_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_or1k_link_hash_entry *ret = - (struct elf_or1k_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, - sizeof (struct elf_or1k_link_hash_entry)); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_or1k_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != NULL) - { - struct elf_or1k_link_hash_entry *eh; - - eh = (struct elf_or1k_link_hash_entry *) ret; - eh->dyn_relocs = NULL; - eh->tls_type = TLS_UNKNOWN; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an or1k ELF linker hash table. */ - -static struct bfd_link_hash_table * -or1k_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_or1k_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_or1k_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - or1k_elf_link_hash_newfunc, - sizeof (struct elf_or1k_link_hash_entry), - OR1K_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -static reloc_howto_type * -or1k_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (or1k_reloc_map); i--;) - if (or1k_reloc_map[i].bfd_reloc_val == code) - return & or1k_elf_howto_table[or1k_reloc_map[i].or1k_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -or1k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (or1k_elf_howto_table) - / sizeof (or1k_elf_howto_table[0])); - i++) - if (or1k_elf_howto_table[i].name != NULL - && strcasecmp (or1k_elf_howto_table[i].name, r_name) == 0) - return &or1k_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an Or1k ELF reloc. */ - -static void -or1k_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_OR1K_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid OR1K reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = & or1k_elf_howto_table[r_type]; -} - - -/* Return the relocation value for @tpoff relocations.. */ -static bfd_vma -tpoff (struct bfd_link_info *info, bfd_vma address) -{ - /* If tls_sec is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_sec == NULL) - return 0; - - /* The thread pointer on or1k stores the address after the TCB where - the data is, just compute the difference. No need to compensate - for the size of TCB. */ - return (address - elf_hash_table (info)->tls_sec->vma); -} - -/* Relocate an Or1k ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -or1k_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - struct elf_or1k_link_hash_table *htab = or1k_elf_hash_table (info); - bfd *dynobj; - asection *sreloc; - bfd_vma *local_got_offsets; - asection *sgot; - - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - local_got_offsets = elf_local_got_offsets (input_bfd); - - sreloc = elf_section_data (input_section)->sreloc; - - sgot = htab->root.sgot; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_type == R_OR1K_GNU_VTINHERIT - || r_type == R_OR1K_GNU_VTENTRY) - continue; - - if (r_type < 0 || r_type >= (int) R_OR1K_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - howto = or1k_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (howto->type) - { - case R_OR1K_PLT26: - { - if (htab->root.splt != NULL && h != NULL - && h->plt.offset != (bfd_vma) -1) - { - relocation = (htab->root.splt->output_section->vma - + htab->root.splt->output_offset - + h->plt.offset); - } - break; - } - - case R_OR1K_GOT16: - /* Relocation is to the entry for this symbol in the global - offset table. */ - BFD_ASSERT (sgot != NULL); - if (h != NULL) - { - bfd_boolean dyn; - bfd_vma off; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - dyn = htab->root.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h))) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - /* Write entry in GOT. */ - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); - /* Mark GOT entry as having been written. */ - h->got.offset |= 1; - } - } - - relocation = sgot->output_offset + off; - } - else - { - bfd_vma off; - bfd_byte *loc; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - /* Get offset into GOT table. */ - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - /* Write entry in GOT. */ - bfd_put_32 (output_bfd, relocation, sgot->contents + off); - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - - /* We need to generate a R_OR1K_RELATIVE reloc - for the dynamic linker. */ - srelgot = htab->root.srelgot; - BFD_ASSERT (srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc); - ++srelgot->reloc_count; - } - - local_got_offsets[r_symndx] |= 1; - } - relocation = sgot->output_offset + off; - } - - /* Addend should be zero. */ - if (rel->r_addend != 0) - _bfd_error_handler - (_("internal error: addend should be zero for R_OR1K_GOT16")); - - break; - - case R_OR1K_GOTOFF_LO16: - case R_OR1K_GOTOFF_HI16: - /* Relocation is offset from GOT. */ - BFD_ASSERT (sgot != NULL); - relocation - -= (htab->root.hgot->root.u.def.value - + htab->root.hgot->root.u.def.section->output_offset - + htab->root.hgot->root.u.def.section->output_section->vma); - break; - - case R_OR1K_INSN_REL_26: - case R_OR1K_HI_16_IN_INSN: - case R_OR1K_LO_16_IN_INSN: - case R_OR1K_32: - /* R_OR1K_16? */ - { - /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ - if (r_symndx == STN_UNDEF - || (input_section->flags & SEC_ALLOC) == 0) - break; - - if ((bfd_link_pic (info) - && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak) - && (howto->type != R_OR1K_INSN_REL_26 - || !SYMBOL_CALLS_LOCAL (info, h))) - || (!bfd_link_pic (info) - && h != NULL - && h->dynindx != -1 - && !h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - BFD_ASSERT (sreloc != NULL); - - skip = FALSE; - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - /* h->dynindx may be -1 if the symbol was marked to - become local. */ - else if (h != NULL - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - if (r_type == R_OR1K_32) - { - outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - BFD_FAIL (); - _bfd_error_handler - (_("%B: probably compiled without -fPIC?"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - break; - } - break; - } - - case R_OR1K_TLS_LDM_HI16: - case R_OR1K_TLS_LDM_LO16: - case R_OR1K_TLS_LDO_HI16: - case R_OR1K_TLS_LDO_LO16: - /* TODO: implement support for local dynamic. */ - BFD_FAIL (); - _bfd_error_handler - (_("%B: support for local dynamic not implemented"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - - case R_OR1K_TLS_GD_HI16: - case R_OR1K_TLS_GD_LO16: - case R_OR1K_TLS_IE_HI16: - case R_OR1K_TLS_IE_LO16: - { - bfd_vma gotoff; - Elf_Internal_Rela rela; - bfd_byte *loc; - int dynamic; - - sreloc = bfd_get_section_by_name (dynobj, ".rela.got"); - - /* Mark as TLS related GOT entry by setting - bit 2 as well as bit 1. */ - if (h != NULL) - { - gotoff = h->got.offset; - h->got.offset |= 3; - } - else - { - gotoff = local_got_offsets[r_symndx]; - local_got_offsets[r_symndx] |= 3; - } - - /* Only process the relocation once. */ - if (gotoff & 1) - { - relocation = sgot->output_offset + (gotoff & ~3); - break; - } - - BFD_ASSERT (elf_hash_table (info)->hgot == NULL - || elf_hash_table (info)->hgot->root.u.def.value == 0); - - /* Dynamic entries will require relocations. if we do not need - them we will just use the default R_OR1K_NONE and - not set anything. */ - dynamic = bfd_link_pic (info) - || (sec && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak || !h->def_regular)); - - /* Shared GD. */ - if (dynamic && (howto->type == R_OR1K_TLS_GD_HI16 - || howto->type == R_OR1K_TLS_GD_LO16)) - { - int i; - - /* Add DTPMOD and DTPOFF GOT and rela entries. */ - for (i = 0; i < 2; ++i) - { - rela.r_offset = sgot->output_section->vma + - sgot->output_offset + gotoff + i*4; - if (h != NULL && h->dynindx != -1) - { - rela.r_info = ELF32_R_INFO (h->dynindx, - (i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF)); - rela.r_addend = 0; - } - else - { - rela.r_info = ELF32_R_INFO (0, - (i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF)); - rela.r_addend = tpoff (info, relocation); - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * - sizeof (Elf32_External_Rela); - - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - bfd_put_32 (output_bfd, 0, sgot->contents + gotoff + i*4); - } - } - /* Static GD. */ - else if (howto->type == R_OR1K_TLS_GD_HI16 - || howto->type == R_OR1K_TLS_GD_LO16) - { - bfd_put_32 (output_bfd, 1, sgot->contents + gotoff); - bfd_put_32 (output_bfd, tpoff (info, relocation), - sgot->contents + gotoff + 4); - } - /* Shared IE. */ - else if (dynamic) - { - /* Add TPOFF GOT and rela entries. */ - rela.r_offset = sgot->output_section->vma + - sgot->output_offset + gotoff; - if (h != NULL && h->dynindx != -1) - { - rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_TLS_TPOFF); - rela.r_addend = 0; - } - else - { - rela.r_info = ELF32_R_INFO (0, R_OR1K_TLS_TPOFF); - rela.r_addend = tpoff (info, relocation); - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - bfd_put_32 (output_bfd, 0, sgot->contents + gotoff); - } - /* Static IE. */ - else - { - bfd_put_32 (output_bfd, tpoff (info, relocation), - sgot->contents + gotoff); - } - relocation = sgot->output_offset + gotoff; - break; - } - case R_OR1K_TLS_LE_HI16: - case R_OR1K_TLS_LE_LO16: - - /* Relocation is offset from TP. */ - relocation = tpoff (info, relocation); - break; - - case R_OR1K_TLS_DTPMOD: - case R_OR1K_TLS_DTPOFF: - case R_OR1K_TLS_TPOFF: - /* These are resolved dynamically on load and shouldn't - be used as linker input. */ - BFD_FAIL (); - _bfd_error_handler - (_("%B: will not resolve runtime TLS relocation"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - default: - break; - } - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, relocation, rel->r_addend); - - if (r != bfd_reloc_ok) - { - const char *msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -or1k_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_OR1K_GNU_VTINHERIT: - case R_OR1K_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. */ - -static bfd_boolean -or1k_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - - const Elf_Internal_Rela *rel_end; - struct elf_or1k_link_hash_table *htab; - bfd *dynobj; - asection *sreloc = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - htab = or1k_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - unsigned char tls_type; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_OR1K_TLS_GD_HI16: - case R_OR1K_TLS_GD_LO16: - tls_type = TLS_GD; - break; - case R_OR1K_TLS_LDM_HI16: - case R_OR1K_TLS_LDM_LO16: - case R_OR1K_TLS_LDO_HI16: - case R_OR1K_TLS_LDO_LO16: - tls_type = TLS_LD; - break; - case R_OR1K_TLS_IE_HI16: - case R_OR1K_TLS_IE_LO16: - tls_type = TLS_IE; - break; - case R_OR1K_TLS_LE_HI16: - case R_OR1K_TLS_LE_LO16: - tls_type = TLS_LE; - break; - default: - tls_type = TLS_NONE; - } - - /* Record TLS type. */ - if (h != NULL) - ((struct elf_or1k_link_hash_entry *) h)->tls_type = tls_type; - else - { - unsigned char *local_tls_type; - - /* This is a TLS type record for a local symbol. */ - local_tls_type = (unsigned char *) elf_or1k_local_tls_type (abfd); - if (local_tls_type == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - local_tls_type = bfd_zalloc (abfd, size); - if (local_tls_type == NULL) - return FALSE; - elf_or1k_local_tls_type (abfd) = local_tls_type; - } - local_tls_type[r_symndx] = tls_type; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_OR1K_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_OR1K_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - /* This relocation requires .plt entry. */ - case R_OR1K_PLT26: - if (h != NULL) - { - h->needs_plt = 1; - h->plt.refcount += 1; - } - break; - - case R_OR1K_GOT16: - case R_OR1K_GOTOFF_HI16: - case R_OR1K_GOTOFF_LO16: - case R_OR1K_TLS_GD_HI16: - case R_OR1K_TLS_GD_LO16: - case R_OR1K_TLS_IE_HI16: - case R_OR1K_TLS_IE_LO16: - if (htab->root.sgot == NULL) - { - if (dynobj == NULL) - htab->root.dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - } - - if (ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_HI16 && - ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_LO16) - { - if (h != NULL) - h->got.refcount += 1; - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - local_got_refcounts[r_symndx] += 1; - } - } - break; - - case R_OR1K_INSN_REL_26: - case R_OR1K_HI_16_IN_INSN: - case R_OR1K_LO_16_IN_INSN: - case R_OR1K_32: - /* R_OR1K_16? */ - { - if (h != NULL && !bfd_link_pic (info)) - { - /* We may need a copy reloc. */ - h->non_got_ref = 1; - - /* We may also need a .plt entry. */ - h->plt.refcount += 1; - if (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26) - h->pointer_equality_needed = 1; - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). In case of a weak definition, - DEF_REGULAR may be cleared later by a strong definition in - a shared library. We account for that possibility below by - storing information in the relocs_copied field of the hash - table entry. A similar situation occurs when creating - shared libraries and symbol visibility changes render the - symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26 - || (h != NULL - && (!SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (!bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - /* When creating a shared object, we must copy these - relocs into the output file. We create a reloc - section in dynobj and make room for the reloc. */ - if (sreloc == NULL) - { - const char *name; - unsigned int strndx = elf_elfheader (abfd)->e_shstrndx; - unsigned int shnam = _bfd_elf_single_rel_hdr (sec)->sh_name; - - name = bfd_elf_string_from_elf_section (abfd, strndx, shnam); - if (name == NULL) - return FALSE; - - if (strncmp (name, ".rela", 5) != 0 - || strcmp (bfd_get_section_name (abfd, sec), - name + 5) != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: bad relocation section name `%s\'"), - abfd, name); - } - - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - dynobj = htab->root.dynobj; - - sreloc = bfd_get_section_by_name (dynobj, name); - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - elf_section_data (sec)->sreloc = sreloc; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf_or1k_link_hash_entry *) h)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - - asection *s; - Elf_Internal_Sym *isym; - void *vpp; - - isym = bfd_sym_from_r_symndx (&htab->sym_sec, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - return FALSE; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = ((struct elf_dyn_relocs *) - bfd_alloc (htab->root.dynobj, amt)); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - if (ELF32_R_TYPE (rel->r_info) == R_OR1K_INSN_REL_26) - p->pc_count += 1; - } - } - break; - } - } - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -or1k_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn, *sgot; - struct elf_or1k_link_hash_table *htab; - - htab = or1k_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - - sgot = htab->root.sgotplt; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sgot != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - continue; - - case DT_PLTGOT: - s = htab->root.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_JMPREL: - s = htab->root.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt; - dyn.d_un.d_val = s->size; - break; - } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; - if (splt && splt->size > 0) - { - if (bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD0, - splt->contents); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD1, - splt->contents + 4); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD2, - splt->contents + 8); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD3, - splt->contents + 12); - bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD4, - splt->contents + 16); - } - else - { - unsigned long addr; - /* addr = .got + 4 */ - addr = sgot->output_section->vma + sgot->output_offset + 4; - bfd_put_32 (output_bfd, - PLT0_ENTRY_WORD0 | ((addr >> 16) & 0xffff), - splt->contents); - bfd_put_32 (output_bfd, - PLT0_ENTRY_WORD1 | (addr & 0xffff), - splt->contents + 4); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD2, splt->contents + 8); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD3, splt->contents + 12); - bfd_put_32 (output_bfd, PLT0_ENTRY_WORD4, splt->contents + 16); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; - } - } - - /* Set the first entry in the global offset table to the address of - the dynamic section. */ - if (sgot && sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - } - - if (htab->root.sgot && htab->root.sgot->size > 0) - elf_section_data (htab->root.sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -or1k_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_or1k_link_hash_table *htab; - bfd_byte *loc; - - htab = or1k_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgot; - asection *srela; - - bfd_vma plt_index; - bfd_vma got_offset; - bfd_vma got_addr; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgot = htab->root.sgotplt; - srela = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; - - /* Get the offset into the .got table of the entry that - corresponds to this function. Each .got entry is 4 bytes. - The first three are reserved. */ - got_offset = (plt_index + 3) * 4; - got_addr = got_offset; - - /* Fill in the entry in the procedure linkage table. */ - if (! bfd_link_pic (info)) - { - got_addr += htab->root.sgotplt->output_section->vma - + htab->root.sgotplt->output_offset; - bfd_put_32 (output_bfd, PLT_ENTRY_WORD0 | ((got_addr >> 16) & 0xffff), - splt->contents + h->plt.offset); - bfd_put_32 (output_bfd, PLT_ENTRY_WORD1 | (got_addr & 0xffff), - splt->contents + h->plt.offset + 4); - bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD2, - splt->contents + h->plt.offset + 8); - bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD3, - splt->contents + h->plt.offset + 12); - bfd_put_32 (output_bfd, PLT_ENTRY_WORD4 - | plt_index * sizeof (Elf32_External_Rela), - splt->contents + h->plt.offset + 16); - } - else - { - bfd_put_32 (output_bfd, PLT_PIC_ENTRY_WORD0 | (got_addr & 0xffff), - splt->contents + h->plt.offset); - bfd_put_32 (output_bfd, PLT_PIC_ENTRY_WORD1 - | plt_index * sizeof (Elf32_External_Rela), - splt->contents + h->plt.offset + 4); - bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD2, - splt->contents + h->plt.offset + 8); - bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD3, - splt->contents + h->plt.offset + 12); - bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD4, - splt->contents + h->plt.offset + 16); - } - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset), /* Same offset. */ - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_JMP_SLOT); - rela.r_addend = 0; - loc = srela->contents; - loc += plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - - } - - if (h->got.offset != (bfd_vma) -1 - && (h->got.offset & 2) == 0) /* Homemade TLS check. */ - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the global offset table. Set it - up. */ - sgot = htab->root.sgot; - srela = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset &~ 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h)) - { - rela.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - BFD_ASSERT ((h->got.offset & 1) == 0); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_GLOB_DAT); - rela.r_addend = 0; - } - - loc = srela->contents; - loc += srela->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++srela->reloc_count; - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - - /* This symbols needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->root.sdynrelro) - s = htab->root.sreldynrelro; - else - s = htab->root.srelbss; - loc = s->contents + s->reloc_count * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - ++s->reloc_count; - } - - /* Mark some specially defined symbols as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || h == htab->root.hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -static enum elf_reloc_type_class -or1k_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_OR1K_RELATIVE: return reloc_class_relative; - case R_OR1K_JMP_SLOT: return reloc_class_plt; - case R_OR1K_COPY: return reloc_class_copy; - default: return reloc_class_normal; - } -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - struct elf_or1k_link_hash_entry *eh = (struct elf_or1k_link_hash_entry *) h; - - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* Adjust a symbol defined by a dynamic object and referenced by a - regular object. The current definition is in some section of the - dynamic object, but we're not including those sections. We have to - change the definition to something the rest of the link can - understand. */ - -static bfd_boolean -or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_or1k_link_hash_table *htab; - bfd *dynobj; - asection *s, *srel; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (! bfd_link_pic (info) - && !h->def_dynamic - && !h->ref_dynamic - && h->root.type != bfd_link_hash_undefweak - && h->root.type != bfd_link_hash_undefined) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a PCREL - reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - return TRUE; - } - else - h->plt.offset = (bfd_vma) -1; - - /* If this is a weak symbol, and there is a real definition, the - processor independent code will have arranged for us to see the - real definition first, and we can just use the same value. */ - if (h->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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 we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (!readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = or1k_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* We must generate a R_OR1K_COPY reloc to tell the dynamic linker - to copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = htab->root.sdynrelro; - srel = htab->root.sreldynrelro; - } - else - { - s = htab->root.sdynbss; - srel = htab->root.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info; - struct elf_or1k_link_hash_table *htab; - struct elf_or1k_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = or1k_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - eh = (struct elf_or1k_link_hash_entry *) h; - - if (htab->root.dynamic_sections_created - && h->plt.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->root.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 (! bfd_link_pic (info) - && !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->root.sgotplt->size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - unsigned char tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->root.sgot; - - h->got.offset = s->size; - - tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type; - - /* TLS GD requires two GOT and two relocs. */ - if (tls_type == TLS_GD) - s->size += 8; - else - s->size += 4; - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) - { - if (tls_type == TLS_GD) - htab->root.srelgot->size += 2 * sizeof (Elf32_External_Rela); - else - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) - { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_or1k_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = or1k_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_section_by_name (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - unsigned char *local_tls_type; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - p != NULL; - p = p->next) - { - if (! bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - s = htab->root.sgot; - srel = htab->root.srelgot; - local_tls_type = (unsigned char *) elf_or1k_local_tls_type (ibfd); - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - - /* TLS GD requires two GOT and two relocs. */ - if (local_tls_type != NULL && *local_tls_type == TLS_GD) - s->size += 8; - else - s->size += 4; - if (bfd_link_pic (info)) - { - if (local_tls_type != NULL && *local_tls_type == TLS_GD) - srel->size += 2 * sizeof (Elf32_External_Rela); - else - srel->size += sizeof (Elf32_External_Rela); - } - } - else - - *local_got = (bfd_vma) -1; - - if (local_tls_type) - ++local_tls_type; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->root.splt - || s == htab->root.sgot - || s == htab->root.sgotplt - || s == htab->root.sdynbss - || s == htab->root.sdynrelro) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 && s != htab->root.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - else - /* It's not one of our sections, so don't allocate space. */ - continue; - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is mostly to handle .rela.bss and - .rela.plt. We must create both sections in - create_dynamic_sections, because they must be created - before the linker maps input sections to output - sections. The linker does that before - adjust_dynamic_symbol is called, and it is that - function which decides whether anything needs to go - into these sections. */ - s->flags |= SEC_EXCLUDE; - continue; - } - - if ((s->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents. We use bfd_zalloc - here in case unused entries are not reclaimed before the - section's contents are written out. This should not happen, - but this way if it does, we get a R_OR1K_NONE reloc instead - of garbage. */ - s->contents = bfd_zalloc (dynobj, s->size); - - if (s->contents == NULL) - return FALSE; - } - - if (htab->root.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in or1k_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (! add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->root.splt->size != 0) - { - if (! add_dynamic_entry (DT_PLTGOT, 0) - || ! add_dynamic_entry (DT_PLTRELSZ, 0) - || ! add_dynamic_entry (DT_PLTREL, DT_RELA) - || ! add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (! add_dynamic_entry (DT_RELA, 0) - || ! add_dynamic_entry (DT_RELASZ, 0) - || ! add_dynamic_entry (DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (! add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } - -#undef add_dynamic_entry - return TRUE; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -or1k_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_or1k_link_hash_entry * edir; - struct elf_or1k_link_hash_entry * eind; - - edir = (struct elf_or1k_link_hash_entry *) dir; - eind = (struct elf_or1k_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - - if (ind->root.type == bfd_link_hash_indirect) - { - if (dir->got.refcount <= 0) - { - edir->tls_type = eind->tls_type; - eind->tls_type = TLS_UNKNOWN; - } - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -/* Set the right machine number. */ - -static bfd_boolean -or1k_elf_object_p (bfd *abfd) -{ - unsigned long mach = bfd_mach_or1k; - - if (elf_elfheader (abfd)->e_flags & EF_OR1K_NODELAY) - mach = bfd_mach_or1knd; - - return bfd_default_set_arch_mach (abfd, bfd_arch_or1k, mach); -} - -/* Store the machine number in the flags field. */ - -static void -or1k_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_or1k: - break; - case bfd_mach_or1knd: - elf_elfheader (abfd)->e_flags |= EF_OR1K_NODELAY; - break; - } -} - -static bfd_boolean -or1k_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Make sure all input files are consistent with respect to - EF_OR1K_NODELAY flag setting. */ - -static bfd_boolean -elf32_or1k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (!elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - return TRUE; - } - - if (in_flags == out_flags) - return TRUE; - - if ((in_flags & EF_OR1K_NODELAY) != (out_flags & EF_OR1K_NODELAY)) - { - _bfd_error_handler - (_("%B: EF_OR1K_NODELAY flag mismatch with previous modules"), ibfd); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - return TRUE; - -} - -#define ELF_ARCH bfd_arch_or1k -#define ELF_MACHINE_CODE EM_OR1K -#define ELF_TARGET_ID OR1K_ELF_DATA -#define ELF_MAXPAGESIZE 0x2000 - -#define TARGET_BIG_SYM or1k_elf32_vec -#define TARGET_BIG_NAME "elf32-or1k" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto or1k_info_to_howto_rela -#define elf_backend_relocate_section or1k_elf_relocate_section -#define elf_backend_gc_mark_hook or1k_elf_gc_mark_hook -#define elf_backend_check_relocs or1k_elf_check_relocs -#define elf_backend_reloc_type_class or1k_elf_reloc_type_class -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_mkobject elf_or1k_mkobject - -#define bfd_elf32_bfd_merge_private_bfd_data elf32_or1k_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags or1k_elf_set_private_flags -#define bfd_elf32_bfd_reloc_type_lookup or1k_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup or1k_reloc_name_lookup - -#define elf_backend_object_p or1k_elf_object_p -#define elf_backend_final_write_processing or1k_elf_final_write_processing -#define elf_backend_can_refcount 1 - -#define elf_backend_plt_readonly 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_want_dynrelro 1 - -#define bfd_elf32_bfd_link_hash_table_create or1k_elf_link_hash_table_create -#define elf_backend_copy_indirect_symbol or1k_elf_copy_indirect_symbol -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections or1k_elf_finish_dynamic_sections -#define elf_backend_size_dynamic_sections or1k_elf_size_dynamic_sections -#define elf_backend_adjust_dynamic_symbol or1k_elf_adjust_dynamic_symbol -#define elf_backend_finish_dynamic_symbol or1k_elf_finish_dynamic_symbol - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-pj.c b/sdcc/support/sdbinutils/bfd/elf32-pj.c deleted file mode 100644 index 3487524de..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-pj.c +++ /dev/null @@ -1,359 +0,0 @@ -/* picoJava specific support for 32-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Contributed by Steve Chamberlan of Transmeta (sac@pobox.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/pj.h" - -/* This function is used for normal relocs. This is like the COFF - function, and is almost certainly incorrect for other ELF targets. */ - -static bfd_reloc_status_type -pj_elf_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol_in, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - unsigned long insn; - bfd_vma sym_value; - enum elf_pj_reloc_type r_type; - bfd_vma addr = reloc_entry->address; - bfd_byte *hit_data = addr + (bfd_byte *) data; - - r_type = (enum elf_pj_reloc_type) reloc_entry->howto->type; - - if (output_bfd != NULL) - { - /* Partial linking--do nothing. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (symbol_in != NULL - && bfd_is_und_section (symbol_in->section)) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol_in->section)) - sym_value = 0; - else - sym_value = (symbol_in->value + - symbol_in->section->output_section->vma + - symbol_in->section->output_offset); - - switch (r_type) - { - case R_PJ_DATA_DIR32: - insn = bfd_get_32 (abfd, hit_data); - insn += sym_value + reloc_entry->addend; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); - break; - - /* Relocations in code are always bigendian, no matter what the - data endianness is. */ - - case R_PJ_CODE_DIR32: - insn = bfd_getb32 (hit_data); - insn += sym_value + reloc_entry->addend; - bfd_putb32 ((bfd_vma) insn, hit_data); - break; - - case R_PJ_CODE_REL16: - insn = bfd_getb16 (hit_data); - insn += sym_value + reloc_entry->addend - - (input_section->output_section->vma - + input_section->output_offset); - bfd_putb16 ((bfd_vma) insn, hit_data); - break; - case R_PJ_CODE_LO16: - insn = bfd_getb16 (hit_data); - insn += sym_value + reloc_entry->addend; - bfd_putb16 ((bfd_vma) insn, hit_data); - break; - - case R_PJ_CODE_HI16: - insn = bfd_getb16 (hit_data); - insn += (sym_value + reloc_entry->addend) >> 16; - bfd_putb16 ((bfd_vma) insn, hit_data); - break; - - default: - abort (); - break; - } - - return bfd_reloc_ok; -} - -static reloc_howto_type pj_elf_howto_table[] = -{ - /* No relocation. */ - HOWTO (R_PJ_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - pj_elf_reloc, /* special_function */ - "R_PJ_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute relocation. Setting partial_inplace to TRUE and - src_mask to a non-zero value is similar to the COFF toolchain. */ - HOWTO (R_PJ_DATA_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - pj_elf_reloc, /* special_function */ - "R_PJ_DIR32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit PC relative relocation. */ - HOWTO (R_PJ_CODE_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - pj_elf_reloc, /* special_function */ - "R_PJ_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - -/* 16 bit PC relative relocation. */ - HOWTO (R_PJ_CODE_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overf6w */ - pj_elf_reloc, /* special_function */ - "R_PJ_REL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - EMPTY_HOWTO (4), - EMPTY_HOWTO (5), - HOWTO (R_PJ_CODE_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - pj_elf_reloc, /* special_function */ - "R_PJ_CODE_DIR32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (7), - EMPTY_HOWTO (8), - EMPTY_HOWTO (9), - EMPTY_HOWTO (10), - EMPTY_HOWTO (11), - EMPTY_HOWTO (12), - - HOWTO (R_PJ_CODE_LO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - pj_elf_reloc, /* special_function */ - "R_PJ_LO16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_PJ_CODE_HI16, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - pj_elf_reloc, /* special_function */ - "R_PJ_HI16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_PJ_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_PJ_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_PJ_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_PJ_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* This structure is used to map BFD reloc codes to PJ ELF relocs. */ - -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -/* An array mapping BFD reloc codes to PJ ELF relocs. */ - -static const struct elf_reloc_map pj_reloc_map[] = -{ - { BFD_RELOC_NONE, R_PJ_NONE }, - { BFD_RELOC_32, R_PJ_DATA_DIR32 }, - { BFD_RELOC_PJ_CODE_DIR16, R_PJ_CODE_DIR16 }, - { BFD_RELOC_PJ_CODE_DIR32, R_PJ_CODE_DIR32 }, - { BFD_RELOC_PJ_CODE_LO16, R_PJ_CODE_LO16 }, - { BFD_RELOC_PJ_CODE_HI16, R_PJ_CODE_HI16 }, - { BFD_RELOC_PJ_CODE_REL32, R_PJ_CODE_REL32 }, - { BFD_RELOC_PJ_CODE_REL16, R_PJ_CODE_REL16 }, - { BFD_RELOC_VTABLE_INHERIT, R_PJ_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_PJ_GNU_VTENTRY }, -}; - -/* Given a BFD reloc code, return the howto structure for the - corresponding PJ ELf reloc. */ - -static reloc_howto_type * -pj_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (pj_reloc_map) / sizeof (struct elf_reloc_map); i++) - if (pj_reloc_map[i].bfd_reloc_val == code) - return & pj_elf_howto_table[(int) pj_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -pj_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (pj_elf_howto_table) / sizeof (pj_elf_howto_table[0]); - i++) - if (pj_elf_howto_table[i].name != NULL - && strcasecmp (pj_elf_howto_table[i].name, r_name) == 0) - return &pj_elf_howto_table[i]; - - return NULL; -} - -/* Given an ELF reloc, fill in the howto field of a relent. */ - -static void -pj_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r; - - r = ELF32_R_TYPE (dst->r_info); - - if (r >= R_PJ_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised PicoJava reloc number: %d"), - abfd, r); - bfd_set_error (bfd_error_bad_value); - r = R_PJ_NONE; - } - - cache_ptr->howto = &pj_elf_howto_table[r]; -} - -/* Take this moment to fill in the special picoJava bits in the - e_flags field. */ - -static void -pj_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_ARCH; - elf_elfheader (abfd)->e_flags |= EF_PICOJAVA_GNUCALLS; -} - -#define TARGET_BIG_SYM pj_elf32_vec -#define TARGET_BIG_NAME "elf32-pj" -#define TARGET_LITTLE_SYM pj_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-pjl" -#define ELF_ARCH bfd_arch_pj -#define ELF_MACHINE_CODE EM_PJ -#define ELF_MACHINE_ALT1 EM_PJ_OLD -#define ELF_MAXPAGESIZE 0x1000 -#define bfd_elf32_bfd_get_relocated_section_contents \ - bfd_generic_get_relocated_section_contents -#define bfd_elf32_bfd_reloc_type_lookup pj_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup pj_elf_reloc_name_lookup -#define elf_backend_final_write_processing pj_elf_final_write_processing -#define elf_info_to_howto pj_elf_info_to_howto -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-ppc.c b/sdcc/support/sdbinutils/bfd/elf32-ppc.c deleted file mode 100644 index 32104a12f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-ppc.c +++ /dev/null @@ -1,10958 +0,0 @@ -/* PowerPC-specific support for 32-bit ELF - Copyright (C) 1994-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the - Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - - -/* This file is based on a preliminary PowerPC ELF ABI. The - information may not match the final PowerPC ELF ABI. It includes - suggestions from the in-progress Embedded PowerPC ABI, and that - information may also not match. */ - -#include "sysdep.h" -#include -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/ppc.h" -#include "elf32-ppc.h" -#include "elf-vxworks.h" -#include "dwarf2.h" -#include "opcode/ppc.h" - -typedef enum split16_format_type -{ - split16a_type = 0, - split16d_type -} -split16_format_type; - -/* RELA relocations are used here. */ - -static bfd_reloc_status_type ppc_elf_addr16_ha_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc_elf_unhandled_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -/* Branch prediction bit for branch taken relocs. */ -#define BRANCH_PREDICT_BIT 0x200000 -/* Mask to set RA in memory instructions. */ -#define RA_REGISTER_MASK 0x001f0000 -/* Value to shift register by to insert RA. */ -#define RA_REGISTER_SHIFT 16 - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -/* For old-style PLT. */ -/* The number of single-slot PLT entries (the rest use two slots). */ -#define PLT_NUM_SINGLE_ENTRIES 8192 - -/* For new-style .glink and .plt. */ -#define GLINK_PLTRESOLVE 16*4 -#define GLINK_ENTRY_SIZE(htab, h) \ - (((!htab->params->speculate_indirect_jumps ? 6*4 : 4*4) \ - + (h != NULL \ - && h == htab->tls_get_addr \ - && !htab->params->no_tls_get_addr_opt ? 8*4 : 0) \ - + (1u << htab->params->plt_stub_align) - 1) \ - & -(1u << htab->params->plt_stub_align)) - -/* VxWorks uses its own plt layout, filled in by the static linker. */ - -/* The standard VxWorks PLT entry. */ -#define VXWORKS_PLT_ENTRY_SIZE 32 -static const bfd_vma ppc_elf_vxworks_plt_entry - [VXWORKS_PLT_ENTRY_SIZE / 4] = - { - 0x3d800000, /* lis r12,0 */ - 0x818c0000, /* lwz r12,0(r12) */ - 0x7d8903a6, /* mtctr r12 */ - 0x4e800420, /* bctr */ - 0x39600000, /* li r11,0 */ - 0x48000000, /* b 14 <.PLT0resolve+0x4> */ - 0x60000000, /* nop */ - 0x60000000, /* nop */ - }; -static const bfd_vma ppc_elf_vxworks_pic_plt_entry - [VXWORKS_PLT_ENTRY_SIZE / 4] = - { - 0x3d9e0000, /* addis r12,r30,0 */ - 0x818c0000, /* lwz r12,0(r12) */ - 0x7d8903a6, /* mtctr r12 */ - 0x4e800420, /* bctr */ - 0x39600000, /* li r11,0 */ - 0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */ - 0x60000000, /* nop */ - 0x60000000, /* nop */ - }; - -/* The initial VxWorks PLT entry. */ -#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32 -static const bfd_vma ppc_elf_vxworks_plt0_entry - [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = - { - 0x3d800000, /* lis r12,0 */ - 0x398c0000, /* addi r12,r12,0 */ - 0x800c0008, /* lwz r0,8(r12) */ - 0x7c0903a6, /* mtctr r0 */ - 0x818c0004, /* lwz r12,4(r12) */ - 0x4e800420, /* bctr */ - 0x60000000, /* nop */ - 0x60000000, /* nop */ - }; -static const bfd_vma ppc_elf_vxworks_pic_plt0_entry - [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = - { - 0x819e0008, /* lwz r12,8(r30) */ - 0x7d8903a6, /* mtctr r12 */ - 0x819e0004, /* lwz r12,4(r30) */ - 0x4e800420, /* bctr */ - 0x60000000, /* nop */ - 0x60000000, /* nop */ - 0x60000000, /* nop */ - 0x60000000, /* nop */ - }; - -/* For executables, we have some additional relocations in - .rela.plt.unloaded, for the kernel loader. */ - -/* The number of non-JMP_SLOT relocations per PLT0 slot. */ -#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3 -/* The number of relocations in the PLTResolve slot. */ -#define VXWORKS_PLTRESOLVE_RELOCS 2 -/* The number of relocations in the PLTResolve slot when creating - a shared library. */ -#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 - -/* Some instructions. */ -#define ADDIS_11_11 0x3d6b0000 -#define ADDIS_11_30 0x3d7e0000 -#define ADDIS_12_12 0x3d8c0000 -#define ADDI_11_11 0x396b0000 -#define ADD_0_11_11 0x7c0b5a14 -#define ADD_3_12_2 0x7c6c1214 -#define ADD_11_0_11 0x7d605a14 -#define B 0x48000000 -#define BA 0x48000002 -#define BCL_20_31 0x429f0005 -#define BCTR 0x4e800420 -#define CRSETEQ 0x4c421242 -#define BEQCTRM 0x4dc20420 -#define BEQLR 0x4d820020 -#define CMPWI_11_0 0x2c0b0000 -#define LIS_11 0x3d600000 -#define LIS_12 0x3d800000 -#define LWZU_0_12 0x840c0000 -#define LWZ_0_12 0x800c0000 -#define LWZ_11_3 0x81630000 -#define LWZ_11_11 0x816b0000 -#define LWZ_11_30 0x817e0000 -#define LWZ_12_3 0x81830000 -#define LWZ_12_12 0x818c0000 -#define MR_0_3 0x7c601b78 -#define MR_3_0 0x7c030378 -#define MFLR_0 0x7c0802a6 -#define MFLR_12 0x7d8802a6 -#define MTCTR_0 0x7c0903a6 -#define MTCTR_11 0x7d6903a6 -#define MTLR_0 0x7c0803a6 -#define NOP 0x60000000 -#define SUB_11_11_12 0x7d6c5850 - -/* Offset of tp and dtp pointers from start of TLS block. */ -#define TP_OFFSET 0x7000 -#define DTP_OFFSET 0x8000 - -/* The value of a defined global symbol. */ -#define SYM_VAL(SYM) \ - ((SYM)->root.u.def.section->output_section->vma \ - + (SYM)->root.u.def.section->output_offset \ - + (SYM)->root.u.def.value) - -static reloc_howto_type *ppc_elf_howto_table[R_PPC_max]; - -static reloc_howto_type ppc_elf_howto_raw[] = { - /* This reloc does nothing. */ - HOWTO (R_PPC_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 32 bit relocation. */ - HOWTO (R_PPC_ADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 26 bit branch; the lower two bits must be zero. - FIXME: we don't check that, we just clear them. */ - HOWTO (R_PPC_ADDR24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 16 bit relocation. */ - HOWTO (R_PPC_ADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit relocation without overflow. */ - HOWTO (R_PPC_ADDR16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high order 16 bits of an address. */ - HOWTO (R_PPC_ADDR16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high order 16 bits of an address, plus 1 if the contents of - the low 16 bits, treated as a signed number, is negative. */ - HOWTO (R_PPC_ADDR16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ - "R_PPC_ADDR16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 16 bit branch; the lower two bits must be zero. - FIXME: we don't check that, we just clear them. */ - HOWTO (R_PPC_ADDR14, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR14", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 16 bit branch, for which bit 10 should be set to - indicate that the branch is expected to be taken. The lower two - bits must be zero. */ - HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR14_BRTAKEN",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 16 bit branch, for which bit 10 should be set to - indicate that the branch is not expected to be taken. The lower - two bits must be zero. */ - HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_ADDR14_BRNTAKEN",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A relative 26 bit branch; the lower two bits must be zero. */ - HOWTO (R_PPC_REL24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 16 bit branch; the lower two bits must be zero. */ - HOWTO (R_PPC_REL14, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL14", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 16 bit branch. Bit 10 should be set to indicate that - the branch is expected to be taken. The lower two bits must be - zero. */ - HOWTO (R_PPC_REL14_BRTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL14_BRTAKEN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 16 bit branch. Bit 10 should be set to indicate that - the branch is not expected to be taken. The lower two bits must - be zero. */ - HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL14_BRNTAKEN",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16, but referring to the GOT table entry for the - symbol. */ - HOWTO (R_PPC_GOT16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_PPC_GOT16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_PPC_GOT16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_PPC_GOT16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_REL24, but referring to the procedure linkage table - entry for the symbol. */ - HOWTO (R_PPC_PLTREL24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_PLTREL24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_PPC_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR32, but used when setting global offset table - entries. */ - HOWTO (R_PPC_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marks a procedure linkage table entry for a symbol. */ - HOWTO (R_PPC_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_PPC_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_REL24, but uses the value of the symbol within the - object rather than the final value. Normally used for - _GLOBAL_OFFSET_TABLE_. */ - HOWTO (R_PPC_LOCAL24PC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_LOCAL24PC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC_ADDR32, but may be unaligned. */ - HOWTO (R_PPC_UADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_UADDR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16, but may be unaligned. */ - HOWTO (R_PPC_UADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_UADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32-bit PC relative */ - HOWTO (R_PPC_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32-bit relocation to the symbol's procedure linkage table. - FIXME: not supported. */ - HOWTO (R_PPC_PLT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_PLT32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32-bit PC relative relocation to the symbol's procedure linkage table. - FIXME: not supported. */ - HOWTO (R_PPC_PLTREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_PLTREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for - the symbol. */ - HOWTO (R_PPC_PLT16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_PLT16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for - the symbol. */ - HOWTO (R_PPC_PLT16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_PLT16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for - the symbol. */ - HOWTO (R_PPC_PLT16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_PLT16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with - small data items. */ - HOWTO (R_PPC_SDAREL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_SDAREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit section relative relocation. */ - HOWTO (R_PPC_SECTOFF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_SECTOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit lower half section relative relocation. */ - HOWTO (R_PPC_SECTOFF_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_SECTOFF_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit upper half section relative relocation. */ - HOWTO (R_PPC_SECTOFF_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_SECTOFF_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit upper half adjusted section relative relocation. */ - HOWTO (R_PPC_SECTOFF_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_SECTOFF_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marker relocs for TLS. */ - HOWTO (R_PPC_TLS, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_TLS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC_TLSGD, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_TLSGD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC_TLSLD, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_TLSLD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes the load module index of the load module that contains the - definition of its TLS sym. */ - HOWTO (R_PPC_DTPMOD32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_DTPMOD32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a dtv-relative displacement, the difference between the value - of sym+add and the base address of the thread-local storage block that - contains the definition of sym, minus 0x8000. */ - HOWTO (R_PPC_DTPREL32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_DTPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit dtprel reloc. */ - HOWTO (R_PPC_DTPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_DTPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16, but no overflow. */ - HOWTO (R_PPC_DTPREL16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_DTPREL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC_DTPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_DTPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC_DTPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_DTPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a tp-relative displacement, the difference between the value of - sym+add and the value of the thread pointer (r13). */ - HOWTO (R_PPC_TPREL32, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_TPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit tprel reloc. */ - HOWTO (R_PPC_TPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_TPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16, but no overflow. */ - HOWTO (R_PPC_TPREL16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_TPREL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC_TPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_TPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC_TPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_TPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates two contiguous entries in the GOT to hold a tls_index structure, - with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset - to the first entry. */ - HOWTO (R_PPC_GOT_TLSGD16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSGD16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSGD16, but no overflow. */ - HOWTO (R_PPC_GOT_TLSGD16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSGD16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC_GOT_TLSGD16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSGD16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC_GOT_TLSGD16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSGD16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates two contiguous entries in the GOT to hold a tls_index structure, - with values (sym+add)@dtpmod and zero, and computes the offset to the - first entry. */ - HOWTO (R_PPC_GOT_TLSLD16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSLD16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSLD16, but no overflow. */ - HOWTO (R_PPC_GOT_TLSLD16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSLD16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC_GOT_TLSLD16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSLD16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC_GOT_TLSLD16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TLSLD16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes - the offset to the entry. */ - HOWTO (R_PPC_GOT_DTPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_DTPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_DTPREL16, but no overflow. */ - HOWTO (R_PPC_GOT_DTPREL16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_DTPREL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_DTPREL16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC_GOT_DTPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_DTPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC_GOT_DTPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_DTPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the - offset to the entry. */ - HOWTO (R_PPC_GOT_TPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TPREL16, but no overflow. */ - HOWTO (R_PPC_GOT_TPREL16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TPREL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TPREL16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC_GOT_TPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC_GOT_TPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_GOT_TPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The remaining relocs are from the Embedded ELF ABI, and are not - in the SVR4 ELF ABI. */ - - /* 32 bit value resulting from the addend minus the symbol. */ - HOWTO (R_PPC_EMB_NADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_NADDR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit value resulting from the addend minus the symbol. */ - HOWTO (R_PPC_EMB_NADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_NADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit value resulting from the addend minus the symbol. */ - HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_ADDR16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high order 16 bits of the addend minus the symbol. */ - HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_NADDR16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high order 16 bits of the result of the addend minus the address, - plus 1 if the contents of the low 16 bits, treated as a signed number, - is negative. */ - HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_NADDR16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit value resulting from allocating a 4 byte word to hold an - address in the .sdata section, and returning the offset from - _SDA_BASE_ for that relocation. */ - HOWTO (R_PPC_EMB_SDAI16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_SDAI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit value resulting from allocating a 4 byte word to hold an - address in the .sdata2 section, and returning the offset from - _SDA2_BASE_ for that relocation. */ - HOWTO (R_PPC_EMB_SDA2I16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_SDA2I16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with - small data items. */ - HOWTO (R_PPC_EMB_SDA2REL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_SDA2REL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit - signed offset from the appropriate base, and filling in the register - field with the appropriate register (0, 2, or 13). */ - HOWTO (R_PPC_EMB_SDA21, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_SDA21", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relocation not handled: R_PPC_EMB_MRKREF */ - /* Relocation not handled: R_PPC_EMB_RELSEC16 */ - /* Relocation not handled: R_PPC_EMB_RELST_LO */ - /* Relocation not handled: R_PPC_EMB_RELST_HI */ - /* Relocation not handled: R_PPC_EMB_RELST_HA */ - /* Relocation not handled: R_PPC_EMB_BIT_FLD */ - - /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling - in the 16 bit signed offset from the appropriate base, and filling in the - register field with the appropriate register (0, 2, or 13). */ - HOWTO (R_PPC_EMB_RELSDA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_EMB_RELSDA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A relative 8 bit branch. */ - HOWTO (R_PPC_VLE_REL8, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_VLE_REL8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 15 bit branch. */ - HOWTO (R_PPC_VLE_REL15, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - TRUE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_VLE_REL15", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffe, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 24 bit branch. */ - HOWTO (R_PPC_VLE_REL24, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_VLE_REL24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1fffffe, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The 16 LSBS in split16a format. */ - HOWTO (R_PPC_VLE_LO16A, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_LO16A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 16 LSBS in split16d format. */ - HOWTO (R_PPC_VLE_LO16D, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_LO16D", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3e007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 split16a format. */ - HOWTO (R_PPC_VLE_HI16A, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_HI16A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 split16d format. */ - HOWTO (R_PPC_VLE_HI16D, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_HI16D", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3e007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 (High Adjusted) in split16a format. */ - HOWTO (R_PPC_VLE_HA16A, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_HA16A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 (High Adjusted) in split16d format. */ - HOWTO (R_PPC_VLE_HA16D, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_HA16D", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3e007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i - instructions. If the register base is 0 then the linker changes - the e_add16i to an e_li instruction. */ - HOWTO (R_PPC_VLE_SDA21, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDA21", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC_VLE_SDA21 but ignore overflow. */ - HOWTO (R_PPC_VLE_SDA21_LO, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDA21_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 16 LSBS relative to _SDA_BASE_ in split16a format. */ - HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDAREL_LO16A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The 16 LSBS relative to _SDA_BASE_ in split16d format. */ - HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDAREL_LO16D", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3e007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 relative to _SDA_BASE_ in split16a format. */ - HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDAREL_HI16A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 relative to _SDA_BASE_ in split16d format. */ - HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDAREL_HI16D", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3e007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */ - HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDAREL_HA16A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */ - HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_VLE_SDAREL_HA16D", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3e007ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* e_li split20 format. */ - HOWTO (R_PPC_VLE_ADDR20, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_VLE_ADDR20", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1f07ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC_IRELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_IRELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit relative relocation. */ - HOWTO (R_PPC_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit relative relocation without overflow. */ - HOWTO (R_PPC_REL16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The high order 16 bits of a relative address. */ - HOWTO (R_PPC_REL16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC_REL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The high order 16 bits of a relative address, plus 1 if the contents of - the low 16 bits, treated as a signed number, is negative. */ - HOWTO (R_PPC_REL16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ - "R_PPC_REL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC_REL16_HA but for split field in addpcis. */ - HOWTO (R_PPC_REL16DX_HA, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ - "R_PPC_REL16DX_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1fffc1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A split-field reloc for addpcis, non-relative (gas internal use only). */ - HOWTO (R_PPC_16DX_HA, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_addr16_ha_reloc, /* special_function */ - "R_PPC_16DX_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1fffc1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_PPC_GNU_VTINHERIT, /* 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 */ - "R_PPC_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_PPC_GNU_VTENTRY, /* 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 */ - "R_PPC_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Phony reloc to handle AIX style TOC entries. */ - HOWTO (R_PPC_TOC16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc_elf_unhandled_reloc, /* special_function */ - "R_PPC_TOC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ - -static void -ppc_elf_howto_init (void) -{ - unsigned int i, type; - - for (i = 0; - i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); - i++) - { - type = ppc_elf_howto_raw[i].type; - if (type >= (sizeof (ppc_elf_howto_table) - / sizeof (ppc_elf_howto_table[0]))) - abort (); - ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; - } -} - -static reloc_howto_type * -ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - enum elf_ppc_reloc_type r; - - /* Initialize howto table if not already done. */ - if (!ppc_elf_howto_table[R_PPC_ADDR32]) - ppc_elf_howto_init (); - - switch (code) - { - default: - return NULL; - - case BFD_RELOC_NONE: r = R_PPC_NONE; break; - case BFD_RELOC_32: r = R_PPC_ADDR32; break; - case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break; - case BFD_RELOC_PPC64_ADDR16_DS: - case BFD_RELOC_16: r = R_PPC_ADDR16; break; - case BFD_RELOC_PPC64_ADDR16_LO_DS: - case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break; - case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break; - case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break; - case BFD_RELOC_PPC_BA16: r = R_PPC_ADDR14; break; - case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC_ADDR14_BRTAKEN; break; - case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC_ADDR14_BRNTAKEN; break; - case BFD_RELOC_PPC_B26: r = R_PPC_REL24; break; - case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break; - case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break; - case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break; - case BFD_RELOC_PPC64_GOT16_DS: - case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break; - case BFD_RELOC_PPC64_GOT16_LO_DS: - case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break; - case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break; - case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break; - case BFD_RELOC_24_PLT_PCREL: r = R_PPC_PLTREL24; break; - case BFD_RELOC_PPC_COPY: r = R_PPC_COPY; break; - case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC_GLOB_DAT; break; - case BFD_RELOC_PPC_LOCAL24PC: r = R_PPC_LOCAL24PC; break; - case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break; - case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break; - case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break; - case BFD_RELOC_PPC64_PLT16_LO_DS: - case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break; - case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break; - case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break; - case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break; - case BFD_RELOC_PPC64_SECTOFF_DS: - case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break; - case BFD_RELOC_PPC64_SECTOFF_LO_DS: - case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break; - case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break; - case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break; - case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break; - case BFD_RELOC_PPC64_TOC16_DS: - case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break; - case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break; - case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break; - case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break; - case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break; - case BFD_RELOC_PPC64_TPREL16_DS: - case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break; - case BFD_RELOC_PPC64_TPREL16_LO_DS: - case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break; - case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break; - case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break; - case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break; - case BFD_RELOC_PPC64_DTPREL16_DS: - case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break; - case BFD_RELOC_PPC64_DTPREL16_LO_DS: - case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break; - case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break; - case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break; - case BFD_RELOC_PPC_DTPREL: r = R_PPC_DTPREL32; break; - case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC_GOT_TLSGD16; break; - case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC_GOT_TLSGD16_LO; break; - case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC_GOT_TLSGD16_HI; break; - case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC_GOT_TLSGD16_HA; break; - case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC_GOT_TLSLD16; break; - case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC_GOT_TLSLD16_LO; break; - case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC_GOT_TLSLD16_HI; break; - case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC_GOT_TLSLD16_HA; break; - case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC_GOT_TPREL16; break; - case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC_GOT_TPREL16_LO; break; - case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC_GOT_TPREL16_HI; break; - case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC_GOT_TPREL16_HA; break; - case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC_GOT_DTPREL16; break; - case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC_GOT_DTPREL16_LO; break; - case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC_GOT_DTPREL16_HI; break; - case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC_GOT_DTPREL16_HA; break; - case BFD_RELOC_PPC_EMB_NADDR32: r = R_PPC_EMB_NADDR32; break; - case BFD_RELOC_PPC_EMB_NADDR16: r = R_PPC_EMB_NADDR16; break; - case BFD_RELOC_PPC_EMB_NADDR16_LO: r = R_PPC_EMB_NADDR16_LO; break; - case BFD_RELOC_PPC_EMB_NADDR16_HI: r = R_PPC_EMB_NADDR16_HI; break; - case BFD_RELOC_PPC_EMB_NADDR16_HA: r = R_PPC_EMB_NADDR16_HA; break; - case BFD_RELOC_PPC_EMB_SDAI16: r = R_PPC_EMB_SDAI16; break; - case BFD_RELOC_PPC_EMB_SDA2I16: r = R_PPC_EMB_SDA2I16; break; - case BFD_RELOC_PPC_EMB_SDA2REL: r = R_PPC_EMB_SDA2REL; break; - case BFD_RELOC_PPC_EMB_SDA21: r = R_PPC_EMB_SDA21; break; - case BFD_RELOC_PPC_EMB_MRKREF: r = R_PPC_EMB_MRKREF; break; - case BFD_RELOC_PPC_EMB_RELSEC16: r = R_PPC_EMB_RELSEC16; break; - case BFD_RELOC_PPC_EMB_RELST_LO: r = R_PPC_EMB_RELST_LO; break; - case BFD_RELOC_PPC_EMB_RELST_HI: r = R_PPC_EMB_RELST_HI; break; - case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break; - case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break; - case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break; - case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break; - case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break; - case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break; - case BFD_RELOC_PPC_VLE_LO16A: r = R_PPC_VLE_LO16A; break; - case BFD_RELOC_PPC_VLE_LO16D: r = R_PPC_VLE_LO16D; break; - case BFD_RELOC_PPC_VLE_HI16A: r = R_PPC_VLE_HI16A; break; - case BFD_RELOC_PPC_VLE_HI16D: r = R_PPC_VLE_HI16D; break; - case BFD_RELOC_PPC_VLE_HA16A: r = R_PPC_VLE_HA16A; break; - case BFD_RELOC_PPC_VLE_HA16D: r = R_PPC_VLE_HA16D; break; - case BFD_RELOC_PPC_VLE_SDA21: r = R_PPC_VLE_SDA21; break; - case BFD_RELOC_PPC_VLE_SDA21_LO: r = R_PPC_VLE_SDA21_LO; break; - case BFD_RELOC_PPC_VLE_SDAREL_LO16A: - r = R_PPC_VLE_SDAREL_LO16A; - break; - case BFD_RELOC_PPC_VLE_SDAREL_LO16D: - r = R_PPC_VLE_SDAREL_LO16D; - break; - case BFD_RELOC_PPC_VLE_SDAREL_HI16A: - r = R_PPC_VLE_SDAREL_HI16A; - break; - case BFD_RELOC_PPC_VLE_SDAREL_HI16D: - r = R_PPC_VLE_SDAREL_HI16D; - break; - case BFD_RELOC_PPC_VLE_SDAREL_HA16A: - r = R_PPC_VLE_SDAREL_HA16A; - break; - case BFD_RELOC_PPC_VLE_SDAREL_HA16D: - r = R_PPC_VLE_SDAREL_HA16D; - break; - case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; - case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; - case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; - case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; - case BFD_RELOC_PPC_16DX_HA: r = R_PPC_16DX_HA; break; - case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break; - case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; - case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; - } - - return ppc_elf_howto_table[r]; -}; - -static reloc_howto_type * -ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); - i++) - if (ppc_elf_howto_raw[i].name != NULL - && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0) - return &ppc_elf_howto_raw[i]; - - return NULL; -} - -/* Set the howto pointer for a PowerPC ELF reloc. */ - -static void -ppc_elf_info_to_howto (bfd *abfd, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - /* Initialize howto table if not already done. */ - if (!ppc_elf_howto_table[R_PPC_ADDR32]) - ppc_elf_howto_init (); - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_PPC_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised PPC reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_PPC_NONE; - } - cache_ptr->howto = ppc_elf_howto_table[r_type]; - - /* Just because the above assert didn't trigger doesn't mean that - ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */ - if (!cache_ptr->howto) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - - cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE]; - } -} - -/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */ - -static bfd_reloc_status_type -ppc_elf_addr16_ha_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - enum elf_ppc_reloc_type r_type; - long insn; - bfd_size_type octets; - bfd_vma value; - - if (output_bfd != NULL) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - reloc_entry->addend += 0x8000; - r_type = reloc_entry->howto->type; - if (r_type != R_PPC_REL16DX_HA) - return bfd_reloc_continue; - - value = 0; - if (!bfd_is_com_section (symbol->section)) - value = symbol->value; - value += (reloc_entry->addend - + symbol->section->output_offset - + symbol->section->output_section->vma); - value -= (reloc_entry->address - + input_section->output_offset - + input_section->output_section->vma); - value >>= 16; - - octets = reloc_entry->address * bfd_octets_per_byte (abfd); - insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); - insn &= ~0x1fffc1; - insn |= (value & 0xffc1) | ((value & 0x3e) << 15); - bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -ppc_elf_unhandled_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - if (error_message != NULL) - { - static char buf[60]; - sprintf (buf, _("generic linker can't handle %s"), - reloc_entry->howto->name); - *error_message = buf; - } - return bfd_reloc_dangerous; -} - -/* Sections created by the linker. */ - -typedef struct elf_linker_section -{ - /* Pointer to the bfd section. */ - asection *section; - /* Section name. */ - const char *name; - /* Associated bss section name. */ - const char *bss_name; - /* Associated symbol name. */ - const char *sym_name; - /* Associated symbol. */ - struct elf_link_hash_entry *sym; -} elf_linker_section_t; - -/* Linked list of allocated pointer entries. This hangs off of the - symbol lists, and provides allows us to return different pointers, - based on different addend's. */ - -typedef struct elf_linker_section_pointers -{ - /* next allocated pointer for this symbol */ - struct elf_linker_section_pointers *next; - /* offset of pointer from beginning of section */ - bfd_vma offset; - /* addend used */ - bfd_vma addend; - /* which linker section this is */ - elf_linker_section_t *lsect; -} elf_linker_section_pointers_t; - -struct ppc_elf_obj_tdata -{ - struct elf_obj_tdata elf; - - /* A mapping from local symbols to offsets into the various linker - sections added. This is index by the symbol index. */ - elf_linker_section_pointers_t **linker_section_pointers; - - /* Flags used to auto-detect plt type. */ - unsigned int makes_plt_call : 1; - unsigned int has_rel16 : 1; -}; - -#define ppc_elf_tdata(bfd) \ - ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any) - -#define elf_local_ptr_offsets(bfd) \ - (ppc_elf_tdata (bfd)->linker_section_pointers) - -#define is_ppc_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_object_id (bfd) == PPC32_ELF_DATA) - -/* Override the generic function because we store some extras. */ - -static bfd_boolean -ppc_elf_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata), - PPC32_ELF_DATA); -} - -/* When defaulting arch/mach, decode apuinfo to find a better match. */ - -bfd_boolean -_bfd_elf_ppc_set_arch (bfd *abfd) -{ - unsigned long mach = 0; - asection *s; - unsigned char *contents; - - if (abfd->arch_info->bits_per_word == 32 - && bfd_big_endian (abfd)) - { - - for (s = abfd->sections; s != NULL; s = s->next) - if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0) - break; - if (s != NULL) - mach = bfd_mach_ppc_vle; - } - - if (mach == 0) - { - s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); - if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents)) - { - unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4); - unsigned int i; - - for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4) - { - unsigned int val = bfd_get_32 (abfd, contents + i); - switch (val >> 16) - { - case PPC_APUINFO_PMR: - case PPC_APUINFO_RFMCI: - if (mach == 0) - mach = bfd_mach_ppc_titan; - break; - - case PPC_APUINFO_ISEL: - case PPC_APUINFO_CACHELCK: - if (mach == bfd_mach_ppc_titan) - mach = bfd_mach_ppc_e500mc; - break; - - case PPC_APUINFO_SPE: - case PPC_APUINFO_EFS: - case PPC_APUINFO_BRLOCK: - if (mach != bfd_mach_ppc_vle) - mach = bfd_mach_ppc_e500; - break; - - case PPC_APUINFO_VLE: - mach = bfd_mach_ppc_vle; - break; - - default: - mach = -1ul; - } - } - free (contents); - } - } - - if (mach != 0 && mach != -1ul) - { - const bfd_arch_info_type *arch; - - for (arch = abfd->arch_info->next; arch; arch = arch->next) - if (arch->mach == mach) - { - abfd->arch_info = arch; - break; - } - } - return TRUE; -} - -/* Fix bad default arch selected for a 32 bit input bfd when the - default is 64 bit. Also select arch based on apuinfo. */ - -static bfd_boolean -ppc_elf_object_p (bfd *abfd) -{ - if (!abfd->arch_info->the_default) - return TRUE; - - if (abfd->arch_info->bits_per_word == 64) - { - Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); - - if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) - { - /* Relies on arch after 64 bit default being 32 bit default. */ - abfd->arch_info = abfd->arch_info->next; - BFD_ASSERT (abfd->arch_info->bits_per_word == 32); - } - } - return _bfd_elf_ppc_set_arch (abfd); -} - -/* Function to set whether a module needs the -mrelocatable bit set. */ - -static bfd_boolean -ppc_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 268: /* Linux/PPC. */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 192; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 128: /* Linux/PPC elf_prpsinfo. */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 16); - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 48, 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; -} - -static char * -ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) -{ - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - { - char data[128]; - va_list ap; - - va_start (ap, note_type); - memset (data, 0, sizeof (data)); - strncpy (data + 32, va_arg (ap, const char *), 16); - strncpy (data + 48, va_arg (ap, const char *), 80); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - - case NT_PRSTATUS: - { - char data[268]; - va_list ap; - long pid; - int cursig; - const void *greg; - - va_start (ap, note_type); - memset (data, 0, 72); - pid = va_arg (ap, long); - bfd_put_32 (abfd, pid, data + 24); - cursig = va_arg (ap, int); - bfd_put_16 (abfd, cursig, data + 12); - greg = va_arg (ap, const void *); - memcpy (data + 72, greg, 192); - memset (data + 264, 0, 4); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - } -} - -static flagword -ppc_elf_lookup_section_flags (char *flag_name) -{ - - if (!strcmp (flag_name, "SHF_PPC_VLE")) - return SHF_PPC_VLE; - - return 0; -} - -/* 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 -ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, - const asection *plt ATTRIBUTE_UNUSED, - const arelent *rel) -{ - return rel->address; -} - -/* Handle a PowerPC specific section when reading an object file. This - is called when bfd_section_from_shdr finds a section with an unknown - type. */ - -static bfd_boolean -ppc_elf_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) -{ - asection *newsect; - flagword flags; - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - newsect = hdr->bfd_section; - flags = bfd_get_section_flags (abfd, newsect); - if (hdr->sh_flags & SHF_EXCLUDE) - flags |= SEC_EXCLUDE; - - if (hdr->sh_type == SHT_ORDERED) - flags |= SEC_SORT_ENTRIES; - - bfd_set_section_flags (abfd, newsect, flags); - return TRUE; -} - -/* Set up any other section flags and such that may be necessary. */ - -static bfd_boolean -ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *shdr, - asection *asect) -{ - if ((asect->flags & SEC_SORT_ENTRIES) != 0) - shdr->sh_type = SHT_ORDERED; - - return TRUE; -} - -/* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we - need to bump up the number of section headers. */ - -static int -ppc_elf_additional_program_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - asection *s; - int ret = 0; - - s = bfd_get_section_by_name (abfd, ".sbss2"); - if (s != NULL && (s->flags & SEC_ALLOC) != 0) - ++ret; - - s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); - if (s != NULL && (s->flags & SEC_ALLOC) != 0) - ++ret; - - return ret; -} - -/* Modify the segment map for VLE executables. */ - -bfd_boolean -ppc_elf_modify_segment_map (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - struct elf_segment_map *m; - - /* At this point in the link, output sections have already been sorted by - LMA and assigned to segments. All that is left to do is to ensure - there is no mixing of VLE & non-VLE sections in a text segment. - If we find that case, we split the segment. - We maintain the original output section order. */ - - for (m = elf_seg_map (abfd); m != NULL; m = m->next) - { - struct elf_segment_map *n; - bfd_size_type amt; - unsigned int j, k; - unsigned int p_flags; - - if (m->p_type != PT_LOAD || m->count == 0) - continue; - - for (p_flags = PF_R, j = 0; j != m->count; ++j) - { - if ((m->sections[j]->flags & SEC_READONLY) == 0) - p_flags |= PF_W; - if ((m->sections[j]->flags & SEC_CODE) != 0) - { - p_flags |= PF_X; - if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0) - p_flags |= PF_PPC_VLE; - break; - } - } - if (j != m->count) - while (++j != m->count) - { - unsigned int p_flags1 = PF_R; - - if ((m->sections[j]->flags & SEC_READONLY) == 0) - p_flags1 |= PF_W; - if ((m->sections[j]->flags & SEC_CODE) != 0) - { - p_flags1 |= PF_X; - if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0) - p_flags1 |= PF_PPC_VLE; - if (((p_flags1 ^ p_flags) & PF_PPC_VLE) != 0) - break; - } - p_flags |= p_flags1; - } - /* If we're splitting a segment which originally contained rw - sections then those sections might now only be in one of the - two parts. So always set p_flags if splitting, even if we - are being called for objcopy with p_flags_valid set. */ - if (j != m->count || !m->p_flags_valid) - { - m->p_flags_valid = 1; - m->p_flags = p_flags; - } - if (j == m->count) - continue; - - /* Sections 0..j-1 stay in this (current) segment, - the remainder are put in a new segment. - The scan resumes with the new segment. */ - - amt = sizeof (struct elf_segment_map); - amt += (m->count - j - 1) * sizeof (asection *); - n = (struct elf_segment_map *) bfd_zalloc (abfd, amt); - if (n == NULL) - return FALSE; - - n->p_type = PT_LOAD; - n->count = m->count - j; - for (k = 0; k < n->count; ++k) - n->sections[k] = m->sections[j + k]; - m->count = j; - m->p_size_valid = 0; - n->next = m->next; - m->next = n; - } - - return TRUE; -} - -/* Add extra PPC sections -- Note, for now, make .sbss2 and - .PPC.EMB.sbss0 a normal section, and not a bss section so - that the linker doesn't crater when trying to make more than - 2 sections. */ - -static const struct bfd_elf_special_section ppc_elf_special_sections[] = -{ - { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, - { STRING_COMMA_LEN (APUINFO_SECTION_NAME), 0, SHT_NOTE, 0 }, - { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, - { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } -}; - -/* This is what we want for new plt/got. */ -static struct bfd_elf_special_section ppc_alt_plt = - { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC }; - -static const struct bfd_elf_special_section * -ppc_elf_get_sec_type_attr (bfd *abfd, asection *sec) -{ - const struct bfd_elf_special_section *ssect; - - /* See if this is one of the special sections. */ - if (sec->name == NULL) - return NULL; - - ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections, - sec->use_rela_p); - if (ssect != NULL) - { - if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0) - ssect = &ppc_alt_plt; - return ssect; - } - - return _bfd_elf_get_sec_type_attr (abfd, sec); -} - -/* Very simple linked list structure for recording apuinfo values. */ -typedef struct apuinfo_list -{ - struct apuinfo_list *next; - unsigned long value; -} -apuinfo_list; - -static apuinfo_list *head; -static bfd_boolean apuinfo_set; - -static void -apuinfo_list_init (void) -{ - head = NULL; - apuinfo_set = FALSE; -} - -static void -apuinfo_list_add (unsigned long value) -{ - apuinfo_list *entry = head; - - while (entry != NULL) - { - if (entry->value == value) - return; - entry = entry->next; - } - - entry = bfd_malloc (sizeof (* entry)); - if (entry == NULL) - return; - - entry->value = value; - entry->next = head; - head = entry; -} - -static unsigned -apuinfo_list_length (void) -{ - apuinfo_list *entry; - unsigned long count; - - for (entry = head, count = 0; - entry; - entry = entry->next) - ++ count; - - return count; -} - -static inline unsigned long -apuinfo_list_element (unsigned long number) -{ - apuinfo_list * entry; - - for (entry = head; - entry && number --; - entry = entry->next) - ; - - return entry ? entry->value : 0; -} - -static void -apuinfo_list_finish (void) -{ - apuinfo_list *entry; - - for (entry = head; entry;) - { - apuinfo_list *next = entry->next; - free (entry); - entry = next; - } - - head = NULL; -} - -/* Scan the input BFDs and create a linked list of - the APUinfo values that will need to be emitted. */ - -static void -ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) -{ - bfd *ibfd; - asection *asec; - char *buffer = NULL; - bfd_size_type largest_input_size = 0; - unsigned i; - unsigned long length; - const char *error_message = NULL; - - if (link_info == NULL) - return; - - apuinfo_list_init (); - - /* Read in the input sections contents. */ - for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link.next) - { - unsigned long datum; - - asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); - if (asec == NULL) - continue; - - /* xgettext:c-format */ - error_message = _("corrupt %s section in %B"); - length = asec->size; - if (length < 20) - goto fail; - - apuinfo_set = TRUE; - if (largest_input_size < asec->size) - { - if (buffer) - free (buffer); - largest_input_size = asec->size; - buffer = bfd_malloc (largest_input_size); - if (!buffer) - return; - } - - if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0 - || (bfd_bread (buffer, length, ibfd) != length)) - { - /* xgettext:c-format */ - error_message = _("unable to read in %s section from %B"); - goto fail; - } - - /* Verify the contents of the header. Note - we have to - extract the values this way in order to allow for a - host whose endian-ness is different from the target. */ - datum = bfd_get_32 (ibfd, buffer); - if (datum != sizeof APUINFO_LABEL) - goto fail; - - datum = bfd_get_32 (ibfd, buffer + 8); - if (datum != 0x2) - goto fail; - - if (strcmp (buffer + 12, APUINFO_LABEL) != 0) - goto fail; - - /* Get the number of bytes used for apuinfo entries. */ - datum = bfd_get_32 (ibfd, buffer + 4); - if (datum + 20 != length) - goto fail; - - /* Scan the apuinfo section, building a list of apuinfo numbers. */ - for (i = 0; i < datum; i += 4) - apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i)); - } - - error_message = NULL; - - if (apuinfo_set) - { - /* Compute the size of the output section. */ - unsigned num_entries = apuinfo_list_length (); - - /* Set the output section size, if it exists. */ - asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); - - if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4)) - { - ibfd = abfd; - /* xgettext:c-format */ - error_message = _("warning: unable to set size of %s section in %B"); - } - } - - fail: - if (buffer) - free (buffer); - - if (error_message) - _bfd_error_handler (error_message, APUINFO_SECTION_NAME, ibfd); -} - -/* Prevent the output section from accumulating the input sections' - contents. We have already stored this in our linked list structure. */ - -static bfd_boolean -ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *link_info ATTRIBUTE_UNUSED, - asection *asec, - bfd_byte *contents ATTRIBUTE_UNUSED) -{ - return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0; -} - -/* Finally we can generate the output section. */ - -static void -ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) -{ - bfd_byte *buffer; - asection *asec; - unsigned i; - unsigned num_entries; - bfd_size_type length; - - asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); - if (asec == NULL) - return; - - if (!apuinfo_set) - return; - - length = asec->size; - if (length < 20) - return; - - buffer = bfd_malloc (length); - if (buffer == NULL) - { - _bfd_error_handler - (_("failed to allocate space for new APUinfo section.")); - return; - } - - /* Create the apuinfo header. */ - num_entries = apuinfo_list_length (); - bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer); - bfd_put_32 (abfd, num_entries * 4, buffer + 4); - bfd_put_32 (abfd, 0x2, buffer + 8); - strcpy ((char *) buffer + 12, APUINFO_LABEL); - - length = 20; - for (i = 0; i < num_entries; i++) - { - bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length); - length += 4; - } - - if (length != asec->size) - _bfd_error_handler (_("failed to compute new APUinfo section.")); - - if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length)) - _bfd_error_handler (_("failed to install new APUinfo section.")); - - free (buffer); - - apuinfo_list_finish (); -} - -static bfd_boolean -is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off) -{ - bfd_byte buf[3 * 4]; - - if (!bfd_get_section_contents (abfd, glink, buf, off, sizeof buf)) - return FALSE; - - return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11 - && (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11 - && bfd_get_32 (abfd, buf + 8) == MTCTR_11); -} - -static bfd_boolean -section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr) -{ - bfd_vma vma = *(bfd_vma *) ptr; - return ((section->flags & SEC_ALLOC) != 0 - && section->vma <= vma - && vma < section->vma + section->size); -} - -static long -ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms, - long dynsymcount, asymbol **dynsyms, - asymbol **ret) -{ - bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - asection *plt, *relplt, *dynamic, *glink; - bfd_vma glink_vma = 0; - bfd_vma resolv_vma = 0; - bfd_vma stub_off; - asymbol *s; - arelent *p; - long count, i, stub_delta; - size_t size; - char *names; - bfd_byte buf[4]; - - *ret = NULL; - - if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) - return 0; - - if (dynsymcount <= 0) - return 0; - - relplt = bfd_get_section_by_name (abfd, ".rela.plt"); - if (relplt == NULL) - return 0; - - plt = bfd_get_section_by_name (abfd, ".plt"); - if (plt == NULL) - return 0; - - /* Call common code to handle old-style executable PLTs. */ - if (elf_section_flags (plt) & SHF_EXECINSTR) - return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, - dynsymcount, dynsyms, ret); - - /* If this object was prelinked, the prelinker stored the address - of .glink at got[1]. If it wasn't prelinked, got[1] will be zero. */ - dynamic = bfd_get_section_by_name (abfd, ".dynamic"); - if (dynamic != NULL) - { - bfd_byte *dynbuf, *extdyn, *extdynend; - size_t extdynsize; - void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); - - if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf)) - return -1; - - 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 + dynamic->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_PPC_GOT) - { - unsigned int g_o_t = dyn.d_un.d_val; - asection *got = bfd_get_section_by_name (abfd, ".got"); - if (got != NULL - && bfd_get_section_contents (abfd, got, buf, - g_o_t - got->vma + 4, 4)) - glink_vma = bfd_get_32 (abfd, buf); - break; - } - } - free (dynbuf); - } - - /* Otherwise we read the first plt entry. */ - if (glink_vma == 0) - { - if (bfd_get_section_contents (abfd, plt, buf, 0, 4)) - glink_vma = bfd_get_32 (abfd, buf); - } - - if (glink_vma == 0) - return 0; - - /* The .glink section usually does not survive the final - link; search for the section (usually .text) where the - glink stubs now reside. */ - glink = bfd_sections_find_if (abfd, section_covers_vma, &glink_vma); - if (glink == NULL) - return 0; - - /* Determine glink PLT resolver by reading the relative branch - from the first glink stub. */ - if (bfd_get_section_contents (abfd, glink, buf, - glink_vma - glink->vma, 4)) - { - unsigned int insn = bfd_get_32 (abfd, buf); - - /* The first glink stub may either branch to the resolver ... */ - insn ^= B; - if ((insn & ~0x3fffffc) == 0) - resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000; - - /* ... or fall through a bunch of NOPs. */ - else if ((insn ^ B ^ NOP) == 0) - for (i = 4; - bfd_get_section_contents (abfd, glink, buf, - glink_vma - glink->vma + i, 4); - i += 4) - if (bfd_get_32 (abfd, buf) != NOP) - { - resolv_vma = glink_vma + i; - break; - } - } - - count = relplt->size / sizeof (Elf32_External_Rela); - /* If the stubs are those for -shared/-pie then we might have - multiple stubs for each plt entry. If that is the case then - there is no way to associate stubs with their plt entries short - of figuring out the GOT pointer value used in the stub. - The offsets tested here need to cover all possible values of - GLINK_ENTRY_SIZE for other than __tls_get_addr_opt. */ - stub_off = glink_vma - glink->vma; - for (stub_delta = 16; stub_delta <= 32; stub_delta += 8) - if (is_nonpic_glink_stub (abfd, glink, stub_off - stub_delta)) - break; - if (stub_delta > 32) - return 0; - - slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; - if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) - return -1; - - size = count * sizeof (asymbol); - p = relplt->relocation; - for (i = 0; i < count; i++, p++) - { - size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); - if (p->addend != 0) - size += sizeof ("+0x") - 1 + 8; - } - - size += sizeof (asymbol) + sizeof ("__glink"); - - if (resolv_vma) - size += sizeof (asymbol) + sizeof ("__glink_PLTresolve"); - - s = *ret = bfd_malloc (size); - if (s == NULL) - return -1; - - stub_off = glink_vma - glink->vma; - names = (char *) (s + count + 1 + (resolv_vma != 0)); - p = relplt->relocation + count - 1; - for (i = 0; i < count; i++) - { - size_t len; - - stub_off -= stub_delta; - if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0) - stub_off -= 32; - *s = **p->sym_ptr_ptr; - /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since - we are defining a symbol, ensure one of them is set. */ - if ((s->flags & BSF_LOCAL) == 0) - s->flags |= BSF_GLOBAL; - s->flags |= BSF_SYNTHETIC; - s->section = glink; - s->value = stub_off; - s->name = names; - s->udata.p = NULL; - len = strlen ((*p->sym_ptr_ptr)->name); - memcpy (names, (*p->sym_ptr_ptr)->name, len); - names += len; - if (p->addend != 0) - { - memcpy (names, "+0x", sizeof ("+0x") - 1); - names += sizeof ("+0x") - 1; - bfd_sprintf_vma (abfd, names, p->addend); - names += strlen (names); - } - memcpy (names, "@plt", sizeof ("@plt")); - names += sizeof ("@plt"); - ++s; - --p; - } - - /* Add a symbol at the start of the glink branch table. */ - memset (s, 0, sizeof *s); - s->the_bfd = abfd; - s->flags = BSF_GLOBAL | BSF_SYNTHETIC; - s->section = glink; - s->value = glink_vma - glink->vma; - s->name = names; - memcpy (names, "__glink", sizeof ("__glink")); - names += sizeof ("__glink"); - s++; - count++; - - if (resolv_vma) - { - /* Add a symbol for the glink PLT resolver. */ - memset (s, 0, sizeof *s); - s->the_bfd = abfd; - s->flags = BSF_GLOBAL | BSF_SYNTHETIC; - s->section = glink; - s->value = resolv_vma - glink->vma; - s->name = names; - memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve")); - names += sizeof ("__glink_PLTresolve"); - s++; - count++; - } - - return count; -} - -/* The following functions are specific to the ELF linker, while - functions above are used generally. They appear in this file more - or less in the order in which they are called. eg. - ppc_elf_check_relocs is called early in the link process, - ppc_elf_finish_dynamic_sections is one of the last functions - called. */ - -/* Track PLT entries needed for a given symbol. We might need more - than one glink entry per symbol when generating a pic binary. */ -struct plt_entry -{ - struct plt_entry *next; - - /* -fPIC uses multiple GOT sections, one per file, called ".got2". - This field stores the offset into .got2 used to initialise the - GOT pointer reg. It will always be at least 32768. (Current - gcc always uses an offset of 32768, but ld -r will pack .got2 - sections together resulting in larger offsets). */ - bfd_vma addend; - - /* The .got2 section. */ - asection *sec; - - /* PLT refcount or offset. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } plt; - - /* .glink stub offset. */ - bfd_vma glink_offset; -}; - -/* Of those relocs that might be copied as dynamic relocs, this - function selects those that must be copied when linking a shared - library or PIE, even when the symbol is local. */ - -static int -must_be_dyn_reloc (struct bfd_link_info *info, - enum elf_ppc_reloc_type r_type) -{ - switch (r_type) - { - default: - /* Only relative relocs can be resolved when the object load - address isn't fixed. DTPREL32 is excluded because the - dynamic linker needs to differentiate global dynamic from - local dynamic __tls_index pairs when PPC_OPT_TLS is set. */ - return 1; - - case R_PPC_REL24: - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - case R_PPC_REL32: - return 0; - - case R_PPC_TPREL32: - case R_PPC_TPREL16: - case R_PPC_TPREL16_LO: - case R_PPC_TPREL16_HI: - case R_PPC_TPREL16_HA: - /* These relocations are relative but in a shared library the - linker doesn't know the thread pointer base. */ - return bfd_link_dll (info); - } -} - -/* 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 - -/* Used to track dynamic relocations for local symbols. */ -struct ppc_dyn_relocs -{ - struct ppc_dyn_relocs *next; - - /* The input section of the reloc. */ - asection *sec; - - /* Total number of relocs copied for the input section. */ - unsigned int count : 31; - - /* Whether this entry is for STT_GNU_IFUNC symbols. */ - unsigned int ifunc : 1; -}; - -/* PPC ELF linker hash entry. */ - -struct ppc_elf_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* If this symbol is used in the linker created sections, the processor - specific backend uses this field to map the field into the offset - from the beginning of the section. */ - elf_linker_section_pointers_t *linker_section_pointer; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* Contexts in which symbol is used in the GOT (or TOC). - TLS_GD .. TLS_TLS bits are or'd into the mask as the - corresponding relocs are encountered during check_relocs. - tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to - indicate the corresponding GOT entry type is not needed. */ -#define TLS_GD 1 /* GD reloc. */ -#define TLS_LD 2 /* LD reloc. */ -#define TLS_TPREL 4 /* TPREL reloc, => IE. */ -#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ -#define TLS_TLS 16 /* Any TLS reloc. */ -#define TLS_TPRELGD 32 /* TPREL reloc resulting from GD->IE. */ -#define PLT_IFUNC 64 /* STT_GNU_IFUNC. */ - char tls_mask; - - /* Nonzero if we have seen a small data relocation referring to this - symbol. */ - unsigned char has_sda_refs : 1; - - /* Flag use of given relocations. */ - unsigned char has_addr16_ha : 1; - unsigned char has_addr16_lo : 1; -}; - -#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent)) - -/* PPC ELF linker hash table. */ - -struct ppc_elf_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Various options passed from the linker. */ - struct ppc_elf_params *params; - - /* Short-cuts to get to dynamic linker sections. */ - asection *glink; - asection *dynsbss; - asection *relsbss; - elf_linker_section_t sdata[2]; - asection *sbss; - asection *glink_eh_frame; - - /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ - asection *srelplt2; - - /* Shortcut to __tls_get_addr. */ - struct elf_link_hash_entry *tls_get_addr; - - /* The bfd that forced an old-style PLT. */ - bfd *old_bfd; - - /* TLS local dynamic got entry handling. */ - union { - bfd_signed_vma refcount; - bfd_vma offset; - } tlsld_got; - - /* Offset of branch table to PltResolve function in glink. */ - bfd_vma glink_pltresolve; - - /* Size of reserved GOT entries. */ - unsigned int got_header_size; - /* Non-zero if allocating the header left a gap. */ - unsigned int got_gap; - - /* The type of PLT we have chosen to use. */ - enum ppc_elf_plt_type plt_type; - - /* True if the target system is VxWorks. */ - unsigned int is_vxworks:1; - - /* Whether there exist local gnu indirect function resolvers, - referenced by dynamic relocations. */ - unsigned int local_ifunc_resolver:1; - unsigned int maybe_local_ifunc_resolver:1; - - /* Set if tls optimization is enabled. */ - unsigned int do_tls_opt:1; - - /* The size of PLT entries. */ - int plt_entry_size; - /* The distance between adjacent PLT slots. */ - int plt_slot_size; - /* The size of the first PLT entry. */ - int plt_initial_entry_size; - - /* Small local sym cache. */ - struct sym_cache sym_cache; -}; - -/* Rename some of the generic section flags to better document how they - are used for ppc32. The flags are only valid for ppc32 elf objects. */ - -/* Nonzero if this section has TLS related relocations. */ -#define has_tls_reloc sec_flg0 - -/* Nonzero if this section has a call to __tls_get_addr. */ -#define has_tls_get_addr_call sec_flg1 - -/* Get the PPC ELF linker hash table from a link_info structure. */ - -#define ppc_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL) - -/* Create an entry in a PPC ELF linker hash table. */ - -static struct bfd_hash_entry * -ppc_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 ppc_elf_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) - { - ppc_elf_hash_entry (entry)->linker_section_pointer = NULL; - ppc_elf_hash_entry (entry)->dyn_relocs = NULL; - ppc_elf_hash_entry (entry)->tls_mask = 0; - ppc_elf_hash_entry (entry)->has_sda_refs = 0; - } - - return entry; -} - -/* Create a PPC ELF linker hash table. */ - -static struct bfd_link_hash_table * -ppc_elf_link_hash_table_create (bfd *abfd) -{ - struct ppc_elf_link_hash_table *ret; - static struct ppc_elf_params default_params - = { PLT_OLD, 0, 1, 0, 1, 0, 0, 12, 0, 0, 0 }; - - ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - ppc_elf_link_hash_newfunc, - sizeof (struct ppc_elf_link_hash_entry), - PPC32_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->elf.init_plt_refcount.refcount = 0; - ret->elf.init_plt_refcount.glist = NULL; - ret->elf.init_plt_offset.offset = 0; - ret->elf.init_plt_offset.glist = NULL; - - ret->params = &default_params; - - ret->sdata[0].name = ".sdata"; - ret->sdata[0].sym_name = "_SDA_BASE_"; - ret->sdata[0].bss_name = ".sbss"; - - ret->sdata[1].name = ".sdata2"; - ret->sdata[1].sym_name = "_SDA2_BASE_"; - ret->sdata[1].bss_name = ".sbss2"; - - ret->plt_entry_size = 12; - ret->plt_slot_size = 8; - ret->plt_initial_entry_size = 72; - - return &ret->elf.root; -} - -/* Hook linker params into hash table. */ - -void -ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - - if (htab) - htab->params = params; - params->pagesize_p2 = bfd_log2 (params->pagesize); -} - -/* Create .got and the related sections. */ - -static bfd_boolean -ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab; - - if (!_bfd_elf_create_got_section (abfd, info)) - return FALSE; - - htab = ppc_elf_hash_table (info); - if (!htab->is_vxworks) - { - /* The powerpc .got has a blrl instruction in it. Mark it - executable. */ - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if (!bfd_set_section_flags (abfd, htab->elf.sgot, flags)) - return FALSE; - } - - return TRUE; -} - -/* Create a special linker section, used for R_PPC_EMB_SDAI16 and - R_PPC_EMB_SDA2I16 pointers. These sections become part of .sdata - and .sdata2. Create _SDA_BASE_ and _SDA2_BASE too. */ - -static bfd_boolean -ppc_elf_create_linker_section (bfd *abfd, - struct bfd_link_info *info, - flagword flags, - elf_linker_section_t *lsect) -{ - asection *s; - - flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - s = bfd_make_section_anyway_with_flags (abfd, lsect->name, flags); - if (s == NULL) - return FALSE; - lsect->section = s; - - /* Define the sym on the first section of this name. */ - s = bfd_get_section_by_name (abfd, lsect->name); - - lsect->sym = _bfd_elf_define_linkage_sym (abfd, info, s, lsect->sym_name); - if (lsect->sym == NULL) - return FALSE; - lsect->sym->root.u.def.value = 0x8000; - return TRUE; -} - -static bfd_boolean -ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - asection *s; - flagword flags; - int p2align; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags); - htab->glink = s; - p2align = htab->params->ppc476_workaround ? 6 : 4; - if (p2align < htab->params->plt_stub_align) - p2align = htab->params->plt_stub_align; - if (s == NULL - || !bfd_set_section_alignment (abfd, s, p2align)) - return FALSE; - - if (!info->no_ld_generated_unwind_info) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - s = bfd_make_section_anyway_with_flags (abfd, ".eh_frame", flags); - htab->glink_eh_frame = s; - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - } - - flags = SEC_ALLOC | SEC_LINKER_CREATED; - s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags); - htab->elf.iplt = s; - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 4)) - return FALSE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - s = bfd_make_section_anyway_with_flags (abfd, ".rela.iplt", flags); - htab->elf.irelplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - if (!ppc_elf_create_linker_section (abfd, info, 0, - &htab->sdata[0])) - return FALSE; - - if (!ppc_elf_create_linker_section (abfd, info, SEC_READONLY, - &htab->sdata[1])) - return FALSE; - - return TRUE; -} - -/* We have to create .dynsbss and .rela.sbss here so that they get mapped - to output sections (just like _bfd_elf_create_dynamic_sections has - to create .dynbss and .rela.bss). */ - -static bfd_boolean -ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab; - asection *s; - flagword flags; - - htab = ppc_elf_hash_table (info); - - if (htab->elf.sgot == NULL - && !ppc_elf_create_got (abfd, info)) - return FALSE; - - if (!_bfd_elf_create_dynamic_sections (abfd, info)) - return FALSE; - - if (htab->glink == NULL - && !ppc_elf_create_glink (abfd, info)) - return FALSE; - - s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss", - SEC_ALLOC | SEC_LINKER_CREATED); - htab->dynsbss = s; - if (s == NULL) - return FALSE; - - if (! bfd_link_pic (info)) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags); - htab->relsbss = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - } - - if (htab->is_vxworks - && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) - return FALSE; - - s = htab->elf.splt; - flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED; - if (htab->plt_type == PLT_VXWORKS) - /* The VxWorks PLT is a loaded section with contents. */ - flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY; - return bfd_set_section_flags (abfd, s, flags); -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct ppc_elf_link_hash_entry *edir, *eind; - - edir = (struct ppc_elf_link_hash_entry *) dir; - eind = (struct ppc_elf_link_hash_entry *) ind; - - edir->tls_mask |= eind->tls_mask; - edir->has_sda_refs |= eind->has_sda_refs; - - if (edir->elf.versioned != versioned_hidden) - edir->elf.ref_dynamic |= eind->elf.ref_dynamic; - edir->elf.ref_regular |= eind->elf.ref_regular; - edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; - edir->elf.non_got_ref |= eind->elf.non_got_ref; - edir->elf.needs_plt |= eind->elf.needs_plt; - edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; - - /* If we were called to copy over info for a weak sym, that's all. */ - if (eind->elf.root.type != bfd_link_hash_indirect) - return; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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; - } - - /* Copy over the GOT refcount entries that we may have already seen to - the symbol which just became indirect. */ - edir->elf.got.refcount += eind->elf.got.refcount; - eind->elf.got.refcount = 0; - - /* And plt entries. */ - if (eind->elf.plt.plist != NULL) - { - if (edir->elf.plt.plist != NULL) - { - struct plt_entry **entp; - struct plt_entry *ent; - - for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; ) - { - struct plt_entry *dent; - - for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next) - if (dent->sec == ent->sec && dent->addend == ent->addend) - { - dent->plt.refcount += ent->plt.refcount; - *entp = ent->next; - break; - } - if (dent == NULL) - entp = &ent->next; - } - *entp = edir->elf.plt.plist; - } - - edir->elf.plt.plist = eind->elf.plt.plist; - eind->elf.plt.plist = NULL; - } - - if (eind->elf.dynindx != -1) - { - if (edir->elf.dynindx != -1) - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - edir->elf.dynstr_index); - edir->elf.dynindx = eind->elf.dynindx; - edir->elf.dynstr_index = eind->elf.dynstr_index; - eind->elf.dynindx = -1; - eind->elf.dynstr_index = 0; - } -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it to put .comm items in .sbss, and not .bss. */ - -static bfd_boolean -ppc_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && is_ppc_elf (info->output_bfd) - && sym->st_size <= elf_gp_size (abfd)) - { - /* Common symbols less than or equal to -G nn bytes are automatically - put into .sbss. */ - struct ppc_elf_link_hash_table *htab; - - htab = ppc_elf_hash_table (info); - if (htab->sbss == NULL) - { - flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; - - if (!htab->elf.dynobj) - htab->elf.dynobj = abfd; - - htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj, - ".sbss", - flags); - if (htab->sbss == NULL) - return FALSE; - } - - *secp = htab->sbss; - *valp = sym->st_size; - } - - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - return TRUE; -} - -/* Find a linker generated pointer with a given addend and type. */ - -static elf_linker_section_pointers_t * -elf_find_pointer_linker_section - (elf_linker_section_pointers_t *linker_pointers, - bfd_vma addend, - elf_linker_section_t *lsect) -{ - for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) - if (lsect == linker_pointers->lsect && addend == linker_pointers->addend) - return linker_pointers; - - return NULL; -} - -/* Allocate a pointer to live in a linker created section. */ - -static bfd_boolean -elf_allocate_pointer_linker_section (bfd *abfd, - elf_linker_section_t *lsect, - struct elf_link_hash_entry *h, - const Elf_Internal_Rela *rel) -{ - elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; - elf_linker_section_pointers_t *linker_section_ptr; - unsigned long r_symndx = ELF32_R_SYM (rel->r_info); - bfd_size_type amt; - - BFD_ASSERT (lsect != NULL); - - /* Is this a global symbol? */ - if (h != NULL) - { - struct ppc_elf_link_hash_entry *eh; - - /* Has this symbol already been allocated? If so, our work is done. */ - eh = (struct ppc_elf_link_hash_entry *) h; - if (elf_find_pointer_linker_section (eh->linker_section_pointer, - rel->r_addend, - lsect)) - return TRUE; - - ptr_linker_section_ptr = &eh->linker_section_pointer; - } - else - { - BFD_ASSERT (is_ppc_elf (abfd)); - - /* Allocation of a pointer to a local symbol. */ - elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); - - /* Allocate a table to hold the local symbols if first time. */ - if (!ptr) - { - unsigned int num_symbols = elf_symtab_hdr (abfd).sh_info; - - amt = num_symbols; - amt *= sizeof (elf_linker_section_pointers_t *); - ptr = bfd_zalloc (abfd, amt); - - if (!ptr) - return FALSE; - - elf_local_ptr_offsets (abfd) = ptr; - } - - /* Has this symbol already been allocated? If so, our work is done. */ - if (elf_find_pointer_linker_section (ptr[r_symndx], - rel->r_addend, - lsect)) - return TRUE; - - ptr_linker_section_ptr = &ptr[r_symndx]; - } - - /* Allocate space for a pointer in the linker section, and allocate - a new pointer record from internal memory. */ - BFD_ASSERT (ptr_linker_section_ptr != NULL); - amt = sizeof (elf_linker_section_pointers_t); - linker_section_ptr = bfd_alloc (abfd, amt); - - if (!linker_section_ptr) - return FALSE; - - linker_section_ptr->next = *ptr_linker_section_ptr; - linker_section_ptr->addend = rel->r_addend; - linker_section_ptr->lsect = lsect; - *ptr_linker_section_ptr = linker_section_ptr; - - if (!bfd_set_section_alignment (lsect->section->owner, lsect->section, 2)) - return FALSE; - linker_section_ptr->offset = lsect->section->size; - lsect->section->size += 4; - -#ifdef DEBUG - fprintf (stderr, - "Create pointer in linker section %s, offset = %ld, section size = %ld\n", - lsect->name, (long) linker_section_ptr->offset, - (long) lsect->section->size); -#endif - - return TRUE; -} - -static struct plt_entry ** -update_local_sym_info (bfd *abfd, - Elf_Internal_Shdr *symtab_hdr, - unsigned long r_symndx, - int tls_type) -{ - bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); - struct plt_entry **local_plt; - char *local_got_tls_masks; - - if (local_got_refcounts == NULL) - { - bfd_size_type size = symtab_hdr->sh_info; - - size *= (sizeof (*local_got_refcounts) - + sizeof (*local_plt) - + sizeof (*local_got_tls_masks)); - local_got_refcounts = bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return NULL; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - - local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info); - local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info); - local_got_tls_masks[r_symndx] |= tls_type; - if (tls_type != PLT_IFUNC) - local_got_refcounts[r_symndx] += 1; - return local_plt + r_symndx; -} - -static bfd_boolean -update_plt_info (bfd *abfd, struct plt_entry **plist, - asection *sec, bfd_vma addend) -{ - struct plt_entry *ent; - - if (addend < 32768) - sec = NULL; - for (ent = *plist; ent != NULL; ent = ent->next) - if (ent->sec == sec && ent->addend == addend) - break; - if (ent == NULL) - { - bfd_size_type amt = sizeof (*ent); - ent = bfd_alloc (abfd, amt); - if (ent == NULL) - return FALSE; - ent->next = *plist; - ent->sec = sec; - ent->addend = addend; - ent->plt.refcount = 0; - *plist = ent; - } - ent->plt.refcount += 1; - return TRUE; -} - -static struct plt_entry * -find_plt_ent (struct plt_entry **plist, asection *sec, bfd_vma addend) -{ - struct plt_entry *ent; - - if (addend < 32768) - sec = NULL; - for (ent = *plist; ent != NULL; ent = ent->next) - if (ent->sec == sec && ent->addend == addend) - break; - return ent; -} - -static bfd_boolean -is_branch_reloc (enum elf_ppc_reloc_type r_type) -{ - return (r_type == R_PPC_PLTREL24 - || r_type == R_PPC_LOCAL24PC - || r_type == R_PPC_REL24 - || r_type == R_PPC_REL14 - || r_type == R_PPC_REL14_BRTAKEN - || r_type == R_PPC_REL14_BRNTAKEN - || r_type == R_PPC_ADDR24 - || r_type == R_PPC_ADDR14 - || r_type == R_PPC_ADDR14_BRTAKEN - || r_type == R_PPC_ADDR14_BRNTAKEN - || r_type == R_PPC_VLE_REL24); -} - -static void -bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type) -{ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s cannot be used when making a shared object"), - abfd, - ppc_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -ppc_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct ppc_elf_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 *got2, *sreloc; - struct elf_link_hash_entry *tga; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - -#ifdef DEBUG - _bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B", - sec, abfd); -#endif - - BFD_ASSERT (is_ppc_elf (abfd)); - - /* Initialize howto table if not already done. */ - if (!ppc_elf_howto_table[R_PPC_ADDR32]) - ppc_elf_howto_init (); - - htab = ppc_elf_hash_table (info); - if (htab->glink == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!ppc_elf_create_glink (htab->elf.dynobj, info)) - return FALSE; - } - tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", - FALSE, FALSE, TRUE); - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - got2 = bfd_get_section_by_name (abfd, ".got2"); - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned long r_symndx; - enum elf_ppc_reloc_type r_type; - struct elf_link_hash_entry *h; - int tls_type; - struct plt_entry **ifunc; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. - This shows up in particular in an R_PPC_ADDR32 in the eabi - startup code. */ - if (h != NULL - && htab->elf.sgot == NULL - && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!ppc_elf_create_got (htab->elf.dynobj, info)) - return FALSE; - BFD_ASSERT (h == htab->elf.hgot); - } - - tls_type = 0; - r_type = ELF32_R_TYPE (rel->r_info); - ifunc = NULL; - if (h == NULL && !htab->is_vxworks) - { - Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - /* Set PLT_IFUNC flag for this sym, no GOT entry yet. */ - ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, - PLT_IFUNC); - if (ifunc == NULL) - return FALSE; - - /* STT_GNU_IFUNC symbols must have a PLT entry; - In a non-pie executable even when there are - no plt calls. */ - if (!bfd_link_pic (info) - || is_branch_reloc (r_type)) - { - bfd_vma addend = 0; - if (r_type == R_PPC_PLTREL24) - { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (bfd_link_pic (info)) - addend = rel->r_addend; - } - if (!update_plt_info (abfd, ifunc, got2, addend)) - return FALSE; - } - } - } - - if (!htab->is_vxworks - && is_branch_reloc (r_type) - && h != NULL - && h == tga) - { - if (rel != relocs - && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD - || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD)) - /* We have a new-style __tls_get_addr call with a marker - reloc. */ - ; - else - /* Mark this section as having an old-style call. */ - sec->has_tls_get_addr_call = 1; - } - - switch (r_type) - { - case R_PPC_TLSGD: - case R_PPC_TLSLD: - /* These special tls relocs tie a call to __tls_get_addr with - its parameter symbol. */ - break; - - case R_PPC_GOT_TLSLD16: - case R_PPC_GOT_TLSLD16_LO: - case R_PPC_GOT_TLSLD16_HI: - case R_PPC_GOT_TLSLD16_HA: - tls_type = TLS_TLS | TLS_LD; - goto dogottls; - - case R_PPC_GOT_TLSGD16: - case R_PPC_GOT_TLSGD16_LO: - case R_PPC_GOT_TLSGD16_HI: - case R_PPC_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD; - goto dogottls; - - case R_PPC_GOT_TPREL16: - case R_PPC_GOT_TPREL16_LO: - case R_PPC_GOT_TPREL16_HI: - case R_PPC_GOT_TPREL16_HA: - if (bfd_link_dll (info)) - info->flags |= DF_STATIC_TLS; - tls_type = TLS_TLS | TLS_TPREL; - goto dogottls; - - case R_PPC_GOT_DTPREL16: - case R_PPC_GOT_DTPREL16_LO: - case R_PPC_GOT_DTPREL16_HI: - case R_PPC_GOT_DTPREL16_HA: - tls_type = TLS_TLS | TLS_DTPREL; - dogottls: - sec->has_tls_reloc = 1; - /* Fall through. */ - - /* GOT16 relocations */ - case R_PPC_GOT16: - case R_PPC_GOT16_LO: - case R_PPC_GOT16_HI: - case R_PPC_GOT16_HA: - /* This symbol requires a global offset table entry. */ - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!ppc_elf_create_got (htab->elf.dynobj, info)) - return FALSE; - } - if (h != NULL) - { - h->got.refcount += 1; - ppc_elf_hash_entry (h)->tls_mask |= tls_type; - } - else - /* This is a global offset table entry for a local symbol. */ - if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type)) - return FALSE; - - /* We may also need a plt entry if the symbol turns out to be - an ifunc. */ - if (h != NULL && !bfd_link_pic (info)) - { - if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) - return FALSE; - } - break; - - /* Indirect .sdata relocation. */ - case R_PPC_EMB_SDAI16: - if (bfd_link_pic (info)) - { - bad_shared_reloc (abfd, r_type); - return FALSE; - } - htab->sdata[0].sym->ref_regular = 1; - if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[0], - h, rel)) - return FALSE; - if (h != NULL) - { - ppc_elf_hash_entry (h)->has_sda_refs = TRUE; - h->non_got_ref = TRUE; - } - break; - - /* Indirect .sdata2 relocation. */ - case R_PPC_EMB_SDA2I16: - if (bfd_link_pic (info)) - { - bad_shared_reloc (abfd, r_type); - return FALSE; - } - htab->sdata[1].sym->ref_regular = 1; - if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[1], - h, rel)) - return FALSE; - if (h != NULL) - { - ppc_elf_hash_entry (h)->has_sda_refs = TRUE; - h->non_got_ref = TRUE; - } - break; - - case R_PPC_SDAREL16: - htab->sdata[0].sym->ref_regular = 1; - /* Fall through. */ - - case R_PPC_VLE_SDAREL_LO16A: - case R_PPC_VLE_SDAREL_LO16D: - case R_PPC_VLE_SDAREL_HI16A: - case R_PPC_VLE_SDAREL_HI16D: - case R_PPC_VLE_SDAREL_HA16A: - case R_PPC_VLE_SDAREL_HA16D: - if (h != NULL) - { - ppc_elf_hash_entry (h)->has_sda_refs = TRUE; - h->non_got_ref = TRUE; - } - break; - - case R_PPC_VLE_REL8: - case R_PPC_VLE_REL15: - case R_PPC_VLE_REL24: - case R_PPC_VLE_LO16A: - case R_PPC_VLE_LO16D: - case R_PPC_VLE_HI16A: - case R_PPC_VLE_HI16D: - case R_PPC_VLE_HA16A: - case R_PPC_VLE_HA16D: - case R_PPC_VLE_ADDR20: - break; - - case R_PPC_EMB_SDA2REL: - if (bfd_link_pic (info)) - { - bad_shared_reloc (abfd, r_type); - return FALSE; - } - htab->sdata[1].sym->ref_regular = 1; - if (h != NULL) - { - ppc_elf_hash_entry (h)->has_sda_refs = TRUE; - h->non_got_ref = TRUE; - } - break; - - case R_PPC_VLE_SDA21_LO: - case R_PPC_VLE_SDA21: - case R_PPC_EMB_SDA21: - case R_PPC_EMB_RELSDA: - if (bfd_link_pic (info)) - { - bad_shared_reloc (abfd, r_type); - return FALSE; - } - if (h != NULL) - { - ppc_elf_hash_entry (h)->has_sda_refs = TRUE; - h->non_got_ref = TRUE; - } - break; - - case R_PPC_EMB_NADDR32: - case R_PPC_EMB_NADDR16: - case R_PPC_EMB_NADDR16_LO: - case R_PPC_EMB_NADDR16_HI: - case R_PPC_EMB_NADDR16_HA: - if (bfd_link_pic (info)) - { - bad_shared_reloc (abfd, r_type); - return FALSE; - } - if (h != NULL) - h->non_got_ref = TRUE; - break; - - case R_PPC_PLTREL24: - if (h == NULL) - break; - /* Fall through */ - case R_PPC_PLT32: - case R_PPC_PLTREL32: - case R_PPC_PLT16_LO: - case R_PPC_PLT16_HI: - case R_PPC_PLT16_HA: -#ifdef DEBUG - fprintf (stderr, "Reloc requires a PLT entry\n"); -#endif - /* This symbol requires a procedure linkage table entry. */ - if (h == NULL) - { - if (ifunc == NULL) - { - /* It does not make sense to have a procedure linkage - table entry for a non-ifunc local symbol. */ - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s reloc against local symbol\n"), - abfd, sec, rel->r_offset, - ppc_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - else - { - bfd_vma addend = 0; - - if (r_type == R_PPC_PLTREL24) - { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (bfd_link_pic (info)) - addend = rel->r_addend; - } - h->needs_plt = 1; - if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) - return FALSE; - } - break; - - /* The following relocations don't need to propagate the - relocation if linking a shared object since they are - section relative. */ - case R_PPC_SECTOFF: - case R_PPC_SECTOFF_LO: - case R_PPC_SECTOFF_HI: - case R_PPC_SECTOFF_HA: - case R_PPC_DTPREL16: - case R_PPC_DTPREL16_LO: - case R_PPC_DTPREL16_HI: - case R_PPC_DTPREL16_HA: - case R_PPC_TOC16: - break; - - case R_PPC_REL16: - case R_PPC_REL16_LO: - case R_PPC_REL16_HI: - case R_PPC_REL16_HA: - case R_PPC_REL16DX_HA: - ppc_elf_tdata (abfd)->has_rel16 = 1; - break; - - /* These are just markers. */ - case R_PPC_TLS: - case R_PPC_EMB_MRKREF: - case R_PPC_NONE: - case R_PPC_max: - case R_PPC_RELAX: - case R_PPC_RELAX_PLT: - case R_PPC_RELAX_PLTREL24: - case R_PPC_16DX_HA: - break; - - /* These should only appear in dynamic objects. */ - case R_PPC_COPY: - case R_PPC_GLOB_DAT: - case R_PPC_JMP_SLOT: - case R_PPC_RELATIVE: - case R_PPC_IRELATIVE: - break; - - /* These aren't handled yet. We'll report an error later. */ - case R_PPC_ADDR30: - case R_PPC_EMB_RELSEC16: - case R_PPC_EMB_RELST_LO: - case R_PPC_EMB_RELST_HI: - case R_PPC_EMB_RELST_HA: - case R_PPC_EMB_BIT_FLD: - break; - - /* This refers only to functions defined in the shared library. */ - case R_PPC_LOCAL24PC: - if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET) - { - htab->plt_type = PLT_OLD; - htab->old_bfd = abfd; - } - if (h != NULL && h->type == STT_GNU_IFUNC) - { - h->needs_plt = 1; - if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) - return FALSE; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_PPC_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_PPC_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - /* We shouldn't really be seeing TPREL32. */ - case R_PPC_TPREL32: - case R_PPC_TPREL16: - case R_PPC_TPREL16_LO: - case R_PPC_TPREL16_HI: - case R_PPC_TPREL16_HA: - if (bfd_link_dll (info)) - info->flags |= DF_STATIC_TLS; - goto dodyn; - - /* Nor these. */ - case R_PPC_DTPMOD32: - case R_PPC_DTPREL32: - goto dodyn; - - case R_PPC_REL32: - if (h == NULL - && got2 != NULL - && (sec->flags & SEC_CODE) != 0 - && bfd_link_pic (info) - && htab->plt_type == PLT_UNSET) - { - /* Old -fPIC gcc code has .long LCTOC1-LCFx just before - the start of a function, which assembles to a REL32 - reference to .got2. If we detect one of these, then - force the old PLT layout because the linker cannot - reliably deduce the GOT pointer value needed for - PLT call stubs. */ - asection *s; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == got2) - { - htab->plt_type = PLT_OLD; - htab->old_bfd = abfd; - } - } - if (h == NULL || h == htab->elf.hgot) - break; - /* fall through */ - - case R_PPC_ADDR32: - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR16_HA: - case R_PPC_UADDR32: - case R_PPC_UADDR16: - if (h != NULL && !bfd_link_pic (info)) - { - /* We may need a plt entry if the symbol turns out to be - a function defined in a dynamic object. */ - if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) - return FALSE; - - /* We may need a copy reloc too. */ - h->non_got_ref = 1; - h->pointer_equality_needed = 1; - if (r_type == R_PPC_ADDR16_HA) - ppc_elf_hash_entry (h)->has_addr16_ha = 1; - if (r_type == R_PPC_ADDR16_LO) - ppc_elf_hash_entry (h)->has_addr16_lo = 1; - } - goto dodyn; - - case R_PPC_REL24: - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - if (h == NULL) - break; - if (h == htab->elf.hgot) - { - if (htab->plt_type == PLT_UNSET) - { - htab->plt_type = PLT_OLD; - htab->old_bfd = abfd; - } - break; - } - /* fall through */ - - case R_PPC_ADDR24: - case R_PPC_ADDR14: - case R_PPC_ADDR14_BRTAKEN: - case R_PPC_ADDR14_BRNTAKEN: - if (h != NULL && !bfd_link_pic (info)) - { - /* We may need a plt entry if the symbol turns out to be - a function defined in a dynamic object. */ - h->needs_plt = 1; - if (!update_plt_info (abfd, &h->plt.plist, NULL, 0)) - return FALSE; - break; - } - - dodyn: - /* 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 dyn_relocs field of the hash - table entry. A similar situation occurs when creating - shared libraries and symbol visibility changes render the - symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (must_be_dyn_reloc (info, r_type) - || (h != NULL - && (!SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { -#ifdef DEBUG - fprintf (stderr, - "ppc_elf_check_relocs needs to " - "create relocation for %s\n", - (h && h->root.root.string - ? h->root.root.string : "")); -#endif - if (sreloc == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **rel_head; - - rel_head = &ppc_elf_hash_entry (h)->dyn_relocs; - p = *rel_head; - if (p == NULL || p->sec != sec) - { - p = bfd_alloc (htab->elf.dynobj, sizeof *p); - if (p == NULL) - return FALSE; - p->next = *rel_head; - *rel_head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - p->count += 1; - if (!must_be_dyn_reloc (info, r_type)) - p->pc_count += 1; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - struct ppc_dyn_relocs *p; - struct ppc_dyn_relocs **rel_head; - bfd_boolean is_ifunc; - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - rel_head = (struct ppc_dyn_relocs **) vpp; - is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC; - p = *rel_head; - if (p != NULL && p->sec == sec && p->ifunc != is_ifunc) - p = p->next; - if (p == NULL || p->sec != sec || p->ifunc != is_ifunc) - { - p = bfd_alloc (htab->elf.dynobj, sizeof *p); - if (p == NULL) - return FALSE; - p->next = *rel_head; - *rel_head = p; - p->sec = sec; - p->ifunc = is_ifunc; - p->count = 0; - } - p->count += 1; - } - } - - break; - } - } - - return TRUE; -} - -/* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD - and OBFD, and merge non-conflicting ones. */ -void -_bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - obj_attribute *in_attr, *in_attrs; - obj_attribute *out_attr, *out_attrs; - - in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; - out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; - - in_attr = &in_attrs[Tag_GNU_Power_ABI_FP]; - out_attr = &out_attrs[Tag_GNU_Power_ABI_FP]; - - if (in_attr->i != out_attr->i) - { - int in_fp = in_attr->i & 3; - int out_fp = out_attr->i & 3; - - if (in_fp == 0) - ; - else if (out_fp == 0) - { - out_attr->type = 1; - out_attr->i ^= in_fp; - } - else if (out_fp != 2 && in_fp == 2) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd); - else if (out_fp == 2 && in_fp != 2) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd); - else if (out_fp == 1 && in_fp == 3) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses double-precision hard float, " - "%B uses single-precision hard float"), obfd, ibfd); - else if (out_fp == 3 && in_fp == 1) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses double-precision hard float, " - "%B uses single-precision hard float"), ibfd, obfd); - - in_fp = in_attr->i & 0xc; - out_fp = out_attr->i & 0xc; - if (in_fp == 0) - ; - else if (out_fp == 0) - { - out_attr->type = 1; - out_attr->i ^= in_fp; - } - else if (out_fp != 2 * 4 && in_fp == 2 * 4) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses 64-bit long double, " - "%B uses 128-bit long double"), ibfd, obfd); - else if (in_fp != 2 * 4 && out_fp == 2 * 4) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses 64-bit long double, " - "%B uses 128-bit long double"), obfd, ibfd); - else if (out_fp == 1 * 4 && in_fp == 3 * 4) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses IBM long double, " - "%B uses IEEE long double"), ibfd, obfd); - else if (out_fp == 3 * 4 && in_fp == 1 * 4) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses IBM long double, " - "%B uses IEEE long double"), obfd, ibfd); - } -} - -/* Merge object attributes from IBFD into OBFD. Warn if - there are conflicting attributes. */ -static bfd_boolean -ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd; - obj_attribute *in_attr, *in_attrs; - obj_attribute *out_attr, *out_attrs; - - _bfd_elf_ppc_merge_fp_attributes (ibfd, info); - - obfd = info->output_bfd; - in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; - out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; - - /* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and - merge non-conflicting ones. */ - in_attr = &in_attrs[Tag_GNU_Power_ABI_Vector]; - out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector]; - if (in_attr->i != out_attr->i) - { - int in_vec = in_attr->i & 3; - int out_vec = out_attr->i & 3; - - if (in_vec == 0) - ; - else if (out_vec == 0) - { - out_attr->type = 1; - out_attr->i = in_vec; - } - /* For now, allow generic to transition to AltiVec or SPE - without a warning. If GCC marked files with their stack - alignment and used don't-care markings for files which are - not affected by the vector ABI, we could warn about this - case too. */ - else if (in_vec == 1) - ; - else if (out_vec == 1) - { - out_attr->type = 1; - out_attr->i = in_vec; - } - else if (out_vec < in_vec) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"), - obfd, ibfd); - else if (out_vec > in_vec) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"), - ibfd, obfd); - } - - /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes - and merge non-conflicting ones. */ - in_attr = &in_attrs[Tag_GNU_Power_ABI_Struct_Return]; - out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return]; - if (in_attr->i != out_attr->i) - { - int in_struct = in_attr->i & 3; - int out_struct = out_attr->i & 3; - - if (in_struct == 0 || in_struct == 3) - ; - else if (out_struct == 0) - { - out_attr->type = 1; - out_attr->i = in_struct; - } - else if (out_struct < in_struct) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses r3/r4 for small structure returns, " - "%B uses memory"), obfd, ibfd); - else if (out_struct > in_struct) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: %B uses r3/r4 for small structure returns, " - "%B uses memory"), ibfd, obfd); - } - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - _bfd_elf_merge_object_attributes (ibfd, info); - - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - bfd_boolean error; - - if (!is_ppc_elf (ibfd) || !is_ppc_elf (obfd)) - return TRUE; - - /* Check if we have the same endianness. */ - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if (!ppc_elf_merge_obj_attributes (ibfd, info)) - return FALSE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - - /* Compatible flags are ok. */ - else if (new_flags == old_flags) - ; - - /* Incompatible flags. */ - else - { - /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib - to be linked with either. */ - error = FALSE; - if ((new_flags & EF_PPC_RELOCATABLE) != 0 - && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) - { - error = TRUE; - _bfd_error_handler - (_("%B: compiled with -mrelocatable and linked with " - "modules compiled normally"), ibfd); - } - else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 - && (old_flags & EF_PPC_RELOCATABLE) != 0) - { - error = TRUE; - _bfd_error_handler - (_("%B: compiled normally and linked with " - "modules compiled with -mrelocatable"), ibfd); - } - - /* The output is -mrelocatable-lib iff both the input files are. */ - if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) - elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; - - /* The output is -mrelocatable iff it can't be -mrelocatable-lib, - but each input file is either -mrelocatable or -mrelocatable-lib. */ - if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) - && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) - && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) - elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; - - /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if - any module uses it. */ - elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); - - new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); - old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); - - /* Warn about any other mismatches. */ - if (new_flags != old_flags) - { - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields " - "than previous modules (%#x)"), - ibfd, new_flags, old_flags); - } - - if (error) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - return TRUE; -} - -static void -ppc_elf_vle_split16 (bfd *input_bfd, - asection *input_section, - unsigned long offset, - bfd_byte *loc, - bfd_vma value, - split16_format_type split16_format, - bfd_boolean fixup) -{ - unsigned int insn, opcode, top5; - - insn = bfd_get_32 (input_bfd, loc); - opcode = insn & 0xfc00f800; - if (opcode == E_OR2I_INSN - || opcode == E_AND2I_DOT_INSN - || opcode == E_OR2IS_INSN - || opcode == E_LIS_INSN - || opcode == E_AND2IS_DOT_INSN) - { - if (split16_format != split16a_type) - { - if (fixup) - split16_format = split16a_type; - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+0x%lx): expected 16A style relocation on 0x%08x insn"), - input_bfd, input_section, offset, opcode); - } - } - else if (opcode == E_ADD2I_DOT_INSN - || opcode == E_ADD2IS_INSN - || opcode == E_CMP16I_INSN - || opcode == E_MULL2I_INSN - || opcode == E_CMPL16I_INSN - || opcode == E_CMPH16I_INSN - || opcode == E_CMPHL16I_INSN) - { - if (split16_format != split16d_type) - { - if (fixup) - split16_format = split16d_type; - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+0x%lx): expected 16D style relocation on 0x%08x insn"), - input_bfd, input_section, offset, opcode); - } - } - top5 = value & 0xf800; - top5 = top5 << (split16_format == split16a_type ? 5 : 10); - insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x3e007ff); - insn |= top5; - insn |= value & 0x7ff; - bfd_put_32 (input_bfd, insn, loc); -} - -static void -ppc_elf_vle_split20 (bfd *output_bfd, bfd_byte *loc, bfd_vma value) -{ - unsigned int insn; - - insn = bfd_get_32 (output_bfd, loc); - /* We have an li20 field, bits 17..20, 11..15, 21..31. */ - /* Top 4 bits of value to 17..20. */ - insn |= (value & 0xf0000) >> 5; - /* Next 5 bits of the value to 11..15. */ - insn |= (value & 0xf800) << 5; - /* And the final 11 bits of the value to bits 21 to 31. */ - insn |= value & 0x7ff; - bfd_put_32 (output_bfd, insn, loc); -} - - -/* Choose which PLT scheme to use, and set .plt flags appropriately. - Returns -1 on error, 0 for old PLT, 1 for new PLT. */ -int -ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab; - flagword flags; - - htab = ppc_elf_hash_table (info); - - if (htab->plt_type == PLT_UNSET) - { - struct elf_link_hash_entry *h; - - if (htab->params->plt_style == PLT_OLD) - htab->plt_type = PLT_OLD; - else if (bfd_link_pic (info) - && htab->elf.dynamic_sections_created - && (h = elf_link_hash_lookup (&htab->elf, "_mcount", - FALSE, FALSE, TRUE)) != NULL - && (h->type == STT_FUNC - || h->needs_plt) - && h->ref_regular - && !(SYMBOL_CALLS_LOCAL (info, h) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) - { - /* Profiling of shared libs (and pies) is not supported with - secure plt, because ppc32 does profiling before a - function prologue and a secure plt pic call stubs needs - r30 to be set up. */ - htab->plt_type = PLT_OLD; - } - else - { - bfd *ibfd; - enum ppc_elf_plt_type plt_type = htab->params->plt_style; - - /* Look through the reloc flags left by ppc_elf_check_relocs. - Use the old style bss plt if a file makes plt calls - without using the new relocs, and if ld isn't given - --secure-plt and we never see REL16 relocs. */ - if (plt_type == PLT_UNSET) - plt_type = PLT_OLD; - for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) - if (is_ppc_elf (ibfd)) - { - if (ppc_elf_tdata (ibfd)->has_rel16) - plt_type = PLT_NEW; - else if (ppc_elf_tdata (ibfd)->makes_plt_call) - { - plt_type = PLT_OLD; - htab->old_bfd = ibfd; - break; - } - } - htab->plt_type = plt_type; - } - } - if (htab->plt_type == PLT_OLD && htab->params->plt_style == PLT_NEW) - { - if (htab->old_bfd != NULL) - info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"), - htab->old_bfd); - else - info->callbacks->einfo (_("%P: bss-plt forced by profiling\n")); - } - - BFD_ASSERT (htab->plt_type != PLT_VXWORKS); - - if (htab->plt_type == PLT_NEW) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - - /* The new PLT is a loaded section. */ - if (htab->elf.splt != NULL - && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.splt, flags)) - return -1; - - /* The new GOT is not executable. */ - if (htab->elf.sgot != NULL - && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.sgot, flags)) - return -1; - } - else - { - /* Stop an unused .glink section from affecting .text alignment. */ - if (htab->glink != NULL - && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0)) - return -1; - } - return htab->plt_type == PLT_NEW; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -ppc_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_PPC_GNU_VTINHERIT: - case R_PPC_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Set plt output section type, htab->tls_get_addr, and call the - generic ELF tls_setup function. */ - -asection * -ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab; - - htab = ppc_elf_hash_table (info); - htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", - FALSE, FALSE, TRUE); - if (htab->plt_type != PLT_NEW) - htab->params->no_tls_get_addr_opt = TRUE; - - if (!htab->params->no_tls_get_addr_opt) - { - struct elf_link_hash_entry *opt, *tga; - opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", - FALSE, FALSE, TRUE); - if (opt != NULL - && (opt->root.type == bfd_link_hash_defined - || opt->root.type == bfd_link_hash_defweak)) - { - /* If glibc supports an optimized __tls_get_addr call stub, - signalled by the presence of __tls_get_addr_opt, and we'll - be calling __tls_get_addr via a plt call stub, then - make __tls_get_addr point to __tls_get_addr_opt. */ - tga = htab->tls_get_addr; - if (htab->elf.dynamic_sections_created - && tga != NULL - && (tga->type == STT_FUNC - || tga->needs_plt) - && !(SYMBOL_CALLS_LOCAL (info, tga) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga))) - { - struct plt_entry *ent; - for (ent = tga->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; - if (ent != NULL) - { - tga->root.type = bfd_link_hash_indirect; - tga->root.u.i.link = &opt->root; - ppc_elf_copy_indirect_symbol (info, opt, tga); - opt->mark = 1; - if (opt->dynindx != -1) - { - /* Use __tls_get_addr_opt in dynamic relocations. */ - opt->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - opt->dynstr_index); - if (!bfd_elf_link_record_dynamic_symbol (info, opt)) - return FALSE; - } - htab->tls_get_addr = opt; - } - } - } - else - htab->params->no_tls_get_addr_opt = TRUE; - } - if (htab->plt_type == PLT_NEW - && htab->elf.splt != NULL - && htab->elf.splt->output_section != NULL) - { - elf_section_type (htab->elf.splt->output_section) = SHT_PROGBITS; - elf_section_flags (htab->elf.splt->output_section) = SHF_ALLOC + SHF_WRITE; - } - - return _bfd_elf_tls_setup (obfd, info); -} - -/* Return TRUE iff REL is a branch reloc with a global symbol matching - HASH. */ - -static bfd_boolean -branch_reloc_hash_match (const bfd *ibfd, - const Elf_Internal_Rela *rel, - const struct elf_link_hash_entry *hash) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); - enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info); - unsigned int r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type)) - { - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); - struct elf_link_hash_entry *h; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - if (h == hash) - return TRUE; - } - return FALSE; -} - -/* Run through all the TLS relocs looking for optimization - opportunities. */ - -bfd_boolean -ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *ibfd; - asection *sec; - struct ppc_elf_link_hash_table *htab; - int pass; - - if (!bfd_link_executable (info)) - return TRUE; - - htab = ppc_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Make two passes through the relocs. First time check that tls - relocs involved in setting up a tls_get_addr call are indeed - followed by such a call. If they are not, don't do any tls - optimization. On the second pass twiddle tls_mask flags to - notify relocate_section that optimization can be done, and - adjust got and plt refcounts. */ - for (pass = 0; pass < 2; ++pass) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - Elf_Internal_Sym *locsyms = NULL; - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); - asection *got2 = bfd_get_section_by_name (ibfd, ".got2"); - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) - { - Elf_Internal_Rela *relstart, *rel, *relend; - int expecting_tls_get_addr = 0; - - /* Read the relocations. */ - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - return FALSE; - - relend = relstart + sec->reloc_count; - for (rel = relstart; rel < relend; rel++) - { - enum elf_ppc_reloc_type r_type; - unsigned long r_symndx; - struct elf_link_hash_entry *h = NULL; - char *tls_mask; - char tls_set, tls_clear; - bfd_boolean is_local; - bfd_signed_vma *got_count; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - struct elf_link_hash_entry **sym_hashes; - - sym_hashes = elf_sym_hashes (ibfd); - 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; - } - - is_local = FALSE; - if (h == NULL - || !h->def_dynamic) - is_local = TRUE; - - r_type = ELF32_R_TYPE (rel->r_info); - /* If this section has old-style __tls_get_addr calls - without marker relocs, then check that each - __tls_get_addr call reloc is preceded by a reloc - that conceivably belongs to the __tls_get_addr arg - setup insn. If we don't find matching arg setup - relocs, don't do any tls optimization. */ - if (pass == 0 - && sec->has_tls_get_addr_call - && h != NULL - && h == htab->tls_get_addr - && !expecting_tls_get_addr - && is_branch_reloc (r_type)) - { - info->callbacks->minfo ("%H __tls_get_addr lost arg, " - "TLS optimization disabled\n", - ibfd, sec, rel->r_offset); - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - return TRUE; - } - - expecting_tls_get_addr = 0; - switch (r_type) - { - case R_PPC_GOT_TLSLD16: - case R_PPC_GOT_TLSLD16_LO: - expecting_tls_get_addr = 1; - /* Fall through. */ - - case R_PPC_GOT_TLSLD16_HI: - case R_PPC_GOT_TLSLD16_HA: - /* These relocs should never be against a symbol - defined in a shared lib. Leave them alone if - that turns out to be the case. */ - if (!is_local) - continue; - - /* LD -> LE */ - tls_set = 0; - tls_clear = TLS_LD; - break; - - case R_PPC_GOT_TLSGD16: - case R_PPC_GOT_TLSGD16_LO: - expecting_tls_get_addr = 1; - /* Fall through. */ - - case R_PPC_GOT_TLSGD16_HI: - case R_PPC_GOT_TLSGD16_HA: - if (is_local) - /* GD -> LE */ - tls_set = 0; - else - /* GD -> IE */ - tls_set = TLS_TLS | TLS_TPRELGD; - tls_clear = TLS_GD; - break; - - case R_PPC_GOT_TPREL16: - case R_PPC_GOT_TPREL16_LO: - case R_PPC_GOT_TPREL16_HI: - case R_PPC_GOT_TPREL16_HA: - if (is_local) - { - /* IE -> LE */ - tls_set = 0; - tls_clear = TLS_TPREL; - break; - } - else - continue; - - case R_PPC_TLSGD: - case R_PPC_TLSLD: - expecting_tls_get_addr = 2; - tls_set = 0; - tls_clear = 0; - break; - - default: - continue; - } - - if (pass == 0) - { - if (!expecting_tls_get_addr - || (expecting_tls_get_addr == 1 - && !sec->has_tls_get_addr_call)) - continue; - - if (rel + 1 < relend - && branch_reloc_hash_match (ibfd, rel + 1, - htab->tls_get_addr)) - continue; - - /* Uh oh, we didn't find the expected call. We - could just mark this symbol to exclude it - from tls optimization but it's safer to skip - the entire optimization. */ - info->callbacks->minfo (_("%H arg lost __tls_get_addr, " - "TLS optimization disabled\n"), - ibfd, sec, rel->r_offset); - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - return TRUE; - } - - if (expecting_tls_get_addr) - { - struct plt_entry *ent; - bfd_vma addend = 0; - - if (bfd_link_pic (info) - && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24) - addend = rel[1].r_addend; - ent = find_plt_ent (&htab->tls_get_addr->plt.plist, - got2, addend); - if (ent != NULL && ent->plt.refcount > 0) - ent->plt.refcount -= 1; - - if (expecting_tls_get_addr == 2) - continue; - } - - if (h != NULL) - { - tls_mask = &ppc_elf_hash_entry (h)->tls_mask; - got_count = &h->got.refcount; - } - else - { - bfd_signed_vma *lgot_refs; - struct plt_entry **local_plt; - char *lgot_masks; - - if (locsyms == NULL) - { - locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (locsyms == NULL) - locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, - symtab_hdr->sh_info, - 0, NULL, NULL, NULL); - if (locsyms == NULL) - { - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - return FALSE; - } - } - lgot_refs = elf_local_got_refcounts (ibfd); - if (lgot_refs == NULL) - abort (); - local_plt = (struct plt_entry **) - (lgot_refs + symtab_hdr->sh_info); - lgot_masks = (char *) (local_plt + symtab_hdr->sh_info); - tls_mask = &lgot_masks[r_symndx]; - got_count = &lgot_refs[r_symndx]; - } - - if (tls_set == 0) - { - /* We managed to get rid of a got entry. */ - if (*got_count > 0) - *got_count -= 1; - } - - *tls_mask |= tls_set; - *tls_mask &= ~tls_clear; - } - - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - } - - if (locsyms != NULL - && (symtab_hdr->contents != (unsigned char *) locsyms)) - { - if (!info->keep_memory) - free (locsyms); - else - symtab_hdr->contents = (unsigned char *) locsyms; - } - } - htab->do_tls_opt = 1; - return TRUE; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* Return true if we have dynamic relocs against H or any of its weak - aliases, that apply to read-only sections. Cannot be used after - size_dynamic_sections. */ - -static bfd_boolean -alias_readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct ppc_elf_link_hash_entry *eh = ppc_elf_hash_entry (h); - do - { - if (readonly_dynrelocs (&eh->elf)) - return TRUE; - eh = ppc_elf_hash_entry (eh->elf.u.alias); - } while (eh != NULL && &eh->elf != h); - - return FALSE; -} - -/* Return whether H has pc-relative dynamic relocs. */ - -static bfd_boolean -pc_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - if (p->pc_count != 0) - return TRUE; - return FALSE; -} - -/* 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 -ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct ppc_elf_link_hash_table *htab; - asection *s; - -#ifdef DEBUG - fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", - h->root.root.string); -#endif - - /* Make sure we know what is going on here. */ - htab = ppc_elf_hash_table (info); - BFD_ASSERT (htab->elf.dynobj != NULL - && (h->needs_plt - || h->type == STT_GNU_IFUNC - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* Deal with function syms. */ - if (h->type == STT_FUNC - || h->type == STT_GNU_IFUNC - || h->needs_plt) - { - bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, h) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - /* Discard dyn_relocs when non-pic if we've decided that a - function symbol is local. */ - if (!bfd_link_pic (info) && local) - ppc_elf_hash_entry (h)->dyn_relocs = NULL; - - /* Clear procedure linkage table information for any symbol that - won't need a .plt entry. */ - struct plt_entry *ent; - for (ent = h->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; - if (ent == NULL - || (h->type != STT_GNU_IFUNC && local)) - { - /* A PLT entry is not required/allowed when: - - 1. We are not using ld.so; because then the PLT entry - can't be set up, so we can't use one. In this case, - ppc_elf_adjust_dynamic_symbol won't even be called. - - 2. GC has rendered the entry unused. - - 3. We know for certain that a call to this symbol - will go to this object, or will remain undefined. */ - h->plt.plist = NULL; - h->needs_plt = 0; - h->pointer_equality_needed = 0; - } - else - { - /* Taking a function's address in a read/write section - doesn't require us to define the function symbol in the - executable on a plt call stub. A dynamic reloc can - be used instead, giving better runtime performance. - (Calls via that function pointer don't need to bounce - through the plt call stub.) Similarly, use a dynamic - reloc for a weak reference when possible, allowing the - resolution of the symbol to be set at load time rather - than link time. */ - if ((h->pointer_equality_needed - || (h->non_got_ref - && !h->ref_regular_nonweak - && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))) - && !htab->is_vxworks - && !ppc_elf_hash_entry (h)->has_sda_refs - && !readonly_dynrelocs (h)) - { - h->pointer_equality_needed = 0; - /* If we haven't seen a branch reloc then we don't need - a plt entry. */ - if (!h->needs_plt) - h->plt.plist = NULL; - } - else if (!bfd_link_pic (info)) - /* We are going to be defining the function symbol on the - plt stub, so no dyn_relocs needed when non-pic. */ - ppc_elf_hash_entry (h)->dyn_relocs = NULL; - } - h->protected_def = 0; - /* Function symbols can't have copy relocs. */ - return TRUE; - } - else - h->plt.plist = NULL; - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - if (def->root.u.def.section == htab->elf.sdynbss - || def->root.u.def.section == htab->elf.sdynrelro - || def->root.u.def.section == htab->dynsbss) - ppc_elf_hash_entry (h)->dyn_relocs = NULL; - 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 (bfd_link_pic (info)) - { - h->protected_def = 0; - 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) - { - h->protected_def = 0; - return TRUE; - } - - /* Protected variables do not work with .dynbss. The copy in - .dynbss won't be used by the shared library with the protected - definition for the variable. Editing to PIC, or text relocations - are preferable to an incorrect program. */ - if (h->protected_def) - { - if (ELIMINATE_COPY_RELOCS - && ppc_elf_hash_entry (h)->has_addr16_ha - && ppc_elf_hash_entry (h)->has_addr16_lo - && htab->params->pic_fixup == 0 - && info->disable_target_specific_optimizations <= 1) - htab->params->pic_fixup = 1; - return TRUE; - } - - /* If -z nocopyreloc was given, we won't generate them either. */ - if (info->nocopyreloc) - return TRUE; - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. - We can't do this if there are any small data relocations. 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 - && !ppc_elf_hash_entry (h)->has_sda_refs - && !htab->is_vxworks - && !h->def_regular - && !alias_readonly_dynrelocs (h)) - 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. - - Of course, if the symbol is referenced using SDAREL relocs, we - must instead allocate it in .sbss. */ - if (ppc_elf_hash_entry (h)->has_sda_refs) - s = htab->dynsbss; - else if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - s = htab->elf.sdynrelro; - else - s = htab->elf.sdynbss; - BFD_ASSERT (s != NULL); - - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - /* We must generate a R_PPC_COPY reloc to tell the dynamic - linker to copy the initial value out of the dynamic object - and into the runtime process image. */ - if (ppc_elf_hash_entry (h)->has_sda_refs) - srel = htab->relsbss; - else if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - srel = htab->elf.sreldynrelro; - else - srel = htab->elf.srelbss; - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - /* We no longer want dyn_relocs. */ - ppc_elf_hash_entry (h)->dyn_relocs = NULL; - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is - xxxxxxxx.plt_call32. where xxxxxxxx is a hex number, usually 0, - specifying the addend on the plt relocation. For -fpic code, the sym - is xxxxxxxx.plt_pic32., and for -fPIC - xxxxxxxx.got2.plt_pic32.. */ - -static bfd_boolean -add_stub_sym (struct plt_entry *ent, - struct elf_link_hash_entry *h, - struct bfd_link_info *info) -{ - struct elf_link_hash_entry *sh; - size_t len1, len2, len3; - char *name; - const char *stub; - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - - if (bfd_link_pic (info)) - stub = ".plt_pic32."; - else - stub = ".plt_call32."; - - len1 = strlen (h->root.root.string); - len2 = strlen (stub); - len3 = 0; - if (ent->sec) - len3 = strlen (ent->sec->name); - name = bfd_malloc (len1 + len2 + len3 + 9); - if (name == NULL) - return FALSE; - sprintf (name, "%08x", (unsigned) ent->addend & 0xffffffff); - if (ent->sec) - memcpy (name + 8, ent->sec->name, len3); - memcpy (name + 8 + len3, stub, len2); - memcpy (name + 8 + len3 + len2, h->root.root.string, len1 + 1); - sh = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); - if (sh == NULL) - return FALSE; - if (sh->root.type == bfd_link_hash_new) - { - sh->root.type = bfd_link_hash_defined; - sh->root.u.def.section = htab->glink; - sh->root.u.def.value = ent->glink_offset; - sh->ref_regular = 1; - sh->def_regular = 1; - sh->ref_regular_nonweak = 1; - sh->forced_local = 1; - sh->non_elf = 0; - sh->root.linker_def = 1; - } - return TRUE; -} - -/* Allocate NEED contiguous space in .got, and return the offset. - Handles allocation of the got header when crossing 32k. */ - -static bfd_vma -allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) -{ - bfd_vma where; - unsigned int max_before_header; - - if (htab->plt_type == PLT_VXWORKS) - { - where = htab->elf.sgot->size; - htab->elf.sgot->size += need; - } - else - { - max_before_header = htab->plt_type == PLT_NEW ? 32768 : 32764; - if (need <= htab->got_gap) - { - where = max_before_header - htab->got_gap; - htab->got_gap -= need; - } - else - { - if (htab->elf.sgot->size + need > max_before_header - && htab->elf.sgot->size <= max_before_header) - { - htab->got_gap = max_before_header - htab->elf.sgot->size; - htab->elf.sgot->size = max_before_header + htab->got_header_size; - } - where = htab->elf.sgot->size; - htab->elf.sgot->size += need; - } - } - return where; -} - -/* Calculate size of GOT entries for symbol given its TLS_MASK. - TLS_LD is excluded because those go in a special GOT slot. */ - -static inline unsigned int -got_entries_needed (int tls_mask) -{ - unsigned int need; - if ((tls_mask & TLS_TLS) == 0) - need = 4; - else - { - need = 0; - if ((tls_mask & TLS_GD) != 0) - need += 8; - if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0) - need += 4; - if ((tls_mask & TLS_DTPREL) != 0) - need += 4; - } - return need; -} - -/* Calculate size of relocs needed for symbol given its TLS_MASK and - NEEDed GOT entries. KNOWN says a TPREL offset can be calculated at - link time. */ - -static inline unsigned int -got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known) -{ - /* All the entries we allocated need relocs. - Except IE in executable with a local symbol. We could also omit - the DTPREL reloc on the second word of a GD entry under the same - condition as that for IE, but ld.so needs to differentiate - LD and GD entries. */ - if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known) - need -= 4; - return need * sizeof (Elf32_External_Rela) / 4; -} - -/* If H is undefined, make it dynamic if that makes sense. */ - -static bfd_boolean -ensure_undef_dynamic (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (htab->dynamic_sections_created - && ((info->dynamic_undefined_weak != 0 - && h->root.type == bfd_link_hash_undefweak) - || h->root.type == bfd_link_hash_undefined) - && h->dynindx == -1 - && !h->forced_local - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - return bfd_elf_link_record_dynamic_symbol (info, h); - return TRUE; -} - -/* Allocate space in associated reloc sections for dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info = inf; - struct ppc_elf_link_hash_entry *eh; - struct ppc_elf_link_hash_table *htab; - struct elf_dyn_relocs *p; - bfd_boolean dyn; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - htab = ppc_elf_hash_table (info); - eh = (struct ppc_elf_link_hash_entry *) h; - if (eh->elf.got.refcount > 0 - || (ELIMINATE_COPY_RELOCS - && !eh->elf.def_regular - && eh->elf.protected_def - && eh->has_addr16_ha - && eh->has_addr16_lo - && htab->params->pic_fixup > 0)) - { - unsigned int need; - - /* Make sure this symbol is output as a dynamic symbol. */ - if (!ensure_undef_dynamic (info, &eh->elf)) - return FALSE; - - need = 0; - if ((eh->tls_mask & TLS_LD) != 0) - { - if (!eh->elf.def_dynamic) - /* We'll just use htab->tlsld_got.offset. This should - always be the case. It's a little odd if we have - a local dynamic reloc against a non-local symbol. */ - htab->tlsld_got.refcount += 1; - else - need += 8; - } - need += got_entries_needed (eh->tls_mask); - if (need == 0) - eh->elf.got.offset = (bfd_vma) -1; - else - { - eh->elf.got.offset = allocate_got (htab, need); - if ((bfd_link_pic (info) - || (htab->elf.dynamic_sections_created - && eh->elf.dynindx != -1 - && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf))) - && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf)) - { - asection *rsec; - bfd_boolean tprel_known = (bfd_link_executable (info) - && SYMBOL_REFERENCES_LOCAL (info, - &eh->elf)); - - need = got_relocs_needed (eh->tls_mask, need, tprel_known); - if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic) - need -= sizeof (Elf32_External_Rela); - rsec = htab->elf.srelgot; - if (eh->elf.type == STT_GNU_IFUNC) - rsec = htab->elf.irelplt; - rsec->size += need; - } - } - } - else - eh->elf.got.offset = (bfd_vma) -1; - - /* If no dynamic sections we can't have dynamic relocs, except for - IFUNCs which are handled even in static executables. */ - if (!htab->elf.dynamic_sections_created - && h->type != STT_GNU_IFUNC) - eh->dyn_relocs = NULL; - - /* Discard relocs on undefined symbols that must be local. */ - else if (h->root.type == bfd_link_hash_undefined - && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Also discard relocs on undefined weak syms with non-default - visibility, or when dynamic_undefined_weak says so. */ - else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; - - if (eh->dyn_relocs == NULL) - ; - - /* 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 relocs that have become local due to symbol visibility - changes. */ - else if (bfd_link_pic (info)) - { - /* Relocs that use pc_count are those that appear on a call insn, - or certain REL relocs (see must_be_dyn_reloc) that can be - 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 elf_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; - } - } - - if (htab->is_vxworks) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - if (eh->dyn_relocs != NULL) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (!ensure_undef_dynamic (info, h)) - return FALSE; - } - } - else if (ELIMINATE_COPY_RELOCS) - { - /* For the non-pic case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - if (h->dynamic_adjusted - && !h->def_regular - && !ELF_COMMON_DEF_P (h) - && !(h->protected_def - && eh->has_addr16_ha - && eh->has_addr16_lo - && htab->params->pic_fixup > 0)) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (!ensure_undef_dynamic (info, h)) - return FALSE; - - if (h->dynindx == -1) - eh->dyn_relocs = NULL; - } - else - eh->dyn_relocs = NULL; - } - - /* Allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - if (eh->elf.type == STT_GNU_IFUNC) - sreloc = htab->elf.irelplt; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - /* Handle PLT relocs. Done last, after dynindx has settled. */ - dyn = htab->elf.dynamic_sections_created && h->dynindx != -1; - if (dyn || h->type == STT_GNU_IFUNC) - { - struct plt_entry *ent; - bfd_boolean doneone = FALSE; - bfd_vma plt_offset = 0, glink_offset = 0; - - for (ent = h->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - { - asection *s = htab->elf.splt; - - if (!dyn) - s = htab->elf.iplt; - - if (htab->plt_type == PLT_NEW || !dyn) - { - if (!doneone) - { - plt_offset = s->size; - s->size += 4; - } - ent->plt.offset = plt_offset; - - s = htab->glink; - if (!doneone || bfd_link_pic (info)) - { - glink_offset = s->size; - s->size += GLINK_ENTRY_SIZE (htab, h); - } - if (!doneone - && !bfd_link_pic (info) - && h->def_dynamic - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = glink_offset; - } - ent->glink_offset = glink_offset; - - if (htab->params->emit_stub_syms - && !add_stub_sym (ent, h, info)) - return FALSE; - } - else - { - if (!doneone) - { - /* If this is the first .plt entry, make room - for the special first entry. */ - if (s->size == 0) - s->size += htab->plt_initial_entry_size; - - /* The PowerPC PLT is actually composed of two - parts, the first part is 2 words (for a load - and a jump), and then there is a remaining - word available at the end. */ - plt_offset = (htab->plt_initial_entry_size - + (htab->plt_slot_size - * ((s->size - - htab->plt_initial_entry_size) - / htab->plt_entry_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 to avoid text - relocations, and is required to make - function pointers compare as equal between - the normal executable and the shared library. */ - if (! bfd_link_pic (info) - && h->def_dynamic - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = plt_offset; - } - - /* Make room for this entry. */ - s->size += htab->plt_entry_size; - /* After the 8192nd entry, room for two entries - is allocated. */ - if (htab->plt_type == PLT_OLD - && (s->size - htab->plt_initial_entry_size) - / htab->plt_entry_size - > PLT_NUM_SINGLE_ENTRIES) - s->size += htab->plt_entry_size; - } - ent->plt.offset = plt_offset; - } - - /* We also need to make an entry in the .rela.plt section. */ - if (!doneone) - { - if (!dyn) - htab->elf.irelplt->size += sizeof (Elf32_External_Rela); - else - { - htab->elf.srelplt->size += sizeof (Elf32_External_Rela); - - if (htab->plt_type == PLT_VXWORKS) - { - /* Allocate space for the unloaded relocations. */ - if (!bfd_link_pic (info) - && htab->elf.dynamic_sections_created) - { - if (ent->plt.offset - == (bfd_vma) htab->plt_initial_entry_size) - { - htab->srelplt2->size - += (sizeof (Elf32_External_Rela) - * VXWORKS_PLTRESOLVE_RELOCS); - } - - htab->srelplt2->size - += (sizeof (Elf32_External_Rela) - * VXWORKS_PLT_NON_JMP_SLOT_RELOCS); - } - - /* Every PLT entry has an associated GOT entry in - .got.plt. */ - htab->elf.sgotplt->size += 4; - } - } - doneone = TRUE; - } - } - else - ent->plt.offset = (bfd_vma) -1; - - if (!doneone) - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - } - else - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -static const unsigned char glink_eh_frame_cie[] = -{ - 0, 0, 0, 16, /* length. */ - 0, 0, 0, 0, /* id. */ - 1, /* CIE version. */ - 'z', 'R', 0, /* Augmentation string. */ - 4, /* Code alignment. */ - 0x7c, /* Data alignment. */ - 65, /* RA reg. */ - 1, /* Augmentation size. */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ - DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ -}; - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -ppc_elf_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - -#ifdef DEBUG - fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); -#endif - - htab = ppc_elf_hash_table (info); - BFD_ASSERT (htab->elf.dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - if (htab->plt_type == PLT_OLD) - htab->got_header_size = 16; - else if (htab->plt_type == PLT_NEW) - htab->got_header_size = 12; - - /* 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; - struct plt_entry **local_plt; - struct plt_entry **end_local_plt; - char *lgot_masks; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - - if (!is_ppc_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct ppc_dyn_relocs *p; - - for (p = ((struct ppc_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 (htab->is_vxworks - && strcmp (p->sec->output_section->name, - ".tls_vars") == 0) - { - /* Relocations in vxworks .tls_vars sections are - handled specially by the loader. */ - } - else if (p->count != 0) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - if (p->ifunc) - sreloc = htab->elf.irelplt; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags - & (SEC_READONLY | SEC_ALLOC)) - == (SEC_READONLY | SEC_ALLOC)) - { - info->flags |= DF_TEXTREL; - info->callbacks->minfo (_("%B: dynamic relocation in read-only section `%A'\n"), - p->sec->owner, p->sec); - } - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - local_plt = (struct plt_entry **) end_local_got; - end_local_plt = local_plt + locsymcount; - lgot_masks = (char *) end_local_plt; - - for (; local_got < end_local_got; ++local_got, ++lgot_masks) - if (*local_got > 0) - { - unsigned int need; - if ((*lgot_masks & TLS_LD) != 0) - htab->tlsld_got.refcount += 1; - need = got_entries_needed (*lgot_masks); - if (need == 0) - *local_got = (bfd_vma) -1; - else - { - *local_got = allocate_got (htab, need); - if (bfd_link_pic (info)) - { - asection *srel; - bfd_boolean tprel_known = bfd_link_executable (info); - - need = got_relocs_needed (*lgot_masks, need, tprel_known); - srel = htab->elf.srelgot; - if ((*lgot_masks & PLT_IFUNC) != 0) - srel = htab->elf.irelplt; - srel->size += need; - } - } - } - else - *local_got = (bfd_vma) -1; - - if (htab->is_vxworks) - continue; - - /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ - for (; local_plt < end_local_plt; ++local_plt) - { - struct plt_entry *ent; - bfd_boolean doneone = FALSE; - bfd_vma plt_offset = 0, glink_offset = 0; - - for (ent = *local_plt; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - { - s = htab->elf.iplt; - - if (!doneone) - { - plt_offset = s->size; - s->size += 4; - } - ent->plt.offset = plt_offset; - - s = htab->glink; - if (!doneone || bfd_link_pic (info)) - { - glink_offset = s->size; - s->size += GLINK_ENTRY_SIZE (htab, NULL); - } - ent->glink_offset = glink_offset; - - if (!doneone) - { - htab->elf.irelplt->size += sizeof (Elf32_External_Rela); - doneone = TRUE; - } - } - else - ent->plt.offset = (bfd_vma) -1; - } - } - - /* Allocate space for global sym dynamic relocs. */ - elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); - - if (htab->tlsld_got.refcount > 0) - { - htab->tlsld_got.offset = allocate_got (htab, 8); - if (bfd_link_pic (info)) - htab->elf.srelgot->size += sizeof (Elf32_External_Rela); - } - else - htab->tlsld_got.offset = (bfd_vma) -1; - - if (htab->elf.sgot != NULL && htab->plt_type != PLT_VXWORKS) - { - unsigned int g_o_t = 32768; - - /* If we haven't allocated the header, do so now. When we get here, - for old plt/got the got size will be 0 to 32764 (not allocated), - or 32780 to 65536 (header allocated). For new plt/got, the - corresponding ranges are 0 to 32768 and 32780 to 65536. */ - if (htab->elf.sgot->size <= 32768) - { - g_o_t = htab->elf.sgot->size; - if (htab->plt_type == PLT_OLD) - g_o_t += 4; - htab->elf.sgot->size += htab->got_header_size; - } - - htab->elf.hgot->root.u.def.value = g_o_t; - } - if (bfd_link_pic (info)) - { - struct elf_link_hash_entry *sda = htab->sdata[0].sym; - - sda->root.u.def.section = htab->elf.hgot->root.u.def.section; - sda->root.u.def.value = htab->elf.hgot->root.u.def.value; - } - if (info->emitrelocations) - { - struct elf_link_hash_entry *sda = htab->sdata[0].sym; - - if (sda != NULL && sda->ref_regular) - sda->root.u.def.section->flags |= SEC_KEEP; - sda = htab->sdata[1].sym; - if (sda != NULL && sda->ref_regular) - sda->root.u.def.section->flags |= SEC_KEEP; - } - - if (htab->glink != NULL - && htab->glink->size != 0 - && htab->elf.dynamic_sections_created) - { - htab->glink_pltresolve = htab->glink->size; - /* Space for the branch table. */ - htab->glink->size - += htab->elf.srelplt->size / (sizeof (Elf32_External_Rela) / 4) - 4; - /* Pad out to align the start of PLTresolve. */ - htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround - ? 63 : 15); - htab->glink->size += GLINK_PLTRESOLVE; - - if (htab->params->emit_stub_syms) - { - struct elf_link_hash_entry *sh; - sh = elf_link_hash_lookup (&htab->elf, "__glink", - TRUE, FALSE, FALSE); - if (sh == NULL) - return FALSE; - if (sh->root.type == bfd_link_hash_new) - { - sh->root.type = bfd_link_hash_defined; - sh->root.u.def.section = htab->glink; - sh->root.u.def.value = htab->glink_pltresolve; - sh->ref_regular = 1; - sh->def_regular = 1; - sh->ref_regular_nonweak = 1; - sh->forced_local = 1; - sh->non_elf = 0; - sh->root.linker_def = 1; - } - sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", - TRUE, FALSE, FALSE); - if (sh == NULL) - return FALSE; - if (sh->root.type == bfd_link_hash_new) - { - sh->root.type = bfd_link_hash_defined; - sh->root.u.def.section = htab->glink; - sh->root.u.def.value = htab->glink->size - GLINK_PLTRESOLVE; - sh->ref_regular = 1; - sh->def_regular = 1; - sh->ref_regular_nonweak = 1; - sh->forced_local = 1; - sh->non_elf = 0; - sh->root.linker_def = 1; - } - } - } - - if (htab->glink != NULL - && htab->glink->size != 0 - && htab->glink_eh_frame != NULL - && !bfd_is_abs_section (htab->glink_eh_frame->output_section) - && _bfd_elf_eh_frame_present (info)) - { - s = htab->glink_eh_frame; - s->size = sizeof (glink_eh_frame_cie) + 20; - if (bfd_link_pic (info)) - { - s->size += 4; - if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256) - s->size += 4; - } - } - - /* We've now determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = htab->elf.dynobj->sections; s != NULL; s = s->next) - { - bfd_boolean strip_section = TRUE; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->elf.splt - || s == htab->elf.sgot) - { - /* 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; - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (s == htab->elf.iplt - || s == htab->glink - || s == htab->glink_eh_frame - || s == htab->elf.sgotplt - || s == htab->sbss - || s == htab->elf.sdynbss - || s == htab->elf.sdynrelro - || s == htab->dynsbss) - { - /* Strip these too. */ - } - else if (s == htab->sdata[0].section - || s == htab->sdata[1].section) - { - strip_section = (s->flags & SEC_KEEP) == 0; - } - else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s), - ".rela")) - { - if (s->size != 0) - { - /* Remember whether there are any relocation sections. */ - 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 && strip_section) - { - /* 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. */ - s->contents = bfd_zalloc (htab->elf.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 ppc_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->elf.splt != NULL && htab->elf.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (htab->plt_type == PLT_NEW - && htab->glink != NULL - && htab->glink->size != 0) - { - if (!add_dynamic_entry (DT_PPC_GOT, 0)) - return FALSE; - if (!htab->params->no_tls_get_addr_opt - && htab->tls_get_addr != NULL - && htab->tls_get_addr->plt.plist != NULL - && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - } - - /* If any dynamic relocs apply to a read-only section, then we - need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (elf_hash_table (info), maybe_set_textrel, - info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - if (htab->is_vxworks - && !elf_vxworks_add_dynamic_entries (output_bfd, info)) - return FALSE; - } -#undef add_dynamic_entry - - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->contents != NULL) - { - unsigned char *p = htab->glink_eh_frame->contents; - bfd_vma val; - - memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); - /* CIE length (rewrite in case little-endian). */ - bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); - p += sizeof (glink_eh_frame_cie); - /* FDE length. */ - val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to .glink. Set later. */ - p += 4; - /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); - p += 4; - /* Augmentation. */ - p += 1; - - if (bfd_link_pic (info) - && htab->elf.dynamic_sections_created) - { - bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; - if (adv < 64) - *p++ = DW_CFA_advance_loc + adv; - else if (adv < 256) - { - *p++ = DW_CFA_advance_loc1; - *p++ = adv; - } - else if (adv < 65536) - { - *p++ = DW_CFA_advance_loc2; - bfd_put_16 (htab->elf.dynobj, adv, p); - p += 2; - } - else - { - *p++ = DW_CFA_advance_loc4; - bfd_put_32 (htab->elf.dynobj, adv, p); - p += 4; - } - *p++ = DW_CFA_register; - *p++ = 65; - p++; - *p++ = DW_CFA_advance_loc + 4; - *p++ = DW_CFA_restore_extended; - *p++ = 65; - } - BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) - == htab->glink_eh_frame->size); - } - - return TRUE; -} - -/* Arrange to have _SDA_BASE_ or _SDA2_BASE_ stripped from the output - if it looks like nothing is using them. */ - -static void -maybe_strip_sdasym (bfd *output_bfd, elf_linker_section_t *lsect) -{ - struct elf_link_hash_entry *sda = lsect->sym; - - if (sda != NULL && !sda->ref_regular && sda->dynindx == -1) - { - asection *s; - - s = bfd_get_section_by_name (output_bfd, lsect->name); - if (s == NULL || bfd_section_removed_from_list (output_bfd, s)) - { - s = bfd_get_section_by_name (output_bfd, lsect->bss_name); - if (s == NULL || bfd_section_removed_from_list (output_bfd, s)) - { - sda->def_regular = 0; - /* This is somewhat magic. See elf_link_output_extsym. */ - sda->ref_dynamic = 1; - sda->forced_local = 0; - } - } - } -} - -void -ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - - if (htab != NULL) - { - maybe_strip_sdasym (info->output_bfd, &htab->sdata[0]); - maybe_strip_sdasym (info->output_bfd, &htab->sdata[1]); - } -} - - -/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ - -static bfd_boolean -ppc_elf_hash_symbol (struct elf_link_hash_entry *h) -{ - if (h->plt.plist != NULL - && !h->def_regular - && (!h->pointer_equality_needed - || !h->ref_regular_nonweak)) - return FALSE; - - return _bfd_elf_hash_symbol (h); -} - -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) - -/* Relaxation trampolines. r12 is available for clobbering (r11, is - used for some functions that are allowed to break the ABI). */ -static const int shared_stub_entry[] = - { - 0x7c0802a6, /* mflr 0 */ - 0x429f0005, /* bcl 20, 31, .Lxxx */ - 0x7d8802a6, /* mflr 12 */ - 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */ - 0x398c0000, /* addi 12, 12, (xxx-.Lxxx)@l */ - 0x7c0803a6, /* mtlr 0 */ - 0x7d8903a6, /* mtctr 12 */ - 0x4e800420, /* bctr */ - }; - -static const int stub_entry[] = - { - 0x3d800000, /* lis 12,xxx@ha */ - 0x398c0000, /* addi 12,12,xxx@l */ - 0x7d8903a6, /* mtctr 12 */ - 0x4e800420, /* bctr */ - }; - -struct ppc_elf_relax_info -{ - unsigned int workaround_size; - unsigned int picfixup_size; -}; - -/* This function implements long branch trampolines, and the ppc476 - icache bug workaround. Any section needing trampolines or patch - space for the workaround has its size extended so that we can - add trampolines at the end of the section. */ - -static bfd_boolean -ppc_elf_relax_section (bfd *abfd, - asection *isec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - struct one_branch_fixup - { - struct one_branch_fixup *next; - asection *tsec; - /* Final link, can use the symbol offset. For a - relocatable link we use the symbol's index. */ - bfd_vma toff; - bfd_vma trampoff; - }; - - Elf_Internal_Shdr *symtab_hdr; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Rela *irel, *irelend = NULL; - struct one_branch_fixup *branch_fixups = NULL; - struct ppc_elf_relax_info *relax_info = NULL; - unsigned changes = 0; - bfd_boolean workaround_change; - struct ppc_elf_link_hash_table *htab; - bfd_size_type trampbase, trampoff, newsize, picfixup_size; - asection *got2; - bfd_boolean maybe_pasted; - - *again = FALSE; - - /* No need to do anything with non-alloc or non-code sections. */ - if ((isec->flags & SEC_ALLOC) == 0 - || (isec->flags & SEC_CODE) == 0 - || (isec->flags & SEC_LINKER_CREATED) != 0 - || isec->size < 4) - return TRUE; - - /* We cannot represent the required PIC relocs in the output, so don't - do anything. The linker doesn't support mixing -shared and -r - anyway. */ - if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info)) - return TRUE; - - htab = ppc_elf_hash_table (link_info); - if (htab == NULL) - return TRUE; - - isec->size = (isec->size + 3) & -4; - if (isec->rawsize == 0) - isec->rawsize = isec->size; - trampbase = isec->size; - - BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE - || isec->sec_info_type == SEC_INFO_TYPE_TARGET); - isec->sec_info_type = SEC_INFO_TYPE_TARGET; - - if (htab->params->ppc476_workaround - || htab->params->pic_fixup > 0) - { - if (elf_section_data (isec)->sec_info == NULL) - { - elf_section_data (isec)->sec_info - = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info)); - if (elf_section_data (isec)->sec_info == NULL) - return FALSE; - } - relax_info = elf_section_data (isec)->sec_info; - trampbase -= relax_info->workaround_size; - } - - maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0 - || strcmp (isec->output_section->name, ".fini") == 0); - /* Space for a branch around any trampolines. */ - trampoff = trampbase; - if (maybe_pasted && trampbase == isec->rawsize) - trampoff += 4; - - symtab_hdr = &elf_symtab_hdr (abfd); - picfixup_size = 0; - if (htab->params->branch_trampolines - || htab->params->pic_fixup > 0) - { - /* Get a copy of the native relocations. */ - if (isec->reloc_count != 0) - { - internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - } - - got2 = bfd_get_section_by_name (abfd, ".got2"); - - irelend = internal_relocs + isec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - unsigned long r_type = ELF32_R_TYPE (irel->r_info); - bfd_vma toff, roff; - asection *tsec; - struct one_branch_fixup *f; - size_t insn_offset = 0; - bfd_vma max_branch_offset = 0, val; - bfd_byte *hit_addr; - unsigned long t0; - struct elf_link_hash_entry *h; - struct plt_entry **plist; - unsigned char sym_type; - - switch (r_type) - { - case R_PPC_REL24: - case R_PPC_LOCAL24PC: - case R_PPC_PLTREL24: - max_branch_offset = 1 << 25; - break; - - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - max_branch_offset = 1 << 15; - break; - - case R_PPC_ADDR16_HA: - if (htab->params->pic_fixup > 0) - break; - continue; - - default: - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - h = NULL; - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == 0) - goto error_return; - } - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - tsec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else - tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - toff = isym->st_value; - sym_type = ELF_ST_TYPE (isym->st_info); - } - else - { - /* Global symbol handling. */ - unsigned long indx; - - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - - 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) - { - tsec = h->root.u.def.section; - toff = h->root.u.def.value; - } - else if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - { - tsec = bfd_und_section_ptr; - toff = bfd_link_relocatable (link_info) ? indx : 0; - } - else - continue; - - /* If this branch is to __tls_get_addr then we may later - optimise away the call. We won't be needing a long- - branch stub in that case. */ - if (bfd_link_executable (link_info) - && h == htab->tls_get_addr - && irel != internal_relocs) - { - unsigned long t_symndx = ELF32_R_SYM (irel[-1].r_info); - unsigned long t_rtype = ELF32_R_TYPE (irel[-1].r_info); - unsigned int tls_mask = 0; - - /* The previous reloc should be one of R_PPC_TLSGD or - R_PPC_TLSLD, or for older object files, a reloc - on the __tls_get_addr arg setup insn. Get tls - mask bits from the symbol on that reloc. */ - if (t_symndx < symtab_hdr->sh_info) - { - bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); - - if (local_got_offsets != NULL) - { - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_offsets + symtab_hdr->sh_info); - char *lgot_masks = (char *) - (local_plt + symtab_hdr->sh_info); - tls_mask = lgot_masks[t_symndx]; - } - } - else - { - struct elf_link_hash_entry *th - = elf_sym_hashes (abfd)[t_symndx - symtab_hdr->sh_info]; - - while (th->root.type == bfd_link_hash_indirect - || th->root.type == bfd_link_hash_warning) - th = (struct elf_link_hash_entry *) th->root.u.i.link; - - tls_mask - = ((struct ppc_elf_link_hash_entry *) th)->tls_mask; - } - - /* The mask bits tell us if the call will be - optimised away. */ - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0 - && (t_rtype == R_PPC_TLSGD - || t_rtype == R_PPC_GOT_TLSGD16 - || t_rtype == R_PPC_GOT_TLSGD16_LO)) - continue; - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0 - && (t_rtype == R_PPC_TLSLD - || t_rtype == R_PPC_GOT_TLSLD16 - || t_rtype == R_PPC_GOT_TLSLD16_LO)) - continue; - } - - sym_type = h->type; - } - - if (r_type == R_PPC_ADDR16_HA) - { - if (h != NULL - && !h->def_regular - && h->protected_def - && ppc_elf_hash_entry (h)->has_addr16_ha - && ppc_elf_hash_entry (h)->has_addr16_lo) - picfixup_size += 12; - continue; - } - - /* The condition here under which we call find_plt_ent must - match that in relocate_section. If we call find_plt_ent here - but not in relocate_section, or vice versa, then the branch - destination used here may be incorrect. */ - plist = NULL; - if (h != NULL) - { - /* We know is_branch_reloc (r_type) is true. */ - if (h->type == STT_GNU_IFUNC - || r_type == R_PPC_PLTREL24) - plist = &h->plt.plist; - } - else if (sym_type == STT_GNU_IFUNC - && elf_local_got_offsets (abfd) != NULL) - { - bfd_vma *local_got_offsets = elf_local_got_offsets (abfd); - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_offsets + symtab_hdr->sh_info); - plist = local_plt + ELF32_R_SYM (irel->r_info); - } - if (plist != NULL) - { - bfd_vma addend = 0; - struct plt_entry *ent; - - if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info)) - addend = irel->r_addend; - ent = find_plt_ent (plist, got2, addend); - if (ent != NULL) - { - if (htab->plt_type == PLT_NEW - || h == NULL - || !htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - tsec = htab->glink; - toff = ent->glink_offset; - } - else - { - tsec = htab->elf.splt; - toff = ent->plt.offset; - } - } - } - - /* If the branch and target are in the same section, you have - no hope of adding stubs. We'll error out later should the - branch overflow. */ - if (tsec == isec) - continue; - - /* There probably isn't any reason to handle symbols in - SEC_MERGE sections; SEC_MERGE doesn't seem a likely - attribute for a code section, and we are only looking at - branches. However, implement it correctly here as a - reference for other target relax_section functions. */ - if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE) - { - /* At this stage in linking, no SEC_MERGE symbol has been - adjusted, so all references to such symbols need to be - passed through _bfd_merged_section_offset. (Later, in - relocate_section, all SEC_MERGE symbols *except* for - section symbols have been adjusted.) - - gas may reduce relocations against symbols in SEC_MERGE - sections to a relocation against the section symbol when - the original addend was zero. When the reloc is against - a section symbol we should include the addend in the - offset passed to _bfd_merged_section_offset, since the - location of interest is the original symbol. On the - other hand, an access to "sym+addend" where "sym" is not - a section symbol should not include the addend; Such an - access is presumed to be an offset from "sym"; The - location of interest is just "sym". */ - if (sym_type == STT_SECTION) - toff += irel->r_addend; - - toff - = _bfd_merged_section_offset (abfd, &tsec, - elf_section_data (tsec)->sec_info, - toff); - - if (sym_type != STT_SECTION) - toff += irel->r_addend; - } - /* PLTREL24 addends are special. */ - else if (r_type != R_PPC_PLTREL24) - toff += irel->r_addend; - - /* Attempted -shared link of non-pic code loses. */ - if ((!bfd_link_relocatable (link_info) - && tsec == bfd_und_section_ptr) - || tsec->output_section == NULL - || (tsec->owner != NULL - && (tsec->owner->flags & BFD_PLUGIN) != 0)) - continue; - - roff = irel->r_offset; - - /* If the branch is in range, no need to do anything. */ - if (tsec != bfd_und_section_ptr - && (!bfd_link_relocatable (link_info) - /* A relocatable link may have sections moved during - final link, so do not presume they remain in range. */ - || tsec->output_section == isec->output_section)) - { - bfd_vma symaddr, reladdr; - - symaddr = tsec->output_section->vma + tsec->output_offset + toff; - reladdr = isec->output_section->vma + isec->output_offset + roff; - if (symaddr - reladdr + max_branch_offset - < 2 * max_branch_offset) - continue; - } - - /* Look for an existing fixup to this address. */ - for (f = branch_fixups; f ; f = f->next) - if (f->tsec == tsec && f->toff == toff) - break; - - if (f == NULL) - { - size_t size; - unsigned long stub_rtype; - - val = trampoff - roff; - if (val >= max_branch_offset) - /* Oh dear, we can't reach a trampoline. Don't try to add - one. We'll report an error later. */ - continue; - - if (bfd_link_pic (link_info)) - { - size = 4 * ARRAY_SIZE (shared_stub_entry); - insn_offset = 12; - } - else - { - size = 4 * ARRAY_SIZE (stub_entry); - insn_offset = 0; - } - if (!htab->params->speculate_indirect_jumps) - size += 8; - stub_rtype = R_PPC_RELAX; - if (tsec == htab->elf.splt - || tsec == htab->glink) - { - stub_rtype = R_PPC_RELAX_PLT; - if (r_type == R_PPC_PLTREL24) - stub_rtype = R_PPC_RELAX_PLTREL24; - } - - /* Hijack the old relocation. Since we need two - relocations for this use a "composite" reloc. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - stub_rtype); - irel->r_offset = trampoff + insn_offset; - if (r_type == R_PPC_PLTREL24 - && stub_rtype != R_PPC_RELAX_PLTREL24) - irel->r_addend = 0; - - /* Record the fixup so we don't do it again this section. */ - f = bfd_malloc (sizeof (*f)); - f->next = branch_fixups; - f->tsec = tsec; - f->toff = toff; - f->trampoff = trampoff; - branch_fixups = f; - - trampoff += size; - changes++; - } - else - { - val = f->trampoff - roff; - if (val >= max_branch_offset) - continue; - - /* Nop out the reloc, since we're finalizing things here. */ - irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); - } - - /* Get the section contents. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (isec)->this_hdr.contents != NULL) - contents = elf_section_data (isec)->this_hdr.contents; - /* Go get them off disk. */ - else if (!bfd_malloc_and_get_section (abfd, isec, &contents)) - goto error_return; - } - - /* Fix up the existing branch to hit the trampoline. */ - hit_addr = contents + roff; - switch (r_type) - { - case R_PPC_REL24: - case R_PPC_LOCAL24PC: - case R_PPC_PLTREL24: - t0 = bfd_get_32 (abfd, hit_addr); - t0 &= ~0x3fffffc; - t0 |= val & 0x3fffffc; - bfd_put_32 (abfd, t0, hit_addr); - break; - - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - t0 = bfd_get_32 (abfd, hit_addr); - t0 &= ~0xfffc; - t0 |= val & 0xfffc; - bfd_put_32 (abfd, t0, hit_addr); - break; - } - } - - while (branch_fixups != NULL) - { - struct one_branch_fixup *f = branch_fixups; - branch_fixups = branch_fixups->next; - free (f); - } - } - - workaround_change = FALSE; - newsize = trampoff; - if (htab->params->ppc476_workaround - && (!bfd_link_relocatable (link_info) - || isec->output_section->alignment_power >= htab->params->pagesize_p2)) - { - bfd_vma addr, end_addr; - unsigned int crossings; - bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; - - addr = isec->output_section->vma + isec->output_offset; - end_addr = addr + trampoff; - addr &= -pagesize; - crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2; - if (crossings != 0) - { - /* Keep space aligned, to ensure the patch code itself does - not cross a page. Don't decrease size calculated on a - previous pass as otherwise we might never settle on a layout. */ - newsize = 15 - ((end_addr - 1) & 15); - newsize += crossings * 16; - if (relax_info->workaround_size < newsize) - { - relax_info->workaround_size = newsize; - workaround_change = TRUE; - } - /* Ensure relocate_section is called. */ - isec->flags |= SEC_RELOC; - } - newsize = trampoff + relax_info->workaround_size; - } - - if (htab->params->pic_fixup > 0) - { - picfixup_size -= relax_info->picfixup_size; - if (picfixup_size != 0) - relax_info->picfixup_size += picfixup_size; - newsize += relax_info->picfixup_size; - } - - if (changes != 0 || picfixup_size != 0 || workaround_change) - isec->size = newsize; - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (isec)->this_hdr.contents != contents) - { - if (!changes && !link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (isec)->this_hdr.contents = contents; - } - } - - changes += picfixup_size; - if (changes != 0) - { - /* Append sufficient NOP relocs so we can write out relocation - information for the trampolines. */ - Elf_Internal_Shdr *rel_hdr; - Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count) - * sizeof (*new_relocs)); - unsigned ix; - - if (!new_relocs) - goto error_return; - memcpy (new_relocs, internal_relocs, - isec->reloc_count * sizeof (*new_relocs)); - for (ix = changes; ix--;) - { - irel = new_relocs + ix + isec->reloc_count; - - irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); - } - if (internal_relocs != elf_section_data (isec)->relocs) - free (internal_relocs); - elf_section_data (isec)->relocs = new_relocs; - isec->reloc_count += changes; - rel_hdr = _bfd_elf_single_rel_hdr (isec); - rel_hdr->sh_size += changes * rel_hdr->sh_entsize; - } - else if (internal_relocs != NULL - && elf_section_data (isec)->relocs != internal_relocs) - free (internal_relocs); - - *again = changes != 0 || workaround_change; - return TRUE; - - error_return: - while (branch_fixups != NULL) - { - struct one_branch_fixup *f = branch_fixups; - branch_fixups = branch_fixups->next; - free (f); - } - if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) - free (isymbuf); - if (contents != NULL - && elf_section_data (isec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (isec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -/* What to do when ld finds relocations against symbols defined in - discarded sections. */ - -static unsigned int -ppc_elf_action_discarded (asection *sec) -{ - if (strcmp (".fixup", sec->name) == 0) - return 0; - - if (strcmp (".got2", sec->name) == 0) - return 0; - - return _bfd_elf_default_action_discarded (sec); -} - -/* Fill in the address for a pointer generated in a linker section. */ - -static bfd_vma -elf_finish_pointer_linker_section (bfd *input_bfd, - elf_linker_section_t *lsect, - struct elf_link_hash_entry *h, - bfd_vma relocation, - const Elf_Internal_Rela *rel) -{ - elf_linker_section_pointers_t *linker_section_ptr; - - BFD_ASSERT (lsect != NULL); - - if (h != NULL) - { - /* Handle global symbol. */ - struct ppc_elf_link_hash_entry *eh; - - eh = (struct ppc_elf_link_hash_entry *) h; - BFD_ASSERT (eh->elf.def_regular); - linker_section_ptr = eh->linker_section_pointer; - } - else - { - /* Handle local symbol. */ - unsigned long r_symndx = ELF32_R_SYM (rel->r_info); - - BFD_ASSERT (is_ppc_elf (input_bfd)); - BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); - linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx]; - } - - linker_section_ptr = elf_find_pointer_linker_section (linker_section_ptr, - rel->r_addend, - lsect); - BFD_ASSERT (linker_section_ptr != NULL); - - /* Offset will always be a multiple of four, so use the bottom bit - as a "written" flag. */ - if ((linker_section_ptr->offset & 1) == 0) - { - bfd_put_32 (lsect->section->owner, - relocation + linker_section_ptr->addend, - lsect->section->contents + linker_section_ptr->offset); - linker_section_ptr->offset += 1; - } - - relocation = (lsect->section->output_section->vma - + lsect->section->output_offset - + linker_section_ptr->offset - 1 - - SYM_VAL (lsect->sym)); - -#ifdef DEBUG - fprintf (stderr, - "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", - lsect->name, (long) relocation, (long) relocation); -#endif - - return relocation; -} - -#define PPC_LO(v) ((v) & 0xffff) -#define PPC_HI(v) (((v) >> 16) & 0xffff) -#define PPC_HA(v) PPC_HI ((v) + 0x8000) - -static inline bfd_byte * -output_bctr (struct ppc_elf_link_hash_table *htab, bfd *obfd, bfd_byte *p) -{ - if (!htab->params->speculate_indirect_jumps) - { - bfd_put_32 (obfd, CRSETEQ, p); - p += 4; - bfd_put_32 (obfd, BEQCTRM, p); - p += 4; - bfd_put_32 (obfd, B, p); - p += 4; - } - else - { - bfd_put_32 (obfd, BCTR, p); - p += 4; - } - return p; -} - -static void -write_glink_stub (struct elf_link_hash_entry *h, struct plt_entry *ent, - asection *plt_sec, unsigned char *p, - struct bfd_link_info *info) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - bfd *output_bfd = info->output_bfd; - bfd_vma plt; - unsigned char *end = p + GLINK_ENTRY_SIZE (htab, h); - - if (h != NULL - && h == htab->tls_get_addr - && !htab->params->no_tls_get_addr_opt) - { - bfd_put_32 (output_bfd, LWZ_11_3, p); - p += 4; - bfd_put_32 (output_bfd, LWZ_12_3 + 4, p); - p += 4; - bfd_put_32 (output_bfd, MR_0_3, p); - p += 4; - bfd_put_32 (output_bfd, CMPWI_11_0, p); - p += 4; - bfd_put_32 (output_bfd, ADD_3_12_2, p); - p += 4; - bfd_put_32 (output_bfd, BEQLR, p); - p += 4; - bfd_put_32 (output_bfd, MR_3_0, p); - p += 4; - bfd_put_32 (output_bfd, NOP, p); - p += 4; - } - - plt = ((ent->plt.offset & ~1) - + plt_sec->output_section->vma - + plt_sec->output_offset); - - if (bfd_link_pic (info)) - { - bfd_vma got = 0; - - if (ent->addend >= 32768) - got = (ent->addend - + ent->sec->output_section->vma - + ent->sec->output_offset); - else if (htab->elf.hgot != NULL) - got = SYM_VAL (htab->elf.hgot); - - plt -= got; - - if (plt + 0x8000 < 0x10000) - bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p); - else - { - bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p); - p += 4; - bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p); - } - } - else - { - bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p); - p += 4; - bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p); - } - p += 4; - bfd_put_32 (output_bfd, MTCTR_11, p); - p += 4; - p = output_bctr (htab, output_bfd, p); - while (p < end) - { - bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p); - p += 4; - } -} - -/* Return true if symbol is defined statically. */ - -static bfd_boolean -is_static_defined (struct elf_link_hash_entry *h) -{ - return ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section != NULL - && h->root.u.def.section->output_section != NULL); -} - -/* If INSN is an opcode that may be used with an @tls operand, return - the transformed insn for TLS optimisation, otherwise return 0. If - REG is non-zero only match an insn with RB or RA equal to REG. */ - -unsigned int -_bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg) -{ - unsigned int rtra; - - if ((insn & (0x3f << 26)) != 31 << 26) - return 0; - - if (reg == 0 || ((insn >> 11) & 0x1f) == reg) - rtra = insn & ((1 << 26) - (1 << 16)); - else if (((insn >> 16) & 0x1f) == reg) - rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5); - else - return 0; - - if ((insn & (0x3ff << 1)) == 266 << 1) - /* add -> addi. */ - insn = 14 << 26; - else if ((insn & (0x1f << 1)) == 23 << 1 - && ((insn & (0x1f << 6)) < 14 << 6 - || ((insn & (0x1f << 6)) >= 16 << 6 - && (insn & (0x1f << 6)) < 24 << 6))) - /* load and store indexed -> dform. */ - insn = (32 | ((insn >> 6) & 0x1f)) << 26; - else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1) - /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ - insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1); - else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1) - /* lwax -> lwa. */ - insn = (58 << 26) | 2; - else - return 0; - insn |= rtra; - return insn; -} - -/* If INSN is an opcode that may be used with an @tprel operand, return - the transformed insn for an undefined weak symbol, ie. with the - thread pointer REG operand removed. Otherwise return 0. */ - -unsigned int -_bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) -{ - if ((insn & (0x1f << 16)) == reg << 16 - && ((insn & (0x3f << 26)) == 14u << 26 /* addi */ - || (insn & (0x3f << 26)) == 15u << 26 /* addis */ - || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ - || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ - || (insn & (0x3f << 26)) == 36u << 26 /* stw */ - || (insn & (0x3f << 26)) == 38u << 26 /* stb */ - || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ - || (insn & (0x3f << 26)) == 42u << 26 /* lha */ - || (insn & (0x3f << 26)) == 44u << 26 /* sth */ - || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ - || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ - || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ - || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ - || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ - || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ - || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ - && (insn & 3) != 1) - || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ - && ((insn & 3) == 0 || (insn & 3) == 3)))) - { - insn &= ~(0x1f << 16); - } - else if ((insn & (0x1f << 21)) == reg << 21 - && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */ - || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */ - || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */)) - { - insn &= ~(0x1f << 21); - insn |= (insn & (0x1f << 16)) << 5; - if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */) - insn -= 2 >> 26; /* convert to ori,oris */ - } - else - insn = 0; - return insn; -} - -static bfd_boolean -is_insn_ds_form (unsigned int insn) -{ - return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */ - || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */ - || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */ - || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */); -} - -static bfd_boolean -is_insn_dq_form (unsigned int insn) -{ - return ((insn & (0x3f << 26)) == 56u << 26 /* lq */ - || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */ - && (insn & 3) == 1)); -} - -/* 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. */ - -static bfd_boolean -ppc_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - struct ppc_elf_link_hash_table *htab; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *wrel; - Elf_Internal_Rela *relend; - Elf_Internal_Rela outrel; - asection *got2; - bfd_vma *local_got_offsets; - bfd_boolean ret = TRUE; - bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0); - bfd_boolean is_vxworks_tls; - unsigned int picfixup_size = 0; - struct ppc_elf_relax_info *relax_info = NULL; - -#ifdef DEBUG - _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, " - "%ld relocations%s", - input_bfd, input_section, - (long) input_section->reloc_count, - (bfd_link_relocatable (info)) ? " (relocatable)" : ""); -#endif - - got2 = bfd_get_section_by_name (input_bfd, ".got2"); - - /* Initialize howto table if not already done. */ - if (!ppc_elf_howto_table[R_PPC_ADDR32]) - ppc_elf_howto_init (); - - htab = ppc_elf_hash_table (info); - local_got_offsets = elf_local_got_offsets (input_bfd); - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - /* We have to handle relocations in vxworks .tls_vars sections - specially, because the dynamic loader is 'weird'. */ - is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info) - && !strcmp (input_section->output_section->name, - ".tls_vars")); - if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET) - relax_info = elf_section_data (input_section)->sec_info; - rel = wrel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; wrel++, rel++) - { - enum elf_ppc_reloc_type r_type; - bfd_vma addend; - bfd_reloc_status_type r; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - const char *sym_name; - reloc_howto_type *howto; - unsigned long r_symndx; - bfd_vma relocation; - bfd_vma branch_bit, from; - bfd_boolean unresolved_reloc; - bfd_boolean warned; - unsigned int tls_type, tls_mask, tls_gd; - struct plt_entry **ifunc; - struct reloc_howto_struct alt_howto; - - again: - r_type = ELF32_R_TYPE (rel->r_info); - sym = NULL; - sec = NULL; - h = NULL; - unresolved_reloc = FALSE; - warned = FALSE; - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); - - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - sym_name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - howto = NULL; - if (r_type < R_PPC_max) - howto = ppc_elf_howto_table[r_type]; - - _bfd_clear_contents (howto, input_bfd, input_section, - contents + rel->r_offset); - wrel->r_offset = rel->r_offset; - wrel->r_info = 0; - wrel->r_addend = 0; - - /* For ld -r, remove relocations in debug sections against - symbols defined in discarded sections. Not done for - non-debug to preserve relocs in .eh_frame which the - eh_frame editing code expects to be present. */ - if (bfd_link_relocatable (info) - && (input_section->flags & SEC_DEBUGGING)) - wrel--; - - continue; - } - - if (bfd_link_relocatable (info)) - { - if (got2 != NULL - && r_type == R_PPC_PLTREL24 - && rel->r_addend != 0) - { - /* R_PPC_PLTREL24 is rather special. If non-zero, the - addend specifies the GOT pointer offset within .got2. */ - rel->r_addend += got2->output_offset; - } - if (r_type != R_PPC_RELAX_PLT - && r_type != R_PPC_RELAX_PLTREL24 - && r_type != R_PPC_RELAX) - goto copy_reloc; - } - - /* TLS optimizations. Replace instruction sequences and relocs - based on information we collected in tls_optimize. We edit - RELOCS so that --emit-relocs will output something sensible - for the final instruction stream. */ - tls_mask = 0; - tls_gd = 0; - if (h != NULL) - tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask; - else if (local_got_offsets != NULL) - { - struct plt_entry **local_plt; - char *lgot_masks; - local_plt - = (struct plt_entry **) (local_got_offsets + symtab_hdr->sh_info); - lgot_masks = (char *) (local_plt + symtab_hdr->sh_info); - tls_mask = lgot_masks[r_symndx]; - } - - /* Ensure reloc mapping code below stays sane. */ - if ((R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TLSGD16 & 3) - || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3) - || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3) - || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TLSGD16_HA & 3) - || (R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TPREL16 & 3) - || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TPREL16_LO & 3) - || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TPREL16_HI & 3) - || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TPREL16_HA & 3)) - abort (); - switch (r_type) - { - default: - break; - - case R_PPC_GOT_TPREL16: - case R_PPC_GOT_TPREL16_LO: - if ((tls_mask & TLS_TLS) != 0 - && (tls_mask & TLS_TPREL) == 0) - { - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - insn &= 31 << 21; - insn |= 0x3c020000; /* addis 0,2,0 */ - bfd_put_32 (input_bfd, insn, - contents + rel->r_offset - d_offset); - r_type = R_PPC_TPREL16_HA; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC_TLS: - if ((tls_mask & TLS_TLS) != 0 - && (tls_mask & TLS_TPREL) == 0) - { - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn = _bfd_elf_ppc_at_tls_transform (insn, 2); - if (insn == 0) - abort (); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - r_type = R_PPC_TPREL16_LO; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - - /* Was PPC_TLS which sits on insn boundary, now - PPC_TPREL16_LO which is at low-order half-word. */ - rel->r_offset += d_offset; - } - break; - - case R_PPC_GOT_TLSGD16_HI: - case R_PPC_GOT_TLSGD16_HA: - tls_gd = TLS_TPRELGD; - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) - goto tls_gdld_hi; - break; - - case R_PPC_GOT_TLSLD16_HI: - case R_PPC_GOT_TLSLD16_HA: - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) - { - tls_gdld_hi: - if ((tls_mask & tls_gd) != 0) - r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) - + R_PPC_GOT_TPREL16); - else - { - rel->r_offset -= d_offset; - bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); - r_type = R_PPC_NONE; - } - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC_GOT_TLSGD16: - case R_PPC_GOT_TLSGD16_LO: - tls_gd = TLS_TPRELGD; - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) - goto tls_ldgd_opt; - break; - - case R_PPC_GOT_TLSLD16: - case R_PPC_GOT_TLSLD16_LO: - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) - { - unsigned int insn1, insn2; - bfd_vma offset; - - tls_ldgd_opt: - offset = (bfd_vma) -1; - /* If not using the newer R_PPC_TLSGD/LD to mark - __tls_get_addr calls, we must trust that the call - stays with its arg setup insns, ie. that the next - reloc is the __tls_get_addr call associated with - the current reloc. Edit both insns. */ - if (input_section->has_tls_get_addr_call - && rel + 1 < relend - && branch_reloc_hash_match (input_bfd, rel + 1, - htab->tls_get_addr)) - offset = rel[1].r_offset; - /* We read the low GOT_TLS insn because we need to keep - the destination reg. It may be something other than - the usual r3, and moved to r3 before the call by - intervening code. */ - insn1 = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - if ((tls_mask & tls_gd) != 0) - { - /* IE */ - insn1 &= (0x1f << 21) | (0x1f << 16); - insn1 |= 32 << 26; /* lwz */ - if (offset != (bfd_vma) -1) - { - rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); - insn2 = 0x7c631214; /* add 3,3,2 */ - bfd_put_32 (input_bfd, insn2, contents + offset); - } - r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) - + R_PPC_GOT_TPREL16); - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - } - else - { - /* LE */ - insn1 &= 0x1f << 21; - insn1 |= 0x3c020000; /* addis r,2,0 */ - if (tls_gd == 0) - { - /* Was an LD reloc. */ - for (r_symndx = 0; - r_symndx < symtab_hdr->sh_info; - r_symndx++) - if (local_sections[r_symndx] == sec) - break; - if (r_symndx >= symtab_hdr->sh_info) - r_symndx = STN_UNDEF; - rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != STN_UNDEF) - rel->r_addend -= (local_syms[r_symndx].st_value - + sec->output_offset - + sec->output_section->vma); - } - r_type = R_PPC_TPREL16_HA; - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - if (offset != (bfd_vma) -1) - { - rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO); - rel[1].r_offset = offset + d_offset; - rel[1].r_addend = rel->r_addend; - insn2 = 0x38630000; /* addi 3,3,0 */ - bfd_put_32 (input_bfd, insn2, contents + offset); - } - } - bfd_put_32 (input_bfd, insn1, - contents + rel->r_offset - d_offset); - if (tls_gd == 0) - { - /* We changed the symbol on an LD reloc. Start over - in order to get h, sym, sec etc. right. */ - goto again; - } - } - break; - - case R_PPC_TLSGD: - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0) - { - unsigned int insn2; - bfd_vma offset = rel->r_offset; - - if ((tls_mask & TLS_TPRELGD) != 0) - { - /* IE */ - r_type = R_PPC_NONE; - insn2 = 0x7c631214; /* add 3,3,2 */ - } - else - { - /* LE */ - r_type = R_PPC_TPREL16_LO; - rel->r_offset += d_offset; - insn2 = 0x38630000; /* addi 3,3,0 */ - } - rel->r_info = ELF32_R_INFO (r_symndx, r_type); - bfd_put_32 (input_bfd, insn2, contents + offset); - /* Zap the reloc on the _tls_get_addr call too. */ - BFD_ASSERT (offset == rel[1].r_offset); - rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); - } - break; - - case R_PPC_TLSLD: - if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0) - { - unsigned int insn2; - - for (r_symndx = 0; - r_symndx < symtab_hdr->sh_info; - r_symndx++) - if (local_sections[r_symndx] == sec) - break; - if (r_symndx >= symtab_hdr->sh_info) - r_symndx = STN_UNDEF; - rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != STN_UNDEF) - rel->r_addend -= (local_syms[r_symndx].st_value - + sec->output_offset - + sec->output_section->vma); - - rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO); - rel->r_offset += d_offset; - insn2 = 0x38630000; /* addi 3,3,0 */ - bfd_put_32 (input_bfd, insn2, - contents + rel->r_offset - d_offset); - /* Zap the reloc on the _tls_get_addr call too. */ - BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); - rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); - goto again; - } - break; - } - - /* Handle other relocations that tweak non-addend part of insn. */ - branch_bit = 0; - switch (r_type) - { - default: - break; - - /* Branch taken prediction relocations. */ - case R_PPC_ADDR14_BRTAKEN: - case R_PPC_REL14_BRTAKEN: - branch_bit = BRANCH_PREDICT_BIT; - /* Fall through. */ - - /* Branch not taken prediction relocations. */ - case R_PPC_ADDR14_BRNTAKEN: - case R_PPC_REL14_BRNTAKEN: - { - bfd_vma insn; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn &= ~BRANCH_PREDICT_BIT; - insn |= branch_bit; - - from = (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma); - - /* Invert 'y' bit if not the default. */ - if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) - insn ^= BRANCH_PREDICT_BIT; - - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - break; - } - } - - if (ELIMINATE_COPY_RELOCS - && h != NULL - && !h->def_regular - && h->protected_def - && ppc_elf_hash_entry (h)->has_addr16_ha - && ppc_elf_hash_entry (h)->has_addr16_lo - && htab->params->pic_fixup > 0) - { - /* Convert lis;addi or lis;load/store accessing a protected - variable defined in a shared library to PIC. */ - unsigned int insn; - - if (r_type == R_PPC_ADDR16_HA) - { - insn = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - if ((insn & (0x3f << 26)) == (15u << 26) - && (insn & (0x1f << 16)) == 0 /* lis */) - { - bfd_byte *p; - bfd_vma off; - bfd_vma got_addr; - - p = (contents + input_section->size - - relax_info->workaround_size - - relax_info->picfixup_size - + picfixup_size); - off = (p - contents) - (rel->r_offset - d_offset); - if (off > 0x1fffffc || (off & 3) != 0) - info->callbacks->einfo - (_("%H: fixup branch overflow\n"), - input_bfd, input_section, rel->r_offset); - - bfd_put_32 (input_bfd, B | off, - contents + rel->r_offset - d_offset); - got_addr = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + (h->got.offset & ~1)); - wrel->r_offset = (p - contents) + d_offset; - wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA); - wrel->r_addend = got_addr; - insn &= ~0xffff; - insn |= ((unsigned int) (got_addr + 0x8000) >> 16) & 0xffff; - bfd_put_32 (input_bfd, insn, p); - - /* Convert lis to lwz, loading address from GOT. */ - insn &= ~0xffff; - insn ^= (32u ^ 15u) << 26; - insn |= (insn & (0x1f << 21)) >> 5; - insn |= got_addr & 0xffff; - bfd_put_32 (input_bfd, insn, p + 4); - - bfd_put_32 (input_bfd, B | ((-4 - off) & 0x3ffffff), p + 8); - picfixup_size += 12; - - /* Use one of the spare relocs, so --emit-relocs - output is reasonable. */ - memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel)); - wrel++, rel++; - rel->r_offset = wrel[-1].r_offset + 4; - rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO); - rel->r_addend = wrel[-1].r_addend; - - /* Continue on as if we had a got reloc, to output - dynamic reloc. */ - r_type = R_PPC_GOT16_LO; - } - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): error: %s with unexpected instruction %#x"), - input_bfd, input_section, rel->r_offset, - "R_PPC_ADDR16_HA", insn); - } - else if (r_type == R_PPC_ADDR16_LO) - { - insn = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - if ((insn & (0x3f << 26)) == 14u << 26 /* addi */ - || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ - || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ - || (insn & (0x3f << 26)) == 36u << 26 /* stw */ - || (insn & (0x3f << 26)) == 38u << 26 /* stb */ - || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ - || (insn & (0x3f << 26)) == 42u << 26 /* lha */ - || (insn & (0x3f << 26)) == 44u << 26 /* sth */ - || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ - || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ - || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ - || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ - || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ - || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ - || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ - && (insn & 3) != 1) - || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ - && ((insn & 3) == 0 || (insn & 3) == 3))) - { - /* Arrange to apply the reloc addend, if any. */ - relocation = 0; - unresolved_reloc = FALSE; - rel->r_info = ELF32_R_INFO (0, r_type); - } - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): error: %s with unexpected instruction %#x"), - input_bfd, input_section, rel->r_offset, - "R_PPC_ADDR16_LO", insn); - } - } - - ifunc = NULL; - if (!htab->is_vxworks) - { - struct plt_entry *ent; - - if (h != NULL) - { - if (h->type == STT_GNU_IFUNC) - ifunc = &h->plt.plist; - } - else if (local_got_offsets != NULL - && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - struct plt_entry **local_plt; - - local_plt = (struct plt_entry **) (local_got_offsets - + symtab_hdr->sh_info); - ifunc = local_plt + r_symndx; - } - - ent = NULL; - if (ifunc != NULL - && (!bfd_link_pic (info) - || is_branch_reloc (r_type))) - { - addend = 0; - if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info)) - addend = rel->r_addend; - ent = find_plt_ent (ifunc, got2, addend); - } - if (ent != NULL) - { - if (bfd_link_pic (info) - && ent->sec != got2 - && htab->plt_type != PLT_NEW - && (!htab->elf.dynamic_sections_created - || h == NULL - || h->dynindx == -1)) - { - /* Uh oh, we are going to create a pic glink stub - for an ifunc (here for h == NULL and later in - finish_dynamic_symbol for h != NULL), and - apparently are using code compiled with - -mbss-plt. The difficulty is that -mbss-plt code - gives no indication via a magic PLTREL24 addend - whether r30 is equal to _GLOBAL_OFFSET_TABLE_ or - is pointing into a .got2 section (and how far - into .got2). */ - info->callbacks->einfo - /* xgettext:c-format */ - (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"), - input_bfd, input_section, rel->r_offset, sym_name); - } - if (h == NULL && (ent->plt.offset & 1) == 0) - { - Elf_Internal_Rela rela; - bfd_byte *loc; - - rela.r_offset = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + ent->plt.offset); - rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); - rela.r_addend = relocation; - loc = htab->elf.irelplt->contents; - loc += (htab->elf.irelplt->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - htab->local_ifunc_resolver = 1; - - ent->plt.offset |= 1; - } - if (h == NULL && (ent->glink_offset & 1) == 0) - { - unsigned char *p = ((unsigned char *) htab->glink->contents - + ent->glink_offset); - - write_glink_stub (NULL, ent, htab->elf.iplt, p, info); - ent->glink_offset |= 1; - } - - unresolved_reloc = FALSE; - if (htab->plt_type == PLT_NEW - || !htab->elf.dynamic_sections_created - || h == NULL - || h->dynindx == -1) - relocation = (htab->glink->output_section->vma - + htab->glink->output_offset - + (ent->glink_offset & ~1)); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset); - } - } - - addend = rel->r_addend; - howto = NULL; - if (r_type < R_PPC_max) - howto = ppc_elf_howto_table[r_type]; - - switch (r_type) - { - default: - break; - - case R_PPC_TPREL16_HA: - if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) - { - bfd_byte *p = contents + (rel->r_offset & ~3); - unsigned int insn = bfd_get_32 (input_bfd, p); - if ((insn & ((0x3f << 26) | 0x1f << 16)) - != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */) - /* xgettext:c-format */ - info->callbacks->minfo - (_("%H: warning: %s unexpected insn %#x.\n"), - input_bfd, input_section, rel->r_offset, howto->name, insn); - else - bfd_put_32 (input_bfd, NOP, p); - } - break; - - case R_PPC_TPREL16_LO: - if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) - { - bfd_byte *p = contents + (rel->r_offset & ~3); - unsigned int insn = bfd_get_32 (input_bfd, p); - insn &= ~(0x1f << 16); - insn |= 2 << 16; - bfd_put_32 (input_bfd, insn, p); - } - break; - } - - tls_type = 0; - switch (r_type) - { - default: - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: unknown relocation type %d for symbol %s\n"), - input_bfd, (int) r_type, sym_name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - goto copy_reloc; - - case R_PPC_NONE: - case R_PPC_TLS: - case R_PPC_TLSGD: - case R_PPC_TLSLD: - case R_PPC_EMB_MRKREF: - case R_PPC_GNU_VTINHERIT: - case R_PPC_GNU_VTENTRY: - goto copy_reloc; - - /* GOT16 relocations. Like an ADDR16 using the symbol's - address in the GOT as relocation value instead of the - symbol's value itself. Also, create a GOT entry for the - symbol and put the symbol value there. */ - case R_PPC_GOT_TLSGD16: - case R_PPC_GOT_TLSGD16_LO: - case R_PPC_GOT_TLSGD16_HI: - case R_PPC_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD; - goto dogot; - - case R_PPC_GOT_TLSLD16: - case R_PPC_GOT_TLSLD16_LO: - case R_PPC_GOT_TLSLD16_HI: - case R_PPC_GOT_TLSLD16_HA: - tls_type = TLS_TLS | TLS_LD; - goto dogot; - - case R_PPC_GOT_TPREL16: - case R_PPC_GOT_TPREL16_LO: - case R_PPC_GOT_TPREL16_HI: - case R_PPC_GOT_TPREL16_HA: - tls_type = TLS_TLS | TLS_TPREL; - goto dogot; - - case R_PPC_GOT_DTPREL16: - case R_PPC_GOT_DTPREL16_LO: - case R_PPC_GOT_DTPREL16_HI: - case R_PPC_GOT_DTPREL16_HA: - tls_type = TLS_TLS | TLS_DTPREL; - goto dogot; - - case R_PPC_GOT16: - case R_PPC_GOT16_LO: - case R_PPC_GOT16_HI: - case R_PPC_GOT16_HA: - tls_mask = 0; - dogot: - { - /* Relocation is to the entry for this symbol in the global - offset table. */ - bfd_vma off; - bfd_vma *offp; - unsigned long indx; - - if (htab->elf.sgot == NULL) - abort (); - - indx = 0; - if (tls_type == (TLS_TLS | TLS_LD) - && (h == NULL - || !h->def_dynamic)) - offp = &htab->tlsld_got.offset; - else if (h != NULL) - { - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1 - || SYMBOL_REFERENCES_LOCAL (info, h) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. */ - ; - else - { - indx = h->dynindx; - unresolved_reloc = FALSE; - } - offp = &h->got.offset; - } - else - { - if (local_got_offsets == NULL) - abort (); - offp = &local_got_offsets[r_symndx]; - } - - /* The offset must always be a multiple of 4. We use the - least significant bit to record whether we have already - processed this entry. */ - off = *offp; - if ((off & 1) != 0) - off &= ~1; - else - { - unsigned int tls_m = (tls_mask - & (TLS_LD | TLS_GD | TLS_DTPREL - | TLS_TPREL | TLS_TPRELGD)); - - if (offp == &htab->tlsld_got.offset) - tls_m = TLS_LD; - else if (h == NULL - || !h->def_dynamic) - tls_m &= ~TLS_LD; - - /* We might have multiple got entries for this sym. - Initialize them all. */ - do - { - int tls_ty = 0; - - if ((tls_m & TLS_LD) != 0) - { - tls_ty = TLS_TLS | TLS_LD; - tls_m &= ~TLS_LD; - } - else if ((tls_m & TLS_GD) != 0) - { - tls_ty = TLS_TLS | TLS_GD; - tls_m &= ~TLS_GD; - } - else if ((tls_m & TLS_DTPREL) != 0) - { - tls_ty = TLS_TLS | TLS_DTPREL; - tls_m &= ~TLS_DTPREL; - } - else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0) - { - tls_ty = TLS_TLS | TLS_TPREL; - tls_m = 0; - } - - /* Generate relocs for the dynamic linker. */ - if (indx != 0 - || (bfd_link_pic (info) - && (h == NULL - || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) - || offp == &htab->tlsld_got.offset) - && !(tls_ty == (TLS_TLS | TLS_TPREL) - && bfd_link_executable (info) - && SYMBOL_REFERENCES_LOCAL (info, h)))) - { - asection *rsec = htab->elf.srelgot; - bfd_byte * loc; - - if (ifunc != NULL) - { - rsec = htab->elf.irelplt; - if (indx == 0) - htab->local_ifunc_resolver = 1; - else if (is_static_defined (h)) - htab->maybe_local_ifunc_resolver = 1; - } - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - outrel.r_addend = 0; - if (tls_ty & (TLS_LD | TLS_GD)) - { - outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32); - if (tls_ty == (TLS_TLS | TLS_GD)) - { - loc = rsec->contents; - loc += (rsec->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, - &outrel, loc); - outrel.r_offset += 4; - outrel.r_info - = ELF32_R_INFO (indx, R_PPC_DTPREL32); - } - } - else if (tls_ty == (TLS_TLS | TLS_DTPREL)) - outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32); - else if (tls_ty == (TLS_TLS | TLS_TPREL)) - outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32); - else if (indx != 0) - outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT); - else if (ifunc != NULL) - outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); - else - outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); - if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD)) - { - outrel.r_addend += relocation; - if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - { - if (htab->elf.tls_sec == NULL) - outrel.r_addend = 0; - else - outrel.r_addend -= htab->elf.tls_sec->vma; - } - } - loc = rsec->contents; - loc += (rsec->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - - /* Init the .got section contents if we're not - emitting a reloc. */ - else - { - bfd_vma value = relocation; - - if (tls_ty != 0) - { - if (htab->elf.tls_sec == NULL) - value = 0; - else - { - if (tls_ty & TLS_LD) - value = 0; - else - value -= htab->elf.tls_sec->vma + DTP_OFFSET; - if (tls_ty & TLS_TPREL) - value += DTP_OFFSET - TP_OFFSET; - } - - if (tls_ty & (TLS_LD | TLS_GD)) - { - bfd_put_32 (input_bfd, value, - htab->elf.sgot->contents + off + 4); - value = 1; - } - } - bfd_put_32 (input_bfd, value, - htab->elf.sgot->contents + off); - } - - off += 4; - if (tls_ty & (TLS_LD | TLS_GD)) - off += 4; - } - while (tls_m != 0); - - off = *offp; - *offp = off | 1; - } - - if (off >= (bfd_vma) -2) - abort (); - - if ((tls_type & TLS_TLS) != 0) - { - if (tls_type != (TLS_TLS | TLS_LD)) - { - if ((tls_mask & TLS_LD) != 0 - && !(h == NULL - || !h->def_dynamic)) - off += 8; - if (tls_type != (TLS_TLS | TLS_GD)) - { - if ((tls_mask & TLS_GD) != 0) - off += 8; - if (tls_type != (TLS_TLS | TLS_DTPREL)) - { - if ((tls_mask & TLS_DTPREL) != 0) - off += 4; - } - } - } - } - - /* If here for a picfixup, we're done. */ - if (r_type != ELF32_R_TYPE (rel->r_info)) - goto copy_reloc; - - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off - - SYM_VAL (htab->elf.hgot)); - - /* Addends on got relocations don't make much sense. - x+off@got is actually x@got+off, and since the got is - generated by a hash table traversal, the value in the - got at entry m+n bears little relation to the entry m. */ - if (addend != 0) - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: non-zero addend on %s reloc against `%s'\n"), - input_bfd, input_section, rel->r_offset, - howto->name, - sym_name); - } - break; - - /* Relocations that need no special processing. */ - case R_PPC_LOCAL24PC: - /* It makes no sense to point a local relocation - at a symbol not in this object. */ - if (unresolved_reloc) - { - (*info->callbacks->undefined_symbol) (info, - h->root.root.string, - input_bfd, - input_section, - rel->r_offset, - TRUE); - goto copy_reloc; - } - if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info)) - { - /* @local on an ifunc does not really make sense since - the ifunc resolver can take you anywhere. More - seriously, calls to ifuncs must go through a plt call - stub, and for pic the plt call stubs uses r30 to - access the PLT. The problem is that a call that is - local won't have the +32k reloc addend trick marking - -fPIC code, so the linker won't know whether r30 is - _GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section. */ - /* xgettext:c-format */ - info->callbacks->einfo (_("%X%H: @local call to ifunc %s\n"), - input_bfd, input_section, rel->r_offset, - h->root.root.string); - } - break; - - case R_PPC_DTPREL16: - case R_PPC_DTPREL16_LO: - case R_PPC_DTPREL16_HI: - case R_PPC_DTPREL16_HA: - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; - break; - - /* Relocations that may need to be propagated if this is a shared - object. */ - case R_PPC_TPREL16: - case R_PPC_TPREL16_LO: - case R_PPC_TPREL16_HI: - case R_PPC_TPREL16_HA: - if (h != NULL - && h->root.type == bfd_link_hash_undefweak - && h->dynindx == -1) - { - /* Make this relocation against an undefined weak symbol - resolve to zero. This is really just a tweak, since - code using weak externs ought to check that they are - defined before using them. */ - bfd_byte *p = contents + rel->r_offset - d_offset; - unsigned int insn = bfd_get_32 (input_bfd, p); - insn = _bfd_elf_ppc_at_tprel_transform (insn, 2); - if (insn != 0) - bfd_put_32 (input_bfd, insn, p); - break; - } - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + TP_OFFSET; - /* The TPREL16 relocs shouldn't really be used in shared - libs or with non-local symbols as that will result in - DT_TEXTREL being set, but support them anyway. */ - goto dodyn; - - case R_PPC_TPREL32: - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + TP_OFFSET; - goto dodyn; - - case R_PPC_DTPREL32: - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; - goto dodyn; - - case R_PPC_DTPMOD32: - relocation = 1; - addend = 0; - goto dodyn; - - case R_PPC_REL16: - case R_PPC_REL16_LO: - case R_PPC_REL16_HI: - case R_PPC_REL16_HA: - case R_PPC_REL16DX_HA: - break; - - case R_PPC_REL32: - if (h == NULL || h == htab->elf.hgot) - break; - /* fall through */ - - case R_PPC_ADDR32: - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16_HI: - case R_PPC_ADDR16_HA: - case R_PPC_UADDR32: - case R_PPC_UADDR16: - goto dodyn; - - case R_PPC_VLE_REL8: - case R_PPC_VLE_REL15: - case R_PPC_VLE_REL24: - case R_PPC_REL24: - case R_PPC_REL14: - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - /* If these relocations are not to a named symbol, they can be - handled right here, no need to bother the dynamic linker. */ - if (SYMBOL_CALLS_LOCAL (info, h) - || h == htab->elf.hgot) - break; - /* fall through */ - - case R_PPC_ADDR24: - case R_PPC_ADDR14: - case R_PPC_ADDR14_BRTAKEN: - case R_PPC_ADDR14_BRNTAKEN: - if (h != NULL && !bfd_link_pic (info)) - break; - /* fall through */ - - dodyn: - if ((input_section->flags & SEC_ALLOC) == 0 - || is_vxworks_tls) - break; - - if (bfd_link_pic (info) - ? ((h == NULL - || ppc_elf_hash_entry (h)->dyn_relocs != NULL) - && ((h != NULL && pc_dynrelocs (h)) - || must_be_dyn_reloc (info, r_type))) - : (h != NULL - && ppc_elf_hash_entry (h)->dyn_relocs != NULL)) - { - int skip; - bfd_byte *loc; - asection *sreloc; - long indx = 0; - -#ifdef DEBUG - fprintf (stderr, "ppc_elf_relocate_section needs to " - "create relocation for %s\n", - (h && h->root.root.string - ? h->root.root.string : "")); -#endif - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - skip = 0; - outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1 - || outrel.r_offset == (bfd_vma) -2) - skip = (int) outrel.r_offset; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if (!SYMBOL_REFERENCES_LOCAL (info, h)) - { - indx = h->dynindx; - BFD_ASSERT (indx != -1); - unresolved_reloc = FALSE; - outrel.r_info = ELF32_R_INFO (indx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - outrel.r_addend = relocation + rel->r_addend; - - if (r_type != R_PPC_ADDR32) - { - if (ifunc != NULL) - { - /* If we get here when building a static - executable, then the libc startup function - responsible for applying indirect function - relocations is going to complain about - the reloc type. - If we get here when building a dynamic - executable, it will be because we have - a text relocation. The dynamic loader - will set the text segment writable and - non-executable to apply text relocations. - So we'll segfault when trying to run the - indirection function to resolve the reloc. */ - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: relocation %s for indirect " - "function %s unsupported\n"), - input_bfd, input_section, rel->r_offset, - howto->name, - sym_name); - ret = FALSE; - } - else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) - ; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - } - else - { - asection *osec; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. - FIXME: Why not always use a zero index? */ - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - if (indx == 0) - { - osec = htab->elf.text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); -#ifdef DEBUG - if (indx == 0) - printf ("indx=%ld section=%s flags=%08x name=%s\n", - indx, osec->name, osec->flags, - h->root.root.string); -#endif - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - } - else if (ifunc != NULL) - outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); - else - outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); - } - - sreloc = elf_section_data (input_section)->sreloc; - if (ifunc) - { - sreloc = htab->elf.irelplt; - if (indx == 0) - htab->local_ifunc_resolver = 1; - else if (is_static_defined (h)) - htab->maybe_local_ifunc_resolver = 1; - } - if (sreloc == NULL) - return FALSE; - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - if (skip == -1) - goto copy_reloc; - - /* This reloc will be computed at runtime. Clear the memory - so that it contains a predictable value for prelink. */ - if (!skip) - { - relocation = howto->pc_relative ? outrel.r_offset : 0; - addend = 0; - break; - } - } - break; - - case R_PPC_RELAX_PLT: - case R_PPC_RELAX_PLTREL24: - if (h != NULL) - { - struct plt_entry *ent; - bfd_vma got2_addend = 0; - - if (r_type == R_PPC_RELAX_PLTREL24) - { - if (bfd_link_pic (info)) - got2_addend = addend; - addend = 0; - } - ent = find_plt_ent (&h->plt.plist, got2, got2_addend); - if (htab->plt_type == PLT_NEW) - relocation = (htab->glink->output_section->vma - + htab->glink->output_offset - + ent->glink_offset); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset); - } - /* Fall through. */ - - case R_PPC_RELAX: - { - const int *stub; - size_t size; - size_t insn_offset = rel->r_offset; - unsigned int insn; - - if (bfd_link_pic (info)) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset - 4); - stub = shared_stub_entry; - bfd_put_32 (input_bfd, stub[0], contents + insn_offset - 12); - bfd_put_32 (input_bfd, stub[1], contents + insn_offset - 8); - bfd_put_32 (input_bfd, stub[2], contents + insn_offset - 4); - stub += 3; - size = ARRAY_SIZE (shared_stub_entry) - 3; - } - else - { - stub = stub_entry; - size = ARRAY_SIZE (stub_entry); - } - --size; - - relocation += addend; - if (bfd_link_relocatable (info)) - relocation = 0; - - /* First insn is HA, second is LO. */ - insn = *stub++; - insn |= ((relocation + 0x8000) >> 16) & 0xffff; - bfd_put_32 (input_bfd, insn, contents + insn_offset); - insn_offset += 4; - - insn = *stub++; - insn |= relocation & 0xffff; - bfd_put_32 (input_bfd, insn, contents + insn_offset); - insn_offset += 4; - size -= 2; - - while (size != 0) - { - insn = *stub++; - --size; - bfd_put_32 (input_bfd, insn, contents + insn_offset); - insn_offset += 4; - } - output_bctr (htab, input_bfd, contents + insn_offset); - - /* Rewrite the reloc and convert one of the trailing nop - relocs to describe this relocation. */ - BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE); - /* The relocs are at the bottom 2 bytes */ - wrel->r_offset = rel->r_offset + d_offset; - wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA); - wrel->r_addend = rel->r_addend; - memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel)); - wrel++, rel++; - wrel->r_offset += 4; - wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO); - } - continue; - - /* Indirect .sdata relocation. */ - case R_PPC_EMB_SDAI16: - BFD_ASSERT (htab->sdata[0].section != NULL); - if (!is_static_defined (htab->sdata[0].sym)) - { - unresolved_reloc = TRUE; - break; - } - relocation - = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0], - h, relocation, rel); - addend = 0; - break; - - /* Indirect .sdata2 relocation. */ - case R_PPC_EMB_SDA2I16: - BFD_ASSERT (htab->sdata[1].section != NULL); - if (!is_static_defined (htab->sdata[1].sym)) - { - unresolved_reloc = TRUE; - break; - } - relocation - = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1], - h, relocation, rel); - addend = 0; - break; - - /* Handle the TOC16 reloc. We want to use the offset within the .got - section, not the actual VMA. This is appropriate when generating - an embedded ELF object, for which the .got section acts like the - AIX .toc section. */ - case R_PPC_TOC16: /* phony GOT16 relocations */ - if (sec == NULL || sec->output_section == NULL) - { - unresolved_reloc = TRUE; - break; - } - BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec), - ".got") == 0 - || strcmp (bfd_get_section_name (sec->owner, sec), - ".cgot") == 0); - - addend -= sec->output_section->vma + sec->output_offset + 0x8000; - break; - - case R_PPC_PLTREL24: - if (h != NULL && ifunc == NULL) - { - struct plt_entry *ent; - - ent = find_plt_ent (&h->plt.plist, got2, - bfd_link_pic (info) ? addend : 0); - if (ent == NULL - || htab->elf.splt == NULL) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - } - else - { - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - unresolved_reloc = FALSE; - if (htab->plt_type == PLT_NEW) - relocation = (htab->glink->output_section->vma - + htab->glink->output_offset - + ent->glink_offset); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset); - } - } - - /* R_PPC_PLTREL24 is rather special. If non-zero, the - addend specifies the GOT pointer offset within .got2. - Don't apply it to the relocation field. */ - addend = 0; - break; - - /* Relocate against _SDA_BASE_. */ - case R_PPC_SDAREL16: - { - const char *name; - struct elf_link_hash_entry *sda = htab->sdata[0].sym; - - if (sec == NULL - || sec->output_section == NULL - || !is_static_defined (sda)) - { - unresolved_reloc = TRUE; - break; - } - addend -= SYM_VAL (sda); - - name = bfd_get_section_name (output_bfd, sec->output_section); - if (!(strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0)) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: the target (%s) of a %s relocation is " - "in the wrong output section (%s)\n"), - input_bfd, - sym_name, - howto->name, - name); - } - } - break; - - /* Relocate against _SDA2_BASE_. */ - case R_PPC_EMB_SDA2REL: - { - const char *name; - struct elf_link_hash_entry *sda = htab->sdata[1].sym; - - if (sec == NULL - || sec->output_section == NULL - || !is_static_defined (sda)) - { - unresolved_reloc = TRUE; - break; - } - addend -= SYM_VAL (sda); - - name = bfd_get_section_name (output_bfd, sec->output_section); - if (!(strcmp (name, ".sdata2") == 0 - || strcmp (name, ".sbss2") == 0)) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: the target (%s) of a %s relocation is " - "in the wrong output section (%s)\n"), - input_bfd, - sym_name, - howto->name, - name); - } - } - break; - - case R_PPC_VLE_LO16A: - relocation = relocation + addend; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, relocation, - split16a_type, htab->params->vle_reloc_fixup); - goto copy_reloc; - - case R_PPC_VLE_LO16D: - relocation = relocation + addend; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, relocation, - split16d_type, htab->params->vle_reloc_fixup); - goto copy_reloc; - - case R_PPC_VLE_HI16A: - relocation = (relocation + addend) >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, relocation, - split16a_type, htab->params->vle_reloc_fixup); - goto copy_reloc; - - case R_PPC_VLE_HI16D: - relocation = (relocation + addend) >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, relocation, - split16d_type, htab->params->vle_reloc_fixup); - goto copy_reloc; - - case R_PPC_VLE_HA16A: - relocation = (relocation + addend + 0x8000) >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, relocation, - split16a_type, htab->params->vle_reloc_fixup); - goto copy_reloc; - - case R_PPC_VLE_HA16D: - relocation = (relocation + addend + 0x8000) >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, relocation, - split16d_type, htab->params->vle_reloc_fixup); - goto copy_reloc; - - /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ - case R_PPC_EMB_SDA21: - case R_PPC_VLE_SDA21: - case R_PPC_EMB_RELSDA: - case R_PPC_VLE_SDA21_LO: - { - const char *name; - int reg; - unsigned int insn; - struct elf_link_hash_entry *sda = NULL; - - if (sec == NULL || sec->output_section == NULL) - { - unresolved_reloc = TRUE; - break; - } - - name = bfd_get_section_name (output_bfd, sec->output_section); - if (strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0) - { - reg = 13; - sda = htab->sdata[0].sym; - } - else if (strcmp (name, ".sdata2") == 0 - || strcmp (name, ".sbss2") == 0) - { - reg = 2; - sda = htab->sdata[1].sym; - } - else if (strcmp (name, ".PPC.EMB.sdata0") == 0 - || strcmp (name, ".PPC.EMB.sbss0") == 0) - { - reg = 0; - } - else - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: the target (%s) of a %s relocation is " - "in the wrong output section (%s)\n"), - input_bfd, - sym_name, - howto->name, - name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - goto copy_reloc; - } - - if (sda != NULL) - { - if (!is_static_defined (sda)) - { - unresolved_reloc = TRUE; - break; - } - addend -= SYM_VAL (sda); - } - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if (reg == 0 - && (r_type == R_PPC_VLE_SDA21 - || r_type == R_PPC_VLE_SDA21_LO)) - { - relocation = relocation + addend; - addend = 0; - - /* Force e_li insn, keeping RT from original insn. */ - insn &= 0x1f << 21; - insn |= 28u << 26; - - /* We have an li20 field, bits 17..20, 11..15, 21..31. */ - /* Top 4 bits of value to 17..20. */ - insn |= (relocation & 0xf0000) >> 5; - /* Next 5 bits of the value to 11..15. */ - insn |= (relocation & 0xf800) << 5; - /* And the final 11 bits of the value to bits 21 to 31. */ - insn |= relocation & 0x7ff; - - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - - if (r_type == R_PPC_VLE_SDA21 - && ((relocation + 0x80000) & 0xffffffff) > 0x100000) - goto overflow; - goto copy_reloc; - } - else if (r_type == R_PPC_EMB_SDA21 - || r_type == R_PPC_VLE_SDA21 - || r_type == R_PPC_VLE_SDA21_LO) - { - /* Fill in register field. */ - insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); - } - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - break; - - case R_PPC_VLE_SDAREL_LO16A: - case R_PPC_VLE_SDAREL_LO16D: - case R_PPC_VLE_SDAREL_HI16A: - case R_PPC_VLE_SDAREL_HI16D: - case R_PPC_VLE_SDAREL_HA16A: - case R_PPC_VLE_SDAREL_HA16D: - { - bfd_vma value; - const char *name; - struct elf_link_hash_entry *sda = NULL; - - if (sec == NULL || sec->output_section == NULL) - { - unresolved_reloc = TRUE; - break; - } - - name = bfd_get_section_name (output_bfd, sec->output_section); - if (strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0) - sda = htab->sdata[0].sym; - else if (strcmp (name, ".sdata2") == 0 - || strcmp (name, ".sbss2") == 0) - sda = htab->sdata[1].sym; - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: the target (%s) of a %s relocation is " - "in the wrong output section (%s)"), - input_bfd, - sym_name, - howto->name, - name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - goto copy_reloc; - } - - if (sda == NULL || !is_static_defined (sda)) - { - unresolved_reloc = TRUE; - break; - } - value = relocation + addend - SYM_VAL (sda); - - if (r_type == R_PPC_VLE_SDAREL_LO16A) - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, value, - split16a_type, - htab->params->vle_reloc_fixup); - else if (r_type == R_PPC_VLE_SDAREL_LO16D) - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, value, - split16d_type, - htab->params->vle_reloc_fixup); - else if (r_type == R_PPC_VLE_SDAREL_HI16A) - { - value = value >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, value, - split16a_type, - htab->params->vle_reloc_fixup); - } - else if (r_type == R_PPC_VLE_SDAREL_HI16D) - { - value = value >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, value, - split16d_type, - htab->params->vle_reloc_fixup); - } - else if (r_type == R_PPC_VLE_SDAREL_HA16A) - { - value = (value + 0x8000) >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, value, - split16a_type, - htab->params->vle_reloc_fixup); - } - else if (r_type == R_PPC_VLE_SDAREL_HA16D) - { - value = (value + 0x8000) >> 16; - ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset, - contents + rel->r_offset, value, - split16d_type, - htab->params->vle_reloc_fixup); - } - } - goto copy_reloc; - - case R_PPC_VLE_ADDR20: - ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation); - continue; - - /* Relocate against the beginning of the section. */ - case R_PPC_SECTOFF: - case R_PPC_SECTOFF_LO: - case R_PPC_SECTOFF_HI: - case R_PPC_SECTOFF_HA: - if (sec == NULL || sec->output_section == NULL) - { - unresolved_reloc = TRUE; - break; - } - addend -= sec->output_section->vma; - break; - - /* Negative relocations. */ - case R_PPC_EMB_NADDR32: - case R_PPC_EMB_NADDR16: - case R_PPC_EMB_NADDR16_LO: - case R_PPC_EMB_NADDR16_HI: - case R_PPC_EMB_NADDR16_HA: - addend -= 2 * relocation; - break; - - case R_PPC_COPY: - case R_PPC_GLOB_DAT: - case R_PPC_JMP_SLOT: - case R_PPC_RELATIVE: - case R_PPC_IRELATIVE: - case R_PPC_PLT32: - case R_PPC_PLTREL32: - case R_PPC_PLT16_LO: - case R_PPC_PLT16_HI: - case R_PPC_PLT16_HA: - case R_PPC_ADDR30: - case R_PPC_EMB_RELSEC16: - case R_PPC_EMB_RELST_LO: - case R_PPC_EMB_RELST_HI: - case R_PPC_EMB_RELST_HA: - case R_PPC_EMB_BIT_FLD: - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: relocation %s is not yet supported for symbol %s\n"), - input_bfd, - howto->name, - sym_name); - - bfd_set_error (bfd_error_invalid_operation); - ret = FALSE; - goto copy_reloc; - } - - /* Do any further special processing. */ - switch (r_type) - { - default: - break; - - case R_PPC_ADDR16_HA: - case R_PPC_REL16_HA: - case R_PPC_REL16DX_HA: - case R_PPC_SECTOFF_HA: - case R_PPC_TPREL16_HA: - case R_PPC_DTPREL16_HA: - case R_PPC_EMB_NADDR16_HA: - case R_PPC_EMB_RELST_HA: - /* It's just possible that this symbol is a weak symbol - that's not actually defined anywhere. In that case, - 'sec' would be NULL, and we should leave the symbol - alone (it will be set to zero elsewhere in the link). */ - if (sec == NULL) - break; - /* Fall through. */ - - case R_PPC_PLT16_HA: - case R_PPC_GOT16_HA: - case R_PPC_GOT_TLSGD16_HA: - case R_PPC_GOT_TLSLD16_HA: - case R_PPC_GOT_TPREL16_HA: - case R_PPC_GOT_DTPREL16_HA: - /* Add 0x10000 if sign bit in 0:15 is set. - Bits 0:15 are not used. */ - addend += 0x8000; - break; - - case R_PPC_ADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_GOT16: - case R_PPC_GOT16_LO: - case R_PPC_SDAREL16: - case R_PPC_SECTOFF: - case R_PPC_SECTOFF_LO: - case R_PPC_DTPREL16: - case R_PPC_DTPREL16_LO: - case R_PPC_TPREL16: - case R_PPC_TPREL16_LO: - case R_PPC_GOT_TLSGD16: - case R_PPC_GOT_TLSGD16_LO: - case R_PPC_GOT_TLSLD16: - case R_PPC_GOT_TLSLD16_LO: - case R_PPC_GOT_DTPREL16: - case R_PPC_GOT_DTPREL16_LO: - case R_PPC_GOT_TPREL16: - case R_PPC_GOT_TPREL16_LO: - { - /* The 32-bit ABI lacks proper relocations to deal with - certain 64-bit instructions. Prevent damage to bits - that make up part of the insn opcode. */ - unsigned int insn, mask, lobit; - - insn = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - mask = 0; - if (is_insn_ds_form (insn)) - mask = 3; - else if (is_insn_dq_form (insn)) - mask = 15; - else - break; - relocation += addend; - addend = insn & mask; - lobit = mask & relocation; - if (lobit != 0) - { - relocation ^= lobit; - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: error: %s against `%s' not a multiple of %u\n"), - input_bfd, input_section, rel->r_offset, - howto->name, sym_name, mask + 1); - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - } - } - break; - } - -#ifdef DEBUG - fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, " - "offset = %ld, addend = %ld\n", - howto->name, - (int) r_type, - sym_name, - r_symndx, - (long) rel->r_offset, - (long) addend); -#endif - - if (unresolved_reloc - && !((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic) - && _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: unresolvable %s relocation against symbol `%s'\n"), - input_bfd, input_section, rel->r_offset, - howto->name, - sym_name); - ret = FALSE; - } - - /* 16-bit fields in insns mostly have signed values, but a - few insns have 16-bit unsigned values. Really, we should - have different reloc types. */ - if (howto->complain_on_overflow != complain_overflow_dont - && howto->dst_mask == 0xffff - && (input_section->flags & SEC_CODE) != 0) - { - enum complain_overflow complain = complain_overflow_signed; - - if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0) - { - unsigned int insn; - - insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) - complain = complain_overflow_bitfield; - else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */ - || (insn & (0x3f << 26)) == 24u << 26 /* ori */ - || (insn & (0x3f << 26)) == 26u << 26 /* xori */) - complain = complain_overflow_unsigned; - } - if (howto->complain_on_overflow != complain) - { - alt_howto = *howto; - alt_howto.complain_on_overflow = complain; - howto = &alt_howto; - } - } - - if (r_type == R_PPC_REL16DX_HA) - { - /* Split field reloc isn't handled by _bfd_final_link_relocate. */ - if (rel->r_offset + 4 > input_section->size) - r = bfd_reloc_outofrange; - else - { - unsigned int insn; - - relocation += addend; - relocation -= (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma); - relocation >>= 16; - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn &= ~0x1fffc1; - insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - r = bfd_reloc_ok; - } - } - else - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, relocation, addend); - - if (r != bfd_reloc_ok) - { - if (r == bfd_reloc_overflow) - { - overflow: - /* On code like "if (foo) foo();" don't report overflow - on a branch to zero when foo is undefined. */ - if (!warned - && !(h != NULL - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined) - && is_branch_reloc (r_type))) - info->callbacks->reloc_overflow - (info, (h ? &h->root : NULL), sym_name, howto->name, - rel->r_addend, input_bfd, input_section, rel->r_offset); - } - else - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s reloc against `%s': error %d\n"), - input_bfd, input_section, rel->r_offset, - howto->name, sym_name, (int) r); - ret = FALSE; - } - } - copy_reloc: - if (wrel != rel) - *wrel = *rel; - } - - if (wrel != rel) - { - Elf_Internal_Shdr *rel_hdr; - size_t deleted = rel - wrel; - - rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - if (rel_hdr->sh_size == 0) - { - /* It is too late to remove an empty reloc section. Leave - one NONE reloc. - ??? What is wrong with an empty section??? */ - rel_hdr->sh_size = rel_hdr->sh_entsize; - deleted -= 1; - wrel++; - } - relend = wrel; - rel_hdr = _bfd_elf_single_rel_hdr (input_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - input_section->reloc_count -= deleted; - } - -#ifdef DEBUG - fprintf (stderr, "\n"); -#endif - - if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET - && input_section->size != input_section->rawsize - && (strcmp (input_section->output_section->name, ".init") == 0 - || strcmp (input_section->output_section->name, ".fini") == 0)) - { - /* Branch around the trampolines. */ - unsigned int insn = B + input_section->size - input_section->rawsize; - bfd_put_32 (input_bfd, insn, contents + input_section->rawsize); - } - - if (htab->params->ppc476_workaround - && input_section->sec_info_type == SEC_INFO_TYPE_TARGET - && (!bfd_link_relocatable (info) - || (input_section->output_section->alignment_power - >= htab->params->pagesize_p2))) - { - bfd_vma start_addr, end_addr, addr; - bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; - - if (relax_info->workaround_size != 0) - { - bfd_byte *p; - unsigned int n; - bfd_byte fill[4]; - - bfd_put_32 (input_bfd, BA, fill); - p = contents + input_section->size - relax_info->workaround_size; - n = relax_info->workaround_size >> 2; - while (n--) - { - memcpy (p, fill, 4); - p += 4; - } - } - - /* The idea is: Replace the last instruction on a page with a - branch to a patch area. Put the insn there followed by a - branch back to the next page. Complicated a little by - needing to handle moved conditional branches, and by not - wanting to touch data-in-text. */ - - start_addr = (input_section->output_section->vma - + input_section->output_offset); - end_addr = (start_addr + input_section->size - - relax_info->workaround_size); - for (addr = ((start_addr & -pagesize) + pagesize - 4); - addr < end_addr; - addr += pagesize) - { - bfd_vma offset = addr - start_addr; - Elf_Internal_Rela *lo, *hi; - bfd_boolean is_data; - bfd_vma patch_off, patch_addr; - unsigned int insn; - - /* Do we have a data reloc at this offset? If so, leave - the word alone. */ - is_data = FALSE; - lo = relocs; - hi = relend; - rel = NULL; - while (lo < hi) - { - rel = lo + (hi - lo) / 2; - if (rel->r_offset < offset) - lo = rel + 1; - else if (rel->r_offset > offset + 3) - hi = rel; - else - { - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_PPC_ADDR32: - case R_PPC_UADDR32: - case R_PPC_REL32: - case R_PPC_ADDR30: - is_data = TRUE; - break; - default: - break; - } - break; - } - } - if (is_data) - continue; - - /* Some instructions can be left alone too. Unconditional - branches, except for bcctr with BO=0x14 (bctr, bctrl), - avoid the icache failure. - - The problem occurs due to prefetch across a page boundary - where stale instructions can be fetched from the next - page, and the mechanism for flushing these bad - instructions fails under certain circumstances. The - unconditional branches: - 1) Branch: b, bl, ba, bla, - 2) Branch Conditional: bc, bca, bcl, bcla, - 3) Branch Conditional to Link Register: bclr, bclrl, - where (2) and (3) have BO=0x14 making them unconditional, - prevent the bad prefetch because the prefetch itself is - affected by these instructions. This happens even if the - instruction is not executed. - - A bctr example: - . - . lis 9,new_page@ha - . addi 9,9,new_page@l - . mtctr 9 - . bctr - . nop - . nop - . new_page: - . - The bctr is not predicted taken due to ctr not being - ready, so prefetch continues on past the bctr into the - new page which might have stale instructions. If they - fail to be flushed, then they will be executed after the - bctr executes. Either of the following modifications - prevent the bad prefetch from happening in the first - place: - . - . lis 9,new_page@ha lis 9,new_page@ha - . addi 9,9,new_page@l addi 9,9,new_page@l - . mtctr 9 mtctr 9 - . bctr bctr - . nop b somewhere_else - . b somewhere_else nop - . new_page: new_page: - . */ - insn = bfd_get_32 (input_bfd, contents + offset); - if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */ - || ((insn & (0x3f << 26)) == (16u << 26) /* bc,bcl,bca,bcla*/ - && (insn & (0x14 << 21)) == (0x14 << 21)) /* with BO=0x14 */ - || ((insn & (0x3f << 26)) == (19u << 26) - && (insn & (0x3ff << 1)) == (16u << 1) /* bclr,bclrl */ - && (insn & (0x14 << 21)) == (0x14 << 21)))/* with BO=0x14 */ - continue; - - patch_addr = (start_addr + input_section->size - - relax_info->workaround_size); - patch_addr = (patch_addr + 15) & -16; - patch_off = patch_addr - start_addr; - bfd_put_32 (input_bfd, B + patch_off - offset, contents + offset); - - if (rel != NULL - && rel->r_offset >= offset - && rel->r_offset < offset + 4) - { - asection *sreloc; - - /* If the insn we are patching had a reloc, adjust the - reloc r_offset so that the reloc applies to the moved - location. This matters for -r and --emit-relocs. */ - if (rel + 1 != relend) - { - Elf_Internal_Rela tmp = *rel; - - /* Keep the relocs sorted by r_offset. */ - memmove (rel, rel + 1, (relend - (rel + 1)) * sizeof (*rel)); - relend[-1] = tmp; - } - relend[-1].r_offset += patch_off - offset; - - /* Adjust REL16 addends too. */ - switch (ELF32_R_TYPE (relend[-1].r_info)) - { - case R_PPC_REL16: - case R_PPC_REL16_LO: - case R_PPC_REL16_HI: - case R_PPC_REL16_HA: - relend[-1].r_addend += patch_off - offset; - break; - default: - break; - } - - /* If we are building a PIE or shared library with - non-PIC objects, perhaps we had a dynamic reloc too? - If so, the dynamic reloc must move with the insn. */ - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc != NULL) - { - Elf32_External_Rela *slo, *shi, *srelend; - bfd_vma soffset; - - slo = (Elf32_External_Rela *) sreloc->contents; - shi = srelend = slo + sreloc->reloc_count; - soffset = (offset + input_section->output_section->vma - + input_section->output_offset); - while (slo < shi) - { - Elf32_External_Rela *srel = slo + (shi - slo) / 2; - bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel, - &outrel); - if (outrel.r_offset < soffset) - slo = srel + 1; - else if (outrel.r_offset > soffset + 3) - shi = srel; - else - { - if (srel + 1 != srelend) - { - memmove (srel, srel + 1, - (srelend - (srel + 1)) * sizeof (*srel)); - srel = srelend - 1; - } - outrel.r_offset += patch_off - offset; - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - (bfd_byte *) srel); - break; - } - } - } - } - else - rel = NULL; - - if ((insn & (0x3f << 26)) == (16u << 26) /* bc */ - && (insn & 2) == 0 /* relative */) - { - bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000; - - delta += offset - patch_off; - if (bfd_link_relocatable (info) && rel != NULL) - delta = 0; - if (!bfd_link_relocatable (info) && rel != NULL) - { - enum elf_ppc_reloc_type r_type; - - r_type = ELF32_R_TYPE (relend[-1].r_info); - if (r_type == R_PPC_REL14_BRTAKEN) - insn |= BRANCH_PREDICT_BIT; - else if (r_type == R_PPC_REL14_BRNTAKEN) - insn &= ~BRANCH_PREDICT_BIT; - else - BFD_ASSERT (r_type == R_PPC_REL14); - - if ((r_type == R_PPC_REL14_BRTAKEN - || r_type == R_PPC_REL14_BRNTAKEN) - && delta + 0x8000 < 0x10000 - && (bfd_signed_vma) delta < 0) - insn ^= BRANCH_PREDICT_BIT; - } - if (delta + 0x8000 < 0x10000) - { - bfd_put_32 (input_bfd, - (insn & ~0xfffc) | (delta & 0xfffc), - contents + patch_off); - patch_off += 4; - bfd_put_32 (input_bfd, - B | ((offset + 4 - patch_off) & 0x3fffffc), - contents + patch_off); - patch_off += 4; - } - else - { - if (rel != NULL) - { - unsigned int r_sym = ELF32_R_SYM (relend[-1].r_info); - - relend[-1].r_offset += 8; - relend[-1].r_info = ELF32_R_INFO (r_sym, R_PPC_REL24); - } - bfd_put_32 (input_bfd, - (insn & ~0xfffc) | 8, - contents + patch_off); - patch_off += 4; - bfd_put_32 (input_bfd, - B | ((offset + 4 - patch_off) & 0x3fffffc), - contents + patch_off); - patch_off += 4; - bfd_put_32 (input_bfd, - B | ((delta - 8) & 0x3fffffc), - contents + patch_off); - patch_off += 4; - } - } - else - { - bfd_put_32 (input_bfd, insn, contents + patch_off); - patch_off += 4; - bfd_put_32 (input_bfd, - B | ((offset + 4 - patch_off) & 0x3fffffc), - contents + patch_off); - patch_off += 4; - } - BFD_ASSERT (patch_off <= input_section->size); - relax_info->workaround_size = input_section->size - patch_off; - } - } - - return ret; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -ppc_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct ppc_elf_link_hash_table *htab; - struct plt_entry *ent; - bfd_boolean doneone; - -#ifdef DEBUG - fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", - h->root.root.string); -#endif - - htab = ppc_elf_hash_table (info); - BFD_ASSERT (htab->elf.dynobj != NULL); - - doneone = FALSE; - for (ent = h->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.offset != (bfd_vma) -1) - { - if (!doneone) - { - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_vma reloc_index; - - if (htab->plt_type == PLT_NEW - || !htab->elf.dynamic_sections_created - || h->dynindx == -1) - reloc_index = ent->plt.offset / 4; - else - { - reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size) - / htab->plt_slot_size); - if (reloc_index > PLT_NUM_SINGLE_ENTRIES - && htab->plt_type == PLT_OLD) - reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; - } - - /* This symbol has an entry in the procedure linkage table. - Set it up. */ - if (htab->plt_type == PLT_VXWORKS - && htab->elf.dynamic_sections_created - && h->dynindx != -1) - { - bfd_vma got_offset; - const bfd_vma *plt_entry; - - /* The first three entries in .got.plt are reserved. */ - got_offset = (reloc_index + 3) * 4; - - /* Use the right PLT. */ - plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry - : ppc_elf_vxworks_plt_entry; - - /* Fill in the .plt on VxWorks. */ - if (bfd_link_pic (info)) - { - bfd_put_32 (output_bfd, - plt_entry[0] | PPC_HA (got_offset), - htab->elf.splt->contents + ent->plt.offset + 0); - bfd_put_32 (output_bfd, - plt_entry[1] | PPC_LO (got_offset), - htab->elf.splt->contents + ent->plt.offset + 4); - } - else - { - bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot); - - bfd_put_32 (output_bfd, - plt_entry[0] | PPC_HA (got_loc), - htab->elf.splt->contents + ent->plt.offset + 0); - bfd_put_32 (output_bfd, - plt_entry[1] | PPC_LO (got_loc), - htab->elf.splt->contents + ent->plt.offset + 4); - } - - bfd_put_32 (output_bfd, plt_entry[2], - htab->elf.splt->contents + ent->plt.offset + 8); - bfd_put_32 (output_bfd, plt_entry[3], - htab->elf.splt->contents + ent->plt.offset + 12); - - /* This instruction is an immediate load. The value loaded is - the byte offset of the R_PPC_JMP_SLOT relocation from the - start of the .rela.plt section. The value is stored in the - low-order 16 bits of the load instruction. */ - /* NOTE: It appears that this is now an index rather than a - prescaled offset. */ - bfd_put_32 (output_bfd, - plt_entry[4] | reloc_index, - htab->elf.splt->contents + ent->plt.offset + 16); - /* This instruction is a PC-relative branch whose target is - the start of the PLT section. The address of this branch - instruction is 20 bytes beyond the start of this PLT entry. - The address is encoded in bits 6-29, inclusive. The value - stored is right-shifted by two bits, permitting a 26-bit - offset. */ - bfd_put_32 (output_bfd, - (plt_entry[5] - | (-(ent->plt.offset + 20) & 0x03fffffc)), - htab->elf.splt->contents + ent->plt.offset + 20); - bfd_put_32 (output_bfd, plt_entry[6], - htab->elf.splt->contents + ent->plt.offset + 24); - bfd_put_32 (output_bfd, plt_entry[7], - htab->elf.splt->contents + ent->plt.offset + 28); - - /* Fill in the GOT entry corresponding to this PLT slot with - the address immediately after the "bctr" instruction - in this PLT entry. */ - bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset + 16), - htab->elf.sgotplt->contents + got_offset); - - if (!bfd_link_pic (info)) - { - /* Fill in a couple of entries in .rela.plt.unloaded. */ - loc = htab->srelplt2->contents - + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index - * VXWORKS_PLT_NON_JMP_SLOT_RELOCS) - * sizeof (Elf32_External_Rela)); - - /* Provide the @ha relocation for the first instruction. */ - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset + 2); - rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, - R_PPC_ADDR16_HA); - rela.r_addend = got_offset; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - loc += sizeof (Elf32_External_Rela); - - /* Provide the @l relocation for the second instruction. */ - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset + 6); - rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, - R_PPC_ADDR16_LO); - rela.r_addend = got_offset; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - loc += sizeof (Elf32_External_Rela); - - /* Provide a relocation for the GOT entry corresponding to this - PLT slot. Point it at the middle of the .plt entry. */ - rela.r_offset = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, - R_PPC_ADDR32); - rela.r_addend = ent->plt.offset + 16; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. - In particular, the offset for the relocation is not the - address of the PLT entry for this function, as specified - by the ABI. Instead, the offset is set to the address of - the GOT slot for this function. See EABI 4.4.4.1. */ - rela.r_offset = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + got_offset); - - } - else - { - asection *splt = htab->elf.splt; - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - splt = htab->elf.iplt; - - rela.r_offset = (splt->output_section->vma - + splt->output_offset - + ent->plt.offset); - if (htab->plt_type == PLT_OLD - || !htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - /* We don't need to fill in the .plt. The ppc dynamic - linker will fill it in. */ - } - else - { - bfd_vma val = (htab->glink_pltresolve + ent->plt.offset - + htab->glink->output_section->vma - + htab->glink->output_offset); - bfd_put_32 (output_bfd, val, - splt->contents + ent->plt.offset); - } - } - - /* Fill in the entry in the .rela.plt section. */ - rela.r_addend = 0; - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - BFD_ASSERT (h->type == STT_GNU_IFUNC - && h->def_regular - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); - rela.r_addend = SYM_VAL (h); - } - else - rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); - - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - loc = (htab->elf.irelplt->contents - + (htab->elf.irelplt->reloc_count++ - * sizeof (Elf32_External_Rela))); - htab->local_ifunc_resolver = 1; - } - else - { - loc = (htab->elf.srelplt->contents - + reloc_index * sizeof (Elf32_External_Rela)); - if (h->type == STT_GNU_IFUNC && is_static_defined (h)) - htab->maybe_local_ifunc_resolver = 1; - } - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as - defined in the .plt section. Leave the value 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. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; - else if (!h->ref_regular_nonweak) - { - /* This breaks function pointer comparisons, but - that is better than breaking tests for a NULL - function pointer. */ - sym->st_value = 0; - } - } - else if (h->type == STT_GNU_IFUNC - && !bfd_link_pic (info)) - { - /* Set the value of ifunc symbols in a non-pie - executable to the glink entry. This is to avoid - text relocations. We can't do this for ifunc in - allocate_dynrelocs, as we do for normal dynamic - function symbols with plt entries, because we need - to keep the original value around for the ifunc - relocation. */ - sym->st_shndx = (_bfd_elf_section_from_bfd_section - (output_bfd, htab->glink->output_section)); - sym->st_value = (ent->glink_offset - + htab->glink->output_offset - + htab->glink->output_section->vma); - } - doneone = TRUE; - } - - if (htab->plt_type == PLT_NEW - || !htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - unsigned char *p; - asection *splt = htab->elf.splt; - - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - splt = htab->elf.iplt; - - p = (unsigned char *) htab->glink->contents + ent->glink_offset; - write_glink_stub (h, ent, splt, p, info); - - if (!bfd_link_pic (info)) - /* We only need one non-PIC glink stub. */ - break; - } - else - break; - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbols needs a copy reloc. Set it up. */ - -#ifdef DEBUG - fprintf (stderr, ", copy"); -#endif - - BFD_ASSERT (h->dynindx != -1); - - if (ppc_elf_hash_entry (h)->has_sda_refs) - s = htab->relsbss; - else if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - BFD_ASSERT (s != NULL); - - rela.r_offset = SYM_VAL (h); - rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); - rela.r_addend = 0; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - -#ifdef DEBUG - fprintf (stderr, "\n"); -#endif - - return TRUE; -} - -static enum elf_reloc_type_class -ppc_elf_reloc_type_class (const struct bfd_link_info *info, - const asection *rel_sec, - const Elf_Internal_Rela *rela) -{ - struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); - - if (rel_sec == htab->elf.irelplt) - return reloc_class_ifunc; - - switch (ELF32_R_TYPE (rela->r_info)) - { - case R_PPC_RELATIVE: - return reloc_class_relative; - case R_PPC_JMP_SLOT: - return reloc_class_plt; - case R_PPC_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -ppc_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *sdyn; - struct ppc_elf_link_hash_table *htab; - bfd_vma got; - bfd *dynobj; - bfd_boolean ret = TRUE; - -#ifdef DEBUG - fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); -#endif - - htab = ppc_elf_hash_table (info); - dynobj = htab->elf.dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - got = 0; - if (htab->elf.hgot != NULL) - got = SYM_VAL (htab->elf.hgot); - - if (htab->elf.dynamic_sections_created) - { - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (htab->elf.splt != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_PLTGOT: - if (htab->is_vxworks) - s = htab->elf.sgotplt; - else - s = htab->elf.splt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = htab->elf.srelplt->size; - break; - - case DT_JMPREL: - s = htab->elf.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PPC_GOT: - dyn.d_un.d_ptr = got; - break; - - case DT_TEXTREL: - if (htab->local_ifunc_resolver) - info->callbacks->einfo - (_("%X%P: text relocations and GNU indirect " - "functions will result in a segfault at runtime\n")); - else if (htab->maybe_local_ifunc_resolver) - info->callbacks->einfo - (_("%P: warning: text relocations and GNU indirect " - "functions may result in a segfault at runtime\n")); - continue; - - default: - if (htab->is_vxworks - && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) - break; - continue; - } - - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - - if (htab->elf.sgot != NULL - && htab->elf.sgot->output_section != bfd_abs_section_ptr) - { - if (htab->elf.hgot->root.u.def.section == htab->elf.sgot - || htab->elf.hgot->root.u.def.section == htab->elf.sgotplt) - { - unsigned char *p = htab->elf.hgot->root.u.def.section->contents; - - p += htab->elf.hgot->root.u.def.value; - if (htab->plt_type == PLT_OLD) - { - /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 - so that a function can easily find the address of - _GLOBAL_OFFSET_TABLE_. */ - BFD_ASSERT (htab->elf.hgot->root.u.def.value - 4 - < htab->elf.hgot->root.u.def.section->size); - bfd_put_32 (output_bfd, 0x4e800021, p - 4); - } - - if (sdyn != NULL) - { - bfd_vma val = sdyn->output_section->vma + sdyn->output_offset; - BFD_ASSERT (htab->elf.hgot->root.u.def.value - < htab->elf.hgot->root.u.def.section->size); - bfd_put_32 (output_bfd, val, p); - } - } - else - { - /* xgettext:c-format */ - info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"), - htab->elf.hgot->root.root.string, - (htab->elf.sgotplt != NULL - ? htab->elf.sgotplt->name - : htab->elf.sgot->name)); - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - } - - elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; - } - - /* Fill in the first entry in the VxWorks procedure linkage table. */ - if (htab->is_vxworks - && htab->elf.splt != NULL - && htab->elf.splt->size != 0 - && htab->elf.splt->output_section != bfd_abs_section_ptr) - { - asection *splt = htab->elf.splt; - /* Use the right PLT. */ - const bfd_vma *plt_entry = (bfd_link_pic (info) - ? ppc_elf_vxworks_pic_plt0_entry - : ppc_elf_vxworks_plt0_entry); - - if (!bfd_link_pic (info)) - { - bfd_vma got_value = SYM_VAL (htab->elf.hgot); - - bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_value), - splt->contents + 0); - bfd_put_32 (output_bfd, plt_entry[1] | PPC_LO (got_value), - splt->contents + 4); - } - else - { - bfd_put_32 (output_bfd, plt_entry[0], splt->contents + 0); - bfd_put_32 (output_bfd, plt_entry[1], splt->contents + 4); - } - bfd_put_32 (output_bfd, plt_entry[2], splt->contents + 8); - bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12); - bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16); - bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20); - bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); - bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); - - if (! bfd_link_pic (info)) - { - Elf_Internal_Rela rela; - bfd_byte *loc; - - loc = htab->srelplt2->contents; - - /* Output the @ha relocation for the first instruction. */ - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + 2); - rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); - rela.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - loc += sizeof (Elf32_External_Rela); - - /* Output the @l relocation for the second instruction. */ - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + 6); - rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); - rela.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - loc += sizeof (Elf32_External_Rela); - - /* Fix up the remaining relocations. They may have the wrong - symbol index for _G_O_T_ or _P_L_T_ depending on the order - in which symbols were output. */ - while (loc < htab->srelplt2->contents + htab->srelplt2->size) - { - Elf_Internal_Rela rel; - - bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); - rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - - bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); - rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - - bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); - rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_PPC_ADDR32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - } - } - } - - if (htab->glink != NULL - && htab->glink->contents != NULL - && htab->elf.dynamic_sections_created) - { - unsigned char *p; - unsigned char *endp; - bfd_vma res0; - - /* - * PIC glink code is the following: - * - * # ith PLT code stub. - * addis 11,30,(plt+(i-1)*4-got)@ha - * lwz 11,(plt+(i-1)*4-got)@l(11) - * mtctr 11 - * bctr - * - * # A table of branches, one for each plt entry. - * # The idea is that the plt call stub loads ctr and r11 with these - * # addresses, so (r11 - res_0) gives the plt index * 4. - * res_0: b PLTresolve - * res_1: b PLTresolve - * . - * # Some number of entries towards the end can be nops - * res_n_m3: nop - * res_n_m2: nop - * res_n_m1: - * - * PLTresolve: - * addis 11,11,(1f-res_0)@ha - * mflr 0 - * bcl 20,31,1f - * 1: addi 11,11,(1b-res_0)@l - * mflr 12 - * mtlr 0 - * sub 11,11,12 # r11 = index * 4 - * addis 12,12,(got+4-1b)@ha - * lwz 0,(got+4-1b)@l(12) # got[1] address of dl_runtime_resolve - * lwz 12,(got+8-1b)@l(12) # got[2] contains the map address - * mtctr 0 - * add 0,11,11 - * add 11,0,11 # r11 = index * 12 = reloc offset. - * bctr - * - * Non-PIC glink code is a little simpler. - * - * # ith PLT code stub. - * lis 11,(plt+(i-1)*4)@ha - * lwz 11,(plt+(i-1)*4)@l(11) - * mtctr 11 - * bctr - * - * The branch table is the same, then comes - * - * PLTresolve: - * lis 12,(got+4)@ha - * addis 11,11,(-res_0)@ha - * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve - * addi 11,11,(-res_0)@l # r11 = index * 4 - * mtctr 0 - * add 0,11,11 - * lwz 12,(got+8)@l(12) # got[2] contains the map address - * add 11,0,11 # r11 = index * 12 = reloc offset. - * bctr - */ - - /* Build the branch table, one for each plt entry (less one), - and perhaps some padding. */ - p = htab->glink->contents; - p += htab->glink_pltresolve; - endp = htab->glink->contents; - endp += htab->glink->size - GLINK_PLTRESOLVE; - while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4)) - { - bfd_put_32 (output_bfd, B + endp - p, p); - p += 4; - } - while (p < endp) - { - bfd_put_32 (output_bfd, NOP, p); - p += 4; - } - - res0 = (htab->glink_pltresolve - + htab->glink->output_section->vma - + htab->glink->output_offset); - - if (htab->params->ppc476_workaround) - { - /* Ensure that a call stub at the end of a page doesn't - result in prefetch over the end of the page into the - glink branch table. */ - bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2; - bfd_vma page_addr; - bfd_vma glink_start = (htab->glink->output_section->vma - + htab->glink->output_offset); - - for (page_addr = res0 & -pagesize; - page_addr > glink_start; - page_addr -= pagesize) - { - /* We have a plt call stub that may need fixing. */ - bfd_byte *loc; - unsigned int insn; - - loc = htab->glink->contents + page_addr - 4 - glink_start; - insn = bfd_get_32 (output_bfd, loc); - if (insn == BCTR) - { - /* By alignment, we know that there must be at least - one other call stub before this one. */ - insn = bfd_get_32 (output_bfd, loc - 16); - if (insn == BCTR) - bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc); - else - bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc); - } - } - } - - /* Last comes the PLTresolve stub. */ - endp = p + GLINK_PLTRESOLVE; - if (bfd_link_pic (info)) - { - bfd_vma bcl; - - bcl = (htab->glink->size - GLINK_PLTRESOLVE + 3*4 - + htab->glink->output_section->vma - + htab->glink->output_offset); - - bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (bcl - res0), p); - p += 4; - bfd_put_32 (output_bfd, MFLR_0, p); - p += 4; - bfd_put_32 (output_bfd, BCL_20_31, p); - p += 4; - bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (bcl - res0), p); - p += 4; - bfd_put_32 (output_bfd, MFLR_12, p); - p += 4; - bfd_put_32 (output_bfd, MTLR_0, p); - p += 4; - bfd_put_32 (output_bfd, SUB_11_11_12, p); - p += 4; - bfd_put_32 (output_bfd, ADDIS_12_12 + PPC_HA (got + 4 - bcl), p); - p += 4; - if (PPC_HA (got + 4 - bcl) == PPC_HA (got + 8 - bcl)) - { - bfd_put_32 (output_bfd, LWZ_0_12 + PPC_LO (got + 4 - bcl), p); - p += 4; - bfd_put_32 (output_bfd, LWZ_12_12 + PPC_LO (got + 8 - bcl), p); - p += 4; - } - else - { - bfd_put_32 (output_bfd, LWZU_0_12 + PPC_LO (got + 4 - bcl), p); - p += 4; - bfd_put_32 (output_bfd, LWZ_12_12 + 4, p); - p += 4; - } - bfd_put_32 (output_bfd, MTCTR_0, p); - p += 4; - bfd_put_32 (output_bfd, ADD_0_11_11, p); - } - else - { - bfd_put_32 (output_bfd, LIS_12 + PPC_HA (got + 4), p); - p += 4; - bfd_put_32 (output_bfd, ADDIS_11_11 + PPC_HA (-res0), p); - p += 4; - if (PPC_HA (got + 4) == PPC_HA (got + 8)) - bfd_put_32 (output_bfd, LWZ_0_12 + PPC_LO (got + 4), p); - else - bfd_put_32 (output_bfd, LWZU_0_12 + PPC_LO (got + 4), p); - p += 4; - bfd_put_32 (output_bfd, ADDI_11_11 + PPC_LO (-res0), p); - p += 4; - bfd_put_32 (output_bfd, MTCTR_0, p); - p += 4; - bfd_put_32 (output_bfd, ADD_0_11_11, p); - p += 4; - if (PPC_HA (got + 4) == PPC_HA (got + 8)) - bfd_put_32 (output_bfd, LWZ_12_12 + PPC_LO (got + 8), p); - else - bfd_put_32 (output_bfd, LWZ_12_12 + 4, p); - } - p += 4; - bfd_put_32 (output_bfd, ADD_11_0_11, p); - p += 4; - p = output_bctr (htab, output_bfd, p); - while (p < endp) - { - bfd_put_32 (output_bfd, - htab->params->ppc476_workaround ? BA : NOP, p); - p += 4; - } - BFD_ASSERT (p == endp); - } - - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->contents != NULL) - { - unsigned char *p = htab->glink_eh_frame->contents; - bfd_vma val; - - p += sizeof (glink_eh_frame_cie); - /* FDE length. */ - p += 4; - /* CIE pointer. */ - p += 4; - /* Offset to .glink. */ - val = (htab->glink->output_section->vma - + htab->glink->output_offset); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset); - val -= p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - - if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME - && !_bfd_elf_write_section_eh_frame (output_bfd, info, - htab->glink_eh_frame, - htab->glink_eh_frame->contents)) - return FALSE; - } - - return ret; -} - -#define TARGET_LITTLE_SYM powerpc_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-powerpcle" -#define TARGET_BIG_SYM powerpc_elf32_vec -#define TARGET_BIG_NAME "elf32-powerpc" -#define ELF_ARCH bfd_arch_powerpc -#define ELF_TARGET_ID PPC32_ELF_DATA -#define ELF_MACHINE_CODE EM_PPC -#ifdef __QNXTARGET__ -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 -#else -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x10000 -#endif -#define ELF_MINPAGESIZE 0x1000 -#define elf_info_to_howto ppc_elf_info_to_howto - -#ifdef EM_CYGNUS_POWERPC -#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC -#endif - -#ifdef EM_PPC_OLD -#define ELF_MACHINE_ALT2 EM_PPC_OLD -#endif - -#define elf_backend_plt_not_loaded 1 -#define elf_backend_want_dynrelro 1 -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_rela_normal 1 -#define elf_backend_caches_rawsize 1 - -#define bfd_elf32_mkobject ppc_elf_mkobject -#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data -#define bfd_elf32_bfd_relax_section ppc_elf_relax_section -#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags -#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create -#define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab - -#define elf_backend_object_p ppc_elf_object_p -#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook -#define elf_backend_section_from_shdr ppc_elf_section_from_shdr -#define elf_backend_relocate_section ppc_elf_relocate_section -#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections -#define elf_backend_check_relocs ppc_elf_check_relocs -#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible -#define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol -#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol -#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook -#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections -#define elf_backend_hash_symbol ppc_elf_hash_symbol -#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections -#define elf_backend_fake_sections ppc_elf_fake_sections -#define elf_backend_additional_program_headers ppc_elf_additional_program_headers -#define elf_backend_modify_segment_map ppc_elf_modify_segment_map -#define elf_backend_grok_prstatus ppc_elf_grok_prstatus -#define elf_backend_grok_psinfo ppc_elf_grok_psinfo -#define elf_backend_write_core_note ppc_elf_write_core_note -#define elf_backend_reloc_type_class ppc_elf_reloc_type_class -#define elf_backend_begin_write_processing ppc_elf_begin_write_processing -#define elf_backend_final_write_processing ppc_elf_final_write_processing -#define elf_backend_write_section ppc_elf_write_section -#define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr -#define elf_backend_plt_sym_val ppc_elf_plt_sym_val -#define elf_backend_action_discarded ppc_elf_action_discarded -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags - -#include "elf32-target.h" - -/* FreeBSD Target */ - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM powerpc_elf32_fbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-powerpc-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf32_bed -#define elf32_bed elf32_powerpc_fbsd_bed - -#include "elf32-target.h" - -/* VxWorks Target */ - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM powerpc_elf32_vxworks_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-powerpc-vxworks" - -#undef ELF_OSABI - -/* VxWorks uses the elf default section flags for .plt. */ -static const struct bfd_elf_special_section * -ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec) -{ - if (sec->name == NULL) - return NULL; - - if (strcmp (sec->name, ".plt") == 0) - return _bfd_elf_get_sec_type_attr (abfd, sec); - - return ppc_elf_get_sec_type_attr (abfd, sec); -} - -/* Like ppc_elf_link_hash_table_create, but overrides - appropriately for VxWorks. */ -static struct bfd_link_hash_table * -ppc_elf_vxworks_link_hash_table_create (bfd *abfd) -{ - struct bfd_link_hash_table *ret; - - ret = ppc_elf_link_hash_table_create (abfd); - if (ret) - { - struct ppc_elf_link_hash_table *htab - = (struct ppc_elf_link_hash_table *)ret; - htab->is_vxworks = 1; - htab->plt_type = PLT_VXWORKS; - htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE; - htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE; - htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE; - } - return ret; -} - -/* Tweak magic VxWorks symbols as they are loaded. */ -static bfd_boolean -ppc_elf_vxworks_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep, - flagword *flagsp, - asection **secp, - bfd_vma *valp) -{ - if (!elf_vxworks_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, - valp)) - return FALSE; - - return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp); -} - -static void -ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) -{ - ppc_elf_final_write_processing (abfd, linker); - elf_vxworks_final_write_processing (abfd, linker); -} - -/* 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 elf_backend_want_got_plt -#define elf_backend_want_got_plt 1 -#undef elf_backend_got_symbol_offset -#define elf_backend_got_symbol_offset 0 -#undef elf_backend_plt_not_loaded -#define elf_backend_plt_not_loaded 0 -#undef elf_backend_plt_readonly -#define elf_backend_plt_readonly 1 -#undef elf_backend_got_header_size -#define elf_backend_got_header_size 12 -#undef elf_backend_dtrel_excludes_plt -#define elf_backend_dtrel_excludes_plt 1 - -#undef bfd_elf32_get_synthetic_symtab - -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create \ - ppc_elf_vxworks_link_hash_table_create -#undef elf_backend_add_symbol_hook -#define elf_backend_add_symbol_hook \ - ppc_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_final_write_processing -#define elf_backend_final_write_processing \ - ppc_elf_vxworks_final_write_processing -#undef elf_backend_get_sec_type_attr -#define elf_backend_get_sec_type_attr \ - ppc_elf_vxworks_get_sec_type_attr -#undef elf_backend_emit_relocs -#define elf_backend_emit_relocs \ - elf_vxworks_emit_relocs - -#undef elf32_bed -#define elf32_bed ppc_elf_vxworks_bed -#undef elf_backend_post_process_headers - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-ppc.h b/sdcc/support/sdbinutils/bfd/elf32-ppc.h deleted file mode 100644 index 8977efa23..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-ppc.h +++ /dev/null @@ -1,71 +0,0 @@ -/* PowerPC-specific support for 64-bit ELF. - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -enum ppc_elf_plt_type -{ - PLT_UNSET, - PLT_OLD, - PLT_NEW, - PLT_VXWORKS -}; - -/* Various options passed from the linker to bfd backend. */ -struct ppc_elf_params -{ - /* Chooses the type of .plt. */ - enum ppc_elf_plt_type plt_style; - - /* Set if individual PLT call stubs should be aligned. */ - int plt_stub_align; - - /* Clear if PLT call stubs should use a speculative execution barrier. */ - int speculate_indirect_jumps; - - /* Whether to emit symbols for stubs. */ - int emit_stub_syms; - - /* Whether to emit special stub for __tls_get_addr calls. */ - int no_tls_get_addr_opt; - - /* Insert trampolines for branches that won't reach their destination. */ - int branch_trampolines; - - /* Avoid execution falling into new page. */ - int ppc476_workaround; - unsigned int pagesize_p2; - - /* The bfd backend detected a non-PIC reference to a protected symbol - defined in a shared library. */ - int pic_fixup; - - /* Relocate 16A relocs as 16D and vice versa. */ - int vle_reloc_fixup; - - bfd_vma pagesize; -}; - -void ppc_elf_link_params (struct bfd_link_info *, struct ppc_elf_params *); -int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *); -asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *); -bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *); -void ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *); -extern bfd_boolean ppc_elf_modify_segment_map (bfd *, - struct bfd_link_info * ATTRIBUTE_UNUSED); -extern bfd_boolean ppc_elf_section_processing (bfd *, Elf_Internal_Shdr *); diff --git a/sdcc/support/sdbinutils/bfd/elf32-pru.c b/sdcc/support/sdbinutils/bfd/elf32-pru.c deleted file mode 100644 index 71bb0a006..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-pru.c +++ /dev/null @@ -1,1469 +0,0 @@ -/* 32-bit ELF support for TI PRU. - Copyright (C) 2014-2018 Free Software Foundation, Inc. - Contributed by Dimitar Dimitrov - Based on elf32-nios2.c - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* This file handles TI PRU ELF targets. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "genlink.h" -#include "elf-bfd.h" -#include "elf/pru.h" -#include "opcode/pru.h" - -#define SWAP_VALS(A,B) \ - do { \ - (A) ^= (B); \ - (B) ^= (A); \ - (A) ^= (B); \ - } while (0) - -/* Enable debugging printout at stdout with this variable. */ -static bfd_boolean debug_relax = FALSE; - -/* Forward declarations. */ -static bfd_reloc_status_type pru_elf32_pmem_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type pru_elf32_s10_pcrel_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type pru_elf32_u8_pcrel_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type pru_elf32_ldi32_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type bfd_elf_pru_diff_relocate - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -/* Target vector. */ -extern const bfd_target pru_elf32_vec; - -/* The relocation table used for SHT_REL sections. */ -static reloc_howto_type elf_pru_howto_table_rel[] = { - /* No relocation. */ - HOWTO (R_PRU_NONE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 3, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PRU_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PRU_16_PMEM, - 2, - 1, /* short */ - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_PRU_16_PMEM", - FALSE, - 0, /* src_mask */ - 0xffff, - FALSE), - - HOWTO (R_PRU_U16_PMEMIMM, - 2, - 2, - 32, - FALSE, - 8, - complain_overflow_unsigned, - pru_elf32_pmem_relocate, - "R_PRU_U16_PMEMIMM", - FALSE, - 0, /* src_mask */ - 0x00ffff00, - FALSE), - - HOWTO (R_PRU_BFD_RELOC_16, - 0, - 1, /* short */ - 16, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_PRU_BFD_RELOC16", - FALSE, - 0, /* src_mask */ - 0x0000ffff, - FALSE), - - /* 16-bit unsigned immediate relocation. */ - HOWTO (R_PRU_U16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned, /* complain on overflow */ - bfd_elf_generic_reloc, /* special function */ - "R_PRU_U16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00ffff00, /* dest_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PRU_32_PMEM, - 2, - 2, /* long */ - 32, - FALSE, - 0, - complain_overflow_dont, - pru_elf32_pmem_relocate, - "R_PRU_32_PMEM", - FALSE, - 0, /* src_mask */ - 0xffffffff, - FALSE), - - HOWTO (R_PRU_BFD_RELOC_32, - 0, - 2, /* long */ - 32, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "R_PRU_BFD_RELOC32", - FALSE, - 0, /* src_mask */ - 0xffffffff, - FALSE), - - HOWTO (R_PRU_S10_PCREL, - 2, - 2, - 10, - TRUE, - 0, - complain_overflow_bitfield, - pru_elf32_s10_pcrel_relocate, - "R_PRU_S10_PCREL", - FALSE, - 0, /* src_mask */ - 0x060000ff, - TRUE), - - HOWTO (R_PRU_U8_PCREL, - 2, - 2, - 8, - TRUE, - 0, - complain_overflow_unsigned, - pru_elf32_u8_pcrel_relocate, - "R_PRU_U8_PCREL", - FALSE, - 0, /* src_mask */ - 0x000000ff, - TRUE), - - HOWTO (R_PRU_LDI32, - 0, /* rightshift */ - 4, /* size (4 = 8bytes) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain on overflow */ - pru_elf32_ldi32_relocate, /* special function */ - "R_PRU_LDI32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dest_mask */ - FALSE), /* pcrel_offset */ - - /* GNU-specific relocations. */ - HOWTO (R_PRU_GNU_BFD_RELOC_8, - 0, - 0, /* byte */ - 8, - FALSE, - 0, - complain_overflow_bitfield, - bfd_elf_generic_reloc, - "R_PRU_BFD_RELOC8", - FALSE, - 0, /* src_mask */ - 0x000000ff, - FALSE), - - HOWTO (R_PRU_GNU_DIFF8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_pru_diff_relocate, /* special_function */ - "R_PRU_DIFF8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PRU_GNU_DIFF16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_pru_diff_relocate,/* special_function */ - "R_PRU_DIFF16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PRU_GNU_DIFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_pru_diff_relocate,/* special_function */ - "R_PRU_DIFF32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PRU_GNU_DIFF16_PMEM, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_pru_diff_relocate,/* special_function */ - "R_PRU_DIFF16_PMEM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PRU_GNU_DIFF32_PMEM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_pru_diff_relocate,/* special_function */ - "R_PRU_DIFF32_PMEM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -/* Add other relocations here. */ -}; - -static unsigned char elf_code_to_howto_index[R_PRU_ILLEGAL + 1]; - -/* Return the howto for relocation RTYPE. */ -static reloc_howto_type * -lookup_howto (unsigned int rtype) -{ - static int initialized = 0; - int i; - int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel) - / sizeof (elf_pru_howto_table_rel[0])); - - if (!initialized) - { - initialized = 1; - memset (elf_code_to_howto_index, 0xff, - sizeof (elf_code_to_howto_index)); - for (i = 0; i < howto_tbl_size; i++) - elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i; - } - - BFD_ASSERT (rtype <= R_PRU_ILLEGAL); - i = elf_code_to_howto_index[rtype]; - if (i >= howto_tbl_size) - return 0; - return elf_pru_howto_table_rel + i; -} - -/* Map for converting BFD reloc types to PRU reloc types. */ -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_val; - enum elf_pru_reloc_type elf_val; -}; - -static const struct elf_reloc_map pru_reloc_map[] = { - {BFD_RELOC_NONE, R_PRU_NONE}, - {BFD_RELOC_PRU_16_PMEM, R_PRU_16_PMEM}, - {BFD_RELOC_PRU_U16_PMEMIMM, R_PRU_U16_PMEMIMM}, - {BFD_RELOC_16, R_PRU_BFD_RELOC_16}, - {BFD_RELOC_PRU_U16, R_PRU_U16}, - {BFD_RELOC_PRU_32_PMEM, R_PRU_32_PMEM}, - {BFD_RELOC_32, R_PRU_BFD_RELOC_32}, - {BFD_RELOC_PRU_S10_PCREL, R_PRU_S10_PCREL}, - {BFD_RELOC_PRU_U8_PCREL, R_PRU_U8_PCREL}, - {BFD_RELOC_PRU_LDI32, R_PRU_LDI32}, - - {BFD_RELOC_8, R_PRU_GNU_BFD_RELOC_8}, - {BFD_RELOC_PRU_GNU_DIFF8, R_PRU_GNU_DIFF8}, - {BFD_RELOC_PRU_GNU_DIFF16, R_PRU_GNU_DIFF16}, - {BFD_RELOC_PRU_GNU_DIFF32, R_PRU_GNU_DIFF32}, - {BFD_RELOC_PRU_GNU_DIFF16_PMEM, R_PRU_GNU_DIFF16_PMEM}, - {BFD_RELOC_PRU_GNU_DIFF32_PMEM, R_PRU_GNU_DIFF32_PMEM}, -}; - - -/* Assorted hash table functions. */ - -/* Create an entry in a PRU 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_link_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = _bfd_elf_link_hash_newfunc (entry, table, string); - - return entry; -} - -/* Implement bfd_elf32_bfd_reloc_type_lookup: - Given a BFD reloc type, return a howto structure. */ -static reloc_howto_type * -pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - int i; - for (i = 0; - i < (int) (sizeof (pru_reloc_map) / sizeof (struct elf_reloc_map)); - ++i) - if (pru_reloc_map[i].bfd_val == code) - return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val); - return NULL; -} - -/* Implement bfd_elf32_bfd_reloc_name_lookup: - Given a reloc name, return a howto structure. */ -static reloc_howto_type * -pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - for (i = 0; - i < (sizeof (elf_pru_howto_table_rel) - / sizeof (elf_pru_howto_table_rel[0])); - i++) - if (elf_pru_howto_table_rel[i].name - && strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0) - return &elf_pru_howto_table_rel[i]; - - return NULL; -} - -/* Implement elf_info_to_howto: - Given a ELF32 relocation, fill in a arelent structure. */ -static void -pru_elf32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - BFD_ASSERT (r_type < R_PRU_ILLEGAL); - cache_ptr->howto = lookup_howto (r_type); -} - -/* Do the relocations that require special handling. */ -/* Produce a word address for program memory. Linker scripts will put .text - at a high offset in order to differentiate it from .data. So here we also - mask the high bits of PMEM address. - - But why 1MB when internal Program Memory much smaller? We want to catch - unintended overflows. - - Why not use (1<<31) as an offset and a mask? Sitara DDRAM usually resides - there, and users might want to put some shared carveout memory region in - their linker scripts. So 0x80000000 might be a valid .data address. - - Note that we still keep and pass down the original howto. This way we - can reuse this function for several different relocations. */ -static bfd_reloc_status_type -pru_elf32_do_pmem_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - symbol_value = symbol_value + addend; - addend = 0; - symbol_value &= 0x3fffff; - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -/* Direct copy of _bfd_final_link_relocate, but with special - "fill-in". This copy-paste mumbo jumbo is only needed because BFD - cannot deal correctly with non-contiguous bit fields. */ -static bfd_reloc_status_type -pru_elf32_do_s10_pcrel_relocate (bfd *input_bfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *contents, bfd_vma address, - bfd_vma relocation, bfd_vma addend) -{ - bfd_byte *location; - bfd_vma x = 0; - bfd_vma qboff; - bfd_reloc_status_type flag = bfd_reloc_ok; - - /* Sanity check the address. */ - if (address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - BFD_ASSERT (howto->pc_relative); - BFD_ASSERT (howto->pcrel_offset); - - relocation = relocation + addend - (input_section->output_section->vma - + input_section->output_offset) - address; - - location = contents + address; - - /* Get the value we are going to relocate. */ - BFD_ASSERT (bfd_get_reloc_size (howto) == 4); - x = bfd_get_32 (input_bfd, location); - - qboff = GET_BROFF_SIGNED (x) << howto->rightshift; - relocation += qboff; - - BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield); - - if (relocation > 2047 && relocation < (bfd_vma)-2048l) - flag = bfd_reloc_overflow; - - /* Check that target address is word-aligned. */ - if (relocation & ((1 << howto->rightshift) - 1)) - flag = bfd_reloc_outofrange; - - relocation >>= (bfd_vma) howto->rightshift; - - /* Fill-in the RELOCATION to the right bits of X. */ - SET_BROFF_URAW (x, relocation); - - bfd_put_32 (input_bfd, x, location); - - return flag; -} - -static bfd_reloc_status_type -pru_elf32_do_u8_pcrel_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - bfd_vma relocation; - - BFD_ASSERT (howto->pc_relative); - BFD_ASSERT (howto->pcrel_offset); - - relocation = symbol_value + addend - (input_section->output_section->vma - + input_section->output_offset) - offset; - relocation >>= howto->rightshift; - - /* 0 and 1 are invalid target labels for LOOP. We cannot - encode this info in HOWTO, so catch such cases here. */ - if (relocation < 2) - return bfd_reloc_outofrange; - - return _bfd_final_link_relocate (howto, abfd, input_section, - data, offset, symbol_value, addend); -} - -/* Idea and code taken from elf32-d30v. */ -static bfd_reloc_status_type -pru_elf32_do_ldi32_relocate (bfd *abfd, reloc_howto_type *howto, - asection *input_section, - bfd_byte *data, bfd_vma offset, - bfd_vma symbol_value, bfd_vma addend) -{ - bfd_signed_vma relocation; - bfd_size_type octets = offset * bfd_octets_per_byte (abfd); - bfd_byte *location; - unsigned long in1, in2, num; - - /* A hacked-up version of _bfd_final_link_relocate() follows. */ - - /* Sanity check the address. */ - if (octets + bfd_get_reloc_size (howto) - > bfd_get_section_limit_octets (abfd, 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 = symbol_value + addend; - - BFD_ASSERT (!howto->pc_relative); - - /* A hacked-up version of _bfd_relocate_contents() follows. */ - location = data + offset * bfd_octets_per_byte (abfd); - - BFD_ASSERT (!howto->pc_relative); - - in1 = bfd_get_32 (abfd, location); - in2 = bfd_get_32 (abfd, location + 4); - - /* Extract the addend - should be zero per my understanding. */ - num = GET_INSN_FIELD (IMM16, in1) | (GET_INSN_FIELD (IMM16, in2) << 16); - BFD_ASSERT (!num); - - relocation += num; - - SET_INSN_FIELD (IMM16, in1, relocation & 0xffff); - SET_INSN_FIELD (IMM16, in2, relocation >> 16); - - bfd_put_32 (abfd, in1, location); - bfd_put_32 (abfd, in2, location + 4); - - return bfd_reloc_ok; -} - -/* HOWTO handlers for relocations that require special handling. */ - -static bfd_reloc_status_type -pru_elf32_pmem_relocate (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, - asection *input_section, bfd *output_bfd, - char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -pru_elf32_s10_pcrel_relocate (bfd *abfd, arelent *reloc_entry, - asymbol *symbol, void *data, - asection *input_section, bfd *output_bfd, - char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto, - input_section, data, - reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -pru_elf32_u8_pcrel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - -static bfd_reloc_status_type -pru_elf32_ldi32_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, - char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto, - input_section, - data, reloc_entry->address, - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset), - reloc_entry->addend); -} - - -/* Implement elf_backend_relocate_section. */ -static bfd_boolean -pru_elf32_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r = bfd_reloc_ok; - const char *name = NULL; - const char* msg = (const char*) NULL; - bfd_boolean unresolved_reloc; - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info)); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - /* Nothing more to do unless this is a final link. */ - if (bfd_link_relocatable (info)) - continue; - - if (howto) - { - switch (howto->type) - { - case R_PRU_NONE: - /* We don't need to find a value for this symbol. It's just a - marker. */ - r = bfd_reloc_ok; - break; - - case R_PRU_U16_PMEMIMM: - case R_PRU_32_PMEM: - case R_PRU_16_PMEM: - r = pru_elf32_do_pmem_relocate (input_bfd, howto, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - case R_PRU_S10_PCREL: - r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - case R_PRU_U8_PCREL: - r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - case R_PRU_LDI32: - r = pru_elf32_do_ldi32_relocate (input_bfd, howto, - input_section, - contents, - rel->r_offset, - relocation, - rel->r_addend); - break; - case R_PRU_GNU_DIFF8: - case R_PRU_GNU_DIFF16: - case R_PRU_GNU_DIFF32: - case R_PRU_GNU_DIFF16_PMEM: - case R_PRU_GNU_DIFF32_PMEM: - /* Nothing to do here, as contents already contain the - diff value. */ - r = bfd_reloc_ok; - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, - input_section, contents, - rel->r_offset, relocation, - rel->r_addend); - break; - } - } - else - r = bfd_reloc_notsupported; - - if (r != bfd_reloc_ok) - { - if (h != NULL) - name = h->root.root.string; - else - { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) (info, NULL, name, - howto->name, (bfd_vma) 0, - input_bfd, input_section, - rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) (info, name, input_bfd, - input_section, - rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - if (msg == NULL) - msg = _("relocation out of range"); - break; - - case bfd_reloc_notsupported: - if (msg == NULL) - msg = _("unsupported relocation"); - break; - - case bfd_reloc_dangerous: - if (msg == NULL) - msg = _("dangerous relocation"); - break; - - default: - if (msg == NULL) - msg = _("unknown error"); - break; - } - - if (msg) - { - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - return FALSE; - } - } - } - return TRUE; -} - - -/* Perform a diff relocation. Nothing to do, as the difference value is - already written into the section's contents. */ - -static bfd_reloc_status_type -bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - return bfd_reloc_ok; -} - - -/* Returns whether the relocation type passed is a diff reloc. */ - -static bfd_boolean -elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel) -{ - return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8 - || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16 - || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32 - || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM - || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM); -} - -/* Reduce the diff value written in the section by count if the shrinked - insn address happens to fall between the two symbols for which this - diff reloc was emitted. */ - -static void -elf32_pru_adjust_diff_reloc_value (bfd *abfd, - struct bfd_section *isec, - Elf_Internal_Rela *irel, - bfd_vma symval, - bfd_vma shrinked_insn_address, - int count) -{ - unsigned char *reloc_contents = NULL; - unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents; - if (isec_contents == NULL) - { - if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents)) - return; - - elf_section_data (isec)->this_hdr.contents = isec_contents; - } - - reloc_contents = isec_contents + irel->r_offset; - - /* Read value written in object file. */ - bfd_signed_vma x = 0; - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_PRU_GNU_DIFF8: - { - x = bfd_get_signed_8 (abfd, reloc_contents); - break; - } - case R_PRU_GNU_DIFF16: - { - x = bfd_get_signed_16 (abfd, reloc_contents); - break; - } - case R_PRU_GNU_DIFF32: - { - x = bfd_get_signed_32 (abfd, reloc_contents); - break; - } - case R_PRU_GNU_DIFF16_PMEM: - { - x = bfd_get_signed_16 (abfd, reloc_contents) * 4; - break; - } - case R_PRU_GNU_DIFF32_PMEM: - { - x = bfd_get_signed_32 (abfd, reloc_contents) * 4; - break; - } - default: - { - BFD_FAIL (); - } - } - - /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written - into the object file at the reloc offset. sym2's logical value is - symval () + reloc addend. Compute the start and end - addresses and check if the shrinked insn falls between sym1 and sym2. */ - - bfd_vma end_address = symval + irel->r_addend; - bfd_vma start_address = end_address - x; - - /* Shrink the absolute DIFF value (get the to labels "closer" - together), because we have removed data between labels. */ - if (x < 0) - { - x += count; - /* In case the signed x is negative, restore order. */ - SWAP_VALS (end_address, start_address); - } - else - { - x -= count; - } - - /* Reduce the diff value by count bytes and write it back into section - contents. */ - - if (shrinked_insn_address >= start_address - && shrinked_insn_address <= end_address) - { - switch (ELF32_R_TYPE (irel->r_info)) - { - case R_PRU_GNU_DIFF8: - { - bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents); - break; - } - case R_PRU_GNU_DIFF16: - { - bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents); - break; - } - case R_PRU_GNU_DIFF32: - { - bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents); - break; - } - case R_PRU_GNU_DIFF16_PMEM: - { - bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents); - break; - } - case R_PRU_GNU_DIFF32_PMEM: - { - bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents); - break; - } - default: - { - BFD_FAIL (); - } - } - - } -} - -/* Delete some bytes from a section while changing the size of an instruction. - The parameter "addr" denotes the section-relative offset pointing just - behind the shrinked instruction. "addr+count" point at the first - byte just behind the original unshrinked instruction. - - Idea copied from the AVR port. */ - -static bfd_boolean -pru_elf_relax_delete_bytes (bfd *abfd, - asection *sec, - bfd_vma addr, - int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymbuf = NULL; - bfd_vma toaddr; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - if (toaddr - addr - count > 0) - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the reloc addresses. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - bfd_vma old_reloc_address; - - old_reloc_address = (sec->output_section->vma - + sec->output_offset + irel->r_offset); - - /* Get the new reloc address. */ - if ((irel->r_offset > addr - && irel->r_offset < toaddr)) - { - if (debug_relax) - printf ("Relocation at address 0x%x needs to be moved.\n" - "Old section offset: 0x%x, New section offset: 0x%x \n", - (unsigned int) old_reloc_address, - (unsigned int) irel->r_offset, - (unsigned int) ((irel->r_offset) - count)); - - irel->r_offset -= count; - } - - } - - /* The reloc's own addresses are now ok. However, we need to readjust - the reloc's addend, i.e. the reloc's value if two conditions are met: - 1.) the reloc is relative to a symbol in this section that - is located in front of the shrinked instruction - 2.) symbol plus addend end up behind the shrinked instruction. - - The most common case where this happens are relocs relative to - the section-start symbol. - - This step needs to be done for all of the sections of the bfd. */ - - { - struct bfd_section *isec; - - for (isec = abfd->sections; isec; isec = isec->next) - { - bfd_vma symval; - bfd_vma shrinked_insn_address; - - if (isec->reloc_count == 0) - continue; - - shrinked_insn_address = (sec->output_section->vma - + sec->output_offset + addr - count); - - irel = elf_section_data (isec)->relocs; - /* PR 12161: Read in the relocs for this section if necessary. */ - if (irel == NULL) - irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE); - - for (irelend = irel + isec->reloc_count; - irel < irelend; - irel++) - { - /* Read this BFD's local symbols if we haven't done - so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = isym->st_value; - /* If the reloc is absolute, it will not have - a symbol or section associated with it. */ - if (sym_sec == sec) - { - symval += sym_sec->output_section->vma - + sym_sec->output_offset; - - if (debug_relax) - printf ("Checking if the relocation's " - "addend needs corrections.\n" - "Address of anchor symbol: 0x%x \n" - "Address of relocation target: 0x%x \n" - "Address of relaxed insn: 0x%x \n", - (unsigned int) symval, - (unsigned int) (symval + irel->r_addend), - (unsigned int) shrinked_insn_address); - - /* Shrink the special DIFF relocations. */ - if (elf32_pru_is_diff_reloc (irel)) - { - elf32_pru_adjust_diff_reloc_value (abfd, isec, irel, - symval, - shrinked_insn_address, - count); - } - - /* Fix the addend, if it is affected. */ - if (symval <= shrinked_insn_address - && (symval + irel->r_addend) > shrinked_insn_address) - { - - irel->r_addend -= count; - - if (debug_relax) - printf ("Relocation's addend needed to be fixed \n"); - } - } - /* else...Reference symbol is absolute. - No adjustment needed. */ - } - /* else...Reference symbol is extern. No need for adjusting - the addend. */ - } - } - } - - /* Adjust the local symbols defined in this section. */ - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - /* Fix PR 9841, there may be no local symbols. */ - if (isym != NULL) - { - Elf_Internal_Sym *isymend; - - isymend = isym + symtab_hdr->sh_info; - for (; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx) - { - if (isym->st_value > addr - && isym->st_value <= toaddr) - isym->st_value -= count; - - if (isym->st_value <= addr - && isym->st_value + isym->st_size > addr) - { - /* If this assert fires then we have a symbol that ends - part way through an instruction. Does that make - sense? */ - BFD_ASSERT (isym->st_value + isym->st_size >= addr + count); - isym->st_size -= count; - } - } - } - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - if (sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value <= toaddr) - sym_hash->root.u.def.value -= count; - - if (sym_hash->root.u.def.value <= addr - && (sym_hash->root.u.def.value + sym_hash->size > addr)) - { - /* If this assert fires then we have a symbol that ends - part way through an instruction. Does that make - sense? */ - BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size - >= addr + count); - sym_hash->size -= count; - } - } - } - - return TRUE; -} - -static bfd_boolean -pru_elf32_relax_section (bfd * abfd, asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * irelend; - bfd_byte * contents = NULL; - Elf_Internal_Sym * isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Check if we can remove an LDI instruction from the LDI32 - pseudo instruction if the upper 16 operand bits are zero. */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32) - { - bfd_vma value = symval + irel->r_addend; - - if (debug_relax) - printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value); - - if ((long) value >> 16 == 0) - { - /* Note that we've changed the relocs, section contents. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Delete bytes. */ - if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 4, 4)) - goto error_return; - - /* We're done with deletion of the second instruction. - Set a regular LDI relocation for the first instruction - we left to load the 16-bit value into the 32-bit - register. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_PRU_U16); - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } - } - - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (!link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (!link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - -error_return: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* Free the derived linker hash table. */ -static void -pru_elf32_link_hash_table_free (bfd *obfd) -{ - _bfd_elf_link_hash_table_free (obfd); -} - -/* Implement bfd_elf32_bfd_link_hash_table_create. */ -static struct bfd_link_hash_table * -pru_elf32_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (ret, abfd, - link_hash_newfunc, - sizeof (struct - elf_link_hash_entry), - PRU_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->root.hash_table_free = pru_elf32_link_hash_table_free; - - return &ret->root; -} - -#define ELF_ARCH bfd_arch_pru -#define ELF_TARGET_ID PRU_ELF_DATA -#define ELF_MACHINE_CODE EM_TI_PRU - -#define ELF_MAXPAGESIZE 1 - -#define bfd_elf32_bfd_link_hash_table_create \ - pru_elf32_link_hash_table_create - -/* Relocation table lookup macros. */ - -#define bfd_elf32_bfd_reloc_type_lookup pru_elf32_bfd_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup pru_elf32_bfd_reloc_name_lookup - -/* elf_info_to_howto (using RELA relocations). */ - -#define elf_info_to_howto pru_elf32_info_to_howto - -/* elf backend functions. */ - -#define elf_backend_rela_normal 1 - -#define elf_backend_relocate_section pru_elf32_relocate_section -#define bfd_elf32_bfd_relax_section pru_elf32_relax_section - -#define TARGET_LITTLE_SYM pru_elf32_vec -#define TARGET_LITTLE_NAME "elf32-pru" - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-rl78.c b/sdcc/support/sdbinutils/bfd/elf32-rl78.c deleted file mode 100644 index 48714c22d..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-rl78.c +++ /dev/null @@ -1,2596 +0,0 @@ -/* Renesas RL78 specific support for 32-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfd_stdint.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/rl78.h" -#include "libiberty.h" - -#define valid_16bit_address(v) ((v) <= 0x0ffff || (v) >= 0xf0000) - -#define RL78REL(n,sz,bit,shift,complain,pcrel) \ - HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ - bfd_elf_generic_reloc, "R_RL78_" #n, FALSE, 0, ~0, FALSE) - -static bfd_reloc_status_type rl78_special_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -/* FIXME: We could omit the SHIFT parameter, it is always zero. */ -#define RL78_OP_REL(n,sz,bit,shift,complain,pcrel) \ - HOWTO (R_RL78_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ - rl78_special_reloc, "R_RL78_" #n, FALSE, 0, ~0, FALSE) - -/* Note that the relocations around 0x7f are internal to this file; - feel free to move them as needed to avoid conflicts with published - relocation numbers. */ - -static reloc_howto_type rl78_elf_howto_table [] = -{ - RL78REL (NONE, 3, 0, 0, dont, FALSE), - RL78REL (DIR32, 2, 32, 0, signed, FALSE), - RL78REL (DIR24S, 2, 24, 0, signed, FALSE), - RL78REL (DIR16, 1, 16, 0, dont, FALSE), - RL78REL (DIR16U, 1, 16, 0, unsigned, FALSE), - RL78REL (DIR16S, 1, 16, 0, signed, FALSE), - RL78REL (DIR8, 0, 8, 0, dont, FALSE), - RL78REL (DIR8U, 0, 8, 0, unsigned, FALSE), - RL78REL (DIR8S, 0, 8, 0, signed, FALSE), - RL78REL (DIR24S_PCREL, 2, 24, 0, signed, TRUE), - RL78REL (DIR16S_PCREL, 1, 16, 0, signed, TRUE), - RL78REL (DIR8S_PCREL, 0, 8, 0, signed, TRUE), - RL78REL (DIR16UL, 1, 16, 2, unsigned, FALSE), - RL78REL (DIR16UW, 1, 16, 1, unsigned, FALSE), - RL78REL (DIR8UL, 0, 8, 2, unsigned, FALSE), - RL78REL (DIR8UW, 0, 8, 1, unsigned, FALSE), - RL78REL (DIR32_REV, 1, 16, 0, dont, FALSE), - RL78REL (DIR16_REV, 1, 16, 0, dont, FALSE), - RL78REL (DIR3U_PCREL, 0, 3, 0, dont, TRUE), - - EMPTY_HOWTO (0x13), - EMPTY_HOWTO (0x14), - EMPTY_HOWTO (0x15), - EMPTY_HOWTO (0x16), - EMPTY_HOWTO (0x17), - EMPTY_HOWTO (0x18), - EMPTY_HOWTO (0x19), - EMPTY_HOWTO (0x1a), - EMPTY_HOWTO (0x1b), - EMPTY_HOWTO (0x1c), - EMPTY_HOWTO (0x1d), - EMPTY_HOWTO (0x1e), - EMPTY_HOWTO (0x1f), - - EMPTY_HOWTO (0x20), - EMPTY_HOWTO (0x21), - EMPTY_HOWTO (0x22), - EMPTY_HOWTO (0x23), - EMPTY_HOWTO (0x24), - EMPTY_HOWTO (0x25), - EMPTY_HOWTO (0x26), - EMPTY_HOWTO (0x27), - EMPTY_HOWTO (0x28), - EMPTY_HOWTO (0x29), - EMPTY_HOWTO (0x2a), - EMPTY_HOWTO (0x2b), - EMPTY_HOWTO (0x2c), - RL78REL (RH_RELAX, 0, 0, 0, dont, FALSE), - - EMPTY_HOWTO (0x2e), - RL78REL (RH_SADDR, 0, 0, 0, dont, FALSE), - EMPTY_HOWTO (0x30), - EMPTY_HOWTO (0x31), - EMPTY_HOWTO (0x32), - EMPTY_HOWTO (0x33), - EMPTY_HOWTO (0x34), - EMPTY_HOWTO (0x35), - EMPTY_HOWTO (0x36), - EMPTY_HOWTO (0x37), - EMPTY_HOWTO (0x38), - EMPTY_HOWTO (0x39), - EMPTY_HOWTO (0x3a), - EMPTY_HOWTO (0x3b), - EMPTY_HOWTO (0x3c), - EMPTY_HOWTO (0x3d), - EMPTY_HOWTO (0x3e), - EMPTY_HOWTO (0x3f), - EMPTY_HOWTO (0x40), - - RL78_OP_REL (ABS32, 2, 32, 0, dont, FALSE), - RL78_OP_REL (ABS24S, 2, 24, 0, signed, FALSE), - RL78_OP_REL (ABS16, 1, 16, 0, dont, FALSE), - RL78_OP_REL (ABS16U, 1, 16, 0, unsigned, FALSE), - RL78_OP_REL (ABS16S, 1, 16, 0, signed, FALSE), - RL78_OP_REL (ABS8, 0, 8, 0, dont, FALSE), - RL78_OP_REL (ABS8U, 0, 8, 0, unsigned, FALSE), - RL78_OP_REL (ABS8S, 0, 8, 0, signed, FALSE), - RL78_OP_REL (ABS24S_PCREL, 2, 24, 0, signed, TRUE), - RL78_OP_REL (ABS16S_PCREL, 1, 16, 0, signed, TRUE), - RL78_OP_REL (ABS8S_PCREL, 0, 8, 0, signed, TRUE), - RL78_OP_REL (ABS16UL, 1, 16, 0, unsigned, FALSE), - RL78_OP_REL (ABS16UW, 1, 16, 0, unsigned, FALSE), - RL78_OP_REL (ABS8UL, 0, 8, 0, unsigned, FALSE), - RL78_OP_REL (ABS8UW, 0, 8, 0, unsigned, FALSE), - RL78_OP_REL (ABS32_REV, 2, 32, 0, dont, FALSE), - RL78_OP_REL (ABS16_REV, 1, 16, 0, dont, FALSE), - -#define STACK_REL_P(x) ((x) <= R_RL78_ABS16_REV && (x) >= R_RL78_ABS32) - - EMPTY_HOWTO (0x52), - EMPTY_HOWTO (0x53), - EMPTY_HOWTO (0x54), - EMPTY_HOWTO (0x55), - EMPTY_HOWTO (0x56), - EMPTY_HOWTO (0x57), - EMPTY_HOWTO (0x58), - EMPTY_HOWTO (0x59), - EMPTY_HOWTO (0x5a), - EMPTY_HOWTO (0x5b), - EMPTY_HOWTO (0x5c), - EMPTY_HOWTO (0x5d), - EMPTY_HOWTO (0x5e), - EMPTY_HOWTO (0x5f), - EMPTY_HOWTO (0x60), - EMPTY_HOWTO (0x61), - EMPTY_HOWTO (0x62), - EMPTY_HOWTO (0x63), - EMPTY_HOWTO (0x64), - EMPTY_HOWTO (0x65), - EMPTY_HOWTO (0x66), - EMPTY_HOWTO (0x67), - EMPTY_HOWTO (0x68), - EMPTY_HOWTO (0x69), - EMPTY_HOWTO (0x6a), - EMPTY_HOWTO (0x6b), - EMPTY_HOWTO (0x6c), - EMPTY_HOWTO (0x6d), - EMPTY_HOWTO (0x6e), - EMPTY_HOWTO (0x6f), - EMPTY_HOWTO (0x70), - EMPTY_HOWTO (0x71), - EMPTY_HOWTO (0x72), - EMPTY_HOWTO (0x73), - EMPTY_HOWTO (0x74), - EMPTY_HOWTO (0x75), - EMPTY_HOWTO (0x76), - EMPTY_HOWTO (0x77), - - EMPTY_HOWTO (0x78), - EMPTY_HOWTO (0x79), - EMPTY_HOWTO (0x7a), - EMPTY_HOWTO (0x7b), - EMPTY_HOWTO (0x7c), - EMPTY_HOWTO (0x7d), - EMPTY_HOWTO (0x7e), - EMPTY_HOWTO (0x7f), - - RL78_OP_REL (SYM, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPneg, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPadd, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPsub, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPmul, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPdiv, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPshla, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPshra, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPsctsize, 2, 32, 0, dont, FALSE), - EMPTY_HOWTO (0x89), - EMPTY_HOWTO (0x8a), - EMPTY_HOWTO (0x8b), - EMPTY_HOWTO (0x8c), - RL78_OP_REL (OPscttop, 2, 32, 0, dont, FALSE), - EMPTY_HOWTO (0x8e), - EMPTY_HOWTO (0x8f), - RL78_OP_REL (OPand, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPor, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPxor, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPnot, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPmod, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPromtop, 2, 32, 0, dont, FALSE), - RL78_OP_REL (OPramtop, 2, 32, 0, dont, FALSE) -}; - -/* Map BFD reloc types to RL78 ELF reloc types. */ - -struct rl78_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int rl78_reloc_val; -}; - -static const struct rl78_reloc_map rl78_reloc_map [] = -{ - { BFD_RELOC_NONE, R_RL78_NONE }, - { BFD_RELOC_8, R_RL78_DIR8S }, - { BFD_RELOC_16, R_RL78_DIR16S }, - { BFD_RELOC_24, R_RL78_DIR24S }, - { BFD_RELOC_32, R_RL78_DIR32 }, - { BFD_RELOC_RL78_16_OP, R_RL78_DIR16 }, - { BFD_RELOC_RL78_DIR3U_PCREL, R_RL78_DIR3U_PCREL }, - { BFD_RELOC_8_PCREL, R_RL78_DIR8S_PCREL }, - { BFD_RELOC_16_PCREL, R_RL78_DIR16S_PCREL }, - { BFD_RELOC_24_PCREL, R_RL78_DIR24S_PCREL }, - { BFD_RELOC_RL78_8U, R_RL78_DIR8U }, - { BFD_RELOC_RL78_16U, R_RL78_DIR16U }, - { BFD_RELOC_RL78_SYM, R_RL78_SYM }, - { BFD_RELOC_RL78_OP_SUBTRACT, R_RL78_OPsub }, - { BFD_RELOC_RL78_OP_NEG, R_RL78_OPneg }, - { BFD_RELOC_RL78_OP_AND, R_RL78_OPand }, - { BFD_RELOC_RL78_OP_SHRA, R_RL78_OPshra }, - { BFD_RELOC_RL78_ABS8, R_RL78_ABS8 }, - { BFD_RELOC_RL78_ABS16, R_RL78_ABS16 }, - { BFD_RELOC_RL78_ABS16_REV, R_RL78_ABS16_REV }, - { BFD_RELOC_RL78_ABS32, R_RL78_ABS32 }, - { BFD_RELOC_RL78_ABS32_REV, R_RL78_ABS32_REV }, - { BFD_RELOC_RL78_ABS16UL, R_RL78_ABS16UL }, - { BFD_RELOC_RL78_ABS16UW, R_RL78_ABS16UW }, - { BFD_RELOC_RL78_ABS16U, R_RL78_ABS16U }, - { BFD_RELOC_RL78_SADDR, R_RL78_RH_SADDR }, - { BFD_RELOC_RL78_RELAX, R_RL78_RH_RELAX } -}; - -static reloc_howto_type * -rl78_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - if (code == BFD_RELOC_RL78_32_OP) - return rl78_elf_howto_table + R_RL78_DIR32; - - for (i = ARRAY_SIZE (rl78_reloc_map); i--;) - if (rl78_reloc_map [i].bfd_reloc_val == code) - return rl78_elf_howto_table + rl78_reloc_map[i].rl78_reloc_val; - - return NULL; -} - -static reloc_howto_type * -rl78_reloc_name_lookup (bfd * abfd ATTRIBUTE_UNUSED, const char * r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (rl78_elf_howto_table); i++) - if (rl78_elf_howto_table[i].name != NULL - && strcasecmp (rl78_elf_howto_table[i].name, r_name) == 0) - return rl78_elf_howto_table + i; - - return NULL; -} - -/* Set the howto pointer for an RL78 ELF reloc. */ - -static void -rl78_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_RL78_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid RL78 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = rl78_elf_howto_table + r_type; -} - -static bfd_vma -get_symbol_value (const char * name, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - int offset) -{ - struct bfd_link_hash_entry * h; - - if (info == NULL) - return 0; - - h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); - - if (h == NULL - || (h->type != bfd_link_hash_defined - && h->type != bfd_link_hash_defweak)) - { - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, offset, TRUE); - return 0; - } - - return (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); -} - -static bfd_vma -get_romstart (struct bfd_link_info * info, - bfd * abfd, - asection * sec, - int offset) -{ - static bfd_boolean cached = FALSE; - static bfd_vma cached_value = 0; - - if (!cached) - { - cached_value = get_symbol_value ("_start", info, abfd, sec, offset); - cached = TRUE; - } - return cached_value; -} - -static bfd_vma -get_ramstart (struct bfd_link_info * info, - bfd * abfd, - asection * sec, - int offset) -{ - static bfd_boolean cached = FALSE; - static bfd_vma cached_value = 0; - - if (!cached) - { - cached_value = get_symbol_value ("__datastart", info, abfd, sec, offset); - cached = TRUE; - } - return cached_value; -} - -#define NUM_STACK_ENTRIES 16 -static int32_t rl78_stack [ NUM_STACK_ENTRIES ]; -static unsigned int rl78_stack_top; - -#define RL78_STACK_PUSH(val) \ - do \ - { \ - if (rl78_stack_top < NUM_STACK_ENTRIES) \ - rl78_stack [rl78_stack_top ++] = (val); \ - else \ - _bfd_error_handler (_("Internal Error: RL78 reloc stack overflow")); \ - } \ - while (0) - -#define RL78_STACK_POP(dest) \ - do \ - { \ - if (rl78_stack_top > 0) \ - (dest) = rl78_stack [-- rl78_stack_top];\ - else \ - { \ - _bfd_error_handler (_("Internal Error: RL78 reloc stack underflow")); \ - (dest) = 0; \ - } \ - } \ - while (0) - -/* Special handling for RL78 complex relocs. Returns the - value of the reloc, or 0 for relocs which do not generate - a result. SYMVAL is the value of the symbol for relocs - which use a symbolic argument. */ - -static bfd_vma -rl78_compute_complex_reloc (unsigned long r_type, - bfd_vma symval, - asection * input_section) -{ - int32_t tmp1, tmp2; - bfd_vma relocation; - - switch (r_type) - { - default: - return 0; - - case R_RL78_ABS24S_PCREL: - case R_RL78_ABS16S_PCREL: - case R_RL78_ABS8S_PCREL: - RL78_STACK_POP (relocation); - relocation -= input_section->output_section->vma + input_section->output_offset; - return relocation; - - case R_RL78_ABS32: - case R_RL78_ABS32_REV: - case R_RL78_ABS16: - case R_RL78_ABS16_REV: - case R_RL78_ABS16S: - case R_RL78_ABS16U: - case R_RL78_ABS8: - case R_RL78_ABS8U: - case R_RL78_ABS8S: - RL78_STACK_POP (relocation); - return relocation; - - case R_RL78_ABS16UL: - case R_RL78_ABS8UL: - RL78_STACK_POP (relocation); - return relocation >> 2; - - case R_RL78_ABS16UW: - case R_RL78_ABS8UW: - RL78_STACK_POP (relocation); - return relocation >> 1; - - /* The rest of the relocs compute values and then push them onto the stack. */ - case R_RL78_OPramtop: - case R_RL78_OPromtop: - case R_RL78_SYM: - RL78_STACK_PUSH (symval); - return 0; - - case R_RL78_OPneg: - RL78_STACK_POP (tmp1); - tmp1 = - tmp1; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPadd: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 += tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPsub: - /* For the expression "A - B", the assembler pushes A, - then B, then OPSUB. So the first op we pop is B, not A. */ - RL78_STACK_POP (tmp2); /* B */ - RL78_STACK_POP (tmp1); /* A */ - tmp1 -= tmp2; /* A - B */ - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPmul: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 *= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPdiv: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 /= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPshla: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 <<= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPshra: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 >>= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPsctsize: - RL78_STACK_PUSH (input_section->size); - return 0; - - case R_RL78_OPscttop: - RL78_STACK_PUSH (input_section->output_section->vma); - return 0; - - case R_RL78_OPand: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 &= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPor: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 |= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPxor: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 ^= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPnot: - RL78_STACK_POP (tmp1); - tmp1 = ~ tmp1; - RL78_STACK_PUSH (tmp1); - return 0; - - case R_RL78_OPmod: - RL78_STACK_POP (tmp2); - RL78_STACK_POP (tmp1); - tmp1 %= tmp2; - RL78_STACK_PUSH (tmp1); - return 0; - } -} - -#undef RL78_STACK_PUSH -#undef RL78_STACK_POP - -#define OP(i) (contents[reloc->address + (i)]) - -static bfd_reloc_status_type -rl78_special_reloc (bfd * input_bfd, - arelent * reloc, - asymbol * symbol, - void * data, - asection * input_section, - bfd * output_bfd ATTRIBUTE_UNUSED, - char ** error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma relocation = 0; - unsigned long r_type = reloc->howto->type; - bfd_byte * contents = data; - - /* If necessary, compute the symbolic value of the relocation. */ - switch (r_type) - { - case R_RL78_SYM: - relocation = (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset - + reloc->addend); - break; - - case R_RL78_OPromtop: - relocation = get_romstart (NULL, input_bfd, input_section, - reloc->address); - break; - - case R_RL78_OPramtop: - relocation = get_ramstart (NULL, input_bfd, input_section, - reloc->address); - break; - } - - /* Get the value of the relocation. */ - relocation = rl78_compute_complex_reloc (r_type, relocation, input_section); - - /* If the relocation alters the contents of the section then apply it now. - Note - since this function is called from - bfd_generic_get_relocated_section_contents via bfd_perform_relocation, - and not from the linker, we do not perform any range checking. The - clients who are calling us are only interested in some relocated section - contents, and not any linkage problems that might occur later. */ - switch (r_type) - { - case R_RL78_ABS32: - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; - break; - - case R_RL78_ABS32_REV: - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; - break; - - case R_RL78_ABS24S_PCREL: - case R_RL78_ABS24S: - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - break; - - case R_RL78_ABS16_REV: - OP (1) = relocation; - OP (0) = relocation >> 8; - break; - - case R_RL78_ABS16S_PCREL: - case R_RL78_ABS16: - case R_RL78_ABS16S: - case R_RL78_ABS16U: - case R_RL78_ABS16UL: - case R_RL78_ABS16UW: - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_ABS8S_PCREL: - case R_RL78_ABS8: - case R_RL78_ABS8U: - case R_RL78_ABS8UL: - case R_RL78_ABS8UW: - case R_RL78_ABS8S: - OP (0) = relocation; - break; - - default: - break; - } - - return r; -} - -#undef OP -#define OP(i) (contents[rel->r_offset + (i)]) - -/* Relocate an RL78 ELF section. - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -rl78_elf_relocate_section - (bfd * output_bfd, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - asection *splt; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - splt = elf_hash_table (info)->splt; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - bfd_boolean unresolved_reloc = TRUE; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = rl78_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - relocation = 0; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, & sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (sym->st_name == 0) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, h, - sec, relocation, unresolved_reloc, - warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - continue; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_RL78_DIR16S: - { - bfd_vma *plt_offset; - - if (h != NULL) - plt_offset = &h->plt.offset; - else - plt_offset = elf_local_got_offsets (input_bfd) + r_symndx; - - if (! valid_16bit_address (relocation)) - { - /* If this is the first time we've processed this symbol, - fill in the plt entry with the correct symbol address. */ - if ((*plt_offset & 1) == 0) - { - unsigned int x; - - x = 0x000000ec; /* br !!abs24 */ - x |= (relocation << 8) & 0xffffff00; - bfd_put_32 (input_bfd, x, splt->contents + *plt_offset); - *plt_offset |= 1; - } - - relocation = (splt->output_section->vma - + splt->output_offset - + (*plt_offset & -2)); - if (name) - { - char *newname = bfd_malloc (strlen(name)+5); - strcpy (newname, name); - strcat(newname, ".plt"); - _bfd_generic_link_add_one_symbol (info, - input_bfd, - newname, - BSF_FUNCTION | BSF_WEAK, - splt, - (*plt_offset & -2), - 0, - 1, - 0, - 0); - } - } - } - break; - } - - if (h != NULL && h->root.type == bfd_link_hash_undefweak) - /* If the symbol is undefined and weak - then the relocation resolves to zero. */ - relocation = 0; - else - { - if (howto->pc_relative) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - relocation -= bfd_get_reloc_size (howto); - } - - relocation += rel->r_addend; - } - - r = bfd_reloc_ok; - -#define RANGE(a,b) if (a > (long) relocation || (long) relocation > b) r = bfd_reloc_overflow - - /* Opcode relocs are always big endian. Data relocs are bi-endian. */ - switch (r_type) - { - case R_RL78_NONE: - break; - - case R_RL78_RH_RELAX: - break; - - case R_RL78_DIR8S_PCREL: - RANGE (-128, 127); - OP (0) = relocation; - break; - - case R_RL78_DIR8S: - RANGE (-128, 255); - OP (0) = relocation; - break; - - case R_RL78_DIR8U: - RANGE (0, 255); - OP (0) = relocation; - break; - - case R_RL78_DIR16S_PCREL: - RANGE (-32768, 32767); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_DIR16S: - if ((relocation & 0xf0000) == 0xf0000) - relocation &= 0xffff; - RANGE (-32768, 65535); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_DIR16U: - RANGE (0, 65536); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_DIR16: - RANGE (-32768, 65536); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_DIR16_REV: - RANGE (-32768, 65536); - OP (1) = relocation; - OP (0) = relocation >> 8; - break; - - case R_RL78_DIR3U_PCREL: - RANGE (3, 10); - OP (0) &= 0xf8; - OP (0) |= relocation & 0x07; - break; - - case R_RL78_DIR24S_PCREL: - RANGE (-0x800000, 0x7fffff); - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - break; - - case R_RL78_DIR24S: - RANGE (-0x800000, 0x7fffff); - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - break; - - case R_RL78_DIR32: - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; - break; - - case R_RL78_DIR32_REV: - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; - break; - - case R_RL78_RH_SFR: - RANGE (0xfff00, 0xfffff); - OP (0) = relocation & 0xff; - break; - - case R_RL78_RH_SADDR: - RANGE (0xffe20, 0xfff1f); - OP (0) = relocation & 0xff; - break; - - /* Complex reloc handling: */ - case R_RL78_ABS32: - case R_RL78_ABS32_REV: - case R_RL78_ABS24S_PCREL: - case R_RL78_ABS24S: - case R_RL78_ABS16: - case R_RL78_ABS16_REV: - case R_RL78_ABS16S_PCREL: - case R_RL78_ABS16S: - case R_RL78_ABS16U: - case R_RL78_ABS16UL: - case R_RL78_ABS16UW: - case R_RL78_ABS8: - case R_RL78_ABS8U: - case R_RL78_ABS8UL: - case R_RL78_ABS8UW: - case R_RL78_ABS8S_PCREL: - case R_RL78_ABS8S: - case R_RL78_OPneg: - case R_RL78_OPadd: - case R_RL78_OPsub: - case R_RL78_OPmul: - case R_RL78_OPdiv: - case R_RL78_OPshla: - case R_RL78_OPshra: - case R_RL78_OPsctsize: - case R_RL78_OPscttop: - case R_RL78_OPand: - case R_RL78_OPor: - case R_RL78_OPxor: - case R_RL78_OPnot: - case R_RL78_OPmod: - relocation = rl78_compute_complex_reloc (r_type, 0, input_section); - - switch (r_type) - { - case R_RL78_ABS32: - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; - break; - - case R_RL78_ABS32_REV: - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; - break; - - case R_RL78_ABS24S_PCREL: - case R_RL78_ABS24S: - RANGE (-0x800000, 0x7fffff); - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - break; - - case R_RL78_ABS16: - RANGE (-32768, 65535); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_ABS16_REV: - RANGE (-32768, 65535); - OP (1) = relocation; - OP (0) = relocation >> 8; - break; - - case R_RL78_ABS16S_PCREL: - case R_RL78_ABS16S: - RANGE (-32768, 32767); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_ABS16U: - case R_RL78_ABS16UL: - case R_RL78_ABS16UW: - RANGE (0, 65536); - OP (0) = relocation; - OP (1) = relocation >> 8; - break; - - case R_RL78_ABS8: - RANGE (-128, 255); - OP (0) = relocation; - break; - - case R_RL78_ABS8U: - case R_RL78_ABS8UL: - case R_RL78_ABS8UW: - RANGE (0, 255); - OP (0) = relocation; - break; - - case R_RL78_ABS8S_PCREL: - case R_RL78_ABS8S: - RANGE (-128, 127); - OP (0) = relocation; - break; - - default: - break; - } - break; - - case R_RL78_SYM: - if (r_symndx < symtab_hdr->sh_info) - relocation = sec->output_section->vma + sec->output_offset - + sym->st_value + rel->r_addend; - else if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - relocation = h->root.u.def.value - + sec->output_section->vma - + sec->output_offset - + rel->r_addend; - else - { - relocation = 0; - if (h->root.type != bfd_link_hash_undefweak) - _bfd_error_handler (_("Warning: RL78_SYM reloc with an unknown symbol")); - } - (void) rl78_compute_complex_reloc (r_type, relocation, input_section); - break; - - case R_RL78_OPromtop: - relocation = get_romstart (info, input_bfd, input_section, rel->r_offset); - (void) rl78_compute_complex_reloc (r_type, relocation, input_section); - break; - - case R_RL78_OPramtop: - relocation = get_ramstart (info, input_bfd, input_section, rel->r_offset); - (void) rl78_compute_complex_reloc (r_type, relocation, input_section); - break; - - default: - r = bfd_reloc_notsupported; - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - /* Catch the case of a missing function declaration - and emit a more helpful error message. */ - if (r_type == R_RL78_DIR24S_PCREL) - /* xgettext:c-format */ - msg = _("%B(%A): error: call to undefined function '%s'"); - else - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_other: - /* xgettext:c-format */ - msg = _("%B(%A): warning: unaligned access to symbol '%s' in the small data area"); - break; - - case bfd_reloc_outofrange: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: dangerous relocation"); - break; - - default: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: unknown error"); - break; - } - - if (msg) - _bfd_error_handler (msg, input_bfd, input_section, name); - } - } - - return TRUE; -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -rl78_elf_set_private_flags (bfd * abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -static bfd_boolean no_warn_mismatch = FALSE; - -void bfd_elf32_rl78_set_target_flags (bfd_boolean); - -void -bfd_elf32_rl78_set_target_flags (bfd_boolean user_no_warn_mismatch) -{ - no_warn_mismatch = user_no_warn_mismatch; -} - -static const char * -rl78_cpu_name (flagword flags) -{ - switch (flags & E_FLAG_RL78_CPU_MASK) - { - default: return ""; - case E_FLAG_RL78_G10: return "G10"; - case E_FLAG_RL78_G13: return "G13"; - case E_FLAG_RL78_G14: return "G14"; - } -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -rl78_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword new_flags; - flagword old_flags; - bfd_boolean error = FALSE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - else if (old_flags != new_flags) - { - flagword changed_flags = old_flags ^ new_flags; - - if (changed_flags & E_FLAG_RL78_CPU_MASK) - { - flagword out_cpu = old_flags & E_FLAG_RL78_CPU_MASK; - flagword in_cpu = new_flags & E_FLAG_RL78_CPU_MASK; - - if (in_cpu == E_FLAG_RL78_ANY_CPU || in_cpu == out_cpu) - /* It does not matter what new_cpu may have. */; - else if (out_cpu == E_FLAG_RL78_ANY_CPU) - { - if (in_cpu == E_FLAG_RL78_G10) - { - /* G10 files can only be linked with other G10 files. - If the output is set to "any" this means that it is - a G14 file that does not use hardware multiply/divide, - but that is still incompatible with the G10 ABI. */ - error = TRUE; - - _bfd_error_handler - /* xgettext:c-format */ - (_("RL78 ABI conflict: G10 file %B cannot be linked" - " with %s file %B"), - ibfd, rl78_cpu_name (out_cpu), obfd); - } - else - { - old_flags &= ~ E_FLAG_RL78_CPU_MASK; - old_flags |= in_cpu; - elf_elfheader (obfd)->e_flags = old_flags; - } - } - else - { - error = TRUE; - - _bfd_error_handler - /* xgettext:c-format */ - (_("RL78 ABI conflict: cannot link %s file %B with %s file %B"), - rl78_cpu_name (in_cpu), ibfd, - rl78_cpu_name (out_cpu), obfd); - } - } - - if (changed_flags & E_FLAG_RL78_64BIT_DOUBLES) - { - _bfd_error_handler - (_("RL78 merge conflict: cannot link 32-bit and 64-bit objects together")); - - if (old_flags & E_FLAG_RL78_64BIT_DOUBLES) - /* xgettext:c-format */ - _bfd_error_handler (_("- %B is 64-bit, %B is not"), - obfd, ibfd); - else - /* xgettext:c-format */ - _bfd_error_handler (_("- %B is 64-bit, %B is not"), - ibfd, obfd); - error = TRUE; - } - } - - return !error; -} - -static bfd_boolean -rl78_elf_print_private_bfd_data (bfd * abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (long) flags); - - if (flags & E_FLAG_RL78_CPU_MASK) - fprintf (file, " [%s]", rl78_cpu_name (flags)); - - if (flags & E_FLAG_RL78_64BIT_DOUBLES) - fprintf (file, _(" [64-bit doubles]")); - - fputc ('\n', file); - return TRUE; -} - -/* Return the MACH for an e_flags value. */ - -static int -elf32_rl78_machine (bfd * abfd ATTRIBUTE_UNUSED) -{ - return bfd_mach_rl78; -} - -static bfd_boolean -rl78_elf_object_p (bfd * abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_rl78, - elf32_rl78_machine (abfd)); - return TRUE; -} - -/* support PLT for 16-bit references to 24-bit functions. */ - -/* We support 16-bit pointers to code above 64k by generating a thunk - below 64k containing a JMP instruction to the final address. */ - -static bfd_boolean -rl78_elf_check_relocs - (bfd * abfd, - struct bfd_link_info * info, - asection * sec, - const Elf_Internal_Rela * relocs) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - const Elf_Internal_Rela * rel; - const Elf_Internal_Rela * rel_end; - bfd_vma *local_plt_offsets; - asection *splt; - bfd *dynobj; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_plt_offsets = elf_local_got_offsets (abfd); - dynobj = elf_hash_table(info)->dynobj; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - bfd_vma *offset; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes a 16-bit pointer to a function. - We may need to allocate a thunk in low memory; reserve memory - for it now. */ - case R_RL78_DIR16S: - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - splt = elf_hash_table (info)->splt; - if (splt == NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED - | SEC_READONLY | SEC_CODE); - splt = bfd_make_section_anyway_with_flags (dynobj, ".plt", - flags); - elf_hash_table (info)->splt = splt; - if (splt == NULL - || ! bfd_set_section_alignment (dynobj, splt, 1)) - return FALSE; - } - - if (h != NULL) - offset = &h->plt.offset; - else - { - if (local_plt_offsets == NULL) - { - size_t size; - unsigned int i; - - size = symtab_hdr->sh_info * sizeof (bfd_vma); - local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size); - if (local_plt_offsets == NULL) - return FALSE; - elf_local_got_offsets (abfd) = local_plt_offsets; - - for (i = 0; i < symtab_hdr->sh_info; i++) - local_plt_offsets[i] = (bfd_vma) -1; - } - offset = &local_plt_offsets[r_symndx]; - } - - if (*offset == (bfd_vma) -1) - { - *offset = splt->size; - splt->size += 4; - } - break; - } - } - - return TRUE; -} - -/* This must exist if dynobj is ever set. */ - -static bfd_boolean -rl78_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *splt; - - if (!elf_hash_table (info)->dynamic_sections_created) - return TRUE; - - /* As an extra sanity check, verify that all plt entries have been - filled in. However, relaxing might have changed the relocs so - that some plt entries don't get filled in, so we have to skip - this check if we're relaxing. Unfortunately, check_relocs is - called before relaxation. */ - - if (info->relax_trip > 0) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - splt = elf_hash_table (info)->splt; - if (dynobj != NULL && splt != NULL) - { - bfd_byte *contents = splt->contents; - unsigned int i, size = splt->size; - - for (i = 0; i < size; i += 4) - { - unsigned int x = bfd_get_32 (dynobj, contents + i); - BFD_ASSERT (x != 0); - } - } - - return TRUE; -} - -static bfd_boolean -rl78_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *splt; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - return TRUE; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->size); - if (splt->contents == NULL) - return FALSE; - - return TRUE; -} - - - -/* Handle relaxing. */ - -/* A subroutine of rl78_elf_relax_section. If the global symbol H - is within the low 64k, remove any entry for it in the plt. */ - -struct relax_plt_data -{ - asection *splt; - bfd_boolean *again; -}; - -static bfd_boolean -rl78_relax_plt_check (struct elf_link_hash_entry *h, void * xdata) -{ - struct relax_plt_data *data = (struct relax_plt_data *) xdata; - - if (h->plt.offset != (bfd_vma) -1) - { - bfd_vma address; - - if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - address = 0; - else - address = (h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset - + h->root.u.def.value); - - if (valid_16bit_address (address)) - { - h->plt.offset = -1; - data->splt->size -= 4; - *data->again = TRUE; - } - } - - return TRUE; -} - -/* A subroutine of rl78_elf_relax_section. If the global symbol H - previously had a plt entry, give it a new entry offset. */ - -static bfd_boolean -rl78_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata) -{ - bfd_vma *entry = (bfd_vma *) xdata; - - if (h->plt.offset != (bfd_vma) -1) - { - h->plt.offset = *entry; - *entry += 4; - } - - return TRUE; -} - -static bfd_boolean -rl78_elf_relax_plt_section (bfd *dynobj, - asection *splt, - struct bfd_link_info *info, - bfd_boolean *again) -{ - struct relax_plt_data relax_plt_data; - bfd *ibfd; - - /* Assume nothing changes. */ - *again = FALSE; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* We only relax the .plt section at the moment. */ - if (dynobj != elf_hash_table (info)->dynobj - || strcmp (splt->name, ".plt") != 0) - return TRUE; - - /* Quick check for an empty plt. */ - if (splt->size == 0) - return TRUE; - - /* Map across all global symbols; see which ones happen to - fall in the low 64k. */ - relax_plt_data.splt = splt; - relax_plt_data.again = again; - elf_link_hash_traverse (elf_hash_table (info), rl78_relax_plt_check, - &relax_plt_data); - - /* Likewise for local symbols, though that's somewhat less convenient - as we have to walk the list of input bfds and swap in symbol data. */ - for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next) - { - bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - unsigned int idx; - - if (! local_plt_offsets) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - for (idx = 0; idx < symtab_hdr->sh_info; ++idx) - { - Elf_Internal_Sym *isym; - asection *tsec; - bfd_vma address; - - if (local_plt_offsets[idx] == (bfd_vma) -1) - continue; - - isym = &isymbuf[idx]; - if (isym->st_shndx == SHN_UNDEF) - continue; - else if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else - tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx); - - address = (tsec->output_section->vma - + tsec->output_offset - + isym->st_value); - if (valid_16bit_address (address)) - { - local_plt_offsets[idx] = -1; - splt->size -= 4; - *again = TRUE; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - } - - /* If we changed anything, walk the symbols again to reallocate - .plt entry addresses. */ - if (*again && splt->size > 0) - { - bfd_vma entry = 0; - - elf_link_hash_traverse (elf_hash_table (info), - rl78_relax_plt_realloc, &entry); - - for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next) - { - bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); - unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info; - unsigned int idx; - - if (! local_plt_offsets) - continue; - - for (idx = 0; idx < nlocals; ++idx) - if (local_plt_offsets[idx] != (bfd_vma) -1) - { - local_plt_offsets[idx] = entry; - entry += 4; - } - } - } - - return TRUE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -elf32_rl78_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count, - Elf_Internal_Rela *alignment_rel, int force_snip) -{ - Elf_Internal_Shdr * symtab_hdr; - unsigned int sec_shndx; - bfd_byte * contents; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * irelend; - Elf_Internal_Sym * isym; - Elf_Internal_Sym * isymend; - bfd_vma toaddr; - unsigned int symcount; - struct elf_link_hash_entry ** sym_hashes; - struct elf_link_hash_entry ** end_hashes; - - if (!alignment_rel) - force_snip = 1; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - /* The deletion must stop at the next alignment boundary, if - ALIGNMENT_REL is non-NULL. */ - toaddr = sec->size; - if (alignment_rel) - toaddr = alignment_rel->r_offset; - - irel = elf_section_data (sec)->relocs; - if (irel == NULL) - { - _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, TRUE); - irel = elf_section_data (sec)->relocs; - } - - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - - /* If we don't have an alignment marker to worry about, we can just - shrink the section. Otherwise, we have to fill in the newly - created gap with NOP insns (0x03). */ - if (force_snip) - sec->size -= count; - else - memset (contents + toaddr - count, 0x03, count); - - /* Adjust all the relocs. */ - for (; irel && irel < irelend; irel++) - { - /* Get the new reloc address. */ - if (irel->r_offset > addr - && (irel->r_offset < toaddr - || (force_snip && irel->r_offset == toaddr))) - irel->r_offset -= count; - - /* If we see an ALIGN marker at the end of the gap, we move it - to the beginning of the gap, since marking these gaps is what - they're for. */ - if (irel->r_offset == toaddr - && ELF32_R_TYPE (irel->r_info) == R_RL78_RH_RELAX - && irel->r_addend & RL78_RELAXA_ALIGN) - irel->r_offset -= count; - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - isymend = isym + symtab_hdr->sh_info; - - for (; isym < isymend; isym++) - { - /* If the symbol is in the range of memory we just moved, we - have to adjust its value. */ - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - isym->st_value -= count; - - /* If the symbol *spans* the bytes we just deleted (i.e. it's - *end* is in the moved bytes but it's *start* isn't), then we - must adjust its size. */ - if (isym->st_shndx == sec_shndx - && isym->st_value < addr - && isym->st_value + isym->st_size > addr - && isym->st_value + isym->st_size < toaddr) - isym->st_size -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - /* As above, adjust the value if needed. */ - if (sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; - - /* As above, adjust the size if needed. */ - if (sym_hash->root.u.def.value < addr - && sym_hash->root.u.def.value + sym_hash->size > addr - && sym_hash->root.u.def.value + sym_hash->size < toaddr) - sym_hash->size -= count; - } - } - - return TRUE; -} - -/* Used to sort relocs by address. If relocs have the same address, - we maintain their relative order, except that R_RL78_RH_RELAX - alignment relocs must be the first reloc for any given address. */ - -static void -reloc_bubblesort (Elf_Internal_Rela * r, int count) -{ - int i; - bfd_boolean again; - bfd_boolean swappit; - - /* This is almost a classic bubblesort. It's the slowest sort, but - we're taking advantage of the fact that the relocations are - mostly in order already (the assembler emits them that way) and - we need relocs with the same address to remain in the same - relative order. */ - again = TRUE; - while (again) - { - again = FALSE; - for (i = 0; i < count - 1; i ++) - { - if (r[i].r_offset > r[i + 1].r_offset) - swappit = TRUE; - else if (r[i].r_offset < r[i + 1].r_offset) - swappit = FALSE; - else if (ELF32_R_TYPE (r[i + 1].r_info) == R_RL78_RH_RELAX - && (r[i + 1].r_addend & RL78_RELAXA_ALIGN)) - swappit = TRUE; - else if (ELF32_R_TYPE (r[i + 1].r_info) == R_RL78_RH_RELAX - && (r[i + 1].r_addend & RL78_RELAXA_ELIGN) - && !(ELF32_R_TYPE (r[i].r_info) == R_RL78_RH_RELAX - && (r[i].r_addend & RL78_RELAXA_ALIGN))) - swappit = TRUE; - else - swappit = FALSE; - - if (swappit) - { - Elf_Internal_Rela tmp; - - tmp = r[i]; - r[i] = r[i + 1]; - r[i + 1] = tmp; - /* If we do move a reloc back, re-scan to see if it - needs to be moved even further back. This avoids - most of the O(n^2) behavior for our cases. */ - if (i > 0) - i -= 2; - again = TRUE; - } - } - } -} - - -#define OFFSET_FOR_RELOC(rel, lrel, scale) \ - rl78_offset_for_reloc (abfd, rel + 1, symtab_hdr, shndx_buf, intsyms, \ - lrel, abfd, sec, link_info, scale) - -static bfd_vma -rl78_offset_for_reloc (bfd * abfd, - Elf_Internal_Rela * rel, - Elf_Internal_Shdr * symtab_hdr, - Elf_External_Sym_Shndx * shndx_buf ATTRIBUTE_UNUSED, - Elf_Internal_Sym * intsyms, - Elf_Internal_Rela ** lrel, - bfd * input_bfd, - asection * input_section, - struct bfd_link_info * info, - int * scale) -{ - bfd_vma symval; - - *scale = 1; - - /* REL is the first of 1..N relocations. We compute the symbol - value for each relocation, then combine them if needed. LREL - gets a pointer to the last relocation used. */ - while (1) - { - unsigned long r_type; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (rel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *ssec; - - isym = intsyms + ELF32_R_SYM (rel->r_info); - - if (isym->st_shndx == SHN_UNDEF) - ssec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - ssec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - ssec = bfd_com_section_ptr; - else - ssec = bfd_section_from_elf_index (abfd, - isym->st_shndx); - - /* Initial symbol value. */ - symval = isym->st_value; - - /* GAS may have made this symbol relative to a section, in - which case, we have to add the addend to find the - symbol. */ - if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) - symval += rel->r_addend; - - if (ssec) - { - if ((ssec->flags & SEC_MERGE) - && ssec->sec_info_type == SEC_INFO_TYPE_MERGE) - symval = _bfd_merged_section_offset (abfd, & ssec, - elf_section_data (ssec)->sec_info, - symval); - } - - /* Now make the offset relative to where the linker is putting it. */ - if (ssec) - symval += - ssec->output_section->vma + ssec->output_offset; - - symval += rel->r_addend; - } - else - { - unsigned long indx; - struct elf_link_hash_entry * h; - - /* An external symbol. */ - indx = ELF32_R_SYM (rel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - if (lrel) - *lrel = rel; - return 0; - } - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - symval += rel->r_addend; - } - - r_type = ELF32_R_TYPE (rel->r_info); - switch (r_type) - { - case R_RL78_SYM: - (void) rl78_compute_complex_reloc (r_type, symval, input_section); - break; - - case R_RL78_OPromtop: - symval = get_romstart (info, input_bfd, input_section, rel->r_offset); - (void) rl78_compute_complex_reloc (r_type, symval, input_section); - break; - - case R_RL78_OPramtop: - symval = get_ramstart (info, input_bfd, input_section, rel->r_offset); - (void) rl78_compute_complex_reloc (r_type, symval, input_section); - break; - - case R_RL78_OPneg: - case R_RL78_OPadd: - case R_RL78_OPsub: - case R_RL78_OPmul: - case R_RL78_OPdiv: - case R_RL78_OPshla: - case R_RL78_OPshra: - case R_RL78_OPsctsize: - case R_RL78_OPscttop: - case R_RL78_OPand: - case R_RL78_OPor: - case R_RL78_OPxor: - case R_RL78_OPnot: - case R_RL78_OPmod: - (void) rl78_compute_complex_reloc (r_type, 0, input_section); - break; - - case R_RL78_DIR16UL: - case R_RL78_DIR8UL: - case R_RL78_ABS16UL: - case R_RL78_ABS8UL: - *scale = 4; - goto reloc_computes_value; - - case R_RL78_DIR16UW: - case R_RL78_DIR8UW: - case R_RL78_ABS16UW: - case R_RL78_ABS8UW: - *scale = 2; - goto reloc_computes_value; - - default: - reloc_computes_value: - symval = rl78_compute_complex_reloc (r_type, symval, input_section); - /* Fall through. */ - case R_RL78_DIR32: - case R_RL78_DIR24S: - case R_RL78_DIR16: - case R_RL78_DIR16U: - case R_RL78_DIR16S: - case R_RL78_DIR24S_PCREL: - case R_RL78_DIR16S_PCREL: - case R_RL78_DIR8S_PCREL: - if (lrel) - *lrel = rel; - return symval; - } - - rel ++; - } -} - -struct { - int prefix; /* or -1 for "no prefix" */ - int insn; /* or -1 for "end of list" */ - int insn_for_saddr; /* or -1 for "no alternative" */ - int insn_for_sfr; /* or -1 for "no alternative" */ -} relax_addr16[] = { - { -1, 0x02, 0x06, -1 }, /* ADDW AX, !addr16 */ - { -1, 0x22, 0x26, -1 }, /* SUBW AX, !addr16 */ - { -1, 0x42, 0x46, -1 }, /* CMPW AX, !addr16 */ - { -1, 0x40, 0x4a, -1 }, /* CMP !addr16, #byte */ - - { -1, 0x0f, 0x0b, -1 }, /* ADD A, !addr16 */ - { -1, 0x1f, 0x1b, -1 }, /* ADDC A, !addr16 */ - { -1, 0x2f, 0x2b, -1 }, /* SUB A, !addr16 */ - { -1, 0x3f, 0x3b, -1 }, /* SUBC A, !addr16 */ - { -1, 0x4f, 0x4b, -1 }, /* CMP A, !addr16 */ - { -1, 0x5f, 0x5b, -1 }, /* AND A, !addr16 */ - { -1, 0x6f, 0x6b, -1 }, /* OR A, !addr16 */ - { -1, 0x7f, 0x7b, -1 }, /* XOR A, !addr16 */ - - { -1, 0x8f, 0x8d, 0x8e }, /* MOV A, !addr16 */ - { -1, 0x9f, 0x9d, 0x9e }, /* MOV !addr16, A */ - { -1, 0xaf, 0xad, 0xae }, /* MOVW AX, !addr16 */ - { -1, 0xbf, 0xbd, 0xbe }, /* MOVW !addr16, AX */ - { -1, 0xcf, 0xcd, 0xce }, /* MOVW !addr16, #word */ - - { -1, 0xa0, 0xa4, -1 }, /* INC !addr16 */ - { -1, 0xa2, 0xa6, -1 }, /* INCW !addr16 */ - { -1, 0xb0, 0xb4, -1 }, /* DEC !addr16 */ - { -1, 0xb2, 0xb6, -1 }, /* DECW !addr16 */ - - { -1, 0xd5, 0xd4, -1 }, /* CMP0 !addr16 */ - { -1, 0xe5, 0xe4, -1 }, /* ONEB !addr16 */ - { -1, 0xf5, 0xf4, -1 }, /* CLRB !addr16 */ - - { -1, 0xd9, 0xd8, -1 }, /* MOV X, !addr16 */ - { -1, 0xe9, 0xe8, -1 }, /* MOV B, !addr16 */ - { -1, 0xf9, 0xf8, -1 }, /* MOV C, !addr16 */ - { -1, 0xdb, 0xda, -1 }, /* MOVW BC, !addr16 */ - { -1, 0xeb, 0xea, -1 }, /* MOVW DE, !addr16 */ - { -1, 0xfb, 0xfa, -1 }, /* MOVW HL, !addr16 */ - - { 0x61, 0xaa, 0xa8, -1 }, /* XCH A, !addr16 */ - - { 0x71, 0x00, 0x02, 0x0a }, /* SET1 !addr16.0 */ - { 0x71, 0x10, 0x12, 0x1a }, /* SET1 !addr16.0 */ - { 0x71, 0x20, 0x22, 0x2a }, /* SET1 !addr16.0 */ - { 0x71, 0x30, 0x32, 0x3a }, /* SET1 !addr16.0 */ - { 0x71, 0x40, 0x42, 0x4a }, /* SET1 !addr16.0 */ - { 0x71, 0x50, 0x52, 0x5a }, /* SET1 !addr16.0 */ - { 0x71, 0x60, 0x62, 0x6a }, /* SET1 !addr16.0 */ - { 0x71, 0x70, 0x72, 0x7a }, /* SET1 !addr16.0 */ - - { 0x71, 0x08, 0x03, 0x0b }, /* CLR1 !addr16.0 */ - { 0x71, 0x18, 0x13, 0x1b }, /* CLR1 !addr16.0 */ - { 0x71, 0x28, 0x23, 0x2b }, /* CLR1 !addr16.0 */ - { 0x71, 0x38, 0x33, 0x3b }, /* CLR1 !addr16.0 */ - { 0x71, 0x48, 0x43, 0x4b }, /* CLR1 !addr16.0 */ - { 0x71, 0x58, 0x53, 0x5b }, /* CLR1 !addr16.0 */ - { 0x71, 0x68, 0x63, 0x6b }, /* CLR1 !addr16.0 */ - { 0x71, 0x78, 0x73, 0x7b }, /* CLR1 !addr16.0 */ - - { -1, -1, -1, -1 } -}; - -/* Relax one section. */ - -static bfd_boolean -rl78_elf_relax_section - (bfd * abfd, - asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Shdr * shndx_hdr; - Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * free_relocs = NULL; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * srel; - Elf_Internal_Rela * irelend; - Elf_Internal_Rela * next_alignment; - bfd_byte * contents = NULL; - bfd_byte * free_contents = NULL; - Elf_Internal_Sym * intsyms = NULL; - Elf_Internal_Sym * free_intsyms = NULL; - Elf_External_Sym_Shndx * shndx_buf = NULL; - bfd_vma pc; - bfd_vma symval ATTRIBUTE_UNUSED = 0; - int pcrel ATTRIBUTE_UNUSED = 0; - int code ATTRIBUTE_UNUSED = 0; - int section_alignment_glue; - int scale; - - if (abfd == elf_hash_table (link_info)->dynobj - && strcmp (sec->name, ".plt") == 0) - return rl78_elf_relax_plt_section (abfd, sec, link_info, again); - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = & elf_symtab_hdr (abfd); - if (elf_symtab_shndx_list (abfd)) - shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; - else - shndx_hdr = NULL; - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else - { - if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - elf_section_data (sec)->this_hdr.contents = contents; - } - - /* Read this BFD's symbols. */ - /* Get cached copy if it exists. */ - if (symtab_hdr->contents != NULL) - intsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - else - { - intsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, symtab_hdr->sh_info, 0, NULL, NULL, NULL); - symtab_hdr->contents = (bfd_byte *) intsyms; - } - - if (shndx_hdr && shndx_hdr->sh_size != 0) - { - bfd_size_type amt; - - amt = symtab_hdr->sh_info; - amt *= sizeof (Elf_External_Sym_Shndx); - shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); - if (shndx_buf == NULL) - goto error_return; - if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (shndx_buf, amt, abfd) != amt) - goto error_return; - shndx_hdr->contents = (bfd_byte *) shndx_buf; - } - - /* Get a copy of the native relocations. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - if (! link_info->keep_memory) - free_relocs = internal_relocs; - - /* The RL_ relocs must be just before the operand relocs they go - with, so we must sort them to guarantee this. We use bubblesort - instead of qsort so we can guarantee that relocs with the same - address remain in the same relative order. */ - reloc_bubblesort (internal_relocs, sec->reloc_count); - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - - - /* This will either be NULL or a pointer to the next alignment - relocation. */ - next_alignment = internal_relocs; - - /* We calculate worst case shrinkage caused by alignment directives. - No fool-proof, but better than either ignoring the problem or - doing heavy duty analysis of all the alignment markers in all - input sections. */ - section_alignment_glue = 0; - for (irel = internal_relocs; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == R_RL78_RH_RELAX - && irel->r_addend & RL78_RELAXA_ALIGN) - { - int this_glue = 1 << (irel->r_addend & RL78_RELAXA_ANUM); - - if (section_alignment_glue < this_glue) - section_alignment_glue = this_glue; - } - /* Worst case is all 0..N alignments, in order, causing 2*N-1 byte - shrinkage. */ - section_alignment_glue *= 2; - - for (irel = internal_relocs; irel < irelend; irel++) - { - unsigned char *insn; - int nrelocs; - - /* The insns we care about are all marked with one of these. */ - if (ELF32_R_TYPE (irel->r_info) != R_RL78_RH_RELAX) - continue; - - if (irel->r_addend & RL78_RELAXA_ALIGN - || next_alignment == internal_relocs) - { - /* When we delete bytes, we need to maintain all the alignments - indicated. In addition, we need to be careful about relaxing - jumps across alignment boundaries - these displacements - *grow* when we delete bytes. For now, don't shrink - displacements across an alignment boundary, just in case. - Note that this only affects relocations to the same - section. */ - next_alignment += 2; - while (next_alignment < irelend - && (ELF32_R_TYPE (next_alignment->r_info) != R_RL78_RH_RELAX - || !(next_alignment->r_addend & RL78_RELAXA_ELIGN))) - next_alignment ++; - if (next_alignment >= irelend || next_alignment->r_offset == 0) - next_alignment = NULL; - } - - /* When we hit alignment markers, see if we've shrunk enough - before them to reduce the gap without violating the alignment - requirements. */ - if (irel->r_addend & RL78_RELAXA_ALIGN) - { - /* At this point, the next relocation *should* be the ELIGN - end marker. */ - Elf_Internal_Rela *erel = irel + 1; - unsigned int alignment, nbytes; - - if (ELF32_R_TYPE (erel->r_info) != R_RL78_RH_RELAX) - continue; - if (!(erel->r_addend & RL78_RELAXA_ELIGN)) - continue; - - alignment = 1 << (irel->r_addend & RL78_RELAXA_ANUM); - - if (erel->r_offset - irel->r_offset < alignment) - continue; - - nbytes = erel->r_offset - irel->r_offset; - nbytes /= alignment; - nbytes *= alignment; - - elf32_rl78_relax_delete_bytes (abfd, sec, erel->r_offset - nbytes, nbytes, - next_alignment, erel->r_offset == sec->size); - *again = TRUE; - - continue; - } - - if (irel->r_addend & RL78_RELAXA_ELIGN) - continue; - - insn = contents + irel->r_offset; - - nrelocs = irel->r_addend & RL78_RELAXA_RNUM; - - /* At this point, we have an insn that is a candidate for linker - relaxation. There are NRELOCS relocs following that may be - relaxed, although each reloc may be made of more than one - reloc entry (such as gp-rel symbols). */ - - /* Get the value of the symbol referred to by the reloc. Just - in case this is the last reloc in the list, use the RL's - addend to choose between this reloc (no addend) or the next - (yes addend, which means at least one following reloc). */ - - /* srel points to the "current" reloction for this insn - - actually the last reloc for a given operand, which is the one - we need to update. We check the relaxations in the same - order that the relocations happen, so we'll just push it - along as we go. */ - srel = irel; - - pc = sec->output_section->vma + sec->output_offset - + srel->r_offset; - -#define GET_RELOC \ - BFD_ASSERT (nrelocs > 0); \ - symval = OFFSET_FOR_RELOC (srel, &srel, &scale); \ - pcrel = symval - pc + srel->r_addend; \ - nrelocs --; - -#define SNIPNR(offset, nbytes) \ - elf32_rl78_relax_delete_bytes (abfd, sec, (insn - contents) + offset, nbytes, next_alignment, 0); - -#define SNIP(offset, nbytes, newtype) \ - SNIPNR (offset, nbytes); \ - srel->r_info = ELF32_R_INFO (ELF32_R_SYM (srel->r_info), newtype) - - /* The order of these bit tests must match the order that the - relocs appear in. Since we sorted those by offset, we can - predict them. */ - - /*----------------------------------------------------------------------*/ - /* EF ad BR $rel8 pcrel - ED al ah BR !abs16 abs - EE al ah BR $!rel16 pcrel - EC al ah as BR !!abs20 abs - - FD al ah CALL !abs16 abs - FE al ah CALL $!rel16 pcrel - FC al ah as CALL !!abs20 abs - - DC ad BC $rel8 - DE ad BNC $rel8 - DD ad BZ $rel8 - DF ad BNZ $rel8 - 61 C3 ad BH $rel8 - 61 D3 ad BNH $rel8 - 61 C8 EF ad SKC ; BR $rel8 - 61 D8 EF ad SKNC ; BR $rel8 - 61 E8 EF ad SKZ ; BR $rel8 - 61 F8 EF ad SKNZ ; BR $rel8 - 61 E3 EF ad SKH ; BR $rel8 - 61 F3 EF ad SKNH ; BR $rel8 - */ - - if ((irel->r_addend & RL78_RELAXA_MASK) == RL78_RELAXA_BRA) - { - /* SKIP opcodes that skip non-branches will have a relax tag - but no corresponding symbol to relax against; we just - skip those. */ - if (irel->r_addend & RL78_RELAXA_RNUM) - { - GET_RELOC; - } - - switch (insn[0]) - { - case 0xdc: /* BC */ - case 0xdd: /* BZ */ - case 0xde: /* BNC */ - case 0xdf: /* BNZ */ - if (insn[1] == 0x03 && insn[2] == 0xee /* BR */ - && (srel->r_offset - irel->r_offset) > 1) /* a B without its own reloc */ - { - /* This is a "long" conditional as generated by gas: - DC 03 EE ad.dr */ - if (pcrel < 127 - && pcrel > -127) - { - insn[0] ^= 0x02; /* invert conditional */ - SNIPNR (4, 1); - SNIP (1, 2, R_RL78_DIR8S_PCREL); - insn[1] = pcrel; - *again = TRUE; - } - } - break; - - case 0xec: /* BR !!abs20 */ - - if (pcrel < 127 - && pcrel > -127) - { - insn[0] = 0xef; - insn[1] = pcrel; - SNIP (2, 2, R_RL78_DIR8S_PCREL); - *again = TRUE; - } - else if (symval < 65536) - { - insn[0] = 0xed; - insn[1] = symval & 0xff; - insn[2] = symval >> 8; - SNIP (2, 1, R_RL78_DIR16U); - *again = TRUE; - } - else if (pcrel < 32767 - && pcrel > -32767) - { - insn[0] = 0xee; - insn[1] = pcrel & 0xff; - insn[2] = pcrel >> 8; - SNIP (2, 1, R_RL78_DIR16S_PCREL); - *again = TRUE; - } - break; - - case 0xee: /* BR $!pcrel16 */ - case 0xed: /* BR $!abs16 */ - if (pcrel < 127 - && pcrel > -127) - { - insn[0] = 0xef; - insn[1] = pcrel; - SNIP (2, 1, R_RL78_DIR8S_PCREL); - *again = TRUE; - } - break; - - case 0xfc: /* CALL !!abs20 */ - if (symval < 65536) - { - insn[0] = 0xfd; - insn[1] = symval & 0xff; - insn[2] = symval >> 8; - SNIP (2, 1, R_RL78_DIR16U); - *again = TRUE; - } - else if (pcrel < 32767 - && pcrel > -32767) - { - insn[0] = 0xfe; - insn[1] = pcrel & 0xff; - insn[2] = pcrel >> 8; - SNIP (2, 1, R_RL78_DIR16S_PCREL); - *again = TRUE; - } - break; - - case 0x61: /* PREFIX */ - /* For SKIP/BR, we change the BR opcode and delete the - SKIP. That way, we don't have to find and change the - relocation for the BR. */ - /* Note that, for the case where we're skipping some - other insn, we have no "other" reloc but that's safe - here anyway. */ - switch (insn[1]) - { - case 0xd3: /* BNH */ - case 0xc3: /* BH */ - if (insn[2] == 0x03 && insn[3] == 0xee - && (srel->r_offset - irel->r_offset) > 2) /* a B without its own reloc */ - { - /* Another long branch by gas: - 61 D3 03 EE ad.dr */ - if (pcrel < 127 - && pcrel > -127) - { - insn[1] ^= 0x10; /* invert conditional */ - SNIPNR (5, 1); - SNIP (2, 2, R_RL78_DIR8S_PCREL); - insn[2] = pcrel; - *again = TRUE; - } - } - break; - - case 0xc8: /* SKC */ - if (insn[2] == 0xef) - { - insn[2] = 0xde; /* BNC */ - SNIPNR (0, 2); - } - break; - - case 0xd8: /* SKNC */ - if (insn[2] == 0xef) - { - insn[2] = 0xdc; /* BC */ - SNIPNR (0, 2); - } - break; - - case 0xe8: /* SKZ */ - if (insn[2] == 0xef) - { - insn[2] = 0xdf; /* BNZ */ - SNIPNR (0, 2); - } - break; - - case 0xf8: /* SKNZ */ - if (insn[2] == 0xef) - { - insn[2] = 0xdd; /* BZ */ - SNIPNR (0, 2); - } - break; - - case 0xe3: /* SKH */ - if (insn[2] == 0xef) - { - insn[2] = 0xd3; /* BNH */ - SNIPNR (1, 1); /* we reuse the 0x61 prefix from the SKH */ - } - break; - - case 0xf3: /* SKNH */ - if (insn[2] == 0xef) - { - insn[2] = 0xc3; /* BH */ - SNIPNR (1, 1); /* we reuse the 0x61 prefix from the SKH */ - } - break; - } - break; - } - } - - if ((irel->r_addend & RL78_RELAXA_MASK) == RL78_RELAXA_ADDR16 - && nrelocs > 0) - { - /*----------------------------------------------------------------------*/ - /* Some insns have both a 16-bit address operand and an 8-bit - variant if the address is within a special range: - - Address 16-bit operand SADDR range SFR range - FFF00-FFFFF 0xff00-0xffff 0x00-0xff - FFE20-FFF1F 0xfe20-0xff1f 0x00-0xff - - The RELAX_ADDR16[] array has the insn encodings for the - 16-bit operand version, as well as the SFR and SADDR - variants. We only need to replace the encodings and - adjust the operand. - - Note: we intentionally do not attempt to decode and skip - any ES: prefix, as adding ES: means the addr16 (likely) - no longer points to saddr/sfr space. - */ - - int is_sfr; - int is_saddr; - int idx; - int poff; - - GET_RELOC; - - if (0xffe20 <= symval && symval <= 0xfffff) - { - - is_saddr = (0xffe20 <= symval && symval <= 0xfff1f); - is_sfr = (0xfff00 <= symval && symval <= 0xfffff); - - for (idx = 0; relax_addr16[idx].insn != -1; idx ++) - { - if (relax_addr16[idx].prefix != -1 - && insn[0] == relax_addr16[idx].prefix - && insn[1] == relax_addr16[idx].insn) - { - poff = 1; - } - else if (relax_addr16[idx].prefix == -1 - && insn[0] == relax_addr16[idx].insn) - { - poff = 0; - } - else - continue; - - /* We have a matched insn, and poff is 0 or 1 depending - on the base pattern size. */ - - if (is_sfr && relax_addr16[idx].insn_for_sfr != -1) - { - insn[poff] = relax_addr16[idx].insn_for_sfr; - SNIP (poff+2, 1, R_RL78_RH_SFR); - } - - else if (is_saddr && relax_addr16[idx].insn_for_saddr != -1) - { - insn[poff] = relax_addr16[idx].insn_for_saddr; - SNIP (poff+2, 1, R_RL78_RH_SADDR); - } - } - } - } - /*----------------------------------------------------------------------*/ - } - - return TRUE; - - error_return: - if (free_relocs != NULL) - free (free_relocs); - - if (free_contents != NULL) - free (free_contents); - - if (shndx_buf != NULL) - { - shndx_hdr->contents = NULL; - free (shndx_buf); - } - - if (free_intsyms != NULL) - free (free_intsyms); - - return TRUE; -} - - - -#define ELF_ARCH bfd_arch_rl78 -#define ELF_MACHINE_CODE EM_RL78 -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_LITTLE_SYM rl78_elf32_vec -#define TARGET_LITTLE_NAME "elf32-rl78" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto rl78_info_to_howto_rela -#define elf_backend_object_p rl78_elf_object_p -#define elf_backend_relocate_section rl78_elf_relocate_section -#define elf_symbol_leading_char ('_') -#define elf_backend_can_gc_sections 1 - -#define bfd_elf32_bfd_reloc_type_lookup rl78_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup rl78_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags rl78_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data rl78_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data rl78_elf_print_private_bfd_data - -#define bfd_elf32_bfd_relax_section rl78_elf_relax_section -#define elf_backend_check_relocs rl78_elf_check_relocs -#define elf_backend_always_size_sections \ - rl78_elf_always_size_sections -#define elf_backend_finish_dynamic_sections \ - rl78_elf_finish_dynamic_sections - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-rx.c b/sdcc/support/sdbinutils/bfd/elf32-rx.c deleted file mode 100644 index a0e1f7822..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-rx.c +++ /dev/null @@ -1,4039 +0,0 @@ -/* Renesas RX specific support for 32-bit ELF. - Copyright (C) 2008-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfd_stdint.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/rx.h" -#include "libiberty.h" -#include "elf32-rx.h" - -#define RX_OPCODE_BIG_ENDIAN 0 - -/* This is a meta-target that's used only with objcopy, to avoid the - endian-swap we would otherwise get. We check for this in - rx_elf_object_p(). */ -const bfd_target rx_elf32_be_ns_vec; -const bfd_target rx_elf32_be_vec; - -#ifdef DEBUG -char * rx_get_reloc (long); -void rx_dump_symtab (bfd *, void *, void *); -#endif - -#define RXREL(n,sz,bit,shift,complain,pcrel) \ - HOWTO (R_RX_##n, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ - bfd_elf_generic_reloc, "R_RX_" #n, FALSE, 0, ~0, FALSE) - -/* Note that the relocations around 0x7f are internal to this file; - feel free to move them as needed to avoid conflicts with published - relocation numbers. */ - -static reloc_howto_type rx_elf_howto_table [] = -{ - RXREL (NONE, 3, 0, 0, dont, FALSE), - RXREL (DIR32, 2, 32, 0, signed, FALSE), - RXREL (DIR24S, 2, 24, 0, signed, FALSE), - RXREL (DIR16, 1, 16, 0, dont, FALSE), - RXREL (DIR16U, 1, 16, 0, unsigned, FALSE), - RXREL (DIR16S, 1, 16, 0, signed, FALSE), - RXREL (DIR8, 0, 8, 0, dont, FALSE), - RXREL (DIR8U, 0, 8, 0, unsigned, FALSE), - RXREL (DIR8S, 0, 8, 0, signed, FALSE), - RXREL (DIR24S_PCREL, 2, 24, 0, signed, TRUE), - RXREL (DIR16S_PCREL, 1, 16, 0, signed, TRUE), - RXREL (DIR8S_PCREL, 0, 8, 0, signed, TRUE), - RXREL (DIR16UL, 1, 16, 2, unsigned, FALSE), - RXREL (DIR16UW, 1, 16, 1, unsigned, FALSE), - RXREL (DIR8UL, 0, 8, 2, unsigned, FALSE), - RXREL (DIR8UW, 0, 8, 1, unsigned, FALSE), - RXREL (DIR32_REV, 1, 16, 0, dont, FALSE), - RXREL (DIR16_REV, 1, 16, 0, dont, FALSE), - RXREL (DIR3U_PCREL, 0, 3, 0, dont, TRUE), - - EMPTY_HOWTO (0x13), - EMPTY_HOWTO (0x14), - EMPTY_HOWTO (0x15), - EMPTY_HOWTO (0x16), - EMPTY_HOWTO (0x17), - EMPTY_HOWTO (0x18), - EMPTY_HOWTO (0x19), - EMPTY_HOWTO (0x1a), - EMPTY_HOWTO (0x1b), - EMPTY_HOWTO (0x1c), - EMPTY_HOWTO (0x1d), - EMPTY_HOWTO (0x1e), - EMPTY_HOWTO (0x1f), - - RXREL (RH_3_PCREL, 0, 3, 0, signed, TRUE), - RXREL (RH_16_OP, 1, 16, 0, signed, FALSE), - RXREL (RH_24_OP, 2, 24, 0, signed, FALSE), - RXREL (RH_32_OP, 2, 32, 0, signed, FALSE), - RXREL (RH_24_UNS, 2, 24, 0, unsigned, FALSE), - RXREL (RH_8_NEG, 0, 8, 0, signed, FALSE), - RXREL (RH_16_NEG, 1, 16, 0, signed, FALSE), - RXREL (RH_24_NEG, 2, 24, 0, signed, FALSE), - RXREL (RH_32_NEG, 2, 32, 0, signed, FALSE), - RXREL (RH_DIFF, 2, 32, 0, signed, FALSE), - RXREL (RH_GPRELB, 1, 16, 0, unsigned, FALSE), - RXREL (RH_GPRELW, 1, 16, 0, unsigned, FALSE), - RXREL (RH_GPRELL, 1, 16, 0, unsigned, FALSE), - RXREL (RH_RELAX, 0, 0, 0, dont, FALSE), - - EMPTY_HOWTO (0x2e), - EMPTY_HOWTO (0x2f), - EMPTY_HOWTO (0x30), - EMPTY_HOWTO (0x31), - EMPTY_HOWTO (0x32), - EMPTY_HOWTO (0x33), - EMPTY_HOWTO (0x34), - EMPTY_HOWTO (0x35), - EMPTY_HOWTO (0x36), - EMPTY_HOWTO (0x37), - EMPTY_HOWTO (0x38), - EMPTY_HOWTO (0x39), - EMPTY_HOWTO (0x3a), - EMPTY_HOWTO (0x3b), - EMPTY_HOWTO (0x3c), - EMPTY_HOWTO (0x3d), - EMPTY_HOWTO (0x3e), - EMPTY_HOWTO (0x3f), - EMPTY_HOWTO (0x40), - - RXREL (ABS32, 2, 32, 0, dont, FALSE), - RXREL (ABS24S, 2, 24, 0, signed, FALSE), - RXREL (ABS16, 1, 16, 0, dont, FALSE), - RXREL (ABS16U, 1, 16, 0, unsigned, FALSE), - RXREL (ABS16S, 1, 16, 0, signed, FALSE), - RXREL (ABS8, 0, 8, 0, dont, FALSE), - RXREL (ABS8U, 0, 8, 0, unsigned, FALSE), - RXREL (ABS8S, 0, 8, 0, signed, FALSE), - RXREL (ABS24S_PCREL, 2, 24, 0, signed, TRUE), - RXREL (ABS16S_PCREL, 1, 16, 0, signed, TRUE), - RXREL (ABS8S_PCREL, 0, 8, 0, signed, TRUE), - RXREL (ABS16UL, 1, 16, 0, unsigned, FALSE), - RXREL (ABS16UW, 1, 16, 0, unsigned, FALSE), - RXREL (ABS8UL, 0, 8, 0, unsigned, FALSE), - RXREL (ABS8UW, 0, 8, 0, unsigned, FALSE), - RXREL (ABS32_REV, 2, 32, 0, dont, FALSE), - RXREL (ABS16_REV, 1, 16, 0, dont, FALSE), - -#define STACK_REL_P(x) ((x) <= R_RX_ABS16_REV && (x) >= R_RX_ABS32) - - EMPTY_HOWTO (0x52), - EMPTY_HOWTO (0x53), - EMPTY_HOWTO (0x54), - EMPTY_HOWTO (0x55), - EMPTY_HOWTO (0x56), - EMPTY_HOWTO (0x57), - EMPTY_HOWTO (0x58), - EMPTY_HOWTO (0x59), - EMPTY_HOWTO (0x5a), - EMPTY_HOWTO (0x5b), - EMPTY_HOWTO (0x5c), - EMPTY_HOWTO (0x5d), - EMPTY_HOWTO (0x5e), - EMPTY_HOWTO (0x5f), - EMPTY_HOWTO (0x60), - EMPTY_HOWTO (0x61), - EMPTY_HOWTO (0x62), - EMPTY_HOWTO (0x63), - EMPTY_HOWTO (0x64), - EMPTY_HOWTO (0x65), - EMPTY_HOWTO (0x66), - EMPTY_HOWTO (0x67), - EMPTY_HOWTO (0x68), - EMPTY_HOWTO (0x69), - EMPTY_HOWTO (0x6a), - EMPTY_HOWTO (0x6b), - EMPTY_HOWTO (0x6c), - EMPTY_HOWTO (0x6d), - EMPTY_HOWTO (0x6e), - EMPTY_HOWTO (0x6f), - EMPTY_HOWTO (0x70), - EMPTY_HOWTO (0x71), - EMPTY_HOWTO (0x72), - EMPTY_HOWTO (0x73), - EMPTY_HOWTO (0x74), - EMPTY_HOWTO (0x75), - EMPTY_HOWTO (0x76), - EMPTY_HOWTO (0x77), - - /* These are internal. */ - /* A 5-bit unsigned displacement to a B/W/L address, at bit position 8/12. */ - /* ---- ---- 4--- 3210. */ -#define R_RX_RH_ABS5p8B 0x78 - RXREL (RH_ABS5p8B, 0, 0, 0, dont, FALSE), -#define R_RX_RH_ABS5p8W 0x79 - RXREL (RH_ABS5p8W, 0, 0, 0, dont, FALSE), -#define R_RX_RH_ABS5p8L 0x7a - RXREL (RH_ABS5p8L, 0, 0, 0, dont, FALSE), - /* A 5-bit unsigned displacement to a B/W/L address, at bit position 5/12. */ - /* ---- -432 1--- 0---. */ -#define R_RX_RH_ABS5p5B 0x7b - RXREL (RH_ABS5p5B, 0, 0, 0, dont, FALSE), -#define R_RX_RH_ABS5p5W 0x7c - RXREL (RH_ABS5p5W, 0, 0, 0, dont, FALSE), -#define R_RX_RH_ABS5p5L 0x7d - RXREL (RH_ABS5p5L, 0, 0, 0, dont, FALSE), - /* A 4-bit unsigned immediate at bit position 8. */ -#define R_RX_RH_UIMM4p8 0x7e - RXREL (RH_UIMM4p8, 0, 0, 0, dont, FALSE), - /* A 4-bit negative unsigned immediate at bit position 8. */ -#define R_RX_RH_UNEG4p8 0x7f - RXREL (RH_UNEG4p8, 0, 0, 0, dont, FALSE), - /* End of internal relocs. */ - - RXREL (SYM, 2, 32, 0, dont, FALSE), - RXREL (OPneg, 2, 32, 0, dont, FALSE), - RXREL (OPadd, 2, 32, 0, dont, FALSE), - RXREL (OPsub, 2, 32, 0, dont, FALSE), - RXREL (OPmul, 2, 32, 0, dont, FALSE), - RXREL (OPdiv, 2, 32, 0, dont, FALSE), - RXREL (OPshla, 2, 32, 0, dont, FALSE), - RXREL (OPshra, 2, 32, 0, dont, FALSE), - RXREL (OPsctsize, 2, 32, 0, dont, FALSE), - RXREL (OPscttop, 2, 32, 0, dont, FALSE), - RXREL (OPand, 2, 32, 0, dont, FALSE), - RXREL (OPor, 2, 32, 0, dont, FALSE), - RXREL (OPxor, 2, 32, 0, dont, FALSE), - RXREL (OPnot, 2, 32, 0, dont, FALSE), - RXREL (OPmod, 2, 32, 0, dont, FALSE), - RXREL (OPromtop, 2, 32, 0, dont, FALSE), - RXREL (OPramtop, 2, 32, 0, dont, FALSE) -}; - -/* Map BFD reloc types to RX ELF reloc types. */ - -struct rx_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int rx_reloc_val; -}; - -static const struct rx_reloc_map rx_reloc_map [] = -{ - { BFD_RELOC_NONE, R_RX_NONE }, - { BFD_RELOC_8, R_RX_DIR8S }, - { BFD_RELOC_16, R_RX_DIR16S }, - { BFD_RELOC_24, R_RX_DIR24S }, - { BFD_RELOC_32, R_RX_DIR32 }, - { BFD_RELOC_RX_16_OP, R_RX_DIR16 }, - { BFD_RELOC_RX_DIR3U_PCREL, R_RX_DIR3U_PCREL }, - { BFD_RELOC_8_PCREL, R_RX_DIR8S_PCREL }, - { BFD_RELOC_16_PCREL, R_RX_DIR16S_PCREL }, - { BFD_RELOC_24_PCREL, R_RX_DIR24S_PCREL }, - { BFD_RELOC_RX_8U, R_RX_DIR8U }, - { BFD_RELOC_RX_16U, R_RX_DIR16U }, - { BFD_RELOC_RX_24U, R_RX_RH_24_UNS }, - { BFD_RELOC_RX_NEG8, R_RX_RH_8_NEG }, - { BFD_RELOC_RX_NEG16, R_RX_RH_16_NEG }, - { BFD_RELOC_RX_NEG24, R_RX_RH_24_NEG }, - { BFD_RELOC_RX_NEG32, R_RX_RH_32_NEG }, - { BFD_RELOC_RX_DIFF, R_RX_RH_DIFF }, - { BFD_RELOC_RX_GPRELB, R_RX_RH_GPRELB }, - { BFD_RELOC_RX_GPRELW, R_RX_RH_GPRELW }, - { BFD_RELOC_RX_GPRELL, R_RX_RH_GPRELL }, - { BFD_RELOC_RX_RELAX, R_RX_RH_RELAX }, - { BFD_RELOC_RX_SYM, R_RX_SYM }, - { BFD_RELOC_RX_OP_SUBTRACT, R_RX_OPsub }, - { BFD_RELOC_RX_OP_NEG, R_RX_OPneg }, - { BFD_RELOC_RX_ABS8, R_RX_ABS8 }, - { BFD_RELOC_RX_ABS16, R_RX_ABS16 }, - { BFD_RELOC_RX_ABS16_REV, R_RX_ABS16_REV }, - { BFD_RELOC_RX_ABS32, R_RX_ABS32 }, - { BFD_RELOC_RX_ABS32_REV, R_RX_ABS32_REV }, - { BFD_RELOC_RX_ABS16UL, R_RX_ABS16UL }, - { BFD_RELOC_RX_ABS16UW, R_RX_ABS16UW }, - { BFD_RELOC_RX_ABS16U, R_RX_ABS16U } -}; - -#define BIGE(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) - -static reloc_howto_type * -rx_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - if (code == BFD_RELOC_RX_32_OP) - return rx_elf_howto_table + R_RX_DIR32; - - for (i = ARRAY_SIZE (rx_reloc_map); i--;) - if (rx_reloc_map [i].bfd_reloc_val == code) - return rx_elf_howto_table + rx_reloc_map[i].rx_reloc_val; - - return NULL; -} - -static reloc_howto_type * -rx_reloc_name_lookup (bfd * abfd ATTRIBUTE_UNUSED, const char * r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (rx_elf_howto_table); i++) - if (rx_elf_howto_table[i].name != NULL - && strcasecmp (rx_elf_howto_table[i].name, r_name) == 0) - return rx_elf_howto_table + i; - - return NULL; -} - -/* Set the howto pointer for an RX ELF reloc. */ - -static void -rx_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_RX_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid RX reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = rx_elf_howto_table + r_type; -} - -static bfd_vma -get_symbol_value (const char * name, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - int offset) -{ - bfd_vma value = 0; - struct bfd_link_hash_entry * h; - - h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); - - if (h == NULL - || (h->type != bfd_link_hash_defined - && h->type != bfd_link_hash_defweak)) - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, offset, TRUE); - else - value = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - return value; -} - -static bfd_vma -get_symbol_value_maybe (const char * name, - struct bfd_link_info * info) -{ - bfd_vma value = 0; - struct bfd_link_hash_entry * h; - - h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE); - - if (h == NULL - || (h->type != bfd_link_hash_defined - && h->type != bfd_link_hash_defweak)) - return 0; - else - value = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - return value; -} - -static bfd_vma -get_gp (struct bfd_link_info * info, - bfd * abfd, - asection * sec, - int offset) -{ - static bfd_boolean cached = FALSE; - static bfd_vma cached_value = 0; - - if (!cached) - { - cached_value = get_symbol_value ("__gp", info, abfd, sec, offset); - cached = TRUE; - } - return cached_value; -} - -static bfd_vma -get_romstart (struct bfd_link_info * info, - bfd * abfd, - asection * sec, - int offset) -{ - static bfd_boolean cached = FALSE; - static bfd_vma cached_value = 0; - - if (!cached) - { - cached_value = get_symbol_value ("_start", info, abfd, sec, offset); - cached = TRUE; - } - return cached_value; -} - -static bfd_vma -get_ramstart (struct bfd_link_info * info, - bfd * abfd, - asection * sec, - int offset) -{ - static bfd_boolean cached = FALSE; - static bfd_vma cached_value = 0; - - if (!cached) - { - cached_value = get_symbol_value ("__datastart", info, abfd, sec, offset); - cached = TRUE; - } - return cached_value; -} - -#define NUM_STACK_ENTRIES 16 -static int32_t rx_stack [ NUM_STACK_ENTRIES ]; -static unsigned int rx_stack_top; - -#define RX_STACK_PUSH(val) \ - do \ - { \ - if (rx_stack_top < NUM_STACK_ENTRIES) \ - rx_stack [rx_stack_top ++] = (val); \ - else \ - r = bfd_reloc_dangerous; \ - } \ - while (0) - -#define RX_STACK_POP(dest) \ - do \ - { \ - if (rx_stack_top > 0) \ - (dest) = rx_stack [-- rx_stack_top]; \ - else \ - (dest) = 0, r = bfd_reloc_dangerous; \ - } \ - while (0) - -/* Relocate an RX ELF section. - There is some attempt to make this function usable for many architectures, - both USE_REL and USE_RELA ['twould be nice if such a critter existed], - if only to serve as a learning tool. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -rx_elf_relocate_section - (bfd * output_bfd, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - bfd_boolean pid_mode; - bfd_boolean saw_subtract = FALSE; - const char * table_default_cache = NULL; - bfd_vma table_start_cache = 0; - bfd_vma table_end_cache = 0; - - if (elf_elfheader (output_bfd)->e_flags & E_FLAG_RX_PID) - pid_mode = TRUE; - else - pid_mode = FALSE; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - bfd_boolean unresolved_reloc = TRUE; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = rx_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - relocation = 0; - - if (rx_stack_top == 0) - saw_subtract = 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); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (sym->st_name == 0) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, h, - sec, relocation, unresolved_reloc, - warned, ignored); - - name = h->root.root.string; - } - - if (strncmp (name, "$tableentry$default$", 20) == 0) - { - bfd_vma entry_vma; - int idx; - char *buf; - - if (table_default_cache != name) - { - - /* All relocs for a given table should be to the same - (weak) default symbol) so we can use it to detect a - cache miss. We use the offset into the table to find - the "real" symbol. Calculate and store the table's - offset here. */ - - table_default_cache = name; - - /* We have already done error checking in rx_table_find(). */ - - buf = (char *) malloc (13 + strlen (name + 20)); - - sprintf (buf, "$tablestart$%s", name + 20); - table_start_cache = get_symbol_value (buf, - info, - input_bfd, - input_section, - rel->r_offset); - - sprintf (buf, "$tableend$%s", name + 20); - table_end_cache = get_symbol_value (buf, - info, - input_bfd, - input_section, - rel->r_offset); - - free (buf); - } - - entry_vma = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - if (table_end_cache <= entry_vma || entry_vma < table_start_cache) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B:%A: table entry %s outside table"), - input_bfd, input_section, - name); - } - else if ((int) (entry_vma - table_start_cache) % 4) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B:%A: table entry %s not word-aligned within table"), - input_bfd, input_section, - name); - } - else - { - idx = (int) (entry_vma - table_start_cache) / 4; - - /* This will look like $tableentry$$ */ - buf = (char *) malloc (12 + 20 + strlen (name + 20)); - sprintf (buf, "$tableentry$%d$%s", idx, name + 20); - - h = (struct elf_link_hash_entry *) bfd_link_hash_lookup (info->hash, buf, FALSE, FALSE, TRUE); - - if (h) - { - relocation = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset);; - } - - free (buf); - } - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - continue; - } - - if (h != NULL && h->root.type == bfd_link_hash_undefweak) - /* If the symbol is undefined and weak - then the relocation resolves to zero. */ - relocation = 0; - else - { - if (howto->pc_relative) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - if (r_type != R_RX_RH_3_PCREL - && r_type != R_RX_DIR3U_PCREL) - relocation ++; - } - - relocation += rel->r_addend; - } - - r = bfd_reloc_ok; - -#define RANGE(a,b) if (a > (long) relocation || (long) relocation > b) r = bfd_reloc_overflow -#define ALIGN(m) if (relocation & m) r = bfd_reloc_other; -#define OP(i) (contents[rel->r_offset + (i)]) -#define WARN_REDHAT(type) \ - /* xgettext:c-format */ \ - _bfd_error_handler (_("%B:%A: Warning: deprecated Red Hat reloc " type " detected against: %s."), \ - input_bfd, input_section, name) - - /* Check for unsafe relocs in PID mode. These are any relocs where - an absolute address is being computed. There are special cases - for relocs against symbols that are known to be referenced in - crt0.o before the PID base address register has been initialised. */ -#define UNSAFE_FOR_PID \ - do \ - { \ - if (pid_mode \ - && sec != NULL \ - && sec->flags & SEC_READONLY \ - && !(input_section->flags & SEC_DEBUGGING) \ - && strcmp (name, "__pid_base") != 0 \ - && strcmp (name, "__gp") != 0 \ - && strcmp (name, "__romdatastart") != 0 \ - && !saw_subtract) \ - /* xgettext:c-format */ \ - _bfd_error_handler (_("%B(%A): unsafe PID relocation %s at %#Lx (against %s in %s)"), \ - input_bfd, input_section, howto->name, \ - input_section->output_section->vma + input_section->output_offset + rel->r_offset, \ - name, sec->name); \ - } \ - while (0) - - /* Opcode relocs are always big endian. Data relocs are bi-endian. */ - switch (r_type) - { - case R_RX_NONE: - break; - - case R_RX_RH_RELAX: - break; - - case R_RX_RH_3_PCREL: - WARN_REDHAT ("RX_RH_3_PCREL"); - RANGE (3, 10); - OP (0) &= 0xf8; - OP (0) |= relocation & 0x07; - break; - - case R_RX_RH_8_NEG: - WARN_REDHAT ("RX_RH_8_NEG"); - relocation = - relocation; - /* Fall through. */ - case R_RX_DIR8S_PCREL: - UNSAFE_FOR_PID; - RANGE (-128, 127); - OP (0) = relocation; - break; - - case R_RX_DIR8S: - UNSAFE_FOR_PID; - RANGE (-128, 255); - OP (0) = relocation; - break; - - case R_RX_DIR8U: - UNSAFE_FOR_PID; - RANGE (0, 255); - OP (0) = relocation; - break; - - case R_RX_RH_16_NEG: - WARN_REDHAT ("RX_RH_16_NEG"); - relocation = - relocation; - /* Fall through. */ - case R_RX_DIR16S_PCREL: - UNSAFE_FOR_PID; - RANGE (-32768, 32767); -#if RX_OPCODE_BIG_ENDIAN -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_RH_16_OP: - WARN_REDHAT ("RX_RH_16_OP"); - UNSAFE_FOR_PID; - RANGE (-32768, 32767); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_DIR16S: - UNSAFE_FOR_PID; - RANGE (-32768, 65535); - if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) - { - OP (1) = relocation; - OP (0) = relocation >> 8; - } - else - { - OP (0) = relocation; - OP (1) = relocation >> 8; - } - break; - - case R_RX_DIR16U: - UNSAFE_FOR_PID; - RANGE (0, 65536); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_DIR16: - UNSAFE_FOR_PID; - RANGE (-32768, 65536); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_DIR16_REV: - UNSAFE_FOR_PID; - RANGE (-32768, 65536); -#if RX_OPCODE_BIG_ENDIAN - OP (0) = relocation; - OP (1) = relocation >> 8; -#else - OP (1) = relocation; - OP (0) = relocation >> 8; -#endif - break; - - case R_RX_DIR3U_PCREL: - RANGE (3, 10); - OP (0) &= 0xf8; - OP (0) |= relocation & 0x07; - break; - - case R_RX_RH_24_NEG: - UNSAFE_FOR_PID; - WARN_REDHAT ("RX_RH_24_NEG"); - relocation = - relocation; - /* Fall through. */ - case R_RX_DIR24S_PCREL: - RANGE (-0x800000, 0x7fffff); -#if RX_OPCODE_BIG_ENDIAN - OP (2) = relocation; - OP (1) = relocation >> 8; - OP (0) = relocation >> 16; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; -#endif - break; - - case R_RX_RH_24_OP: - UNSAFE_FOR_PID; - WARN_REDHAT ("RX_RH_24_OP"); - RANGE (-0x800000, 0x7fffff); -#if RX_OPCODE_BIG_ENDIAN - OP (2) = relocation; - OP (1) = relocation >> 8; - OP (0) = relocation >> 16; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; -#endif - break; - - case R_RX_DIR24S: - UNSAFE_FOR_PID; - RANGE (-0x800000, 0x7fffff); - if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) - { - OP (2) = relocation; - OP (1) = relocation >> 8; - OP (0) = relocation >> 16; - } - else - { - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - } - break; - - case R_RX_RH_24_UNS: - UNSAFE_FOR_PID; - WARN_REDHAT ("RX_RH_24_UNS"); - RANGE (0, 0xffffff); -#if RX_OPCODE_BIG_ENDIAN - OP (2) = relocation; - OP (1) = relocation >> 8; - OP (0) = relocation >> 16; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; -#endif - break; - - case R_RX_RH_32_NEG: - UNSAFE_FOR_PID; - WARN_REDHAT ("RX_RH_32_NEG"); - relocation = - relocation; -#if RX_OPCODE_BIG_ENDIAN - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; -#endif - break; - - case R_RX_RH_32_OP: - UNSAFE_FOR_PID; - WARN_REDHAT ("RX_RH_32_OP"); -#if RX_OPCODE_BIG_ENDIAN - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; -#endif - break; - - case R_RX_DIR32: - if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) - { - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; - } - else - { - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; - } - break; - - case R_RX_DIR32_REV: - if (BIGE (output_bfd)) - { - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; - } - else - { - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; - } - break; - - case R_RX_RH_DIFF: - { - bfd_vma val; - WARN_REDHAT ("RX_RH_DIFF"); - val = bfd_get_32 (output_bfd, & OP (0)); - val -= relocation; - bfd_put_32 (output_bfd, val, & OP (0)); - } - break; - - case R_RX_RH_GPRELB: - WARN_REDHAT ("RX_RH_GPRELB"); - relocation -= get_gp (info, input_bfd, input_section, rel->r_offset); - RANGE (0, 65535); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_RH_GPRELW: - WARN_REDHAT ("RX_RH_GPRELW"); - relocation -= get_gp (info, input_bfd, input_section, rel->r_offset); - ALIGN (1); - relocation >>= 1; - RANGE (0, 65535); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_RH_GPRELL: - WARN_REDHAT ("RX_RH_GPRELL"); - relocation -= get_gp (info, input_bfd, input_section, rel->r_offset); - ALIGN (3); - relocation >>= 2; - RANGE (0, 65535); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - /* Internal relocations just for relaxation: */ - case R_RX_RH_ABS5p5B: - RX_STACK_POP (relocation); - RANGE (0, 31); - OP (0) &= 0xf8; - OP (0) |= relocation >> 2; - OP (1) &= 0x77; - OP (1) |= (relocation << 6) & 0x80; - OP (1) |= (relocation << 3) & 0x08; - break; - - case R_RX_RH_ABS5p5W: - RX_STACK_POP (relocation); - RANGE (0, 62); - ALIGN (1); - relocation >>= 1; - OP (0) &= 0xf8; - OP (0) |= relocation >> 2; - OP (1) &= 0x77; - OP (1) |= (relocation << 6) & 0x80; - OP (1) |= (relocation << 3) & 0x08; - break; - - case R_RX_RH_ABS5p5L: - RX_STACK_POP (relocation); - RANGE (0, 124); - ALIGN (3); - relocation >>= 2; - OP (0) &= 0xf8; - OP (0) |= relocation >> 2; - OP (1) &= 0x77; - OP (1) |= (relocation << 6) & 0x80; - OP (1) |= (relocation << 3) & 0x08; - break; - - case R_RX_RH_ABS5p8B: - RX_STACK_POP (relocation); - RANGE (0, 31); - OP (0) &= 0x70; - OP (0) |= (relocation << 3) & 0x80; - OP (0) |= relocation & 0x0f; - break; - - case R_RX_RH_ABS5p8W: - RX_STACK_POP (relocation); - RANGE (0, 62); - ALIGN (1); - relocation >>= 1; - OP (0) &= 0x70; - OP (0) |= (relocation << 3) & 0x80; - OP (0) |= relocation & 0x0f; - break; - - case R_RX_RH_ABS5p8L: - RX_STACK_POP (relocation); - RANGE (0, 124); - ALIGN (3); - relocation >>= 2; - OP (0) &= 0x70; - OP (0) |= (relocation << 3) & 0x80; - OP (0) |= relocation & 0x0f; - break; - - case R_RX_RH_UIMM4p8: - RANGE (0, 15); - OP (0) &= 0x0f; - OP (0) |= relocation << 4; - break; - - case R_RX_RH_UNEG4p8: - RANGE (-15, 0); - OP (0) &= 0x0f; - OP (0) |= (-relocation) << 4; - break; - - /* Complex reloc handling: */ - - case R_RX_ABS32: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); -#if RX_OPCODE_BIG_ENDIAN - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; -#endif - break; - - case R_RX_ABS32_REV: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); -#if RX_OPCODE_BIG_ENDIAN - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - OP (3) = relocation >> 24; -#else - OP (3) = relocation; - OP (2) = relocation >> 8; - OP (1) = relocation >> 16; - OP (0) = relocation >> 24; -#endif - break; - - case R_RX_ABS24S_PCREL: - case R_RX_ABS24S: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - RANGE (-0x800000, 0x7fffff); - if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) - { - OP (2) = relocation; - OP (1) = relocation >> 8; - OP (0) = relocation >> 16; - } - else - { - OP (0) = relocation; - OP (1) = relocation >> 8; - OP (2) = relocation >> 16; - } - break; - - case R_RX_ABS16: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - RANGE (-32768, 65535); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_ABS16_REV: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - RANGE (-32768, 65535); -#if RX_OPCODE_BIG_ENDIAN - OP (0) = relocation; - OP (1) = relocation >> 8; -#else - OP (1) = relocation; - OP (0) = relocation >> 8; -#endif - break; - - case R_RX_ABS16S_PCREL: - case R_RX_ABS16S: - RX_STACK_POP (relocation); - RANGE (-32768, 32767); - if (BIGE (output_bfd) && !(input_section->flags & SEC_CODE)) - { - OP (1) = relocation; - OP (0) = relocation >> 8; - } - else - { - OP (0) = relocation; - OP (1) = relocation >> 8; - } - break; - - case R_RX_ABS16U: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - RANGE (0, 65536); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_ABS16UL: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - relocation >>= 2; - RANGE (0, 65536); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_ABS16UW: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - relocation >>= 1; - RANGE (0, 65536); -#if RX_OPCODE_BIG_ENDIAN - OP (1) = relocation; - OP (0) = relocation >> 8; -#else - OP (0) = relocation; - OP (1) = relocation >> 8; -#endif - break; - - case R_RX_ABS8: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - RANGE (-128, 255); - OP (0) = relocation; - break; - - case R_RX_ABS8U: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - RANGE (0, 255); - OP (0) = relocation; - break; - - case R_RX_ABS8UL: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - relocation >>= 2; - RANGE (0, 255); - OP (0) = relocation; - break; - - case R_RX_ABS8UW: - UNSAFE_FOR_PID; - RX_STACK_POP (relocation); - relocation >>= 1; - RANGE (0, 255); - OP (0) = relocation; - break; - - case R_RX_ABS8S: - UNSAFE_FOR_PID; - /* Fall through. */ - case R_RX_ABS8S_PCREL: - RX_STACK_POP (relocation); - RANGE (-128, 127); - OP (0) = relocation; - break; - - case R_RX_SYM: - if (r_symndx < symtab_hdr->sh_info) - RX_STACK_PUSH (sec->output_section->vma - + sec->output_offset - + sym->st_value - + rel->r_addend); - else - { - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)) - RX_STACK_PUSH (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset - + rel->r_addend); - else - _bfd_error_handler (_("Warning: RX_SYM reloc with an unknown symbol")); - } - break; - - case R_RX_OPneg: - { - int32_t tmp; - - saw_subtract = TRUE; - RX_STACK_POP (tmp); - tmp = - tmp; - RX_STACK_PUSH (tmp); - } - break; - - case R_RX_OPadd: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 += tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPsub: - { - int32_t tmp1, tmp2; - - saw_subtract = TRUE; - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp2 -= tmp1; - RX_STACK_PUSH (tmp2); - } - break; - - case R_RX_OPmul: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 *= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPdiv: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 /= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPshla: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 <<= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPshra: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 >>= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPsctsize: - RX_STACK_PUSH (input_section->size); - break; - - case R_RX_OPscttop: - RX_STACK_PUSH (input_section->output_section->vma); - break; - - case R_RX_OPand: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 &= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPor: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 |= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPxor: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 ^= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPnot: - { - int32_t tmp; - - RX_STACK_POP (tmp); - tmp = ~ tmp; - RX_STACK_PUSH (tmp); - } - break; - - case R_RX_OPmod: - { - int32_t tmp1, tmp2; - - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 %= tmp2; - RX_STACK_PUSH (tmp1); - } - break; - - case R_RX_OPromtop: - RX_STACK_PUSH (get_romstart (info, input_bfd, input_section, rel->r_offset)); - break; - - case R_RX_OPramtop: - RX_STACK_PUSH (get_ramstart (info, input_bfd, input_section, rel->r_offset)); - break; - - default: - r = bfd_reloc_notsupported; - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - /* Catch the case of a missing function declaration - and emit a more helpful error message. */ - if (r_type == R_RX_DIR24S_PCREL) - /* xgettext:c-format */ - msg = _("%B(%A): error: call to undefined function '%s'"); - else - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_other: - /* xgettext:c-format */ - msg = _("%B(%A): warning: unaligned access to symbol '%s' in the small data area"); - break; - - case bfd_reloc_outofrange: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: dangerous relocation"); - break; - - default: - /* xgettext:c-format */ - msg = _("%B(%A): internal error: unknown error"); - break; - } - - if (msg) - _bfd_error_handler (msg, input_bfd, input_section, name); - } - } - - return TRUE; -} - -/* Relaxation Support. */ - -/* Progression of relocations from largest operand size to smallest - operand size. */ - -static int -next_smaller_reloc (int r) -{ - switch (r) - { - case R_RX_DIR32: return R_RX_DIR24S; - case R_RX_DIR24S: return R_RX_DIR16S; - case R_RX_DIR16S: return R_RX_DIR8S; - case R_RX_DIR8S: return R_RX_NONE; - - case R_RX_DIR16: return R_RX_DIR8; - case R_RX_DIR8: return R_RX_NONE; - - case R_RX_DIR16U: return R_RX_DIR8U; - case R_RX_DIR8U: return R_RX_NONE; - - case R_RX_DIR24S_PCREL: return R_RX_DIR16S_PCREL; - case R_RX_DIR16S_PCREL: return R_RX_DIR8S_PCREL; - case R_RX_DIR8S_PCREL: return R_RX_DIR3U_PCREL; - - case R_RX_DIR16UL: return R_RX_DIR8UL; - case R_RX_DIR8UL: return R_RX_NONE; - case R_RX_DIR16UW: return R_RX_DIR8UW; - case R_RX_DIR8UW: return R_RX_NONE; - - case R_RX_RH_32_OP: return R_RX_RH_24_OP; - case R_RX_RH_24_OP: return R_RX_RH_16_OP; - case R_RX_RH_16_OP: return R_RX_DIR8; - - case R_RX_ABS32: return R_RX_ABS24S; - case R_RX_ABS24S: return R_RX_ABS16S; - case R_RX_ABS16: return R_RX_ABS8; - case R_RX_ABS16U: return R_RX_ABS8U; - case R_RX_ABS16S: return R_RX_ABS8S; - case R_RX_ABS8: return R_RX_NONE; - case R_RX_ABS8U: return R_RX_NONE; - case R_RX_ABS8S: return R_RX_NONE; - case R_RX_ABS24S_PCREL: return R_RX_ABS16S_PCREL; - case R_RX_ABS16S_PCREL: return R_RX_ABS8S_PCREL; - case R_RX_ABS8S_PCREL: return R_RX_NONE; - case R_RX_ABS16UL: return R_RX_ABS8UL; - case R_RX_ABS16UW: return R_RX_ABS8UW; - case R_RX_ABS8UL: return R_RX_NONE; - case R_RX_ABS8UW: return R_RX_NONE; - } - return r; -}; - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -elf32_rx_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, int count, - Elf_Internal_Rela *alignment_rel, int force_snip, - Elf_Internal_Rela *irelstart) -{ - Elf_Internal_Shdr * symtab_hdr; - unsigned int sec_shndx; - bfd_byte * contents; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * irelend; - Elf_Internal_Sym * isym; - Elf_Internal_Sym * isymend; - bfd_vma toaddr; - unsigned int symcount; - struct elf_link_hash_entry ** sym_hashes; - struct elf_link_hash_entry ** end_hashes; - - if (!alignment_rel) - force_snip = 1; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - /* The deletion must stop at the next alignment boundary, if - ALIGNMENT_REL is non-NULL. */ - toaddr = sec->size; - if (alignment_rel) - toaddr = alignment_rel->r_offset; - - BFD_ASSERT (toaddr > addr); - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - - /* If we don't have an alignment marker to worry about, we can just - shrink the section. Otherwise, we have to fill in the newly - created gap with NOP insns (0x03). */ - if (force_snip) - sec->size -= count; - else - memset (contents + toaddr - count, 0x03, count); - - irel = irelstart; - BFD_ASSERT (irel != NULL || sec->reloc_count == 0); - irelend = irel + sec->reloc_count; - - /* Adjust all the relocs. */ - for (; irel < irelend; irel++) - { - /* Get the new reloc address. */ - if (irel->r_offset > addr - && (irel->r_offset < toaddr - || (force_snip && irel->r_offset == toaddr))) - irel->r_offset -= count; - - /* If we see an ALIGN marker at the end of the gap, we move it - to the beginning of the gap, since marking these gaps is what - they're for. */ - if (irel->r_offset == toaddr - && ELF32_R_TYPE (irel->r_info) == R_RX_RH_RELAX - && irel->r_addend & RX_RELAXA_ALIGN) - irel->r_offset -= count; - } - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - isymend = isym + symtab_hdr->sh_info; - - for (; isym < isymend; isym++) - { - /* If the symbol is in the range of memory we just moved, we - have to adjust its value. */ - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - isym->st_value -= count; - - /* If the symbol *spans* the bytes we just deleted (i.e. it's - *end* is in the moved bytes but it's *start* isn't), then we - must adjust its size. */ - if (isym->st_shndx == sec_shndx - && isym->st_value < addr - && isym->st_value + isym->st_size > addr - && isym->st_value + isym->st_size < toaddr) - isym->st_size -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - /* As above, adjust the value if needed. */ - if (sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; - - /* As above, adjust the size if needed. */ - if (sym_hash->root.u.def.value < addr - && sym_hash->root.u.def.value + sym_hash->size > addr - && sym_hash->root.u.def.value + sym_hash->size < toaddr) - sym_hash->size -= count; - } - } - - return TRUE; -} - -/* Used to sort relocs by address. If relocs have the same address, - we maintain their relative order, except that R_RX_RH_RELAX - alignment relocs must be the first reloc for any given address. */ - -static void -reloc_bubblesort (Elf_Internal_Rela * r, int count) -{ - int i; - bfd_boolean again; - bfd_boolean swappit; - - /* This is almost a classic bubblesort. It's the slowest sort, but - we're taking advantage of the fact that the relocations are - mostly in order already (the assembler emits them that way) and - we need relocs with the same address to remain in the same - relative order. */ - again = TRUE; - while (again) - { - again = FALSE; - for (i = 0; i < count - 1; i ++) - { - if (r[i].r_offset > r[i + 1].r_offset) - swappit = TRUE; - else if (r[i].r_offset < r[i + 1].r_offset) - swappit = FALSE; - else if (ELF32_R_TYPE (r[i + 1].r_info) == R_RX_RH_RELAX - && (r[i + 1].r_addend & RX_RELAXA_ALIGN)) - swappit = TRUE; - else if (ELF32_R_TYPE (r[i + 1].r_info) == R_RX_RH_RELAX - && (r[i + 1].r_addend & RX_RELAXA_ELIGN) - && !(ELF32_R_TYPE (r[i].r_info) == R_RX_RH_RELAX - && (r[i].r_addend & RX_RELAXA_ALIGN))) - swappit = TRUE; - else - swappit = FALSE; - - if (swappit) - { - Elf_Internal_Rela tmp; - - tmp = r[i]; - r[i] = r[i + 1]; - r[i + 1] = tmp; - /* If we do move a reloc back, re-scan to see if it - needs to be moved even further back. This avoids - most of the O(n^2) behavior for our cases. */ - if (i > 0) - i -= 2; - again = TRUE; - } - } - } -} - - -#define OFFSET_FOR_RELOC(rel, lrel, scale) \ - rx_offset_for_reloc (abfd, rel + 1, symtab_hdr, shndx_buf, intsyms, \ - lrel, abfd, sec, link_info, scale) - -static bfd_vma -rx_offset_for_reloc (bfd * abfd, - Elf_Internal_Rela * rel, - Elf_Internal_Shdr * symtab_hdr, - Elf_External_Sym_Shndx * shndx_buf ATTRIBUTE_UNUSED, - Elf_Internal_Sym * intsyms, - Elf_Internal_Rela ** lrel, - bfd * input_bfd, - asection * input_section, - struct bfd_link_info * info, - int * scale) -{ - bfd_vma symval; - bfd_reloc_status_type r; - - *scale = 1; - - /* REL is the first of 1..N relocations. We compute the symbol - value for each relocation, then combine them if needed. LREL - gets a pointer to the last relocation used. */ - while (1) - { - int32_t tmp1, tmp2; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (rel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *ssec; - - isym = intsyms + ELF32_R_SYM (rel->r_info); - - if (isym->st_shndx == SHN_UNDEF) - ssec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - ssec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - ssec = bfd_com_section_ptr; - else - ssec = bfd_section_from_elf_index (abfd, - isym->st_shndx); - - /* Initial symbol value. */ - symval = isym->st_value; - - /* GAS may have made this symbol relative to a section, in - which case, we have to add the addend to find the - symbol. */ - if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) - symval += rel->r_addend; - - if (ssec) - { - if ((ssec->flags & SEC_MERGE) - && ssec->sec_info_type == SEC_INFO_TYPE_MERGE) - symval = _bfd_merged_section_offset (abfd, & ssec, - elf_section_data (ssec)->sec_info, - symval); - } - - /* Now make the offset relative to where the linker is putting it. */ - if (ssec) - symval += - ssec->output_section->vma + ssec->output_offset; - - symval += rel->r_addend; - } - else - { - unsigned long indx; - struct elf_link_hash_entry * h; - - /* An external symbol. */ - indx = ELF32_R_SYM (rel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - if (lrel) - *lrel = rel; - return 0; - } - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - symval += rel->r_addend; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_RX_SYM: - RX_STACK_PUSH (symval); - break; - - case R_RX_OPneg: - RX_STACK_POP (tmp1); - tmp1 = - tmp1; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPadd: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 += tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPsub: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp2 -= tmp1; - RX_STACK_PUSH (tmp2); - break; - - case R_RX_OPmul: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 *= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPdiv: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 /= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPshla: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 <<= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPshra: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 >>= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPsctsize: - RX_STACK_PUSH (input_section->size); - break; - - case R_RX_OPscttop: - RX_STACK_PUSH (input_section->output_section->vma); - break; - - case R_RX_OPand: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 &= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPor: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 |= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPxor: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 ^= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPnot: - RX_STACK_POP (tmp1); - tmp1 = ~ tmp1; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPmod: - RX_STACK_POP (tmp1); - RX_STACK_POP (tmp2); - tmp1 %= tmp2; - RX_STACK_PUSH (tmp1); - break; - - case R_RX_OPromtop: - RX_STACK_PUSH (get_romstart (info, input_bfd, input_section, rel->r_offset)); - break; - - case R_RX_OPramtop: - RX_STACK_PUSH (get_ramstart (info, input_bfd, input_section, rel->r_offset)); - break; - - case R_RX_DIR16UL: - case R_RX_DIR8UL: - case R_RX_ABS16UL: - case R_RX_ABS8UL: - if (rx_stack_top) - RX_STACK_POP (symval); - if (lrel) - *lrel = rel; - *scale = 4; - return symval; - - case R_RX_DIR16UW: - case R_RX_DIR8UW: - case R_RX_ABS16UW: - case R_RX_ABS8UW: - if (rx_stack_top) - RX_STACK_POP (symval); - if (lrel) - *lrel = rel; - *scale = 2; - return symval; - - default: - if (rx_stack_top) - RX_STACK_POP (symval); - if (lrel) - *lrel = rel; - return symval; - } - - rel ++; - } - /* FIXME. */ - (void) r; -} - -static void -move_reloc (Elf_Internal_Rela * irel, Elf_Internal_Rela * srel, int delta) -{ - bfd_vma old_offset = srel->r_offset; - - irel ++; - while (irel <= srel) - { - if (irel->r_offset == old_offset) - irel->r_offset += delta; - irel ++; - } -} - -/* Relax one section. */ - -static bfd_boolean -elf32_rx_relax_section (bfd * abfd, - asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again, - bfd_boolean allow_pcrel3) -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Shdr * shndx_hdr; - Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * srel; - Elf_Internal_Rela * irelend; - Elf_Internal_Rela * next_alignment; - Elf_Internal_Rela * prev_alignment; - bfd_byte * contents = NULL; - bfd_byte * free_contents = NULL; - Elf_Internal_Sym * intsyms = NULL; - Elf_Internal_Sym * free_intsyms = NULL; - Elf_External_Sym_Shndx * shndx_buf = NULL; - bfd_vma pc; - bfd_vma sec_start; - bfd_vma symval = 0; - int pcrel = 0; - int code = 0; - int section_alignment_glue; - /* how much to scale the relocation by - 1, 2, or 4. */ - int scale; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = & elf_symtab_hdr (abfd); - if (elf_symtab_shndx_list (abfd)) - shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; - else - shndx_hdr = NULL; - - sec_start = sec->output_section->vma + sec->output_offset; - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - /* Go get them off disk. */ - else - { - if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - elf_section_data (sec)->this_hdr.contents = contents; - } - - /* Read this BFD's symbols. */ - /* Get cached copy if it exists. */ - if (symtab_hdr->contents != NULL) - intsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - else - { - intsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, symtab_hdr->sh_info, 0, NULL, NULL, NULL); - symtab_hdr->contents = (bfd_byte *) intsyms; - } - - if (shndx_hdr && shndx_hdr->sh_size != 0) - { - bfd_size_type amt; - - amt = symtab_hdr->sh_info; - amt *= sizeof (Elf_External_Sym_Shndx); - shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt); - if (shndx_buf == NULL) - goto error_return; - if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (shndx_buf, amt, abfd) != amt) - goto error_return; - shndx_hdr->contents = (bfd_byte *) shndx_buf; - } - - /* Get a copy of the native relocations. */ - /* Note - we ignore the setting of link_info->keep_memory when reading - in these relocs. We have to maintain a permanent copy of the relocs - because we are going to walk over them multiple times, adjusting them - as bytes are deleted from the section, and with this relaxation - function itself being called multiple times on the same section... */ - internal_relocs = _bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, TRUE); - if (internal_relocs == NULL) - goto error_return; - - /* The RL_ relocs must be just before the operand relocs they go - with, so we must sort them to guarantee this. We use bubblesort - instead of qsort so we can guarantee that relocs with the same - address remain in the same relative order. */ - reloc_bubblesort (internal_relocs, sec->reloc_count); - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - - /* This will either be NULL or a pointer to the next alignment - relocation. */ - next_alignment = internal_relocs; - /* This will be the previous alignment, although at first it points - to the first real relocation. */ - prev_alignment = internal_relocs; - - /* We calculate worst case shrinkage caused by alignment directives. - No fool-proof, but better than either ignoring the problem or - doing heavy duty analysis of all the alignment markers in all - input sections. */ - section_alignment_glue = 0; - for (irel = internal_relocs; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == R_RX_RH_RELAX - && irel->r_addend & RX_RELAXA_ALIGN) - { - int this_glue = 1 << (irel->r_addend & RX_RELAXA_ANUM); - - if (section_alignment_glue < this_glue) - section_alignment_glue = this_glue; - } - /* Worst case is all 0..N alignments, in order, causing 2*N-1 byte - shrinkage. */ - section_alignment_glue *= 2; - - for (irel = internal_relocs; irel < irelend; irel++) - { - unsigned char *insn; - int nrelocs; - - /* The insns we care about are all marked with one of these. */ - if (ELF32_R_TYPE (irel->r_info) != R_RX_RH_RELAX) - continue; - - if (irel->r_addend & RX_RELAXA_ALIGN - || next_alignment == internal_relocs) - { - /* When we delete bytes, we need to maintain all the alignments - indicated. In addition, we need to be careful about relaxing - jumps across alignment boundaries - these displacements - *grow* when we delete bytes. For now, don't shrink - displacements across an alignment boundary, just in case. - Note that this only affects relocations to the same - section. */ - prev_alignment = next_alignment; - next_alignment += 2; - while (next_alignment < irelend - && (ELF32_R_TYPE (next_alignment->r_info) != R_RX_RH_RELAX - || !(next_alignment->r_addend & RX_RELAXA_ELIGN))) - next_alignment ++; - if (next_alignment >= irelend || next_alignment->r_offset == 0) - next_alignment = NULL; - } - - /* When we hit alignment markers, see if we've shrunk enough - before them to reduce the gap without violating the alignment - requirements. */ - if (irel->r_addend & RX_RELAXA_ALIGN) - { - /* At this point, the next relocation *should* be the ELIGN - end marker. */ - Elf_Internal_Rela *erel = irel + 1; - unsigned int alignment, nbytes; - - if (ELF32_R_TYPE (erel->r_info) != R_RX_RH_RELAX) - continue; - if (!(erel->r_addend & RX_RELAXA_ELIGN)) - continue; - - alignment = 1 << (irel->r_addend & RX_RELAXA_ANUM); - - if (erel->r_offset - irel->r_offset < alignment) - continue; - - nbytes = erel->r_offset - irel->r_offset; - nbytes /= alignment; - nbytes *= alignment; - - elf32_rx_relax_delete_bytes (abfd, sec, erel->r_offset-nbytes, nbytes, next_alignment, - erel->r_offset == sec->size, internal_relocs); - *again = TRUE; - - continue; - } - - if (irel->r_addend & RX_RELAXA_ELIGN) - continue; - - insn = contents + irel->r_offset; - - nrelocs = irel->r_addend & RX_RELAXA_RNUM; - - /* At this point, we have an insn that is a candidate for linker - relaxation. There are NRELOCS relocs following that may be - relaxed, although each reloc may be made of more than one - reloc entry (such as gp-rel symbols). */ - - /* Get the value of the symbol referred to by the reloc. Just - in case this is the last reloc in the list, use the RL's - addend to choose between this reloc (no addend) or the next - (yes addend, which means at least one following reloc). */ - - /* srel points to the "current" reloction for this insn - - actually the last reloc for a given operand, which is the one - we need to update. We check the relaxations in the same - order that the relocations happen, so we'll just push it - along as we go. */ - srel = irel; - - pc = sec->output_section->vma + sec->output_offset - + srel->r_offset; - -#define GET_RELOC \ - symval = OFFSET_FOR_RELOC (srel, &srel, &scale); \ - pcrel = symval - pc + srel->r_addend; \ - nrelocs --; - -#define SNIPNR(offset, nbytes) \ - elf32_rx_relax_delete_bytes (abfd, sec, (insn - contents) + offset, nbytes, next_alignment, 0, internal_relocs); -#define SNIP(offset, nbytes, newtype) \ - SNIPNR (offset, nbytes); \ - srel->r_info = ELF32_R_INFO (ELF32_R_SYM (srel->r_info), newtype) - - /* The order of these bit tests must match the order that the - relocs appear in. Since we sorted those by offset, we can - predict them. */ - - /* Note that the numbers in, say, DSP6 are the bit offsets of - the code fields that describe the operand. Bits number 0 for - the MSB of insn[0]. */ - - /* DSP* codes: - 0 00 [reg] - 1 01 dsp:8[reg] - 2 10 dsp:16[reg] - 3 11 reg */ - if (irel->r_addend & RX_RELAXA_DSP6) - { - GET_RELOC; - - code = insn[0] & 3; - if (code == 2 && symval/scale <= 255) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - insn[0] &= 0xfc; - insn[0] |= 0x01; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (3, 1, newrel); - *again = TRUE; - } - } - - else if (code == 1 && symval == 0) - { - insn[0] &= 0xfc; - SNIP (2, 1, R_RX_NONE); - *again = TRUE; - } - - /* Special case DSP:5 format: MOV.bwl dsp:5[Rsrc],Rdst. */ - else if (code == 1 && symval/scale <= 31 - /* Decodable bits. */ - && (insn[0] & 0xcc) == 0xcc - /* Width. */ - && (insn[0] & 0x30) != 0x30 - /* Register MSBs. */ - && (insn[1] & 0x88) == 0x00) - { - int newrel = 0; - - insn[0] = 0x88 | (insn[0] & 0x30); - /* The register fields are in the right place already. */ - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - switch ((insn[0] & 0x30) >> 4) - { - case 0: - newrel = R_RX_RH_ABS5p5B; - break; - case 1: - newrel = R_RX_RH_ABS5p5W; - break; - case 2: - newrel = R_RX_RH_ABS5p5L; - break; - } - - move_reloc (irel, srel, -2); - SNIP (2, 1, newrel); - } - - /* Special case DSP:5 format: MOVU.bw dsp:5[Rsrc],Rdst. */ - else if (code == 1 && symval/scale <= 31 - /* Decodable bits. */ - && (insn[0] & 0xf8) == 0x58 - /* Register MSBs. */ - && (insn[1] & 0x88) == 0x00) - { - int newrel = 0; - - insn[0] = 0xb0 | ((insn[0] & 0x04) << 1); - /* The register fields are in the right place already. */ - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - switch ((insn[0] & 0x08) >> 3) - { - case 0: - newrel = R_RX_RH_ABS5p5B; - break; - case 1: - newrel = R_RX_RH_ABS5p5W; - break; - } - - move_reloc (irel, srel, -2); - SNIP (2, 1, newrel); - } - } - - /* A DSP4 operand always follows a DSP6 operand, even if there's - no relocation for it. We have to read the code out of the - opcode to calculate the offset of the operand. */ - if (irel->r_addend & RX_RELAXA_DSP4) - { - int code6, offset = 0; - - GET_RELOC; - - code6 = insn[0] & 0x03; - switch (code6) - { - case 0: offset = 2; break; - case 1: offset = 3; break; - case 2: offset = 4; break; - case 3: offset = 2; break; - } - - code = (insn[0] & 0x0c) >> 2; - - if (code == 2 && symval / scale <= 255) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[0] &= 0xf3; - insn[0] |= 0x04; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (offset+1, 1, newrel); - *again = TRUE; - } - } - - else if (code == 1 && symval == 0) - { - insn[0] &= 0xf3; - SNIP (offset, 1, R_RX_NONE); - *again = TRUE; - } - /* Special case DSP:5 format: MOV.bwl Rsrc,dsp:5[Rdst] */ - else if (code == 1 && symval/scale <= 31 - /* Decodable bits. */ - && (insn[0] & 0xc3) == 0xc3 - /* Width. */ - && (insn[0] & 0x30) != 0x30 - /* Register MSBs. */ - && (insn[1] & 0x88) == 0x00) - { - int newrel = 0; - - insn[0] = 0x80 | (insn[0] & 0x30); - /* The register fields are in the right place already. */ - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - switch ((insn[0] & 0x30) >> 4) - { - case 0: - newrel = R_RX_RH_ABS5p5B; - break; - case 1: - newrel = R_RX_RH_ABS5p5W; - break; - case 2: - newrel = R_RX_RH_ABS5p5L; - break; - } - - move_reloc (irel, srel, -2); - SNIP (2, 1, newrel); - } - } - - /* These always occur alone, but the offset depends on whether - it's a MEMEX opcode (0x06) or not. */ - if (irel->r_addend & RX_RELAXA_DSP14) - { - int offset; - GET_RELOC; - - if (insn[0] == 0x06) - offset = 3; - else - offset = 4; - - code = insn[1] & 3; - - if (code == 2 && symval / scale <= 255) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[1] &= 0xfc; - insn[1] |= 0x01; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (offset, 1, newrel); - *again = TRUE; - } - } - else if (code == 1 && symval == 0) - { - insn[1] &= 0xfc; - SNIP (offset, 1, R_RX_NONE); - *again = TRUE; - } - } - - /* IMM* codes: - 0 00 imm:32 - 1 01 simm:8 - 2 10 simm:16 - 3 11 simm:24. */ - - /* These always occur alone. */ - if (irel->r_addend & RX_RELAXA_IMM6) - { - long ssymval; - - GET_RELOC; - - /* These relocations sign-extend, so we must do signed compares. */ - ssymval = (long) symval; - - code = insn[0] & 0x03; - - if (code == 0 && ssymval <= 8388607 && ssymval >= -8388608) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[0] &= 0xfc; - insn[0] |= 0x03; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (2, 1, newrel); - *again = TRUE; - } - } - - else if (code == 3 && ssymval <= 32767 && ssymval >= -32768) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[0] &= 0xfc; - insn[0] |= 0x02; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (2, 1, newrel); - *again = TRUE; - } - } - - /* Special case UIMM8 format: CMP #uimm8,Rdst. */ - else if (code == 2 && ssymval <= 255 && ssymval >= 16 - /* Decodable bits. */ - && (insn[0] & 0xfc) == 0x74 - /* Decodable bits. */ - && ((insn[1] & 0xf0) == 0x00)) - { - int newrel; - - insn[0] = 0x75; - insn[1] = 0x50 | (insn[1] & 0x0f); - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - if (STACK_REL_P (ELF32_R_TYPE (srel->r_info))) - newrel = R_RX_ABS8U; - else - newrel = R_RX_DIR8U; - - SNIP (2, 1, newrel); - *again = TRUE; - } - - else if (code == 2 && ssymval <= 127 && ssymval >= -128) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[0] &= 0xfc; - insn[0] |= 0x01; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (2, 1, newrel); - *again = TRUE; - } - } - - /* Special case UIMM4 format: CMP, MUL, AND, OR. */ - else if (code == 1 && ssymval <= 15 && ssymval >= 0 - /* Decodable bits and immediate type. */ - && insn[0] == 0x75 - /* Decodable bits. */ - && (insn[1] & 0xc0) == 0x00) - { - static const int newop[4] = { 1, 3, 4, 5 }; - - insn[0] = 0x60 | newop[insn[1] >> 4]; - /* The register number doesn't move. */ - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - move_reloc (irel, srel, -1); - - SNIP (2, 1, R_RX_RH_UIMM4p8); - *again = TRUE; - } - - /* Special case UIMM4 format: ADD -> ADD/SUB. */ - else if (code == 1 && ssymval <= 15 && ssymval >= -15 - /* Decodable bits and immediate type. */ - && insn[0] == 0x71 - /* Same register for source and destination. */ - && ((insn[1] >> 4) == (insn[1] & 0x0f))) - { - int newrel; - - /* Note that we can't turn "add $0,Rs" into a NOP - because the flags need to be set right. */ - - if (ssymval < 0) - { - insn[0] = 0x60; /* Subtract. */ - newrel = R_RX_RH_UNEG4p8; - } - else - { - insn[0] = 0x62; /* Add. */ - newrel = R_RX_RH_UIMM4p8; - } - - /* The register number is in the right place. */ - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - move_reloc (irel, srel, -1); - - SNIP (2, 1, newrel); - *again = TRUE; - } - } - - /* These are either matched with a DSP6 (2-byte base) or an id24 - (3-byte base). */ - if (irel->r_addend & RX_RELAXA_IMM12) - { - int dspcode, offset = 0; - long ssymval; - - GET_RELOC; - - if ((insn[0] & 0xfc) == 0xfc) - dspcode = 1; /* Just something with one byte operand. */ - else - dspcode = insn[0] & 3; - switch (dspcode) - { - case 0: offset = 2; break; - case 1: offset = 3; break; - case 2: offset = 4; break; - case 3: offset = 2; break; - } - - /* These relocations sign-extend, so we must do signed compares. */ - ssymval = (long) symval; - - code = (insn[1] >> 2) & 3; - if (code == 0 && ssymval <= 8388607 && ssymval >= -8388608) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[1] &= 0xf3; - insn[1] |= 0x0c; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (offset, 1, newrel); - *again = TRUE; - } - } - - else if (code == 3 && ssymval <= 32767 && ssymval >= -32768) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - - insn[1] &= 0xf3; - insn[1] |= 0x08; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE (srel->r_info)) - { - SNIP (offset, 1, newrel); - *again = TRUE; - } - } - - /* Special case UIMM8 format: MOV #uimm8,Rdst. */ - else if (code == 2 && ssymval <= 255 && ssymval >= 16 - /* Decodable bits. */ - && insn[0] == 0xfb - /* Decodable bits. */ - && ((insn[1] & 0x03) == 0x02)) - { - int newrel; - - insn[0] = 0x75; - insn[1] = 0x40 | (insn[1] >> 4); - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - if (STACK_REL_P (ELF32_R_TYPE (srel->r_info))) - newrel = R_RX_ABS8U; - else - newrel = R_RX_DIR8U; - - SNIP (2, 1, newrel); - *again = TRUE; - } - - else if (code == 2 && ssymval <= 127 && ssymval >= -128) - { - unsigned int newrel = ELF32_R_TYPE(srel->r_info); - - insn[1] &= 0xf3; - insn[1] |= 0x04; - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - if (newrel != ELF32_R_TYPE(srel->r_info)) - { - SNIP (offset, 1, newrel); - *again = TRUE; - } - } - - /* Special case UIMM4 format: MOV #uimm4,Rdst. */ - else if (code == 1 && ssymval <= 15 && ssymval >= 0 - /* Decodable bits. */ - && insn[0] == 0xfb - /* Decodable bits. */ - && ((insn[1] & 0x03) == 0x02)) - { - insn[0] = 0x66; - insn[1] = insn[1] >> 4; - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - - move_reloc (irel, srel, -1); - - SNIP (2, 1, R_RX_RH_UIMM4p8); - *again = TRUE; - } - } - - if (irel->r_addend & RX_RELAXA_BRA) - { - unsigned int newrel = ELF32_R_TYPE (srel->r_info); - int max_pcrel3 = 4; - int alignment_glue = 0; - - GET_RELOC; - - /* Branches over alignment chunks are problematic, as - deleting bytes here makes the branch *further* away. We - can be agressive with branches within this alignment - block, but not branches outside it. */ - if ((prev_alignment == NULL - || symval < (bfd_vma)(sec_start + prev_alignment->r_offset)) - && (next_alignment == NULL - || symval > (bfd_vma)(sec_start + next_alignment->r_offset))) - alignment_glue = section_alignment_glue; - - if (ELF32_R_TYPE(srel[1].r_info) == R_RX_RH_RELAX - && srel[1].r_addend & RX_RELAXA_BRA - && srel[1].r_offset < irel->r_offset + pcrel) - max_pcrel3 ++; - - newrel = next_smaller_reloc (ELF32_R_TYPE (srel->r_info)); - - /* The values we compare PCREL with are not what you'd - expect; they're off by a little to compensate for (1) - where the reloc is relative to the insn, and (2) how much - the insn is going to change when we relax it. */ - - /* These we have to decode. */ - switch (insn[0]) - { - case 0x04: /* BRA pcdsp:24 */ - if (-32768 + alignment_glue <= pcrel - && pcrel <= 32765 - alignment_glue) - { - insn[0] = 0x38; - SNIP (3, 1, newrel); - *again = TRUE; - } - break; - - case 0x38: /* BRA pcdsp:16 */ - if (-128 + alignment_glue <= pcrel - && pcrel <= 127 - alignment_glue) - { - insn[0] = 0x2e; - SNIP (2, 1, newrel); - *again = TRUE; - } - break; - - case 0x2e: /* BRA pcdsp:8 */ - /* Note that there's a risk here of shortening things so - much that we no longer fit this reloc; it *should* - only happen when you branch across a branch, and that - branch also devolves into BRA.S. "Real" code should - be OK. */ - if (max_pcrel3 + alignment_glue <= pcrel - && pcrel <= 10 - alignment_glue - && allow_pcrel3) - { - insn[0] = 0x08; - SNIP (1, 1, newrel); - move_reloc (irel, srel, -1); - *again = TRUE; - } - break; - - case 0x05: /* BSR pcdsp:24 */ - if (-32768 + alignment_glue <= pcrel - && pcrel <= 32765 - alignment_glue) - { - insn[0] = 0x39; - SNIP (1, 1, newrel); - *again = TRUE; - } - break; - - case 0x3a: /* BEQ.W pcdsp:16 */ - case 0x3b: /* BNE.W pcdsp:16 */ - if (-128 + alignment_glue <= pcrel - && pcrel <= 127 - alignment_glue) - { - insn[0] = 0x20 | (insn[0] & 1); - SNIP (1, 1, newrel); - *again = TRUE; - } - break; - - case 0x20: /* BEQ.B pcdsp:8 */ - case 0x21: /* BNE.B pcdsp:8 */ - if (max_pcrel3 + alignment_glue <= pcrel - && pcrel - alignment_glue <= 10 - && allow_pcrel3) - { - insn[0] = 0x10 | ((insn[0] & 1) << 3); - SNIP (1, 1, newrel); - move_reloc (irel, srel, -1); - *again = TRUE; - } - break; - - case 0x16: /* synthetic BNE dsp24 */ - case 0x1e: /* synthetic BEQ dsp24 */ - if (-32767 + alignment_glue <= pcrel - && pcrel <= 32766 - alignment_glue - && insn[1] == 0x04) - { - if (insn[0] == 0x16) - insn[0] = 0x3b; - else - insn[0] = 0x3a; - /* We snip out the bytes at the end else the reloc - will get moved too, and too much. */ - SNIP (3, 2, newrel); - move_reloc (irel, srel, -1); - *again = TRUE; - } - break; - } - - /* Special case - synthetic conditional branches, pcrel24. - Note that EQ and NE have been handled above. */ - if ((insn[0] & 0xf0) == 0x20 - && insn[1] == 0x06 - && insn[2] == 0x04 - && srel->r_offset != irel->r_offset + 1 - && -32767 + alignment_glue <= pcrel - && pcrel <= 32766 - alignment_glue) - { - insn[1] = 0x05; - insn[2] = 0x38; - SNIP (5, 1, newrel); - *again = TRUE; - } - - /* Special case - synthetic conditional branches, pcrel16 */ - if ((insn[0] & 0xf0) == 0x20 - && insn[1] == 0x05 - && insn[2] == 0x38 - && srel->r_offset != irel->r_offset + 1 - && -127 + alignment_glue <= pcrel - && pcrel <= 126 - alignment_glue) - { - int cond = (insn[0] & 0x0f) ^ 0x01; - - insn[0] = 0x20 | cond; - /* By moving the reloc first, we avoid having - delete_bytes move it also. */ - move_reloc (irel, srel, -2); - SNIP (2, 3, newrel); - *again = TRUE; - } - } - - BFD_ASSERT (nrelocs == 0); - - /* Special case - check MOV.bwl #IMM, dsp[reg] and see if we can - use MOV.bwl #uimm:8, dsp:5[r7] format. This is tricky - because it may have one or two relocations. */ - if ((insn[0] & 0xfc) == 0xf8 - && (insn[1] & 0x80) == 0x00 - && (insn[0] & 0x03) != 0x03) - { - int dcode, icode, reg, ioff, dscale, ilen; - bfd_vma disp_val = 0; - long imm_val = 0; - Elf_Internal_Rela * disp_rel = 0; - Elf_Internal_Rela * imm_rel = 0; - - /* Reset this. */ - srel = irel; - - dcode = insn[0] & 0x03; - icode = (insn[1] >> 2) & 0x03; - reg = (insn[1] >> 4) & 0x0f; - - ioff = dcode == 1 ? 3 : dcode == 2 ? 4 : 2; - - /* Figure out what the dispacement is. */ - if (dcode == 1 || dcode == 2) - { - /* There's a displacement. See if there's a reloc for it. */ - if (srel[1].r_offset == irel->r_offset + 2) - { - GET_RELOC; - disp_val = symval; - disp_rel = srel; - } - else - { - if (dcode == 1) - disp_val = insn[2]; - else - { -#if RX_OPCODE_BIG_ENDIAN - disp_val = insn[2] * 256 + insn[3]; -#else - disp_val = insn[2] + insn[3] * 256; -#endif - } - switch (insn[1] & 3) - { - case 1: - disp_val *= 2; - scale = 2; - break; - case 2: - disp_val *= 4; - scale = 4; - break; - } - } - } - - dscale = scale; - - /* Figure out what the immediate is. */ - if (srel[1].r_offset == irel->r_offset + ioff) - { - GET_RELOC; - imm_val = (long) symval; - imm_rel = srel; - } - else - { - unsigned char * ip = insn + ioff; - - switch (icode) - { - case 1: - /* For byte writes, we don't sign extend. Makes the math easier later. */ - if (scale == 1) - imm_val = ip[0]; - else - imm_val = (char) ip[0]; - break; - case 2: -#if RX_OPCODE_BIG_ENDIAN - imm_val = ((char) ip[0] << 8) | ip[1]; -#else - imm_val = ((char) ip[1] << 8) | ip[0]; -#endif - break; - case 3: -#if RX_OPCODE_BIG_ENDIAN - imm_val = ((char) ip[0] << 16) | (ip[1] << 8) | ip[2]; -#else - imm_val = ((char) ip[2] << 16) | (ip[1] << 8) | ip[0]; -#endif - break; - case 0: -#if RX_OPCODE_BIG_ENDIAN - imm_val = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | ip[3]; -#else - imm_val = (ip[3] << 24) | (ip[2] << 16) | (ip[1] << 8) | ip[0]; -#endif - break; - } - } - - ilen = 2; - - switch (dcode) - { - case 1: - ilen += 1; - break; - case 2: - ilen += 2; - break; - } - - switch (icode) - { - case 1: - ilen += 1; - break; - case 2: - ilen += 2; - break; - case 3: - ilen += 3; - break; - case 4: - ilen += 4; - break; - } - - /* The shortcut happens when the immediate is 0..255, - register r0 to r7, and displacement (scaled) 0..31. */ - - if (0 <= imm_val && imm_val <= 255 - && 0 <= reg && reg <= 7 - && disp_val / dscale <= 31) - { - insn[0] = 0x3c | (insn[1] & 0x03); - insn[1] = (((disp_val / dscale) << 3) & 0x80) | (reg << 4) | ((disp_val/dscale) & 0x0f); - insn[2] = imm_val; - - if (disp_rel) - { - int newrel = R_RX_NONE; - - switch (dscale) - { - case 1: - newrel = R_RX_RH_ABS5p8B; - break; - case 2: - newrel = R_RX_RH_ABS5p8W; - break; - case 4: - newrel = R_RX_RH_ABS5p8L; - break; - } - disp_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (disp_rel->r_info), newrel); - move_reloc (irel, disp_rel, -1); - } - if (imm_rel) - { - imm_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (imm_rel->r_info), R_RX_DIR8U); - move_reloc (disp_rel ? disp_rel : irel, - imm_rel, - irel->r_offset - imm_rel->r_offset + 2); - } - - SNIPNR (3, ilen - 3); - *again = TRUE; - - /* We can't relax this new opcode. */ - irel->r_addend = 0; - } - } - } - - /* We can't reliably relax branches to DIR3U_PCREL unless we know - whatever they're branching over won't shrink any more. If we're - basically done here, do one more pass just for branches - but - don't request a pass after that one! */ - if (!*again && !allow_pcrel3) - { - bfd_boolean ignored; - - elf32_rx_relax_section (abfd, sec, link_info, &ignored, TRUE); - } - - return TRUE; - - error_return: - if (free_contents != NULL) - free (free_contents); - - if (shndx_buf != NULL) - { - shndx_hdr->contents = NULL; - free (shndx_buf); - } - - if (free_intsyms != NULL) - free (free_intsyms); - - return FALSE; -} - -static bfd_boolean -elf32_rx_relax_section_wrapper (bfd * abfd, - asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - return elf32_rx_relax_section (abfd, sec, link_info, again, FALSE); -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -rx_elf_set_private_flags (bfd * abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -static bfd_boolean no_warn_mismatch = FALSE; -static bfd_boolean ignore_lma = TRUE; - -void bfd_elf32_rx_set_target_flags (bfd_boolean, bfd_boolean); - -void -bfd_elf32_rx_set_target_flags (bfd_boolean user_no_warn_mismatch, - bfd_boolean user_ignore_lma) -{ - no_warn_mismatch = user_no_warn_mismatch; - ignore_lma = user_ignore_lma; -} - -/* Converts FLAGS into a descriptive string. - Returns a static pointer. */ - -static const char * -describe_flags (flagword flags) -{ - static char buf [128]; - - buf[0] = 0; - - if (flags & E_FLAG_RX_64BIT_DOUBLES) - strcat (buf, "64-bit doubles"); - else - strcat (buf, "32-bit doubles"); - - if (flags & E_FLAG_RX_DSP) - strcat (buf, ", dsp"); - else - strcat (buf, ", no dsp"); - - if (flags & E_FLAG_RX_PID) - strcat (buf, ", pid"); - else - strcat (buf, ", no pid"); - - if (flags & E_FLAG_RX_ABI) - strcat (buf, ", RX ABI"); - else - strcat (buf, ", GCC ABI"); - - if (flags & E_FLAG_RX_SINSNS_SET) - strcat (buf, flags & E_FLAG_RX_SINSNS_YES ? ", uses String instructions" : ", bans String instructions"); - - return buf; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -rx_elf_merge_private_bfd_data (bfd * ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - bfd_boolean error = FALSE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - else if (old_flags != new_flags) - { - flagword known_flags; - - if (old_flags & E_FLAG_RX_SINSNS_SET) - { - if ((new_flags & E_FLAG_RX_SINSNS_SET) == 0) - { - new_flags &= ~ E_FLAG_RX_SINSNS_MASK; - new_flags |= (old_flags & E_FLAG_RX_SINSNS_MASK); - } - } - else if (new_flags & E_FLAG_RX_SINSNS_SET) - { - old_flags &= ~ E_FLAG_RX_SINSNS_MASK; - old_flags |= (new_flags & E_FLAG_RX_SINSNS_MASK); - } - - known_flags = E_FLAG_RX_ABI | E_FLAG_RX_64BIT_DOUBLES - | E_FLAG_RX_DSP | E_FLAG_RX_PID | E_FLAG_RX_SINSNS_MASK; - - if ((old_flags ^ new_flags) & known_flags) - { - /* Only complain if flag bits we care about do not match. - Other bits may be set, since older binaries did use some - deprecated flags. */ - if (no_warn_mismatch) - { - elf_elfheader (obfd)->e_flags = (new_flags | old_flags) & known_flags; - } - else - { - _bfd_error_handler (_("There is a conflict merging the" - " ELF header flags from %B"), - ibfd); - _bfd_error_handler (_(" the input file's flags: %s"), - describe_flags (new_flags)); - _bfd_error_handler (_(" the output file's flags: %s"), - describe_flags (old_flags)); - error = TRUE; - } - } - else - elf_elfheader (obfd)->e_flags = new_flags & known_flags; - } - - if (error) - bfd_set_error (bfd_error_bad_value); - - return !error; -} - -static bfd_boolean -rx_elf_print_private_bfd_data (bfd * abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (long) flags); - - fprintf (file, "%s", describe_flags (flags)); - return TRUE; -} - -/* Return the MACH for an e_flags value. */ - -static int -elf32_rx_machine (bfd * abfd ATTRIBUTE_UNUSED) -{ -#if 0 /* FIXME: EF_RX_CPU_MASK collides with E_FLAG_RX_... - Need to sort out how these flag bits are used. - For now we assume that the flags are OK. */ - if ((elf_elfheader (abfd)->e_flags & EF_RX_CPU_MASK) == EF_RX_CPU_RX) -#endif - return bfd_mach_rx; - - return 0; -} - -static bfd_boolean -rx_elf_object_p (bfd * abfd) -{ - int i; - unsigned int u; - Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; - Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd); - int nphdrs = ehdr->e_phnum; - sec_ptr bsec; - static int saw_be = FALSE; - bfd_vma end_phdroff; - - /* We never want to automatically choose the non-swapping big-endian - target. The user can only get that explicitly, such as with -I - and objcopy. */ - if (abfd->xvec == &rx_elf32_be_ns_vec - && abfd->target_defaulted) - return FALSE; - - /* BFD->target_defaulted is not set to TRUE when a target is chosen - as a fallback, so we check for "scanning" to know when to stop - using the non-swapping target. */ - if (abfd->xvec == &rx_elf32_be_ns_vec - && saw_be) - return FALSE; - if (abfd->xvec == &rx_elf32_be_vec) - saw_be = TRUE; - - bfd_default_set_arch_mach (abfd, bfd_arch_rx, - elf32_rx_machine (abfd)); - - /* For each PHDR in the object, we must find some section that - corresponds (based on matching file offsets) and use its VMA - information to reconstruct the p_vaddr field we clobbered when we - wrote it out. */ - /* If PT_LOAD headers include the ELF file header or program headers - then the PT_LOAD header does not start with some section contents. - Making adjustments based on the difference between sh_offset and - p_offset is nonsense in such cases. Exclude them. Note that - since standard linker scripts for RX do not use SIZEOF_HEADERS, - the linker won't normally create PT_LOAD segments covering the - headers so this is mainly for passing the ld testsuite. - FIXME. Why are we looking at non-PT_LOAD headers here? */ - end_phdroff = ehdr->e_ehsize; - if (ehdr->e_phoff != 0) - end_phdroff = ehdr->e_phoff + nphdrs * ehdr->e_phentsize; - for (i=0; inum_elf_sections; u++) - { - Elf_Internal_Shdr *sec = elf_tdata(abfd)->elf_sect_ptr[u]; - - if (phdr[i].p_filesz - && phdr[i].p_offset >= end_phdroff - && phdr[i].p_offset <= (bfd_vma) sec->sh_offset - && sec->sh_size > 0 - && sec->sh_type != SHT_NOBITS - && (bfd_vma)sec->sh_offset <= phdr[i].p_offset + (phdr[i].p_filesz - 1)) - { - /* Found one! The difference between the two addresses, - plus the difference between the two file offsets, is - enough information to reconstruct the lma. */ - - /* Example where they aren't: - PHDR[1] = lma fffc0100 offset 00002010 size 00000100 - SEC[6] = vma 00000050 offset 00002050 size 00000040 - - The correct LMA for the section is fffc0140 + (2050-2010). - */ - - phdr[i].p_vaddr = sec->sh_addr + (sec->sh_offset - phdr[i].p_offset); - break; - } - } - - /* We must update the bfd sections as well, so we don't stop - with one match. */ - bsec = abfd->sections; - while (bsec) - { - if (phdr[i].p_filesz - && phdr[i].p_vaddr <= bsec->vma - && bsec->vma <= phdr[i].p_vaddr + (phdr[i].p_filesz - 1)) - { - bsec->lma = phdr[i].p_paddr + (bsec->vma - phdr[i].p_vaddr); - } - bsec = bsec->next; - } - } - - return TRUE; -} - - -#ifdef DEBUG -void -rx_dump_symtab (bfd * abfd, void * internal_syms, void * external_syms) -{ - size_t locsymcount; - Elf_Internal_Sym * isymbuf; - Elf_Internal_Sym * isymend; - Elf_Internal_Sym * isym; - Elf_Internal_Shdr * symtab_hdr; - bfd_boolean free_internal = FALSE, free_external = FALSE; - char * st_info_str; - char * st_info_stb_str; - char * st_other_str; - char * st_shndx_str; - - if (! internal_syms) - { - internal_syms = bfd_malloc (1000); - free_internal = 1; - } - if (! external_syms) - { - external_syms = bfd_malloc (1000); - free_external = 1; - } - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; - if (free_internal) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - internal_syms, external_syms, NULL); - else - isymbuf = internal_syms; - isymend = isymbuf + locsymcount; - - for (isym = isymbuf ; isym < isymend ; isym++) - { - switch (ELF_ST_TYPE (isym->st_info)) - { - case STT_FUNC: st_info_str = "STT_FUNC"; break; - case STT_SECTION: st_info_str = "STT_SECTION"; break; - case STT_FILE: st_info_str = "STT_FILE"; break; - case STT_OBJECT: st_info_str = "STT_OBJECT"; break; - case STT_TLS: st_info_str = "STT_TLS"; break; - default: st_info_str = ""; - } - switch (ELF_ST_BIND (isym->st_info)) - { - case STB_LOCAL: st_info_stb_str = "STB_LOCAL"; break; - case STB_GLOBAL: st_info_stb_str = "STB_GLOBAL"; break; - default: st_info_stb_str = ""; - } - switch (ELF_ST_VISIBILITY (isym->st_other)) - { - case STV_DEFAULT: st_other_str = "STV_DEFAULT"; break; - case STV_INTERNAL: st_other_str = "STV_INTERNAL"; break; - case STV_PROTECTED: st_other_str = "STV_PROTECTED"; break; - default: st_other_str = ""; - } - switch (isym->st_shndx) - { - case SHN_ABS: st_shndx_str = "SHN_ABS"; break; - case SHN_COMMON: st_shndx_str = "SHN_COMMON"; break; - case SHN_UNDEF: st_shndx_str = "SHN_UNDEF"; break; - default: st_shndx_str = ""; - } - - printf ("isym = %p st_value = %lx st_size = %lx st_name = (%lu) %s " - "st_info = (%d) %s %s st_other = (%d) %s st_shndx = (%d) %s\n", - isym, - (unsigned long) isym->st_value, - (unsigned long) isym->st_size, - isym->st_name, - bfd_elf_string_from_elf_section (abfd, symtab_hdr->sh_link, - isym->st_name), - isym->st_info, st_info_str, st_info_stb_str, - isym->st_other, st_other_str, - isym->st_shndx, st_shndx_str); - } - if (free_internal) - free (internal_syms); - if (free_external) - free (external_syms); -} - -char * -rx_get_reloc (long reloc) -{ - if (0 <= reloc && reloc < R_RX_max) - return rx_elf_howto_table[reloc].name; - return ""; -} -#endif /* DEBUG */ - - -/* We must take care to keep the on-disk copy of any code sections - that are fully linked swapped if the target is big endian, to match - the Renesas tools. */ - -/* The rule is: big endian object that are final-link executables, - have code sections stored with 32-bit words swapped relative to - what you'd get by default. */ - -static bfd_boolean -rx_get_section_contents (bfd * abfd, - sec_ptr section, - void * location, - file_ptr offset, - bfd_size_type count) -{ - int exec = (abfd->flags & EXEC_P) ? 1 : 0; - int s_code = (section->flags & SEC_CODE) ? 1 : 0; - bfd_boolean rv; - -#ifdef DJDEBUG - fprintf (stderr, "dj: get %ld %ld from %s %s e%d sc%d %08lx:%08lx\n", - (long) offset, (long) count, section->name, - bfd_big_endian(abfd) ? "be" : "le", - exec, s_code, (long unsigned) section->filepos, - (long unsigned) offset); -#endif - - if (exec && s_code && bfd_big_endian (abfd)) - { - char * cloc = (char *) location; - bfd_size_type cnt, end_cnt; - - rv = TRUE; - - /* Fetch and swap unaligned bytes at the beginning. */ - if (offset % 4) - { - char buf[4]; - - rv = _bfd_generic_get_section_contents (abfd, section, buf, - (offset & -4), 4); - if (!rv) - return FALSE; - - bfd_putb32 (bfd_getl32 (buf), buf); - - cnt = 4 - (offset % 4); - if (cnt > count) - cnt = count; - - memcpy (location, buf + (offset % 4), cnt); - - count -= cnt; - offset += cnt; - cloc += count; - } - - end_cnt = count % 4; - - /* Fetch and swap the middle bytes. */ - if (count >= 4) - { - rv = _bfd_generic_get_section_contents (abfd, section, cloc, offset, - count - end_cnt); - if (!rv) - return FALSE; - - for (cnt = count; cnt >= 4; cnt -= 4, cloc += 4) - bfd_putb32 (bfd_getl32 (cloc), cloc); - } - - /* Fetch and swap the end bytes. */ - if (end_cnt > 0) - { - char buf[4]; - - /* Fetch the end bytes. */ - rv = _bfd_generic_get_section_contents (abfd, section, buf, - offset + count - end_cnt, 4); - if (!rv) - return FALSE; - - bfd_putb32 (bfd_getl32 (buf), buf); - memcpy (cloc, buf, end_cnt); - } - } - else - rv = _bfd_generic_get_section_contents (abfd, section, location, offset, count); - - return rv; -} - -#ifdef DJDEBUG -static bfd_boolean -rx2_set_section_contents (bfd * abfd, - sec_ptr section, - const void * location, - file_ptr offset, - bfd_size_type count) -{ - bfd_size_type i; - - fprintf (stderr, " set sec %s %08x loc %p offset %#x count %#x\n", - section->name, (unsigned) section->vma, location, (int) offset, (int) count); - for (i = 0; i < count; i++) - { - if (i % 16 == 0 && i > 0) - fprintf (stderr, "\n"); - - if (i % 16 && i % 4 == 0) - fprintf (stderr, " "); - - if (i % 16 == 0) - fprintf (stderr, " %08x:", (int) (section->vma + offset + i)); - - fprintf (stderr, " %02x", ((unsigned char *) location)[i]); - } - fprintf (stderr, "\n"); - - return _bfd_elf_set_section_contents (abfd, section, location, offset, count); -} -#define _bfd_elf_set_section_contents rx2_set_section_contents -#endif - -static bfd_boolean -rx_set_section_contents (bfd * abfd, - sec_ptr section, - const void * location, - file_ptr offset, - bfd_size_type count) -{ - bfd_boolean exec = (abfd->flags & EXEC_P) ? TRUE : FALSE; - bfd_boolean s_code = (section->flags & SEC_CODE) ? TRUE : FALSE; - bfd_boolean rv; - char * swapped_data = NULL; - bfd_size_type i; - bfd_vma caddr = section->vma + offset; - file_ptr faddr = 0; - bfd_size_type scount; - -#ifdef DJDEBUG - bfd_size_type i; - - fprintf (stderr, "\ndj: set %ld %ld to %s %s e%d sc%d\n", - (long) offset, (long) count, section->name, - bfd_big_endian (abfd) ? "be" : "le", - exec, s_code); - - for (i = 0; i < count; i++) - { - int a = section->vma + offset + i; - - if (a % 16 == 0 && a > 0) - fprintf (stderr, "\n"); - - if (a % 16 && a % 4 == 0) - fprintf (stderr, " "); - - if (a % 16 == 0 || i == 0) - fprintf (stderr, " %08x:", (int) (section->vma + offset + i)); - - fprintf (stderr, " %02x", ((unsigned char *) location)[i]); - } - - fprintf (stderr, "\n"); -#endif - - if (! exec || ! s_code || ! bfd_big_endian (abfd)) - return _bfd_elf_set_section_contents (abfd, section, location, offset, count); - - while (count > 0 && caddr > 0 && caddr % 4) - { - switch (caddr % 4) - { - case 0: faddr = offset + 3; break; - case 1: faddr = offset + 1; break; - case 2: faddr = offset - 1; break; - case 3: faddr = offset - 3; break; - } - - rv = _bfd_elf_set_section_contents (abfd, section, location, faddr, 1); - if (! rv) - return rv; - - location = (bfd_byte *) location + 1; - offset ++; - count --; - caddr ++; - } - - scount = (int)(count / 4) * 4; - if (scount > 0) - { - char * cloc = (char *) location; - - swapped_data = (char *) bfd_alloc (abfd, count); - - for (i = 0; i < count; i += 4) - { - bfd_vma v = bfd_getl32 (cloc + i); - bfd_putb32 (v, swapped_data + i); - } - - rv = _bfd_elf_set_section_contents (abfd, section, swapped_data, offset, scount); - - if (!rv) - return rv; - } - - count -= scount; - location = (bfd_byte *) location + scount; - offset += scount; - - if (count > 0) - { - caddr = section->vma + offset; - while (count > 0) - { - switch (caddr % 4) - { - case 0: faddr = offset + 3; break; - case 1: faddr = offset + 1; break; - case 2: faddr = offset - 1; break; - case 3: faddr = offset - 3; break; - } - rv = _bfd_elf_set_section_contents (abfd, section, location, faddr, 1); - if (! rv) - return rv; - - location = (bfd_byte *) location + 1; - offset ++; - count --; - caddr ++; - } - } - - return TRUE; -} - -static bfd_boolean -rx_final_link (bfd * abfd, struct bfd_link_info * info) -{ - asection * o; - - for (o = abfd->sections; o != NULL; o = o->next) - { -#ifdef DJDEBUG - fprintf (stderr, "sec %s fl %x vma %lx lma %lx size %lx raw %lx\n", - o->name, o->flags, o->vma, o->lma, o->size, o->rawsize); -#endif - if (o->flags & SEC_CODE - && bfd_big_endian (abfd) - && o->size % 4) - { -#ifdef DJDEBUG - fprintf (stderr, "adjusting...\n"); -#endif - o->size += 4 - (o->size % 4); - } - } - - return bfd_elf_final_link (abfd, info); -} - -static bfd_boolean -elf32_rx_modify_program_headers (bfd * abfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info ATTRIBUTE_UNUSED) -{ - const struct elf_backend_data * bed; - struct elf_obj_tdata * tdata; - Elf_Internal_Phdr * phdr; - unsigned int count; - unsigned int i; - - bed = get_elf_backend_data (abfd); - tdata = elf_tdata (abfd); - phdr = tdata->phdr; - count = elf_program_header_size (abfd) / bed->s->sizeof_phdr; - - if (ignore_lma) - for (i = count; i-- != 0;) - if (phdr[i].p_type == PT_LOAD) - { - /* The Renesas tools expect p_paddr to be zero. However, - there is no other way to store the writable data in ROM for - startup initialization. So, we let the linker *think* - we're using paddr and vaddr the "usual" way, but at the - last minute we move the paddr into the vaddr (which is what - the simulator uses) and zero out paddr. Note that this - does not affect the section headers, just the program - headers. We hope. */ - phdr[i].p_vaddr = phdr[i].p_paddr; -#if 0 /* If we zero out p_paddr, then the LMA in the section table - becomes wrong. */ - phdr[i].p_paddr = 0; -#endif - } - - return TRUE; -} - -/* The default literal sections should always be marked as "code" (i.e., - SHF_EXECINSTR). This is particularly important for big-endian mode - when we do not want their contents byte reversed. */ -static const struct bfd_elf_special_section elf32_rx_special_sections[] = -{ - { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_EXECINSTR }, - { NULL, 0, 0, 0, 0 } -}; - -typedef struct { - bfd *abfd; - struct bfd_link_info *info; - bfd_vma table_start; - int table_size; - bfd_vma *table_handlers; - bfd_vma table_default_handler; - struct bfd_link_hash_entry **table_entries; - struct bfd_link_hash_entry *table_default_entry; - FILE *mapfile; -} RX_Table_Info; - -static bfd_boolean -rx_table_find (struct bfd_hash_entry *vent, void *vinfo) -{ - RX_Table_Info *info = (RX_Table_Info *)vinfo; - struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent; - const char *name; /* of the symbol we've found */ - asection *sec; - struct bfd *abfd; - int idx; - const char *tname; /* name of the table */ - bfd_vma start_addr, end_addr; - char *buf; - struct bfd_link_hash_entry * h; - - /* We're looking for globally defined symbols of the form - $tablestart$. */ - if (ent->type != bfd_link_hash_defined - && ent->type != bfd_link_hash_defweak) - return TRUE; - - name = ent->root.string; - sec = ent->u.def.section; - abfd = sec->owner; - - if (strncmp (name, "$tablestart$", 12)) - return TRUE; - - sec->flags |= SEC_KEEP; - - tname = name + 12; - - start_addr = ent->u.def.value; - - /* At this point, we can't build the table but we can (and must) - find all the related symbols and mark their sections as SEC_KEEP - so we don't garbage collect them. */ - - buf = (char *) malloc (12 + 10 + strlen (tname)); - - sprintf (buf, "$tableend$%s", tname); - h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE); - if (!h || (h->type != bfd_link_hash_defined - && h->type != bfd_link_hash_defweak)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B:%A: table %s missing corresponding %s"), - abfd, sec, name, buf); - return TRUE; - } - - if (h->u.def.section != ent->u.def.section) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B:%A: %s and %s must be in the same input section"), - h->u.def.section->owner, h->u.def.section, - name, buf); - return TRUE; - } - - end_addr = h->u.def.value; - - sprintf (buf, "$tableentry$default$%s", tname); - h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE); - if (h && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - { - h->u.def.section->flags |= SEC_KEEP; - } - - for (idx = 0; idx < (int) (end_addr - start_addr) / 4; idx ++) - { - sprintf (buf, "$tableentry$%d$%s", idx, tname); - h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE); - if (h && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - { - h->u.def.section->flags |= SEC_KEEP; - } - } - - /* Return TRUE to keep scanning, FALSE to end the traversal. */ - return TRUE; -} - -/* We need to check for table entry symbols and build the tables, and - we need to do it before the linker does garbage collection. This function is - called once per input object file. */ -static bfd_boolean -rx_check_directives - (bfd * abfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info ATTRIBUTE_UNUSED) -{ - RX_Table_Info stuff; - - stuff.abfd = abfd; - stuff.info = info; - bfd_hash_traverse (&(info->hash->table), rx_table_find, &stuff); - - return TRUE; -} - - -static bfd_boolean -rx_table_map_2 (struct bfd_hash_entry *vent, void *vinfo) -{ - RX_Table_Info *info = (RX_Table_Info *)vinfo; - struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent; - int idx; - const char *name; - bfd_vma addr; - - /* See if the symbol ENT has an address listed in the table, and - isn't a debug/special symbol. If so, put it in the table. */ - - if (ent->type != bfd_link_hash_defined - && ent->type != bfd_link_hash_defweak) - return TRUE; - - name = ent->root.string; - - if (name[0] == '$' || name[0] == '.' || name[0] < ' ') - return TRUE; - - addr = (ent->u.def.value - + ent->u.def.section->output_section->vma - + ent->u.def.section->output_offset); - - for (idx = 0; idx < info->table_size; idx ++) - if (addr == info->table_handlers[idx]) - info->table_entries[idx] = ent; - - if (addr == info->table_default_handler) - info->table_default_entry = ent; - - return TRUE; -} - -static bfd_boolean -rx_table_map (struct bfd_hash_entry *vent, void *vinfo) -{ - RX_Table_Info *info = (RX_Table_Info *)vinfo; - struct bfd_link_hash_entry *ent = (struct bfd_link_hash_entry *)vent; - const char *name; /* of the symbol we've found */ - int idx; - const char *tname; /* name of the table */ - bfd_vma start_addr, end_addr; - char *buf; - struct bfd_link_hash_entry * h; - int need_elipses; - - /* We're looking for globally defined symbols of the form - $tablestart$. */ - if (ent->type != bfd_link_hash_defined - && ent->type != bfd_link_hash_defweak) - return TRUE; - - name = ent->root.string; - - if (strncmp (name, "$tablestart$", 12)) - return TRUE; - - tname = name + 12; - start_addr = (ent->u.def.value - + ent->u.def.section->output_section->vma - + ent->u.def.section->output_offset); - - buf = (char *) malloc (12 + 10 + strlen (tname)); - - sprintf (buf, "$tableend$%s", tname); - end_addr = get_symbol_value_maybe (buf, info->info); - - sprintf (buf, "$tableentry$default$%s", tname); - h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE); - if (h) - { - info->table_default_handler = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - } - else - /* Zero is a valid handler address! */ - info->table_default_handler = (bfd_vma) (-1); - info->table_default_entry = NULL; - - info->table_start = start_addr; - info->table_size = (int) (end_addr - start_addr) / 4; - info->table_handlers = (bfd_vma *) malloc (info->table_size * sizeof (bfd_vma)); - info->table_entries = (struct bfd_link_hash_entry **) malloc (info->table_size * sizeof (struct bfd_link_hash_entry)); - - for (idx = 0; idx < (int) (end_addr - start_addr) / 4; idx ++) - { - sprintf (buf, "$tableentry$%d$%s", idx, tname); - h = bfd_link_hash_lookup (info->info->hash, buf, FALSE, FALSE, TRUE); - if (h && (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak)) - { - info->table_handlers[idx] = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - } - else - info->table_handlers[idx] = info->table_default_handler; - info->table_entries[idx] = NULL; - } - - free (buf); - - bfd_hash_traverse (&(info->info->hash->table), rx_table_map_2, info); - - fprintf (info->mapfile, "\nRX Vector Table: %s has %d entries at 0x%08" BFD_VMA_FMT "x\n\n", - tname, info->table_size, start_addr); - - if (info->table_default_entry) - fprintf (info->mapfile, " default handler is: %s at 0x%08" BFD_VMA_FMT "x\n", - info->table_default_entry->root.string, - info->table_default_handler); - else if (info->table_default_handler != (bfd_vma)(-1)) - fprintf (info->mapfile, " default handler is at 0x%08" BFD_VMA_FMT "x\n", - info->table_default_handler); - else - fprintf (info->mapfile, " no default handler\n"); - - need_elipses = 1; - for (idx = 0; idx < info->table_size; idx ++) - { - if (info->table_handlers[idx] == info->table_default_handler) - { - if (need_elipses) - fprintf (info->mapfile, " . . .\n"); - need_elipses = 0; - continue; - } - need_elipses = 1; - - fprintf (info->mapfile, " 0x%08" BFD_VMA_FMT "x [%3d] ", start_addr + 4 * idx, idx); - - if (info->table_handlers[idx] == (bfd_vma) (-1)) - fprintf (info->mapfile, "(no handler found)\n"); - - else if (info->table_handlers[idx] == info->table_default_handler) - { - if (info->table_default_entry) - fprintf (info->mapfile, "(default)\n"); - else - fprintf (info->mapfile, "(default)\n"); - } - - else if (info->table_entries[idx]) - { - fprintf (info->mapfile, "0x%08" BFD_VMA_FMT "x %s\n", info->table_handlers[idx], info->table_entries[idx]->root.string); - } - - else - { - fprintf (info->mapfile, "0x%08" BFD_VMA_FMT "x ???\n", info->table_handlers[idx]); - } - } - if (need_elipses) - fprintf (info->mapfile, " . . .\n"); - - return TRUE; -} - -void -rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfile) -{ - /* We scan the symbol table looking for $tableentry$'s, and for - each, try to deduce which handlers go with which entries. */ - - RX_Table_Info stuff; - - stuff.abfd = obfd; - stuff.info = info; - stuff.mapfile = mapfile; - bfd_hash_traverse (&(info->hash->table), rx_table_map, &stuff); -} - - -#define ELF_ARCH bfd_arch_rx -#define ELF_MACHINE_CODE EM_RX -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM rx_elf32_be_vec -#define TARGET_BIG_NAME "elf32-rx-be" - -#define TARGET_LITTLE_SYM rx_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-rx-le" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto rx_info_to_howto_rela -#define elf_backend_object_p rx_elf_object_p -#define elf_backend_relocate_section rx_elf_relocate_section -#define elf_symbol_leading_char ('_') -#define elf_backend_can_gc_sections 1 -#define elf_backend_modify_program_headers elf32_rx_modify_program_headers - -#define bfd_elf32_bfd_reloc_type_lookup rx_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup rx_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags rx_elf_set_private_flags -#define bfd_elf32_bfd_merge_private_bfd_data rx_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data rx_elf_print_private_bfd_data -#define bfd_elf32_get_section_contents rx_get_section_contents -#define bfd_elf32_set_section_contents rx_set_section_contents -#define bfd_elf32_bfd_final_link rx_final_link -#define bfd_elf32_bfd_relax_section elf32_rx_relax_section_wrapper -#define elf_backend_special_sections elf32_rx_special_sections -#define elf_backend_check_directives rx_check_directives - -#include "elf32-target.h" - -/* We define a second big-endian target that doesn't have the custom - section get/set hooks, for times when we want to preserve the - pre-swapped .text sections (like objcopy). */ - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM rx_elf32_be_ns_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-rx-be-ns" -#undef TARGET_LITTLE_SYM - -#undef bfd_elf32_get_section_contents -#undef bfd_elf32_set_section_contents - -#undef elf32_bed -#define elf32_bed elf32_rx_be_ns_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-rx.h b/sdcc/support/sdbinutils/bfd/elf32-rx.h deleted file mode 100644 index 38568eb26..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-rx.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Renesas RX specific support for 32-bit ELF. - Copyright (C) 2014-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -extern void rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfile); diff --git a/sdcc/support/sdbinutils/bfd/elf32-s390.c b/sdcc/support/sdbinutils/bfd/elf32-s390.c deleted file mode 100644 index c5e75814d..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-s390.c +++ /dev/null @@ -1,4055 +0,0 @@ -/* IBM S/390-specific support for 32-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed by Carl B. Pedersen and Martin Schwidefsky. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/s390.h" -#include - -static bfd_reloc_status_type -s390_tls_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_reloc_status_type -s390_elf_ldisp_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -/* The relocation "howto" table. */ - -static reloc_howto_type elf_howto_table[] = -{ - HOWTO (R_390_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = 2 byte, 2 = 4 byte) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_390_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO(R_390_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_8", FALSE, 0,0x000000ff, FALSE), - HOWTO(R_390_12, 0, 1, 12, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_390_12", FALSE, 0,0x00000fff, FALSE), - HOWTO(R_390_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_PC32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC32", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_GOT12, 0, 1, 12, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT12", FALSE, 0,0x00000fff, FALSE), - HOWTO(R_390_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_PLT32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT32", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_COPY, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_COPY", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_GLOB_DAT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GLOB_DAT", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_JMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_JMP_SLOT", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_RELATIVE, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_RELATIVE", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_GOTOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTOFF32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_GOTPC, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPC", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_GOT16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_PC16, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC16", FALSE, 0,0x0000ffff, TRUE), - HOWTO(R_390_PC16DBL, 1, 1, 16, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC16DBL", FALSE, 0,0x0000ffff, TRUE), - HOWTO(R_390_PLT16DBL, 1, 1, 16, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT16DBL", FALSE, 0,0x0000ffff, TRUE), - HOWTO(R_390_PC32DBL, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC32DBL", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_PLT32DBL, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT32DBL", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_GOTPCDBL, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPCDBL", FALSE, 0,0xffffffff, TRUE), - EMPTY_HOWTO (R_390_64), /* Empty entry for R_390_64. */ - EMPTY_HOWTO (R_390_PC64), /* Empty entry for R_390_PC64. */ - EMPTY_HOWTO (R_390_GOT64), /* Empty entry for R_390_GOT64. */ - EMPTY_HOWTO (R_390_PLT64), /* Empty entry for R_390_PLT64. */ - HOWTO(R_390_GOTENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTENT", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_GOTOFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTOFF16", FALSE, 0,0x0000ffff, FALSE), - EMPTY_HOWTO (R_390_GOTOFF64), /* Empty entry for R_390_GOTOFF64. */ - HOWTO(R_390_GOTPLT12, 0, 1, 12, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_390_GOTPLT12", FALSE, 0,0x00000fff, FALSE), - HOWTO(R_390_GOTPLT16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLT16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_GOTPLT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLT32", FALSE, 0,0xffffffff, FALSE), - EMPTY_HOWTO (R_390_GOTPLT64), /* Empty entry for R_390_GOTPLT64. */ - HOWTO(R_390_GOTPLTENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLTENT",FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_PLTOFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLTOFF16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_PLTOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLTOFF32", FALSE, 0,0xffffffff, FALSE), - EMPTY_HOWTO (R_390_PLTOFF64), /* Empty entry for R_390_PLTOFF64. */ - HOWTO(R_390_TLS_LOAD, 0, 0, 0, FALSE, 0, complain_overflow_dont, - s390_tls_reloc, "R_390_TLS_LOAD", FALSE, 0, 0, FALSE), - HOWTO(R_390_TLS_GDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - s390_tls_reloc, "R_390_TLS_GDCALL", FALSE, 0, 0, FALSE), - HOWTO(R_390_TLS_LDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - s390_tls_reloc, "R_390_TLS_LDCALL", FALSE, 0, 0, FALSE), - HOWTO(R_390_TLS_GD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_GD32", FALSE, 0, 0xffffffff, FALSE), - EMPTY_HOWTO (R_390_TLS_GD64), /* Empty entry for R_390_TLS_GD64. */ - HOWTO(R_390_TLS_GOTIE12, 0, 1, 12, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_390_TLS_GOTIE12", FALSE, 0, 0x00000fff, FALSE), - HOWTO(R_390_TLS_GOTIE32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_GOTIE32", FALSE, 0, 0xffffffff, FALSE), - EMPTY_HOWTO (R_390_TLS_GOTIE64), /* Empty entry for R_390_TLS_GOTIE64. */ - HOWTO(R_390_TLS_LDM32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_LDM32", FALSE, 0, 0xffffffff, FALSE), - EMPTY_HOWTO (R_390_TLS_LDM64), /* Empty entry for R_390_TLS_LDM64. */ - HOWTO(R_390_TLS_IE32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_IE32", FALSE, 0, 0xffffffff, FALSE), - EMPTY_HOWTO (R_390_TLS_IE64), /* Empty entry for R_390_TLS_IE64. */ - HOWTO(R_390_TLS_IEENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_IEENT", FALSE, 0, 0xffffffff, TRUE), - HOWTO(R_390_TLS_LE32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_LE32", FALSE, 0, 0xffffffff, FALSE), - EMPTY_HOWTO (R_390_TLS_LE64), /* Empty entry for R_390_TLS_LE64. */ - HOWTO(R_390_TLS_LDO32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_LDO32", FALSE, 0, 0xffffffff, FALSE), - EMPTY_HOWTO (R_390_TLS_LDO64), /* Empty entry for R_390_TLS_LDO64. */ - HOWTO(R_390_TLS_DTPMOD, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_DTPMOD", FALSE, 0, 0xffffffff, FALSE), - HOWTO(R_390_TLS_DTPOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_DTPOFF", FALSE, 0, 0xffffffff, FALSE), - HOWTO(R_390_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_TPOFF", FALSE, 0, 0xffffffff, FALSE), - HOWTO(R_390_20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_GOT20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_GOT20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_GOTPLT20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_GOTPLT20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_TLS_GOTIE20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_TLS_GOTIE20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_IRELATIVE, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_IRELATIVE", FALSE, 0, 0xffffffff, FALSE), - HOWTO(R_390_PC12DBL, 1, 1, 12, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC12DBL", FALSE, 0,0x00000fff, TRUE), - HOWTO(R_390_PLT12DBL, 1, 1, 12, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT12DBL", FALSE, 0,0x00000fff, TRUE), - HOWTO(R_390_PC24DBL, 1, 2, 24, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC24DBL", FALSE, 0,0x00ffffff, TRUE), - HOWTO(R_390_PLT24DBL, 1, 2, 24, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT24DBL", FALSE, 0,0x00ffffff, TRUE), -}; - -/* GNU extension to record C++ vtable hierarchy. */ -static reloc_howto_type elf32_s390_vtinherit_howto = - HOWTO (R_390_GNU_VTINHERIT, 0,2,0,FALSE,0,complain_overflow_dont, NULL, "R_390_GNU_VTINHERIT", FALSE,0, 0, FALSE); -static reloc_howto_type elf32_s390_vtentry_howto = - HOWTO (R_390_GNU_VTENTRY, 0,2,0,FALSE,0,complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_390_GNU_VTENTRY", FALSE,0,0, FALSE); - -static reloc_howto_type * -elf_s390_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_NONE: - return &elf_howto_table[(int) R_390_NONE]; - case BFD_RELOC_8: - return &elf_howto_table[(int) R_390_8]; - case BFD_RELOC_390_12: - return &elf_howto_table[(int) R_390_12]; - case BFD_RELOC_16: - return &elf_howto_table[(int) R_390_16]; - case BFD_RELOC_32: - return &elf_howto_table[(int) R_390_32]; - case BFD_RELOC_CTOR: - return &elf_howto_table[(int) R_390_32]; - case BFD_RELOC_32_PCREL: - return &elf_howto_table[(int) R_390_PC32]; - case BFD_RELOC_390_GOT12: - return &elf_howto_table[(int) R_390_GOT12]; - case BFD_RELOC_32_GOT_PCREL: - return &elf_howto_table[(int) R_390_GOT32]; - case BFD_RELOC_390_PLT32: - return &elf_howto_table[(int) R_390_PLT32]; - case BFD_RELOC_390_COPY: - return &elf_howto_table[(int) R_390_COPY]; - case BFD_RELOC_390_GLOB_DAT: - return &elf_howto_table[(int) R_390_GLOB_DAT]; - case BFD_RELOC_390_JMP_SLOT: - return &elf_howto_table[(int) R_390_JMP_SLOT]; - case BFD_RELOC_390_RELATIVE: - return &elf_howto_table[(int) R_390_RELATIVE]; - case BFD_RELOC_32_GOTOFF: - return &elf_howto_table[(int) R_390_GOTOFF32]; - case BFD_RELOC_390_GOTPC: - return &elf_howto_table[(int) R_390_GOTPC]; - case BFD_RELOC_390_GOT16: - return &elf_howto_table[(int) R_390_GOT16]; - case BFD_RELOC_16_PCREL: - return &elf_howto_table[(int) R_390_PC16]; - case BFD_RELOC_390_PC12DBL: - return &elf_howto_table[(int) R_390_PC12DBL]; - case BFD_RELOC_390_PLT12DBL: - return &elf_howto_table[(int) R_390_PLT12DBL]; - case BFD_RELOC_390_PC16DBL: - return &elf_howto_table[(int) R_390_PC16DBL]; - case BFD_RELOC_390_PLT16DBL: - return &elf_howto_table[(int) R_390_PLT16DBL]; - case BFD_RELOC_390_PC24DBL: - return &elf_howto_table[(int) R_390_PC24DBL]; - case BFD_RELOC_390_PLT24DBL: - return &elf_howto_table[(int) R_390_PLT24DBL]; - case BFD_RELOC_390_PC32DBL: - return &elf_howto_table[(int) R_390_PC32DBL]; - case BFD_RELOC_390_PLT32DBL: - return &elf_howto_table[(int) R_390_PLT32DBL]; - case BFD_RELOC_390_GOTPCDBL: - return &elf_howto_table[(int) R_390_GOTPCDBL]; - case BFD_RELOC_390_GOTENT: - return &elf_howto_table[(int) R_390_GOTENT]; - case BFD_RELOC_16_GOTOFF: - return &elf_howto_table[(int) R_390_GOTOFF16]; - case BFD_RELOC_390_GOTPLT12: - return &elf_howto_table[(int) R_390_GOTPLT12]; - case BFD_RELOC_390_GOTPLT16: - return &elf_howto_table[(int) R_390_GOTPLT16]; - case BFD_RELOC_390_GOTPLT32: - return &elf_howto_table[(int) R_390_GOTPLT32]; - case BFD_RELOC_390_GOTPLTENT: - return &elf_howto_table[(int) R_390_GOTPLTENT]; - case BFD_RELOC_390_PLTOFF16: - return &elf_howto_table[(int) R_390_PLTOFF16]; - case BFD_RELOC_390_PLTOFF32: - return &elf_howto_table[(int) R_390_PLTOFF32]; - case BFD_RELOC_390_TLS_LOAD: - return &elf_howto_table[(int) R_390_TLS_LOAD]; - case BFD_RELOC_390_TLS_GDCALL: - return &elf_howto_table[(int) R_390_TLS_GDCALL]; - case BFD_RELOC_390_TLS_LDCALL: - return &elf_howto_table[(int) R_390_TLS_LDCALL]; - case BFD_RELOC_390_TLS_GD32: - return &elf_howto_table[(int) R_390_TLS_GD32]; - case BFD_RELOC_390_TLS_GOTIE12: - return &elf_howto_table[(int) R_390_TLS_GOTIE12]; - case BFD_RELOC_390_TLS_GOTIE32: - return &elf_howto_table[(int) R_390_TLS_GOTIE32]; - case BFD_RELOC_390_TLS_LDM32: - return &elf_howto_table[(int) R_390_TLS_LDM32]; - case BFD_RELOC_390_TLS_IE32: - return &elf_howto_table[(int) R_390_TLS_IE32]; - case BFD_RELOC_390_TLS_IEENT: - return &elf_howto_table[(int) R_390_TLS_IEENT]; - case BFD_RELOC_390_TLS_LE32: - return &elf_howto_table[(int) R_390_TLS_LE32]; - case BFD_RELOC_390_TLS_LDO32: - return &elf_howto_table[(int) R_390_TLS_LDO32]; - case BFD_RELOC_390_TLS_DTPMOD: - return &elf_howto_table[(int) R_390_TLS_DTPMOD]; - case BFD_RELOC_390_TLS_DTPOFF: - return &elf_howto_table[(int) R_390_TLS_DTPOFF]; - case BFD_RELOC_390_TLS_TPOFF: - return &elf_howto_table[(int) R_390_TLS_TPOFF]; - case BFD_RELOC_390_20: - return &elf_howto_table[(int) R_390_20]; - case BFD_RELOC_390_GOT20: - return &elf_howto_table[(int) R_390_GOT20]; - case BFD_RELOC_390_GOTPLT20: - return &elf_howto_table[(int) R_390_GOTPLT20]; - case BFD_RELOC_390_TLS_GOTIE20: - return &elf_howto_table[(int) R_390_TLS_GOTIE20]; - case BFD_RELOC_390_IRELATIVE: - return &elf_howto_table[(int) R_390_IRELATIVE]; - case BFD_RELOC_VTABLE_INHERIT: - return &elf32_s390_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &elf32_s390_vtentry_howto; - default: - break; - } - return 0; -} - -static reloc_howto_type * -elf_s390_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - if (strcasecmp (elf32_s390_vtinherit_howto.name, r_name) == 0) - return &elf32_s390_vtinherit_howto; - if (strcasecmp (elf32_s390_vtentry_howto.name, r_name) == 0) - return &elf32_s390_vtentry_howto; - - return NULL; -} - -/* We need to use ELF32_R_TYPE so we have our own copy of this function, - and elf32-s390.c has its own copy. */ - -static void -elf_s390_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF32_R_TYPE(dst->r_info); - switch (r_type) - { - case R_390_GNU_VTINHERIT: - cache_ptr->howto = &elf32_s390_vtinherit_howto; - break; - - case R_390_GNU_VTENTRY: - cache_ptr->howto = &elf32_s390_vtentry_howto; - break; - - default: - if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0])) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) r_type); - r_type = R_390_NONE; - } - cache_ptr->howto = &elf_howto_table[r_type]; - } -} - -/* A relocation function which doesn't do anything. */ -static bfd_reloc_status_type -s390_tls_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -/* Handle the large displacement relocs. */ -static bfd_reloc_status_type -s390_elf_ldisp_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) -{ - reloc_howto_type *howto = reloc_entry->howto; - bfd_vma relocation; - bfd_vma insn; - - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - return bfd_reloc_continue; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - relocation = (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset); - relocation += reloc_entry->addend; - if (howto->pc_relative) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset); - relocation -= reloc_entry->address; - } - - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - insn |= (relocation & 0xfff) << 16 | (relocation & 0xff000) >> 4; - bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); - - if ((bfd_signed_vma) relocation < - 0x80000 - || (bfd_signed_vma) relocation > 0x7ffff) - return bfd_reloc_overflow; - else - return bfd_reloc_ok; -} - -static bfd_boolean -elf_s390_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == '.' && (name[1] == 'X' || name[1] == 'L')) - return TRUE; - - return _bfd_elf_is_local_label_name (abfd, name); -} - -/* Functions for the 390 ELF linker. */ - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.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 the first entry in the procedure linkage table. */ -#define PLT_FIRST_ENTRY_SIZE 32 -/* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE 32 - -#define GOT_ENTRY_SIZE 4 - -#define RELA_ENTRY_SIZE sizeof (Elf32_External_Rela) - -/* The first three entries in a procedure linkage table are reserved, - and the initial contents are unimportant (we zero them out). - Subsequent entries look like this. See the SVR4 ABI 386 - supplement to see how this works. */ - -/* For the s390, simple addr offset can only be 0 - 4096. - To use the full 2 GB address space, several instructions - are needed to load an address in a register and execute - a branch( or just saving the address) - - Furthermore, only r 0 and 1 are free to use!!! */ - -/* The first 3 words in the GOT are then reserved. - Word 0 is the address of the dynamic table. - Word 1 is a pointer to a structure describing the object - Word 2 is used to point to the loader entry address. - - The code for position independent PLT entries looks like this: - - r12 holds addr of the current GOT at entry to the PLT - - The GOT holds the address in the PLT to be executed. - The loader then gets: - 24(15) = Pointer to the structure describing the object. - 28(15) = Offset into rela.plt - - The loader must then find the module where the function is - and insert the address in the GOT. - - Note: 390 can only address +- 64 K relative. - We check if offset > 65536, then make a relative branch -64xxx - back to a previous defined branch - -PLT1: BASR 1,0 # 2 bytes - L 1,22(1) # 4 bytes Load offset in GOT in r 1 - L 1,(1,12) # 4 bytes Load address from GOT in r1 - BCR 15,1 # 2 bytes Jump to address -RET1: BASR 1,0 # 2 bytes Return from GOT 1st time - L 1,14(1) # 4 bytes Load offset in symol table in r1 - BRC 15,-x # 4 bytes Jump to start of PLT - .word 0 # 2 bytes filler - .long ? # 4 bytes offset in GOT - .long ? # 4 bytes offset into rela.plt - - This was the general case. There are two additional, optimizes PLT - definitions. One for GOT offsets < 4096 and one for GOT offsets < 32768. - First the one for GOT offsets < 4096: - -PLT1: L 1,(12) # 4 bytes Load address from GOT in R1 - BCR 15,1 # 2 bytes Jump to address - .word 0,0,0 # 6 bytes filler -RET1: BASR 1,0 # 2 bytes Return from GOT 1st time - L 1,14(1) # 4 bytes Load offset in rela.plt in r1 - BRC 15,-x # 4 bytes Jump to start of PLT - .word 0,0,0 # 6 bytes filler - .long ? # 4 bytes offset into rela.plt - - Second the one for GOT offsets < 32768: - -PLT1: LHI 1, # 4 bytes Load offset in GOT to r1 - L 1,(1,12) # 4 bytes Load address from GOT to r1 - BCR 15,1 # 2 bytes Jump to address - .word 0 # 2 bytes filler -RET1: BASR 1,0 # 2 bytes Return from GOT 1st time - L 1,14(1) # 4 bytes Load offset in rela.plt in r1 - BRC 15,-x # 4 bytes Jump to start of PLT - .word 0,0,0 # 6 bytes filler - .long ? # 4 bytes offset into rela.plt - -Total = 32 bytes per PLT entry - - The code for static build PLT entries looks like this: - -PLT1: BASR 1,0 # 2 bytes - L 1,22(1) # 4 bytes Load address of GOT entry - L 1,0(0,1) # 4 bytes Load address from GOT in r1 - BCR 15,1 # 2 bytes Jump to address -RET1: BASR 1,0 # 2 bytes Return from GOT 1st time - L 1,14(1) # 4 bytes Load offset in symbol table in r1 - BRC 15,-x # 4 bytes Jump to start of PLT - .word 0 # 2 bytes filler - .long ? # 4 bytes address of GOT entry - .long ? # 4 bytes offset into rela.plt */ - -static const bfd_byte elf_s390_plt_entry[PLT_ENTRY_SIZE] = - { - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x16, /* l %r1,22(%r1) */ - 0x58, 0x10, 0x10, 0x00, /* l %r1,0(%r1) */ - 0x07, 0xf1, /* br %r1 */ - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x0e, /* l %r1,14(%r1) */ - 0xa7, 0xf4, 0x00, 0x00, /* j first plt */ - 0x00, 0x00, /* padding */ - 0x00, 0x00, 0x00, 0x00, /* GOT offset */ - 0x00, 0x00, 0x00, 0x00 /* rela.plt offset */ - }; - -/* Generic PLT pic entry. */ -static const bfd_byte elf_s390_plt_pic_entry[PLT_ENTRY_SIZE] = - { - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x16, /* l %r1,22(%r1) */ - 0x58, 0x11, 0xc0, 0x00, /* l %r1,0(%r1,%r12) */ - 0x07, 0xf1, /* br %r1 */ - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x0e, /* l %r1,14(%r1) */ - 0xa7, 0xf4, 0x00, 0x00, /* j first plt */ - 0x00, 0x00, /* padding */ - 0x00, 0x00, 0x00, 0x00, /* GOT offset */ - 0x00, 0x00, 0x00, 0x00 /* rela.plt offset */ - }; - -/* Optimized PLT pic entry for GOT offset < 4k. xx will be replaced - when generating the PLT slot with the GOT offset. */ -static const bfd_byte elf_s390_plt_pic12_entry[PLT_ENTRY_SIZE] = - { - 0x58, 0x10, 0xc0, 0x00, /* l %r1,xx(%r12) */ - 0x07, 0xf1, /* br %r1 */ - 0x00, 0x00, 0x00, 0x00, /* padding */ - 0x00, 0x00, - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x0e, /* l %r1,14(%r1) */ - 0xa7, 0xf4, 0x00, 0x00, /* j first plt */ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - -/* Optimized PLT pic entry for GOT offset < 32k. xx will be replaced - when generating the PLT slot with the GOT offset. */ -static const bfd_byte elf_s390_plt_pic16_entry[PLT_ENTRY_SIZE] = - { - 0xa7, 0x18, 0x00, 0x00, /* lhi %r1,xx */ - 0x58, 0x11, 0xc0, 0x00, /* l %r1,0(%r1,%r12) */ - 0x07, 0xf1, /* br %r1 */ - 0x00, 0x00, - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x0e, /* l %r1,14(%r1) */ - 0xa7, 0xf4, 0x00, 0x00, /* j first plt */ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - -/* The first PLT entry pushes the offset into the rela.plt - from R1 onto the stack at 8(15) and the loader object info - at 12(15), loads the loader address in R1 and jumps to it. */ - -/* The first entry in the PLT for PIC code: - -PLT0: - ST 1,28(15) # R1 has offset into rela.plt - L 1,4(12) # Get loader ino(object struct address) - ST 1,24(15) # Store address - L 1,8(12) # Entry address of loader in R1 - BR 1 # Jump to loader - - The first entry in the PLT for static code: - -PLT0: - ST 1,28(15) # R1 has offset into rela.plt - BASR 1,0 - L 1,18(0,1) # Get address of GOT - MVC 24(4,15),4(1) # Move loader ino to stack - L 1,8(1) # Get address of loader - BR 1 # Jump to loader - .word 0 # filler - .long got # address of GOT */ - -static const bfd_byte elf_s390_plt_first_entry[PLT_FIRST_ENTRY_SIZE] = - { - 0x50, 0x10, 0xf0, 0x1c, /* st %r1,28(%r15) */ - 0x0d, 0x10, /* basr %r1,%r0 */ - 0x58, 0x10, 0x10, 0x12, /* l %r1,18(%r1) */ - 0xd2, 0x03, 0xf0, 0x18, 0x10, 0x04, /* mvc 24(4,%r15),4(%r1) */ - 0x58, 0x10, 0x10, 0x08, /* l %r1,8(%r1) */ - 0x07, 0xf1, /* br %r1 */ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - -static const bfd_byte elf_s390_plt_pic_first_entry[PLT_FIRST_ENTRY_SIZE] = - { - 0x50, 0x10, 0xf0, 0x1c, /* st %r1,28(%r15) */ - 0x58, 0x10, 0xc0, 0x04, /* l %r1,4(%r12) */ - 0x50, 0x10, 0xf0, 0x18, /* st %r1,24(%r15) */ - 0x58, 0x10, 0xc0, 0x08, /* l %r1,8(%r12) */ - 0x07, 0xf1, /* br %r1 */ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 - }; - - -/* s390 ELF linker hash entry. */ - -struct elf_s390_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* Number of GOTPLT references for a function. */ - bfd_signed_vma gotplt_refcount; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_IE 3 -#define GOT_TLS_IE_NLT 4 - unsigned char tls_type; - - /* For pointer equality reasons we might need to change the symbol - type from STT_GNU_IFUNC to STT_FUNC together with its value and - section entry. So after alloc_dynrelocs only these values should - be used. In order to check whether a symbol is IFUNC use - s390_is_ifunc_symbol_p. */ - bfd_vma ifunc_resolver_address; - asection *ifunc_resolver_section; -}; - -#define elf_s390_hash_entry(ent) \ - ((struct elf_s390_link_hash_entry *)(ent)) - -/* This structure represents an entry in the local PLT list needed for - local IFUNC symbols. */ -struct plt_entry -{ - /* The section of the local symbol. - Set in relocate_section and used in finish_dynamic_sections. */ - asection *sec; - - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } plt; -}; - -/* NOTE: Keep this structure in sync with - the one declared in elf64-s390.c. */ -struct elf_s390_obj_tdata -{ - struct elf_obj_tdata root; - - /* A local PLT is needed for ifunc symbols. */ - struct plt_entry *local_plt; - - /* TLS type for each local got entry. */ - char *local_got_tls_type; -}; - -#define elf_s390_tdata(abfd) \ - ((struct elf_s390_obj_tdata *) (abfd)->tdata.any) - -#define elf_s390_local_plt(abfd) \ - (elf_s390_tdata (abfd)->local_plt) - -#define elf_s390_local_got_tls_type(abfd) \ - (elf_s390_tdata (abfd)->local_got_tls_type) - -#define is_s390_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == S390_ELF_DATA) - -static bfd_boolean -elf_s390_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_s390_obj_tdata), - S390_ELF_DATA); -} - -static bfd_boolean -elf_s390_object_p (bfd *abfd) -{ - /* Set the right machine number for an s390 elf32 file. */ - return bfd_default_set_arch_mach (abfd, bfd_arch_s390, bfd_mach_s390_31); -} - -/* s390 ELF linker hash table. */ - -struct elf_s390_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *irelifunc; - - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - /* Small local sym cache. */ - struct sym_cache sym_cache; -}; - -/* Get the s390 ELF linker hash table from a link_info structure. */ - -#define elf_s390_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == S390_ELF_DATA ? ((struct elf_s390_link_hash_table *) ((p)->hash)) : NULL) - -#undef ELF64 -#include "elf-s390-common.c" - -/* Create an entry in an s390 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_s390_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_s390_link_hash_entry *eh; - - eh = (struct elf_s390_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - eh->gotplt_refcount = 0; - eh->tls_type = GOT_UNKNOWN; - eh->ifunc_resolver_address = 0; - eh->ifunc_resolver_section = NULL; - } - - return entry; -} - -/* Create an s390 ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf_s390_link_hash_table_create (bfd *abfd) -{ - struct elf_s390_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_s390_link_hash_table); - - ret = (struct elf_s390_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, - sizeof (struct elf_s390_link_hash_entry), - S390_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->elf.root; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf_s390_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_s390_link_hash_entry *edir, *eind; - - edir = (struct elf_s390_link_hash_entry *) dir; - eind = (struct elf_s390_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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. */ - if (dir->versioned != versioned_hidden) - 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; - } - else - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -static int -elf_s390_tls_transition (struct bfd_link_info *info, - int r_type, - int is_local) -{ - if (bfd_link_pic (info)) - return r_type; - - switch (r_type) - { - case R_390_TLS_GD32: - case R_390_TLS_IE32: - if (is_local) - return R_390_TLS_LE32; - return R_390_TLS_IE32; - case R_390_TLS_GOTIE32: - if (is_local) - return R_390_TLS_LE32; - return R_390_TLS_GOTIE32; - case R_390_TLS_LDM32: - return R_390_TLS_LE32; - } - - return r_type; -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -elf_s390_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_s390_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; - bfd_signed_vma *local_got_refcounts; - int tls_type, old_tls_type; - Elf_Internal_Sym *isym; - - if (bfd_link_relocatable (info)) - return TRUE; - - BFD_ASSERT (is_s390_elf (abfd)); - - htab = elf_s390_hash_table (info); - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned int r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), - abfd, r_symndx); - return FALSE; - } - - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - struct plt_entry *plt; - - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - if (!s390_elf_create_ifunc_sections (htab->elf.dynobj, info)) - return FALSE; - - if (local_got_refcounts == NULL) - { - if (!elf_s390_allocate_local_syminfo (abfd, symtab_hdr)) - return FALSE; - local_got_refcounts = elf_local_got_refcounts (abfd); - } - plt = elf_s390_local_plt (abfd); - plt[r_symndx].plt.refcount++; - } - 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; - } - - /* Create got section and local_got_refcounts array if they - are needed. */ - r_type = elf_s390_tls_transition (info, - ELF32_R_TYPE (rel->r_info), - h == NULL); - switch (r_type) - { - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOTENT: - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLTENT: - case R_390_TLS_GD32: - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_GOTIE32: - case R_390_TLS_IEENT: - case R_390_TLS_IE32: - case R_390_TLS_LDM32: - if (h == NULL - && local_got_refcounts == NULL) - { - if (!elf_s390_allocate_local_syminfo (abfd, symtab_hdr)) - return FALSE; - local_got_refcounts = elf_local_got_refcounts (abfd); - } - /* Fall through. */ - case R_390_GOTOFF16: - case R_390_GOTOFF32: - case R_390_GOTPC: - case R_390_GOTPCDBL: - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } - } - - if (h != NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!s390_elf_create_ifunc_sections (htab->elf.dynobj, info)) - return FALSE; - - /* Make sure an IFUNC symbol defined in a non-shared object - always gets a PLT slot. */ - if (s390_is_ifunc_symbol_p (h) && h->def_regular) - { - /* The symbol is called by the dynamic loader in order - to resolve the relocation. So it is in fact also - referenced. */ - h->ref_regular = 1; - h->needs_plt = 1; - } - } - switch (r_type) - { - case R_390_GOTPC: - case R_390_GOTPCDBL: - /* These relocs do not need a GOT slot. They just load the - GOT pointer itself or address something else relative to - the GOT. Since the GOT pointer has been set up above we - are done. */ - break; - case R_390_GOTOFF16: - case R_390_GOTOFF32: - if (h == NULL || !s390_is_ifunc_symbol_p (h) || !h->def_regular) - break; - /* Fall through. */ - - case R_390_PLT12DBL: - case R_390_PLT16DBL: - case R_390_PLT24DBL: - case R_390_PLT32DBL: - case R_390_PLT32: - case R_390_PLTOFF16: - case R_390_PLTOFF32: - /* 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) - { - h->needs_plt = 1; - h->plt.refcount += 1; - } - break; - - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLTENT: - /* This symbol requires either a procedure linkage table entry - or an entry in the local got. We actually build the entry - in adjust_dynamic_symbol because whether this is really a - global reference can change and with it the fact if we have - to create a plt entry or a local got entry. To be able to - make a once global symbol a local one we have to keep track - of the number of gotplt references that exist for this - symbol. */ - if (h != NULL) - { - ((struct elf_s390_link_hash_entry *) h)->gotplt_refcount++; - h->needs_plt = 1; - h->plt.refcount += 1; - } - else - local_got_refcounts[r_symndx] += 1; - break; - - case R_390_TLS_LDM32: - htab->tls_ldm_got.refcount += 1; - break; - - case R_390_TLS_IE32: - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_GOTIE32: - case R_390_TLS_IEENT: - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - /* Fall through. */ - - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOTENT: - case R_390_TLS_GD32: - /* This symbol requires a global offset table entry. */ - switch (r_type) - { - default: - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOTENT: - tls_type = GOT_NORMAL; - break; - case R_390_TLS_GD32: - tls_type = GOT_TLS_GD; - break; - case R_390_TLS_IE32: - case R_390_TLS_GOTIE32: - tls_type = GOT_TLS_IE; - break; - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_IEENT: - tls_type = GOT_TLS_IE_NLT; - break; - } - - if (h != NULL) - { - h->got.refcount += 1; - old_tls_type = elf_s390_hash_entry(h)->tls_type; - } - else - { - local_got_refcounts[r_symndx] += 1; - old_tls_type = elf_s390_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) - { - if (old_tls_type == GOT_NORMAL || tls_type == GOT_NORMAL) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as normal and thread local symbol"), - abfd, h->root.root.string); - return FALSE; - } - if (old_tls_type > tls_type) - tls_type = old_tls_type; - } - - if (old_tls_type != tls_type) - { - if (h != NULL) - elf_s390_hash_entry (h)->tls_type = tls_type; - else - elf_s390_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - - if (r_type != R_390_TLS_IE32) - break; - /* Fall through. */ - - case R_390_TLS_LE32: - /* For static linking and executables this reloc will be - calculated at linktime otherwise a TLS_TPOFF runtime - reloc will be generated. */ - if (r_type == R_390_TLS_LE32 && bfd_link_pie (info)) - break; - - if (!bfd_link_pic (info)) - break; - info->flags |= DF_STATIC_TLS; - /* Fall through. */ - - case R_390_8: - case R_390_16: - case R_390_32: - case R_390_PC16: - case R_390_PC12DBL: - case R_390_PC16DBL: - case R_390_PC24DBL: - case R_390_PC32DBL: - case R_390_PC32: - if (h != NULL && bfd_link_executable (info)) - { - /* 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; - - if (!bfd_link_pic (info)) - { - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - h->plt.refcount += 1; - } - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). In case of a weak definition, - DEF_REGULAR may be cleared later by a strong definition in - a shared library. We account for that possibility below by - storing information in the relocs_copied field of the hash - table entry. A similar situation occurs when creating - shared libraries and symbol visibility changes render the - symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && ((ELF32_R_TYPE (rel->r_info) != R_390_PC16 - && ELF32_R_TYPE (rel->r_info) != R_390_PC12DBL - && ELF32_R_TYPE (rel->r_info) != R_390_PC16DBL - && ELF32_R_TYPE (rel->r_info) != R_390_PC24DBL - && ELF32_R_TYPE (rel->r_info) != R_390_PC32DBL - && ELF32_R_TYPE (rel->r_info) != R_390_PC32) - || (h != NULL - && (! SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_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) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - { - head = &((struct elf_s390_link_hash_entry *) h)->dyn_relocs; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - asection *s; - void *vpp; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - - p = ((struct elf_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 (ELF32_R_TYPE (rel->r_info) == R_390_PC16 - || ELF32_R_TYPE (rel->r_info) == R_390_PC12DBL - || ELF32_R_TYPE (rel->r_info) == R_390_PC16DBL - || ELF32_R_TYPE (rel->r_info) == R_390_PC24DBL - || ELF32_R_TYPE (rel->r_info) == R_390_PC32DBL - || ELF32_R_TYPE (rel->r_info) == R_390_PC32) - p->pc_count += 1; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_390_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_390_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !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 * -elf_s390_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_390_GNU_VTINHERIT: - case R_390_GNU_VTENTRY: - return NULL; - } - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); - -} - -/* Make sure we emit a GOT entry if the symbol was supposed to have a PLT - entry but we found we will not create any. Called when we find we will - not have any PLT for this symbol, by for example - elf_s390_adjust_dynamic_symbol when we're doing a proper dynamic link, - or elf_s390_size_dynamic_sections if no dynamic sections will be - created (we're only linking static objects). */ - -static void -elf_s390_adjust_gotplt (struct elf_s390_link_hash_entry *h) -{ - if (h->elf.root.type == bfd_link_hash_warning) - h = (struct elf_s390_link_hash_entry *) h->elf.root.u.i.link; - - if (h->gotplt_refcount <= 0) - return; - - /* We simply add the number of gotplt references to the number - * of got references for this symbol. */ - h->elf.got.refcount += h->gotplt_refcount; - h->gotplt_refcount = -1; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = elf_s390_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* 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_s390_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_s390_link_hash_table *htab; - asection *s, *srel; - - /* STT_GNU_IFUNC symbol must go through PLT. */ - if (s390_is_ifunc_symbol_p (h)) - { - /* All local STT_GNU_IFUNC references must be treated as local - calls via local PLT. */ - if (h->ref_regular && SYMBOL_CALLS_LOCAL (info, h)) - { - bfd_size_type pc_count = 0, count = 0; - struct elf_dyn_relocs **pp; - struct elf_s390_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - eh = (struct elf_s390_link_hash_entry *) h; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - pc_count += p->pc_count; - p->count -= p->pc_count; - p->pc_count = 0; - count += p->count; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - - if (pc_count || count) - { - h->needs_plt = 1; - h->non_got_ref = 1; - if (h->plt.refcount <= 0) - h->plt.refcount = 1; - else - h->plt.refcount += 1; - } - } - - if (h->plt.refcount <= 0) - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - return TRUE; - } - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later - (although we could actually do it here). */ - 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; - elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h); - } - - return TRUE; - } - else - /* It's possible that we incorrectly decided a .plt reloc was - needed for an R_390_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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) - h->non_got_ref = def->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 (bfd_link_pic (info)) - 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 we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = elf_s390_hash_table (info); - - /* We must generate a R_390_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_READONLY) != 0) - { - s = htab->elf.sdynrelro; - srel = htab->elf.sreldynrelro; - } - else - { - s = htab->elf.sdynbss; - srel = htab->elf.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info; - struct elf_s390_link_hash_table *htab; - struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry *)h; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = elf_s390_hash_table (info); - - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it - here if it is defined and referenced in a non-shared object. */ - if (s390_is_ifunc_symbol_p (h) && h->def_regular) - return s390_elf_allocate_ifunc_dyn_relocs (info, h); - else 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 (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - asection *s = htab->elf.splt; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += PLT_FIRST_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 (! bfd_link_pic (info) - && !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->elf.sgotplt->size += GOT_ENTRY_SIZE; - - /* We also need to make an entry in the .rela.plt section. */ - htab->elf.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h); - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h); - } - - /* If R_390_TLS_{IE32,GOTIE32,GOTIE12,IEENT} symbol is now local to - the binary, we can optimize a bit. IE32 and GOTIE32 get converted - to R_390_TLS_LE32 requiring no TLS entry. For GOTIE12 and IEENT - we can save the dynamic TLS relocation. */ - if (h->got.refcount > 0 - && !bfd_link_pic (info) - && h->dynindx == -1 - && elf_s390_hash_entry(h)->tls_type >= GOT_TLS_IE) - { - if (elf_s390_hash_entry(h)->tls_type == GOT_TLS_IE_NLT) - /* For the GOTIE access without a literal pool entry the offset has - to be stored somewhere. The immediate value in the instruction - is not bit enough so the value is stored in the got. */ - { - h->got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += GOT_ENTRY_SIZE; - } - else - h->got.offset = (bfd_vma) -1; - } - else if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = elf_s390_hash_entry(h)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->elf.sgot; - h->got.offset = s->size; - s->size += GOT_ENTRY_SIZE; - /* R_390_TLS_GD32 needs 2 consecutive GOT slots. */ - if (tls_type == GOT_TLS_GD) - s->size += GOT_ENTRY_SIZE; - dyn = htab->elf.dynamic_sections_created; - /* R_390_TLS_IE32 needs one dynamic relocation, - R_390_TLS_GD32 needs one if local symbol and two if global. */ - if ((tls_type == GOT_TLS_GD && h->dynindx == -1) - || tls_type >= GOT_TLS_IE) - htab->elf.srelgot->size += sizeof (Elf32_External_Rela); - else if (tls_type == GOT_TLS_GD) - htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rela); - else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak) - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->elf.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_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 - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - 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_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_s390_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_s390_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = elf_s390_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 (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (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_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srela; - struct plt_entry *local_plt; - unsigned int i; - - if (! is_s390_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = 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) - { - srela = elf_section_data (p->sec)->sreloc; - srela->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - local_tls_type = elf_s390_local_got_tls_type (ibfd); - s = htab->elf.sgot; - srela = htab->elf.srelgot; - for (; local_got < end_local_got; ++local_got, ++local_tls_type) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += GOT_ENTRY_SIZE; - if (*local_tls_type == GOT_TLS_GD) - s->size += GOT_ENTRY_SIZE; - if (bfd_link_pic (info)) - srela->size += sizeof (Elf32_External_Rela); - } - else - *local_got = (bfd_vma) -1; - } - local_plt = elf_s390_local_plt (ibfd); - for (i = 0; i < symtab_hdr->sh_info; i++) - { - if (local_plt[i].plt.refcount > 0) - { - local_plt[i].plt.offset = htab->elf.iplt->size; - htab->elf.iplt->size += PLT_ENTRY_SIZE; - htab->elf.igotplt->size += GOT_ENTRY_SIZE; - htab->elf.irelplt->size += RELA_ENTRY_SIZE; - } - else - local_plt[i].plt.offset = (bfd_vma) -1; - } - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate 2 got entries and 1 dynamic reloc for R_390_TLS_LDM32 - relocs. */ - htab->tls_ldm_got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += 2 * GOT_ENTRY_SIZE; - htab->elf.srelgot->size += sizeof (Elf32_External_Rela); - } - 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, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->elf.splt - || s == htab->elf.sgot - || s == htab->elf.sgotplt - || s == htab->elf.sdynbss - || s == htab->elf.sdynrelro - || s == htab->elf.iplt - || s == htab->elf.igotplt - || s == htab->irelifunc) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0) - 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 to handle .rela.bss and - .rela.plt. We must create it in - create_dynamic_sections, because it 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_390_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 elf_s390_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->elf.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Return the base VMA address which should be subtracted from real addresses - when resolving @dtpoff relocation. - This is PT_TLS segment p_vaddr. */ - -static bfd_vma -dtpoff_base (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; -} - -/* Complain if TLS instruction relocation is against an invalid - instruction. */ - -static void -invalid_tls_insn (bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *rel) -{ - reloc_howto_type *howto; - - howto = elf_howto_table + ELF32_R_TYPE (rel->r_info); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): invalid instruction for TLS relocation %s"), - input_bfd, - input_section, - rel->r_offset, - howto->name); - bfd_set_error (bfd_error_bad_value); -} - -/* Relocate a 390 ELF section. */ - -static bfd_boolean -elf_s390_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_s390_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - BFD_ASSERT (is_s390_elf (input_bfd)); - - htab = elf_s390_hash_table (info); - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - unsigned int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - asection *sec; - bfd_vma off; - bfd_vma relocation; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - int tls_type; - asection *base_got = htab->elf.sgot; - bfd_boolean resolved_to_zero; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == (int) R_390_GNU_VTINHERIT - || r_type == (int) R_390_GNU_VTENTRY) - continue; - if (r_type >= (int) R_390_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - howto = elf_howto_table + r_type; - r_symndx = ELF32_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]; - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - struct plt_entry *local_plt = elf_s390_local_plt (input_bfd); - if (local_plt == NULL) - return FALSE; - - /* Address of the PLT slot. */ - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + local_plt[r_symndx].plt.offset); - - switch (r_type) - { - case R_390_PLTOFF16: - case R_390_PLTOFF32: - relocation -= htab->elf.sgot->output_section->vma; - break; - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLTENT: - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOTENT: - { - /* Write the PLT slot address into the GOT slot. */ - bfd_put_32 (output_bfd, relocation, - htab->elf.sgot->contents + - local_got_offsets[r_symndx]); - relocation = (local_got_offsets[r_symndx] + - htab->elf.sgot->output_offset); - - if (r_type == R_390_GOTENT || r_type == R_390_GOTPLTENT) - relocation += htab->elf.sgot->output_section->vma; - break; - } - default: - break; - } - /* The output section is needed later in - finish_dynamic_section when creating the dynamic - relocation. */ - local_plt[r_symndx].sec = sec; - goto do_relocation; - } - else - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch (r_type) - { - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLTENT: - /* There are three cases for a GOTPLT relocation. 1) The - relocation is against the jump slot entry of a plt that - will get emitted to the output file. 2) The relocation - is against the jump slot of a plt entry that has been - removed. elf_s390_adjust_gotplt has created a GOT entry - as replacement. 3) The relocation is against a local symbol. - Cases 2) and 3) are the same as the GOT relocation code - so we just have to test for case 1 and fall through for - the other two. */ - if (h != NULL && h->plt.offset != (bfd_vma) -1) - { - bfd_vma plt_index; - - if (s390_is_ifunc_symbol_p (h)) - { - plt_index = h->plt.offset / PLT_ENTRY_SIZE; - relocation = (plt_index * GOT_ENTRY_SIZE + - htab->elf.igotplt->output_offset); - if (r_type == R_390_GOTPLTENT) - relocation += htab->elf.igotplt->output_section->vma; - } - else - { - /* Calc. index no. - Current offset - size first entry / entry size. */ - plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) / - PLT_ENTRY_SIZE; - - /* Offset in GOT is PLT index plus GOT headers(3) - times 4, addr & GOT addr. */ - relocation = (plt_index + 3) * GOT_ENTRY_SIZE; - if (r_type == R_390_GOTPLTENT) - relocation += htab->elf.sgot->output_section->vma; - } - unresolved_reloc = FALSE; - - } - /* Fall through. */ - - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOTENT: - /* Relocation is to the entry for this symbol in the global - offset table. */ - if (base_got == NULL) - abort (); - - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; - dyn = htab->elf.dynamic_sections_created; - - if (s390_is_ifunc_symbol_p (h)) - { - BFD_ASSERT (h->plt.offset != (bfd_vma) -1); - if (off == (bfd_vma)-1) - { - /* No explicit GOT usage so redirect to the - got.iplt slot. */ - base_got = htab->elf.igotplt; - off = h->plt.offset / PLT_ENTRY_SIZE * GOT_ENTRY_SIZE; - } - else - { - /* Explicit GOT slots must contain the address - of the PLT slot. This will be handled in - finish_dynamic_symbol. */ - } - } - else if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && 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 2, 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, - base_got->contents + off); - h->got.offset |= 1; - } - - if ((h->def_regular - && bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - /* lrl rx,sym@GOTENT -> larl rx, sym */ - && ((r_type == R_390_GOTENT - && (bfd_get_16 (input_bfd, - contents + rel->r_offset - 2) - & 0xff0f) == 0xc40d) - /* ly rx, sym@GOT(r12) -> larl rx, sym */ - || (r_type == R_390_GOT20 - && (bfd_get_32 (input_bfd, - contents + rel->r_offset - 2) - & 0xff00f000) == 0xe300c000 - && bfd_get_8 (input_bfd, - contents + rel->r_offset + 3) == 0x58))) - { - unsigned short new_insn = - (0xc000 | (bfd_get_8 (input_bfd, - contents + rel->r_offset - 1) & 0xf0)); - bfd_put_16 (output_bfd, new_insn, - contents + rel->r_offset - 2); - r_type = R_390_PC32DBL; - rel->r_addend = 2; - howto = elf_howto_table + r_type; - relocation = h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset; - goto do_relocation; - } - } - 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->elf.sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *srelgot; - Elf_Internal_Rela outrel; - bfd_byte *loc; - - srelgot = htab->elf.srelgot; - if (srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_390_RELATIVE); - outrel.r_addend = relocation; - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - - local_got_offsets[r_symndx] |= 1; - } - } - - if (off >= (bfd_vma) -2) - abort (); - - relocation = base_got->output_offset + off; - - /* For @GOTENT the relocation is against the offset between - the instruction and the symbols entry in the GOT and not - between the start of the GOT and the symbols entry. We - add the vma of the GOT to get the correct value. */ - if ( r_type == R_390_GOTENT - || r_type == R_390_GOTPLTENT) - relocation += base_got->output_section->vma; - - break; - - case R_390_GOTOFF16: - case R_390_GOTOFF32: - /* Relocation is relative to the start of the global offset - table. */ - - if (h != NULL - && s390_is_ifunc_symbol_p (h) - && h->def_regular - && !bfd_link_executable (info)) - { - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset - - htab->elf.sgot->output_section->vma); - goto do_relocation; - } - - /* Note that sgot->output_offset is not involved in this - calculation. We always want the start of .got. If we - defined _GLOBAL_OFFSET_TABLE in a different way, as is - permitted by the ABI, we might have to change this - calculation. */ - relocation -= htab->elf.sgot->output_section->vma; - break; - - case R_390_GOTPC: - case R_390_GOTPCDBL: - /* Use global offset table as symbol value. */ - relocation = htab->elf.sgot->output_section->vma; - unresolved_reloc = FALSE; - break; - - case R_390_PLT12DBL: - case R_390_PLT16DBL: - case R_390_PLT24DBL: - case R_390_PLT32DBL: - case R_390_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->elf.splt == NULL && htab->elf.iplt == NULL)) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } - - if (s390_is_ifunc_symbol_p (h)) - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); - unresolved_reloc = FALSE; - break; - - case R_390_PLTOFF16: - case R_390_PLTOFF32: - /* Relocation is to the entry for this symbol in the - procedure linkage table relative to the start of the GOT. */ - - /* For local symbols or if we didn't make a PLT entry for - this symbol resolve the symbol directly. */ - if (h == NULL - || h->plt.offset == (bfd_vma) -1 - || (htab->elf.splt == NULL && !s390_is_ifunc_symbol_p (h))) - { - relocation -= htab->elf.sgot->output_section->vma; - break; - } - - if (s390_is_ifunc_symbol_p (h)) - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset - - htab->elf.sgot->output_section->vma); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset - - htab->elf.sgot->output_section->vma); - unresolved_reloc = FALSE; - break; - - case R_390_PC16: - case R_390_PC12DBL: - case R_390_PC16DBL: - case R_390_PC24DBL: - case R_390_PC32DBL: - case R_390_PC32: - if (h != NULL - && s390_is_ifunc_symbol_p (h) - && h->def_regular - && !bfd_link_executable (info)) - { - /* This will not work our if the function does not - happen to set up the GOT pointer for some other - reason. 31 bit PLT entries require r12 to hold the - GOT pointer. - FIXME: Implement an errorcheck. - NOTE: It will work when brasl is not available - (e.g. with -m31 -march=g5) since a local function - call then does use GOTOFF which implies r12 being set - up. */ - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h ->plt.offset); - goto do_relocation; - } - /* Fall through. */ - - case R_390_8: - case R_390_16: - case R_390_32: - if (h != NULL - && s390_is_ifunc_symbol_p (h) - && h->def_regular) - { - if (!bfd_link_pic (info)) - { - /* For a non-shared object STT_GNU_IFUNC symbol must - go through PLT. */ - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h ->plt.offset); - goto do_relocation; - } - else - { - /* For shared objects a runtime relocation is needed. */ - - Elf_Internal_Rela outrel; - asection *sreloc; - - /* Need a dynamic relocation to get the real function - address. */ - outrel.r_offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1 - || outrel.r_offset == (bfd_vma) -2) - abort (); - - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (h->dynindx == -1 - || h->forced_local - || bfd_link_executable (info)) - { - /* This symbol is resolved locally. */ - outrel.r_info = ELF32_R_INFO (0, R_390_IRELATIVE); - outrel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = 0; - } - - sreloc = htab->elf.irelifunc; - elf_append_rela (output_bfd, sreloc, &outrel); - - /* 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. For an - internal symbol, we have updated addend. */ - continue; - } - } - - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - if ((bfd_link_pic (info) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && ((r_type != R_390_PC16 - && r_type != R_390_PC12DBL - && r_type != R_390_PC16DBL - && r_type != R_390_PC24DBL - && r_type != R_390_PC32DBL - && r_type != R_390_PC32) - || !SYMBOL_CALLS_LOCAL (info, h))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && 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_boolean skip, relocate; - asection *sreloc; - bfd_byte *loc; - - /* 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_390_PC16 - || r_type == R_390_PC12DBL - || r_type == R_390_PC16DBL - || r_type == R_390_PC24DBL - || r_type == R_390_PC32DBL - || r_type == R_390_PC32 - || !bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !h->def_regular)) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* This symbol is local, or marked to become local. */ - outrel.r_addend = relocation + rel->r_addend; - if (r_type == R_390_32) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_390_RELATIVE); - } - 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; - if (sindx == 0) - { - osec = htab->elf.text_index_section; - sindx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (sindx != 0); - - /* We are turning this relocation into one - against a section symbol, so subtract out - the output section's address but not the - offset of the input section in the output - section. */ - outrel.r_addend -= osec->vma; - } - outrel.r_info = ELF32_R_INFO (sindx, r_type); - } - } - - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_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; - - /* Relocations for tls literal pool entries. */ - case R_390_TLS_IE32: - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - asection *sreloc; - bfd_byte *loc; - - outrel.r_offset = rel->r_offset - + input_section->output_section->vma - + input_section->output_offset; - outrel.r_info = ELF32_R_INFO (0, R_390_RELATIVE); - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); - } - /* Fall through. */ - - case R_390_TLS_GD32: - case R_390_TLS_GOTIE32: - r_type = elf_s390_tls_transition (info, r_type, h == NULL); - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = elf_s390_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - { - tls_type = elf_s390_hash_entry(h)->tls_type; - if (!bfd_link_pic (info) - && h->dynindx == -1 - && tls_type >= GOT_TLS_IE) - r_type = R_390_TLS_LE32; - } - if (r_type == R_390_TLS_GD32 && tls_type >= GOT_TLS_IE) - r_type = R_390_TLS_IE32; - - if (r_type == R_390_TLS_LE32) - { - /* This relocation gets optimized away by the local exec - access optimization. */ - BFD_ASSERT (! unresolved_reloc); - bfd_put_32 (output_bfd, -tpoff (info, relocation), - contents + rel->r_offset); - continue; - } - - if (htab->elf.sgot == NULL) - abort (); - - if (h != NULL) - off = h->got.offset; - else - { - if (local_got_offsets == NULL) - abort (); - - off = local_got_offsets[r_symndx]; - } - - emit_tls_relocs: - - if ((off & 1) != 0) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - int dr_type, indx; - - if (htab->elf.srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - - indx = h && h->dynindx != -1 ? h->dynindx : 0; - if (r_type == R_390_TLS_GD32) - dr_type = R_390_TLS_DTPMOD; - else - dr_type = R_390_TLS_TPOFF; - if (dr_type == R_390_TLS_TPOFF && indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (indx, dr_type); - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ - * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - if (r_type == R_390_TLS_GD32) - { - if (indx == 0) - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_32 (output_bfd, - relocation - dtpoff_base (info), - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - } - else - { - outrel.r_info = ELF32_R_INFO (indx, R_390_TLS_DTPOFF); - outrel.r_offset += GOT_ENTRY_SIZE; - outrel.r_addend = 0; - htab->elf.srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - } - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - if (off >= (bfd_vma) -2) - abort (); - if (r_type == ELF32_R_TYPE (rel->r_info)) - { - relocation = htab->elf.sgot->output_offset + off; - if (r_type == R_390_TLS_IE32 || r_type == R_390_TLS_IEENT) - relocation += htab->elf.sgot->output_section->vma; - unresolved_reloc = FALSE; - } - else - { - bfd_put_32 (output_bfd, htab->elf.sgot->output_offset + off, - contents + rel->r_offset); - continue; - } - break; - - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_IEENT: - if (h == NULL) - { - if (local_got_offsets == NULL) - abort(); - off = local_got_offsets[r_symndx]; - if (bfd_link_pic (info)) - goto emit_tls_relocs; - } - else - { - off = h->got.offset; - tls_type = elf_s390_hash_entry(h)->tls_type; - if (bfd_link_pic (info) - || h->dynindx != -1 - || tls_type < GOT_TLS_IE) - goto emit_tls_relocs; - } - - if (htab->elf.sgot == NULL) - abort (); - - BFD_ASSERT (! unresolved_reloc); - bfd_put_32 (output_bfd, -tpoff (info, relocation), - htab->elf.sgot->contents + off); - relocation = htab->elf.sgot->output_offset + off; - if (r_type == R_390_TLS_IEENT) - relocation += htab->elf.sgot->output_section->vma; - unresolved_reloc = FALSE; - break; - - case R_390_TLS_LDM32: - if (! bfd_link_pic (info)) - /* The literal pool entry this relocation refers to gets ignored - by the optimized code of the local exec model. Do nothing - and the value will turn out zero. */ - continue; - - if (htab->elf.sgot == NULL) - abort (); - - off = htab->tls_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - if (htab->elf.srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - - bfd_put_32 (output_bfd, 0, - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - outrel.r_info = ELF32_R_INFO (0, R_390_TLS_DTPMOD); - outrel.r_addend = 0; - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ - * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->tls_ldm_got.offset |= 1; - } - relocation = htab->elf.sgot->output_offset + off; - unresolved_reloc = FALSE; - break; - - case R_390_TLS_LE32: - if (bfd_link_dll (info)) - { - /* Linking a shared library with non-fpic code requires - a R_390_TLS_TPOFF relocation. */ - 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; - outrel.r_info = ELF32_R_INFO (indx, R_390_TLS_TPOFF); - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_32 (output_bfd, -tpoff (info, relocation), - contents + rel->r_offset); - } - continue; - - case R_390_TLS_LDO32: - if (bfd_link_pic (info) || (input_section->flags & SEC_DEBUGGING)) - relocation -= dtpoff_base (info); - else - /* When converting LDO to LE, we must negate. */ - relocation = -tpoff (info, relocation); - break; - - /* Relocations for tls instructions. */ - case R_390_TLS_LOAD: - case R_390_TLS_GDCALL: - case R_390_TLS_LDCALL: - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = elf_s390_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - tls_type = elf_s390_hash_entry(h)->tls_type; - - if (tls_type == GOT_TLS_GD) - continue; - - if (r_type == R_390_TLS_LOAD) - { - if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) - { - /* IE->LE transition. Four valid cases: - l %rx,0(0,%ry) -> lr %rx,%ry + bcr 0,0 - l %rx,0(%ry,0) -> lr %rx,%ry + bcr 0,0 - l %rx,0(%ry,%r12) -> lr %rx,%ry + bcr 0,0 - l %rx,0(%r12,%ry) -> lr %rx,%ry + bcr 0,0 */ - unsigned int insn, ry; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if ((insn & 0xff00f000) == 0x58000000) - /* l %rx,0(%ry,0) -> lr %rx,%ry + bcr 0,0 */ - ry = (insn & 0x000f0000); - else if ((insn & 0xff0f0000) == 0x58000000) - /* l %rx,0(0,%ry) -> lr %rx,%ry + bcr 0,0 */ - ry = (insn & 0x0000f000) << 4; - else if ((insn & 0xff00f000) == 0x5800c000) - /* l %rx,0(%ry,%r12) -> lr %rx,%ry + bcr 0,0 */ - ry = (insn & 0x000f0000); - else if ((insn & 0xff0f0000) == 0x580c0000) - /* l %rx,0(%r12,%ry) -> lr %rx,%ry + bcr 0,0 */ - ry = (insn & 0x0000f000) << 4; - else - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - insn = 0x18000700 | (insn & 0x00f00000) | ry; - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); - } - } - else if (r_type == R_390_TLS_GDCALL) - { - unsigned int insn; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if ((insn & 0xff000fff) != 0x4d000000 && - (insn & 0xffff0000) != 0xc0e50000 && - (insn & 0xff000000) != 0x0d000000) - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) - { - if ((insn & 0xff000000) == 0x0d000000) - { - /* GD->LE transition. - basr rx, ry -> nopr r7 */ - insn = 0x07070000 | (insn & 0xffff); - } - else if ((insn & 0xff000000) == 0x4d000000) - { - /* GD->LE transition. - bas %r14,0(%rx,%r13) -> bc 0,0 */ - insn = 0x47000000; - } - else - { - /* GD->LE transition. - brasl %r14,_tls_get_offset@plt -> brcl 0,. */ - insn = 0xc0040000; - bfd_put_16 (output_bfd, 0x0000, - contents + rel->r_offset + 4); - } - } - else - { - /* If basr is used in the pic case to invoke - _tls_get_offset, something went wrong before. */ - if ((insn & 0xff000000) == 0x0d000000) - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - - if ((insn & 0xff000000) == 0x4d000000) - { - /* GD->IE transition. - bas %r14,0(%rx,%r13) -> l %r2,0(%r2,%r12) */ - insn = 0x5822c000; - } - else - { - /* GD->IE transition. - brasl %r14,__tls_get_addr@plt -> - l %r2,0(%r2,%r12) ; bcr 0,0 */ - insn = 0x5822c000; - bfd_put_16 (output_bfd, 0x0700, - contents + rel->r_offset + 4); - } - } - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); - } - else if (r_type == R_390_TLS_LDCALL) - { - if (!bfd_link_pic (info)) - { - unsigned int insn; - - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if ((insn & 0xff000fff) != 0x4d000000 && - (insn & 0xffff0000) != 0xc0e50000 && - (insn & 0xff000000) != 0x0d000000) - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - - if ((insn & 0xff000000) == 0x0d000000) - { - /* LD->LE transition. - basr rx, ry -> nopr r7 */ - insn = 0x07070000 | (insn & 0xffff); - } - else if ((insn & 0xff000000) == 0x4d000000) - { - /* LD->LE transition. - bas %r14,0(%rx,%r13) -> bc 0,0 */ - insn = 0x47000000; - } - else - { - /* LD->LE transition. - brasl %r14,__tls_get_offset@plt -> brcl 0,. */ - insn = 0xc0040000; - bfd_put_16 (output_bfd, 0x0000, - contents + rel->r_offset + 4); - } - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); - } - } - continue; - - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - - do_relocation: - - /* When applying a 24 bit reloc we need to start one byte - earlier. Otherwise the 32 bit get/put bfd operations might - access a byte after the actual section. */ - if (r_type == R_390_PC24DBL - || r_type == R_390_PLT24DBL) - rel->r_offset--; - - if (r_type == R_390_20 - || r_type == R_390_GOT20 - || r_type == R_390_GOTPLT20 - || r_type == R_390_TLS_GOTIE20) - { - relocation += rel->r_addend; - relocation = (relocation&0xfff) << 8 | (relocation&0xff000) >> 12; - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, 0); - } - else - 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) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), - input_bfd, input_section, - rel->r_offset, name, (int) r); - return FALSE; - } - } - } - - return TRUE; -} - -/* Generate the PLT slots together with the dynamic relocations needed - for IFUNC symbols. */ - -static void -elf_s390_finish_ifunc_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - struct elf_s390_link_hash_table *htab, - bfd_vma iplt_offset, - bfd_vma resolver_address) -{ - bfd_vma iplt_index; - bfd_vma got_offset; - bfd_vma igotiplt_offset; - Elf_Internal_Rela rela; - bfd_byte *loc; - asection *plt, *gotplt, *relplt; - bfd_vma relative_offset; - - if (htab->elf.iplt == NULL - || htab->elf.igotplt == NULL - || htab->elf.irelplt == NULL) - abort (); - - gotplt = htab->elf.igotplt; - relplt = htab->elf.irelplt; - - /* Index of the PLT slot within iplt section. */ - iplt_index = iplt_offset / PLT_ENTRY_SIZE; - plt = htab->elf.iplt; - /* Offset into the igot.plt section. */ - igotiplt_offset = iplt_index * GOT_ENTRY_SIZE; - /* Offset into the got section. */ - got_offset = igotiplt_offset + gotplt->output_offset; - - /* S390 uses halfwords for relative branch calc! */ - relative_offset = - (plt->output_offset + - (PLT_ENTRY_SIZE * iplt_index) + 18) / 2; - /* If offset is > 32768, branch to a previous branch - 390 can only handle +-64 K jumps. */ - if ( -32768 > (int) relative_offset ) - relative_offset - = -(unsigned) (((65536 / PLT_ENTRY_SIZE - 1) * PLT_ENTRY_SIZE) / 2); - - /* Fill in the entry in the procedure linkage table. */ - if (!bfd_link_pic (info)) - { - memcpy (plt->contents + iplt_offset, elf_s390_plt_entry, - PLT_ENTRY_SIZE); - - /* Adjust jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - plt->contents + iplt_offset + 20); - - /* Push the GOT offset field. */ - bfd_put_32 (output_bfd, - (gotplt->output_section->vma - + got_offset), - plt->contents + iplt_offset + 24); - } - else if (got_offset < 4096) - { - /* The GOT offset is small enough to be used directly as - displacement. */ - memcpy (plt->contents + iplt_offset, - elf_s390_plt_pic12_entry, - PLT_ENTRY_SIZE); - - /* Put in the GOT offset as displacement value. The 0xc000 - value comes from the first word of the plt entry. Look - at the elf_s390_plt_pic16_entry content. */ - bfd_put_16 (output_bfd, (bfd_vma)0xc000 | got_offset, - plt->contents + iplt_offset + 2); - - /* Adjust the jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - plt->contents + iplt_offset + 20); - } - else if (got_offset < 32768) - { - /* The GOT offset is too big for a displacement but small - enough to be a signed 16 bit immediate value as it can be - used in an lhi instruction. */ - memcpy (plt->contents + iplt_offset, - elf_s390_plt_pic16_entry, - PLT_ENTRY_SIZE); - - /* Put in the GOT offset for the lhi instruction. */ - bfd_put_16 (output_bfd, (bfd_vma)got_offset, - plt->contents + iplt_offset + 2); - - /* Adjust the jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - plt->contents + iplt_offset + 20); - } - else - { - memcpy (plt->contents + iplt_offset, - elf_s390_plt_pic_entry, - PLT_ENTRY_SIZE); - - /* Adjust the jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - plt->contents + iplt_offset + 20); - - /* Push the GOT offset field. */ - bfd_put_32 (output_bfd, got_offset, - plt->contents + iplt_offset + 24); - } - /* Insert offset into reloc. table here. */ - bfd_put_32 (output_bfd, relplt->output_offset + - iplt_index * RELA_ENTRY_SIZE, - plt->contents + iplt_offset + 28); - - /* Fill in the entry in the global offset table. - Points to instruction after GOT offset. */ - bfd_put_32 (output_bfd, - (plt->output_section->vma - + plt->output_offset - + iplt_offset - + 12), - gotplt->contents + igotiplt_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = gotplt->output_section->vma + got_offset; - - if (!h - || h->dynindx == -1 - || ((bfd_link_executable (info) - || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - && h->def_regular)) - { - /* The symbol can be locally resolved. */ - rela.r_info = ELF32_R_INFO (0, R_390_IRELATIVE); - rela.r_addend = resolver_address; - } - else - { - rela.r_info = ELF32_R_INFO (h->dynindx, R_390_JMP_SLOT); - rela.r_addend = 0; - } - - loc = relplt->contents + iplt_index * RELA_ENTRY_SIZE; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_s390_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_s390_link_hash_table *htab; - struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h; - - htab = elf_s390_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; - bfd_vma relative_offset; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - if (s390_is_ifunc_symbol_p (h) && h->def_regular) - { - elf_s390_finish_ifunc_symbol (output_bfd, info, h, - htab, h->plt.offset, - eh->ifunc_resolver_address + - eh->ifunc_resolver_section->output_offset + - eh->ifunc_resolver_section->output_section->vma); - /* Do not return yet. Handling of explicit GOT slots of - IFUNC symbols is below. */ - } - else - { - if (h->dynindx == -1 - || htab->elf.splt == NULL - || htab->elf.sgotplt == NULL - || htab->elf.srelplt == NULL) - abort (); - - /* Calc. index no. - Current offset - size first entry / entry size. */ - plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) / PLT_ENTRY_SIZE; - - /* Offset in GOT is PLT index plus GOT headers(3) times 4, - addr & GOT addr. */ - got_offset = (plt_index + 3) * GOT_ENTRY_SIZE; - - /* S390 uses halfwords for relative branch calc! */ - relative_offset = - ((PLT_FIRST_ENTRY_SIZE + - (PLT_ENTRY_SIZE * plt_index) + 18) / 2); - /* If offset is > 32768, branch to a previous branch - 390 can only handle +-64 K jumps. */ - if ( -32768 > (int) relative_offset ) - relative_offset - = -(unsigned) (((65536 / PLT_ENTRY_SIZE - 1) * PLT_ENTRY_SIZE) / 2); - - /* Fill in the entry in the procedure linkage table. */ - if (!bfd_link_pic (info)) - { - memcpy (htab->elf.splt->contents + h->plt.offset, elf_s390_plt_entry, - PLT_ENTRY_SIZE); - - /* Adjust jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - htab->elf.splt->contents + h->plt.offset + 20); - - /* Push the GOT offset field. */ - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + got_offset), - htab->elf.splt->contents + h->plt.offset + 24); - } - else if (got_offset < 4096) - { - /* The GOT offset is small enough to be used directly as - displacement. */ - memcpy (htab->elf.splt->contents + h->plt.offset, - elf_s390_plt_pic12_entry, - PLT_ENTRY_SIZE); - - /* Put in the GOT offset as displacement value. The 0xc000 - value comes from the first word of the plt entry. Look - at the elf_s390_plt_pic12_entry content. */ - bfd_put_16 (output_bfd, (bfd_vma)0xc000 | got_offset, - htab->elf.splt->contents + h->plt.offset + 2); - - /* Adjust the jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - htab->elf.splt->contents + h->plt.offset + 20); - } - else if (got_offset < 32768) - { - /* The GOT offset is too big for a displacement but small - enough to be a signed 16 bit immediate value as it can be - used in an lhi instruction. */ - memcpy (htab->elf.splt->contents + h->plt.offset, - elf_s390_plt_pic16_entry, - PLT_ENTRY_SIZE); - - /* Put in the GOT offset for the lhi instruction. */ - bfd_put_16 (output_bfd, (bfd_vma)got_offset, - htab->elf.splt->contents + h->plt.offset + 2); - - /* Adjust the jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - htab->elf.splt->contents + h->plt.offset + 20); - } - else - { - memcpy (htab->elf.splt->contents + h->plt.offset, - elf_s390_plt_pic_entry, - PLT_ENTRY_SIZE); - - /* Adjust the jump to the first plt entry. */ - bfd_put_32 (output_bfd, (bfd_vma) 0+(relative_offset << 16), - htab->elf.splt->contents + h->plt.offset + 20); - - /* Push the GOT offset field. */ - bfd_put_32 (output_bfd, got_offset, - htab->elf.splt->contents + h->plt.offset + 24); - } - /* Insert offset into reloc. table here. */ - bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela), - htab->elf.splt->contents + h->plt.offset + 28); - - /* Fill in the entry in the global offset table. - Points to instruction after GOT offset. */ - bfd_put_32 (output_bfd, - (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset - + 12), - htab->elf.sgotplt->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_390_JMP_SLOT); - rela.r_addend = 0; - loc = htab->elf.srelplt->contents + plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. This is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library. */ - sym->st_shndx = SHN_UNDEF; - } - } - } - - if (h->got.offset != (bfd_vma) -1 - && elf_s390_hash_entry(h)->tls_type != GOT_TLS_GD - && elf_s390_hash_entry(h)->tls_type != GOT_TLS_IE - && elf_s390_hash_entry(h)->tls_type != GOT_TLS_IE_NLT) - { - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL) - abort (); - - rela.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.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 (h->def_regular && s390_is_ifunc_symbol_p (h)) - { - if (bfd_link_pic (info)) - { - /* An explicit GOT slot usage needs GLOB_DAT. If the - symbol references local the implicit got.iplt slot - will be used and the IRELATIVE reloc has been created - above. */ - goto do_glob_dat; - } - else - { - /* For non-shared objects explicit GOT slots must be - filled with the PLT slot address for pointer - equality reasons. */ - bfd_put_32 (output_bfd, (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset), - htab->elf.sgot->contents + h->got.offset); - return TRUE; - } - } - else if (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - { - /* 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 (!(h->def_regular || ELF_COMMON_DEF_P (h))) - return FALSE; - BFD_ASSERT((h->got.offset & 1) != 0); - rela.r_info = ELF32_R_INFO (0, R_390_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); - do_glob_dat: - bfd_put_32 (output_bfd, (bfd_vma) 0, htab->elf.sgot->contents + h->got.offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_390_GLOB_DAT); - rela.r_addend = 0; - } - - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - if (h->needs_copy) - { - Elf_Internal_Rela rela; - asection *s; - bfd_byte *loc; - - /* This symbols 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->elf.srelbss == NULL - || htab->elf.sreldynrelro == 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 = ELF32_R_INFO (h->dynindx, R_390_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark some specially defined symbols as absolute. */ - if (h == htab->elf.hdynamic - || h == htab->elf.hgot - || h == htab->elf.hplt) - 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_s390_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - bfd *abfd = info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info); - unsigned long r_symndx = ELF32_R_SYM (rela->r_info); - Elf_Internal_Sym sym; - - if (htab->elf.dynsym == NULL - || !bed->s->swap_symbol_in (abfd, - (htab->elf.dynsym->contents - + r_symndx * bed->s->sizeof_sym), - 0, &sym)) - abort (); - - /* Check relocation against STT_GNU_IFUNC symbol. */ - if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) - return reloc_class_ifunc; - - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_390_RELATIVE: - return reloc_class_relative; - case R_390_JMP_SLOT: - return reloc_class_plt; - case R_390_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf_s390_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_s390_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - bfd *ibfd; - unsigned int i; - - htab = elf_s390_hash_table (info); - dynobj = htab->elf.dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->elf.dynamic_sections_created) - { - Elf32_External_Dyn *dyncon, *dynconend; - - if (sdyn == NULL || htab->elf.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->elf.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_JMPREL: - s = htab->elf.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = htab->elf.srelplt->size; - if (htab->elf.irelplt) - dyn.d_un.d_val += htab->elf.irelplt->size; - break; - } - - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - /* Fill in the special first entry in the procedure linkage table. */ - if (htab->elf.splt && htab->elf.splt->size > 0) - { - memset (htab->elf.splt->contents, 0, PLT_FIRST_ENTRY_SIZE); - if (bfd_link_pic (info)) - { - memcpy (htab->elf.splt->contents, elf_s390_plt_pic_first_entry, - PLT_FIRST_ENTRY_SIZE); - } - else - { - memcpy (htab->elf.splt->contents, elf_s390_plt_first_entry, - PLT_FIRST_ENTRY_SIZE); - bfd_put_32 (output_bfd, - htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset, - htab->elf.splt->contents + 24); - } - elf_section_data (htab->elf.splt->output_section) - ->this_hdr.sh_entsize = 4; - } - - } - - if (htab->elf.sgotplt) - { - /* Fill in the first three entries in the global offset table. */ - if (htab->elf.sgotplt->size > 0) - { - bfd_put_32 (output_bfd, - (sdyn == NULL ? (bfd_vma) 0 - : sdyn->output_section->vma + sdyn->output_offset), - htab->elf.sgotplt->contents); - /* One entry for shared object struct ptr. */ - bfd_put_32 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 4); - /* One entry for _dl_runtime_resolve. */ - bfd_put_32 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 8); - } - - elf_section_data (htab->elf.sgotplt->output_section) - ->this_hdr.sh_entsize = 4; - } - /* Finish dynamic symbol for local IFUNC symbols. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - struct plt_entry *local_plt; - Elf_Internal_Sym *isym; - Elf_Internal_Shdr *symtab_hdr; - - symtab_hdr = &elf_symtab_hdr (ibfd); - - if (!is_s390_elf (ibfd)) - continue; - - local_plt = elf_s390_local_plt (ibfd); - if (local_plt != NULL) - for (i = 0; i < symtab_hdr->sh_info; i++) - { - if (local_plt[i].plt.offset != (bfd_vma) -1) - { - asection *sec = local_plt[i].sec; - isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, i); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - elf_s390_finish_ifunc_symbol (output_bfd, info, NULL, htab, - local_plt[i].plt.offset, - isym->st_value - + sec->output_section->vma - + sec->output_offset); - - } - } - } - return TRUE; -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf_s390_grok_prstatus (bfd * abfd, Elf_Internal_Note * note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 224: /* S/390 Linux. */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 144; - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf_s390_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* sizeof(struct elf_prpsinfo) on s390 */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 12); - 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); - break; - } - - /* 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; -} - -static char * -elf_s390_write_core_note (bfd *abfd, char *buf, int *bufsiz, - int note_type, ...) -{ - va_list ap; - - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - { - char data[124] = { 0 }; - const char *fname, *psargs; - - va_start (ap, note_type); - fname = va_arg (ap, const char *); - psargs = va_arg (ap, const char *); - va_end (ap); - - strncpy (data + 28, fname, 16); - strncpy (data + 44, psargs, 80); - return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type, - &data, sizeof (data)); - } - - case NT_PRSTATUS: - { - char data[224] = { 0 }; - long pid; - int cursig; - const void *gregs; - - va_start (ap, note_type); - pid = va_arg (ap, long); - cursig = va_arg (ap, int); - gregs = va_arg (ap, const void *); - va_end (ap); - - bfd_put_16 (abfd, cursig, data + 12); - bfd_put_32 (abfd, pid, data + 24); - memcpy (data + 72, gregs, 144); - return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type, - &data, sizeof (data)); - } - } - /* NOTREACHED */ -} - -/* 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_s390_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + PLT_FIRST_ENTRY_SIZE + i * PLT_ENTRY_SIZE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf32_s390_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - - if (!is_s390_elf (ibfd) || !is_s390_elf (obfd)) - return TRUE; - - if (!elf_s390_merge_obj_attributes (ibfd, info)) - return FALSE; - - elf_elfheader (obfd)->e_flags |= elf_elfheader (ibfd)->e_flags; - return TRUE; -} - - -#define TARGET_BIG_SYM s390_elf32_vec -#define TARGET_BIG_NAME "elf32-s390" -#define ELF_ARCH bfd_arch_s390 -#define ELF_TARGET_ID S390_ELF_DATA -#define ELF_MACHINE_CODE EM_S390 -#define ELF_MACHINE_ALT1 EM_S390_OLD -#define ELF_MAXPAGESIZE 0x1000 - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 - -#define elf_info_to_howto elf_s390_info_to_howto - -#define bfd_elf32_bfd_is_local_label_name elf_s390_is_local_label_name -#define bfd_elf32_bfd_link_hash_table_create elf_s390_link_hash_table_create -#define bfd_elf32_bfd_reloc_type_lookup elf_s390_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf_s390_reloc_name_lookup - -#define bfd_elf32_bfd_merge_private_bfd_data elf32_s390_merge_private_bfd_data - -#define elf_backend_adjust_dynamic_symbol elf_s390_adjust_dynamic_symbol -#define elf_backend_check_relocs elf_s390_check_relocs -#define elf_backend_copy_indirect_symbol elf_s390_copy_indirect_symbol -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections elf_s390_finish_dynamic_sections -#define elf_backend_finish_dynamic_symbol elf_s390_finish_dynamic_symbol -#define elf_backend_gc_mark_hook elf_s390_gc_mark_hook -#define elf_backend_reloc_type_class elf_s390_reloc_type_class -#define elf_backend_relocate_section elf_s390_relocate_section -#define elf_backend_size_dynamic_sections elf_s390_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_grok_prstatus elf_s390_grok_prstatus -#define elf_backend_grok_psinfo elf_s390_grok_psinfo -#define elf_backend_write_core_note elf_s390_write_core_note -#define elf_backend_plt_sym_val elf_s390_plt_sym_val -#define elf_backend_add_symbol_hook elf_s390_add_symbol_hook -#define elf_backend_sort_relocs_p elf_s390_elf_sort_relocs_p - -#define bfd_elf32_mkobject elf_s390_mkobject -#define elf_backend_object_p elf_s390_object_p - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-score.c b/sdcc/support/sdbinutils/bfd/elf32-score.c deleted file mode 100644 index 897ab8a3f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-score.c +++ /dev/null @@ -1,4504 +0,0 @@ -/* 32-bit ELF support for S+core. - Copyright (C) 2006-2018 Free Software Foundation, Inc. - Contributed by - Brain.lin (brain.lin@sunplusct.com) - Mei Ligang (ligang@sunnorth.com.cn) - Pei-Lin Tsai (pltsai@sunplus.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" -#include "elf-bfd.h" -#include "elf/score.h" -#include "elf/common.h" -#include "elf/internal.h" -#include "hashtab.h" -#include "elf32-score.h" - - -int score3 = 0; -int score7 = 1; - -/* The SCORE ELF linker needs additional information for each symbol in - the global hash table. */ -struct score_elf_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol. */ - unsigned int possibly_dynamic_relocs; - - /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section. */ - bfd_boolean readonly_reloc; - - /* We must not create a stub for a symbol that has relocations related to - taking the function's address, i.e. any but R_SCORE_CALL15 ones. */ - bfd_boolean no_fn_stub; - - /* Are we forced local? This will only be set if we have converted - the initial global GOT entry to a local GOT entry. */ - bfd_boolean forced_local; -}; - -/* Traverse a score ELF linker hash table. */ -#define score_elf_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - ((table), \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* This structure is used to hold .got entries while estimating got sizes. */ -struct score_got_entry -{ - /* The input bfd in which the symbol is defined. */ - bfd *abfd; - /* The index of the symbol, as stored in the relocation r_info, if - we have a local symbol; -1 otherwise. */ - long symndx; - union - { - /* If abfd == NULL, an address that must be stored in the got. */ - bfd_vma address; - /* If abfd != NULL && symndx != -1, the addend of the relocation - that should be added to the symbol value. */ - bfd_vma addend; - /* If abfd != NULL && symndx == -1, the hash table entry - corresponding to a global symbol in the got (or, local, if - h->forced_local). */ - struct score_elf_link_hash_entry *h; - } d; - - /* The offset from the beginning of the .got section to the entry - corresponding to this symbol+addend. If it's a global symbol - whose offset is yet to be decided, it's going to be -1. */ - long gotidx; -}; - -/* This structure is passed to score_elf_sort_hash_table_f when sorting - the dynamic symbols. */ - -struct score_elf_hash_sort_data -{ - /* The symbol in the global GOT with the lowest dynamic symbol table index. */ - struct elf_link_hash_entry *low; - /* The least dynamic symbol table index corresponding to a symbol with a GOT entry. */ - long min_got_dynindx; - /* The greatest dynamic symbol table index corresponding to a symbol - with a GOT entry that is not referenced (e.g., a dynamic symbol - with dynamic relocations pointing to it from non-primary GOTs). */ - long max_unref_got_dynindx; - /* The greatest dynamic symbol table index not corresponding to a - symbol without a GOT entry. */ - long max_non_got_dynindx; -}; - -struct score_got_info -{ - /* The global symbol in the GOT with the lowest index in the dynamic - symbol table. */ - struct elf_link_hash_entry *global_gotsym; - /* The number of global .got entries. */ - unsigned int global_gotno; - /* The number of local .got entries. */ - unsigned int local_gotno; - /* The number of local .got entries we have used. */ - unsigned int assigned_gotno; - /* A hash table holding members of the got. */ - struct htab *got_entries; - /* In multi-got links, a pointer to the next got (err, rather, most - of the time, it points to the previous got). */ - struct score_got_info *next; -}; - -/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal. */ -struct _score_elf_section_data -{ - struct bfd_elf_section_data elf; - union - { - struct score_got_info *got_info; - bfd_byte *tdata; - } - u; -}; - -#define score_elf_section_data(sec) \ - ((struct _score_elf_section_data *) elf_section_data (sec)) - -/* The size of a symbol-table entry. */ -#define SCORE_ELF_SYM_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->sizeof_sym) - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) -#define MINUS_TWO (((bfd_vma)0) - 2) - -#define PDR_SIZE 32 - - -/* The number of local .got entries we reserve. */ -#define SCORE_RESERVED_GOTNO (2) -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -/* The offset of $gp from the beginning of the .got section. */ -#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0) -/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp. */ -#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff) - -#define SCORE_ELF_STUB_SECTION_NAME (".SCORE.stub") -#define SCORE_FUNCTION_STUB_SIZE (16) - -#define STUB_LW 0xc3bcc010 /* lw r29, [r28, -0x3ff0] */ -#define STUB_MOVE 0x8363bc56 /* mv r27, r3 */ -#define STUB_LI16 0x87548000 /* ori r26, .dynsym_index */ -#define STUB_BRL 0x801dbc09 /* brl r29 */ - -#define SCORE_ELF_GOT_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->arch_size / 8) - -#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \ - (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val)) - -/* The size of an external dynamic table entry. */ -#define SCORE_ELF_DYN_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->sizeof_dyn) - -/* The size of an external REL relocation. */ -#define SCORE_ELF_REL_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->sizeof_rel) - -/* The default alignment for sections, as a power of two. */ -#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ - (get_elf_backend_data (abfd)->s->log_file_align) - -static bfd_byte *hi16_rel_addr; - -/* This will be used when we sort the dynamic relocation records. */ -static bfd *reldyn_sorting_bfd; - -/* SCORE ELF uses two common sections. One is the usual one, and the - other is for small objects. All the small objects are kept - together, and then referenced via the gp pointer, which yields - faster assembler code. This is what we use for the small common - section. This approach is copied from ecoff.c. */ -static asection score_elf_scom_section; -static asymbol score_elf_scom_symbol; -static asymbol *score_elf_scom_symbol_ptr; - -static bfd_vma -score_bfd_get_16 (bfd *abfd, const void *data) -{ - return bfd_get_16 (abfd, data); -} - -static bfd_vma -score3_bfd_getl32 (const void *p) -{ - const bfd_byte *addr = p; - unsigned long v; - - v = (unsigned long) addr[2]; - v |= (unsigned long) addr[3] << 8; - v |= (unsigned long) addr[0] << 16; - v |= (unsigned long) addr[1] << 24; - return v; -} - -static bfd_vma -score3_bfd_getl48 (const void *p) -{ - const bfd_byte *addr = p; - bfd_uint64_t v; - - v = (bfd_uint64_t) addr[4]; - v |= (bfd_uint64_t) addr[5] << 8; - v |= (bfd_uint64_t) addr[2] << 16; - v |= (bfd_uint64_t) addr[3] << 24; - v |= (bfd_uint64_t) addr[0] << 32; - v |= (bfd_uint64_t) addr[1] << 40; - return v; -} - -static bfd_vma -score_bfd_get_32 (bfd *abfd, const void *data) -{ - if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) - return score3_bfd_getl32 (data); - else - return bfd_get_32 (abfd, data); -} - -static bfd_vma -score_bfd_get_48 (bfd *abfd, const void *p) -{ - if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) - return score3_bfd_getl48 (p); - else - return bfd_get_bits (p, 48, 1); -} - -static void -score_bfd_put_16 (bfd *abfd, bfd_vma addr, void *data) -{ - return bfd_put_16 (abfd, addr, data); -} - -static void -score3_bfd_putl32 (bfd_vma data, void *p) -{ - bfd_byte *addr = p; - addr[0] = (data >> 16) & 0xff; - addr[1] = (data >> 24) & 0xff; - addr[2] = data & 0xff; - addr[3] = (data >> 8) & 0xff; -} - -static void -score3_bfd_putl48 (bfd_vma data, void *p) -{ - bfd_byte *addr = p; - addr[0] = (data >> 32) & 0xff; - addr[1] = (data >> 40) & 0xff; - addr[2] = (data >> 16) & 0xff; - addr[3] = (data >> 24) & 0xff; - addr[4] = data & 0xff; - addr[5] = (data >> 8) & 0xff; -} - -static void -score_bfd_put_32 (bfd *abfd, bfd_vma addr, void *data) -{ - if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) - return score3_bfd_putl32 (addr, data); - else - return bfd_put_32 (abfd, addr, data); -} - -static void -score_bfd_put_48 (bfd *abfd, bfd_vma val, void *p) -{ - if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE) - return score3_bfd_putl48 (val, p); - else - return bfd_put_bits (val, p, 48, 1); -} - -static bfd_reloc_status_type -score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -score_elf_lo16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma addend = 0, offset = 0; - unsigned long val; - unsigned long hi16_offset, hi16_value, uvalue; - - hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr); - hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; - addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; - val = reloc_entry->addend; - if (reloc_entry->address > input_section->size) - return bfd_reloc_outofrange; - uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); - offset = (uvalue & 0xffff) << 1; - addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ - -static bfd_boolean -score_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) -{ - unsigned int count; - asymbol **sym; - unsigned int i; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - /* The linker script will have created a symbol named `_gp' with the - appropriate value. */ - if (sym == NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - *pgp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, *pgp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - return TRUE; -} - -/* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ -static bfd_reloc_status_type -score_elf_final_gp (bfd *output_bfd, - asymbol *symbol, - bfd_boolean relocatable, - char **error_message, - bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) - && ! relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 - && (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma + 0x4000; - _bfd_set_gp_value (output_bfd, *pgp); - } - else if (!score_elf_assign_gp (output_bfd, pgp)) - { - *error_message = - (char *) _("GP relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -score_elf_gprel15_with_gp (bfd *abfd, - asymbol *symbol, - arelent *reloc_entry, - asection *input_section, - bfd_boolean relocateable, - void * data, - bfd_vma gp ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - unsigned long insn; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - if (reloc_entry->address > input_section->size) - return bfd_reloc_outofrange; - - insn = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - if (((reloc_entry->addend & 0xffffc000) != 0) - && ((reloc_entry->addend & 0xffffc000) != 0xffffc000)) - return bfd_reloc_overflow; - - insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff); - score_bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); - if (relocateable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, - asection *input_section, bfd_boolean relocatable, - void *data, bfd_vma gp) -{ - bfd_vma relocation; - bfd_vma val; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Set val to the offset into the section or symbol. */ - val = reloc_entry->addend; - - if (reloc_entry->howto->partial_inplace) - val += score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - - /* Adjust val for the final section location and GP value. If we - are producing relocatable output, we don't want to do this for - an external symbol. */ - if (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0) - val += relocation - gp; - - if (reloc_entry->howto->partial_inplace) - score_bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); - else - reloc_entry->addend = val; - - if (relocatable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -score_elf_gprel15_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocateable; - bfd_reloc_status_type ret; - bfd_vma gp; - - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - if (output_bfd != NULL) - relocateable = TRUE; - else - { - relocateable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - - return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry, - input_section, relocateable, data, gp); -} - -/* Do a R_SCORE_GPREL32 relocation. This is a 32 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* R_SCORE_GPREL32 relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("32bits gp relative relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - - gp = 0; - return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, - relocatable, data, gp); -} - -/* A howto special_function for R_SCORE_GOT15 relocations. This is just - like any other 16-bit relocation when applied to global symbols, but is - treated in the same as R_SCORE_HI16 when applied to local symbols. */ -static bfd_reloc_status_type -score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 - || bfd_is_und_section (bfd_get_section (symbol)) - || bfd_is_com_section (bfd_get_section (symbol))) - /* The relocation is against a global symbol. */ - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, - error_message); - - return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - -static bfd_reloc_status_type -score_elf_got_lo16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma addend = 0, offset = 0; - signed long val; - signed long hi16_offset, hi16_value, uvalue; - - hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr); - hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; - addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; - val = reloc_entry->addend; - if (reloc_entry->address > input_section->size) - return bfd_reloc_outofrange; - uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - if ((uvalue > -0x8000) && (uvalue < 0x7fff)) - hi16_offset = 0; - else - hi16_offset = (uvalue >> 16) & 0x7fff; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); - offset = (uvalue & 0xffff) << 1; - addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -static reloc_howto_type elf32_score_howto_table[] = -{ - /* No relocation. */ - HOWTO (R_SCORE_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_HI16 */ - HOWTO (R_SCORE_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_hi16_reloc, /* special_function */ - "R_SCORE_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x37fff, /* src_mask */ - 0x37fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_LO16 */ - HOWTO (R_SCORE_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_lo16_reloc, /* special_function */ - "R_SCORE_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x37fff, /* src_mask */ - 0x37fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_BCMP */ - HOWTO (R_SCORE_BCMP, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_BCMP", /* name */ - FALSE, /* partial_inplace */ - 0x03e00381, /* src_mask */ - 0x03e00381, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /*R_SCORE_24 */ - HOWTO (R_SCORE_24, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_24", /* name */ - FALSE, /* partial_inplace */ - 0x3ff7fff, /* src_mask */ - 0x3ff7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /*R_SCORE_PC19 */ - HOWTO (R_SCORE_PC19, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_PC19", /* name */ - FALSE, /* partial_inplace */ - 0x3ff03fe, /* src_mask */ - 0x3ff03fe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /*R_SCORE16_11 */ - HOWTO (R_SCORE16_11, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE16_11", /* name */ - FALSE, /* partial_inplace */ - 0x000000ffe, /* src_mask */ - 0x000000ffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE16_PC8 */ - HOWTO (R_SCORE16_PC8, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE16_PC8", /* name */ - FALSE, /* partial_inplace */ - 0x000001ff, /* src_mask */ - 0x000001ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute */ - HOWTO (R_SCORE_ABS32, /* type 8 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_ABS32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit absolute */ - HOWTO (R_SCORE_ABS16, /* type 11 */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_DUMMY2 */ - HOWTO (R_SCORE_DUMMY2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_DUMMY2", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_GP15 */ - HOWTO (R_SCORE_GP15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_gprel15_reloc,/* special_function */ - "R_SCORE_GP15", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_SCORE_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_SCORE_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_SCORE_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_SCORE_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_SCORE_GOT15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - score_elf_got15_reloc, /* special_function */ - "R_SCORE_GOT15", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_SCORE_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_got_lo16_reloc, /* special_function */ - "R_SCORE_GOT_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x37ffe, /* src_mask */ - 0x37ffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 15 bit call through global offset table. */ - HOWTO (R_SCORE_CALL15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_CALL15", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_SCORE_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_gprel32_reloc, /* special_function */ - "R_SCORE_GPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_SCORE_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_REL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_DUMMY_HI16 */ - HOWTO (R_SCORE_DUMMY_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_hi16_reloc, /* special_function */ - "R_SCORE_DUMMY_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x37fff, /* src_mask */ - 0x37fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_IMM30 */ - HOWTO (R_SCORE_IMM30, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 30, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_IMM30", /* name */ - FALSE, /* partial_inplace */ - 0x7f7fff7f80LL, /* src_mask */ - 0x7f7fff7f80LL, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_IMM32 */ - HOWTO (R_SCORE_IMM32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 5, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_IMM32", /* name */ - FALSE, /* partial_inplace */ - 0x7f7fff7fe0LL, /* src_mask */ - 0x7f7fff7fe0LL, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -struct score_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct score_reloc_map elf32_score_reloc_map[] = -{ - {BFD_RELOC_NONE, R_SCORE_NONE}, - {BFD_RELOC_HI16_S, R_SCORE_HI16}, - {BFD_RELOC_LO16, R_SCORE_LO16}, - {BFD_RELOC_SCORE_BCMP, R_SCORE_BCMP}, - {BFD_RELOC_SCORE_JMP, R_SCORE_24}, - {BFD_RELOC_SCORE_BRANCH, R_SCORE_PC19}, - {BFD_RELOC_SCORE16_JMP, R_SCORE16_11}, - {BFD_RELOC_SCORE16_BRANCH, R_SCORE16_PC8}, - {BFD_RELOC_32, R_SCORE_ABS32}, - {BFD_RELOC_16, R_SCORE_ABS16}, - {BFD_RELOC_SCORE_DUMMY2, R_SCORE_DUMMY2}, - {BFD_RELOC_SCORE_GPREL15, R_SCORE_GP15}, - {BFD_RELOC_VTABLE_INHERIT, R_SCORE_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_SCORE_GNU_VTENTRY}, - {BFD_RELOC_SCORE_GOT15, R_SCORE_GOT15}, - {BFD_RELOC_SCORE_GOT_LO16, R_SCORE_GOT_LO16}, - {BFD_RELOC_SCORE_CALL15, R_SCORE_CALL15}, - {BFD_RELOC_GPREL32, R_SCORE_GPREL32}, - {BFD_RELOC_32_PCREL, R_SCORE_REL32}, - {BFD_RELOC_SCORE_DUMMY_HI16, R_SCORE_DUMMY_HI16}, - {BFD_RELOC_SCORE_IMM30, R_SCORE_IMM30}, - {BFD_RELOC_SCORE_IMM32, R_SCORE_IMM32}, -}; - -/* got_entries only match if they're identical, except for gotidx, so - use all fields to compute the hash, and compare the appropriate - union members. */ -static hashval_t -score_elf_got_entry_hash (const void *entry_) -{ - const struct score_got_entry *entry = (struct score_got_entry *)entry_; - - return entry->symndx - + (!entry->abfd ? entry->d.address : entry->abfd->id); -} - -static int -score_elf_got_entry_eq (const void *entry1, const void *entry2) -{ - const struct score_got_entry *e1 = (struct score_got_entry *)entry1; - const struct score_got_entry *e2 = (struct score_got_entry *)entry2; - - return e1->abfd == e2->abfd && e1->symndx == e2->symndx - && (! e1->abfd ? e1->d.address == e2->d.address - : e1->symndx >= 0 ? e1->d.addend == e2->d.addend - : e1->d.h == e2->d.h); -} - -/* If H needs a GOT entry, assign it the highest available dynamic - index. Otherwise, assign it the lowest available dynamic - index. */ -static bfd_boolean -score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data) -{ - struct score_elf_hash_sort_data *hsd = data; - - /* Symbols without dynamic symbol table entries aren't interesting at all. */ - if (h->root.dynindx == -1) - return TRUE; - - /* Global symbols that need GOT entries that are not explicitly - referenced are marked with got offset 2. Those that are - referenced get a 1, and those that don't need GOT entries get - -1. */ - if (h->root.got.offset == 2) - { - if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx) - hsd->low = (struct elf_link_hash_entry *) h; - h->root.dynindx = hsd->max_unref_got_dynindx++; - } - else if (h->root.got.offset != 1) - h->root.dynindx = hsd->max_non_got_dynindx++; - else - { - h->root.dynindx = --hsd->min_got_dynindx; - hsd->low = (struct elf_link_hash_entry *) h; - } - - return TRUE; -} - -static asection * -score_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded) -{ - asection *sgot = bfd_get_linker_section (abfd, ".got"); - - if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0)) - return NULL; - return sgot; -} - -/* Returns the GOT information associated with the link indicated by - INFO. If SGOTP is non-NULL, it is filled in with the GOT section. */ -static struct score_got_info * -score_elf_got_info (bfd *abfd, asection **sgotp) -{ - asection *sgot; - struct score_got_info *g; - - sgot = score_elf_got_section (abfd, TRUE); - BFD_ASSERT (sgot != NULL); - BFD_ASSERT (elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - - if (sgotp) - *sgotp = sgot; - return g; -} - -/* Sort the dynamic symbol table so that symbols that need GOT entries - appear towards the end. This reduces the amount of GOT space - required. MAX_LOCAL is used to set the number of local symbols - known to be in the dynamic symbol table. During - s3_bfd_score_elf_size_dynamic_sections, this value is 1. Afterward, the - section symbols are added and the count is higher. */ -static bfd_boolean -score_elf_sort_hash_table (struct bfd_link_info *info, - unsigned long max_local) -{ - struct score_elf_hash_sort_data hsd; - struct score_got_info *g; - bfd *dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - g = score_elf_got_info (dynobj, NULL); - - hsd.low = NULL; - hsd.max_unref_got_dynindx = - hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount - /* In the multi-got case, assigned_gotno of the master got_info - indicate the number of entries that aren't referenced in the - primary GOT, but that must have entries because there are - dynamic relocations that reference it. Since they aren't - referenced, we move them to the end of the GOT, so that they - don't prevent other entries that are referenced from getting - too large offsets. */ - - (g->next ? g->assigned_gotno : 0); - hsd.max_non_got_dynindx = max_local; - score_elf_link_hash_traverse (elf_hash_table (info), - score_elf_sort_hash_table_f, - &hsd); - - /* There should have been enough room in the symbol table to - accommodate both the GOT and non-GOT symbols. */ - BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx); - BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx - <= elf_hash_table (info)->dynsymcount); - - /* Now we know which dynamic symbol has the lowest dynamic symbol - table index in the GOT. */ - g->global_gotsym = hsd.low; - - return TRUE; -} - -/* Create an entry in an score ELF linker hash table. */ - -static struct bfd_hash_entry * -score_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, sizeof (struct score_elf_link_hash_entry)); - if (ret == NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct score_elf_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - - if (ret != NULL) - { - ret->possibly_dynamic_relocs = 0; - ret->readonly_reloc = FALSE; - ret->no_fn_stub = FALSE; - ret->forced_local = FALSE; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Returns the first relocation of type r_type found, beginning with - RELOCATION. RELEND is one-past-the-end of the relocation table. */ -static const Elf_Internal_Rela * -score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, - const Elf_Internal_Rela *relocation, - const Elf_Internal_Rela *relend) -{ - while (relocation < relend) - { - if (ELF32_R_TYPE (relocation->r_info) == r_type) - return relocation; - - ++relocation; - } - - /* We didn't find it. */ - bfd_set_error (bfd_error_bad_value); - return NULL; -} - -/* This function is called via qsort() to sort the dynamic relocation - entries by increasing r_symndx value. */ -static int -score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2) -{ - Elf_Internal_Rela int_reloc1; - Elf_Internal_Rela int_reloc2; - - bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1); - bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2); - - return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info)); -} - -/* Return whether a relocation is against a local symbol. */ -static bfd_boolean -score_elf_local_relocation_p (bfd *input_bfd, - const Elf_Internal_Rela *relocation, - asection **local_sections, - bfd_boolean check_forced) -{ - unsigned long r_symndx; - Elf_Internal_Shdr *symtab_hdr; - struct score_elf_link_hash_entry *h; - size_t extsymoff; - - r_symndx = ELF32_R_SYM (relocation->r_info); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; - - if (r_symndx < extsymoff) - return TRUE; - if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL) - return TRUE; - - if (check_forced) - { - /* Look up the hash table to check whether the symbol was forced local. */ - h = (struct score_elf_link_hash_entry *) - elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; - /* Find the real hash-table entry for this symbol. */ - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; - if (h->root.forced_local) - return TRUE; - } - - return FALSE; -} - -/* Returns the dynamic relocation section for DYNOBJ. */ -static asection * -score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) -{ - static const char dname[] = ".rel.dyn"; - asection *sreloc; - - sreloc = bfd_get_linker_section (dynobj, dname); - if (sreloc == NULL && create_p) - { - sreloc = bfd_make_section_anyway_with_flags (dynobj, dname, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (sreloc == NULL - || ! bfd_set_section_alignment (dynobj, sreloc, - SCORE_ELF_LOG_FILE_ALIGN (dynobj))) - return NULL; - } - return sreloc; -} - -static void -score_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n) -{ - asection *s; - - s = score_elf_rel_dyn_section (abfd, FALSE); - BFD_ASSERT (s != NULL); - - if (s->size == 0) - { - /* Make room for a null element. */ - s->size += SCORE_ELF_REL_SIZE (abfd); - ++s->reloc_count; - } - s->size += n * SCORE_ELF_REL_SIZE (abfd); -} - -/* Create a rel.dyn relocation for the dynamic linker to resolve. REL - is the original relocation, which is now being transformed into a - dynamic relocation. The ADDENDP is adjusted if necessary; the - caller should store the result in place of the original addend. */ -static bfd_boolean -score_elf_create_dynamic_relocation (bfd *output_bfd, - struct bfd_link_info *info, - const Elf_Internal_Rela *rel, - struct score_elf_link_hash_entry *h, - bfd_vma symbol, - bfd_vma *addendp, asection *input_section) -{ - Elf_Internal_Rela outrel[3]; - asection *sreloc; - bfd *dynobj; - int r_type; - long indx; - bfd_boolean defined_p; - - r_type = ELF32_R_TYPE (rel->r_info); - dynobj = elf_hash_table (info)->dynobj; - sreloc = score_elf_rel_dyn_section (dynobj, FALSE); - BFD_ASSERT (sreloc != NULL); - BFD_ASSERT (sreloc->contents != NULL); - BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size); - - outrel[0].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset); - outrel[1].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset); - outrel[2].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); - - if (outrel[0].r_offset == MINUS_ONE) - /* The relocation field has been deleted. */ - return TRUE; - - if (outrel[0].r_offset == MINUS_TWO) - { - /* The relocation field has been converted into a relative value of - some sort. Functions like _bfd_elf_write_section_eh_frame expect - the field to be fully relocated, so add in the symbol's value. */ - *addendp += symbol; - return TRUE; - } - - /* We must now calculate the dynamic symbol table index to use - in the relocation. */ - if (h != NULL - && (! info->symbolic || !h->root.def_regular) - /* h->root.dynindx may be -1 if this symbol was marked to - become local. */ - && h->root.dynindx != -1) - { - indx = h->root.dynindx; - /* ??? glibc's ld.so just adds the final GOT entry to the - relocation field. It therefore treats relocs against - defined symbols in the same way as relocs against - undefined symbols. */ - defined_p = FALSE; - } - else - { - indx = 0; - defined_p = TRUE; - } - - /* If the relocation was previously an absolute relocation and - this symbol will not be referred to by the relocation, we must - adjust it by the value we give it in the dynamic symbol table. - Otherwise leave the job up to the dynamic linker. */ - if (defined_p && r_type != R_SCORE_REL32) - *addendp += symbol; - - /* The relocation is always an REL32 relocation because we don't - know where the shared library will wind up at load-time. */ - outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32); - - /* For strict adherence to the ABI specification, we should - generate a R_SCORE_64 relocation record by itself before the - _REL32/_64 record as well, such that the addend is read in as - a 64-bit value (REL32 is a 32-bit relocation, after all). - However, since none of the existing ELF64 SCORE dynamic - loaders seems to care, we don't waste space with these - artificial relocations. If this turns out to not be true, - score_elf_allocate_dynamic_relocations() should be tweaked so - as to make room for a pair of dynamic relocations per - invocation if ABI_64_P, and here we should generate an - additional relocation record with R_SCORE_64 by itself for a - NULL symbol before this relocation record. */ - outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE); - outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE); - - /* Adjust the output offset of the relocation to reference the - correct location in the output file. */ - outrel[0].r_offset += (input_section->output_section->vma - + input_section->output_offset); - outrel[1].r_offset += (input_section->output_section->vma - + input_section->output_offset); - outrel[2].r_offset += (input_section->output_section->vma - + input_section->output_offset); - - /* Put the relocation back out. We have to use the special - relocation outputter in the 64-bit case since the 64-bit - relocation format is non-standard. */ - bfd_elf32_swap_reloc_out - (output_bfd, &outrel[0], - (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel))); - - /* We've now added another relocation. */ - ++sreloc->reloc_count; - - /* Make sure the output section is writable. The dynamic linker - will be writing to it. */ - elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE; - - return TRUE; -} - -static bfd_boolean -score_elf_create_got_section (bfd *abfd, - struct bfd_link_info *info, - bfd_boolean maybe_exclude) -{ - flagword flags; - asection *s; - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - struct score_got_info *g; - bfd_size_type amt; - - /* This function may be called more than once. */ - s = score_elf_got_section (abfd, TRUE); - if (s) - { - if (! maybe_exclude) - s->flags &= ~SEC_EXCLUDE; - return TRUE; - } - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - - if (maybe_exclude) - flags |= SEC_EXCLUDE; - - /* We have to use an alignment of 2**4 here because this is hardcoded - in the function stub generation and in the linker script. */ - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - elf_hash_table (info)->sgot = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 4)) - return FALSE; - - /* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the - linker script because we don't want to define the symbol if we - are not creating a global offset table. */ - bh = NULL; - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, - 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->non_elf = 0; - h->def_regular = 1; - h->type = STT_OBJECT; - elf_hash_table (info)->hgot = h; - - if (bfd_link_pic (info) && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - amt = sizeof (struct score_got_info); - g = bfd_alloc (abfd, amt); - if (g == NULL) - return FALSE; - - g->global_gotsym = NULL; - g->global_gotno = 0; - - g->local_gotno = SCORE_RESERVED_GOTNO; - g->assigned_gotno = SCORE_RESERVED_GOTNO; - g->next = NULL; - - g->got_entries = htab_try_create (1, score_elf_got_entry_hash, - score_elf_got_entry_eq, NULL); - if (g->got_entries == NULL) - return FALSE; - score_elf_section_data (s)->u.got_info = g; - score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; - - return TRUE; -} - -/* Calculate the %high function. */ -static bfd_vma -score_elf_high (bfd_vma value) -{ - return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff; -} - -/* Create a local GOT entry for VALUE. Return the index of the entry, - or -1 if it could not be created. */ -static struct score_got_entry * -score_elf_create_local_got_entry (bfd *abfd, - bfd *ibfd ATTRIBUTE_UNUSED, - struct score_got_info *gg, - asection *sgot, bfd_vma value, - unsigned long r_symndx ATTRIBUTE_UNUSED, - struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED, - int r_type ATTRIBUTE_UNUSED) -{ - struct score_got_entry entry, **loc; - struct score_got_info *g; - - entry.abfd = NULL; - entry.symndx = -1; - entry.d.address = value; - - g = gg; - loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT); - if (*loc) - return *loc; - - entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; - - *loc = bfd_alloc (abfd, sizeof entry); - - if (! *loc) - return NULL; - - memcpy (*loc, &entry, sizeof entry); - - if (g->assigned_gotno >= g->local_gotno) - { - (*loc)->gotidx = -1; - /* We didn't allocate enough space in the GOT. */ - _bfd_error_handler - (_("not enough GOT space for local GOT entries")); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - score_bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx)); - - return *loc; -} - -/* Find a GOT entry whose higher-order 16 bits are the same as those - for value. Return the index into the GOT for this entry. */ -static bfd_vma -score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - bfd_vma value, bfd_boolean external) -{ - asection *sgot; - struct score_got_info *g; - struct score_got_entry *entry; - - if (!external) - { - /* Although the ABI says that it is "the high-order 16 bits" that we - want, it is really the %high value. The complete value is - calculated with a `addiu' of a LO16 relocation, just as with a - HI16/LO16 pair. */ - value = score_elf_high (value) << 16; - } - - g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - - entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL, - R_SCORE_GOT15); - if (entry) - return entry->gotidx; - else - return MINUS_ONE; -} - -static void -s3_bfd_score_elf_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *entry, - bfd_boolean force_local) -{ - bfd *dynobj; - asection *got; - struct score_got_info *g; - struct score_elf_link_hash_entry *h; - - h = (struct score_elf_link_hash_entry *) entry; - if (h->forced_local) - return; - h->forced_local = TRUE; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj != NULL && force_local) - { - got = score_elf_got_section (dynobj, FALSE); - if (got == NULL) - return; - g = score_elf_section_data (got)->u.got_info; - - if (g->next) - { - struct score_got_entry e; - struct score_got_info *gg = g; - - /* Since we're turning what used to be a global symbol into a - local one, bump up the number of local entries of each GOT - that had an entry for it. This will automatically decrease - the number of global entries, since global_gotno is actually - the upper limit of global entries. */ - e.abfd = dynobj; - e.symndx = -1; - e.d.h = h; - - for (g = g->next; g != gg; g = g->next) - if (htab_find (g->got_entries, &e)) - { - BFD_ASSERT (g->global_gotno > 0); - g->local_gotno++; - g->global_gotno--; - } - - /* If this was a global symbol forced into the primary GOT, we - no longer need an entry for it. We can't release the entry - at this point, but we must at least stop counting it as one - of the symbols that required a forced got entry. */ - if (h->root.got.offset == 2) - { - BFD_ASSERT (gg->assigned_gotno > 0); - gg->assigned_gotno--; - } - } - else if (g->global_gotno == 0 && g->global_gotsym == NULL) - /* If we haven't got through GOT allocation yet, just bump up the - number of local entries, as this symbol won't be counted as - global. */ - g->local_gotno++; - else if (h->root.got.offset == 1) - { - /* If we're past non-multi-GOT allocation and this symbol had - been marked for a global got entry, give it a local entry - instead. */ - BFD_ASSERT (g->global_gotno > 0); - g->local_gotno++; - g->global_gotno--; - } - } - - _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); -} - -/* If H is a symbol that needs a global GOT entry, but has a dynamic - symbol table index lower than any we've seen to date, record it for - posterity. */ -static bfd_boolean -score_elf_record_global_got_symbol (struct elf_link_hash_entry *h, - bfd *abfd, - struct bfd_link_info *info, - struct score_got_info *g) -{ - struct score_got_entry entry, **loc; - - /* A global symbol in the GOT must also be in the dynamic symbol table. */ - if (h->dynindx == -1) - { - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - s3_bfd_score_elf_hide_symbol (info, h, TRUE); - break; - } - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - entry.abfd = abfd; - entry.symndx = -1; - entry.d.h = (struct score_elf_link_hash_entry *)h; - - loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT); - - /* If we've already marked this entry as needing GOT space, we don't - need to do it again. */ - if (*loc) - return TRUE; - - *loc = bfd_alloc (abfd, sizeof entry); - if (! *loc) - return FALSE; - - entry.gotidx = -1; - - memcpy (*loc, &entry, sizeof (entry)); - - if (h->got.offset != MINUS_ONE) - return TRUE; - - /* By setting this to a value other than -1, we are indicating that - there needs to be a GOT entry for H. Avoid using zero, as the - generic ELF copy_indirect_symbol tests for <= 0. */ - h->got.offset = 1; - - return TRUE; -} - -/* Reserve space in G for a GOT entry containing the value of symbol - SYMNDX in input bfd ABDF, plus ADDEND. */ -static bfd_boolean -score_elf_record_local_got_symbol (bfd *abfd, - long symndx, - bfd_vma addend, - struct score_got_info *g) -{ - struct score_got_entry entry, **loc; - - entry.abfd = abfd; - entry.symndx = symndx; - entry.d.addend = addend; - loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT); - - if (*loc) - return TRUE; - - entry.gotidx = g->local_gotno++; - - *loc = bfd_alloc (abfd, sizeof(entry)); - if (! *loc) - return FALSE; - - memcpy (*loc, &entry, sizeof (entry)); - - return TRUE; -} - -/* Returns the GOT offset at which the indicated address can be found. - If there is not yet a GOT entry for this value, create one. - Returns -1 if no satisfactory GOT offset can be found. */ -static bfd_vma -score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - bfd_vma value, unsigned long r_symndx, - struct score_elf_link_hash_entry *h, int r_type) -{ - asection *sgot; - struct score_got_info *g; - struct score_got_entry *entry; - - g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - - entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, - r_symndx, h, r_type); - if (!entry) - return MINUS_ONE; - - else - return entry->gotidx; -} - -/* Returns the GOT index for the global symbol indicated by H. */ - -static bfd_vma -score_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h) -{ - bfd_vma got_index; - asection *sgot; - struct score_got_info *g; - long global_got_dynindx = 0; - - g = score_elf_got_info (abfd, &sgot); - if (g->global_gotsym != NULL) - global_got_dynindx = g->global_gotsym->dynindx; - - /* Once we determine the global GOT entry with the lowest dynamic - symbol table index, we must put all dynamic symbols with greater - indices into the GOT. That makes it easy to calculate the GOT - offset. */ - BFD_ASSERT (h->dynindx >= global_got_dynindx); - got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd)); - BFD_ASSERT (got_index < sgot->size); - - return got_index; -} - -/* Returns the offset for the entry at the INDEXth position in the GOT. */ - -static bfd_vma -score_elf_got_offset_from_index (bfd *dynobj, - bfd *output_bfd, - bfd *input_bfd ATTRIBUTE_UNUSED, - bfd_vma got_index) -{ - asection *sgot; - bfd_vma gp; - - score_elf_got_info (dynobj, &sgot); - gp = _bfd_get_gp_value (output_bfd); - - return sgot->output_section->vma + sgot->output_offset + got_index - gp; -} - -/* Follow indirect and warning hash entries so that each got entry - points to the final symbol definition. P must point to a pointer - to the hash table we're traversing. Since this traversal may - modify the hash table, we set this pointer to NULL to indicate - we've made a potentially-destructive change to the hash table, so - the traversal must be restarted. */ -static int -score_elf_resolve_final_got_entry (void **entryp, void *p) -{ - struct score_got_entry *entry = (struct score_got_entry *)*entryp; - htab_t got_entries = *(htab_t *)p; - - if (entry->abfd != NULL && entry->symndx == -1) - { - struct score_elf_link_hash_entry *h = entry->d.h; - - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; - - if (entry->d.h == h) - return 1; - - entry->d.h = h; - - /* If we can't find this entry with the new bfd hash, re-insert - it, and get the traversal restarted. */ - if (! htab_find (got_entries, entry)) - { - htab_clear_slot (got_entries, entryp); - entryp = htab_find_slot (got_entries, entry, INSERT); - if (! *entryp) - *entryp = entry; - /* Abort the traversal, since the whole table may have - moved, and leave it up to the parent to restart the - process. */ - *(htab_t *)p = NULL; - return 0; - } - /* We might want to decrement the global_gotno count, but it's - either too early or too late for that at this point. */ - } - - return 1; -} - -/* Turn indirect got entries in a got_entries table into their final locations. */ -static void -score_elf_resolve_final_got_entries (struct score_got_info *g) -{ - htab_t got_entries; - - do - { - got_entries = g->got_entries; - - htab_traverse (got_entries, - score_elf_resolve_final_got_entry, - &got_entries); - } - while (got_entries == NULL); -} - -/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r */ -static void -score_elf_add_to_rel (bfd *abfd, - bfd_byte *address, - reloc_howto_type *howto, - bfd_signed_vma increment) -{ - bfd_signed_vma addend; - bfd_vma contents; - unsigned long offset; - unsigned long r_type = howto->type; - unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; - - contents = score_bfd_get_32 (abfd, address); - /* Get the (signed) value from the instruction. */ - addend = contents & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~howto->src_mask; - addend |= mask; - } - /* Add in the increment, (which is a byte value). */ - switch (r_type) - { - case R_SCORE_PC19: - offset = - (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff); - offset += increment; - contents = - (contents & ~howto-> - src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff); - score_bfd_put_32 (abfd, contents, address); - break; - case R_SCORE_HI16: - break; - case R_SCORE_LO16: - hi16_addend = score_bfd_get_32 (abfd, address - 4); - hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; - offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1; - offset = (hi16_offset << 16) | (offset & 0xffff); - uvalue = increment + offset; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_addend & (~(howto->dst_mask))) - | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (abfd, hi16_value, address - 4); - offset = (uvalue & 0xffff) << 1; - contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - score_bfd_put_32 (abfd, contents, address); - break; - case R_SCORE_24: - offset = - (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff); - offset += increment; - contents = - (contents & ~howto-> - src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff); - score_bfd_put_32 (abfd, contents, address); - break; - - case R_SCORE16_11: - - contents = score_bfd_get_16 (abfd, address); - offset = contents & howto->src_mask; - offset += increment; - contents = (contents & ~howto->src_mask) | (offset & howto->src_mask); - score_bfd_put_16 (abfd, contents, address); - - break; - case R_SCORE16_PC8: - - contents = score_bfd_get_16 (abfd, address); - offset = (contents & howto->src_mask) + ((increment >> 1) & 0x1ff); - contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); - score_bfd_put_16 (abfd, contents, address); - - break; - - case R_SCORE_BCMP: - contents = score_bfd_get_32 (abfd, address); - offset = (contents & howto->src_mask); - offset <<= howto->rightshift; - offset += increment; - offset >>= howto->rightshift; - contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); - score_bfd_put_32 (abfd, contents, address); - break; - - case R_SCORE_IMM30: - contents = score_bfd_get_48 (abfd, address); - offset = (contents & howto->src_mask); - offset <<= howto->rightshift; - offset += increment; - offset >>= howto->rightshift; - contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); - score_bfd_put_48 (abfd, contents, address); - break; - - case R_SCORE_IMM32: - contents = score_bfd_get_48 (abfd, address); - offset = (contents & howto->src_mask); - offset += increment; - contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); - score_bfd_put_48 (abfd, contents, address); - break; - - default: - addend += increment; - contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask); - score_bfd_put_32 (abfd, contents, address); - break; - } -} - -/* Perform a relocation as part of a final link. */ -static bfd_reloc_status_type -score_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - bfd *output_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - Elf_Internal_Rela *relocs, - bfd_vma symbol, - struct bfd_link_info *info, - const char *sym_name ATTRIBUTE_UNUSED, - int sym_flags ATTRIBUTE_UNUSED, - struct score_elf_link_hash_entry *h, - asection **local_sections, - bfd_boolean gp_disp_p) -{ - unsigned long r_type; - unsigned long r_symndx; - bfd_byte *hit_data = contents + rel->r_offset; - bfd_vma addend; - /* The final GP value to be used for the relocatable, executable, or - shared object file being produced. */ - bfd_vma gp = MINUS_ONE; - /* The place (section offset or address) of the storage unit being relocated. */ - bfd_vma rel_addr; - /* The offset into the global offset table at which the address of the relocation entry - symbol, adjusted by the addend, resides during execution. */ - bfd_vma g = MINUS_ONE; - /* TRUE if the symbol referred to by this relocation is a local symbol. */ - bfd_boolean local_p; - /* The eventual value we will relocate. */ - bfd_vma value = symbol; - unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0; - - - if (elf_gp (output_bfd) == 0) - { - struct bfd_link_hash_entry *bh; - asection *o; - - bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1); - if (bh != NULL && bh->type == bfd_link_hash_defined) - elf_gp (output_bfd) = (bh->u.def.value - + bh->u.def.section->output_section->vma - + bh->u.def.section->output_offset); - else if (bfd_link_relocatable (info)) - { - bfd_vma lo = -1; - - /* Find the GP-relative section with the lowest offset. */ - for (o = output_bfd->sections; o != NULL; o = o->next) - if (o->vma < lo) - lo = o->vma; - /* And calculate GP relative to that. */ - elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd); - } - else - { - /* If the relocate_section function needs to do a reloc - involving the GP value, it should make a reloc_dangerous - callback to warn that GP is not defined. */ - } - } - - /* Parse the relocation. */ - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset); - local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE); - - if (r_type == R_SCORE_GOT15) - { - const Elf_Internal_Rela *relend; - const Elf_Internal_Rela *lo16_rel; - bfd_vma lo_value = 0; - - relend = relocs + input_section->reloc_count; - lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); - if ((local_p) && (lo16_rel != NULL)) - { - bfd_vma tmp = 0; - tmp = score_bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); - lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); - } - addend = lo_value; - } - /* For score3 R_SCORE_ABS32. */ - else if (r_type == R_SCORE_ABS32 || r_type == R_SCORE_REL32) - { - addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; - } - else - { - addend = (score_bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; - } - - /* If we haven't already determined the GOT offset, or the GP value, - and we're going to need it, get it now. */ - switch (r_type) - { - case R_SCORE_CALL15: - case R_SCORE_GOT15: - if (!local_p) - { - g = score_elf_global_got_index (elf_hash_table (info)->dynobj, - (struct elf_link_hash_entry *) h); - if ((! elf_hash_table (info)->dynamic_sections_created - || (bfd_link_pic (info) - && (info->symbolic || h->root.dynindx == -1) - && h->root.def_regular))) - { - /* This is a static link or a -Bsymbolic link. The - symbol is defined locally, or was forced to be local. - We must initialize this entry in the GOT. */ - bfd *tmpbfd = elf_hash_table (info)->dynobj; - asection *sgot = score_elf_got_section (tmpbfd, FALSE); - score_bfd_put_32 (tmpbfd, value, sgot->contents + g); - } - } - else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15) - { - /* There's no need to create a local GOT entry here; the - calculation for a local GOT15 entry does not involve G. */ - ; - } - else - { - g = score_elf_local_got_index (output_bfd, input_bfd, info, - symbol + addend, r_symndx, h, r_type); - if (g == MINUS_ONE) - return bfd_reloc_outofrange; - } - - /* Convert GOT indices to actual offsets. */ - g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, - output_bfd, input_bfd, g); - break; - - case R_SCORE_HI16: - case R_SCORE_LO16: - case R_SCORE_GPREL32: - gp = _bfd_get_gp_value (output_bfd); - break; - - case R_SCORE_GP15: - gp = _bfd_get_gp_value (output_bfd); - - default: - break; - } - - switch (r_type) - { - case R_SCORE_NONE: - return bfd_reloc_ok; - - case R_SCORE_ABS32: - case R_SCORE_REL32: - if ((bfd_link_pic (info) - || (elf_hash_table (info)->dynamic_sections_created - && h != NULL - && h->root.def_dynamic - && !h->root.def_regular)) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0) - { - /* If we're creating a shared library, or this relocation is against a symbol - in a shared library, then we can't know where the symbol will end up. - So, we create a relocation record in the output, and leave the job up - to the dynamic linker. */ - value = addend; - if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h, - symbol, &value, - input_section)) - return bfd_reloc_undefined; - } - else if (r_symndx == STN_UNDEF) - /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ - value = 0; - else - { - if (r_type != R_SCORE_REL32) - value = symbol + addend; - else - value = addend; - } - value &= howto->dst_mask; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_ABS16: - value += addend; - if ((long)value > 0x7fff || (long)value < -0x8000) - return bfd_reloc_overflow; - score_bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_24: - addend = score_bfd_get_32 (input_bfd, hit_data); - offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff); - if ((offset & 0x1000000) != 0) - offset |= 0xfe000000; - value += offset; - abs_value = value - rel_addr; - if ((abs_value & 0xfe000000) != 0) - return bfd_reloc_overflow; - addend = (addend & ~howto->src_mask) - | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff); - score_bfd_put_32 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - /* signed imm32. */ - case R_SCORE_IMM30: - { - int not_word_align_p = 0; - bfd_vma imm_offset = 0; - addend = score_bfd_get_48 (input_bfd, hit_data); - imm_offset = ((addend >> 7) & 0xff) - | (((addend >> 16) & 0x7fff) << 8) - | (((addend >> 32) & 0x7f) << 23); - imm_offset <<= howto->rightshift; - value += imm_offset; - value &= 0xffffffff; - - /* Check lw48/sw48 rd, value/label word align. */ - if ((value & 0x3) != 0) - not_word_align_p = 1; - - value >>= howto->rightshift; - addend = (addend & ~howto->src_mask) - | (((value & 0xff) >> 0) << 7) - | (((value & 0x7fff00) >> 8) << 16) - | (((value & 0x3f800000) >> 23) << 32); - score_bfd_put_48 (input_bfd, addend, hit_data); - if (not_word_align_p) - return bfd_reloc_other; - else - return bfd_reloc_ok; - } - - case R_SCORE_IMM32: - { - bfd_vma imm_offset = 0; - addend = score_bfd_get_48 (input_bfd, hit_data); - imm_offset = ((addend >> 5) & 0x3ff) - | (((addend >> 16) & 0x7fff) << 10) - | (((addend >> 32) & 0x7f) << 25); - value += imm_offset; - value &= 0xffffffff; - addend = (addend & ~howto->src_mask) - | ((value & 0x3ff) << 5) - | (((value >> 10) & 0x7fff) << 16) - | (((value >> 25) & 0x7f) << 32); - score_bfd_put_48 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - } - - case R_SCORE_PC19: - addend = score_bfd_get_32 (input_bfd, hit_data); - offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff); - if ((offset & 0x80000) != 0) - offset |= 0xfff00000; - abs_value = value = value - rel_addr + offset; - /* exceed 20 bit : overflow. */ - if ((abs_value & 0x80000000) == 0x80000000) - abs_value = 0xffffffff - value + 1; - if ((abs_value & 0xfff80000) != 0) - return bfd_reloc_overflow; - addend = (addend & ~howto->src_mask) - | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff); - score_bfd_put_32 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE16_11: - addend = score_bfd_get_16 (input_bfd, hit_data); - offset = addend & howto->src_mask; - if ((offset & 0x800) != 0) /* Offset is negative. */ - offset |= 0xfffff000; - value += offset; - abs_value = value - rel_addr; - if ((abs_value & 0xfffff000) != 0) - return bfd_reloc_overflow; - addend = (addend & ~howto->src_mask) | (value & howto->src_mask); - score_bfd_put_16 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE16_PC8: - addend = score_bfd_get_16 (input_bfd, hit_data); - offset = (addend & howto->src_mask) << 1; - if ((offset & 0x200) != 0) /* Offset is negative. */ - offset |= 0xfffffe00; - abs_value = value = value - rel_addr + offset; - /* Sign bit + exceed 9 bit. */ - if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00)) - return bfd_reloc_overflow; - value >>= 1; - addend = (addend & ~howto->src_mask) | (value & howto->src_mask); - score_bfd_put_16 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE_BCMP: - addend = score_bfd_get_32 (input_bfd, hit_data); - offset = (addend & howto->src_mask) << howto->rightshift; - if ((offset & 0x200) != 0) /* Offset is negative. */ - offset |= 0xfffffe00; - value = value - rel_addr + offset; - /* Sign bit + exceed 9 bit. */ - if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00)) - return bfd_reloc_overflow; - value >>= howto->rightshift; - addend = (addend & ~howto->src_mask) - | (value & 0x1) - | (((value >> 1) & 0x7) << 7) - | (((value >> 4) & 0x1f) << 21); - score_bfd_put_32 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE_HI16: - return bfd_reloc_ok; - - case R_SCORE_LO16: - hi16_addend = score_bfd_get_32 (input_bfd, hit_data - 4); - hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; - addend = score_bfd_get_32 (input_bfd, hit_data); - offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; - offset = (hi16_offset << 16) | (offset & 0xffff); - - if (!gp_disp_p) - uvalue = value + offset; - else - uvalue = offset + gp - rel_addr + 4; - - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_addend & (~(howto->dst_mask))) - | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (input_bfd, hi16_value, hit_data - 4); - offset = (uvalue & 0xffff) << 1; - value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - score_bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GP15: - addend = score_bfd_get_32 (input_bfd, hit_data); - offset = addend & 0x7fff; - if ((offset & 0x4000) == 0x4000) - offset |= 0xffffc000; - value = value + offset - gp; - if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000)) - return bfd_reloc_overflow; - value = (addend & ~howto->src_mask) | (value & howto->src_mask); - score_bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GOT15: - case R_SCORE_CALL15: - if (local_p) - { - bfd_boolean forced; - - /* The special case is when the symbol is forced to be local. We need the - full address in the GOT since no R_SCORE_GOT_LO16 relocation follows. */ - forced = ! score_elf_local_relocation_p (input_bfd, rel, - local_sections, FALSE); - value = score_elf_got16_entry (output_bfd, input_bfd, info, - symbol + addend, forced); - if (value == MINUS_ONE) - return bfd_reloc_outofrange; - value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, - output_bfd, input_bfd, value); - } - else - { - value = g; - } - - if ((long) value > 0x3fff || (long) value < -0x4000) - return bfd_reloc_overflow; - - addend = score_bfd_get_32 (input_bfd, hit_data); - value = (addend & ~howto->dst_mask) | (value & howto->dst_mask); - score_bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GPREL32: - value = (addend + symbol - gp); - value &= howto->dst_mask; - score_bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GOT_LO16: - addend = score_bfd_get_32 (input_bfd, hit_data); - value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1); - value += symbol; - value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) - | (((value >> 14) & 0x3) << 16); - - score_bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_DUMMY_HI16: - return bfd_reloc_ok; - - case R_SCORE_GNU_VTINHERIT: - case R_SCORE_GNU_VTENTRY: - /* We don't do anything with these at present. */ - return bfd_reloc_continue; - - default: - return bfd_reloc_notsupported; - } -} - -/* Score backend functions. */ -static void -s3_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (elf_reloc->r_info); - if (r_type >= ARRAY_SIZE (elf32_score_howto_table)) - bfd_reloc->howto = NULL; - else - bfd_reloc->howto = &elf32_score_howto_table[r_type]; -} - -/* Relocate an score ELF section. */ -static bfd_boolean -s3_bfd_score_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - const char *name; - unsigned long offset; - unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; - size_t extsymoff; - bfd_boolean gp_disp_p = FALSE; - - /* Sort dynsym. */ - if (elf_hash_table (info)->dynamic_sections_created) - { - bfd_size_type dynsecsymcount = 0; - if (bfd_link_pic (info)) - { - asection * p; - const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); - - 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)) - ++ dynsecsymcount; - } - - if (!score_elf_sort_hash_table (info, dynsecsymcount + 1)) - return FALSE; - } - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct score_elf_link_hash_entry *h; - bfd_vma relocation = 0; - bfd_reloc_status_type r; - arelent bfd_reloc; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - s3_bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel); - howto = bfd_reloc.howto; - - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < extsymoff) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); - - if (!bfd_link_relocatable (info) - && (sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - asection *msec; - bfd_vma addend, value; - - switch (r_type) - { - case R_SCORE_HI16: - break; - case R_SCORE_LO16: - hi16_addend = score_bfd_get_32 (input_bfd, contents + rel->r_offset - 4); - hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; - value = score_bfd_get_32 (input_bfd, contents + rel->r_offset); - offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1; - addend = (hi16_offset << 16) | (offset & 0xffff); - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); - addend -= relocation; - addend += msec->output_section->vma + msec->output_offset; - uvalue = addend; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_addend & (~(howto->dst_mask))) - | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4); - offset = (uvalue & 0xffff) << 1; - value = (value & (~(howto->dst_mask))) - | (offset & 0x7fff) | ((offset << 1) & 0x30000); - score_bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - - case R_SCORE_IMM32: - { - value = score_bfd_get_48 (input_bfd, contents + rel->r_offset); - addend = ((value >> 5) & 0x3ff) - | (((value >> 16) & 0x7fff) << 10) - | (((value >> 32) & 0x7f) << 25); - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); - addend -= relocation; - addend += msec->output_section->vma + msec->output_offset; - addend &= 0xffffffff; - value = (value & ~howto->src_mask) - | ((addend & 0x3ff) << 5) - | (((addend >> 10) & 0x7fff) << 16) - | (((addend >> 25) & 0x7f) << 32); - score_bfd_put_48 (input_bfd, value, contents + rel->r_offset); - break; - } - - case R_SCORE_IMM30: - { - int not_word_align_p = 0; - value = score_bfd_get_48 (input_bfd, contents + rel->r_offset); - addend = ((value >> 7) & 0xff) - | (((value >> 16) & 0x7fff) << 8) - | (((value >> 32) & 0x7f) << 23); - addend <<= howto->rightshift; - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); - addend -= relocation; - addend += msec->output_section->vma + msec->output_offset; - addend &= 0xffffffff; - - /* Check lw48/sw48 rd, value/label word align. */ - if ((addend & 0x3) != 0) - not_word_align_p = 1; - - addend >>= howto->rightshift; - value = (value & ~howto->src_mask) - | (((addend & 0xff) >> 0) << 7) - | (((addend & 0x7fff00) >> 8) << 16) - | (((addend & 0x3f800000) >> 23) << 32); - score_bfd_put_48 (input_bfd, value, contents + rel->r_offset); - - if (not_word_align_p) - return bfd_reloc_other; - else - break; - } - - case R_SCORE_GOT_LO16: - value = score_bfd_get_32 (input_bfd, contents + rel->r_offset); - addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1); - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; - addend += msec->output_section->vma + msec->output_offset; - value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1) - | (((addend >> 14) & 0x3) << 16); - - score_bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - - case R_SCORE_ABS32: - case R_SCORE_REL32: - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - /* Get the (signed) value from the instruction. */ - addend = value & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~howto->src_mask; - addend |= mask; - } - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; - addend += msec->output_section->vma + msec->output_offset; - value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - - default: - value = score_bfd_get_32 (input_bfd, contents + rel->r_offset); - /* Get the (signed) value from the instruction. */ - addend = value & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~howto->src_mask; - addend |= mask; - } - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; - addend += msec->output_section->vma + msec->output_offset; - value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); - score_bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - } - } - } - else - { - /* For global symbols we look up the symbol in the hash-table. */ - h = ((struct score_elf_link_hash_entry *) - elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - h = ((struct score_elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &h->root.root)); - - /* Find the real hash-table entry for this symbol. */ - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; - - /* Record the name of this symbol, for our caller. */ - name = h->root.root.root.string; - - /* See if this is the special GP_DISP_LABEL symbol. Note that such a - symbol must always be a global symbol. */ - if (strcmp (name, GP_DISP_LABEL) == 0) - { - /* Relocations against GP_DISP_LABEL are permitted only with - R_SCORE_HI16 and R_SCORE_LO16 relocations. */ - if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16) - return bfd_reloc_notsupported; - - gp_disp_p = TRUE; - } - - /* If this symbol is defined, calculate its address. Note that - GP_DISP_LABEL is a magic symbol, always implicitly defined by the - linker, so it's inappropriate to check to see whether or not - its defined. */ - else if ((h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - && h->root.root.u.def.section) - { - sec = h->root.root.u.def.section; - if (sec->output_section) - relocation = (h->root.root.u.def.value - + sec->output_section->vma - + sec->output_offset); - else - { - relocation = h->root.root.u.def.value; - } - } - else if (h->root.root.type == bfd_link_hash_undefweak) - /* We allow relocations against undefined weak symbols, giving - it the value zero, so that you can undefined weak functions - and check to see if they exist by looking at their addresses. */ - relocation = 0; - else if (info->unresolved_syms_in_objects == RM_IGNORE - && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) - relocation = 0; - else if (strcmp (name, "_DYNAMIC_LINK") == 0) - { - /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol - in s3_bfd_score_elf_create_dynamic_sections. Otherwise, we should define - the symbol with a value of 0. */ - BFD_ASSERT (! bfd_link_pic (info)); - BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL); - relocation = 0; - } - else if (!bfd_link_relocatable (info)) - { - (*info->callbacks->undefined_symbol) - (info, h->root.root.root.string, input_bfd, - input_section, rel->r_offset, - (info->unresolved_syms_in_objects == RM_GENERATE_ERROR) - || ELF_ST_VISIBILITY (h->root.other)); - relocation = 0; - } - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* 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) - { - sym = local_syms + r_symndx; - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - sec = local_sections[r_symndx]; - score_elf_add_to_rel (input_bfd, contents + rel->r_offset, - howto, (bfd_signed_vma) (sec->output_offset + sym->st_value)); - } - } - continue; - } - - /* This is a final link. */ - r = score_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, contents, rel, relocs, - relocation, info, name, - (h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) : - ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections, - gp_disp_p); - - if (r != bfd_reloc_ok) - { - const char *msg = (const char *)0; - - switch (r) - { - case bfd_reloc_overflow: - /* If the overflowing reloc was to an undefined symbol, - we have already printed one error message and there - is no point complaining again. */ - if (!h || h->root.root.type != bfd_link_hash_undefined) - (*info->callbacks->reloc_overflow) - (info, NULL, name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - /* Use bfd_reloc_other to check lw48, sw48 word align. */ - case bfd_reloc_other: - msg = _("address not word align"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* Fall through. */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table. */ -static bfd_boolean -s3_bfd_score_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - struct score_got_info *g; - size_t extsymoff; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - asection *sgot; - asection *sreloc; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; - - if (dynobj == NULL) - { - sgot = NULL; - g = NULL; - } - else - { - sgot = score_elf_got_section (dynobj, FALSE); - if (sgot == NULL) - g = NULL; - else - { - BFD_ASSERT (score_elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - } - } - - sreloc = NULL; - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; ++rel) - { - unsigned long r_symndx; - unsigned int r_type; - 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 < extsymoff) - { - h = NULL; - } - else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Malformed reloc detected for section %A"), abfd, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - h = sym_hashes[r_symndx - extsymoff]; - - /* This may be an indirect symbol created because of a version. */ - if (h != NULL) - { - while (h->root.type == bfd_link_hash_indirect) - h = (struct elf_link_hash_entry *)h->root.u.i.link; - } - } - - /* Some relocs require a global offset table. */ - if (dynobj == NULL || sgot == NULL) - { - switch (r_type) - { - case R_SCORE_GOT15: - case R_SCORE_CALL15: - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - if (!score_elf_create_got_section (dynobj, info, FALSE)) - return FALSE; - g = score_elf_got_info (dynobj, &sgot); - break; - case R_SCORE_ABS32: - case R_SCORE_REL32: - if (dynobj == NULL - && (bfd_link_pic (info) || h != NULL) - && (sec->flags & SEC_ALLOC) != 0) - elf_hash_table (info)->dynobj = dynobj = abfd; - break; - default: - break; - } - } - - if (!h && (r_type == R_SCORE_GOT_LO16)) - { - if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g)) - return FALSE; - } - - switch (r_type) - { - case R_SCORE_CALL15: - if (h == NULL) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: CALL15 reloc at %#Lx not against global symbol"), - abfd, rel->r_offset); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - /* This symbol requires a global offset table entry. */ - if (! score_elf_record_global_got_symbol (h, abfd, info, g)) - return FALSE; - - /* We need a stub, not a plt entry for the undefined function. But we record - it as if it needs plt. See _bfd_elf_adjust_dynamic_symbol. */ - h->needs_plt = 1; - h->type = STT_FUNC; - } - break; - case R_SCORE_GOT15: - if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g)) - return FALSE; - break; - case R_SCORE_ABS32: - case R_SCORE_REL32: - if ((bfd_link_pic (info) || h != NULL) - && (sec->flags & SEC_ALLOC) != 0) - { - if (sreloc == NULL) - { - sreloc = score_elf_rel_dyn_section (dynobj, TRUE); - if (sreloc == NULL) - return FALSE; - } -#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY) - if (bfd_link_pic (info)) - { - /* When creating a shared object, we must copy these reloc types into - the output file as R_SCORE_REL32 relocs. We make room for this reloc - in the .rel.dyn reloc section. */ - score_elf_allocate_dynamic_relocations (dynobj, 1); - if ((sec->flags & SCORE_READONLY_SECTION) - == SCORE_READONLY_SECTION) - /* We tell the dynamic linker that there are - relocations against the text segment. */ - info->flags |= DF_TEXTREL; - } - else - { - struct score_elf_link_hash_entry *hscore; - - /* We only need to copy this reloc if the symbol is - defined in a dynamic object. */ - hscore = (struct score_elf_link_hash_entry *)h; - ++hscore->possibly_dynamic_relocs; - if ((sec->flags & SCORE_READONLY_SECTION) - == SCORE_READONLY_SECTION) - /* We need it to tell the dynamic linker if there - are relocations against the text segment. */ - hscore->readonly_reloc = TRUE; - } - - /* Even though we don't directly need a GOT entry for this symbol, - a symbol must have a dynamic symbol table index greater that - DT_SCORE_GOTSYM if there are dynamic relocations against it. */ - if (h != NULL) - { - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! score_elf_create_got_section (dynobj, info, TRUE)) - return FALSE; - g = score_elf_got_info (dynobj, &sgot); - if (! score_elf_record_global_got_symbol (h, abfd, info, g)) - return FALSE; - } - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_SCORE_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_SCORE_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - default: - break; - } - - /* We must not create a stub for a symbol that has relocations - related to taking the function's address. */ - switch (r_type) - { - default: - if (h != NULL) - { - struct score_elf_link_hash_entry *sh; - - sh = (struct score_elf_link_hash_entry *) h; - sh->no_fn_stub = TRUE; - } - break; - case R_SCORE_CALL15: - break; - } - } - - return TRUE; -} - -static bfd_boolean -s3_bfd_score_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - switch (sym->st_shndx) - { - case SHN_COMMON: - if (sym->st_size > elf_gp_size (abfd)) - break; - /* Fall through. */ - case SHN_SCORE_SCOMMON: - *secp = bfd_make_section_old_way (abfd, ".scommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - -static void -s3_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) -{ - elf_symbol_type *elfsym; - - elfsym = (elf_symbol_type *) asym; - switch (elfsym->internal_elf_sym.st_shndx) - { - case SHN_COMMON: - if (asym->value > elf_gp_size (abfd)) - break; - /* Fall through. */ - case SHN_SCORE_SCOMMON: - if (score_elf_scom_section.name == NULL) - { - /* Initialize the small common section. */ - score_elf_scom_section.name = ".scommon"; - score_elf_scom_section.flags = SEC_IS_COMMON; - score_elf_scom_section.output_section = &score_elf_scom_section; - score_elf_scom_section.symbol = &score_elf_scom_symbol; - score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr; - score_elf_scom_symbol.name = ".scommon"; - score_elf_scom_symbol.flags = BSF_SECTION_SYM; - score_elf_scom_symbol.section = &score_elf_scom_section; - score_elf_scom_symbol_ptr = &score_elf_scom_symbol; - } - asym->section = &score_elf_scom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - } -} - -static int -s3_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - /* If we see a common symbol, which implies a relocatable link, then - if a symbol was small common in an input file, mark it as small - common in the output file. */ - if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) - sym->st_shndx = SHN_SCORE_SCOMMON; - - return 1; -} - -static bfd_boolean -s3_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) - { - *retval = SHN_SCORE_SCOMMON; - return TRUE; - } - - return FALSE; -} - -/* 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 -s3_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj; - struct score_elf_link_hash_entry *hscore; - asection *s; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic && h->ref_regular && !h->def_regular))); - - /* If this symbol is defined in a dynamic object, we need to copy - any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output - file. */ - hscore = (struct score_elf_link_hash_entry *)h; - if (!bfd_link_relocatable (info) - && hscore->possibly_dynamic_relocs != 0 - && (h->root.type == bfd_link_hash_defweak || !h->def_regular)) - { - score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs); - if (hscore->readonly_reloc) - /* We tell the dynamic linker that there are relocations - against the text segment. */ - info->flags |= DF_TEXTREL; - } - - /* For a function, create a stub, if allowed. */ - if (!hscore->no_fn_stub && h->needs_plt) - { - if (!elf_hash_table (info)->dynamic_sections_created) - return TRUE; - - /* If this symbol is not defined in a regular file, then set - the symbol to the stub location. This is required to make - function pointers compare as equal between the normal - executable and the shared library. */ - if (!h->def_regular) - { - /* We need .stub section. */ - s = bfd_get_linker_section (dynobj, SCORE_ELF_STUB_SECTION_NAME); - BFD_ASSERT (s != NULL); - - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* XXX Write this stub address somewhere. */ - h->plt.offset = s->size; - - /* Make room for this stub code. */ - s->size += SCORE_FUNCTION_STUB_SIZE; - - /* The last half word of the stub will be filled with the index - of this symbol in .dynsym section. */ - return TRUE; - } - } - else if ((h->type == STT_FUNC) && !h->needs_plt) - { - /* This will set the entry for this symbol in the GOT to 0, and - the dynamic linker will take care of this. */ - h->root.u.def.value = 0; - return TRUE; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - return TRUE; -} - -/* This function is called after all the input files have been read, - and the input sections have been assigned to output sections. */ -static bfd_boolean -s3_bfd_score_elf_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - struct score_got_info *g; - int i; - bfd_size_type loadable_size = 0; - bfd_size_type local_gotno; - bfd *sub; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - /* Relocatable links don't have it. */ - return TRUE; - - g = score_elf_got_info (dynobj, &s); - if (s == NULL) - return TRUE; - - /* Calculate the total loadable size of the output. That will give us the - maximum number of GOT_PAGE entries required. */ - for (sub = info->input_bfds; sub; sub = sub->link.next) - { - asection *subsection; - - for (subsection = sub->sections; - subsection; - subsection = subsection->next) - { - if ((subsection->flags & SEC_ALLOC) == 0) - continue; - loadable_size += ((subsection->size + 0xf) - &~ (bfd_size_type) 0xf); - } - } - - /* There has to be a global GOT entry for every symbol with - a dynamic symbol table index of DT_SCORE_GOTSYM or - higher. Therefore, it make sense to put those symbols - that need GOT entries at the end of the symbol table. We - do that here. */ - if (! score_elf_sort_hash_table (info, 1)) - return FALSE; - - if (g->global_gotsym != NULL) - i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx; - else - /* If there are no global symbols, or none requiring - relocations, then GLOBAL_GOTSYM will be NULL. */ - i = 0; - - /* In the worst case, we'll get one stub per dynamic symbol. */ - loadable_size += SCORE_FUNCTION_STUB_SIZE * i; - - /* Assume there are two loadable segments consisting of - contiguous sections. Is 5 enough? */ - local_gotno = (loadable_size >> 16) + 5; - - g->local_gotno += local_gotno; - s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd); - - g->global_gotno = i; - s->size += i * SCORE_ELF_GOT_SIZE (output_bfd); - - score_elf_resolve_final_got_entries (g); - - if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd)) - { - /* Fixme. Error message or Warning message should be issued here. */ - } - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ -static bfd_boolean -s3_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean reltext; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; - s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (CONST_STRNEQ (name, ".rel")) - { - if (s->size == 0) - { - /* We only strip the section if the output section name - has the same name. Otherwise, there might be several - input sections for this output section. FIXME: This - code is probably not needed these days anyhow, since - the linker now does not create empty output sections. */ - if (s->output_section != NULL - && strcmp (name, - bfd_get_section_name (s->output_section->owner, - s->output_section)) == 0) - s->flags |= SEC_EXCLUDE; - } - else - { - const char *outname; - asection *target; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL entry. - If the relocation section is .rel.dyn, we always - assert a DT_TEXTREL entry rather than testing whether - there exists a relocation to a read only section or - not. */ - outname = bfd_get_section_name (output_bfd, s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 4); - if ((target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0) - reltext = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - if (strcmp (name, ".rel.dyn") != 0) - s->reloc_count = 0; - } - } - else if (CONST_STRNEQ (name, ".got")) - { - /* s3_bfd_score_elf_always_size_sections() has already done - most of the work, but some symbols may have been mapped - to versions that we must now resolve in the got_entries - hash tables. */ - } - else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0) - { - /* IRIX rld assumes that the function stub isn't at the end - of .text section. So put a dummy. XXX */ - s->size += SCORE_FUNCTION_STUB_SIZE; - } - else if (! CONST_STRNEQ (name, ".init")) - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - /* Allocate memory for the section contents. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL && s->size != 0) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in s3_bfd_score_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) - return FALSE; - - if (reltext) - info->flags |= DF_TEXTREL; - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0)) - return FALSE; - } - - if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0)) - return FALSE; - - if (score_elf_rel_dyn_section (dynobj, FALSE)) - { - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0)) - return FALSE; - } - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0)) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -s3_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - flagword flags; - asection *s; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY); - - /* ABI requests the .dynamic section to be read only. */ - s = bfd_get_linker_section (abfd, ".dynamic"); - if (s != NULL) - { - if (!bfd_set_section_flags (abfd, s, flags)) - return FALSE; - } - - /* We need to create .got section. */ - if (!score_elf_create_got_section (abfd, info, FALSE)) - return FALSE; - - if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE)) - return FALSE; - - /* Create .stub section. */ - if (bfd_get_linker_section (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL) - { - s = bfd_make_section_anyway_with_flags (abfd, SCORE_ELF_STUB_SECTION_NAME, - flags | SEC_CODE); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 2)) - - return FALSE; - } - - if (!bfd_link_pic (info)) - { - const char *name; - - name = "_DYNAMIC_LINK"; - bh = NULL; - if (!(_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, - (bfd_vma) 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *)bh; - h->non_elf = 0; - h->def_regular = 1; - h->type = STT_SECTION; - - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - return TRUE; -} - - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ -static bfd_boolean -s3_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - bfd *dynobj; - asection *sgot; - struct score_got_info *g; - const char *name; - - dynobj = elf_hash_table (info)->dynobj; - - if (h->plt.offset != MINUS_ONE) - { - asection *s; - bfd_byte stub[SCORE_FUNCTION_STUB_SIZE]; - - /* This symbol has a stub. Set it up. */ - BFD_ASSERT (h->dynindx != -1); - - s = bfd_get_linker_section (dynobj, SCORE_ELF_STUB_SECTION_NAME); - BFD_ASSERT (s != NULL); - - /* FIXME: Can h->dynindex be more than 64K? */ - if (h->dynindx & 0xffff0000) - return FALSE; - - /* Fill the stub. */ - score_bfd_put_32 (output_bfd, STUB_LW, stub); - score_bfd_put_32 (output_bfd, STUB_MOVE, stub + 4); - score_bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8); - score_bfd_put_32 (output_bfd, STUB_BRL, stub + 12); - - BFD_ASSERT (h->plt.offset <= s->size); - memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE); - - /* Mark the symbol as undefined. plt.offset != -1 occurs - only for the referenced symbol. */ - sym->st_shndx = SHN_UNDEF; - - /* The run-time linker uses the st_value field of the symbol - to reset the global offset table entry for this external - to its stub address when unlinking a shared object. */ - sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset); - } - - BFD_ASSERT (h->dynindx != -1 || h->forced_local); - - sgot = score_elf_got_section (dynobj, FALSE); - BFD_ASSERT (sgot != NULL); - BFD_ASSERT (score_elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - - /* Run through the global symbol table, creating GOT entries for all - the symbols that need them. */ - if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx) - { - bfd_vma offset; - bfd_vma value; - - value = sym->st_value; - offset = score_elf_global_got_index (dynobj, h); - score_bfd_put_32 (output_bfd, value, sgot->contents + offset); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - name = h->root.root.string; - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - else if (strcmp (name, "_DYNAMIC_LINK") == 0) - { - sym->st_shndx = SHN_ABS; - sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); - sym->st_value = 1; - } - else if (strcmp (name, GP_DISP_LABEL) == 0) - { - sym->st_shndx = SHN_ABS; - sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); - sym->st_value = elf_gp (output_bfd); - } - - return TRUE; -} - -/* Finish up the dynamic sections. */ -static bfd_boolean -s3_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - asection *sgot; - asection *s; - struct score_got_info *g; - - dynobj = elf_hash_table (info)->dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - sgot = score_elf_got_section (dynobj, FALSE); - if (sgot == NULL) - g = NULL; - else - { - BFD_ASSERT (score_elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - bfd_byte *b; - - BFD_ASSERT (sdyn != NULL); - BFD_ASSERT (g != NULL); - - for (b = sdyn->contents; - b < sdyn->contents + sdyn->size; - b += SCORE_ELF_DYN_SIZE (dynobj)) - { - Elf_Internal_Dyn dyn; - const char *name; - size_t elemsize; - bfd_boolean swap_out_p; - - /* Read in the current dynamic entry. */ - (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); - - /* Assume that we're going to modify it and write it out. */ - swap_out_p = TRUE; - - switch (dyn.d_tag) - { - case DT_RELENT: - dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj); - break; - - case DT_STRSZ: - /* Rewrite DT_STRSZ. */ - dyn.d_un.d_val - = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); - break; - - case DT_PLTGOT: - s = elf_hash_table (info)->sgot; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_SCORE_BASE_ADDRESS: - s = output_bfd->sections; - BFD_ASSERT (s != NULL); - dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff; - break; - - case DT_SCORE_LOCAL_GOTNO: - dyn.d_un.d_val = g->local_gotno; - break; - - case DT_SCORE_UNREFEXTNO: - /* The index into the dynamic symbol table which is the - entry of the first external symbol that is not - referenced within the same object. */ - dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1; - break; - - case DT_SCORE_GOTSYM: - if (g->global_gotsym) - { - dyn.d_un.d_val = g->global_gotsym->dynindx; - break; - } - /* In case if we don't have global got symbols we default - to setting DT_SCORE_GOTSYM to the same value as - DT_SCORE_SYMTABNO. */ - /* Fall through. */ - - case DT_SCORE_SYMTABNO: - name = ".dynsym"; - elemsize = SCORE_ELF_SYM_SIZE (output_bfd); - s = bfd_get_linker_section (dynobj, name); - dyn.d_un.d_val = s->size / elemsize; - break; - - case DT_SCORE_HIPAGENO: - dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO; - break; - - default: - swap_out_p = FALSE; - break; - } - - if (swap_out_p) - (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b); - } - } - - /* The first entry of the global offset table will be filled at - runtime. The second entry will be used by some runtime loaders. - This isn't the case of IRIX rld. */ - if (sgot != NULL && sgot->size > 0) - { - score_bfd_put_32 (output_bfd, 0, sgot->contents); - score_bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd)); - } - - if (sgot != NULL) - elf_section_data (sgot->output_section)->this_hdr.sh_entsize - = SCORE_ELF_GOT_SIZE (output_bfd); - - - /* We need to sort the entries of the dynamic relocation section. */ - s = score_elf_rel_dyn_section (dynobj, FALSE); - - if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd)) - { - reldyn_sorting_bfd = output_bfd; - qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1, - sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs); - } - - return TRUE; -} - -/* This function 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. */ -static bfd_boolean -s3_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, - asection *sec) -{ - const char *name; - - name = bfd_get_section_name (abfd, sec); - - if (strcmp (name, ".got") == 0 - || strcmp (name, ".srdata") == 0 - || strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0) - hdr->sh_flags |= SHF_SCORE_GPREL; - - return TRUE; -} - -/* This function do additional processing on the ELF section header before writing - it out. This is used to set the flags and type fields for some sections. */ - -/* assign_file_positions_except_relocs() check section flag and if it is allocatable, - warning message will be issued. backend_fake_section is called before - assign_file_positions_except_relocs(); backend_section_processing after it. so, we - modify section flag there, but not backend_fake_section. */ -static bfd_boolean -s3_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) -{ - if (hdr->bfd_section != NULL) - { - const char *name = bfd_get_section_name (abfd, hdr->bfd_section); - - if (strcmp (name, ".sdata") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; - hdr->sh_type = SHT_PROGBITS; - } - else if (strcmp (name, ".sbss") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; - hdr->sh_type = SHT_NOBITS; - } - else if (strcmp (name, ".srdata") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL; - hdr->sh_type = SHT_PROGBITS; - } - } - - return TRUE; -} - -static bfd_boolean -s3_bfd_score_elf_write_section (bfd *output_bfd, asection *sec, bfd_byte *contents) -{ - bfd_byte *to, *from, *end; - int i; - - if (strcmp (sec->name, ".pdr") != 0) - return FALSE; - - if (score_elf_section_data (sec)->u.tdata == NULL) - return FALSE; - - to = contents; - end = contents + sec->size; - for (from = contents, i = 0; from < end; from += PDR_SIZE, i++) - { - if ((score_elf_section_data (sec)->u.tdata)[i] == 1) - continue; - - if (to != from) - memcpy (to, from, PDR_SIZE); - - to += PDR_SIZE; - } - bfd_set_section_contents (output_bfd, sec->output_section, contents, - (file_ptr) sec->output_offset, sec->size); - - return TRUE; -} - -/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old - indirect symbol. Process additional relocation information. */ -static void -s3_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct score_elf_link_hash_entry *dirscore, *indscore; - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); - - if (ind->root.type != bfd_link_hash_indirect) - return; - - dirscore = (struct score_elf_link_hash_entry *) dir; - indscore = (struct score_elf_link_hash_entry *) ind; - dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs; - - if (indscore->readonly_reloc) - dirscore->readonly_reloc = TRUE; - - if (indscore->no_fn_stub) - dirscore->no_fn_stub = TRUE; -} - -/* Remove information about discarded functions from other sections which mention them. */ -static bfd_boolean -s3_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, - struct bfd_link_info *info) -{ - asection *o; - bfd_boolean ret = FALSE; - unsigned char *tdata; - size_t i, skip; - - o = bfd_get_section_by_name (abfd, ".pdr"); - if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0) - || (o->output_section != NULL && bfd_is_abs_section (o->output_section))) - return FALSE; - - tdata = bfd_zmalloc (o->size / PDR_SIZE); - if (!tdata) - return FALSE; - - cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory); - if (!cookie->rels) - { - free (tdata); - return FALSE; - } - - cookie->rel = cookie->rels; - cookie->relend = cookie->rels + o->reloc_count; - - for (i = 0, skip = 0; i < o->size; i++) - { - if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie)) - { - tdata[i] = 1; - skip++; - } - } - - if (skip != 0) - { - score_elf_section_data (o)->u.tdata = tdata; - o->size -= skip * PDR_SIZE; - ret = TRUE; - } - else - free (tdata); - - if (!info->keep_memory) - free (cookie->rels); - - return ret; -} - -/* Signal that discard_info() has removed the discarded relocations for this section. */ -static bfd_boolean -s3_bfd_score_elf_ignore_discarded_relocs (asection *sec) -{ - if (strcmp (sec->name, ".pdr") == 0) - return TRUE; - return FALSE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ -static asection * -s3_bfd_score_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_SCORE_GNU_VTINHERIT: - case R_SCORE_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -s3_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int raw_size; - - switch (note->descsz) - { - default: - return FALSE; - - case 148: /* Linux/Score 32-bit. */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal - = score_bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid - = score_bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - raw_size = 72; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, - note->descpos + offset); -} - -static bfd_boolean -s3_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/Score 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; -} - - -/* Score BFD functions. */ -static reloc_howto_type * -s3_elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_score_reloc_map); i++) - if (elf32_score_reloc_map[i].bfd_reloc_val == code) - return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -elf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf32_score_howto_table) - / sizeof (elf32_score_howto_table[0])); - i++) - if (elf32_score_howto_table[i].name != NULL - && strcasecmp (elf32_score_howto_table[i].name, r_name) == 0) - return &elf32_score_howto_table[i]; - - return NULL; -} - -static bfd_boolean -s3_elf32_score_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC) - { - fprintf (file, _(" [pic]")); - } - if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP) - { - fprintf (file, _(" [fix dep]")); - } - fputc ('\n', file); - - return TRUE; -} - -static bfd_boolean -s3_elf32_score_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword in_flags; - flagword out_flags; - - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - { - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); - } - - return TRUE; - } - - if (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0)) - _bfd_error_handler - (_("%B: warning: linking PIC files with non-PIC files"), ibfd); - - /* FIXME: Maybe dependency fix compatibility should be checked here. */ - - return TRUE; -} - -static bfd_boolean -s3_elf32_score_new_section_hook (bfd *abfd, asection *sec) -{ - struct _score_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - - return _bfd_elf_new_section_hook (abfd, sec); -} - -/*****************************************************************************/ - -/* s3_s7: backend hooks. */ -static void -_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc); - else - return s7_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc); -} - -static bfd_boolean -_bfd_score_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - if (bfd_get_mach (output_bfd) == bfd_mach_score3) - return s3_bfd_score_elf_relocate_section (output_bfd, - info, input_bfd, input_section, contents, relocs, - local_syms, local_sections); - else - return s7_bfd_score_elf_relocate_section (output_bfd, - info, input_bfd, input_section, contents, relocs, - local_syms, local_sections); -} - -static bfd_boolean -_bfd_score_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_check_relocs (abfd, info, sec, relocs); - else - return s7_bfd_score_elf_check_relocs (abfd, info, sec, relocs); -} - -static bfd_boolean -_bfd_score_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, - secp, valp); - else - return s7_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, - secp, valp); -} - -static void -_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_symbol_processing (abfd, asym); - else - return s7_bfd_score_elf_symbol_processing (abfd, asym); -} - -static int -_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - /* If link a empty .o, then this filed is NULL. */ - if (info->input_bfds == NULL) - { - /* If we see a common symbol, which implies a relocatable link, then - if a symbol was small common in an input file, mark it as small - common in the output file. */ - if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) - sym->st_shndx = SHN_SCORE_SCOMMON; - return 1; - } - - if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) - return s3_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h); - else - return s7_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h); -} - -static bfd_boolean -_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_section_from_bfd_section (abfd, sec, retval); - else - return s7_bfd_score_elf_section_from_bfd_section (abfd, sec, retval); -} - -static bfd_boolean -_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) - return s3_bfd_score_elf_adjust_dynamic_symbol (info, h); - else - return s7_bfd_score_elf_adjust_dynamic_symbol (info, h); -} - -static bfd_boolean -_bfd_score_elf_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - if (bfd_get_mach (output_bfd) == bfd_mach_score3) - return s3_bfd_score_elf_always_size_sections (output_bfd, info); - else - return s7_bfd_score_elf_always_size_sections (output_bfd, info); -} - -static bfd_boolean -_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - if (bfd_get_mach (output_bfd) == bfd_mach_score3) - return s3_bfd_score_elf_size_dynamic_sections (output_bfd, info); - else - return s7_bfd_score_elf_size_dynamic_sections (output_bfd, info); -} - -static bfd_boolean -_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_create_dynamic_sections (abfd, info); - else - return s7_bfd_score_elf_create_dynamic_sections (abfd, info); -} - -static bfd_boolean -_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (bfd_get_mach (output_bfd) == bfd_mach_score3) - return s3_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym); - else - return s7_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym); -} - -static bfd_boolean -_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - if (bfd_get_mach (output_bfd) == bfd_mach_score3) - return s3_bfd_score_elf_finish_dynamic_sections (output_bfd, info); - else - return s7_bfd_score_elf_finish_dynamic_sections (output_bfd, info); -} - -static bfd_boolean -_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, - asection *sec) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_fake_sections (abfd, hdr, sec); - else - return s7_bfd_score_elf_fake_sections (abfd, hdr, sec); -} - -static bfd_boolean -_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_section_processing (abfd, hdr); - else - return s7_bfd_score_elf_section_processing (abfd, hdr); -} - -static bfd_boolean -_bfd_score_elf_write_section (bfd *output_bfd, - struct bfd_link_info *link_info ATTRIBUTE_UNUSED, - asection *sec, bfd_byte *contents) -{ - if (bfd_get_mach (output_bfd) == bfd_mach_score3) - return s3_bfd_score_elf_write_section (output_bfd, sec, contents); - else - return s7_bfd_score_elf_write_section (output_bfd, sec, contents); -} - -static void -_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) - return s3_bfd_score_elf_copy_indirect_symbol (info, dir, ind); - else - return s7_bfd_score_elf_copy_indirect_symbol (info, dir, ind); -} - -static void -_bfd_score_elf_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *entry, - bfd_boolean force_local) -{ - if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) - return s3_bfd_score_elf_hide_symbol (info, entry, force_local); - else - return s7_bfd_score_elf_hide_symbol (info, entry, force_local); -} - -static bfd_boolean -_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, - struct bfd_link_info *info) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_discard_info (abfd, cookie, info); - else - return s7_bfd_score_elf_discard_info (abfd, cookie, info); -} - -static bfd_boolean -_bfd_score_elf_ignore_discarded_relocs (asection *sec) -{ - if (bfd_get_mach (sec->owner) == bfd_mach_score3) - return s3_bfd_score_elf_ignore_discarded_relocs (sec); - else - return s7_bfd_score_elf_ignore_discarded_relocs (sec); -} - -static asection * -_bfd_score_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (bfd_get_mach (info->input_bfds) == bfd_mach_score3) - return s3_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym); - else - return s7_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -static bfd_boolean -_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_grok_prstatus (abfd, note); - else - return s7_bfd_score_elf_grok_prstatus (abfd, note); -} - -static bfd_boolean -_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_bfd_score_elf_grok_psinfo (abfd, note); - else - return s7_bfd_score_elf_grok_psinfo (abfd, note); -} - -static reloc_howto_type * -elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) -{ - /* s3: NOTE!!! - gas will call elf32_score_reloc_type_lookup, and don't write elf file. - So just using score3, but we don't know ld will call this or not. - If so, this way can't work. */ - - if (score3) - return s3_elf32_score_reloc_type_lookup (abfd, code); - else - return s7_elf32_score_reloc_type_lookup (abfd, code); -} - -/* Create a score elf linker hash table. - This is a copy of _bfd_elf_link_hash_table_create() except with a - different hash table entry creation function. */ - -static struct bfd_link_hash_table * -elf32_score_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_link_hash_table); - - ret = (struct elf_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (ret, abfd, score_elf_link_hash_newfunc, - sizeof (struct score_elf_link_hash_entry), - GENERIC_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root; -} - -static bfd_boolean -elf32_score_print_private_bfd_data (bfd *abfd, void * ptr) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_elf32_score_print_private_bfd_data (abfd, ptr); - else - return s7_elf32_score_print_private_bfd_data (abfd, ptr); -} - -static bfd_boolean -elf32_score_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - if (bfd_get_mach (info->output_bfd) == bfd_mach_score3) - return s3_elf32_score_merge_private_bfd_data (ibfd, info); - else - return s7_elf32_score_merge_private_bfd_data (ibfd, info); -} - -static bfd_boolean -elf32_score_new_section_hook (bfd *abfd, asection *sec) -{ - if (bfd_get_mach (abfd) == bfd_mach_score3) - return s3_elf32_score_new_section_hook (abfd, sec); - else - return s7_elf32_score_new_section_hook (abfd, sec); -} - - -/* s3_s7: don't need to split. */ - -/* Set the right machine number. */ -static bfd_boolean -_bfd_score_elf_score_object_p (bfd * abfd) -{ - int e_set = bfd_mach_score7; - - if (elf_elfheader (abfd)->e_machine == EM_SCORE) - { - int e_mach = elf_elfheader (abfd)->e_flags & EF_SCORE_MACH & EF_OMIT_PIC_FIXDD; - switch (e_mach) - { - /* Set default target is score7. */ - default: - case E_SCORE_MACH_SCORE7: - e_set = bfd_mach_score7; - break; - - case E_SCORE_MACH_SCORE3: - e_set = bfd_mach_score3; - break; - } - } - - return bfd_default_set_arch_mach (abfd, bfd_arch_score, e_set); -} - -bfd_boolean -_bfd_score_elf_common_definition (Elf_Internal_Sym *sym) -{ - return (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_SCORE_SCOMMON); -} - -/*****************************************************************************/ - - -#define USE_REL 1 -#define TARGET_LITTLE_SYM score_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-littlescore" -#define TARGET_BIG_SYM score_elf32_be_vec -#define TARGET_BIG_NAME "elf32-bigscore" -#define ELF_ARCH bfd_arch_score -#define ELF_MACHINE_CODE EM_SCORE -#define ELF_MACHINE_ALT1 EM_SCORE_OLD -#define ELF_MAXPAGESIZE 0x8000 - -#define elf_info_to_howto 0 -#define elf_info_to_howto_rel _bfd_score_info_to_howto -#define elf_backend_relocate_section _bfd_score_elf_relocate_section -#define elf_backend_check_relocs _bfd_score_elf_check_relocs -#define elf_backend_add_symbol_hook _bfd_score_elf_add_symbol_hook -#define elf_backend_symbol_processing _bfd_score_elf_symbol_processing -#define elf_backend_link_output_symbol_hook \ - _bfd_score_elf_link_output_symbol_hook -#define elf_backend_section_from_bfd_section \ - _bfd_score_elf_section_from_bfd_section -#define elf_backend_adjust_dynamic_symbol \ - _bfd_score_elf_adjust_dynamic_symbol -#define elf_backend_always_size_sections \ - _bfd_score_elf_always_size_sections -#define elf_backend_size_dynamic_sections \ - _bfd_score_elf_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_create_dynamic_sections \ - _bfd_score_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_symbol \ - _bfd_score_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_score_elf_finish_dynamic_sections -#define elf_backend_fake_sections _bfd_score_elf_fake_sections -#define elf_backend_section_processing _bfd_score_elf_section_processing -#define elf_backend_write_section _bfd_score_elf_write_section -#define elf_backend_copy_indirect_symbol _bfd_score_elf_copy_indirect_symbol -#define elf_backend_hide_symbol _bfd_score_elf_hide_symbol -#define elf_backend_discard_info _bfd_score_elf_discard_info -#define elf_backend_ignore_discarded_relocs \ - _bfd_score_elf_ignore_discarded_relocs -#define elf_backend_gc_mark_hook _bfd_score_elf_gc_mark_hook -#define elf_backend_grok_prstatus _bfd_score_elf_grok_prstatus -#define elf_backend_grok_psinfo _bfd_score_elf_grok_psinfo -#define elf_backend_can_gc_sections 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size (4 * SCORE_RESERVED_GOTNO) -#define elf_backend_plt_header_size 0 -#define elf_backend_collect TRUE -#define elf_backend_type_change_ok TRUE -#define elf_backend_object_p _bfd_score_elf_score_object_p - -#define bfd_elf32_bfd_reloc_type_lookup elf32_score_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - elf32_score_reloc_name_lookup -#define bfd_elf32_bfd_link_hash_table_create elf32_score_link_hash_table_create -#define bfd_elf32_bfd_print_private_bfd_data elf32_score_print_private_bfd_data -#define bfd_elf32_bfd_merge_private_bfd_data elf32_score_merge_private_bfd_data -#define bfd_elf32_new_section_hook elf32_score_new_section_hook - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-score.h b/sdcc/support/sdbinutils/bfd/elf32-score.h deleted file mode 100644 index dc9fd1ea9..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-score.h +++ /dev/null @@ -1,152 +0,0 @@ -/* 32-bit ELF support for S+core. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Contributed by - Brain.lin (brain.lin@sunplusct.com) - Mei Ligang (ligang@sunnorth.com.cn) - Pei-Lin Tsai (pltsai@sunplus.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "elf/common.h" -#include "elf/internal.h" - -extern void -s7_bfd_score_elf_hide_symbol (struct bfd_link_info *, - struct elf_link_hash_entry *, - bfd_boolean); - -extern void -s7_bfd_score_info_to_howto (bfd *, arelent *, Elf_Internal_Rela *); - -extern bfd_boolean -s7_bfd_score_elf_relocate_section (bfd *, - struct bfd_link_info *, - bfd *, - asection *, - bfd_byte *, - Elf_Internal_Rela *, - Elf_Internal_Sym *, - asection **); - -extern bfd_boolean -s7_bfd_score_elf_check_relocs (bfd *, - struct bfd_link_info *, - asection *, - const Elf_Internal_Rela *); - -extern bfd_boolean -s7_bfd_score_elf_add_symbol_hook (bfd *, - struct bfd_link_info *, - Elf_Internal_Sym *, - const char **, - flagword *, - asection **, - bfd_vma *); - -extern void -s7_bfd_score_elf_symbol_processing (bfd *, asymbol *); - -extern int -s7_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *, - const char *, - Elf_Internal_Sym *, - asection *, - struct elf_link_hash_entry *); - -extern bfd_boolean -s7_bfd_score_elf_section_from_bfd_section (bfd *, - asection *, - int *); - -extern bfd_boolean -s7_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *, - struct elf_link_hash_entry *); - -extern bfd_boolean -s7_bfd_score_elf_always_size_sections (bfd *, struct bfd_link_info *); - -extern bfd_boolean -s7_bfd_score_elf_size_dynamic_sections (bfd *, struct bfd_link_info *); - -extern bfd_boolean -s7_bfd_score_elf_create_dynamic_sections (bfd *, struct bfd_link_info *); - -extern bfd_boolean -s7_bfd_score_elf_finish_dynamic_symbol (bfd *, - struct bfd_link_info *, - struct elf_link_hash_entry *, - Elf_Internal_Sym *); - -extern bfd_boolean -s7_bfd_score_elf_finish_dynamic_sections (bfd *, struct bfd_link_info *); - -extern bfd_boolean -s7_bfd_score_elf_fake_sections (bfd *, - Elf_Internal_Shdr *, - asection *); - -extern bfd_boolean -s7_bfd_score_elf_section_processing (bfd *, Elf_Internal_Shdr *); - -extern bfd_boolean -s7_bfd_score_elf_write_section (bfd *, asection *, bfd_byte *); - -extern void -s7_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *, - struct elf_link_hash_entry *, - struct elf_link_hash_entry *); - -extern bfd_boolean -s7_bfd_score_elf_discard_info (bfd *, struct elf_reloc_cookie *, - struct bfd_link_info *); - -extern bfd_boolean -s7_bfd_score_elf_ignore_discarded_relocs (asection *); - -extern asection * -s7_bfd_score_elf_gc_mark_hook (asection *, - struct bfd_link_info *, - Elf_Internal_Rela *, - struct elf_link_hash_entry *, - Elf_Internal_Sym *); - -extern bfd_boolean -s7_bfd_score_elf_grok_prstatus (bfd *, Elf_Internal_Note *); - -extern bfd_boolean -s7_bfd_score_elf_grok_psinfo (bfd *, Elf_Internal_Note *); - -extern reloc_howto_type * -s7_elf32_score_reloc_type_lookup (bfd *, bfd_reloc_code_real_type); - -extern struct bfd_link_hash_table * -s7_elf32_score_link_hash_table_create (bfd *); - -extern bfd_boolean -s7_elf32_score_print_private_bfd_data (bfd *, void *); - -extern bfd_boolean -s7_elf32_score_merge_private_bfd_data (bfd *, struct bfd_link_info *); - -extern bfd_boolean -s7_elf32_score_new_section_hook (bfd *, asection *); - -extern bfd_boolean -_bfd_score_elf_common_definition (Elf_Internal_Sym *); - -#define elf_backend_common_definition _bfd_score_elf_common_definition diff --git a/sdcc/support/sdbinutils/bfd/elf32-score7.c b/sdcc/support/sdbinutils/bfd/elf32-score7.c deleted file mode 100644 index 2b803e672..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-score7.c +++ /dev/null @@ -1,3875 +0,0 @@ -/* 32-bit ELF support for S+core. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Contributed by - Brain.lin (brain.lin@sunplusct.com) - Mei Ligang (ligang@sunnorth.com.cn) - Pei-Lin Tsai (pltsai@sunplus.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" -#include "elf-bfd.h" -#include "elf/score.h" -#include "elf/common.h" -#include "elf/internal.h" -#include "hashtab.h" -#include "elf32-score.h" - - -/* The SCORE ELF linker needs additional information for each symbol in - the global hash table. */ -struct score_elf_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol. */ - unsigned int possibly_dynamic_relocs; - - /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section. */ - bfd_boolean readonly_reloc; - - /* We must not create a stub for a symbol that has relocations related to - taking the function's address, i.e. any but R_SCORE_CALL15 ones. */ - bfd_boolean no_fn_stub; - - /* Are we forced local? This will only be set if we have converted - the initial global GOT entry to a local GOT entry. */ - bfd_boolean forced_local; -}; - -/* Traverse a score ELF linker hash table. */ -#define score_elf_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - ((table), \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* This structure is used to hold .got entries while estimating got sizes. */ -struct score_got_entry -{ - /* The input bfd in which the symbol is defined. */ - bfd *abfd; - /* The index of the symbol, as stored in the relocation r_info, if - we have a local symbol; -1 otherwise. */ - long symndx; - union - { - /* If abfd == NULL, an address that must be stored in the got. */ - bfd_vma address; - /* If abfd != NULL && symndx != -1, the addend of the relocation - that should be added to the symbol value. */ - bfd_vma addend; - /* If abfd != NULL && symndx == -1, the hash table entry - corresponding to a global symbol in the got (or, local, if - h->forced_local). */ - struct score_elf_link_hash_entry *h; - } d; - - /* The offset from the beginning of the .got section to the entry - corresponding to this symbol+addend. If it's a global symbol - whose offset is yet to be decided, it's going to be -1. */ - long gotidx; -}; - -/* This structure is passed to score_elf_sort_hash_table_f when sorting - the dynamic symbols. */ -struct score_elf_hash_sort_data -{ - /* The symbol in the global GOT with the lowest dynamic symbol table index. */ - struct elf_link_hash_entry *low; - /* The least dynamic symbol table index corresponding to a symbol with a GOT entry. */ - long min_got_dynindx; - /* The greatest dynamic symbol table index corresponding to a symbol - with a GOT entry that is not referenced (e.g., a dynamic symbol - with dynamic relocations pointing to it from non-primary GOTs). */ - long max_unref_got_dynindx; - /* The greatest dynamic symbol table index not corresponding to a - symbol without a GOT entry. */ - long max_non_got_dynindx; -}; - -struct score_got_info -{ - /* The global symbol in the GOT with the lowest index in the dynamic - symbol table. */ - struct elf_link_hash_entry *global_gotsym; - /* The number of global .got entries. */ - unsigned int global_gotno; - /* The number of local .got entries. */ - unsigned int local_gotno; - /* The number of local .got entries we have used. */ - unsigned int assigned_gotno; - /* A hash table holding members of the got. */ - struct htab *got_entries; - /* In multi-got links, a pointer to the next got (err, rather, most - of the time, it points to the previous got). */ - struct score_got_info *next; -}; - -/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal. */ -struct _score_elf_section_data -{ - struct bfd_elf_section_data elf; - union - { - struct score_got_info *got_info; - bfd_byte *tdata; - } - u; -}; - -#define score_elf_section_data(sec) \ - ((struct _score_elf_section_data *) elf_section_data (sec)) - -/* The size of a symbol-table entry. */ -#define SCORE_ELF_SYM_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->sizeof_sym) - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) -#define MINUS_TWO (((bfd_vma)0) - 2) - -#define PDR_SIZE 32 - - -/* The number of local .got entries we reserve. */ -#define SCORE_RESERVED_GOTNO (2) -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -/* The offset of $gp from the beginning of the .got section. */ -#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0) - -/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp. */ -#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff) - -#define SCORE_ELF_STUB_SECTION_NAME (".SCORE.stub") -#define SCORE_FUNCTION_STUB_SIZE (16) - -#define STUB_LW 0xc3bcc010 /* lw r29, [r28, -0x3ff0] */ -#define STUB_MOVE 0x8323bc56 /* mv r25, r3 */ -#define STUB_LI16 0x87548000 /* ori r26, .dynsym_index */ -#define STUB_BRL 0x801dbc09 /* brl r29 */ - -#define SCORE_ELF_GOT_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->arch_size / 8) - -#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \ - (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val)) - -/* The size of an external dynamic table entry. */ -#define SCORE_ELF_DYN_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->sizeof_dyn) - -/* The size of an external REL relocation. */ -#define SCORE_ELF_REL_SIZE(abfd) \ - (get_elf_backend_data (abfd)->s->sizeof_rel) - -/* The default alignment for sections, as a power of two. */ -#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ - (get_elf_backend_data (abfd)->s->log_file_align) - -static bfd_byte *hi16_rel_addr; - -/* This will be used when we sort the dynamic relocation records. */ -static bfd *reldyn_sorting_bfd; - -/* SCORE ELF uses two common sections. One is the usual one, and the - other is for small objects. All the small objects are kept - together, and then referenced via the gp pointer, which yields - faster assembler code. This is what we use for the small common - section. This approach is copied from ecoff.c. */ -static asection score_elf_scom_section; -static asymbol score_elf_scom_symbol; -static asymbol * score_elf_scom_symbol_ptr; - -static bfd_reloc_status_type -score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -score_elf_lo16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma addend = 0, offset = 0; - unsigned long val; - unsigned long hi16_offset, hi16_value, uvalue; - - hi16_value = bfd_get_32 (abfd, hi16_rel_addr); - hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; - addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; - val = reloc_entry->addend; - if (reloc_entry->address > input_section->size) - return bfd_reloc_outofrange; - uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (abfd, hi16_value, hi16_rel_addr); - offset = (uvalue & 0xffff) << 1; - addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ - -static bfd_boolean -score_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) -{ - unsigned int count; - asymbol **sym; - unsigned int i; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - /* The linker script will have created a symbol named `_gp' with the - appropriate value. */ - if (sym == NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - *pgp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, *pgp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - return TRUE; -} - -/* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static bfd_reloc_status_type -score_elf_final_gp (bfd *output_bfd, - asymbol *symbol, - bfd_boolean relocatable, - char **error_message, - bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) - && ! relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 - && (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma + 0x4000; - _bfd_set_gp_value (output_bfd, *pgp); - } - else if (!score_elf_assign_gp (output_bfd, pgp)) - { - *error_message = - (char *) _("GP relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -score_elf_gprel15_with_gp (bfd *abfd, - asymbol *symbol, - arelent *reloc_entry, - asection *input_section, - bfd_boolean relocateable, - void * data, - bfd_vma gp ATTRIBUTE_UNUSED) -{ - bfd_vma relocation; - unsigned long insn; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - if (reloc_entry->address > input_section->size) - return bfd_reloc_outofrange; - - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - if (((reloc_entry->addend & 0xffffc000) != 0) - && ((reloc_entry->addend & 0xffffc000) != 0xffffc000)) - return bfd_reloc_overflow; - - insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff); - bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); - if (relocateable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, - asection *input_section, bfd_boolean relocatable, - void *data, bfd_vma gp) -{ - bfd_vma relocation; - bfd_vma val; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Set val to the offset into the section or symbol. */ - val = reloc_entry->addend; - - if (reloc_entry->howto->partial_inplace) - val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - - /* Adjust val for the final section location and GP value. If we - are producing relocatable output, we don't want to do this for - an external symbol. */ - if (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0) - val += relocation - gp; - - if (reloc_entry->howto->partial_inplace) - bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); - else - reloc_entry->addend = val; - - if (relocatable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -score_elf_gprel15_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocateable; - bfd_reloc_status_type ret; - bfd_vma gp; - - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - if (output_bfd != NULL) - relocateable = TRUE; - else - { - relocateable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - - return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry, - input_section, relocateable, data, gp); -} - -/* Do a R_SCORE_GPREL32 relocation. This is a 32 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* R_SCORE_GPREL32 relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("32bits gp relative relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - - gp = 0; - return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, - relocatable, data, gp); -} - -/* A howto special_function for R_SCORE_GOT15 relocations. This is just - like any other 16-bit relocation when applied to global symbols, but is - treated in the same as R_SCORE_HI16 when applied to local symbols. */ - -static bfd_reloc_status_type -score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 - || bfd_is_und_section (bfd_get_section (symbol)) - || bfd_is_com_section (bfd_get_section (symbol))) - /* The relocation is against a global symbol. */ - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, - error_message); - - return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - -static bfd_reloc_status_type -score_elf_got_lo16_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma addend = 0, offset = 0; - signed long val; - signed long hi16_offset, hi16_value, uvalue; - - hi16_value = bfd_get_32 (abfd, hi16_rel_addr); - hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; - addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; - val = reloc_entry->addend; - if (reloc_entry->address > input_section->size) - return bfd_reloc_outofrange; - uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - if ((uvalue > -0x8000) && (uvalue < 0x7fff)) - hi16_offset = 0; - else - hi16_offset = (uvalue >> 16) & 0x7fff; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (abfd, hi16_value, hi16_rel_addr); - offset = (uvalue & 0xffff) << 1; - addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); - return bfd_reloc_ok; -} - -static reloc_howto_type elf32_score_howto_table[] = -{ - /* No relocation. */ - HOWTO (R_SCORE_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_HI16 */ - HOWTO (R_SCORE_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_hi16_reloc, /* special_function */ - "R_SCORE_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x37fff, /* src_mask */ - 0x37fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_LO16 */ - HOWTO (R_SCORE_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_lo16_reloc, /* special_function */ - "R_SCORE_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x37fff, /* src_mask */ - 0x37fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_BCMP */ - HOWTO (R_SCORE_BCMP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_BCMP", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SCORE_24, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_24", /* name */ - FALSE, /* partial_inplace */ - 0x3ff7fff, /* src_mask */ - 0x3ff7fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /*R_SCORE_PC19 */ - HOWTO (R_SCORE_PC19, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_PC19", /* name */ - FALSE, /* partial_inplace */ - 0x3ff03fe, /* src_mask */ - 0x3ff03fe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /*R_SCORE16_11 */ - HOWTO (R_SCORE16_11, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE16_11", /* name */ - FALSE, /* partial_inplace */ - 0x000000ffe, /* src_mask */ - 0x000000ffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE16_PC8 */ - HOWTO (R_SCORE16_PC8, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE16_PC8", /* name */ - FALSE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute */ - HOWTO (R_SCORE_ABS32, /* type 8 */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_ABS32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit absolute */ - HOWTO (R_SCORE_ABS16, /* type 11 */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_DUMMY2 */ - HOWTO (R_SCORE_DUMMY2, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_DUMMY2", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_GP15 */ - HOWTO (R_SCORE_GP15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_gprel15_reloc,/* special_function */ - "R_SCORE_GP15", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_SCORE_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_SCORE_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_SCORE_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_SCORE_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_SCORE_GOT15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - score_elf_got15_reloc, /* special_function */ - "R_SCORE_GOT15", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_SCORE_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_got_lo16_reloc, /* special_function */ - "R_SCORE_GOT_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x37ffe, /* src_mask */ - 0x37ffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 15 bit call through global offset table. */ - HOWTO (R_SCORE_CALL15, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_CALL15", /* name */ - TRUE, /* partial_inplace */ - 0x00007fff, /* src_mask */ - 0x00007fff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_SCORE_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_gprel32_reloc, /* special_function */ - "R_SCORE_GPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_SCORE_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SCORE_REL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_SCORE_DUMMY_HI16 */ - HOWTO (R_SCORE_DUMMY_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - score_elf_hi16_reloc, /* special_function */ - "R_SCORE_DUMMY_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x37fff, /* src_mask */ - 0x37fff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -struct score_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct score_reloc_map elf32_score_reloc_map[] = -{ - {BFD_RELOC_NONE, R_SCORE_NONE}, - {BFD_RELOC_HI16_S, R_SCORE_HI16}, - {BFD_RELOC_LO16, R_SCORE_LO16}, - {BFD_RELOC_SCORE_BCMP, R_SCORE_BCMP}, - {BFD_RELOC_SCORE_JMP, R_SCORE_24}, - {BFD_RELOC_SCORE_BRANCH, R_SCORE_PC19}, - {BFD_RELOC_SCORE16_JMP, R_SCORE16_11}, - {BFD_RELOC_SCORE16_BRANCH, R_SCORE16_PC8}, - {BFD_RELOC_32, R_SCORE_ABS32}, - {BFD_RELOC_16, R_SCORE_ABS16}, - {BFD_RELOC_SCORE_DUMMY2, R_SCORE_DUMMY2}, - {BFD_RELOC_SCORE_GPREL15, R_SCORE_GP15}, - {BFD_RELOC_VTABLE_INHERIT, R_SCORE_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_SCORE_GNU_VTENTRY}, - {BFD_RELOC_SCORE_GOT15, R_SCORE_GOT15}, - {BFD_RELOC_SCORE_GOT_LO16, R_SCORE_GOT_LO16}, - {BFD_RELOC_SCORE_CALL15, R_SCORE_CALL15}, - {BFD_RELOC_GPREL32, R_SCORE_GPREL32}, - {BFD_RELOC_32_PCREL, R_SCORE_REL32}, - {BFD_RELOC_SCORE_DUMMY_HI16, R_SCORE_DUMMY_HI16}, -}; - -static INLINE hashval_t -score_elf_hash_bfd_vma (bfd_vma addr) -{ -#ifdef BFD64 - return addr + (addr >> 32); -#else - return addr; -#endif -} - -/* got_entries only match if they're identical, except for gotidx, so - use all fields to compute the hash, and compare the appropriate - union members. */ - -static hashval_t -score_elf_got_entry_hash (const void *entry_) -{ - const struct score_got_entry *entry = (struct score_got_entry *) entry_; - - return entry->symndx - + (! entry->abfd ? score_elf_hash_bfd_vma (entry->d.address) - : entry->abfd->id - + (entry->symndx >= 0 ? score_elf_hash_bfd_vma (entry->d.addend) - : entry->d.h->root.root.root.hash)); -} - -static int -score_elf_got_entry_eq (const void *entry1, const void *entry2) -{ - const struct score_got_entry *e1 = (struct score_got_entry *) entry1; - const struct score_got_entry *e2 = (struct score_got_entry *) entry2; - - return e1->abfd == e2->abfd && e1->symndx == e2->symndx - && (! e1->abfd ? e1->d.address == e2->d.address - : e1->symndx >= 0 ? e1->d.addend == e2->d.addend - : e1->d.h == e2->d.h); -} - -/* If H needs a GOT entry, assign it the highest available dynamic - index. Otherwise, assign it the lowest available dynamic - index. */ - -static bfd_boolean -score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data) -{ - struct score_elf_hash_sort_data *hsd = data; - - /* Symbols without dynamic symbol table entries aren't interesting at all. */ - if (h->root.dynindx == -1) - return TRUE; - - /* Global symbols that need GOT entries that are not explicitly - referenced are marked with got offset 2. Those that are - referenced get a 1, and those that don't need GOT entries get - -1. */ - if (h->root.got.offset == 2) - { - if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx) - hsd->low = (struct elf_link_hash_entry *) h; - h->root.dynindx = hsd->max_unref_got_dynindx++; - } - else if (h->root.got.offset != 1) - h->root.dynindx = hsd->max_non_got_dynindx++; - else - { - h->root.dynindx = --hsd->min_got_dynindx; - hsd->low = (struct elf_link_hash_entry *) h; - } - - return TRUE; -} - -static asection * -score_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded) -{ - asection *sgot = bfd_get_linker_section (abfd, ".got"); - - if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0)) - return NULL; - return sgot; -} - -/* Returns the GOT information associated with the link indicated by - INFO. If SGOTP is non-NULL, it is filled in with the GOT section. */ - -static struct score_got_info * -score_elf_got_info (bfd *abfd, asection **sgotp) -{ - asection *sgot; - struct score_got_info *g; - - sgot = score_elf_got_section (abfd, TRUE); - BFD_ASSERT (sgot != NULL); - BFD_ASSERT (elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - - if (sgotp) - *sgotp = sgot; - return g; -} - -/* Sort the dynamic symbol table so that symbols that need GOT entries - appear towards the end. This reduces the amount of GOT space - required. MAX_LOCAL is used to set the number of local symbols - known to be in the dynamic symbol table. During - s7_bfd_score_elf_size_dynamic_sections, this value is 1. Afterward, the - section symbols are added and the count is higher. */ - -static bfd_boolean -score_elf_sort_hash_table (struct bfd_link_info *info, - unsigned long max_local) -{ - struct score_elf_hash_sort_data hsd; - struct score_got_info *g; - bfd *dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - g = score_elf_got_info (dynobj, NULL); - - hsd.low = NULL; - hsd.max_unref_got_dynindx = - hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount - /* In the multi-got case, assigned_gotno of the master got_info - indicate the number of entries that aren't referenced in the - primary GOT, but that must have entries because there are - dynamic relocations that reference it. Since they aren't - referenced, we move them to the end of the GOT, so that they - don't prevent other entries that are referenced from getting - too large offsets. */ - - (g->next ? g->assigned_gotno : 0); - hsd.max_non_got_dynindx = max_local; - score_elf_link_hash_traverse (elf_hash_table (info), - score_elf_sort_hash_table_f, - &hsd); - - /* There should have been enough room in the symbol table to - accommodate both the GOT and non-GOT symbols. */ - BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx); - BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx - <= elf_hash_table (info)->dynsymcount); - - /* Now we know which dynamic symbol has the lowest dynamic symbol - table index in the GOT. */ - g->global_gotsym = hsd.low; - - return TRUE; -} - -/* Returns the first relocation of type r_type found, beginning with - RELOCATION. RELEND is one-past-the-end of the relocation table. */ - -static const Elf_Internal_Rela * -score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, - const Elf_Internal_Rela *relocation, - const Elf_Internal_Rela *relend) -{ - while (relocation < relend) - { - if (ELF32_R_TYPE (relocation->r_info) == r_type) - return relocation; - - ++relocation; - } - - /* We didn't find it. */ - bfd_set_error (bfd_error_bad_value); - return NULL; -} - -/* This function is called via qsort() to sort the dynamic relocation - entries by increasing r_symndx value. */ -static int -score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2) -{ - Elf_Internal_Rela int_reloc1; - Elf_Internal_Rela int_reloc2; - - bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1); - bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2); - - return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info)); -} - -/* Return whether a relocation is against a local symbol. */ -static bfd_boolean -score_elf_local_relocation_p (bfd *input_bfd, - const Elf_Internal_Rela *relocation, - asection **local_sections, - bfd_boolean check_forced) -{ - unsigned long r_symndx; - Elf_Internal_Shdr *symtab_hdr; - struct score_elf_link_hash_entry *h; - size_t extsymoff; - - r_symndx = ELF32_R_SYM (relocation->r_info); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; - - if (r_symndx < extsymoff) - return TRUE; - if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL) - return TRUE; - - if (check_forced) - { - /* Look up the hash table to check whether the symbol was forced local. */ - h = (struct score_elf_link_hash_entry *) - elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; - /* Find the real hash-table entry for this symbol. */ - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; - if (h->root.forced_local) - return TRUE; - } - - return FALSE; -} - -/* Returns the dynamic relocation section for DYNOBJ. */ - -static asection * -score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) -{ - static const char dname[] = ".rel.dyn"; - asection *sreloc; - - sreloc = bfd_get_linker_section (dynobj, dname); - if (sreloc == NULL && create_p) - { - sreloc = bfd_make_section_anyway_with_flags (dynobj, dname, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (sreloc == NULL - || ! bfd_set_section_alignment (dynobj, sreloc, - SCORE_ELF_LOG_FILE_ALIGN (dynobj))) - return NULL; - } - return sreloc; -} - -static void -score_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n) -{ - asection *s; - - s = score_elf_rel_dyn_section (abfd, FALSE); - BFD_ASSERT (s != NULL); - - if (s->size == 0) - { - /* Make room for a null element. */ - s->size += SCORE_ELF_REL_SIZE (abfd); - ++s->reloc_count; - } - s->size += n * SCORE_ELF_REL_SIZE (abfd); -} - -/* Create a rel.dyn relocation for the dynamic linker to resolve. REL - is the original relocation, which is now being transformed into a - dynamic relocation. The ADDENDP is adjusted if necessary; the - caller should store the result in place of the original addend. */ - -static bfd_boolean -score_elf_create_dynamic_relocation (bfd *output_bfd, - struct bfd_link_info *info, - const Elf_Internal_Rela *rel, - struct score_elf_link_hash_entry *h, - bfd_vma symbol, - bfd_vma *addendp, asection *input_section) -{ - Elf_Internal_Rela outrel[3]; - asection *sreloc; - bfd *dynobj; - int r_type; - long indx; - bfd_boolean defined_p; - - r_type = ELF32_R_TYPE (rel->r_info); - dynobj = elf_hash_table (info)->dynobj; - sreloc = score_elf_rel_dyn_section (dynobj, FALSE); - BFD_ASSERT (sreloc != NULL); - BFD_ASSERT (sreloc->contents != NULL); - BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size); - - outrel[0].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset); - outrel[1].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset); - outrel[2].r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); - - if (outrel[0].r_offset == MINUS_ONE) - /* The relocation field has been deleted. */ - return TRUE; - - if (outrel[0].r_offset == MINUS_TWO) - { - /* The relocation field has been converted into a relative value of - some sort. Functions like _bfd_elf_write_section_eh_frame expect - the field to be fully relocated, so add in the symbol's value. */ - *addendp += symbol; - return TRUE; - } - - /* We must now calculate the dynamic symbol table index to use - in the relocation. */ - if (h != NULL - && (! info->symbolic || !h->root.def_regular) - /* h->root.dynindx may be -1 if this symbol was marked to - become local. */ - && h->root.dynindx != -1) - { - indx = h->root.dynindx; - /* ??? glibc's ld.so just adds the final GOT entry to the - relocation field. It therefore treats relocs against - defined symbols in the same way as relocs against - undefined symbols. */ - defined_p = FALSE; - } - else - { - indx = 0; - defined_p = TRUE; - } - - /* If the relocation was previously an absolute relocation and - this symbol will not be referred to by the relocation, we must - adjust it by the value we give it in the dynamic symbol table. - Otherwise leave the job up to the dynamic linker. */ - if (defined_p && r_type != R_SCORE_REL32) - *addendp += symbol; - - /* The relocation is always an REL32 relocation because we don't - know where the shared library will wind up at load-time. */ - outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32); - - /* For strict adherence to the ABI specification, we should - generate a R_SCORE_64 relocation record by itself before the - _REL32/_64 record as well, such that the addend is read in as - a 64-bit value (REL32 is a 32-bit relocation, after all). - However, since none of the existing ELF64 SCORE dynamic - loaders seems to care, we don't waste space with these - artificial relocations. If this turns out to not be true, - score_elf_allocate_dynamic_relocations() should be tweaked so - as to make room for a pair of dynamic relocations per - invocation if ABI_64_P, and here we should generate an - additional relocation record with R_SCORE_64 by itself for a - NULL symbol before this relocation record. */ - outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE); - outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE); - - /* Adjust the output offset of the relocation to reference the - correct location in the output file. */ - outrel[0].r_offset += (input_section->output_section->vma - + input_section->output_offset); - outrel[1].r_offset += (input_section->output_section->vma - + input_section->output_offset); - outrel[2].r_offset += (input_section->output_section->vma - + input_section->output_offset); - - /* Put the relocation back out. We have to use the special - relocation outputter in the 64-bit case since the 64-bit - relocation format is non-standard. */ - bfd_elf32_swap_reloc_out - (output_bfd, &outrel[0], - (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel))); - - /* We've now added another relocation. */ - ++sreloc->reloc_count; - - /* Make sure the output section is writable. The dynamic linker - will be writing to it. */ - elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE; - - return TRUE; -} - -static bfd_boolean -score_elf_create_got_section (bfd *abfd, - struct bfd_link_info *info, - bfd_boolean maybe_exclude) -{ - flagword flags; - asection *s; - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - struct score_got_info *g; - bfd_size_type amt; - - /* This function may be called more than once. */ - s = score_elf_got_section (abfd, TRUE); - if (s) - { - if (! maybe_exclude) - s->flags &= ~SEC_EXCLUDE; - return TRUE; - } - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - - if (maybe_exclude) - flags |= SEC_EXCLUDE; - - /* We have to use an alignment of 2**4 here because this is hardcoded - in the function stub generation and in the linker script. */ - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - elf_hash_table (info)->sgot = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 4)) - return FALSE; - - /* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the - linker script because we don't want to define the symbol if we - are not creating a global offset table. */ - bh = NULL; - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, - 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->non_elf = 0; - h->def_regular = 1; - h->type = STT_OBJECT; - elf_hash_table (info)->hgot = h; - - if (bfd_link_pic (info) - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - amt = sizeof (struct score_got_info); - g = bfd_alloc (abfd, amt); - if (g == NULL) - return FALSE; - - g->global_gotsym = NULL; - g->global_gotno = 0; - - g->local_gotno = SCORE_RESERVED_GOTNO; - g->assigned_gotno = SCORE_RESERVED_GOTNO; - g->next = NULL; - - g->got_entries = htab_try_create (1, score_elf_got_entry_hash, - score_elf_got_entry_eq, NULL); - if (g->got_entries == NULL) - return FALSE; - score_elf_section_data (s)->u.got_info = g; - score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; - - return TRUE; -} - -/* Calculate the %high function. */ - -static bfd_vma -score_elf_high (bfd_vma value) -{ - return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff; -} - -/* Create a local GOT entry for VALUE. Return the index of the entry, - or -1 if it could not be created. */ - -static struct score_got_entry * -score_elf_create_local_got_entry (bfd *abfd, - bfd *ibfd ATTRIBUTE_UNUSED, - struct score_got_info *gg, - asection *sgot, bfd_vma value, - unsigned long r_symndx ATTRIBUTE_UNUSED, - struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED, - int r_type ATTRIBUTE_UNUSED) -{ - struct score_got_entry entry, **loc; - struct score_got_info *g; - - entry.abfd = NULL; - entry.symndx = -1; - entry.d.address = value; - - g = gg; - loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT); - if (*loc) - return *loc; - - entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; - - *loc = bfd_alloc (abfd, sizeof entry); - - if (! *loc) - return NULL; - - memcpy (*loc, &entry, sizeof entry); - - if (g->assigned_gotno >= g->local_gotno) - { - (*loc)->gotidx = -1; - /* We didn't allocate enough space in the GOT. */ - _bfd_error_handler - (_("not enough GOT space for local GOT entries")); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx)); - - return *loc; -} - -/* Find a GOT entry whose higher-order 16 bits are the same as those - for value. Return the index into the GOT for this entry. */ - -static bfd_vma -score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - bfd_vma value, bfd_boolean external) -{ - asection *sgot; - struct score_got_info *g; - struct score_got_entry *entry; - - if (!external) - { - /* Although the ABI says that it is "the high-order 16 bits" that we - want, it is really the %high value. The complete value is - calculated with a `addiu' of a LO16 relocation, just as with a - HI16/LO16 pair. */ - value = score_elf_high (value) << 16; - } - - g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - - entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL, - R_SCORE_GOT15); - if (entry) - return entry->gotidx; - else - return MINUS_ONE; -} - -void -s7_bfd_score_elf_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *entry, - bfd_boolean force_local) -{ - bfd *dynobj; - asection *got; - struct score_got_info *g; - struct score_elf_link_hash_entry *h; - - h = (struct score_elf_link_hash_entry *) entry; - if (h->forced_local) - return; - h->forced_local = TRUE; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj != NULL && force_local) - { - got = score_elf_got_section (dynobj, FALSE); - if (got == NULL) - return; - g = score_elf_section_data (got)->u.got_info; - - if (g->next) - { - struct score_got_entry e; - struct score_got_info *gg = g; - - /* Since we're turning what used to be a global symbol into a - local one, bump up the number of local entries of each GOT - that had an entry for it. This will automatically decrease - the number of global entries, since global_gotno is actually - the upper limit of global entries. */ - e.abfd = dynobj; - e.symndx = -1; - e.d.h = h; - - for (g = g->next; g != gg; g = g->next) - if (htab_find (g->got_entries, &e)) - { - BFD_ASSERT (g->global_gotno > 0); - g->local_gotno++; - g->global_gotno--; - } - - /* If this was a global symbol forced into the primary GOT, we - no longer need an entry for it. We can't release the entry - at this point, but we must at least stop counting it as one - of the symbols that required a forced got entry. */ - if (h->root.got.offset == 2) - { - BFD_ASSERT (gg->assigned_gotno > 0); - gg->assigned_gotno--; - } - } - else if (g->global_gotno == 0 && g->global_gotsym == NULL) - /* If we haven't got through GOT allocation yet, just bump up the - number of local entries, as this symbol won't be counted as - global. */ - g->local_gotno++; - else if (h->root.got.offset == 1) - { - /* If we're past non-multi-GOT allocation and this symbol had - been marked for a global got entry, give it a local entry - instead. */ - BFD_ASSERT (g->global_gotno > 0); - g->local_gotno++; - g->global_gotno--; - } - } - - _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); -} - -/* If H is a symbol that needs a global GOT entry, but has a dynamic - symbol table index lower than any we've seen to date, record it for - posterity. */ - -static bfd_boolean -score_elf_record_global_got_symbol (struct elf_link_hash_entry *h, - bfd *abfd, - struct bfd_link_info *info, - struct score_got_info *g) -{ - struct score_got_entry entry, **loc; - - /* A global symbol in the GOT must also be in the dynamic symbol table. */ - if (h->dynindx == -1) - { - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - s7_bfd_score_elf_hide_symbol (info, h, TRUE); - break; - } - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - entry.abfd = abfd; - entry.symndx = -1; - entry.d.h = (struct score_elf_link_hash_entry *) h; - - loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT); - - /* If we've already marked this entry as needing GOT space, we don't - need to do it again. */ - if (*loc) - return TRUE; - - *loc = bfd_alloc (abfd, sizeof entry); - if (! *loc) - return FALSE; - - entry.gotidx = -1; - - memcpy (*loc, &entry, sizeof (entry)); - - if (h->got.offset != MINUS_ONE) - return TRUE; - - /* By setting this to a value other than -1, we are indicating that - there needs to be a GOT entry for H. Avoid using zero, as the - generic ELF copy_indirect_symbol tests for <= 0. */ - h->got.offset = 1; - - return TRUE; -} - -/* Reserve space in G for a GOT entry containing the value of symbol - SYMNDX in input bfd ABDF, plus ADDEND. */ - -static bfd_boolean -score_elf_record_local_got_symbol (bfd *abfd, - long symndx, - bfd_vma addend, - struct score_got_info *g) -{ - struct score_got_entry entry, **loc; - - entry.abfd = abfd; - entry.symndx = symndx; - entry.d.addend = addend; - loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT); - - if (*loc) - return TRUE; - - entry.gotidx = g->local_gotno++; - - *loc = bfd_alloc (abfd, sizeof(entry)); - if (! *loc) - return FALSE; - - memcpy (*loc, &entry, sizeof (entry)); - - return TRUE; -} - -/* Returns the GOT offset at which the indicated address can be found. - If there is not yet a GOT entry for this value, create one. - Returns -1 if no satisfactory GOT offset can be found. */ - -static bfd_vma -score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - bfd_vma value, unsigned long r_symndx, - struct score_elf_link_hash_entry *h, int r_type) -{ - asection *sgot; - struct score_got_info *g; - struct score_got_entry *entry; - - g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot); - - entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, - r_symndx, h, r_type); - if (!entry) - return MINUS_ONE; - - else - return entry->gotidx; -} - -/* Returns the GOT index for the global symbol indicated by H. */ - -static bfd_vma -score_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h) -{ - bfd_vma got_index; - asection *sgot; - struct score_got_info *g; - long global_got_dynindx = 0; - - g = score_elf_got_info (abfd, &sgot); - if (g->global_gotsym != NULL) - global_got_dynindx = g->global_gotsym->dynindx; - - /* Once we determine the global GOT entry with the lowest dynamic - symbol table index, we must put all dynamic symbols with greater - indices into the GOT. That makes it easy to calculate the GOT - offset. */ - BFD_ASSERT (h->dynindx >= global_got_dynindx); - got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd)); - BFD_ASSERT (got_index < sgot->size); - - return got_index; -} - -/* Returns the offset for the entry at the INDEXth position in the GOT. */ - -static bfd_vma -score_elf_got_offset_from_index (bfd *dynobj, - bfd *output_bfd, - bfd *input_bfd ATTRIBUTE_UNUSED, - bfd_vma got_index) -{ - asection *sgot; - bfd_vma gp; - - score_elf_got_info (dynobj, &sgot); - gp = _bfd_get_gp_value (output_bfd); - - return sgot->output_section->vma + sgot->output_offset + got_index - gp; -} - -/* Follow indirect and warning hash entries so that each got entry - points to the final symbol definition. P must point to a pointer - to the hash table we're traversing. Since this traversal may - modify the hash table, we set this pointer to NULL to indicate - we've made a potentially-destructive change to the hash table, so - the traversal must be restarted. */ - -static int -score_elf_resolve_final_got_entry (void **entryp, void *p) -{ - struct score_got_entry *entry = (struct score_got_entry *) *entryp; - htab_t got_entries = *(htab_t *) p; - - if (entry->abfd != NULL && entry->symndx == -1) - { - struct score_elf_link_hash_entry *h = entry->d.h; - - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; - - if (entry->d.h == h) - return 1; - - entry->d.h = h; - - /* If we can't find this entry with the new bfd hash, re-insert - it, and get the traversal restarted. */ - if (! htab_find (got_entries, entry)) - { - htab_clear_slot (got_entries, entryp); - entryp = htab_find_slot (got_entries, entry, INSERT); - if (! *entryp) - *entryp = entry; - /* Abort the traversal, since the whole table may have - moved, and leave it up to the parent to restart the - process. */ - *(htab_t *) p = NULL; - return 0; - } - /* We might want to decrement the global_gotno count, but it's - either too early or too late for that at this point. */ - } - - return 1; -} - -/* Turn indirect got entries in a got_entries table into their final locations. */ - -static void -score_elf_resolve_final_got_entries (struct score_got_info *g) -{ - htab_t got_entries; - - do - { - got_entries = g->got_entries; - - htab_traverse (got_entries, - score_elf_resolve_final_got_entry, - &got_entries); - } - while (got_entries == NULL); -} - -/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r */ - -static void -score_elf_add_to_rel (bfd *abfd, - bfd_byte *address, - reloc_howto_type *howto, - bfd_signed_vma increment) -{ - bfd_signed_vma addend; - bfd_vma contents; - unsigned long offset; - unsigned long r_type = howto->type; - unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; - - contents = bfd_get_32 (abfd, address); - /* Get the (signed) value from the instruction. */ - addend = contents & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~howto->src_mask; - addend |= mask; - } - /* Add in the increment, (which is a byte value). */ - switch (r_type) - { - case R_SCORE_PC19: - offset = - (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff); - offset += increment; - contents = - (contents & ~howto-> - src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff); - bfd_put_32 (abfd, contents, address); - break; - case R_SCORE_HI16: - break; - case R_SCORE_LO16: - hi16_addend = bfd_get_32 (abfd, address - 4); - hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; - offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1; - offset = (hi16_offset << 16) | (offset & 0xffff); - uvalue = increment + offset; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_addend & (~(howto->dst_mask))) - | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (abfd, hi16_value, address - 4); - offset = (uvalue & 0xffff) << 1; - contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - bfd_put_32 (abfd, contents, address); - break; - case R_SCORE_24: - offset = - (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff); - offset += increment; - contents = - (contents & ~howto-> - src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff); - bfd_put_32 (abfd, contents, address); - break; - case R_SCORE16_11: - - contents = bfd_get_16 (abfd, address); - offset = contents & howto->src_mask; - offset += increment; - contents = (contents & ~howto->src_mask) | (offset & howto->src_mask); - bfd_put_16 (abfd, contents, address); - - break; - case R_SCORE16_PC8: - - contents = bfd_get_16 (abfd, address); - offset = (contents & howto->src_mask) + ((increment >> 1) & 0xff); - contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask); - bfd_put_16 (abfd, contents, address); - - break; - case R_SCORE_GOT15: - case R_SCORE_GOT_LO16: - break; - - default: - addend += increment; - contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask); - bfd_put_32 (abfd, contents, address); - break; - } -} - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -score_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - bfd *output_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *rel, - Elf_Internal_Rela *relocs, - bfd_vma symbol, - struct bfd_link_info *info, - const char *sym_name ATTRIBUTE_UNUSED, - int sym_flags ATTRIBUTE_UNUSED, - struct score_elf_link_hash_entry *h, - Elf_Internal_Sym *local_syms, - asection **local_sections, - bfd_boolean gp_disp_p) -{ - unsigned long r_type; - unsigned long r_symndx; - bfd_byte *hit_data = contents + rel->r_offset; - bfd_vma addend; - /* The final GP value to be used for the relocatable, executable, or - shared object file being produced. */ - bfd_vma gp = MINUS_ONE; - /* The place (section offset or address) of the storage unit being relocated. */ - bfd_vma rel_addr; - /* The value of GP used to create the relocatable object. */ - bfd_vma gp0 = MINUS_ONE; - /* The offset into the global offset table at which the address of the relocation entry - symbol, adjusted by the addend, resides during execution. */ - bfd_vma g = MINUS_ONE; - /* TRUE if the symbol referred to by this relocation is a local symbol. */ - bfd_boolean local_p; - /* The eventual value we will relocate. */ - bfd_vma value = symbol; - unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0; - - Elf_Internal_Sym *sym = 0; - asection *sec = NULL; - bfd_boolean merge_p = 0; - - - if (elf_gp (output_bfd) == 0) - { - struct bfd_link_hash_entry *bh; - asection *o; - - bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1); - if (bh != NULL && bh->type == bfd_link_hash_defined) - { - elf_gp (output_bfd) = (bh->u.def.value - + bh->u.def.section->output_offset); - if (bh->u.def.section->output_section) - elf_gp (output_bfd) += bh->u.def.section->output_section->vma; - } - else if (bfd_link_relocatable (info)) - { - bfd_vma lo = -1; - - /* Find the GP-relative section with the lowest offset. */ - for (o = output_bfd->sections; o != NULL; o = o->next) - if (o->vma < lo) - lo = o->vma; - /* And calculate GP relative to that. */ - elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd); - } - else - { - /* If the relocate_section function needs to do a reloc - involving the GP value, it should make a reloc_dangerous - callback to warn that GP is not defined. */ - } - } - - /* Parse the relocation. */ - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset); - - /* For hidden symbol. */ - local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE); - if (local_p) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - - symbol = sec->output_section->vma + sec->output_offset; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION - || (sec->flags & SEC_MERGE)) - symbol += sym->st_value; - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - merge_p = 1; - } - - if (r_type == R_SCORE_GOT15) - { - const Elf_Internal_Rela *relend; - const Elf_Internal_Rela *lo16_rel; - bfd_vma lo_value = 0; - - relend = relocs + input_section->reloc_count; - lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); - if ((local_p) && (lo16_rel != NULL)) - { - bfd_vma tmp = 0; - tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); - lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); - if (merge_p) - { - asection *msec = sec; - lo_value = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, lo_value); - lo_value -= symbol; - lo_value += msec->output_section->vma + msec->output_offset; - } - } - addend = lo_value; - } - else - { - addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask; - } - - /* Figure out the value of the symbol. */ - if (local_p && !merge_p) - { - if (r_type == R_SCORE_GOT15) - { - const Elf_Internal_Rela *relend; - const Elf_Internal_Rela *lo16_rel; - bfd_vma lo_value = 0; - - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - addend = value & 0x7fff; - if ((addend & 0x4000) == 0x4000) - addend |= 0xffffc000; - - relend = relocs + input_section->reloc_count; - lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); - if ((local_p) && (lo16_rel != NULL)) - { - bfd_vma tmp = 0; - tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); - lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1); - } - - addend <<= 16; - addend += lo_value; - } - } - - local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE); - - /* If we haven't already determined the GOT offset, or the GP value, - and we're going to need it, get it now. */ - switch (r_type) - { - case R_SCORE_CALL15: - case R_SCORE_GOT15: - if (!local_p) - { - g = score_elf_global_got_index (elf_hash_table (info)->dynobj, - (struct elf_link_hash_entry *) h); - if ((! elf_hash_table(info)->dynamic_sections_created - || (bfd_link_pic (info) - && (info->symbolic || h->root.dynindx == -1) - && h->root.def_regular))) - { - /* This is a static link or a -Bsymbolic link. The - symbol is defined locally, or was forced to be local. - We must initialize this entry in the GOT. */ - bfd *tmpbfd = elf_hash_table (info)->dynobj; - asection *sgot = score_elf_got_section (tmpbfd, FALSE); - bfd_put_32 (tmpbfd, value, sgot->contents + g); - } - } - else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15) - { - /* There's no need to create a local GOT entry here; the - calculation for a local GOT15 entry does not involve G. */ - ; - } - else - { - g = score_elf_local_got_index (output_bfd, input_bfd, info, - symbol + addend, r_symndx, h, r_type); - if (g == MINUS_ONE) - return bfd_reloc_outofrange; - } - - /* Convert GOT indices to actual offsets. */ - g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, - output_bfd, input_bfd, g); - break; - - case R_SCORE_HI16: - case R_SCORE_LO16: - case R_SCORE_GPREL32: - gp0 = _bfd_get_gp_value (input_bfd); - gp = _bfd_get_gp_value (output_bfd); - break; - - case R_SCORE_GP15: - gp = _bfd_get_gp_value (output_bfd); - - default: - break; - } - - switch (r_type) - { - case R_SCORE_NONE: - return bfd_reloc_ok; - - case R_SCORE_ABS32: - case R_SCORE_REL32: - if ((bfd_link_pic (info) - || (elf_hash_table (info)->dynamic_sections_created - && h != NULL - && h->root.def_dynamic - && !h->root.def_regular)) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0) - { - /* If we're creating a shared library, or this relocation is against a symbol - in a shared library, then we can't know where the symbol will end up. - So, we create a relocation record in the output, and leave the job up - to the dynamic linker. */ - value = addend; - if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h, - symbol, &value, - input_section)) - return bfd_reloc_undefined; - } - else if (r_symndx == STN_UNDEF) - /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ - value = 0; - else - { - if (r_type != R_SCORE_REL32) - value = symbol + addend; - else - value = addend; - } - value &= howto->dst_mask; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_ABS16: - value += addend; - if ((long) value > 0x7fff || (long) value < -0x8000) - return bfd_reloc_overflow; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_24: - addend = bfd_get_32 (input_bfd, hit_data); - offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff); - if ((offset & 0x1000000) != 0) - offset |= 0xfe000000; - value += offset; - abs_value = value - rel_addr; - if ((abs_value & 0xfe000000) != 0) - return bfd_reloc_overflow; - addend = (addend & ~howto->src_mask) - | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff); - bfd_put_32 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE_PC19: - addend = bfd_get_32 (input_bfd, hit_data); - offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff); - if ((offset & 0x80000) != 0) - offset |= 0xfff00000; - abs_value = value = value - rel_addr + offset; - /* exceed 20 bit : overflow. */ - if ((abs_value & 0x80000000) == 0x80000000) - abs_value = 0xffffffff - value + 1; - if ((abs_value & 0xfff80000) != 0) - return bfd_reloc_overflow; - addend = (addend & ~howto->src_mask) - | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff); - bfd_put_32 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE16_11: - addend = bfd_get_16 (input_bfd, hit_data); - offset = addend & howto->src_mask; - if ((offset & 0x800) != 0) /* Offset is negative. */ - offset |= 0xfffff000; - value += offset; - abs_value = value - rel_addr; - if ((abs_value & 0xfffff000) != 0) - return bfd_reloc_overflow; - addend = (addend & ~howto->src_mask) | (value & howto->src_mask); - bfd_put_16 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE16_PC8: - addend = bfd_get_16 (input_bfd, hit_data); - offset = (addend & howto->src_mask) << 1; - if ((offset & 0x100) != 0) /* Offset is negative. */ - offset |= 0xfffffe00; - abs_value = value = value - rel_addr + offset; - /* Sign bit + exceed 9 bit. */ - if (((value & 0xffffff00) != 0) && ((value & 0xffffff00) != 0xffffff00)) - return bfd_reloc_overflow; - value >>= 1; - addend = (addend & ~howto->src_mask) | (value & howto->src_mask); - bfd_put_16 (input_bfd, addend, hit_data); - return bfd_reloc_ok; - - case R_SCORE_HI16: - return bfd_reloc_ok; - - case R_SCORE_LO16: - hi16_addend = bfd_get_32 (input_bfd, hit_data - 4); - hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; - addend = bfd_get_32 (input_bfd, hit_data); - offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; - offset = (hi16_offset << 16) | (offset & 0xffff); - - if (!gp_disp_p) - uvalue = value + offset; - else - uvalue = offset + gp - rel_addr + 4; - - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_addend & (~(howto->dst_mask))) - | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (input_bfd, hi16_value, hit_data - 4); - offset = (uvalue & 0xffff) << 1; - value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000); - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GP15: - addend = bfd_get_32 (input_bfd, hit_data); - offset = addend & 0x7fff; - if ((offset & 0x4000) == 0x4000) - offset |= 0xffffc000; - value = value + offset - gp; - if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000)) - return bfd_reloc_overflow; - value = (addend & ~howto->src_mask) | (value & howto->src_mask); - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GOT15: - case R_SCORE_CALL15: - if (local_p) - { - bfd_boolean forced; - - /* The special case is when the symbol is forced to be local. We need the - full address in the GOT since no R_SCORE_GOT_LO16 relocation follows. */ - forced = ! score_elf_local_relocation_p (input_bfd, rel, - local_sections, FALSE); - value = score_elf_got16_entry (output_bfd, input_bfd, info, - symbol + addend, forced); - if (value == MINUS_ONE) - return bfd_reloc_outofrange; - value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj, - output_bfd, input_bfd, value); - } - else - { - value = g; - } - - if ((long) value > 0x3fff || (long) value < -0x4000) - return bfd_reloc_overflow; - - addend = bfd_get_32 (input_bfd, hit_data); - value = (addend & ~howto->dst_mask) | (value & howto->dst_mask); - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GPREL32: - value = (addend + symbol + gp0 - gp); - value &= howto->dst_mask; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_GOT_LO16: - addend = bfd_get_32 (input_bfd, hit_data); - value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1); - value += symbol; - value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) - | (((value >> 14) & 0x3) << 16); - - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_SCORE_DUMMY_HI16: - return bfd_reloc_ok; - - case R_SCORE_GNU_VTINHERIT: - case R_SCORE_GNU_VTENTRY: - /* We don't do anything with these at present. */ - return bfd_reloc_continue; - - default: - return bfd_reloc_notsupported; - } -} - -/* Score backend functions. */ - -void -s7_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (elf_reloc->r_info); - if (r_type >= ARRAY_SIZE (elf32_score_howto_table)) - bfd_reloc->howto = NULL; - else - bfd_reloc->howto = &elf32_score_howto_table[r_type]; -} - -/* Relocate an score ELF section. */ - -bfd_boolean -s7_bfd_score_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - const char *name; - unsigned long offset; - unsigned long hi16_addend, hi16_offset, hi16_value, uvalue; - size_t extsymoff; - bfd_boolean gp_disp_p = FALSE; - - /* Sort dynsym. */ - if (elf_hash_table (info)->dynamic_sections_created) - { - bfd_size_type dynsecsymcount = 0; - if (bfd_link_pic (info)) - { - asection * p; - const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); - - 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)) - ++ dynsecsymcount; - } - - if (!score_elf_sort_hash_table (info, dynsecsymcount + 1)) - return FALSE; - } - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct score_elf_link_hash_entry *h; - bfd_vma relocation = 0; - bfd_reloc_status_type r; - arelent bfd_reloc; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - s7_bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel); - howto = bfd_reloc.howto; - - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < extsymoff) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = sec->output_section->vma + sec->output_offset; - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); - - if (!bfd_link_relocatable (info)) - { - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION - || (sec->flags & SEC_MERGE)) - { - relocation += sym->st_value; - } - - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - asection *msec; - bfd_vma addend, value; - - switch (r_type) - { - case R_SCORE_HI16: - break; - case R_SCORE_LO16: - hi16_addend = bfd_get_32 (input_bfd, contents + rel->r_offset - 4); - hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1; - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1; - addend = (hi16_offset << 16) | (offset & 0xffff); - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); - addend -= relocation; - addend += msec->output_section->vma + msec->output_offset; - uvalue = addend; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_addend & (~(howto->dst_mask))) - | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4); - offset = (uvalue & 0xffff) << 1; - value = (value & (~(howto->dst_mask))) - | (offset & 0x7fff) | ((offset << 1) & 0x30000); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - case R_SCORE_GOT_LO16: - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1); - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; - addend += msec->output_section->vma + msec->output_offset; - value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1) - | (((addend >> 14) & 0x3) << 16); - - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - default: - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - /* Get the (signed) value from the instruction. */ - addend = value & howto->src_mask; - if (addend & ((howto->src_mask + 1) >> 1)) - { - bfd_signed_vma mask; - - mask = -1; - mask &= ~howto->src_mask; - addend |= mask; - } - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation; - addend += msec->output_section->vma + msec->output_offset; - value = (value & ~howto->dst_mask) | (addend & howto->dst_mask); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - break; - } - } - } - } - else - { - /* For global symbols we look up the symbol in the hash-table. */ - h = ((struct score_elf_link_hash_entry *) - elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - h = ((struct score_elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &h->root.root)); - - /* Find the real hash-table entry for this symbol. */ - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link; - - /* Record the name of this symbol, for our caller. */ - name = h->root.root.root.string; - - /* See if this is the special GP_DISP_LABEL symbol. Note that such a - symbol must always be a global symbol. */ - if (strcmp (name, GP_DISP_LABEL) == 0) - { - /* Relocations against GP_DISP_LABEL are permitted only with - R_SCORE_HI16 and R_SCORE_LO16 relocations. */ - if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16) - return bfd_reloc_notsupported; - - gp_disp_p = TRUE; - } - - /* If this symbol is defined, calculate its address. Note that - GP_DISP_LABEL is a magic symbol, always implicitly defined by the - linker, so it's inappropriate to check to see whether or not - its defined. */ - else if ((h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - && h->root.root.u.def.section) - { - sec = h->root.root.u.def.section; - if (sec->output_section) - relocation = (h->root.root.u.def.value - + sec->output_section->vma - + sec->output_offset); - else - { - relocation = h->root.root.u.def.value; - } - } - else if (h->root.root.type == bfd_link_hash_undefweak) - /* We allow relocations against undefined weak symbols, giving - it the value zero, so that you can undefined weak functions - and check to see if they exist by looking at their addresses. */ - relocation = 0; - else if (info->unresolved_syms_in_objects == RM_IGNORE - && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) - relocation = 0; - else if (strcmp (name, "_DYNAMIC_LINK") == 0) - { - /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol - in s7_bfd_score_elf_create_dynamic_sections. Otherwise, we should define - the symbol with a value of 0. */ - BFD_ASSERT (! bfd_link_pic (info)); - BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL); - relocation = 0; - } - else if (!bfd_link_relocatable (info)) - { - (*info->callbacks->undefined_symbol) - (info, h->root.root.root.string, input_bfd, - input_section, rel->r_offset, - (info->unresolved_syms_in_objects == RM_GENERATE_ERROR) - || ELF_ST_VISIBILITY (h->root.other)); - relocation = 0; - } - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* 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) - { - sym = local_syms + r_symndx; - - if (r_type == R_SCORE_GOT15) - { - const Elf_Internal_Rela *lo16_rel; - bfd_vma lo_addend = 0, lo_value = 0; - bfd_vma addend, value; - - value = bfd_get_32 (input_bfd, contents + rel->r_offset); - addend = value & 0x7fff; - if ((addend & 0x4000) == 0x4000) - addend |= 0xffffc000; - - relend = relocs + input_section->reloc_count; - lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend); - if (lo16_rel != NULL) - { - lo_value = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset); - lo_addend = (((lo_value >> 16) & 0x3) << 14) | ((lo_value & 0x7fff) >> 1); - } - - addend <<= 16; - addend += lo_addend; - - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - addend += local_sections[r_symndx]->output_offset; - - lo_addend = addend & 0xffff; - lo_value = (lo_value & (~(howto->dst_mask))) | ((lo_addend & 0x3fff) << 1) - | (((lo_addend >> 14) & 0x3) << 16); - bfd_put_32 (input_bfd, lo_value, contents + lo16_rel->r_offset); - - addend = addend >> 16; - value = (value & ~howto->src_mask) | (addend & howto->src_mask); - bfd_put_32 (input_bfd, value, contents + rel->r_offset); - } - else if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - sec = local_sections[r_symndx]; - score_elf_add_to_rel (input_bfd, contents + rel->r_offset, - howto, (bfd_signed_vma) (sec->output_offset + sym->st_value)); - } - } - continue; - } - - /* This is a final link. */ - r = score_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, contents, rel, relocs, - relocation, info, name, - (h ? ELF_ST_TYPE ((unsigned int) h->root.root.type) : - ELF_ST_TYPE ((unsigned int) sym->st_info)), h, local_syms, - local_sections, gp_disp_p); - - if (r != bfd_reloc_ok) - { - const char *msg = (const char *)0; - - switch (r) - { - case bfd_reloc_overflow: - /* If the overflowing reloc was to an undefined symbol, - we have already printed one error message and there - is no point complaining again. */ - if (!h || h->root.root.type != bfd_link_hash_undefined) - (*info->callbacks->reloc_overflow) - (info, NULL, name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* Fall through. */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table. */ - -bfd_boolean -s7_bfd_score_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - struct score_got_info *g; - size_t extsymoff; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - asection *sgot; - asection *sreloc; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; - - if (dynobj == NULL) - { - sgot = NULL; - g = NULL; - } - else - { - sgot = score_elf_got_section (dynobj, FALSE); - if (sgot == NULL) - g = NULL; - else - { - BFD_ASSERT (score_elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - } - } - - sreloc = NULL; - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; ++rel) - { - unsigned long r_symndx; - unsigned int r_type; - 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 < extsymoff) - { - h = NULL; - } - else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Malformed reloc detected for section %A"), abfd, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - h = sym_hashes[r_symndx - extsymoff]; - - /* This may be an indirect symbol created because of a version. */ - if (h != NULL) - { - while (h->root.type == bfd_link_hash_indirect) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - } - - /* Some relocs require a global offset table. */ - if (dynobj == NULL || sgot == NULL) - { - switch (r_type) - { - case R_SCORE_GOT15: - case R_SCORE_CALL15: - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - if (!score_elf_create_got_section (dynobj, info, FALSE)) - return FALSE; - g = score_elf_got_info (dynobj, &sgot); - break; - case R_SCORE_ABS32: - case R_SCORE_REL32: - if (dynobj == NULL - && (bfd_link_pic (info) || h != NULL) - && (sec->flags & SEC_ALLOC) != 0) - elf_hash_table (info)->dynobj = dynobj = abfd; - break; - default: - break; - } - } - - if (!h && (r_type == R_SCORE_GOT_LO16)) - { - if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g)) - return FALSE; - } - - switch (r_type) - { - case R_SCORE_CALL15: - if (h == NULL) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: CALL15 reloc at %#Lx not against global symbol"), - abfd, rel->r_offset); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - /* This symbol requires a global offset table entry. */ - if (! score_elf_record_global_got_symbol (h, abfd, info, g)) - return FALSE; - - /* We need a stub, not a plt entry for the undefined function. But we record - it as if it needs plt. See _bfd_elf_adjust_dynamic_symbol. */ - h->needs_plt = 1; - h->type = STT_FUNC; - } - break; - case R_SCORE_GOT15: - if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g)) - return FALSE; - break; - case R_SCORE_ABS32: - case R_SCORE_REL32: - if ((bfd_link_pic (info) || h != NULL) - && (sec->flags & SEC_ALLOC) != 0) - { - if (sreloc == NULL) - { - sreloc = score_elf_rel_dyn_section (dynobj, TRUE); - if (sreloc == NULL) - return FALSE; - } -#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY) - if (bfd_link_pic (info)) - { - /* When creating a shared object, we must copy these reloc types into - the output file as R_SCORE_REL32 relocs. We make room for this reloc - in the .rel.dyn reloc section. */ - score_elf_allocate_dynamic_relocations (dynobj, 1); - if ((sec->flags & SCORE_READONLY_SECTION) - == SCORE_READONLY_SECTION) - /* We tell the dynamic linker that there are - relocations against the text segment. */ - info->flags |= DF_TEXTREL; - } - else - { - struct score_elf_link_hash_entry *hscore; - - /* We only need to copy this reloc if the symbol is - defined in a dynamic object. */ - hscore = (struct score_elf_link_hash_entry *) h; - ++hscore->possibly_dynamic_relocs; - if ((sec->flags & SCORE_READONLY_SECTION) - == SCORE_READONLY_SECTION) - /* We need it to tell the dynamic linker if there - are relocations against the text segment. */ - hscore->readonly_reloc = TRUE; - } - - /* Even though we don't directly need a GOT entry for this symbol, - a symbol must have a dynamic symbol table index greater that - DT_SCORE_GOTSYM if there are dynamic relocations against it. */ - if (h != NULL) - { - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! score_elf_create_got_section (dynobj, info, TRUE)) - return FALSE; - g = score_elf_got_info (dynobj, &sgot); - if (! score_elf_record_global_got_symbol (h, abfd, info, g)) - return FALSE; - } - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_SCORE_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_SCORE_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - default: - break; - } - - /* We must not create a stub for a symbol that has relocations - related to taking the function's address. */ - switch (r_type) - { - default: - if (h != NULL) - { - struct score_elf_link_hash_entry *sh; - - sh = (struct score_elf_link_hash_entry *) h; - sh->no_fn_stub = TRUE; - } - break; - case R_SCORE_CALL15: - break; - } - } - - return TRUE; -} - -bfd_boolean -s7_bfd_score_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - switch (sym->st_shndx) - { - case SHN_COMMON: - if (sym->st_size > elf_gp_size (abfd)) - break; - /* Fall through. */ - case SHN_SCORE_SCOMMON: - *secp = bfd_make_section_old_way (abfd, ".scommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - -void -s7_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym) -{ - elf_symbol_type *elfsym; - - elfsym = (elf_symbol_type *) asym; - switch (elfsym->internal_elf_sym.st_shndx) - { - case SHN_COMMON: - if (asym->value > elf_gp_size (abfd)) - break; - /* Fall through. */ - case SHN_SCORE_SCOMMON: - if (score_elf_scom_section.name == NULL) - { - /* Initialize the small common section. */ - score_elf_scom_section.name = ".scommon"; - score_elf_scom_section.flags = SEC_IS_COMMON; - score_elf_scom_section.output_section = &score_elf_scom_section; - score_elf_scom_section.symbol = &score_elf_scom_symbol; - score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr; - score_elf_scom_symbol.name = ".scommon"; - score_elf_scom_symbol.flags = BSF_SECTION_SYM; - score_elf_scom_symbol.section = &score_elf_scom_section; - score_elf_scom_symbol_ptr = &score_elf_scom_symbol; - } - asym->section = &score_elf_scom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - } -} - -int -s7_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - /* If we see a common symbol, which implies a relocatable link, then - if a symbol was small common in an input file, mark it as small - common in the output file. */ - if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) - sym->st_shndx = SHN_SCORE_SCOMMON; - - return 1; -} - -bfd_boolean -s7_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) - { - *retval = SHN_SCORE_SCOMMON; - return TRUE; - } - - return FALSE; -} - -/* 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. */ - -bfd_boolean -s7_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj; - struct score_elf_link_hash_entry *hscore; - asection *s; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic && h->ref_regular && !h->def_regular))); - - /* If this symbol is defined in a dynamic object, we need to copy - any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output - file. */ - hscore = (struct score_elf_link_hash_entry *) h; - if (!bfd_link_relocatable (info) - && hscore->possibly_dynamic_relocs != 0 - && (h->root.type == bfd_link_hash_defweak || !h->def_regular)) - { - score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs); - if (hscore->readonly_reloc) - /* We tell the dynamic linker that there are relocations - against the text segment. */ - info->flags |= DF_TEXTREL; - } - - /* For a function, create a stub, if allowed. */ - if (!hscore->no_fn_stub && h->needs_plt) - { - if (!elf_hash_table (info)->dynamic_sections_created) - return TRUE; - - /* If this symbol is not defined in a regular file, then set - the symbol to the stub location. This is required to make - function pointers compare as equal between the normal - executable and the shared library. */ - if (!h->def_regular) - { - /* We need .stub section. */ - s = bfd_get_linker_section (dynobj, SCORE_ELF_STUB_SECTION_NAME); - BFD_ASSERT (s != NULL); - - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* XXX Write this stub address somewhere. */ - h->plt.offset = s->size; - - /* Make room for this stub code. */ - s->size += SCORE_FUNCTION_STUB_SIZE; - - /* The last half word of the stub will be filled with the index - of this symbol in .dynsym section. */ - return TRUE; - } - } - else if ((h->type == STT_FUNC) && !h->needs_plt) - { - /* This will set the entry for this symbol in the GOT to 0, and - the dynamic linker will take care of this. */ - h->root.u.def.value = 0; - return TRUE; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - return TRUE; -} - -/* This function is called after all the input files have been read, - and the input sections have been assigned to output sections. */ - -bfd_boolean -s7_bfd_score_elf_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - struct score_got_info *g; - int i; - bfd_size_type loadable_size = 0; - bfd_size_type local_gotno; - bfd *sub; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - /* Relocatable links don't have it. */ - return TRUE; - - g = score_elf_got_info (dynobj, &s); - if (s == NULL) - return TRUE; - - /* Calculate the total loadable size of the output. That will give us the - maximum number of GOT_PAGE entries required. */ - for (sub = info->input_bfds; sub; sub = sub->link.next) - { - asection *subsection; - - for (subsection = sub->sections; - subsection; - subsection = subsection->next) - { - if ((subsection->flags & SEC_ALLOC) == 0) - continue; - loadable_size += ((subsection->size + 0xf) - &~ (bfd_size_type) 0xf); - } - } - - /* There has to be a global GOT entry for every symbol with - a dynamic symbol table index of DT_SCORE_GOTSYM or - higher. Therefore, it make sense to put those symbols - that need GOT entries at the end of the symbol table. We - do that here. */ - if (! score_elf_sort_hash_table (info, 1)) - return FALSE; - - if (g->global_gotsym != NULL) - i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx; - else - /* If there are no global symbols, or none requiring - relocations, then GLOBAL_GOTSYM will be NULL. */ - i = 0; - - /* In the worst case, we'll get one stub per dynamic symbol. */ - loadable_size += SCORE_FUNCTION_STUB_SIZE * i; - - /* Assume there are two loadable segments consisting of - contiguous sections. Is 5 enough? */ - local_gotno = (loadable_size >> 16) + 5; - - g->local_gotno += local_gotno; - s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd); - - g->global_gotno = i; - s->size += i * SCORE_ELF_GOT_SIZE (output_bfd); - - score_elf_resolve_final_got_entries (g); - - if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd)) - { - /* Fixme. Error message or Warning message should be issued here. */ - } - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -bfd_boolean -s7_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean reltext; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; - s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (CONST_STRNEQ (name, ".rel")) - { - if (s->size == 0) - { - /* We only strip the section if the output section name - has the same name. Otherwise, there might be several - input sections for this output section. FIXME: This - code is probably not needed these days anyhow, since - the linker now does not create empty output sections. */ - if (s->output_section != NULL - && strcmp (name, - bfd_get_section_name (s->output_section->owner, - s->output_section)) == 0) - s->flags |= SEC_EXCLUDE; - } - else - { - const char *outname; - asection *target; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL entry. - If the relocation section is .rel.dyn, we always - assert a DT_TEXTREL entry rather than testing whether - there exists a relocation to a read only section or - not. */ - outname = bfd_get_section_name (output_bfd, s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 4); - if ((target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0) - reltext = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - if (strcmp (name, ".rel.dyn") != 0) - s->reloc_count = 0; - } - } - else if (CONST_STRNEQ (name, ".got")) - { - /* s7_bfd_score_elf_always_size_sections() has already done - most of the work, but some symbols may have been mapped - to versions that we must now resolve in the got_entries - hash tables. */ - } - else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0) - { - /* IRIX rld assumes that the function stub isn't at the end - of .text section. So put a dummy. XXX */ - s->size += SCORE_FUNCTION_STUB_SIZE; - } - else if (! CONST_STRNEQ (name, ".init")) - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - /* Allocate memory for the section contents. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL && s->size != 0) - { - bfd_set_error (bfd_error_no_memory); - return FALSE; - } - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in s7_bfd_score_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) - return FALSE; - - if (reltext) - info->flags |= DF_TEXTREL; - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0)) - return FALSE; - } - - if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0)) - return FALSE; - - if (score_elf_rel_dyn_section (dynobj, FALSE)) - { - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0)) - return FALSE; - } - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0)) - return FALSE; - - if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0)) - return FALSE; - } - - return TRUE; -} - -bfd_boolean -s7_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - flagword flags; - asection *s; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY); - - /* ABI requests the .dynamic section to be read only. */ - s = bfd_get_linker_section (abfd, ".dynamic"); - if (s != NULL) - { - if (!bfd_set_section_flags (abfd, s, flags)) - return FALSE; - } - - /* We need to create .got section. */ - if (!score_elf_create_got_section (abfd, info, FALSE)) - return FALSE; - - if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE)) - return FALSE; - - /* Create .stub section. */ - if (bfd_get_linker_section (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL) - { - s = bfd_make_section_anyway_with_flags (abfd, SCORE_ELF_STUB_SECTION_NAME, - flags | SEC_CODE); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 2)) - - return FALSE; - } - - if (!bfd_link_pic (info)) - { - const char *name; - - name = "_DYNAMIC_LINK"; - bh = NULL; - if (!(_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, - (bfd_vma) 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->non_elf = 0; - h->def_regular = 1; - h->type = STT_SECTION; - - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - return TRUE; -} - - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -bfd_boolean -s7_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - bfd *dynobj; - asection *sgot; - struct score_got_info *g; - const char *name; - - dynobj = elf_hash_table (info)->dynobj; - - if (h->plt.offset != MINUS_ONE) - { - asection *s; - bfd_byte stub[SCORE_FUNCTION_STUB_SIZE]; - - /* This symbol has a stub. Set it up. */ - BFD_ASSERT (h->dynindx != -1); - - s = bfd_get_linker_section (dynobj, SCORE_ELF_STUB_SECTION_NAME); - BFD_ASSERT (s != NULL); - - /* FIXME: Can h->dynindex be more than 64K? */ - if (h->dynindx & 0xffff0000) - return FALSE; - - /* Fill the stub. */ - bfd_put_32 (output_bfd, STUB_LW, stub); - bfd_put_32 (output_bfd, STUB_MOVE, stub + 4); - bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8); - bfd_put_32 (output_bfd, STUB_BRL, stub + 12); - - BFD_ASSERT (h->plt.offset <= s->size); - memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE); - - /* Mark the symbol as undefined. plt.offset != -1 occurs - only for the referenced symbol. */ - sym->st_shndx = SHN_UNDEF; - - /* The run-time linker uses the st_value field of the symbol - to reset the global offset table entry for this external - to its stub address when unlinking a shared object. */ - sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset); - } - - BFD_ASSERT (h->dynindx != -1 || h->forced_local); - - sgot = score_elf_got_section (dynobj, FALSE); - BFD_ASSERT (sgot != NULL); - BFD_ASSERT (score_elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - - /* Run through the global symbol table, creating GOT entries for all - the symbols that need them. */ - if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx) - { - bfd_vma offset; - bfd_vma value; - - value = sym->st_value; - offset = score_elf_global_got_index (dynobj, h); - bfd_put_32 (output_bfd, value, sgot->contents + offset); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - name = h->root.root.string; - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - else if (strcmp (name, "_DYNAMIC_LINK") == 0) - { - sym->st_shndx = SHN_ABS; - sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); - sym->st_value = 1; - } - else if (strcmp (name, GP_DISP_LABEL) == 0) - { - sym->st_shndx = SHN_ABS; - sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); - sym->st_value = elf_gp (output_bfd); - } - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -bfd_boolean -s7_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - asection *sgot; - asection *s; - struct score_got_info *g; - - dynobj = elf_hash_table (info)->dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - sgot = score_elf_got_section (dynobj, FALSE); - if (sgot == NULL) - g = NULL; - else - { - BFD_ASSERT (score_elf_section_data (sgot) != NULL); - g = score_elf_section_data (sgot)->u.got_info; - BFD_ASSERT (g != NULL); - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - bfd_byte *b; - - BFD_ASSERT (sdyn != NULL); - BFD_ASSERT (g != NULL); - - for (b = sdyn->contents; - b < sdyn->contents + sdyn->size; - b += SCORE_ELF_DYN_SIZE (dynobj)) - { - Elf_Internal_Dyn dyn; - const char *name; - size_t elemsize; - bfd_boolean swap_out_p; - - /* Read in the current dynamic entry. */ - (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); - - /* Assume that we're going to modify it and write it out. */ - swap_out_p = TRUE; - - switch (dyn.d_tag) - { - case DT_RELENT: - dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj); - break; - - case DT_STRSZ: - /* Rewrite DT_STRSZ. */ - dyn.d_un.d_val - = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); - break; - - case DT_PLTGOT: - s = elf_hash_table (info)->sgot; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_SCORE_BASE_ADDRESS: - s = output_bfd->sections; - BFD_ASSERT (s != NULL); - dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff; - break; - - case DT_SCORE_LOCAL_GOTNO: - dyn.d_un.d_val = g->local_gotno; - break; - - case DT_SCORE_UNREFEXTNO: - /* The index into the dynamic symbol table which is the - entry of the first external symbol that is not - referenced within the same object. */ - dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1; - break; - - case DT_SCORE_GOTSYM: - if (g->global_gotsym) - { - dyn.d_un.d_val = g->global_gotsym->dynindx; - break; - } - /* In case if we don't have global got symbols we default - to setting DT_SCORE_GOTSYM to the same value as - DT_SCORE_SYMTABNO. */ - /* Fall through. */ - - case DT_SCORE_SYMTABNO: - name = ".dynsym"; - elemsize = SCORE_ELF_SYM_SIZE (output_bfd); - s = bfd_get_linker_section (dynobj, name); - dyn.d_un.d_val = s->size / elemsize; - break; - - case DT_SCORE_HIPAGENO: - dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO; - break; - - default: - swap_out_p = FALSE; - break; - } - - if (swap_out_p) - (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b); - } - } - - /* The first entry of the global offset table will be filled at - runtime. The second entry will be used by some runtime loaders. - This isn't the case of IRIX rld. */ - if (sgot != NULL && sgot->size > 0) - { - bfd_put_32 (output_bfd, 0, sgot->contents); - bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd)); - } - - if (sgot != NULL) - elf_section_data (sgot->output_section)->this_hdr.sh_entsize - = SCORE_ELF_GOT_SIZE (output_bfd); - - - /* We need to sort the entries of the dynamic relocation section. */ - s = score_elf_rel_dyn_section (dynobj, FALSE); - - if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd)) - { - reldyn_sorting_bfd = output_bfd; - qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1, - sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs); - } - - return TRUE; -} - -/* This function 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 -s7_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, - asection *sec) -{ - const char *name; - - name = bfd_get_section_name (abfd, sec); - - if (strcmp (name, ".got") == 0 - || strcmp (name, ".srdata") == 0 - || strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0) - hdr->sh_flags |= SHF_SCORE_GPREL; - - return TRUE; -} - -/* This function do additional processing on the ELF section header before writing - it out. This is used to set the flags and type fields for some sections. */ - -/* assign_file_positions_except_relocs() check section flag and if it is allocatable, - warning message will be issued. backend_fake_section is called before - assign_file_positions_except_relocs(); backend_section_processing after it. so, we - modify section flag there, but not backend_fake_section. */ - -bfd_boolean -s7_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr) -{ - if (hdr->bfd_section != NULL) - { - const char *name = bfd_get_section_name (abfd, hdr->bfd_section); - - if (strcmp (name, ".sdata") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; - hdr->sh_type = SHT_PROGBITS; - } - else if (strcmp (name, ".sbss") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL; - hdr->sh_type = SHT_NOBITS; - } - else if (strcmp (name, ".srdata") == 0) - { - hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL; - hdr->sh_type = SHT_PROGBITS; - } - } - - return TRUE; -} - -bfd_boolean -s7_bfd_score_elf_write_section (bfd *output_bfd, asection *sec, bfd_byte *contents) -{ - bfd_byte *to, *from, *end; - int i; - - if (strcmp (sec->name, ".pdr") != 0) - return FALSE; - - if (score_elf_section_data (sec)->u.tdata == NULL) - return FALSE; - - to = contents; - end = contents + sec->size; - for (from = contents, i = 0; from < end; from += PDR_SIZE, i++) - { - if ((score_elf_section_data (sec)->u.tdata)[i] == 1) - continue; - - if (to != from) - memcpy (to, from, PDR_SIZE); - - to += PDR_SIZE; - } - bfd_set_section_contents (output_bfd, sec->output_section, contents, - (file_ptr) sec->output_offset, sec->size); - - return TRUE; -} - -/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old - indirect symbol. Process additional relocation information. */ - -void -s7_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct score_elf_link_hash_entry *dirscore, *indscore; - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); - - if (ind->root.type != bfd_link_hash_indirect) - return; - - dirscore = (struct score_elf_link_hash_entry *) dir; - indscore = (struct score_elf_link_hash_entry *) ind; - dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs; - - if (indscore->readonly_reloc) - dirscore->readonly_reloc = TRUE; - - if (indscore->no_fn_stub) - dirscore->no_fn_stub = TRUE; -} - -/* Remove information about discarded functions from other sections which mention them. */ - -bfd_boolean -s7_bfd_score_elf_discard_info (bfd *abfd, - struct elf_reloc_cookie *cookie, - struct bfd_link_info *info) -{ - asection *o; - bfd_boolean ret = FALSE; - unsigned char *tdata; - size_t i, skip; - - o = bfd_get_section_by_name (abfd, ".pdr"); - if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0) - || (o->output_section != NULL && bfd_is_abs_section (o->output_section))) - return FALSE; - - tdata = bfd_zmalloc (o->size / PDR_SIZE); - if (!tdata) - return FALSE; - - cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory); - if (!cookie->rels) - { - free (tdata); - return FALSE; - } - - cookie->rel = cookie->rels; - cookie->relend = cookie->rels + o->reloc_count; - - for (i = 0, skip = 0; i < o->size; i++) - { - if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie)) - { - tdata[i] = 1; - skip++; - } - } - - if (skip != 0) - { - score_elf_section_data (o)->u.tdata = tdata; - o->size -= skip * PDR_SIZE; - ret = TRUE; - } - else - free (tdata); - - if (!info->keep_memory) - free (cookie->rels); - - return ret; -} - -/* Signal that discard_info() has removed the discarded relocations for this section. */ - -bfd_boolean -s7_bfd_score_elf_ignore_discarded_relocs (asection *sec) -{ - if (strcmp (sec->name, ".pdr") == 0) - return TRUE; - return FALSE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -asection * -s7_bfd_score_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_SCORE_GNU_VTINHERIT: - case R_SCORE_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Support for core dump NOTE sections. */ - -bfd_boolean -s7_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int raw_size; - - switch (note->descsz) - { - default: - return FALSE; - case 272: /* Linux/Score elf_prstatus */ - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - - /* sizeof(elf_gregset_t) */ - raw_size = 196; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, - note->descpos + offset); -} - -bfd_boolean -s7_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 128: /* Linux/Score elf_prpsinfo. */ - /* pr_fname */ - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - - /* pr_psargs */ - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); - break; - } - - /* 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; -} - - -/* Score BFD functions. */ - -reloc_howto_type * -s7_elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_score_reloc_map); i++) - if (elf32_score_reloc_map[i].bfd_reloc_val == code) - return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -bfd_boolean -s7_elf32_score_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC) - { - fprintf (file, _(" [pic]")); - } - if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP) - { - fprintf (file, _(" [fix dep]")); - } - fputc ('\n', file); - - return TRUE; -} - -bfd_boolean -s7_elf32_score_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword in_flags; - flagword out_flags; - - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - { - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); - } - - return TRUE; - } - - if (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0)) - { - _bfd_error_handler (_("%B: warning: linking PIC files with non-PIC files"), ibfd); - } - - /* Maybe dependency fix compatibility should be checked here. */ - return TRUE; -} - -bfd_boolean -s7_elf32_score_new_section_hook (bfd *abfd, asection *sec) -{ - struct _score_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - - return _bfd_elf_new_section_hook (abfd, sec); -} - -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) diff --git a/sdcc/support/sdbinutils/bfd/elf32-sh-relocs.h b/sdcc/support/sdbinutils/bfd/elf32-sh-relocs.h deleted file mode 100644 index 8f3ac803f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sh-relocs.h +++ /dev/null @@ -1,1880 +0,0 @@ -/* Copyright (C) 2006-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* No relocation. */ - HOWTO (R_SH_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute relocation. Setting partial_inplace to TRUE and - src_mask to a non-zero value is similar to the COFF toolchain. */ - HOWTO (R_SH_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - SH_ELF_RELOC, /* special_function */ - "R_SH_DIR32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit PC relative relocation. */ - HOWTO (R_SH_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_REL32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit PC relative branch divided by 2. */ - HOWTO (R_SH_DIR8WPN, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DIR8WPN", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 12 bit PC relative branch divided by 2. */ - /* This cannot be partial_inplace because relaxation can't know the - eventual value of a symbol. */ - HOWTO (R_SH_IND12W, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - NULL, /* special_function */ - "R_SH_IND12W", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xfff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit unsigned PC relative divided by 4. */ - HOWTO (R_SH_DIR8WPL, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DIR8WPL", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit unsigned PC relative divided by 2. */ - HOWTO (R_SH_DIR8WPZ, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DIR8WPZ", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit GBR relative. FIXME: This only makes sense if we have some - special symbol for the GBR relative area, and that is not - implemented. */ - HOWTO (R_SH_DIR8BP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DIR8BP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit GBR relative divided by 2. FIXME: This only makes sense if - we have some special symbol for the GBR relative area, and that - is not implemented. */ - HOWTO (R_SH_DIR8W, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DIR8W", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit GBR relative divided by 4. FIXME: This only makes sense if - we have some special symbol for the GBR relative area, and that - is not implemented. */ - HOWTO (R_SH_DIR8L, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DIR8L", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit PC relative divided by 2 - but specified in a very odd way. */ - HOWTO (R_SH_LOOP_START, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_LOOP_START", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 8 bit PC relative divided by 2 - but specified in a very odd way. */ - HOWTO (R_SH_LOOP_END, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_LOOP_END", /* name */ - TRUE, /* partial_inplace */ - 0xff, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (12), - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - EMPTY_HOWTO (16), - EMPTY_HOWTO (17), - EMPTY_HOWTO (18), - EMPTY_HOWTO (19), - EMPTY_HOWTO (20), - EMPTY_HOWTO (21), - - /* The remaining relocs are a GNU extension used for relaxing. The - final pass of the linker never needs to do anything with any of - these relocs. Any required operations are handled by the - relaxation code. */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_SH_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_SH_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_SH_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_SH_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit switch table entry. This is generated for an expression - such as ``.word L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_SH_SWITCH8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_SWITCH8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit switch table entry. This is generated for an expression - such as ``.word L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_SH_SWITCH16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_SWITCH16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit switch table entry. This is generated for an expression - such as ``.long L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_SH_SWITCH32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_SWITCH32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Indicates a .uses pseudo-op. The compiler will generate .uses - pseudo-ops when it finds a function call which can be relaxed. - The offset field holds the PC relative offset to the instruction - which loads the register used in the function call. */ - HOWTO (R_SH_USES, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_USES", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The assembler will generate this reloc for addresses referred to - by the register loads associated with USES relocs. The offset - field holds the number of times the address is referenced in the - object file. */ - HOWTO (R_SH_COUNT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_COUNT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Indicates an alignment statement. The offset field is the power - of 2 to which subsequent portions of the object file must be - aligned. */ - HOWTO (R_SH_ALIGN, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_ALIGN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The assembler will generate this reloc before a block of - instructions. A section should be processed as assuming it - contains data, unless this reloc is seen. */ - HOWTO (R_SH_CODE, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_CODE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The assembler will generate this reloc after a block of - instructions when it sees data that is not instructions. */ - HOWTO (R_SH_DATA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_DATA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The assembler generates this reloc for each label within a block - of instructions. This permits the linker to avoid swapping - instructions which are the targets of branches. */ - HOWTO (R_SH_LABEL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_LABEL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The next 12 are only supported via linking in SHC-generated objects. */ - HOWTO (R_SH_DIR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR8UL, /* type */ - 2, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR8UL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR8UW, /* type */ - 1, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR8UW", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR8U, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR8U", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR8SW, /* type */ - 1, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR8SW", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR8S, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR8S", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR4UL, /* type */ - 2, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 4, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR4UL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0f, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR4UW, /* type */ - 1, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 4, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR4UW", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0f, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_DIR4U, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 4, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR4U", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0f, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_PSHA, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PSHA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0f, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_PSHL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - FALSE, /* pc_relative */ - 4, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PSHL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0f, /* dst_mask */ - FALSE), /* pcrel_offset */ - -#ifdef INCLUDE_SHMEDIA - /* Used in SHLLI.L and SHLRI.L. */ - HOWTO (R_SH_DIR5U, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR5U", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in SHARI, SHLLI et al. */ - HOWTO (R_SH_DIR6U, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR6U", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in BxxI, LDHI.L et al. */ - HOWTO (R_SH_DIR6S, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR6S", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in ADDI, ANDI et al. */ - HOWTO (R_SH_DIR10S, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10S", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in LD.UW, ST.W et al. */ - HOWTO (R_SH_DIR10SW, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10SW", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in LD.L, FLD.S et al. */ - HOWTO (R_SH_DIR10SL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10SL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in FLD.D, FST.P et al. */ - HOWTO (R_SH_DIR10SQ, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10SQ", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - -#else - EMPTY_HOWTO (45), - EMPTY_HOWTO (46), - EMPTY_HOWTO (47), - EMPTY_HOWTO (48), - EMPTY_HOWTO (49), - EMPTY_HOWTO (50), - EMPTY_HOWTO (51), -#endif - - EMPTY_HOWTO (52), - - HOWTO (R_SH_DIR16S, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR16S", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - EMPTY_HOWTO (60), - EMPTY_HOWTO (61), - EMPTY_HOWTO (62), - EMPTY_HOWTO (63), - EMPTY_HOWTO (64), - EMPTY_HOWTO (65), - EMPTY_HOWTO (66), - EMPTY_HOWTO (67), - EMPTY_HOWTO (68), - EMPTY_HOWTO (69), - EMPTY_HOWTO (70), - EMPTY_HOWTO (71), - EMPTY_HOWTO (72), - EMPTY_HOWTO (73), - EMPTY_HOWTO (74), - EMPTY_HOWTO (75), - EMPTY_HOWTO (76), - EMPTY_HOWTO (77), - EMPTY_HOWTO (78), - EMPTY_HOWTO (79), - EMPTY_HOWTO (80), - EMPTY_HOWTO (81), - EMPTY_HOWTO (82), - EMPTY_HOWTO (83), - EMPTY_HOWTO (84), - EMPTY_HOWTO (85), - EMPTY_HOWTO (86), - EMPTY_HOWTO (87), - EMPTY_HOWTO (88), - EMPTY_HOWTO (89), - EMPTY_HOWTO (90), - EMPTY_HOWTO (91), - EMPTY_HOWTO (92), - EMPTY_HOWTO (93), - EMPTY_HOWTO (94), - EMPTY_HOWTO (95), - EMPTY_HOWTO (96), - EMPTY_HOWTO (97), - EMPTY_HOWTO (98), - EMPTY_HOWTO (99), - EMPTY_HOWTO (100), - EMPTY_HOWTO (101), - EMPTY_HOWTO (102), - EMPTY_HOWTO (103), - EMPTY_HOWTO (104), - EMPTY_HOWTO (105), - EMPTY_HOWTO (106), - EMPTY_HOWTO (107), - EMPTY_HOWTO (108), - EMPTY_HOWTO (109), - EMPTY_HOWTO (110), - EMPTY_HOWTO (111), - EMPTY_HOWTO (112), - EMPTY_HOWTO (113), - EMPTY_HOWTO (114), - EMPTY_HOWTO (115), - EMPTY_HOWTO (116), - EMPTY_HOWTO (117), - EMPTY_HOWTO (118), - EMPTY_HOWTO (119), - EMPTY_HOWTO (120), - EMPTY_HOWTO (121), - EMPTY_HOWTO (122), - EMPTY_HOWTO (123), - EMPTY_HOWTO (124), - EMPTY_HOWTO (125), - EMPTY_HOWTO (126), - EMPTY_HOWTO (127), - EMPTY_HOWTO (128), - EMPTY_HOWTO (129), - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - EMPTY_HOWTO (133), - EMPTY_HOWTO (134), - EMPTY_HOWTO (135), - EMPTY_HOWTO (136), - EMPTY_HOWTO (137), - EMPTY_HOWTO (138), - EMPTY_HOWTO (139), - EMPTY_HOWTO (140), - EMPTY_HOWTO (141), - EMPTY_HOWTO (142), - EMPTY_HOWTO (143), - - HOWTO (R_SH_TLS_GD_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_GD_32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_LD_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_LD_32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_LDO_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_LDO_32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_IE_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_IE_32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_LE_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_LE_32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_DTPMOD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_DTPMOD32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_DTPOFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_DTPOFF32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_TLS_TPOFF32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_TLS_TPOFF32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (152), - EMPTY_HOWTO (153), - EMPTY_HOWTO (154), - EMPTY_HOWTO (155), - EMPTY_HOWTO (156), - EMPTY_HOWTO (157), - EMPTY_HOWTO (158), - EMPTY_HOWTO (159), - - HOWTO (R_SH_GOT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_GOT32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_PLT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_PLT32", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_SH_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_COPY", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_GLOB_DAT", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_JMP_SLOT", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_RELATIVE", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_GOTOFF, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_GOTOFF", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_GOTPC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_GOTPC", /* name */ - SH_PARTIAL32, /* partial_inplace */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_SH_GOTPLT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* */ - "R_SH_GOTPLT32", /* name */ - FALSE, /* partial_inplace */ - /* ??? Why not 0? */ - SH_SRC_MASK32, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -#ifdef INCLUDE_SHMEDIA - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOT_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOT_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOT_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOT_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOTPLT_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOTPLT_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOTPLT_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOTPLT_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_PLT_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_PLT_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_PLT_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_PLT_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOTOFF_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOTOFF_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOTOFF_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOTOFF_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOTPC_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOTPC_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOTPC_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOTPC_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in LD.L, FLD.S et al. */ - HOWTO (R_SH_GOT10BY4, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT10BY4", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in LD.L, FLD.S et al. */ - HOWTO (R_SH_GOTPLT10BY4, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT10BY4", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in FLD.D, FST.P et al. */ - HOWTO (R_SH_GOT10BY8, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT10BY8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in FLD.D, FST.P et al. */ - HOWTO (R_SH_GOTPLT10BY8, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT10BY8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_COPY64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_COPY64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_GLOB_DAT64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GLOB_DAT64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_JMP_SLOT64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_JMP_SLOT64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_RELATIVE64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_RELATIVE64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ -#else - EMPTY_HOWTO (169), - EMPTY_HOWTO (170), - EMPTY_HOWTO (171), - EMPTY_HOWTO (172), - EMPTY_HOWTO (173), - EMPTY_HOWTO (174), - EMPTY_HOWTO (175), - EMPTY_HOWTO (176), - EMPTY_HOWTO (177), - EMPTY_HOWTO (178), - EMPTY_HOWTO (179), - EMPTY_HOWTO (180), - EMPTY_HOWTO (181), - EMPTY_HOWTO (182), - EMPTY_HOWTO (183), - EMPTY_HOWTO (184), - EMPTY_HOWTO (185), - EMPTY_HOWTO (186), - EMPTY_HOWTO (187), - EMPTY_HOWTO (188), - EMPTY_HOWTO (189), - EMPTY_HOWTO (190), - EMPTY_HOWTO (191), - EMPTY_HOWTO (192), - EMPTY_HOWTO (193), - EMPTY_HOWTO (194), - EMPTY_HOWTO (195), - EMPTY_HOWTO (196), -#endif - - EMPTY_HOWTO (197), - EMPTY_HOWTO (198), - EMPTY_HOWTO (199), - EMPTY_HOWTO (200), - - /* FDPIC-relative offset to a GOT entry, for movi20. */ - HOWTO (R_SH_GOT20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT20", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00f0ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* FDPIC-relative offset to a data object, for movi20. */ - HOWTO (R_SH_GOTOFF20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF20", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00f0ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* FDPIC-relative offset to a GOT entry for a function descriptor. */ - HOWTO (R_SH_GOTFUNCDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTFUNCDESC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* FDPIC-relative offset to a GOT entry for a function descriptor, - for movi20. */ - HOWTO (R_SH_GOTFUNCDESC20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTFUNCDESC20", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00f0ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* FDPIC-relative offset to a function descriptor. */ - HOWTO (R_SH_GOTOFFFUNCDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFFFUNCDESC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* FDPIC-relative offset to a function descriptor, for movi20. */ - HOWTO (R_SH_GOTOFFFUNCDESC20, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 20, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFFFUNCDESC20", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00f0ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Address of an official function descriptor. */ - HOWTO (R_SH_FUNCDESC, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_FUNCDESC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Function descriptor to be filled in by the dynamic linker. */ - HOWTO (R_SH_FUNCDESC_VALUE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_FUNCDESC_VALUE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -#ifdef INCLUDE_SHMEDIA - EMPTY_HOWTO (209), - EMPTY_HOWTO (210), - EMPTY_HOWTO (211), - EMPTY_HOWTO (212), - EMPTY_HOWTO (213), - EMPTY_HOWTO (214), - EMPTY_HOWTO (215), - EMPTY_HOWTO (216), - EMPTY_HOWTO (217), - EMPTY_HOWTO (218), - EMPTY_HOWTO (219), - EMPTY_HOWTO (220), - EMPTY_HOWTO (221), - EMPTY_HOWTO (222), - EMPTY_HOWTO (223), - EMPTY_HOWTO (224), - EMPTY_HOWTO (225), - EMPTY_HOWTO (226), - EMPTY_HOWTO (227), - EMPTY_HOWTO (228), - EMPTY_HOWTO (229), - EMPTY_HOWTO (230), - EMPTY_HOWTO (231), - EMPTY_HOWTO (232), - EMPTY_HOWTO (233), - EMPTY_HOWTO (234), - EMPTY_HOWTO (235), - EMPTY_HOWTO (236), - EMPTY_HOWTO (237), - EMPTY_HOWTO (238), - EMPTY_HOWTO (239), - EMPTY_HOWTO (240), - EMPTY_HOWTO (241), - - /* Relocations for SHmedia code. None of these are partial_inplace or - use the field being relocated (except R_SH_PT_16). */ - - /* The assembler will generate this reloc before a block of SHmedia - instructions. A section should be processed as assuming it contains - data, unless this reloc is seen. Note that a block of SHcompact - instructions are instead preceded by R_SH_CODE. - This is currently not implemented, but should be used for SHmedia - linker relaxation. */ - HOWTO (R_SH_SHMEDIA_CODE, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf_ignore_reloc, /* special_function */ - "R_SH_SHMEDIA_CODE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The assembler will generate this reloc at a PTA or PTB instruction, - and the linker checks the right type of target, or changes a PTA to a - PTB, if the original insn was PT. */ - HOWTO (R_SH_PT_16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PT_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in unexpanded MOVI. */ - HOWTO (R_SH_IMMS16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMMS16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in SHORI. */ - HOWTO (R_SH_IMMU16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMMU16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_IMM_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x - $) & 65536). */ - HOWTO (R_SH_IMM_LOW16_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_LOW16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_IMM_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (((x - $) >> 16) & 65536). */ - HOWTO (R_SH_IMM_MEDLOW16_PCREL, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDLOW16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_IMM_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (((x - $) >> 32) & 65536). */ - HOWTO (R_SH_IMM_MEDHI16_PCREL, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDHI16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_IMM_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (((x - $) >> 48) & 65536). */ - HOWTO (R_SH_IMM_HI16_PCREL, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_HI16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* For the .uaquad pseudo. */ - HOWTO (R_SH_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* For the .uaquad pseudo, (x - $). */ - HOWTO (R_SH_64_PCREL, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_64_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - TRUE), /* pcrel_offset */ - -#endif -#undef SH_PARTIAL32 -#undef SH_SRC_MASK32 -#undef SH_ELF_RELOC diff --git a/sdcc/support/sdbinutils/bfd/elf32-sh-symbian.c b/sdcc/support/sdbinutils/bfd/elf32-sh-symbian.c deleted file mode 100644 index 9abfd739b..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sh-symbian.c +++ /dev/null @@ -1,615 +0,0 @@ -/* Renesas / SuperH specific support for Symbian 32-bit ELF files - Copyright (C) 2004-2018 Free Software Foundation, Inc. - Contributed by Red Hat - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* Stop elf32-sh.c from defining any target vectors. */ -#define SH_TARGET_ALREADY_DEFINED -#define sh_find_elf_flags sh_symbian_find_elf_flags -#define sh_elf_get_flags_from_mach sh_symbian_elf_get_flags_from_mach -#include "elf32-sh.c" - - -//#define SYMBIAN_DEBUG 1 -#define SYMBIAN_DEBUG 0 - -#define DIRECTIVE_HEADER "##\n" -#define DIRECTIVE_IMPORT "IMPORT " -#define DIRECTIVE_EXPORT "EXPORT " -#define DIRECTIVE_AS "AS " - -/* Macro to advance 's' until either it reaches 'e' or the - character pointed to by 's' is equal to 'c'. If 'e' is - reached and SYMBIAN_DEBUG is enabled then the error message 'm' - is displayed. */ -#define SKIP_UNTIL(s,e,c,m) \ - do \ - { \ - while (s < e && *s != c) \ - ++ s; \ - if (s >= e) \ - { \ - if (SYMBIAN_DEBUG) \ - fprintf (stderr, "Corrupt directive: %s\n", m); \ - result = FALSE; \ - } \ - } \ - while (0); \ - if (!result) \ - break; - -/* Like SKIP_UNTIL except there are two terminator characters - c1 and c2. */ -#define SKIP_UNTIL2(s,e,c1,c2,m) \ - do \ - { \ - while (s < e && *s != c1 && *s != c2) \ - ++ s; \ - if (s >= e) \ - { \ - if (SYMBIAN_DEBUG) \ - fprintf (stderr, "Corrupt directive: %s\n", m); \ - result = FALSE; \ - } \ - } \ - while (0); \ - if (!result) \ - break; - -/* Macro to advance 's' until either it reaches 'e' or the - character pointed to by 's' is not equal to 'c'. If 'e' - is reached and SYMBIAN_DEBUG is enabled then the error message - 'm' is displayed. */ -#define SKIP_WHILE(s,e,c,m) \ - do \ - { \ - while (s < e && *s == c) \ - ++ s; \ - if (s >= e) \ - { \ - if (SYMBIAN_DEBUG) \ - fprintf (stderr, "Corrupt directive: %s\n", m); \ - result = FALSE; \ - } \ - } \ - while (0); \ - if (!result) \ - break; - - -typedef struct symbol_rename -{ - struct symbol_rename * next; - char * current_name; - char * new_name; - struct elf_link_hash_entry * current_hash; - unsigned long new_symndx; -} -symbol_rename; - -static symbol_rename * rename_list = NULL; - -/* Accumulate a list of symbols to be renamed. */ - -static bfd_boolean -sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd, - char * current_name, char * new_name) -{ - struct elf_link_hash_entry * new_hash; - symbol_rename * node; - - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name); - - for (node = rename_list; node; node = node->next) - if (strcmp (node->current_name, current_name) == 0) - { - if (strcmp (node->new_name, new_name) == 0) - /* Already added to rename list. */ - return TRUE; - - bfd_set_error (bfd_error_invalid_operation); - /* xgettext:c-format */ - _bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"), - abfd, current_name); - return FALSE; - } - - if ((node = bfd_malloc (sizeof * node)) == NULL) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT AS: No mem for new rename node\n"); - return FALSE; - } - - if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n"); - free (node); - return FALSE; - } - else - strcpy (node->current_name, current_name); - - if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n"); - free (node->current_name); - free (node); - return FALSE; - } - else - strcpy (node->new_name, new_name); - - node->next = rename_list; - node->current_hash = NULL; - node->new_symndx = 0; - rename_list = node; - - new_hash = elf_link_hash_lookup (elf_hash_table (info), node->new_name, TRUE, FALSE, TRUE); - bfd_elf_link_record_dynamic_symbol (info, new_hash); - if (new_hash->root.type == bfd_link_hash_new) - new_hash->root.type = bfd_link_hash_undefined; - - return TRUE; -} - - -static bfd_boolean -sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, char * name) -{ - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT '%s'\n", name); - - /* XXX: Generate an import somehow ? */ - - return TRUE; -} - -static bfd_boolean -sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, char * name) -{ - if (SYMBIAN_DEBUG) - fprintf (stderr, "EXPORT '%s'\n", name); - - /* XXX: Generate an export somehow ? */ - - return TRUE; -} - -/* Process any magic embedded commands in the .directive. section. - Returns TRUE upon sucecss, but if it fails it sets bfd_error and - returns FALSE. */ - -static bfd_boolean -sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd, - asection * sec, bfd_byte * contents) -{ - char *s; - char *e; - bfd_boolean result = TRUE; - bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size; - - for (s = (char *) contents, e = s + sz; s < e;) - { - char * directive = s; - - switch (*s) - { - /* I want to use "case DIRECTIVE_HEADER [0]:" here but gcc won't let me :-( */ - case '#': - if (strcmp (s, DIRECTIVE_HEADER)) - result = FALSE; - else - /* Just ignore the header. - XXX: Strictly speaking we ought to check that the header - is present and that it is the first thing in the file. */ - s += strlen (DIRECTIVE_HEADER) + 1; - break; - - case 'I': - if (! CONST_STRNEQ (s, DIRECTIVE_IMPORT)) - result = FALSE; - else - { - char * new_name; - char * new_name_end; - char name_end_char; - - /* Skip the IMPORT directive. */ - s += strlen (DIRECTIVE_IMPORT); - - new_name = s; - /* Find the end of the new name. */ - while (s < e && *s != ' ' && *s != '\n') - ++ s; - if (s >= e) - { - /* We have reached the end of the .directive section - without encountering a string terminator. This is - allowed for IMPORT directives. */ - new_name_end = e - 1; - name_end_char = * new_name_end; - * new_name_end = 0; - result = sh_symbian_import (abfd, new_name); - * new_name_end = name_end_char; - break; - } - - /* Remember where the name ends. */ - new_name_end = s; - /* Skip any whitespace before the 'AS'. */ - SKIP_WHILE (s, e, ' ', "IMPORT: Name just followed by spaces"); - /* Terminate the new name. (Do this after skiping...) */ - name_end_char = * new_name_end; - * new_name_end = 0; - - /* Check to see if 'AS '... is present. If so we have an - IMPORT AS directive, otherwise we have an IMPORT directive. */ - if (! CONST_STRNEQ (s, DIRECTIVE_AS)) - { - /* Skip the new-line at the end of the name. */ - if (SYMBIAN_DEBUG && name_end_char != '\n') - fprintf (stderr, "IMPORT: No newline at end of directive\n"); - else - s ++; - - result = sh_symbian_import (abfd, new_name); - - /* Skip past the NUL character. */ - if (* s ++ != 0) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT: No NUL at end of directive\n"); - } - } - else - { - char * current_name; - char * current_name_end; - char current_name_end_char; - - /* Skip the 'AS '. */ - s += strlen (DIRECTIVE_AS); - /* Skip any white space after the 'AS '. */ - SKIP_WHILE (s, e, ' ', "IMPORT AS: Nothing after AS"); - current_name = s; - /* Find the end of the current name. */ - SKIP_UNTIL2 (s, e, ' ', '\n', "IMPORT AS: No newline at the end of the current name"); - /* Skip (backwards) over spaces at the end of the current name. */ - current_name_end = s; - current_name_end_char = * current_name_end; - - SKIP_WHILE (s, e, ' ', "IMPORT AS: Current name just followed by spaces"); - /* Skip past the newline character. */ - if (* s ++ != '\n') - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT AS: No newline at end of directive\n"); - - /* Terminate the current name after having performed the skips. */ - * current_name_end = 0; - - result = sh_symbian_import_as (info, abfd, current_name, new_name); - - /* The next character should be a NUL. */ - if (* s != 0) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT AS: Junk at end of directive\n"); - result = FALSE; - } - s ++; - - * current_name_end = current_name_end_char; - } - - /* Restore the characters we overwrote, since - the .directive section will be emitted. */ - * new_name_end = name_end_char; - } - break; - - case 'E': - if (! CONST_STRNEQ (s, DIRECTIVE_EXPORT)) - result = FALSE; - else - { - char * name; - char * name_end; - char name_end_char; - - /* Skip the directive. */ - s += strlen (DIRECTIVE_EXPORT); - name = s; - /* Find the end of the name to be exported. */ - SKIP_UNTIL (s, e, '\n', "EXPORT: no newline at end of directive"); - /* Skip (backwards) over spaces at end of exported name. */ - for (name_end = s; name_end[-1] == ' '; name_end --) - ; - /* name_end now points at the first character after the - end of the exported name, so we can termiante it */ - name_end_char = * name_end; - * name_end = 0; - /* Skip passed the newline character. */ - s ++; - - result = sh_symbian_export (abfd, name); - - /* The next character should be a NUL. */ - if (* s != 0) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "EXPORT: Junk at end of directive\n"); - result = FALSE; - } - s++; - - /* Restore the character we deleted. */ - * name_end = name_end_char; - } - break; - - default: - result = FALSE; - break; - } - - if (! result) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "offset into .directive section: %ld\n", - (long) (directive - (char *) contents)); - - bfd_set_error (bfd_error_invalid_operation); - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Unrecognised .directive command: %s"), - abfd, directive); - break; - } - } - - return result; -} - - -/* Scan a bfd for a .directive section, and if found process it. - Returns TRUE upon success, FALSE otherwise. */ - -static bfd_boolean -sh_symbian_process_directives (bfd *abfd, struct bfd_link_info *info) -{ - bfd_boolean result = FALSE; - bfd_byte * contents; - asection * sec = bfd_get_section_by_name (abfd, ".directive"); - bfd_size_type sz; - - if (!sec) - return TRUE; - - sz = sec->rawsize ? sec->rawsize : sec->size; - contents = bfd_malloc (sz); - - if (!contents) - bfd_set_error (bfd_error_no_memory); - else - { - if (bfd_get_section_contents (abfd, sec, contents, 0, sz)) - result = sh_symbian_process_embedded_commands (info, abfd, sec, contents); - free (contents); - } - - return result; -} - -/* Intercept the normal sh_relocate_section() function - and magle the relocs to allow for symbol renaming. */ - -static bfd_boolean -sh_symbian_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) -{ - /* When performing a final link we implement the IMPORT AS directives. */ - if (!bfd_link_relocatable (info)) - { - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - struct elf_link_hash_entry ** sym_hashes_end; - struct elf_link_hash_table * hash_table; - symbol_rename * ptr; - bfd_size_type num_global_syms; - unsigned long num_local_syms; - - BFD_ASSERT (! elf_bad_symtab (input_bfd)); - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - hash_table = elf_hash_table (info); - num_local_syms = symtab_hdr->sh_info; - num_global_syms = symtab_hdr->sh_size / sizeof (Elf32_External_Sym); - num_global_syms -= num_local_syms; - sym_hashes = elf_sym_hashes (input_bfd); - sym_hashes_end = sym_hashes + num_global_syms; - - /* First scan the rename table, caching the hash entry and the new index. */ - for (ptr = rename_list; ptr; ptr = ptr->next) - { - struct elf_link_hash_entry * new_hash; - struct elf_link_hash_entry ** h; - - ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE); - - if (ptr->current_hash == NULL) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name); - continue; - } - - new_hash = elf_link_hash_lookup (hash_table, ptr->new_name, - FALSE, FALSE, TRUE); - /* If we could not find the symbol then it is a new, undefined symbol. - Symbian want this behaviour - ie they want to be able to rename the - reference in a reloc from one undefined symbol to another, new and - undefined symbol. So we create that symbol here. */ - if (new_hash == NULL) - { - struct bfd_link_hash_entry *bh = NULL; - bfd_boolean collect = get_elf_backend_data (input_bfd)->collect; - if (_bfd_generic_link_add_one_symbol (info, input_bfd, - ptr->new_name, BSF_GLOBAL, - bfd_und_section_ptr, 0, - NULL, FALSE, collect, - &bh)) - { - new_hash = (struct elf_link_hash_entry *) bh; - new_hash->type = STT_FUNC; - new_hash->non_elf = 0; - - if (SYMBIAN_DEBUG) - fprintf (stderr, "Created new symbol %s\n", ptr->new_name); - } - } - - if (new_hash == NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: Failed to add renamed symbol %s"), - input_bfd, ptr->new_name); - continue; - } - - /* Convert the new_hash value into a index into the table of symbol hashes. */ - for (h = sym_hashes; h < sym_hashes_end; h ++) - { - if (* h == new_hash) - { - ptr->new_symndx = h - sym_hashes + num_local_syms; - if (SYMBIAN_DEBUG) - fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx); - break; - } - } - /* If the new symbol is not in the hash table then it must be - because it is one of the newly created undefined symbols - manufactured above. So we extend the sym has table here to - include this extra symbol. */ - if (h == sym_hashes_end) - { - struct elf_link_hash_entry ** new_sym_hashes; - - /* This is not very efficient, but it works. */ - ++ num_global_syms; - new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes); - if (new_sym_hashes == NULL) - { - if (SYMBIAN_DEBUG) - fprintf (stderr, "Out of memory extending hash table\n"); - continue; - } - memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes); - new_sym_hashes[num_global_syms - 1] = new_hash; - elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes; - sym_hashes_end = sym_hashes + num_global_syms; - symtab_hdr->sh_size = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym); - - ptr->new_symndx = num_global_syms - 1 + num_local_syms; - - if (SYMBIAN_DEBUG) - fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n", - ptr->new_symndx); - } - } - - /* Walk the reloc list looking for references to renamed symbols. - When we find one, we alter the index in the reloc to point to the new symbol. */ - for (rel = relocs, relend = relocs + input_section->reloc_count; - rel < relend; - rel ++) - { - 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); - - /* Ignore unused relocs. */ - if ((r_type >= (int) R_SH_GNU_VTINHERIT - && r_type <= (int) R_SH_LABEL) - || r_type == (int) R_SH_NONE - || r_type < 0 - || r_type >= R_SH_max) - continue; - - /* Ignore relocs against local symbols. */ - if (r_symndx < num_local_syms) - continue; - - BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms)); - h = sym_hashes[r_symndx - num_local_syms]; - BFD_ASSERT (h != NULL); - - while ( h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - /* If the symbol is defined there is no need to rename it. - XXX - is this true ? */ - if ( h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak - || h->root.type == bfd_link_hash_undefweak) - continue; - - for (ptr = rename_list; ptr; ptr = ptr->next) - if (h == ptr->current_hash) - { - BFD_ASSERT (ptr->new_symndx); - if (SYMBIAN_DEBUG) - fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n", - (unsigned long) rel->r_info, - (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx); - rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type); - break; - } - } - } - - return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section, - contents, relocs, local_syms, local_sections); -} - -#define TARGET_LITTLE_SYM sh_elf32_symbian_le_vec -#define TARGET_LITTLE_NAME "elf32-shl-symbian" - -#undef elf_backend_relocate_section -#define elf_backend_relocate_section sh_symbian_relocate_section -#undef elf_backend_check_directives -#define elf_backend_check_directives sh_symbian_process_directives - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-sh.c b/sdcc/support/sdbinutils/bfd/elf32-sh.c deleted file mode 100644 index b4854a2ce..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sh.c +++ /dev/null @@ -1,7405 +0,0 @@ -/* Renesas / SuperH SH specific support for 32-bit ELF - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Contributed 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf-vxworks.h" -#include "elf/sh.h" -#include "dwarf2.h" -#include "libiberty.h" -#include "../opcodes/sh-opc.h" - -static bfd_reloc_status_type sh_elf_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type sh_elf_ignore_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_boolean sh_elf_relax_delete_bytes - (bfd *, asection *, bfd_vma, int); -static bfd_boolean sh_elf_align_loads - (bfd *, asection *, Elf_Internal_Rela *, bfd_byte *, bfd_boolean *); -#ifndef SH64_ELF -static bfd_boolean sh_elf_swap_insns - (bfd *, asection *, void *, bfd_byte *, bfd_vma); -#endif -static int sh_elf_optimized_tls_reloc - (struct bfd_link_info *, int, int); -static bfd_vma dtpoff_base - (struct bfd_link_info *); -static bfd_vma tpoff - (struct bfd_link_info *, bfd_vma); - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" - -/* FDPIC binaries have a default 128K stack. */ -#define DEFAULT_STACK_SIZE 0x20000 - -#define MINUS_ONE ((bfd_vma) 0 - 1) - -/* Decide whether a reference to a symbol can be resolved locally or - not. If the symbol is protected, we want the local address, but - its function descriptor must be assigned by the dynamic linker. */ -#define SYMBOL_FUNCDESC_LOCAL(INFO, H) \ - (SYMBOL_REFERENCES_LOCAL (INFO, H) \ - || ! elf_hash_table (INFO)->dynamic_sections_created) - -#define SH_PARTIAL32 TRUE -#define SH_SRC_MASK32 0xffffffff -#define SH_ELF_RELOC sh_elf_reloc -static reloc_howto_type sh_elf_howto_table[] = -{ -#include "elf32-sh-relocs.h" -}; - -#define SH_PARTIAL32 FALSE -#define SH_SRC_MASK32 0 -#define SH_ELF_RELOC bfd_elf_generic_reloc -static reloc_howto_type sh_vxworks_howto_table[] = -{ -#include "elf32-sh-relocs.h" -}; - -/* Return true if OUTPUT_BFD is a VxWorks object. */ - -static bfd_boolean -vxworks_object_p (bfd *abfd ATTRIBUTE_UNUSED) -{ -#if !defined INCLUDE_SHMEDIA && !defined SH_TARGET_ALREADY_DEFINED - extern const bfd_target sh_elf32_vxworks_le_vec; - extern const bfd_target sh_elf32_vxworks_vec; - - return (abfd->xvec == &sh_elf32_vxworks_le_vec - || abfd->xvec == &sh_elf32_vxworks_vec); -#else - return FALSE; -#endif -} - -/* Return true if OUTPUT_BFD is an FDPIC object. */ - -static bfd_boolean -fdpic_object_p (bfd *abfd ATTRIBUTE_UNUSED) -{ -#if !defined INCLUDE_SHMEDIA && !defined SH_TARGET_ALREADY_DEFINED - extern const bfd_target sh_elf32_fdpic_le_vec; - extern const bfd_target sh_elf32_fdpic_be_vec; - - return (abfd->xvec == &sh_elf32_fdpic_le_vec - || abfd->xvec == &sh_elf32_fdpic_be_vec); -#else - return FALSE; -#endif -} - -/* Return the howto table for ABFD. */ - -static reloc_howto_type * -get_howto_table (bfd *abfd) -{ - if (vxworks_object_p (abfd)) - return sh_vxworks_howto_table; - return sh_elf_howto_table; -} - -static bfd_reloc_status_type -sh_elf_reloc_loop (int r_type ATTRIBUTE_UNUSED, bfd *input_bfd, - asection *input_section, bfd_byte *contents, - bfd_vma addr, asection *symbol_section, - bfd_vma start, bfd_vma end) -{ - static bfd_vma last_addr; - static asection *last_symbol_section; - bfd_byte *start_ptr, *ptr, *last_ptr; - int diff, cum_diff; - bfd_signed_vma x; - int insn; - - /* Sanity check the address. */ - if (addr > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - /* We require the start and end relocations to be processed consecutively - - although we allow then to be processed forwards or backwards. */ - if (! last_addr) - { - last_addr = addr; - last_symbol_section = symbol_section; - return bfd_reloc_ok; - } - if (last_addr != addr) - abort (); - last_addr = 0; - - if (! symbol_section || last_symbol_section != symbol_section || end < start) - return bfd_reloc_outofrange; - - /* Get the symbol_section contents. */ - if (symbol_section != input_section) - { - if (elf_section_data (symbol_section)->this_hdr.contents != NULL) - contents = elf_section_data (symbol_section)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (input_bfd, symbol_section, - &contents)) - { - if (contents != NULL) - free (contents); - return bfd_reloc_outofrange; - } - } - } -#define IS_PPI(PTR) ((bfd_get_16 (input_bfd, (PTR)) & 0xfc00) == 0xf800) - start_ptr = contents + start; - for (cum_diff = -6, ptr = contents + end; cum_diff < 0 && ptr > start_ptr;) - { - for (last_ptr = ptr, ptr -= 4; ptr >= start_ptr && IS_PPI (ptr);) - ptr -= 2; - ptr += 2; - diff = (last_ptr - ptr) >> 1; - cum_diff += diff & 1; - cum_diff += diff; - } - /* Calculate the start / end values to load into rs / re minus four - - so that will cancel out the four we would otherwise have to add to - addr to get the value to subtract in order to get relative addressing. */ - if (cum_diff >= 0) - { - start -= 4; - end = (ptr + cum_diff * 2) - contents; - } - else - { - bfd_vma start0 = start - 4; - - while (start0 && IS_PPI (contents + start0)) - start0 -= 2; - start0 = start - 2 - ((start - start0) & 2); - start = start0 - cum_diff - 2; - end = start0; - } - - if (contents != NULL - && elf_section_data (symbol_section)->this_hdr.contents != contents) - free (contents); - - insn = bfd_get_16 (input_bfd, contents + addr); - - x = (insn & 0x200 ? end : start) - addr; - if (input_section != symbol_section) - x += ((symbol_section->output_section->vma + symbol_section->output_offset) - - (input_section->output_section->vma - + input_section->output_offset)); - x >>= 1; - if (x < -128 || x > 127) - return bfd_reloc_overflow; - - x = (insn & ~0xff) | (x & 0xff); - bfd_put_16 (input_bfd, (bfd_vma) x, contents + addr); - - return bfd_reloc_ok; -} - -/* This function is used for normal relocs. This used to be like the COFF - function, and is almost certainly incorrect for other ELF targets. */ - -static bfd_reloc_status_type -sh_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in, - void *data, asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - unsigned long insn; - bfd_vma sym_value; - enum elf_sh_reloc_type r_type; - bfd_vma addr = reloc_entry->address; - bfd_byte *hit_data = addr + (bfd_byte *) data; - - r_type = (enum elf_sh_reloc_type) reloc_entry->howto->type; - - if (output_bfd != NULL) - { - /* Partial linking--do nothing. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Almost all relocs have to do with relaxing. If any work must be - done for them, it has been done in sh_relax_section. */ - if (r_type == R_SH_IND12W && (symbol_in->flags & BSF_LOCAL) != 0) - return bfd_reloc_ok; - - if (symbol_in != NULL - && bfd_is_und_section (symbol_in->section)) - return bfd_reloc_undefined; - - /* PR 17512: file: 9891ca98. */ - if (addr * bfd_octets_per_byte (abfd) + bfd_get_reloc_size (reloc_entry->howto) - > bfd_get_section_limit_octets (abfd, input_section)) - return bfd_reloc_outofrange; - - if (bfd_is_com_section (symbol_in->section)) - sym_value = 0; - else - sym_value = (symbol_in->value + - symbol_in->section->output_section->vma + - symbol_in->section->output_offset); - - switch (r_type) - { - case R_SH_DIR32: - insn = bfd_get_32 (abfd, hit_data); - insn += sym_value + reloc_entry->addend; - bfd_put_32 (abfd, (bfd_vma) insn, hit_data); - break; - case R_SH_IND12W: - insn = bfd_get_16 (abfd, hit_data); - sym_value += reloc_entry->addend; - sym_value -= (input_section->output_section->vma - + input_section->output_offset - + addr - + 4); - sym_value += (insn & 0xfff) << 1; - if (insn & 0x800) - sym_value -= 0x1000; - insn = (insn & 0xf000) | (sym_value & 0xfff); - bfd_put_16 (abfd, (bfd_vma) insn, hit_data); - if (sym_value < (bfd_vma) -0x1000 || sym_value >= 0x1000) - return bfd_reloc_overflow; - break; - default: - abort (); - break; - } - - return bfd_reloc_ok; -} - -/* This function is used for relocs which are only used for relaxing, - which the linker should otherwise ignore. */ - -static bfd_reloc_status_type -sh_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -/* This structure is used to map BFD reloc codes to SH ELF relocs. */ - -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -/* An array mapping BFD reloc codes to SH ELF relocs. */ - -static const struct elf_reloc_map sh_reloc_map[] = -{ - { BFD_RELOC_NONE, R_SH_NONE }, - { BFD_RELOC_32, R_SH_DIR32 }, - { BFD_RELOC_16, R_SH_DIR16 }, - { BFD_RELOC_8, R_SH_DIR8 }, - { BFD_RELOC_CTOR, R_SH_DIR32 }, - { BFD_RELOC_32_PCREL, R_SH_REL32 }, - { BFD_RELOC_SH_PCDISP8BY2, R_SH_DIR8WPN }, - { BFD_RELOC_SH_PCDISP12BY2, R_SH_IND12W }, - { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_DIR8WPZ }, - { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_DIR8WPL }, - { BFD_RELOC_8_PCREL, R_SH_SWITCH8 }, - { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 }, - { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 }, - { BFD_RELOC_SH_USES, R_SH_USES }, - { BFD_RELOC_SH_COUNT, R_SH_COUNT }, - { BFD_RELOC_SH_ALIGN, R_SH_ALIGN }, - { BFD_RELOC_SH_CODE, R_SH_CODE }, - { BFD_RELOC_SH_DATA, R_SH_DATA }, - { BFD_RELOC_SH_LABEL, R_SH_LABEL }, - { BFD_RELOC_VTABLE_INHERIT, R_SH_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_SH_GNU_VTENTRY }, - { BFD_RELOC_SH_LOOP_START, R_SH_LOOP_START }, - { BFD_RELOC_SH_LOOP_END, R_SH_LOOP_END }, - { BFD_RELOC_SH_TLS_GD_32, R_SH_TLS_GD_32 }, - { BFD_RELOC_SH_TLS_LD_32, R_SH_TLS_LD_32 }, - { BFD_RELOC_SH_TLS_LDO_32, R_SH_TLS_LDO_32 }, - { BFD_RELOC_SH_TLS_IE_32, R_SH_TLS_IE_32 }, - { BFD_RELOC_SH_TLS_LE_32, R_SH_TLS_LE_32 }, - { BFD_RELOC_SH_TLS_DTPMOD32, R_SH_TLS_DTPMOD32 }, - { BFD_RELOC_SH_TLS_DTPOFF32, R_SH_TLS_DTPOFF32 }, - { BFD_RELOC_SH_TLS_TPOFF32, R_SH_TLS_TPOFF32 }, - { BFD_RELOC_32_GOT_PCREL, R_SH_GOT32 }, - { BFD_RELOC_32_PLT_PCREL, R_SH_PLT32 }, - { BFD_RELOC_SH_COPY, R_SH_COPY }, - { BFD_RELOC_SH_GLOB_DAT, R_SH_GLOB_DAT }, - { BFD_RELOC_SH_JMP_SLOT, R_SH_JMP_SLOT }, - { BFD_RELOC_SH_RELATIVE, R_SH_RELATIVE }, - { BFD_RELOC_32_GOTOFF, R_SH_GOTOFF }, - { BFD_RELOC_SH_GOTPC, R_SH_GOTPC }, - { BFD_RELOC_SH_GOTPLT32, R_SH_GOTPLT32 }, - { BFD_RELOC_SH_GOT20, R_SH_GOT20 }, - { BFD_RELOC_SH_GOTOFF20, R_SH_GOTOFF20 }, - { BFD_RELOC_SH_GOTFUNCDESC, R_SH_GOTFUNCDESC }, - { BFD_RELOC_SH_GOTFUNCDESC20, R_SH_GOTFUNCDESC20 }, - { BFD_RELOC_SH_GOTOFFFUNCDESC, R_SH_GOTOFFFUNCDESC }, - { BFD_RELOC_SH_GOTOFFFUNCDESC20, R_SH_GOTOFFFUNCDESC20 }, - { BFD_RELOC_SH_FUNCDESC, R_SH_FUNCDESC }, -#ifdef INCLUDE_SHMEDIA - { BFD_RELOC_SH_GOT_LOW16, R_SH_GOT_LOW16 }, - { BFD_RELOC_SH_GOT_MEDLOW16, R_SH_GOT_MEDLOW16 }, - { BFD_RELOC_SH_GOT_MEDHI16, R_SH_GOT_MEDHI16 }, - { BFD_RELOC_SH_GOT_HI16, R_SH_GOT_HI16 }, - { BFD_RELOC_SH_GOTPLT_LOW16, R_SH_GOTPLT_LOW16 }, - { BFD_RELOC_SH_GOTPLT_MEDLOW16, R_SH_GOTPLT_MEDLOW16 }, - { BFD_RELOC_SH_GOTPLT_MEDHI16, R_SH_GOTPLT_MEDHI16 }, - { BFD_RELOC_SH_GOTPLT_HI16, R_SH_GOTPLT_HI16 }, - { BFD_RELOC_SH_PLT_LOW16, R_SH_PLT_LOW16 }, - { BFD_RELOC_SH_PLT_MEDLOW16, R_SH_PLT_MEDLOW16 }, - { BFD_RELOC_SH_PLT_MEDHI16, R_SH_PLT_MEDHI16 }, - { BFD_RELOC_SH_PLT_HI16, R_SH_PLT_HI16 }, - { BFD_RELOC_SH_GOTOFF_LOW16, R_SH_GOTOFF_LOW16 }, - { BFD_RELOC_SH_GOTOFF_MEDLOW16, R_SH_GOTOFF_MEDLOW16 }, - { BFD_RELOC_SH_GOTOFF_MEDHI16, R_SH_GOTOFF_MEDHI16 }, - { BFD_RELOC_SH_GOTOFF_HI16, R_SH_GOTOFF_HI16 }, - { BFD_RELOC_SH_GOTPC_LOW16, R_SH_GOTPC_LOW16 }, - { BFD_RELOC_SH_GOTPC_MEDLOW16, R_SH_GOTPC_MEDLOW16 }, - { BFD_RELOC_SH_GOTPC_MEDHI16, R_SH_GOTPC_MEDHI16 }, - { BFD_RELOC_SH_GOTPC_HI16, R_SH_GOTPC_HI16 }, - { BFD_RELOC_SH_COPY64, R_SH_COPY64 }, - { BFD_RELOC_SH_GLOB_DAT64, R_SH_GLOB_DAT64 }, - { BFD_RELOC_SH_JMP_SLOT64, R_SH_JMP_SLOT64 }, - { BFD_RELOC_SH_RELATIVE64, R_SH_RELATIVE64 }, - { BFD_RELOC_SH_GOT10BY4, R_SH_GOT10BY4 }, - { BFD_RELOC_SH_GOT10BY8, R_SH_GOT10BY8 }, - { BFD_RELOC_SH_GOTPLT10BY4, R_SH_GOTPLT10BY4 }, - { BFD_RELOC_SH_GOTPLT10BY8, R_SH_GOTPLT10BY8 }, - { BFD_RELOC_SH_PT_16, R_SH_PT_16 }, - { BFD_RELOC_SH_SHMEDIA_CODE, R_SH_SHMEDIA_CODE }, - { BFD_RELOC_SH_IMMU5, R_SH_DIR5U }, - { BFD_RELOC_SH_IMMS6, R_SH_DIR6S }, - { BFD_RELOC_SH_IMMU6, R_SH_DIR6U }, - { BFD_RELOC_SH_IMMS10, R_SH_DIR10S }, - { BFD_RELOC_SH_IMMS10BY2, R_SH_DIR10SW }, - { BFD_RELOC_SH_IMMS10BY4, R_SH_DIR10SL }, - { BFD_RELOC_SH_IMMS10BY8, R_SH_DIR10SQ }, - { BFD_RELOC_SH_IMMS16, R_SH_IMMS16 }, - { BFD_RELOC_SH_IMMU16, R_SH_IMMU16 }, - { BFD_RELOC_SH_IMM_LOW16, R_SH_IMM_LOW16 }, - { BFD_RELOC_SH_IMM_LOW16_PCREL, R_SH_IMM_LOW16_PCREL }, - { BFD_RELOC_SH_IMM_MEDLOW16, R_SH_IMM_MEDLOW16 }, - { BFD_RELOC_SH_IMM_MEDLOW16_PCREL, R_SH_IMM_MEDLOW16_PCREL }, - { BFD_RELOC_SH_IMM_MEDHI16, R_SH_IMM_MEDHI16 }, - { BFD_RELOC_SH_IMM_MEDHI16_PCREL, R_SH_IMM_MEDHI16_PCREL }, - { BFD_RELOC_SH_IMM_HI16, R_SH_IMM_HI16 }, - { BFD_RELOC_SH_IMM_HI16_PCREL, R_SH_IMM_HI16_PCREL }, - { BFD_RELOC_64, R_SH_64 }, - { BFD_RELOC_64_PCREL, R_SH_64_PCREL }, -#endif /* not INCLUDE_SHMEDIA */ -}; - -/* Given a BFD reloc code, return the howto structure for the - corresponding SH ELF reloc. */ - -static reloc_howto_type * -sh_elf_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (sh_reloc_map) / sizeof (struct elf_reloc_map); i++) - { - if (sh_reloc_map[i].bfd_reloc_val == code) - return get_howto_table (abfd) + (int) sh_reloc_map[i].elf_reloc_val; - } - - return NULL; -} - -static reloc_howto_type * -sh_elf_reloc_name_lookup (bfd *abfd, const char *r_name) -{ - unsigned int i; - - if (vxworks_object_p (abfd)) - { - for (i = 0; - i < (sizeof (sh_vxworks_howto_table) - / sizeof (sh_vxworks_howto_table[0])); - i++) - if (sh_vxworks_howto_table[i].name != NULL - && strcasecmp (sh_vxworks_howto_table[i].name, r_name) == 0) - return &sh_vxworks_howto_table[i]; - } - else - { - for (i = 0; - i < (sizeof (sh_elf_howto_table) - / sizeof (sh_elf_howto_table[0])); - i++) - if (sh_elf_howto_table[i].name != NULL - && strcasecmp (sh_elf_howto_table[i].name, r_name) == 0) - return &sh_elf_howto_table[i]; - } - - return NULL; -} - -/* Given an ELF reloc, fill in the howto field of a relent. */ - -static void -sh_elf_info_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r; - - r = ELF32_R_TYPE (dst->r_info); - - if (r >= R_SH_max - || (r >= R_SH_FIRST_INVALID_RELOC && r <= R_SH_LAST_INVALID_RELOC) - || (r >= R_SH_FIRST_INVALID_RELOC_2 && r <= R_SH_LAST_INVALID_RELOC_2) - || (r >= R_SH_FIRST_INVALID_RELOC_3 && r <= R_SH_LAST_INVALID_RELOC_3) - || (r >= R_SH_FIRST_INVALID_RELOC_4 && r <= R_SH_LAST_INVALID_RELOC_4) - || (r >= R_SH_FIRST_INVALID_RELOC_5 && r <= R_SH_LAST_INVALID_RELOC_5) - || (r >= R_SH_FIRST_INVALID_RELOC_6 && r <= R_SH_LAST_INVALID_RELOC_6)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised SH reloc number: %d"), - abfd, r); - bfd_set_error (bfd_error_bad_value); - r = R_SH_NONE; - } - - cache_ptr->howto = get_howto_table (abfd) + r; -} - -/* This function handles relaxing for SH ELF. See the corresponding - function in coff-sh.c for a description of what this does. FIXME: - There is a lot of duplication here between this code and the COFF - specific code. The format of relocs and symbols is wound deeply - into this code, but it would still be better if the duplication - could be eliminated somehow. Note in particular that although both - functions use symbols like R_SH_CODE, those symbols have different - values; in coff-sh.c they come from include/coff/sh.h, whereas here - they come from enum elf_sh_reloc_type in include/elf/sh.h. */ - -static bfd_boolean -sh_elf_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - bfd_boolean have_code; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - *again = FALSE; - - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0) - return TRUE; - -#ifdef INCLUDE_SHMEDIA - if (elf_section_data (sec)->this_hdr.sh_flags - & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) - { - return TRUE; - } -#endif - - symtab_hdr = &elf_symtab_hdr (abfd); - - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - have_code = FALSE; - - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma laddr, paddr, symval; - unsigned short insn; - Elf_Internal_Rela *irelfn, *irelscan, *irelcount; - bfd_signed_vma foff; - - if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_CODE) - have_code = TRUE; - - if (ELF32_R_TYPE (irel->r_info) != (int) R_SH_USES) - continue; - - /* Get the section contents. */ - if (contents == NULL) - { - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* The r_addend field of the R_SH_USES reloc will point us to - the register load. The 4 is because the r_addend field is - computed as though it were a jump offset, which are based - from 4 bytes after the jump instruction. */ - laddr = irel->r_offset + 4 + irel->r_addend; - if (laddr >= sec->size) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %#Lx: warning: bad R_SH_USES offset"), - abfd, irel->r_offset); - continue; - } - insn = bfd_get_16 (abfd, contents + laddr); - - /* If the instruction is not mov.l NN,rN, we don't know what to - do. */ - if ((insn & 0xf000) != 0xd000) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_SH_USES points to unrecognized insn 0x%x"), - abfd, irel->r_offset, insn); - continue; - } - - /* Get the address from which the register is being loaded. The - displacement in the mov.l instruction is quadrupled. It is a - displacement from four bytes after the movl instruction, but, - before adding in the PC address, two least significant bits - of the PC are cleared. We assume that the section is aligned - on a four byte boundary. */ - paddr = insn & 0xff; - paddr *= 4; - paddr += (laddr + 4) &~ (bfd_vma) 3; - if (paddr >= sec->size) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: bad R_SH_USES load offset"), - abfd, irel->r_offset); - continue; - } - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - for (irelfn = internal_relocs; irelfn < irelend; irelfn++) - if (irelfn->r_offset == paddr - && ELF32_R_TYPE (irelfn->r_info) == (int) R_SH_DIR32) - break; - if (irelfn >= irelend) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: could not find expected reloc"), - abfd, paddr); - continue; - } - - /* Read this BFD's symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - isym = isymbuf + ELF32_R_SYM (irelfn->r_info); - if (isym->st_shndx - != (unsigned int) _bfd_elf_section_from_bfd_section (abfd, sec)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: symbol in unexpected section"), - abfd, paddr); - continue; - } - - symval = (isym->st_value - + sec->output_section->vma - + sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - indx = ELF32_R_SYM (irelfn->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - { - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - } - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - if (get_howto_table (abfd)[R_SH_DIR32].partial_inplace) - symval += bfd_get_32 (abfd, contents + paddr); - else - symval += irelfn->r_addend; - - /* See if this function call can be shortened. */ - foff = (symval - - (irel->r_offset - + sec->output_section->vma - + sec->output_offset - + 4)); - /* A branch to an address beyond ours might be increased by an - .align that doesn't move when bytes behind us are deleted. - So, we add some slop in this calculation to allow for - that. */ - if (foff < -0x1000 || foff >= 0x1000 - 8) - { - /* After all that work, we can't shorten this function call. */ - continue; - } - - /* Shorten the function call. */ - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Replace the jmp/jsr with a bra/bsr. */ - - /* Change the R_SH_USES reloc into an R_SH_IND12W reloc, and - replace the jmp/jsr with a bra/bsr. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_SH_IND12W); - /* We used to test (ELF32_R_SYM (irelfn->r_info) < symtab_hdr->sh_info) - here, but that only checks if the symbol is an external symbol, - not if the symbol is in a different section. Besides, we need - a consistent meaning for the relocation, so we just assume here that - the value of the symbol is not available. */ - - /* We can't fully resolve this yet, because the external - symbol value may be changed by future relaxing. We let - the final link phase handle it. */ - if (bfd_get_16 (abfd, contents + irel->r_offset) & 0x0020) - bfd_put_16 (abfd, (bfd_vma) 0xa000, contents + irel->r_offset); - else - bfd_put_16 (abfd, (bfd_vma) 0xb000, contents + irel->r_offset); - - irel->r_addend = -4; - - /* When we calculated the symbol "value" we had an offset in the - DIR32's word in memory (we read and add it above). However, - the jsr we create does NOT have this offset encoded, so we - have to add it to the addend to preserve it. */ - irel->r_addend += bfd_get_32 (abfd, contents + paddr); - - /* See if there is another R_SH_USES reloc referring to the same - register load. */ - for (irelscan = internal_relocs; irelscan < irelend; irelscan++) - if (ELF32_R_TYPE (irelscan->r_info) == (int) R_SH_USES - && laddr == irelscan->r_offset + 4 + irelscan->r_addend) - break; - if (irelscan < irelend) - { - /* Some other function call depends upon this register load, - and we have not yet converted that function call. - Indeed, we may never be able to convert it. There is - nothing else we can do at this point. */ - continue; - } - - /* Look for a R_SH_COUNT reloc on the location where the - function address is stored. Do this before deleting any - bytes, to avoid confusion about the address. */ - for (irelcount = internal_relocs; irelcount < irelend; irelcount++) - if (irelcount->r_offset == paddr - && ELF32_R_TYPE (irelcount->r_info) == (int) R_SH_COUNT) - break; - - /* Delete the register load. */ - if (! sh_elf_relax_delete_bytes (abfd, sec, laddr, 2)) - goto error_return; - - /* That will change things, so, just in case it permits some - other function call to come within range, we should relax - again. Note that this is not required, and it may be slow. */ - *again = TRUE; - - /* Now check whether we got a COUNT reloc. */ - if (irelcount >= irelend) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: could not find expected COUNT reloc"), - abfd, paddr); - continue; - } - - /* The number of uses is stored in the r_addend field. We've - just deleted one. */ - if (irelcount->r_addend == 0) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %#Lx: warning: bad count"), - abfd, paddr); - continue; - } - - --irelcount->r_addend; - - /* If there are no more uses, we can delete the address. Reload - the address from irelfn, in case it was changed by the - previous call to sh_elf_relax_delete_bytes. */ - if (irelcount->r_addend == 0) - { - if (! sh_elf_relax_delete_bytes (abfd, sec, irelfn->r_offset, 4)) - goto error_return; - } - - /* We've done all we can with that function call. */ - } - - /* Look for load and store instructions that we can align on four - byte boundaries. */ - if ((elf_elfheader (abfd)->e_flags & EF_SH_MACH_MASK) != EF_SH4 - && have_code) - { - bfd_boolean swapped; - - /* Get the section contents. */ - if (contents == NULL) - { - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - if (! sh_elf_align_loads (abfd, sec, internal_relocs, contents, - &swapped)) - goto error_return; - - if (swapped) - { - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (! link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; -} - -/* Delete some bytes from a section while relaxing. FIXME: There is a - lot of duplication between this function and sh_relax_delete_bytes - in coff-sh.c. */ - -static bfd_boolean -sh_elf_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, - int count) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Rela *irelalign; - bfd_vma toaddr; - Elf_Internal_Sym *isymbuf, *isym, *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - asection *o; - - symtab_hdr = &elf_symtab_hdr (abfd); - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - /* The deletion must stop at the next ALIGN reloc for an alignment - power larger than the number of bytes we are deleting. */ - - irelalign = NULL; - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - for (; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN - && irel->r_offset > addr - && count < (1 << irel->r_addend)) - { - irelalign = irel; - toaddr = irel->r_offset; - break; - } - } - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - if (irelalign == NULL) - sec->size -= count; - else - { - int i; - -#define NOP_OPCODE (0x0009) - - BFD_ASSERT ((count & 1) == 0); - for (i = 0; i < count; i += 2) - bfd_put_16 (abfd, (bfd_vma) NOP_OPCODE, contents + toaddr - count + i); - } - - /* Adjust all the relocs. */ - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - bfd_vma nraddr, stop; - bfd_vma start = 0; - int insn = 0; - int off, adjust, oinsn; - bfd_signed_vma voff = 0; - bfd_boolean overflow; - - /* Get the new reloc address. */ - nraddr = irel->r_offset; - if ((irel->r_offset > addr - && irel->r_offset < toaddr) - || (ELF32_R_TYPE (irel->r_info) == (int) R_SH_ALIGN - && irel->r_offset == toaddr)) - nraddr -= count; - - /* See if this reloc was for the bytes we have deleted, in which - case we no longer care about it. Don't delete relocs which - represent addresses, though. */ - if (irel->r_offset >= addr - && irel->r_offset < addr + count - && ELF32_R_TYPE (irel->r_info) != (int) R_SH_ALIGN - && ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE - && ELF32_R_TYPE (irel->r_info) != (int) R_SH_DATA - && ELF32_R_TYPE (irel->r_info) != (int) R_SH_LABEL) - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (int) R_SH_NONE); - - /* If this is a PC relative reloc, see if the range it covers - includes the bytes we have deleted. */ - switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info)) - { - default: - break; - - case R_SH_DIR8WPN: - case R_SH_IND12W: - case R_SH_DIR8WPZ: - case R_SH_DIR8WPL: - start = irel->r_offset; - insn = bfd_get_16 (abfd, contents + nraddr); - break; - } - - switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info)) - { - default: - start = stop = addr; - break; - - case R_SH_DIR32: - /* If this reloc is against a symbol defined in this - section, and the symbol will not be adjusted below, we - must check the addend to see it will put the value in - range to be adjusted, and hence must be changed. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == sec_shndx - && (isym->st_value <= addr - || isym->st_value >= toaddr)) - { - bfd_vma val; - - if (get_howto_table (abfd)[R_SH_DIR32].partial_inplace) - { - val = bfd_get_32 (abfd, contents + nraddr); - val += isym->st_value; - if (val > addr && val < toaddr) - bfd_put_32 (abfd, val - count, contents + nraddr); - } - else - { - val = isym->st_value + irel->r_addend; - if (val > addr && val < toaddr) - irel->r_addend -= count; - } - } - } - start = stop = addr; - break; - - case R_SH_DIR8WPN: - off = insn & 0xff; - if (off & 0x80) - off -= 0x100; - stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); - break; - - case R_SH_IND12W: - off = insn & 0xfff; - if (! off) - { - /* This has been made by previous relaxation. Since the - relocation will be against an external symbol, the - final relocation will just do the right thing. */ - start = stop = addr; - } - else - { - if (off & 0x800) - off -= 0x1000; - stop = (bfd_vma) ((bfd_signed_vma) start + 4 + off * 2); - - /* The addend will be against the section symbol, thus - for adjusting the addend, the relevant start is the - start of the section. - N.B. If we want to abandon in-place changes here and - test directly using symbol + addend, we have to take into - account that the addend has already been adjusted by -4. */ - if (stop > addr && stop < toaddr) - irel->r_addend -= count; - } - break; - - case R_SH_DIR8WPZ: - off = insn & 0xff; - stop = start + 4 + off * 2; - break; - - case R_SH_DIR8WPL: - off = insn & 0xff; - stop = (start & ~(bfd_vma) 3) + 4 + off * 4; - break; - - case R_SH_SWITCH8: - case R_SH_SWITCH16: - case R_SH_SWITCH32: - /* These relocs types represent - .word L2-L1 - The r_addend field holds the difference between the reloc - address and L1. That is the start of the reloc, and - adding in the contents gives us the top. We must adjust - both the r_offset field and the section contents. - N.B. in gas / coff bfd, the elf bfd r_addend is called r_offset, - and the elf bfd r_offset is called r_vaddr. */ - - stop = irel->r_offset; - start = (bfd_vma) ((bfd_signed_vma) stop - (long) irel->r_addend); - - if (start > addr - && start < toaddr - && (stop <= addr || stop >= toaddr)) - irel->r_addend += count; - else if (stop > addr - && stop < toaddr - && (start <= addr || start >= toaddr)) - irel->r_addend -= count; - - if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_SWITCH16) - voff = bfd_get_signed_16 (abfd, contents + nraddr); - else if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_SWITCH8) - voff = bfd_get_8 (abfd, contents + nraddr); - else - voff = bfd_get_signed_32 (abfd, contents + nraddr); - stop = (bfd_vma) ((bfd_signed_vma) start + voff); - - break; - - case R_SH_USES: - start = irel->r_offset; - stop = (bfd_vma) ((bfd_signed_vma) start - + (long) irel->r_addend - + 4); - break; - } - - if (start > addr - && start < toaddr - && (stop <= addr || stop >= toaddr)) - adjust = count; - else if (stop > addr - && stop < toaddr - && (start <= addr || start >= toaddr)) - adjust = - count; - else - adjust = 0; - - if (adjust != 0) - { - oinsn = insn; - overflow = FALSE; - switch ((enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info)) - { - default: - abort (); - break; - - case R_SH_DIR8WPN: - case R_SH_DIR8WPZ: - insn += adjust / 2; - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr); - break; - - case R_SH_IND12W: - insn += adjust / 2; - if ((oinsn & 0xf000) != (insn & 0xf000)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr); - break; - - case R_SH_DIR8WPL: - BFD_ASSERT (adjust == count || count >= 4); - if (count >= 4) - insn += adjust / 4; - else - { - if ((irel->r_offset & 3) == 0) - ++insn; - } - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, contents + nraddr); - break; - - case R_SH_SWITCH8: - voff += adjust; - if (voff < 0 || voff >= 0xff) - overflow = TRUE; - bfd_put_8 (abfd, voff, contents + nraddr); - break; - - case R_SH_SWITCH16: - voff += adjust; - if (voff < - 0x8000 || voff >= 0x8000) - overflow = TRUE; - bfd_put_signed_16 (abfd, (bfd_vma) voff, contents + nraddr); - break; - - case R_SH_SWITCH32: - voff += adjust; - bfd_put_signed_32 (abfd, (bfd_vma) voff, contents + nraddr); - break; - - case R_SH_USES: - irel->r_addend += adjust; - break; - } - - if (overflow) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: reloc overflow while relaxing"), - abfd, irel->r_offset); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - irel->r_offset = nraddr; - } - - /* Look through all the other sections. If there contain any IMM32 - relocs against internal symbols which we are not going to adjust - below, we may need to adjust the addends. */ - for (o = abfd->sections; o != NULL; o = o->next) - { - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irelscan, *irelscanend; - bfd_byte *ocontents; - - if (o == sec - || (o->flags & SEC_RELOC) == 0 - || o->reloc_count == 0) - continue; - - /* We always cache the relocs. Perhaps, if info->keep_memory is - FALSE, we should free them, if we are permitted to, when we - leave sh_coff_relax_section. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, o, NULL, (Elf_Internal_Rela *) NULL, TRUE)); - if (internal_relocs == NULL) - return FALSE; - - ocontents = NULL; - irelscanend = internal_relocs + o->reloc_count; - for (irelscan = internal_relocs; irelscan < irelscanend; irelscan++) - { - /* Dwarf line numbers use R_SH_SWITCH32 relocs. */ - if (ELF32_R_TYPE (irelscan->r_info) == (int) R_SH_SWITCH32) - { - bfd_vma start, stop; - bfd_signed_vma voff; - - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to, - when we leave sh_coff_relax_section. */ - if (!bfd_malloc_and_get_section (abfd, o, &ocontents)) - { - if (ocontents != NULL) - free (ocontents); - return FALSE; - } - - elf_section_data (o)->this_hdr.contents = ocontents; - } - } - - stop = irelscan->r_offset; - start - = (bfd_vma) ((bfd_signed_vma) stop - (long) irelscan->r_addend); - - /* STOP is in a different section, so it won't change. */ - if (start > addr && start < toaddr) - irelscan->r_addend += count; - - voff = bfd_get_signed_32 (abfd, ocontents + irelscan->r_offset); - stop = (bfd_vma) ((bfd_signed_vma) start + voff); - - if (start > addr - && start < toaddr - && (stop <= addr || stop >= toaddr)) - bfd_put_signed_32 (abfd, (bfd_vma) voff + count, - ocontents + irelscan->r_offset); - else if (stop > addr - && stop < toaddr - && (start <= addr || start >= toaddr)) - bfd_put_signed_32 (abfd, (bfd_vma) voff - count, - ocontents + irelscan->r_offset); - } - - if (ELF32_R_TYPE (irelscan->r_info) != (int) R_SH_DIR32) - continue; - - if (ELF32_R_SYM (irelscan->r_info) >= symtab_hdr->sh_info) - continue; - - - isym = isymbuf + ELF32_R_SYM (irelscan->r_info); - if (isym->st_shndx == sec_shndx - && (isym->st_value <= addr - || isym->st_value >= toaddr)) - { - bfd_vma val; - - if (ocontents == NULL) - { - if (elf_section_data (o)->this_hdr.contents != NULL) - ocontents = elf_section_data (o)->this_hdr.contents; - else - { - /* We always cache the section contents. - Perhaps, if info->keep_memory is FALSE, we - should free them, if we are permitted to, - when we leave sh_coff_relax_section. */ - if (!bfd_malloc_and_get_section (abfd, o, &ocontents)) - { - if (ocontents != NULL) - free (ocontents); - return FALSE; - } - - elf_section_data (o)->this_hdr.contents = ocontents; - } - } - - val = bfd_get_32 (abfd, ocontents + irelscan->r_offset); - val += isym->st_value; - if (val > addr && val < toaddr) - bfd_put_32 (abfd, val - count, - ocontents + irelscan->r_offset); - } - } - } - - /* Adjust the local symbols defined in this section. */ - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf; isym < isymend; isym++) - { - if (isym->st_shndx == sec_shndx - && isym->st_value > addr - && isym->st_value < toaddr) - isym->st_value -= count; - } - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - { - sym_hash->root.u.def.value -= count; - } - } - - /* See if we can move the ALIGN reloc forward. We have adjusted - r_offset for it already. */ - if (irelalign != NULL) - { - bfd_vma alignto, alignaddr; - - alignto = BFD_ALIGN (toaddr, 1 << irelalign->r_addend); - alignaddr = BFD_ALIGN (irelalign->r_offset, - 1 << irelalign->r_addend); - if (alignto != alignaddr) - { - /* Tail recursion. */ - return sh_elf_relax_delete_bytes (abfd, sec, alignaddr, - (int) (alignto - alignaddr)); - } - } - - return TRUE; -} - -/* Look for loads and stores which we can align to four byte - boundaries. This is like sh_align_loads in coff-sh.c. */ - -static bfd_boolean -sh_elf_align_loads (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, - Elf_Internal_Rela *internal_relocs, - bfd_byte *contents ATTRIBUTE_UNUSED, - bfd_boolean *pswapped) -{ - Elf_Internal_Rela *irel, *irelend; - bfd_vma *labels = NULL; - bfd_vma *label, *label_end; - bfd_size_type amt; - - *pswapped = FALSE; - - irelend = internal_relocs + sec->reloc_count; - - /* Get all the addresses with labels on them. */ - amt = sec->reloc_count; - amt *= sizeof (bfd_vma); - labels = (bfd_vma *) bfd_malloc (amt); - if (labels == NULL) - goto error_return; - label_end = labels; - for (irel = internal_relocs; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_LABEL) - { - *label_end = irel->r_offset; - ++label_end; - } - } - - /* Note that the assembler currently always outputs relocs in - address order. If that ever changes, this code will need to sort - the label values and the relocs. */ - - label = labels; - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma start, stop; - - if (ELF32_R_TYPE (irel->r_info) != (int) R_SH_CODE) - continue; - - start = irel->r_offset; - - for (irel++; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == (int) R_SH_DATA) - break; - if (irel < irelend) - stop = irel->r_offset; - else - stop = sec->size; - - if (! _bfd_sh_align_load_span (abfd, sec, contents, sh_elf_swap_insns, - internal_relocs, &label, - label_end, start, stop, pswapped)) - goto error_return; - } - - free (labels); - - return TRUE; - - error_return: - if (labels != NULL) - free (labels); - return FALSE; -} - -#ifndef SH64_ELF -/* Swap two SH instructions. This is like sh_swap_insns in coff-sh.c. */ - -static bfd_boolean -sh_elf_swap_insns (bfd *abfd, asection *sec, void *relocs, - bfd_byte *contents, bfd_vma addr) -{ - Elf_Internal_Rela *internal_relocs = (Elf_Internal_Rela *) relocs; - unsigned short i1, i2; - Elf_Internal_Rela *irel, *irelend; - - /* Swap the instructions themselves. */ - i1 = bfd_get_16 (abfd, contents + addr); - i2 = bfd_get_16 (abfd, contents + addr + 2); - bfd_put_16 (abfd, (bfd_vma) i2, contents + addr); - bfd_put_16 (abfd, (bfd_vma) i1, contents + addr + 2); - - /* Adjust all reloc addresses. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - enum elf_sh_reloc_type type; - int add; - - /* There are a few special types of relocs that we don't want to - adjust. These relocs do not apply to the instruction itself, - but are only associated with the address. */ - type = (enum elf_sh_reloc_type) ELF32_R_TYPE (irel->r_info); - if (type == R_SH_ALIGN - || type == R_SH_CODE - || type == R_SH_DATA - || type == R_SH_LABEL) - continue; - - /* If an R_SH_USES reloc points to one of the addresses being - swapped, we must adjust it. It would be incorrect to do this - for a jump, though, since we want to execute both - instructions after the jump. (We have avoided swapping - around a label, so the jump will not wind up executing an - instruction it shouldn't). */ - if (type == R_SH_USES) - { - bfd_vma off; - - off = irel->r_offset + 4 + irel->r_addend; - if (off == addr) - irel->r_offset += 2; - else if (off == addr + 2) - irel->r_offset -= 2; - } - - if (irel->r_offset == addr) - { - irel->r_offset += 2; - add = -2; - } - else if (irel->r_offset == addr + 2) - { - irel->r_offset -= 2; - add = 2; - } - else - add = 0; - - if (add != 0) - { - bfd_byte *loc; - unsigned short insn, oinsn; - bfd_boolean overflow; - - loc = contents + irel->r_offset; - overflow = FALSE; - switch (type) - { - default: - break; - - case R_SH_DIR8WPN: - case R_SH_DIR8WPZ: - insn = bfd_get_16 (abfd, loc); - oinsn = insn; - insn += add / 2; - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, loc); - break; - - case R_SH_IND12W: - insn = bfd_get_16 (abfd, loc); - oinsn = insn; - insn += add / 2; - if ((oinsn & 0xf000) != (insn & 0xf000)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, loc); - break; - - case R_SH_DIR8WPL: - /* This reloc ignores the least significant 3 bits of - the program counter before adding in the offset. - This means that if ADDR is at an even address, the - swap will not affect the offset. If ADDR is an at an - odd address, then the instruction will be crossing a - four byte boundary, and must be adjusted. */ - if ((addr & 3) != 0) - { - insn = bfd_get_16 (abfd, loc); - oinsn = insn; - insn += add / 2; - if ((oinsn & 0xff00) != (insn & 0xff00)) - overflow = TRUE; - bfd_put_16 (abfd, (bfd_vma) insn, loc); - } - - break; - } - - if (overflow) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: reloc overflow while relaxing"), - abfd, irel->r_offset); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - } - - return TRUE; -} -#endif /* defined SH64_ELF */ - -/* Describes one of the various PLT styles. */ - -struct elf_sh_plt_info -{ - /* The template for the first PLT entry, or NULL if there is no special - first entry. */ - const bfd_byte *plt0_entry; - - /* The size of PLT0_ENTRY in bytes, or 0 if PLT0_ENTRY is NULL. */ - bfd_vma plt0_entry_size; - - /* Index I is the offset into PLT0_ENTRY of a pointer to - _GLOBAL_OFFSET_TABLE_ + I * 4. The value is MINUS_ONE - if there is no such pointer. */ - bfd_vma plt0_got_fields[3]; - - /* The template for a symbol's PLT entry. */ - const bfd_byte *symbol_entry; - - /* The size of SYMBOL_ENTRY in bytes. */ - bfd_vma symbol_entry_size; - - /* Byte offsets of fields in SYMBOL_ENTRY. Not all fields are used - on all targets. The comments by each member indicate the value - that the field must hold. */ - struct { - bfd_vma got_entry; /* the address of the symbol's .got.plt entry */ - bfd_vma plt; /* .plt (or a branch to .plt on VxWorks) */ - bfd_vma reloc_offset; /* the offset of the symbol's JMP_SLOT reloc */ - bfd_boolean got20; /* TRUE if got_entry points to a movi20 - instruction (instead of a constant pool - entry). */ - } symbol_fields; - - /* The offset of the resolver stub from the start of SYMBOL_ENTRY. */ - bfd_vma symbol_resolve_offset; - - /* A different PLT layout which can be used for the first - MAX_SHORT_PLT entries. It must share the same plt0. NULL in - other cases. */ - const struct elf_sh_plt_info *short_plt; -}; - -#ifdef INCLUDE_SHMEDIA - -/* The size in bytes of an entry in the procedure linkage table. */ - -#define ELF_PLT_ENTRY_SIZE 64 - -/* First entry in an absolute procedure linkage table look like this. */ - -static const bfd_byte elf_sh_plt0_entry_be[ELF_PLT_ENTRY_SIZE] = -{ - 0xcc, 0x00, 0x01, 0x10, /* movi .got.plt >> 16, r17 */ - 0xc8, 0x00, 0x01, 0x10, /* shori .got.plt & 65535, r17 */ - 0x89, 0x10, 0x09, 0x90, /* ld.l r17, 8, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x89, 0x10, 0x05, 0x10, /* ld.l r17, 4, r17 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ -}; - -static const bfd_byte elf_sh_plt0_entry_le[ELF_PLT_ENTRY_SIZE] = -{ - 0x10, 0x01, 0x00, 0xcc, /* movi .got.plt >> 16, r17 */ - 0x10, 0x01, 0x00, 0xc8, /* shori .got.plt & 65535, r17 */ - 0x90, 0x09, 0x10, 0x89, /* ld.l r17, 8, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0x10, 0x05, 0x10, 0x89, /* ld.l r17, 4, r17 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ -}; - -/* Sebsequent entries in an absolute procedure linkage table look like - this. */ - -static const bfd_byte elf_sh_plt_entry_be[ELF_PLT_ENTRY_SIZE] = -{ - 0xcc, 0x00, 0x01, 0x90, /* movi nameN-in-GOT >> 16, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori nameN-in-GOT & 65535, r25 */ - 0x89, 0x90, 0x01, 0x90, /* ld.l r25, 0, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0xcc, 0x00, 0x01, 0x90, /* movi .PLT0 >> 16, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori .PLT0 & 65535, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0xcc, 0x00, 0x01, 0x50, /* movi reloc-offset >> 16, r21 */ - 0xc8, 0x00, 0x01, 0x50, /* shori reloc-offset & 65535, r21 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ -}; - -static const bfd_byte elf_sh_plt_entry_le[ELF_PLT_ENTRY_SIZE] = -{ - 0x90, 0x01, 0x00, 0xcc, /* movi nameN-in-GOT >> 16, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori nameN-in-GOT & 65535, r25 */ - 0x90, 0x01, 0x90, 0x89, /* ld.l r25, 0, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0x90, 0x01, 0x00, 0xcc, /* movi .PLT0 >> 16, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori .PLT0 & 65535, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0x50, 0x01, 0x00, 0xcc, /* movi reloc-offset >> 16, r21 */ - 0x50, 0x01, 0x00, 0xc8, /* shori reloc-offset & 65535, r21 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ -}; - -/* Entries in a PIC procedure linkage table look like this. */ - -static const bfd_byte elf_sh_pic_plt_entry_be[ELF_PLT_ENTRY_SIZE] = -{ - 0xcc, 0x00, 0x01, 0x90, /* movi nameN@GOT >> 16, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori nameN@GOT & 65535, r25 */ - 0x40, 0xc2, 0x65, 0x90, /* ldx.l r12, r25, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0xce, 0x00, 0x01, 0x10, /* movi -GOT_BIAS, r17 */ - 0x00, 0xc8, 0x45, 0x10, /* add.l r12, r17, r17 */ - 0x89, 0x10, 0x09, 0x90, /* ld.l r17, 8, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x89, 0x10, 0x05, 0x10, /* ld.l r17, 4, r17 */ - 0xcc, 0x00, 0x01, 0x50, /* movi reloc-offset >> 16, r21 */ - 0xc8, 0x00, 0x01, 0x50, /* shori reloc-offset & 65535, r21 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ -}; - -static const bfd_byte elf_sh_pic_plt_entry_le[ELF_PLT_ENTRY_SIZE] = -{ - 0x90, 0x01, 0x00, 0xcc, /* movi nameN@GOT >> 16, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori nameN@GOT & 65535, r25 */ - 0x90, 0x65, 0xc2, 0x40, /* ldx.l r12, r25, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0x10, 0x01, 0x00, 0xce, /* movi -GOT_BIAS, r17 */ - 0x10, 0x45, 0xc8, 0x00, /* add.l r12, r17, r17 */ - 0x90, 0x09, 0x10, 0x89, /* ld.l r17, 8, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0x10, 0x05, 0x10, 0x89, /* ld.l r17, 4, r17 */ - 0x50, 0x01, 0x00, 0xcc, /* movi reloc-offset >> 16, r21 */ - 0x50, 0x01, 0x00, 0xc8, /* shori reloc-offset & 65535, r21 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ -}; - -static const struct elf_sh_plt_info elf_sh_plts[2][2] = { - { - { - /* Big-endian non-PIC. */ - elf_sh_plt0_entry_be, - ELF_PLT_ENTRY_SIZE, - { 0, MINUS_ONE, MINUS_ONE }, - elf_sh_plt_entry_be, - ELF_PLT_ENTRY_SIZE, - { 0, 32, 48, FALSE }, - 33, /* includes ISA encoding */ - NULL - }, - { - /* Little-endian non-PIC. */ - elf_sh_plt0_entry_le, - ELF_PLT_ENTRY_SIZE, - { 0, MINUS_ONE, MINUS_ONE }, - elf_sh_plt_entry_le, - ELF_PLT_ENTRY_SIZE, - { 0, 32, 48, FALSE }, - 33, /* includes ISA encoding */ - NULL - }, - }, - { - { - /* Big-endian PIC. */ - elf_sh_plt0_entry_be, - ELF_PLT_ENTRY_SIZE, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - elf_sh_pic_plt_entry_be, - ELF_PLT_ENTRY_SIZE, - { 0, MINUS_ONE, 52, FALSE }, - 33, /* includes ISA encoding */ - NULL - }, - { - /* Little-endian PIC. */ - elf_sh_plt0_entry_le, - ELF_PLT_ENTRY_SIZE, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - elf_sh_pic_plt_entry_le, - ELF_PLT_ENTRY_SIZE, - { 0, MINUS_ONE, 52, FALSE }, - 33, /* includes ISA encoding */ - NULL - }, - } -}; - -/* Return offset of the linker in PLT0 entry. */ -#define elf_sh_plt0_gotplt_offset(info) 0 - -/* Install a 32-bit PLT field starting at ADDR, which occurs in OUTPUT_BFD. - VALUE is the field's value and CODE_P is true if VALUE refers to code, - not data. - - On SH64, each 32-bit field is loaded by a movi/shori pair. */ - -inline static void -install_plt_field (bfd *output_bfd, bfd_boolean code_p, - unsigned long value, bfd_byte *addr) -{ - value |= code_p; - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr) - | ((value >> 6) & 0x3fffc00), - addr); - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr + 4) - | ((value << 10) & 0x3fffc00), - addr + 4); -} - -/* Return the type of PLT associated with ABFD. PIC_P is true if - the object is position-independent. */ - -static const struct elf_sh_plt_info * -get_plt_info (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean pic_p) -{ - return &elf_sh_plts[pic_p][!bfd_big_endian (abfd)]; -} -#else -/* The size in bytes of an entry in the procedure linkage table. */ - -#define ELF_PLT_ENTRY_SIZE 28 - -/* First entry in an absolute procedure linkage table look like this. */ - -/* Note - this code has been "optimised" not to use r2. r2 is used by - GCC to return the address of large structures, so it should not be - corrupted here. This does mean however, that this PLT does not conform - to the SH PIC ABI. That spec says that r0 contains the type of the PLT - and r2 contains the GOT id. This version stores the GOT id in r0 and - ignores the type. Loaders can easily detect this difference however, - since the type will always be 0 or 8, and the GOT ids will always be - greater than or equal to 12. */ -static const bfd_byte elf_sh_plt0_entry_be[ELF_PLT_ENTRY_SIZE] = -{ - 0xd0, 0x05, /* mov.l 2f,r0 */ - 0x60, 0x02, /* mov.l @r0,r0 */ - 0x2f, 0x06, /* mov.l r0,@-r15 */ - 0xd0, 0x03, /* mov.l 1f,r0 */ - 0x60, 0x02, /* mov.l @r0,r0 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x60, 0xf6, /* mov.l @r15+,r0 */ - 0x00, 0x09, /* nop */ - 0x00, 0x09, /* nop */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 1: replaced with address of .got.plt + 8. */ - 0, 0, 0, 0, /* 2: replaced with address of .got.plt + 4. */ -}; - -static const bfd_byte elf_sh_plt0_entry_le[ELF_PLT_ENTRY_SIZE] = -{ - 0x05, 0xd0, /* mov.l 2f,r0 */ - 0x02, 0x60, /* mov.l @r0,r0 */ - 0x06, 0x2f, /* mov.l r0,@-r15 */ - 0x03, 0xd0, /* mov.l 1f,r0 */ - 0x02, 0x60, /* mov.l @r0,r0 */ - 0x2b, 0x40, /* jmp @r0 */ - 0xf6, 0x60, /* mov.l @r15+,r0 */ - 0x09, 0x00, /* nop */ - 0x09, 0x00, /* nop */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 1: replaced with address of .got.plt + 8. */ - 0, 0, 0, 0, /* 2: replaced with address of .got.plt + 4. */ -}; - -/* Sebsequent entries in an absolute procedure linkage table look like - this. */ - -static const bfd_byte elf_sh_plt_entry_be[ELF_PLT_ENTRY_SIZE] = -{ - 0xd0, 0x04, /* mov.l 1f,r0 */ - 0x60, 0x02, /* mov.l @(r0,r12),r0 */ - 0xd1, 0x02, /* mov.l 0f,r1 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x60, 0x13, /* mov r1,r0 */ - 0xd1, 0x03, /* mov.l 2f,r1 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 0: replaced with address of .PLT0. */ - 0, 0, 0, 0, /* 1: replaced with address of this symbol in .got. */ - 0, 0, 0, 0, /* 2: replaced with offset into relocation table. */ -}; - -static const bfd_byte elf_sh_plt_entry_le[ELF_PLT_ENTRY_SIZE] = -{ - 0x04, 0xd0, /* mov.l 1f,r0 */ - 0x02, 0x60, /* mov.l @r0,r0 */ - 0x02, 0xd1, /* mov.l 0f,r1 */ - 0x2b, 0x40, /* jmp @r0 */ - 0x13, 0x60, /* mov r1,r0 */ - 0x03, 0xd1, /* mov.l 2f,r1 */ - 0x2b, 0x40, /* jmp @r0 */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 0: replaced with address of .PLT0. */ - 0, 0, 0, 0, /* 1: replaced with address of this symbol in .got. */ - 0, 0, 0, 0, /* 2: replaced with offset into relocation table. */ -}; - -/* Entries in a PIC procedure linkage table look like this. */ - -static const bfd_byte elf_sh_pic_plt_entry_be[ELF_PLT_ENTRY_SIZE] = -{ - 0xd0, 0x04, /* mov.l 1f,r0 */ - 0x00, 0xce, /* mov.l @(r0,r12),r0 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x00, 0x09, /* nop */ - 0x50, 0xc2, /* mov.l @(8,r12),r0 */ - 0xd1, 0x03, /* mov.l 2f,r1 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x50, 0xc1, /* mov.l @(4,r12),r0 */ - 0x00, 0x09, /* nop */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 1: replaced with address of this symbol in .got. */ - 0, 0, 0, 0 /* 2: replaced with offset into relocation table. */ -}; - -static const bfd_byte elf_sh_pic_plt_entry_le[ELF_PLT_ENTRY_SIZE] = -{ - 0x04, 0xd0, /* mov.l 1f,r0 */ - 0xce, 0x00, /* mov.l @(r0,r12),r0 */ - 0x2b, 0x40, /* jmp @r0 */ - 0x09, 0x00, /* nop */ - 0xc2, 0x50, /* mov.l @(8,r12),r0 */ - 0x03, 0xd1, /* mov.l 2f,r1 */ - 0x2b, 0x40, /* jmp @r0 */ - 0xc1, 0x50, /* mov.l @(4,r12),r0 */ - 0x09, 0x00, /* nop */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 1: replaced with address of this symbol in .got. */ - 0, 0, 0, 0 /* 2: replaced with offset into relocation table. */ -}; - -static const struct elf_sh_plt_info elf_sh_plts[2][2] = { - { - { - /* Big-endian non-PIC. */ - elf_sh_plt0_entry_be, - ELF_PLT_ENTRY_SIZE, - { MINUS_ONE, 24, 20 }, - elf_sh_plt_entry_be, - ELF_PLT_ENTRY_SIZE, - { 20, 16, 24, FALSE }, - 8, - NULL - }, - { - /* Little-endian non-PIC. */ - elf_sh_plt0_entry_le, - ELF_PLT_ENTRY_SIZE, - { MINUS_ONE, 24, 20 }, - elf_sh_plt_entry_le, - ELF_PLT_ENTRY_SIZE, - { 20, 16, 24, FALSE }, - 8, - NULL - }, - }, - { - { - /* Big-endian PIC. */ - elf_sh_plt0_entry_be, - ELF_PLT_ENTRY_SIZE, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - elf_sh_pic_plt_entry_be, - ELF_PLT_ENTRY_SIZE, - { 20, MINUS_ONE, 24, FALSE }, - 8, - NULL - }, - { - /* Little-endian PIC. */ - elf_sh_plt0_entry_le, - ELF_PLT_ENTRY_SIZE, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - elf_sh_pic_plt_entry_le, - ELF_PLT_ENTRY_SIZE, - { 20, MINUS_ONE, 24, FALSE }, - 8, - NULL - }, - } -}; - -#define VXWORKS_PLT_HEADER_SIZE 12 -#define VXWORKS_PLT_ENTRY_SIZE 24 - -static const bfd_byte vxworks_sh_plt0_entry_be[VXWORKS_PLT_HEADER_SIZE] = -{ - 0xd1, 0x01, /* mov.l @(8,pc),r1 */ - 0x61, 0x12, /* mov.l @r1,r1 */ - 0x41, 0x2b, /* jmp @r1 */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0 /* 0: replaced with _GLOBAL_OFFSET_TABLE+8. */ -}; - -static const bfd_byte vxworks_sh_plt0_entry_le[VXWORKS_PLT_HEADER_SIZE] = -{ - 0x01, 0xd1, /* mov.l @(8,pc),r1 */ - 0x12, 0x61, /* mov.l @r1,r1 */ - 0x2b, 0x41, /* jmp @r1 */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0 /* 0: replaced with _GLOBAL_OFFSET_TABLE+8. */ -}; - -static const bfd_byte vxworks_sh_plt_entry_be[VXWORKS_PLT_ENTRY_SIZE] = -{ - 0xd0, 0x01, /* mov.l @(8,pc),r0 */ - 0x60, 0x02, /* mov.l @r0,r0 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 0: replaced with address of this symbol in .got. */ - 0xd0, 0x01, /* mov.l @(8,pc),r0 */ - 0xa0, 0x00, /* bra PLT (We need to fix the offset.) */ - 0x00, 0x09, /* nop */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ -}; - -static const bfd_byte vxworks_sh_plt_entry_le[VXWORKS_PLT_ENTRY_SIZE] = -{ - 0x01, 0xd0, /* mov.l @(8,pc),r0 */ - 0x02, 0x60, /* mov.l @r0,r0 */ - 0x2b, 0x40, /* jmp @r0 */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 0: replaced with address of this symbol in .got. */ - 0x01, 0xd0, /* mov.l @(8,pc),r0 */ - 0x00, 0xa0, /* bra PLT (We need to fix the offset.) */ - 0x09, 0x00, /* nop */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ -}; - -static const bfd_byte vxworks_sh_pic_plt_entry_be[VXWORKS_PLT_ENTRY_SIZE] = -{ - 0xd0, 0x01, /* mov.l @(8,pc),r0 */ - 0x00, 0xce, /* mov.l @(r0,r12),r0 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 0: replaced with offset of this symbol in .got. */ - 0xd0, 0x01, /* mov.l @(8,pc),r0 */ - 0x51, 0xc2, /* mov.l @(8,r12),r1 */ - 0x41, 0x2b, /* jmp @r1 */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ -}; - -static const bfd_byte vxworks_sh_pic_plt_entry_le[VXWORKS_PLT_ENTRY_SIZE] = -{ - 0x01, 0xd0, /* mov.l @(8,pc),r0 */ - 0xce, 0x00, /* mov.l @(r0,r12),r0 */ - 0x2b, 0x40, /* jmp @r0 */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 0: replaced with offset of this symbol in .got. */ - 0x01, 0xd0, /* mov.l @(8,pc),r0 */ - 0xc2, 0x51, /* mov.l @(8,r12),r1 */ - 0x2b, 0x41, /* jmp @r1 */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ -}; - -static const struct elf_sh_plt_info vxworks_sh_plts[2][2] = { - { - { - /* Big-endian non-PIC. */ - vxworks_sh_plt0_entry_be, - VXWORKS_PLT_HEADER_SIZE, - { MINUS_ONE, MINUS_ONE, 8 }, - vxworks_sh_plt_entry_be, - VXWORKS_PLT_ENTRY_SIZE, - { 8, 14, 20, FALSE }, - 12, - NULL - }, - { - /* Little-endian non-PIC. */ - vxworks_sh_plt0_entry_le, - VXWORKS_PLT_HEADER_SIZE, - { MINUS_ONE, MINUS_ONE, 8 }, - vxworks_sh_plt_entry_le, - VXWORKS_PLT_ENTRY_SIZE, - { 8, 14, 20, FALSE }, - 12, - NULL - }, - }, - { - { - /* Big-endian PIC. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - vxworks_sh_pic_plt_entry_be, - VXWORKS_PLT_ENTRY_SIZE, - { 8, MINUS_ONE, 20, FALSE }, - 12, - NULL - }, - { - /* Little-endian PIC. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - vxworks_sh_pic_plt_entry_le, - VXWORKS_PLT_ENTRY_SIZE, - { 8, MINUS_ONE, 20, FALSE }, - 12, - NULL - }, - } -}; - -/* FDPIC PLT entries. Two unimplemented optimizations for lazy - binding are to omit the lazy binding stub when linking with -z now - and to move lazy binding stubs into a separate region for better - cache behavior. */ - -#define FDPIC_PLT_ENTRY_SIZE 28 -#define FDPIC_PLT_LAZY_OFFSET 20 - -/* FIXME: The lazy binding stub requires a plt0 - which may need to be - duplicated if it is out of range, or which can be inlined. So - right now it is always inlined, which wastes a word per stub. It - might be easier to handle the duplication if we put the lazy - stubs separately. */ - -static const bfd_byte fdpic_sh_plt_entry_be[FDPIC_PLT_ENTRY_SIZE] = -{ - 0xd0, 0x02, /* mov.l @(12,pc),r0 */ - 0x01, 0xce, /* mov.l @(r0,r12),r1 */ - 0x70, 0x04, /* add #4, r0 */ - 0x41, 0x2b, /* jmp @r1 */ - 0x0c, 0xce, /* mov.l @(r0,r12),r12 */ - 0x00, 0x09, /* nop */ - 0, 0, 0, 0, /* 0: replaced with offset of this symbol's funcdesc */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ - 0x60, 0xc2, /* mov.l @r12,r0 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x53, 0xc1, /* mov.l @(4,r12),r3 */ - 0x00, 0x09, /* nop */ -}; - -static const bfd_byte fdpic_sh_plt_entry_le[FDPIC_PLT_ENTRY_SIZE] = -{ - 0x02, 0xd0, /* mov.l @(12,pc),r0 */ - 0xce, 0x01, /* mov.l @(r0,r12),r1 */ - 0x04, 0x70, /* add #4, r0 */ - 0x2b, 0x41, /* jmp @r1 */ - 0xce, 0x0c, /* mov.l @(r0,r12),r12 */ - 0x09, 0x00, /* nop */ - 0, 0, 0, 0, /* 0: replaced with offset of this symbol's funcdesc */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ - 0xc2, 0x60, /* mov.l @r12,r0 */ - 0x2b, 0x40, /* jmp @r0 */ - 0xc1, 0x53, /* mov.l @(4,r12),r3 */ - 0x09, 0x00, /* nop */ -}; - -static const struct elf_sh_plt_info fdpic_sh_plts[2] = { - { - /* Big-endian PIC. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - fdpic_sh_plt_entry_be, - FDPIC_PLT_ENTRY_SIZE, - { 12, MINUS_ONE, 16, FALSE }, - FDPIC_PLT_LAZY_OFFSET, - NULL - }, - { - /* Little-endian PIC. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - fdpic_sh_plt_entry_le, - FDPIC_PLT_ENTRY_SIZE, - { 12, MINUS_ONE, 16, FALSE }, - FDPIC_PLT_LAZY_OFFSET, - NULL - }, -}; - -/* On SH2A, we can use the movi20 instruction to generate shorter PLT - entries for the first 64K slots. We use the normal FDPIC PLT entry - past that point; we could also use movi20s, which might be faster, - but would not be any smaller. */ - -#define FDPIC_SH2A_PLT_ENTRY_SIZE 24 -#define FDPIC_SH2A_PLT_LAZY_OFFSET 16 - -static const bfd_byte fdpic_sh2a_plt_entry_be[FDPIC_SH2A_PLT_ENTRY_SIZE] = -{ - 0, 0, 0, 0, /* movi20 #gotofffuncdesc,r0 */ - 0x01, 0xce, /* mov.l @(r0,r12),r1 */ - 0x70, 0x04, /* add #4, r0 */ - 0x41, 0x2b, /* jmp @r1 */ - 0x0c, 0xce, /* mov.l @(r0,r12),r12 */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ - 0x60, 0xc2, /* mov.l @r12,r0 */ - 0x40, 0x2b, /* jmp @r0 */ - 0x53, 0xc1, /* mov.l @(4,r12),r3 */ - 0x00, 0x09, /* nop */ -}; - -static const bfd_byte fdpic_sh2a_plt_entry_le[FDPIC_SH2A_PLT_ENTRY_SIZE] = -{ - 0, 0, 0, 0, /* movi20 #gotofffuncdesc,r0 */ - 0xce, 0x01, /* mov.l @(r0,r12),r1 */ - 0x04, 0x70, /* add #4, r0 */ - 0x2b, 0x41, /* jmp @r1 */ - 0xce, 0x0c, /* mov.l @(r0,r12),r12 */ - 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */ - 0xc2, 0x60, /* mov.l @r12,r0 */ - 0x2b, 0x40, /* jmp @r0 */ - 0xc1, 0x53, /* mov.l @(4,r12),r3 */ - 0x09, 0x00, /* nop */ -}; - -static const struct elf_sh_plt_info fdpic_sh2a_short_plt_be = { - /* Big-endian FDPIC, max index 64K. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - fdpic_sh2a_plt_entry_be, - FDPIC_SH2A_PLT_ENTRY_SIZE, - { 0, MINUS_ONE, 12, TRUE }, - FDPIC_SH2A_PLT_LAZY_OFFSET, - NULL -}; - -static const struct elf_sh_plt_info fdpic_sh2a_short_plt_le = { - /* Little-endian FDPIC, max index 64K. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - fdpic_sh2a_plt_entry_le, - FDPIC_SH2A_PLT_ENTRY_SIZE, - { 0, MINUS_ONE, 12, TRUE }, - FDPIC_SH2A_PLT_LAZY_OFFSET, - NULL -}; - -static const struct elf_sh_plt_info fdpic_sh2a_plts[2] = { - { - /* Big-endian PIC. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - fdpic_sh_plt_entry_be, - FDPIC_PLT_ENTRY_SIZE, - { 12, MINUS_ONE, 16, FALSE }, - FDPIC_PLT_LAZY_OFFSET, - &fdpic_sh2a_short_plt_be - }, - { - /* Little-endian PIC. */ - NULL, - 0, - { MINUS_ONE, MINUS_ONE, MINUS_ONE }, - fdpic_sh_plt_entry_le, - FDPIC_PLT_ENTRY_SIZE, - { 12, MINUS_ONE, 16, FALSE }, - FDPIC_PLT_LAZY_OFFSET, - &fdpic_sh2a_short_plt_le - }, -}; - -/* Return the type of PLT associated with ABFD. PIC_P is true if - the object is position-independent. */ - -static const struct elf_sh_plt_info * -get_plt_info (bfd *abfd, bfd_boolean pic_p) -{ - if (fdpic_object_p (abfd)) - { - /* If any input file requires SH2A we can use a shorter PLT - sequence. */ - if (sh_get_arch_from_bfd_mach (bfd_get_mach (abfd)) & arch_sh2a_base) - return &fdpic_sh2a_plts[!bfd_big_endian (abfd)]; - else - return &fdpic_sh_plts[!bfd_big_endian (abfd)]; - } - if (vxworks_object_p (abfd)) - return &vxworks_sh_plts[pic_p][!bfd_big_endian (abfd)]; - return &elf_sh_plts[pic_p][!bfd_big_endian (abfd)]; -} - -/* Install a 32-bit PLT field starting at ADDR, which occurs in OUTPUT_BFD. - VALUE is the field's value and CODE_P is true if VALUE refers to code, - not data. */ - -inline static void -install_plt_field (bfd *output_bfd, bfd_boolean code_p ATTRIBUTE_UNUSED, - unsigned long value, bfd_byte *addr) -{ - bfd_put_32 (output_bfd, value, addr); -} -#endif - -/* The number of PLT entries which can use a shorter PLT, if any. - Currently always 64K, since only SH-2A FDPIC uses this; a - 20-bit movi20 can address that many function descriptors below - _GLOBAL_OFFSET_TABLE_. */ -#define MAX_SHORT_PLT 65536 - -/* Return the index of the PLT entry at byte offset OFFSET. */ - -static bfd_vma -get_plt_index (const struct elf_sh_plt_info *info, bfd_vma offset) -{ - bfd_vma plt_index = 0; - - offset -= info->plt0_entry_size; - if (info->short_plt != NULL) - { - if (offset > MAX_SHORT_PLT * info->short_plt->symbol_entry_size) - { - plt_index = MAX_SHORT_PLT; - offset -= MAX_SHORT_PLT * info->short_plt->symbol_entry_size; - } - else - info = info->short_plt; - } - return plt_index + offset / info->symbol_entry_size; -} - -/* Do the inverse operation. */ - -static bfd_vma -get_plt_offset (const struct elf_sh_plt_info *info, bfd_vma plt_index) -{ - bfd_vma offset = 0; - - if (info->short_plt != NULL) - { - if (plt_index > MAX_SHORT_PLT) - { - offset = MAX_SHORT_PLT * info->short_plt->symbol_entry_size; - plt_index -= MAX_SHORT_PLT; - } - else - info = info->short_plt; - } - return (offset + info->plt0_entry_size - + (plt_index * info->symbol_entry_size)); -} - -union gotref -{ - bfd_signed_vma refcount; - bfd_vma offset; -}; - -/* sh ELF linker hash entry. */ - -struct elf_sh_link_hash_entry -{ - struct elf_link_hash_entry root; - -#ifdef INCLUDE_SHMEDIA - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } datalabel_got; -#endif - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - bfd_signed_vma gotplt_refcount; - - /* A local function descriptor, for FDPIC. The refcount counts - R_SH_FUNCDESC, R_SH_GOTOFFFUNCDESC, and R_SH_GOTOFFFUNCDESC20 - relocations; the PLT and GOT entry are accounted - for separately. After adjust_dynamic_symbol, the offset is - MINUS_ONE if there is no local descriptor (dynamic linker - managed and no PLT entry, or undefined weak non-dynamic). - During check_relocs we do not yet know whether the local - descriptor will be canonical. */ - union gotref funcdesc; - - /* How many of the above refcounted relocations were R_SH_FUNCDESC, - and thus require fixups or relocations. */ - bfd_signed_vma abs_funcdesc_refcount; - - enum got_type { - GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE, GOT_FUNCDESC - } got_type; -}; - -#define sh_elf_hash_entry(ent) ((struct elf_sh_link_hash_entry *)(ent)) - -struct sh_elf_obj_tdata -{ - struct elf_obj_tdata root; - - /* got_type for each local got entry. */ - char *local_got_type; - - /* Function descriptor refcount and offset for each local symbol. */ - union gotref *local_funcdesc; -}; - -#define sh_elf_tdata(abfd) \ - ((struct sh_elf_obj_tdata *) (abfd)->tdata.any) - -#define sh_elf_local_got_type(abfd) \ - (sh_elf_tdata (abfd)->local_got_type) - -#define sh_elf_local_funcdesc(abfd) \ - (sh_elf_tdata (abfd)->local_funcdesc) - -#define is_sh_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == SH_ELF_DATA) - -/* Override the generic function because we need to store sh_elf_obj_tdata - as the specific tdata. */ - -static bfd_boolean -sh_elf_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct sh_elf_obj_tdata), - SH_ELF_DATA); -} - -/* sh ELF linker hash table. */ - -struct elf_sh_link_hash_table -{ - struct elf_link_hash_table root; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sdynbss; - asection *srelbss; - asection *sfuncdesc; - asection *srelfuncdesc; - asection *srofixup; - - /* The (unloaded but important) VxWorks .rela.plt.unloaded section. */ - asection *srelplt2; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* A counter or offset to track a TLS got entry. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - /* The type of PLT to use. */ - const struct elf_sh_plt_info *plt_info; - - /* True if the target system is VxWorks. */ - bfd_boolean vxworks_p; - - /* True if the target system uses FDPIC. */ - bfd_boolean fdpic_p; -}; - -/* Traverse an sh ELF linker hash table. */ - -#define sh_elf_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* Get the sh ELF linker hash table from a link_info structure. */ - -#define sh_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == SH_ELF_DATA ? ((struct elf_sh_link_hash_table *) ((p)->hash)) : NULL) - -/* Create an entry in an sh ELF linker hash table. */ - -static struct bfd_hash_entry * -sh_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_sh_link_hash_entry *ret = - (struct elf_sh_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct elf_sh_link_hash_entry *) NULL) - ret = ((struct elf_sh_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_sh_link_hash_entry))); - if (ret == (struct elf_sh_link_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_sh_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != (struct elf_sh_link_hash_entry *) NULL) - { - ret->dyn_relocs = NULL; - ret->gotplt_refcount = 0; -#ifdef INCLUDE_SHMEDIA - ret->datalabel_got.refcount = ret->root.got.refcount; -#endif - ret->funcdesc.refcount = 0; - ret->abs_funcdesc_refcount = 0; - ret->got_type = GOT_UNKNOWN; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an sh ELF linker hash table. */ - -static struct bfd_link_hash_table * -sh_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_sh_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_sh_link_hash_table); - - ret = (struct elf_sh_link_hash_table *) bfd_zmalloc (amt); - if (ret == (struct elf_sh_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - sh_elf_link_hash_newfunc, - sizeof (struct elf_sh_link_hash_entry), - SH_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->vxworks_p = vxworks_object_p (abfd); - ret->fdpic_p = fdpic_object_p (abfd); - - return &ret->root.root; -} - -static bfd_boolean -sh_elf_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, asection *p) -{ - struct elf_sh_link_hash_table *htab = sh_elf_hash_table (info); - - /* Non-FDPIC binaries do not need dynamic symbols for sections. */ - if (!htab->fdpic_p) - return TRUE; - - /* We need dynamic symbols for every section, since segments can - relocate independently. */ - 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: - return FALSE; - - /* There shouldn't be section relative relocations - against any other section. */ - default: - return TRUE; - } -} - -/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up - shortcuts to them in our hash table. */ - -static bfd_boolean -create_got_section (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf_sh_link_hash_table *htab; - - if (! _bfd_elf_create_got_section (dynobj, info)) - return FALSE; - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - htab->sfuncdesc = bfd_make_section_anyway_with_flags (dynobj, ".got.funcdesc", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (htab->sfuncdesc == NULL - || ! bfd_set_section_alignment (dynobj, htab->sfuncdesc, 2)) - return FALSE; - - htab->srelfuncdesc = bfd_make_section_anyway_with_flags (dynobj, - ".rela.got.funcdesc", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (htab->srelfuncdesc == NULL - || ! bfd_set_section_alignment (dynobj, htab->srelfuncdesc, 2)) - return FALSE; - - /* Also create .rofixup. */ - htab->srofixup = bfd_make_section_anyway_with_flags (dynobj, ".rofixup", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (htab->srofixup == NULL - || ! bfd_set_section_alignment (dynobj, htab->srofixup, 2)) - return FALSE; - - return TRUE; -} - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -sh_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_sh_link_hash_table *htab; - flagword flags, pltflags; - asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - int ptralign = 0; - - 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; - } - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - if (htab->root.dynamic_sections_created) - return TRUE; - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - pltflags = flags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - htab->root.splt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - - if (bed->want_plt_sym) - { - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh = NULL; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, - (bfd_vma) 0, (const char *) NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - htab->root.hplt = h; - - if (bfd_link_pic (info) - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = bfd_make_section_anyway_with_flags (abfd, - bed->default_use_rela_p - ? ".rela.plt" : ".rel.plt", - flags | SEC_READONLY); - htab->root.srelplt = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (htab->root.sgot == NULL - && !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_anyway_with_flags (abfd, ".dynbss", - SEC_ALLOC | SEC_LINKER_CREATED); - htab->sdynbss = s; - 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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - htab->srelbss = s; - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - if (htab->vxworks_p) - { - if (!elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) - return FALSE; - } - - return TRUE; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = sh_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* 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 -sh_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_sh_link_hash_table *htab; - asection *s; - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (htab->root.dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (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 PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a REL32 - reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - return TRUE; - } - else - h->plt.offset = (bfd_vma) -1; - - /* If this is a weak symbol, and there is a real definition, the - processor independent code will have arranged for us to see the - real definition first, and we can just use the same value. */ - if (h->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - if (info->nocopyreloc) - h->non_got_ref = def->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 (bfd_link_pic (info)) - 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 (0 && info->nocopyreloc) - { - h->non_got_ref = 0; - return TRUE; - } - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (0 && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - s = htab->sdynbss; - BFD_ASSERT (s != NULL); - - /* We must generate a R_SH_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - srel = htab->srelbss; - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct elf_sh_link_hash_table *htab; - struct elf_sh_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - eh = (struct elf_sh_link_hash_entry *) h; - if ((h->got.refcount > 0 - || h->forced_local) - && eh->gotplt_refcount > 0) - { - /* The symbol has been forced local, or we have some direct got refs, - so treat all the gotplt refs as got refs. */ - h->got.refcount += eh->gotplt_refcount; - if (h->plt.refcount >= eh->gotplt_refcount) - h->plt.refcount -= eh->gotplt_refcount; - } - - if (htab->root.dynamic_sections_created - && h->plt.refcount > 0 - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - { - /* 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 (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - asection *s = htab->root.splt; - const struct elf_sh_plt_info *plt_info; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += htab->plt_info->plt0_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. Skip this for FDPIC, since the - function's address will be the address of the canonical - function descriptor. */ - if (!htab->fdpic_p && !bfd_link_pic (info) && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; - } - - /* Make room for this entry. */ - plt_info = htab->plt_info; - if (plt_info->short_plt != NULL - && (get_plt_index (plt_info->short_plt, s->size) < MAX_SHORT_PLT)) - plt_info = plt_info->short_plt; - s->size += plt_info->symbol_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. */ - if (!htab->fdpic_p) - htab->root.sgotplt->size += 4; - else - htab->root.sgotplt->size += 8; - - /* We also need to make an entry in the .rel.plt section. */ - htab->root.srelplt->size += sizeof (Elf32_External_Rela); - - if (htab->vxworks_p && !bfd_link_pic (info)) - { - /* VxWorks executables have a second set of relocations - for each PLT entry. They go in a separate relocation - section, which is processed by the kernel loader. */ - - /* There is a relocation for the initial PLT entry: - an R_SH_DIR32 relocation for _GLOBAL_OFFSET_TABLE_. */ - if (h->plt.offset == htab->plt_info->plt0_entry_size) - htab->srelplt2->size += sizeof (Elf32_External_Rela); - - /* There are two extra relocations for each subsequent - PLT entry: an R_SH_DIR32 relocation for the GOT entry, - and an R_SH_DIR32 relocation for the PLT entry. */ - htab->srelplt2->size += sizeof (Elf32_External_Rela) * 2; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - enum got_type got_type = sh_elf_hash_entry (h)->got_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->root.sgot; - h->got.offset = s->size; - s->size += 4; - /* R_SH_TLS_GD needs 2 consecutive GOT slots. */ - if (got_type == GOT_TLS_GD) - s->size += 4; - dyn = htab->root.dynamic_sections_created; - if (!dyn) - { - /* No dynamic relocations required. */ - if (htab->fdpic_p && !bfd_link_pic (info) - && h->root.type != bfd_link_hash_undefweak - && (got_type == GOT_NORMAL || got_type == GOT_FUNCDESC)) - htab->srofixup->size += 4; - } - /* No dynamic relocations required when IE->LE conversion happens. */ - else if (got_type == GOT_TLS_IE - && !h->def_dynamic - && !bfd_link_pic (info)) - ; - /* R_SH_TLS_IE_32 needs one dynamic relocation if dynamic, - R_SH_TLS_GD needs one if local symbol and two if global. */ - else if ((got_type == GOT_TLS_GD && h->dynindx == -1) - || got_type == GOT_TLS_IE) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - else if (got_type == GOT_TLS_GD) - htab->root.srelgot->size += 2 * sizeof (Elf32_External_Rela); - else if (got_type == GOT_FUNCDESC) - { - if (!bfd_link_pic (info) && SYMBOL_FUNCDESC_LOCAL (info, h)) - htab->srofixup->size += 4; - else - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak) - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - else if (htab->fdpic_p - && !bfd_link_pic (info) - && got_type == GOT_NORMAL - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - htab->srofixup->size += 4; - } - else - h->got.offset = (bfd_vma) -1; - -#ifdef INCLUDE_SHMEDIA - if (eh->datalabel_got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - - /* 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->root.sgot; - eh->datalabel_got.offset = s->size; - s->size += 4; - dyn = htab->root.dynamic_sections_created; - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - eh->datalabel_got.offset = (bfd_vma) -1; -#endif - - /* Allocate space for any dynamic relocations to function - descriptors, canonical or otherwise. We need to relocate the - reference unless it resolves to zero, which only happens for - undefined weak symbols (either non-default visibility, or when - static linking). Any GOT slot is accounted for elsewhere. */ - if (eh->abs_funcdesc_refcount > 0 - && (h->root.type != bfd_link_hash_undefweak - || (htab->root.dynamic_sections_created - && ! SYMBOL_CALLS_LOCAL (info, h)))) - { - if (!bfd_link_pic (info) && SYMBOL_FUNCDESC_LOCAL (info, h)) - htab->srofixup->size += eh->abs_funcdesc_refcount * 4; - else - htab->root.srelgot->size - += eh->abs_funcdesc_refcount * sizeof (Elf32_External_Rela); - } - - /* We must allocate a function descriptor if there are references to - a canonical descriptor (R_SH_GOTFUNCDESC or R_SH_FUNCDESC) and - the dynamic linker isn't going to allocate it. None of this - applies if we already created one in .got.plt, but if the - canonical function descriptor can be in this object, there - won't be a PLT entry at all. */ - if ((eh->funcdesc.refcount > 0 - || (h->got.offset != MINUS_ONE && eh->got_type == GOT_FUNCDESC)) - && h->root.type != bfd_link_hash_undefweak - && SYMBOL_FUNCDESC_LOCAL (info, h)) - { - /* Make room for this function descriptor. */ - eh->funcdesc.offset = htab->sfuncdesc->size; - htab->sfuncdesc->size += 8; - - /* We will need a relocation or two fixups to initialize the - function descriptor, so allocate those too. */ - if (!bfd_link_pic (info) && SYMBOL_CALLS_LOCAL (info, h)) - htab->srofixup->size += 8; - else - htab->srelfuncdesc->size += sizeof (Elf32_External_Rela); - } - - 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 (bfd_link_pic (info)) - { - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_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; - } - } - - if (htab->vxworks_p) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - if (strcmp (p->sec->output_section->name, ".tls_vars") == 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 - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->root.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - sreloc->size += p->count * sizeof (Elf32_External_Rela); - - /* If we need relocations, we do not need fixups. */ - if (htab->fdpic_p && !bfd_link_pic (info)) - htab->srofixup->size -= 4 * (p->count - p->pc_count); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* This function is called after all the input files have been read, - and the input sections have been assigned to output sections. - It's a convenient place to determine the PLT style. */ - -static bfd_boolean -sh_elf_always_size_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - sh_elf_hash_table (info)->plt_info = get_plt_info (output_bfd, - bfd_link_pic (info)); - - if (sh_elf_hash_table (info)->fdpic_p && !bfd_link_relocatable (info) - && !bfd_elf_stack_segment_size (output_bfd, info, - "__stacksize", DEFAULT_STACK_SIZE)) - return FALSE; - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_sh_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (htab->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - union gotref *local_funcdesc, *end_local_funcdesc; - char *local_got_type; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (! is_sh_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_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 (htab->vxworks_p - && strcmp (p->sec->output_section->name, - ".tls_vars") == 0) - { - /* Relocations in vxworks .tls_vars sections are - handled specially by the loader. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - { - info->flags |= DF_TEXTREL; - info->callbacks->minfo (_("%B: dynamic relocation in read-only section `%A'\n"), - p->sec->owner, p->sec); - } - - /* If we need relocations, we do not need fixups. */ - if (htab->fdpic_p && !bfd_link_pic (info)) - htab->srofixup->size -= 4 * (p->count - p->pc_count); - } - } - } - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; -#ifdef INCLUDE_SHMEDIA - /* Count datalabel local GOT. */ - locsymcount *= 2; -#endif - s = htab->root.sgot; - srel = htab->root.srelgot; - - local_got = elf_local_got_refcounts (ibfd); - if (local_got) - { - end_local_got = local_got + locsymcount; - local_got_type = sh_elf_local_got_type (ibfd); - local_funcdesc = sh_elf_local_funcdesc (ibfd); - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += 4; - if (*local_got_type == GOT_TLS_GD) - s->size += 4; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf32_External_Rela); - else - htab->srofixup->size += 4; - - if (*local_got_type == GOT_FUNCDESC) - { - if (local_funcdesc == NULL) - { - bfd_size_type size; - - size = locsymcount * sizeof (union gotref); - local_funcdesc = (union gotref *) bfd_zalloc (ibfd, - size); - if (local_funcdesc == NULL) - return FALSE; - sh_elf_local_funcdesc (ibfd) = local_funcdesc; - local_funcdesc += (local_got - - elf_local_got_refcounts (ibfd)); - } - local_funcdesc->refcount++; - ++local_funcdesc; - } - } - else - *local_got = (bfd_vma) -1; - ++local_got_type; - } - } - - local_funcdesc = sh_elf_local_funcdesc (ibfd); - if (local_funcdesc) - { - end_local_funcdesc = local_funcdesc + locsymcount; - - for (; local_funcdesc < end_local_funcdesc; ++local_funcdesc) - { - if (local_funcdesc->refcount > 0) - { - local_funcdesc->offset = htab->sfuncdesc->size; - htab->sfuncdesc->size += 8; - if (!bfd_link_pic (info)) - htab->srofixup->size += 8; - else - htab->srelfuncdesc->size += sizeof (Elf32_External_Rela); - } - else - local_funcdesc->offset = MINUS_ONE; - } - } - - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate 2 got entries and 1 dynamic reloc for R_SH_TLS_LD_32 - relocs. */ - htab->tls_ldm_got.offset = htab->root.sgot->size; - htab->root.sgot->size += 8; - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - else - htab->tls_ldm_got.offset = -1; - - /* Only the reserved entries should be present. For FDPIC, they go at - the end of .got.plt. */ - if (htab->fdpic_p) - { - BFD_ASSERT (htab->root.sgotplt && htab->root.sgotplt->size == 12); - htab->root.sgotplt->size = 0; - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info); - - /* Move the reserved entries and the _GLOBAL_OFFSET_TABLE_ symbol to the - end of the FDPIC .got.plt. */ - if (htab->fdpic_p) - { - htab->root.hgot->root.u.def.value = htab->root.sgotplt->size; - htab->root.sgotplt->size += 12; - } - - /* At the very end of the .rofixup section is a pointer to the GOT. */ - if (htab->fdpic_p && htab->srofixup != NULL) - htab->srofixup->size += 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) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->root.splt - || s == htab->root.sgot - || s == htab->root.sgotplt - || s == htab->sfuncdesc - || s == htab->srofixup - || s == htab->sdynbss) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 && s != htab->root.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 .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_SH_NONE reloc instead - of garbage. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (htab->root.dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in sh_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (! add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->root.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; - } - else if ((elf_elfheader (output_bfd)->e_flags & EF_SH_FDPIC)) - { - if (! add_dynamic_entry (DT_PLTGOT, 0)) - return FALSE; - } - - if (relocs) - { - if (! add_dynamic_entry (DT_RELA, 0) - || ! add_dynamic_entry (DT_RELASZ, 0) - || ! add_dynamic_entry (DT_RELAENT, - sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (! add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - if (htab->vxworks_p - && !elf_vxworks_add_dynamic_entries (output_bfd, info)) - return FALSE; - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Add a dynamic relocation to the SRELOC section. */ - -inline static bfd_vma -sh_elf_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, - int reloc_type, long dynindx, bfd_vma addend) -{ - Elf_Internal_Rela outrel; - bfd_vma reloc_offset; - - outrel.r_offset = offset; - outrel.r_info = ELF32_R_INFO (dynindx, reloc_type); - outrel.r_addend = addend; - - reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rela); - BFD_ASSERT (reloc_offset < sreloc->size); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, - sreloc->contents + reloc_offset); - sreloc->reloc_count++; - - return reloc_offset; -} - -/* Add an FDPIC read-only fixup. */ - -inline static void -sh_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset) -{ - bfd_vma fixup_offset; - - fixup_offset = srofixup->reloc_count++ * 4; - BFD_ASSERT (fixup_offset < srofixup->size); - bfd_put_32 (output_bfd, offset, srofixup->contents + fixup_offset); -} - -/* Return the offset of the generated .got section from the - _GLOBAL_OFFSET_TABLE_ symbol. */ - -static bfd_signed_vma -sh_elf_got_offset (struct elf_sh_link_hash_table *htab) -{ - return (htab->root.sgot->output_offset - htab->root.sgotplt->output_offset - - htab->root.hgot->root.u.def.value); -} - -/* Find the segment number in which OSEC, and output section, is - located. */ - -static unsigned -sh_elf_osec_to_segment (bfd *output_bfd, asection *osec) -{ - Elf_Internal_Phdr *p = NULL; - - if (output_bfd->xvec->flavour == bfd_target_elf_flavour - /* PR ld/17110: Do not look for output segments in an input bfd. */ - && output_bfd->direction != read_direction) - p = _bfd_elf_find_segment_containing_section (output_bfd, osec); - - /* FIXME: Nothing ever says what this index is relative to. The kernel - supplies data in terms of the number of load segments but this is - a phdr index and the first phdr may not be a load segment. */ - return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1; -} - -static bfd_boolean -sh_elf_osec_readonly_p (bfd *output_bfd, asection *osec) -{ - unsigned seg = sh_elf_osec_to_segment (output_bfd, osec); - - return (seg != (unsigned) -1 - && ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W)); -} - -/* Generate the initial contents of a local function descriptor, along - with any relocations or fixups required. */ -static bfd_boolean -sh_elf_initialize_funcdesc (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - bfd_vma offset, - asection *section, - bfd_vma value) -{ - struct elf_sh_link_hash_table *htab; - int dynindx; - bfd_vma addr, seg; - - htab = sh_elf_hash_table (info); - - /* FIXME: The ABI says that the offset to the function goes in the - descriptor, along with the segment index. We're RELA, so it could - go in the reloc instead... */ - - if (h != NULL && SYMBOL_CALLS_LOCAL (info, h)) - { - section = h->root.u.def.section; - value = h->root.u.def.value; - } - - if (h == NULL || SYMBOL_CALLS_LOCAL (info, h)) - { - dynindx = elf_section_data (section->output_section)->dynindx; - addr = value + section->output_offset; - seg = sh_elf_osec_to_segment (output_bfd, section->output_section); - } - else - { - BFD_ASSERT (h->dynindx != -1); - dynindx = h->dynindx; - addr = seg = 0; - } - - if (!bfd_link_pic (info) && SYMBOL_CALLS_LOCAL (info, h)) - { - if (h == NULL || h->root.type != bfd_link_hash_undefweak) - { - sh_elf_add_rofixup (output_bfd, htab->srofixup, - offset - + htab->sfuncdesc->output_section->vma - + htab->sfuncdesc->output_offset); - sh_elf_add_rofixup (output_bfd, htab->srofixup, - offset + 4 - + htab->sfuncdesc->output_section->vma - + htab->sfuncdesc->output_offset); - } - - /* There are no dynamic relocations so fill in the final - address and gp value (barring fixups). */ - addr += section->output_section->vma; - seg = htab->root.hgot->root.u.def.value - + htab->root.hgot->root.u.def.section->output_section->vma - + htab->root.hgot->root.u.def.section->output_offset; - } - else - sh_elf_add_dyn_reloc (output_bfd, htab->srelfuncdesc, - offset - + htab->sfuncdesc->output_section->vma - + htab->sfuncdesc->output_offset, - R_SH_FUNCDESC_VALUE, dynindx, 0); - - bfd_put_32 (output_bfd, addr, htab->sfuncdesc->contents + offset); - bfd_put_32 (output_bfd, seg, htab->sfuncdesc->contents + offset + 4); - - return TRUE; -} - -/* Install a 20-bit movi20 field starting at ADDR, which occurs in OUTPUT_BFD. - VALUE is the field's value. Return bfd_reloc_ok if successful or an error - otherwise. */ - -static bfd_reloc_status_type -install_movi20_field (bfd *output_bfd, unsigned long relocation, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, bfd_vma offset) -{ - unsigned long cur_val; - bfd_byte *addr; - bfd_reloc_status_type r; - - if (offset > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - r = bfd_check_overflow (complain_overflow_signed, 20, 0, - bfd_arch_bits_per_address (input_bfd), relocation); - if (r != bfd_reloc_ok) - return r; - - addr = contents + offset; - cur_val = bfd_get_16 (output_bfd, addr); - bfd_put_16 (output_bfd, cur_val | ((relocation & 0xf0000) >> 12), addr); - bfd_put_16 (output_bfd, relocation & 0xffff, addr + 2); - - return bfd_reloc_ok; -} - -/* Relocate an SH ELF section. */ - -static bfd_boolean -sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - struct elf_sh_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - bfd_vma *local_got_offsets; - asection *sgot = NULL; - asection *sgotplt = NULL; - asection *splt = NULL; - asection *sreloc = NULL; - asection *srelgot = NULL; - bfd_boolean is_vxworks_tls; - unsigned isec_segment, got_segment, plt_segment, check_segment[2]; - bfd_boolean fdpic_p = FALSE; - - BFD_ASSERT (is_sh_elf (input_bfd)); - - htab = sh_elf_hash_table (info); - if (htab != NULL) - { - sgot = htab->root.sgot; - sgotplt = htab->root.sgotplt; - srelgot = htab->root.srelgot; - splt = htab->root.splt; - fdpic_p = htab->fdpic_p; - } - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - isec_segment = sh_elf_osec_to_segment (output_bfd, - input_section->output_section); - if (fdpic_p && sgot) - got_segment = sh_elf_osec_to_segment (output_bfd, - sgot->output_section); - else - got_segment = -1; - if (fdpic_p && splt) - plt_segment = sh_elf_osec_to_segment (output_bfd, - splt->output_section); - else - plt_segment = -1; - - /* We have to handle relocations in vxworks .tls_vars sections - specially, because the dynamic loader is 'weird'. */ - is_vxworks_tls = (htab && htab->vxworks_p && bfd_link_pic (info) - && !strcmp (input_section->output_section->name, - ".tls_vars")); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_vma addend = (bfd_vma) 0; - bfd_reloc_status_type r; - int seen_stt_datalabel = 0; - bfd_vma off; - enum got_type got_type; - const char *symname = NULL; - bfd_boolean resolved_to_zero; - - r_symndx = ELF32_R_SYM (rel->r_info); - - r_type = ELF32_R_TYPE (rel->r_info); - - /* Many of the relocs are only used for relaxing, and are - handled entirely by the relaxation code. */ - if (r_type >= (int) R_SH_GNU_VTINHERIT - && r_type <= (int) R_SH_LABEL) - continue; - if (r_type == (int) R_SH_NONE) - continue; - - if (r_type < 0 - || r_type >= R_SH_max - || (r_type >= (int) R_SH_FIRST_INVALID_RELOC - && r_type <= (int) R_SH_LAST_INVALID_RELOC) - || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2 - && r_type <= (int) R_SH_LAST_INVALID_RELOC_2) - || ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_3 - && r_type <= (int) R_SH_LAST_INVALID_RELOC_3) - || ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_4 - && r_type <= (int) R_SH_LAST_INVALID_RELOC_4) - || ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_5 - && r_type <= (int) R_SH_LAST_INVALID_RELOC_5) - || ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_6 - && r_type <= (int) R_SH_LAST_INVALID_RELOC_6)) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - howto = get_howto_table (output_bfd) + r_type; - - /* For relocs that aren't partial_inplace, we get the addend from - the relocation. */ - if (! howto->partial_inplace) - addend = rel->r_addend; - - resolved_to_zero = FALSE; - h = NULL; - sym = NULL; - sec = NULL; - check_segment[0] = -1; - check_segment[1] = -1; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - - symname = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - if (symname == NULL || *symname == '\0') - symname = bfd_section_name (input_bfd, sec); - - relocation = (sec->output_section->vma - + sec->output_offset - + sym->st_value); - /* A local symbol never has STO_SH5_ISA32, so we don't need - datalabel processing here. Make sure this does not change - without notice. */ - if ((sym->st_other & STO_SH5_ISA32) != 0) - (*info->callbacks->reloc_dangerous) - (info, - _("Unexpected STO_SH5_ISA32 on local symbol is not handled"), - input_bfd, input_section, rel->r_offset); - - if (sec != NULL && discarded_section (sec)) - /* Handled below. */ - ; - else if (bfd_link_relocatable (info)) - { - /* 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 (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - if (! howto->partial_inplace) - { - /* For relocations with the addend in the - relocation, we need just to update the addend. - All real relocs are of type partial_inplace; this - code is mostly for completeness. */ - rel->r_addend += sec->output_offset; - - continue; - } - - /* Relocs of type partial_inplace need to pick up the - contents in the contents and add the offset resulting - from the changed location of the section symbol. - Using _bfd_final_link_relocate (e.g. goto - final_link_relocate) here would be wrong, because - relocations marked pc_relative would get the current - location subtracted, and we must only do that at the - final link. */ - r = _bfd_relocate_contents (howto, input_bfd, - sec->output_offset - + sym->st_value, - contents + rel->r_offset); - goto relocation_done; - } - - continue; - } - else if (! howto->partial_inplace) - { - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - addend = rel->r_addend; - } - else if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - asection *msec; - - if (howto->rightshift || howto->src_mask != 0xffffffff) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation against SEC_MERGE section"), - input_bfd, input_section, - rel->r_offset, howto->name); - return FALSE; - } - - addend = bfd_get_32 (input_bfd, contents + rel->r_offset); - msec = sec; - addend = - _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - - relocation; - addend += msec->output_section->vma + msec->output_offset; - bfd_put_32 (input_bfd, addend, contents + rel->r_offset); - addend = 0; - } - } - else - { - /* FIXME: Ought to make use of the RELOC_FOR_GLOBAL_SYMBOL macro. */ - - relocation = 0; - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - symname = h->root.root.string; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - { -#ifdef INCLUDE_SHMEDIA - /* If the reference passes a symbol marked with - STT_DATALABEL, then any STO_SH5_ISA32 on the final value - doesn't count. */ - seen_stt_datalabel |= h->type == STT_DATALABEL; -#endif - 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) - { - bfd_boolean dyn; - - dyn = htab ? htab->root.dynamic_sections_created : FALSE; - sec = h->root.u.def.section; - /* In these cases, we don't need the relocation value. - We check specially because in some obscure cases - sec->output_section will be NULL. */ - if (r_type == R_SH_GOTPC - || r_type == R_SH_GOTPC_LOW16 - || r_type == R_SH_GOTPC_MEDLOW16 - || r_type == R_SH_GOTPC_MEDHI16 - || r_type == R_SH_GOTPC_HI16 - || ((r_type == R_SH_PLT32 - || r_type == R_SH_PLT_LOW16 - || r_type == R_SH_PLT_MEDLOW16 - || r_type == R_SH_PLT_MEDHI16 - || r_type == R_SH_PLT_HI16) - && h->plt.offset != (bfd_vma) -1) - || ((r_type == R_SH_GOT32 - || r_type == R_SH_GOT20 - || r_type == R_SH_GOTFUNCDESC - || r_type == R_SH_GOTFUNCDESC20 - || r_type == R_SH_GOTOFFFUNCDESC - || r_type == R_SH_GOTOFFFUNCDESC20 - || r_type == R_SH_FUNCDESC - || r_type == R_SH_GOT_LOW16 - || r_type == R_SH_GOT_MEDLOW16 - || r_type == R_SH_GOT_MEDHI16 - || r_type == R_SH_GOT_HI16) - && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (! bfd_link_pic (info) - || (! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - /* The cases above are those in which relocation is - overwritten in the switch block below. The cases - below are those in which we must defer relocation - to run-time, because we can't resolve absolute - addresses when creating a shared library. */ - || (bfd_link_pic (info) - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular) - && ((r_type == R_SH_DIR32 - && !h->forced_local) - || (r_type == R_SH_REL32 - && !SYMBOL_CALLS_LOCAL (info, h))) - && ((input_section->flags & SEC_ALLOC) != 0 - /* DWARF will emit R_SH_DIR32 relocations in its - sections against symbols defined externally - in shared libraries. We can't do anything - with them here. */ - || ((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic))) - /* Dynamic relocs are not propagated for SEC_DEBUGGING - sections because such sections are not SEC_ALLOC and - thus ld.so will not process them. */ - || (sec->output_section == NULL - && ((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic)) - || (sec->output_section == NULL - && (sh_elf_hash_entry (h)->got_type == GOT_TLS_IE - || sh_elf_hash_entry (h)->got_type == GOT_TLS_GD))) - ; - else if (sec->output_section != NULL) - relocation = ((h->root.u.def.value - + sec->output_section->vma - + sec->output_offset) - /* A STO_SH5_ISA32 causes a "bitor 1" to the - symbol value, unless we've seen - STT_DATALABEL on the way to it. */ - | ((h->other & STO_SH5_ISA32) != 0 - && ! seen_stt_datalabel)); - else if (!bfd_link_relocatable (info) - && (_bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset) - != (bfd_vma) -1)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - return FALSE; - } - } - else if (h->root.type == bfd_link_hash_undefweak) - resolved_to_zero = UNDEFWEAK_NO_DYNAMIC_RELOC (info, h); - else if (info->unresolved_syms_in_objects == RM_IGNORE - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - ; - else if (!bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, rel->r_offset, - (info->unresolved_syms_in_objects == RM_GENERATE_ERROR - || ELF_ST_VISIBILITY (h->other))); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - /* Check for inter-segment relocations in FDPIC files. Most - relocations connect the relocation site to the location of - the target symbol, but there are some exceptions below. */ - check_segment[0] = isec_segment; - if (sec != NULL) - check_segment[1] = sh_elf_osec_to_segment (output_bfd, - sec->output_section); - else - check_segment[1] = -1; - - switch ((int) r_type) - { - final_link_relocate: - /* COFF relocs don't use the addend. The addend is used for - R_SH_DIR32 to be compatible with other compilers. */ - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, addend); - break; - - case R_SH_IND12W: - goto final_link_relocate; - - case R_SH_DIR8WPN: - case R_SH_DIR8WPZ: - case R_SH_DIR8WPL: - /* If the reloc is against the start of this section, then - the assembler has already taken care of it and the reloc - is here only to assist in relaxing. If the reloc is not - against the start of this section, then it's against an - external symbol and we must deal with it ourselves. */ - if (input_section->output_section->vma + input_section->output_offset - != relocation) - { - int disp = (relocation - - input_section->output_section->vma - - input_section->output_offset - - rel->r_offset); - int mask = 0; - switch (r_type) - { - case R_SH_DIR8WPN: - case R_SH_DIR8WPZ: mask = 1; break; - case R_SH_DIR8WPL: mask = 3; break; - default: mask = 0; break; - } - if (disp & mask) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: unaligned branch target for relax-support relocation"), - input_section->owner, - rel->r_offset); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - relocation -= 4; - goto final_link_relocate; - } - r = bfd_reloc_ok; - break; - - default: -#ifdef INCLUDE_SHMEDIA - if (shmedia_prepare_reloc (info, input_bfd, input_section, - contents, rel, &relocation)) - goto final_link_relocate; -#endif - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case R_SH_DIR16: - case R_SH_DIR8: - case R_SH_DIR8U: - case R_SH_DIR8S: - case R_SH_DIR4U: - goto final_link_relocate; - - case R_SH_DIR8UL: - case R_SH_DIR4UL: - if (relocation & 3) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: unaligned %s relocation %#Lx"), - input_section->owner, - rel->r_offset, howto->name, - relocation); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - goto final_link_relocate; - - case R_SH_DIR8UW: - case R_SH_DIR8SW: - case R_SH_DIR4UW: - if (relocation & 1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: unaligned %s relocation %#Lx"), - input_section->owner, - rel->r_offset, howto->name, - relocation); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - goto final_link_relocate; - - case R_SH_PSHA: - if ((signed int)relocation < -32 - || (signed int)relocation > 32) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: R_SH_PSHA relocation %Ld not in range -32..32"), - input_section->owner, - rel->r_offset, - relocation); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - goto final_link_relocate; - - case R_SH_PSHL: - if ((signed int)relocation < -16 - || (signed int)relocation > 16) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: fatal: R_SH_PSHL relocation %Ld not in range -32..32"), - input_section->owner, - rel->r_offset, - relocation); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - goto final_link_relocate; - - case R_SH_DIR32: - case R_SH_REL32: -#ifdef INCLUDE_SHMEDIA - case R_SH_IMM_LOW16_PCREL: - case R_SH_IMM_MEDLOW16_PCREL: - case R_SH_IMM_MEDHI16_PCREL: - case R_SH_IMM_HI16_PCREL: -#endif - if (bfd_link_pic (info) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0 - && !is_vxworks_tls - && (r_type == R_SH_DIR32 - || !SYMBOL_CALLS_LOCAL (info, h))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip, relocate; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - skip = FALSE; - relocate = FALSE; - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if (r_type == R_SH_REL32) - { - BFD_ASSERT (h != NULL && h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, R_SH_REL32); - outrel.r_addend - = (howto->partial_inplace - ? bfd_get_32 (input_bfd, contents + rel->r_offset) - : addend); - } -#ifdef INCLUDE_SHMEDIA - else if (r_type == R_SH_IMM_LOW16_PCREL - || r_type == R_SH_IMM_MEDLOW16_PCREL - || r_type == R_SH_IMM_MEDHI16_PCREL - || r_type == R_SH_IMM_HI16_PCREL) - { - BFD_ASSERT (h != NULL && h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = addend; - } -#endif - else if (fdpic_p - && (h == NULL - || ((info->symbolic || h->dynindx == -1) - && h->def_regular))) - { - int dynindx; - - BFD_ASSERT (sec != NULL); - BFD_ASSERT (sec->output_section != NULL); - dynindx = elf_section_data (sec->output_section)->dynindx; - outrel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32); - outrel.r_addend = relocation; - outrel.r_addend - += (howto->partial_inplace - ? bfd_get_32 (input_bfd, contents + rel->r_offset) - : addend); - outrel.r_addend -= sec->output_section->vma; - } - else - { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (h == NULL - || ((info->symbolic || h->dynindx == -1) - && h->def_regular)) - { - relocate = howto->partial_inplace; - outrel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE); - } - else - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, R_SH_DIR32); - } - outrel.r_addend = relocation; - outrel.r_addend - += (howto->partial_inplace - ? bfd_get_32 (input_bfd, contents + rel->r_offset) - : addend); - } - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - check_segment[0] = check_segment[1] = -1; - - /* 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; - } - else if (fdpic_p && !bfd_link_pic (info) - && r_type == R_SH_DIR32 - && (input_section->flags & SEC_ALLOC) != 0) - { - bfd_vma offset; - - BFD_ASSERT (htab); - - if (sh_elf_osec_readonly_p (output_bfd, - input_section->output_section)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): cannot emit fixup to `%s' in read-only section"), - input_bfd, - input_section, - rel->r_offset, - symname); - return FALSE; - } - - offset = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - if (offset != (bfd_vma)-1) - sh_elf_add_rofixup (output_bfd, htab->srofixup, - input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - check_segment[0] = check_segment[1] = -1; - } - /* We don't want warnings for non-NULL tests on undefined weak - symbols. */ - else if (r_type == R_SH_REL32 - && h - && h->root.type == bfd_link_hash_undefweak) - check_segment[0] = check_segment[1] = -1; - goto final_link_relocate; - - case R_SH_GOTPLT32: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOTPLT_LOW16: - case R_SH_GOTPLT_MEDLOW16: - case R_SH_GOTPLT_MEDHI16: - case R_SH_GOTPLT_HI16: - case R_SH_GOTPLT10BY4: - case R_SH_GOTPLT10BY8: -#endif - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - if (h == NULL - || h->forced_local - || ! bfd_link_pic (info) - || info->symbolic - || h->dynindx == -1 - || h->plt.offset == (bfd_vma) -1 - || h->got.offset != (bfd_vma) -1) - goto force_got; - - /* Relocation is to the entry for this symbol in the global - offset table extension for the procedure linkage table. */ - - BFD_ASSERT (htab); - BFD_ASSERT (sgotplt != NULL); - relocation = (sgotplt->output_offset - + (get_plt_index (htab->plt_info, h->plt.offset) - + 3) * 4); - -#ifdef GOT_BIAS - relocation -= GOT_BIAS; -#endif - - goto final_link_relocate; - - force_got: - case R_SH_GOT32: - case R_SH_GOT20: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOT_LOW16: - case R_SH_GOT_MEDLOW16: - case R_SH_GOT_MEDHI16: - case R_SH_GOT_HI16: - case R_SH_GOT10BY4: - case R_SH_GOT10BY8: -#endif - /* Relocation is to the entry for this symbol in the global - offset table. */ - - BFD_ASSERT (htab); - BFD_ASSERT (sgot != NULL); - check_segment[0] = check_segment[1] = -1; - - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; -#ifdef INCLUDE_SHMEDIA - if (seen_stt_datalabel) - { - struct elf_sh_link_hash_entry *hsh; - - hsh = (struct elf_sh_link_hash_entry *)h; - off = hsh->datalabel_got.offset; - } -#endif - BFD_ASSERT (off != (bfd_vma) -1); - - dyn = htab->root.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - || ((ELF_ST_VISIBILITY (h->other) - || resolved_to_zero) - && 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 .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - sgot->contents + off); -#ifdef INCLUDE_SHMEDIA - if (seen_stt_datalabel) - { - struct elf_sh_link_hash_entry *hsh; - - hsh = (struct elf_sh_link_hash_entry *)h; - hsh->datalabel_got.offset |= 1; - } - else -#endif - h->got.offset |= 1; - - /* If we initialize the GOT entry here with a valid - symbol address, also add a fixup. */ - if (fdpic_p && !bfd_link_pic (info) - && sh_elf_hash_entry (h)->got_type == GOT_NORMAL - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - sh_elf_add_rofixup (output_bfd, htab->srofixup, - sgot->output_section->vma - + sgot->output_offset - + off); - } - } - - relocation = sh_elf_got_offset (htab) + off; - } - else - { -#ifdef INCLUDE_SHMEDIA - if (rel->r_addend) - { - BFD_ASSERT (local_got_offsets != NULL - && (local_got_offsets[symtab_hdr->sh_info - + r_symndx] - != (bfd_vma) -1)); - - off = local_got_offsets[symtab_hdr->sh_info - + r_symndx]; - } - else - { -#endif - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; -#ifdef INCLUDE_SHMEDIA - } -#endif - - /* 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, sgot->contents + off); - - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - if (fdpic_p) - { - int dynindx - = elf_section_data (sec->output_section)->dynindx; - outrel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32); - outrel.r_addend = relocation; - outrel.r_addend -= sec->output_section->vma; - } - else - { - outrel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE); - outrel.r_addend = relocation; - } - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - else if (fdpic_p - && (sh_elf_local_got_type (input_bfd) [r_symndx] - == GOT_NORMAL)) - sh_elf_add_rofixup (output_bfd, htab->srofixup, - sgot->output_section->vma - + sgot->output_offset - + off); - -#ifdef INCLUDE_SHMEDIA - if (rel->r_addend) - local_got_offsets[symtab_hdr->sh_info + r_symndx] |= 1; - else -#endif - local_got_offsets[r_symndx] |= 1; - } - - relocation = sh_elf_got_offset (htab) + off; - } - -#ifdef GOT_BIAS - relocation -= GOT_BIAS; -#endif - - if (r_type == R_SH_GOT20) - { - r = install_movi20_field (output_bfd, relocation + addend, - input_bfd, input_section, contents, - rel->r_offset); - break; - } - else - goto final_link_relocate; - - case R_SH_GOTOFF: - case R_SH_GOTOFF20: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOTOFF_LOW16: - case R_SH_GOTOFF_MEDLOW16: - case R_SH_GOTOFF_MEDHI16: - case R_SH_GOTOFF_HI16: -#endif - /* GOTOFF relocations are relative to _GLOBAL_OFFSET_TABLE_, which - we place at the start of the .got.plt section. This is the same - as the start of the output .got section, unless there are function - descriptors in front of it. */ - BFD_ASSERT (htab); - BFD_ASSERT (sgotplt != NULL); - check_segment[0] = got_segment; - relocation -= sgotplt->output_section->vma + sgotplt->output_offset - + htab->root.hgot->root.u.def.value; - -#ifdef GOT_BIAS - relocation -= GOT_BIAS; -#endif - - addend = rel->r_addend; - - if (r_type == R_SH_GOTOFF20) - { - r = install_movi20_field (output_bfd, relocation + addend, - input_bfd, input_section, contents, - rel->r_offset); - break; - } - else - goto final_link_relocate; - - case R_SH_GOTPC: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOTPC_LOW16: - case R_SH_GOTPC_MEDLOW16: - case R_SH_GOTPC_MEDHI16: - case R_SH_GOTPC_HI16: -#endif - /* Use global offset table as symbol value. */ - - BFD_ASSERT (sgotplt != NULL); - relocation = sgotplt->output_section->vma + sgotplt->output_offset; - -#ifdef GOT_BIAS - relocation += GOT_BIAS; -#endif - - addend = rel->r_addend; - - goto final_link_relocate; - - case R_SH_PLT32: -#ifdef INCLUDE_SHMEDIA - case R_SH_PLT_LOW16: - case R_SH_PLT_MEDLOW16: - case R_SH_PLT_MEDHI16: - case R_SH_PLT_HI16: -#endif - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* Resolve a PLT reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL) - goto final_link_relocate; - - /* We don't want to warn on calls to undefined weak symbols, - as calls to them must be protected by non-NULL tests - anyway, and unprotected calls would invoke undefined - behavior. */ - if (h->root.type == bfd_link_hash_undefweak) - check_segment[0] = check_segment[1] = -1; - - if (h->forced_local) - goto final_link_relocate; - - if (h->plt.offset == (bfd_vma) -1) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - goto final_link_relocate; - } - - BFD_ASSERT (splt != NULL); - check_segment[1] = plt_segment; - relocation = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - -#ifdef INCLUDE_SHMEDIA - relocation++; -#endif - - addend = rel->r_addend; - - goto final_link_relocate; - - /* Relocation is to the canonical function descriptor for this - symbol, possibly via the GOT. Initialize the GOT - entry and function descriptor if necessary. */ - case R_SH_GOTFUNCDESC: - case R_SH_GOTFUNCDESC20: - case R_SH_FUNCDESC: - { - int dynindx = -1; - asection *reloc_section; - bfd_vma reloc_offset; - int reloc_type = R_SH_FUNCDESC; - - BFD_ASSERT (htab); - - check_segment[0] = check_segment[1] = -1; - - /* FIXME: See what FRV does for global symbols in the - executable, with --export-dynamic. Do they need ld.so - to allocate official descriptors? See what this code - does. */ - - relocation = 0; - addend = 0; - - if (r_type == R_SH_FUNCDESC) - { - reloc_section = input_section; - reloc_offset = rel->r_offset; - } - else - { - reloc_section = sgot; - - if (h != NULL) - reloc_offset = h->got.offset; - else - { - BFD_ASSERT (local_got_offsets != NULL); - reloc_offset = local_got_offsets[r_symndx]; - } - BFD_ASSERT (reloc_offset != MINUS_ONE); - - if (reloc_offset & 1) - { - reloc_offset &= ~1; - goto funcdesc_done_got; - } - } - - if (h && h->root.type == bfd_link_hash_undefweak - && (SYMBOL_CALLS_LOCAL (info, h) - || !htab->root.dynamic_sections_created)) - /* Undefined weak symbol which will not be dynamically - resolved later; leave it at zero. */ - goto funcdesc_leave_zero; - else if (SYMBOL_CALLS_LOCAL (info, h) - && ! SYMBOL_FUNCDESC_LOCAL (info, h)) - { - /* If the symbol needs a non-local function descriptor - but binds locally (i.e., its visibility is - protected), emit a dynamic relocation decayed to - section+offset. This is an optimization; the dynamic - linker would resolve our function descriptor request - to our copy of the function anyway. */ - dynindx = elf_section_data (h->root.u.def.section - ->output_section)->dynindx; - relocation += h->root.u.def.section->output_offset - + h->root.u.def.value; - } - else if (! SYMBOL_FUNCDESC_LOCAL (info, h)) - { - /* If the symbol is dynamic and there will be dynamic - symbol resolution because we are or are linked with a - shared library, emit a FUNCDESC relocation such that - the dynamic linker will allocate the function - descriptor. */ - BFD_ASSERT (h->dynindx != -1); - dynindx = h->dynindx; - } - else - { - bfd_vma offset; - - /* Otherwise, we know we have a private function - descriptor, so reference it directly. */ - reloc_type = R_SH_DIR32; - dynindx = elf_section_data (htab->sfuncdesc - ->output_section)->dynindx; - - if (h) - { - offset = sh_elf_hash_entry (h)->funcdesc.offset; - BFD_ASSERT (offset != MINUS_ONE); - if ((offset & 1) == 0) - { - if (!sh_elf_initialize_funcdesc (output_bfd, info, h, - offset, NULL, 0)) - return FALSE; - sh_elf_hash_entry (h)->funcdesc.offset |= 1; - } - } - else - { - union gotref *local_funcdesc; - - local_funcdesc = sh_elf_local_funcdesc (input_bfd); - offset = local_funcdesc[r_symndx].offset; - BFD_ASSERT (offset != MINUS_ONE); - if ((offset & 1) == 0) - { - if (!sh_elf_initialize_funcdesc (output_bfd, info, NULL, - offset, sec, - sym->st_value)) - return FALSE; - local_funcdesc[r_symndx].offset |= 1; - } - } - - relocation = htab->sfuncdesc->output_offset + (offset & ~1); - } - - if (!bfd_link_pic (info) && SYMBOL_FUNCDESC_LOCAL (info, h)) - { - bfd_vma offset; - - if (sh_elf_osec_readonly_p (output_bfd, - reloc_section->output_section)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): cannot emit fixup to `%s' in read-only section"), - input_bfd, - input_section, - rel->r_offset, - symname); - return FALSE; - } - - offset = _bfd_elf_section_offset (output_bfd, info, - reloc_section, reloc_offset); - - if (offset != (bfd_vma)-1) - sh_elf_add_rofixup (output_bfd, htab->srofixup, - offset - + reloc_section->output_section->vma - + reloc_section->output_offset); - } - else if ((reloc_section->output_section->flags - & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma offset; - - if (sh_elf_osec_readonly_p (output_bfd, - reloc_section->output_section)) - { - info->callbacks->warning - (info, - _("cannot emit dynamic relocations in read-only section"), - symname, input_bfd, reloc_section, reloc_offset); - return FALSE; - } - - offset = _bfd_elf_section_offset (output_bfd, info, - reloc_section, reloc_offset); - - if (offset != (bfd_vma)-1) - sh_elf_add_dyn_reloc (output_bfd, srelgot, - offset - + reloc_section->output_section->vma - + reloc_section->output_offset, - reloc_type, dynindx, relocation); - - if (r_type == R_SH_FUNCDESC) - { - r = bfd_reloc_ok; - break; - } - else - { - relocation = 0; - goto funcdesc_leave_zero; - } - } - - if (SYMBOL_FUNCDESC_LOCAL (info, h)) - relocation += htab->sfuncdesc->output_section->vma; - funcdesc_leave_zero: - if (r_type != R_SH_FUNCDESC) - { - bfd_put_32 (output_bfd, relocation, - reloc_section->contents + reloc_offset); - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - - funcdesc_done_got: - - relocation = sh_elf_got_offset (htab) + reloc_offset; -#ifdef GOT_BIAS - relocation -= GOT_BIAS; -#endif - } - if (r_type == R_SH_GOTFUNCDESC20) - { - r = install_movi20_field (output_bfd, relocation + addend, - input_bfd, input_section, contents, - rel->r_offset); - break; - } - else - goto final_link_relocate; - } - break; - - case R_SH_GOTOFFFUNCDESC: - case R_SH_GOTOFFFUNCDESC20: - /* FIXME: See R_SH_FUNCDESC comment about global symbols in the - executable and --export-dynamic. If such symbols get - ld.so-allocated descriptors we can not use R_SH_GOTOFFFUNCDESC - for them. */ - BFD_ASSERT (htab); - - check_segment[0] = check_segment[1] = -1; - relocation = 0; - addend = rel->r_addend; - - if (h && (h->root.type == bfd_link_hash_undefweak - || !SYMBOL_FUNCDESC_LOCAL (info, h))) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation against external symbol \"%s\""), - input_bfd, input_section, rel->r_offset, howto->name, - h->root.root.string); - return FALSE; - } - else - { - bfd_vma offset; - - /* Otherwise, we know we have a private function - descriptor, so reference it directly. */ - if (h) - { - offset = sh_elf_hash_entry (h)->funcdesc.offset; - BFD_ASSERT (offset != MINUS_ONE); - if ((offset & 1) == 0) - { - if (!sh_elf_initialize_funcdesc (output_bfd, info, h, - offset, NULL, 0)) - return FALSE; - sh_elf_hash_entry (h)->funcdesc.offset |= 1; - } - } - else - { - union gotref *local_funcdesc; - - local_funcdesc = sh_elf_local_funcdesc (input_bfd); - offset = local_funcdesc[r_symndx].offset; - BFD_ASSERT (offset != MINUS_ONE); - if ((offset & 1) == 0) - { - if (!sh_elf_initialize_funcdesc (output_bfd, info, NULL, - offset, sec, - sym->st_value)) - return FALSE; - local_funcdesc[r_symndx].offset |= 1; - } - } - - relocation = htab->sfuncdesc->output_offset + (offset & ~1); - } - - relocation -= (htab->root.hgot->root.u.def.value - + sgotplt->output_offset); -#ifdef GOT_BIAS - relocation -= GOT_BIAS; -#endif - - if (r_type == R_SH_GOTOFFFUNCDESC20) - { - r = install_movi20_field (output_bfd, relocation + addend, - input_bfd, input_section, contents, - rel->r_offset); - break; - } - else - goto final_link_relocate; - - case R_SH_LOOP_START: - { - static bfd_vma start, end; - - start = (relocation + rel->r_addend - - (sec->output_section->vma + sec->output_offset)); - r = sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, - rel->r_offset, sec, start, end); - break; - - case R_SH_LOOP_END: - end = (relocation + rel->r_addend - - (sec->output_section->vma + sec->output_offset)); - r = sh_elf_reloc_loop (r_type, input_bfd, input_section, contents, - rel->r_offset, sec, start, end); - break; - } - - case R_SH_TLS_GD_32: - case R_SH_TLS_IE_32: - BFD_ASSERT (htab); - check_segment[0] = check_segment[1] = -1; - r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL); - got_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - got_type = sh_elf_local_got_type (input_bfd) [r_symndx]; - else if (h != NULL) - { - got_type = sh_elf_hash_entry (h)->got_type; - if (! bfd_link_pic (info) - && (h->dynindx == -1 - || h->def_regular)) - r_type = R_SH_TLS_LE_32; - } - - if (r_type == R_SH_TLS_GD_32 && got_type == GOT_TLS_IE) - r_type = R_SH_TLS_IE_32; - - if (r_type == R_SH_TLS_LE_32) - { - bfd_vma offset; - unsigned short insn; - - if (ELF32_R_TYPE (rel->r_info) == R_SH_TLS_GD_32) - { - /* GD->LE transition: - mov.l 1f,r4; mova 2f,r0; mov.l 2f,r1; add r0,r1; - jsr @r1; add r12,r4; bra 3f; nop; .align 2; - 1: .long x$TLSGD; 2: .long __tls_get_addr@PLT; 3: - We change it into: - mov.l 1f,r4; stc gbr,r0; add r4,r0; nop; - nop; nop; ... - 1: .long x@TPOFF; 2: .long __tls_get_addr@PLT; 3:. */ - - offset = rel->r_offset; - BFD_ASSERT (offset >= 16); - /* Size of GD instructions is 16 or 18. */ - offset -= 16; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - if ((insn & 0xff00) == 0xc700) - { - BFD_ASSERT (offset >= 2); - offset -= 2; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - } - - BFD_ASSERT ((insn & 0xff00) == 0xd400); - insn = bfd_get_16 (input_bfd, contents + offset + 2); - BFD_ASSERT ((insn & 0xff00) == 0xc700); - insn = bfd_get_16 (input_bfd, contents + offset + 4); - BFD_ASSERT ((insn & 0xff00) == 0xd100); - insn = bfd_get_16 (input_bfd, contents + offset + 6); - BFD_ASSERT (insn == 0x310c); - insn = bfd_get_16 (input_bfd, contents + offset + 8); - BFD_ASSERT (insn == 0x410b); - insn = bfd_get_16 (input_bfd, contents + offset + 10); - BFD_ASSERT (insn == 0x34cc); - - bfd_put_16 (output_bfd, 0x0012, contents + offset + 2); - bfd_put_16 (output_bfd, 0x304c, contents + offset + 4); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 6); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 8); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 10); - } - else - { - int target; - - /* IE->LE transition: - mov.l 1f,r0; stc gbr,rN; mov.l @(r0,r12),rM; - bra 2f; add ...; .align 2; 1: x@GOTTPOFF; 2: - We change it into: - mov.l .Ln,rM; stc gbr,rN; nop; ...; - 1: x@TPOFF; 2:. */ - - offset = rel->r_offset; - BFD_ASSERT (offset >= 16); - /* Size of IE instructions is 10 or 12. */ - offset -= 10; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - if ((insn & 0xf0ff) == 0x0012) - { - BFD_ASSERT (offset >= 2); - offset -= 2; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - } - - BFD_ASSERT ((insn & 0xff00) == 0xd000); - target = insn & 0x00ff; - insn = bfd_get_16 (input_bfd, contents + offset + 2); - BFD_ASSERT ((insn & 0xf0ff) == 0x0012); - insn = bfd_get_16 (input_bfd, contents + offset + 4); - BFD_ASSERT ((insn & 0xf0ff) == 0x00ce); - insn = 0xd000 | (insn & 0x0f00) | target; - bfd_put_16 (output_bfd, insn, contents + offset + 0); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 4); - } - - bfd_put_32 (output_bfd, tpoff (info, relocation), - contents + rel->r_offset); - continue; - } - - if (sgot == NULL || sgotplt == NULL) - abort (); - - if (h != NULL) - off = h->got.offset; - else - { - if (local_got_offsets == NULL) - abort (); - - off = local_got_offsets[r_symndx]; - } - - /* Relocate R_SH_TLS_IE_32 directly when statically linking. */ - if (r_type == R_SH_TLS_IE_32 - && ! htab->root.dynamic_sections_created) - { - off &= ~1; - bfd_put_32 (output_bfd, tpoff (info, relocation), - sgot->contents + off); - bfd_put_32 (output_bfd, sh_elf_got_offset (htab) + off, - contents + rel->r_offset); - continue; - } - - if ((off & 1) != 0) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - int dr_type, indx; - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset + off); - - if (h == NULL || h->dynindx == -1) - indx = 0; - else - indx = h->dynindx; - - dr_type = (r_type == R_SH_TLS_GD_32 ? R_SH_TLS_DTPMOD32 : - R_SH_TLS_TPOFF32); - if (dr_type == R_SH_TLS_TPOFF32 && indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (indx, dr_type); - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - if (r_type == R_SH_TLS_GD_32) - { - if (indx == 0) - { - bfd_put_32 (output_bfd, - relocation - dtpoff_base (info), - sgot->contents + off + 4); - } - else - { - outrel.r_info = ELF32_R_INFO (indx, - R_SH_TLS_DTPOFF32); - outrel.r_offset += 4; - outrel.r_addend = 0; - srelgot->reloc_count++; - loc += sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - } - } - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - if (off >= (bfd_vma) -2) - abort (); - - if (r_type == (int) ELF32_R_TYPE (rel->r_info)) - relocation = sh_elf_got_offset (htab) + off; - else - { - bfd_vma offset; - unsigned short insn; - - /* GD->IE transition: - mov.l 1f,r4; mova 2f,r0; mov.l 2f,r1; add r0,r1; - jsr @r1; add r12,r4; bra 3f; nop; .align 2; - 1: .long x$TLSGD; 2: .long __tls_get_addr@PLT; 3: - We change it into: - mov.l 1f,r0; stc gbr,r4; mov.l @(r0,r12),r0; add r4,r0; - nop; nop; bra 3f; nop; .align 2; - 1: .long x@TPOFF; 2:...; 3:. */ - - offset = rel->r_offset; - BFD_ASSERT (offset >= 16); - /* Size of GD instructions is 16 or 18. */ - offset -= 16; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - if ((insn & 0xff00) == 0xc700) - { - BFD_ASSERT (offset >= 2); - offset -= 2; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - } - - BFD_ASSERT ((insn & 0xff00) == 0xd400); - - /* Replace mov.l 1f,R4 with mov.l 1f,r0. */ - bfd_put_16 (output_bfd, insn & 0xf0ff, contents + offset); - - insn = bfd_get_16 (input_bfd, contents + offset + 2); - BFD_ASSERT ((insn & 0xff00) == 0xc700); - insn = bfd_get_16 (input_bfd, contents + offset + 4); - BFD_ASSERT ((insn & 0xff00) == 0xd100); - insn = bfd_get_16 (input_bfd, contents + offset + 6); - BFD_ASSERT (insn == 0x310c); - insn = bfd_get_16 (input_bfd, contents + offset + 8); - BFD_ASSERT (insn == 0x410b); - insn = bfd_get_16 (input_bfd, contents + offset + 10); - BFD_ASSERT (insn == 0x34cc); - - bfd_put_16 (output_bfd, 0x0412, contents + offset + 2); - bfd_put_16 (output_bfd, 0x00ce, contents + offset + 4); - bfd_put_16 (output_bfd, 0x304c, contents + offset + 6); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 8); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 10); - - bfd_put_32 (output_bfd, sh_elf_got_offset (htab) + off, - contents + rel->r_offset); - - continue; - } - - addend = rel->r_addend; - - goto final_link_relocate; - - case R_SH_TLS_LD_32: - BFD_ASSERT (htab); - check_segment[0] = check_segment[1] = -1; - if (! bfd_link_pic (info)) - { - bfd_vma offset; - unsigned short insn; - - /* LD->LE transition: - mov.l 1f,r4; mova 2f,r0; mov.l 2f,r1; add r0,r1; - jsr @r1; add r12,r4; bra 3f; nop; .align 2; - 1: .long x$TLSLD; 2: .long __tls_get_addr@PLT; 3: - We change it into: - stc gbr,r0; nop; nop; nop; - nop; nop; bra 3f; ...; 3:. */ - - offset = rel->r_offset; - BFD_ASSERT (offset >= 16); - /* Size of LD instructions is 16 or 18. */ - offset -= 16; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - if ((insn & 0xff00) == 0xc700) - { - BFD_ASSERT (offset >= 2); - offset -= 2; - insn = bfd_get_16 (input_bfd, contents + offset + 0); - } - - BFD_ASSERT ((insn & 0xff00) == 0xd400); - insn = bfd_get_16 (input_bfd, contents + offset + 2); - BFD_ASSERT ((insn & 0xff00) == 0xc700); - insn = bfd_get_16 (input_bfd, contents + offset + 4); - BFD_ASSERT ((insn & 0xff00) == 0xd100); - insn = bfd_get_16 (input_bfd, contents + offset + 6); - BFD_ASSERT (insn == 0x310c); - insn = bfd_get_16 (input_bfd, contents + offset + 8); - BFD_ASSERT (insn == 0x410b); - insn = bfd_get_16 (input_bfd, contents + offset + 10); - BFD_ASSERT (insn == 0x34cc); - - bfd_put_16 (output_bfd, 0x0012, contents + offset + 0); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 2); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 4); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 6); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 8); - bfd_put_16 (output_bfd, 0x0009, contents + offset + 10); - - continue; - } - - if (sgot == NULL || sgotplt == NULL) - abort (); - - off = htab->tls_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset + off); - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (0, R_SH_TLS_DTPMOD32); - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - htab->tls_ldm_got.offset |= 1; - } - - relocation = sh_elf_got_offset (htab) + off; - addend = rel->r_addend; - - goto final_link_relocate; - - case R_SH_TLS_LDO_32: - check_segment[0] = check_segment[1] = -1; - if (! bfd_link_pic (info)) - relocation = tpoff (info, relocation); - else - relocation -= dtpoff_base (info); - - addend = rel->r_addend; - goto final_link_relocate; - - case R_SH_TLS_LE_32: - { - int indx; - Elf_Internal_Rela outrel; - bfd_byte *loc; - - check_segment[0] = check_segment[1] = -1; - - if (!bfd_link_dll (info)) - { - relocation = tpoff (info, relocation); - addend = rel->r_addend; - goto final_link_relocate; - } - - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - if (h == NULL || h->dynindx == -1) - indx = 0; - else - indx = h->dynindx; - - outrel.r_offset = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - outrel.r_info = ELF32_R_INFO (indx, R_SH_TLS_TPOFF32); - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - continue; - } - } - - relocation_done: - if (fdpic_p && check_segment[0] != (unsigned) -1 - && check_segment[0] != check_segment[1]) - { - /* We don't want duplicate errors for undefined symbols. */ - if (!h || h->root.type != bfd_link_hash_undefined) - { - if (bfd_link_pic (info)) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%X%C: relocation to \"%s\" references a different segment\n"), - input_bfd, input_section, rel->r_offset, symname); - return FALSE; - } - else - info->callbacks->einfo - /* xgettext:c-format */ - (_("%C: warning: relocation to \"%s\" references a different segment\n"), - input_bfd, input_section, rel->r_offset, symname); - } - - elf_elfheader (output_bfd)->e_flags |= EF_SH_PIC; - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - { - const char *name; - - if (h != NULL) - name = NULL; - 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); - } - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - } - break; - } - } - } - - return TRUE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - which uses sh_elf_relocate_section. */ - -static bfd_byte * -sh_elf_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_symtab_hdr (input_bfd); - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - (size_t) input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - asection **secpp; - Elf_Internal_Sym *isym, *isymend; - bfd_size_type amt; - - internal_relocs = (_bfd_elf_link_read_relocs - (input_bfd, input_section, NULL, - (Elf_Internal_Rela *) NULL, FALSE)); - if (internal_relocs == NULL) - goto error_return; - - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - amt = symtab_hdr->sh_info; - amt *= sizeof (asection *); - sections = (asection **) bfd_malloc (amt); - if (sections == NULL && amt != 0) - goto error_return; - - isymend = isymbuf + symtab_hdr->sh_info; - for (isym = isymbuf, secpp = sections; isym < isymend; ++isym, ++secpp) - { - asection *isec; - - if (isym->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - 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 - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - - *secpp = isec; - } - - if (! sh_elf_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (input_section)->relocs != internal_relocs) - free (internal_relocs); - return NULL; -} - -/* 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 R_SH_TLS_TPOFF32.. */ - -static bfd_vma -tpoff (struct bfd_link_info *info, bfd_vma address) -{ - /* If tls_sec is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_sec == NULL) - return 0; - /* SH TLS ABI is variant I and static TLS block start just after tcbhead - structure which has 2 pointer fields. */ - return (address - elf_hash_table (info)->tls_sec->vma - + align_power ((bfd_vma) 8, - elf_hash_table (info)->tls_sec->alignment_power)); -} - -static asection * -sh_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_SH_GNU_VTINHERIT: - case R_SH_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -sh_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_sh_link_hash_entry *edir, *eind; - - edir = (struct elf_sh_link_hash_entry *) dir; - eind = (struct elf_sh_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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; - } - edir->gotplt_refcount = eind->gotplt_refcount; - eind->gotplt_refcount = 0; -#ifdef INCLUDE_SHMEDIA - edir->datalabel_got.refcount += eind->datalabel_got.refcount; - eind->datalabel_got.refcount = 0; -#endif - edir->funcdesc.refcount += eind->funcdesc.refcount; - eind->funcdesc.refcount = 0; - edir->abs_funcdesc_refcount += eind->abs_funcdesc_refcount; - eind->abs_funcdesc_refcount = 0; - - if (ind->root.type == bfd_link_hash_indirect - && dir->got.refcount <= 0) - { - edir->got_type = eind->got_type; - eind->got_type = GOT_UNKNOWN; - } - - if (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. */ - if (dir->versioned != versioned_hidden) - 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; - } - else - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -static int -sh_elf_optimized_tls_reloc (struct bfd_link_info *info, int r_type, - int is_local) -{ - if (bfd_link_pic (info)) - return r_type; - - switch (r_type) - { - case R_SH_TLS_GD_32: - case R_SH_TLS_IE_32: - if (is_local) - return R_SH_TLS_LE_32; - return R_SH_TLS_IE_32; - case R_SH_TLS_LD_32: - return R_SH_TLS_LE_32; - } - - return r_type; -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - struct elf_sh_link_hash_table *htab; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - asection *sreloc; - unsigned int r_type; - enum got_type got_type, old_got_type; - - sreloc = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - BFD_ASSERT (is_sh_elf (abfd)); - - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; -#ifdef INCLUDE_SHMEDIA - int seen_stt_datalabel = 0; -#endif - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - { -#ifdef INCLUDE_SHMEDIA - seen_stt_datalabel |= h->type == STT_DATALABEL; -#endif - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - } - - r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL); - if (! bfd_link_pic (info) - && r_type == R_SH_TLS_IE_32 - && h != NULL - && h->root.type != bfd_link_hash_undefined - && h->root.type != bfd_link_hash_undefweak - && (h->dynindx == -1 - || h->def_regular)) - r_type = R_SH_TLS_LE_32; - - if (htab->fdpic_p) - switch (r_type) - { - case R_SH_GOTOFFFUNCDESC: - case R_SH_GOTOFFFUNCDESC20: - case R_SH_FUNCDESC: - case R_SH_GOTFUNCDESC: - case R_SH_GOTFUNCDESC20: - if (h != NULL) - { - if (h->dynindx == -1) - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - break; - default: - bfd_elf_link_record_dynamic_symbol (info, h); - break; - } - } - break; - } - - /* Some relocs require a global offset table. */ - if (htab->root.sgot == NULL) - { - switch (r_type) - { - case R_SH_DIR32: - /* This may require an rofixup. */ - if (!htab->fdpic_p) - break; - /* Fall through. */ - case R_SH_GOTPLT32: - case R_SH_GOT32: - case R_SH_GOT20: - case R_SH_GOTOFF: - case R_SH_GOTOFF20: - case R_SH_FUNCDESC: - case R_SH_GOTFUNCDESC: - case R_SH_GOTFUNCDESC20: - case R_SH_GOTOFFFUNCDESC: - case R_SH_GOTOFFFUNCDESC20: - case R_SH_GOTPC: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOTPLT_LOW16: - case R_SH_GOTPLT_MEDLOW16: - case R_SH_GOTPLT_MEDHI16: - case R_SH_GOTPLT_HI16: - case R_SH_GOTPLT10BY4: - case R_SH_GOTPLT10BY8: - case R_SH_GOT_LOW16: - case R_SH_GOT_MEDLOW16: - case R_SH_GOT_MEDHI16: - case R_SH_GOT_HI16: - case R_SH_GOT10BY4: - case R_SH_GOT10BY8: - case R_SH_GOTOFF_LOW16: - case R_SH_GOTOFF_MEDLOW16: - case R_SH_GOTOFF_MEDHI16: - case R_SH_GOTOFF_HI16: - case R_SH_GOTPC_LOW16: - case R_SH_GOTPC_MEDLOW16: - case R_SH_GOTPC_MEDHI16: - case R_SH_GOTPC_HI16: -#endif - case R_SH_TLS_GD_32: - case R_SH_TLS_LD_32: - case R_SH_TLS_IE_32: - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - if (!create_got_section (htab->root.dynobj, info)) - return FALSE; - break; - - default: - break; - } - } - - switch (r_type) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_SH_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_SH_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_SH_TLS_IE_32: - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - - /* FALLTHROUGH */ - force_got: - case R_SH_TLS_GD_32: - case R_SH_GOT32: - case R_SH_GOT20: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOT_LOW16: - case R_SH_GOT_MEDLOW16: - case R_SH_GOT_MEDHI16: - case R_SH_GOT_HI16: - case R_SH_GOT10BY4: - case R_SH_GOT10BY8: -#endif - case R_SH_GOTFUNCDESC: - case R_SH_GOTFUNCDESC20: - switch (r_type) - { - default: - got_type = GOT_NORMAL; - break; - case R_SH_TLS_GD_32: - got_type = GOT_TLS_GD; - break; - case R_SH_TLS_IE_32: - got_type = GOT_TLS_IE; - break; - case R_SH_GOTFUNCDESC: - case R_SH_GOTFUNCDESC20: - got_type = GOT_FUNCDESC; - break; - } - - if (h != NULL) - { -#ifdef INCLUDE_SHMEDIA - if (seen_stt_datalabel) - { - struct elf_sh_link_hash_entry *eh - = (struct elf_sh_link_hash_entry *) h; - - eh->datalabel_got.refcount += 1; - } - else -#endif - h->got.refcount += 1; - old_got_type = sh_elf_hash_entry (h)->got_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); -#ifdef INCLUDE_SHMEDIA - /* Reserve space for both the datalabel and - codelabel local GOT offsets. */ - size *= 2; -#endif - size += symtab_hdr->sh_info; - 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; -#ifdef INCLUDE_SHMEDIA - /* Take care of both the datalabel and codelabel local - GOT offsets. */ - sh_elf_local_got_type (abfd) - = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); -#else - sh_elf_local_got_type (abfd) - = (char *) (local_got_refcounts + symtab_hdr->sh_info); -#endif - } -#ifdef INCLUDE_SHMEDIA - if (rel->r_addend & 1) - local_got_refcounts[symtab_hdr->sh_info + r_symndx] += 1; - else -#endif - local_got_refcounts[r_symndx] += 1; - old_got_type = sh_elf_local_got_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_got_type != got_type && old_got_type != GOT_UNKNOWN - && (old_got_type != GOT_TLS_GD || got_type != GOT_TLS_IE)) - { - if (old_got_type == GOT_TLS_IE && got_type == GOT_TLS_GD) - got_type = GOT_TLS_IE; - else - { - if ((old_got_type == GOT_FUNCDESC || got_type == GOT_FUNCDESC) - && (old_got_type == GOT_NORMAL || got_type == GOT_NORMAL)) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as normal and FDPIC symbol"), - abfd, h->root.root.string); - else if (old_got_type == GOT_FUNCDESC - || got_type == GOT_FUNCDESC) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as FDPIC and thread local symbol"), - abfd, h->root.root.string); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as normal and thread local symbol"), - abfd, h->root.root.string); - return FALSE; - } - } - - if (old_got_type != got_type) - { - if (h != NULL) - sh_elf_hash_entry (h)->got_type = got_type; - else - sh_elf_local_got_type (abfd) [r_symndx] = got_type; - } - - break; - - case R_SH_TLS_LD_32: - sh_elf_hash_table(info)->tls_ldm_got.refcount += 1; - break; - - case R_SH_FUNCDESC: - case R_SH_GOTOFFFUNCDESC: - case R_SH_GOTOFFFUNCDESC20: - if (rel->r_addend) - { - _bfd_error_handler - (_("%B: Function descriptor relocation with non-zero addend"), - abfd); - return FALSE; - } - - if (h == NULL) - { - union gotref *local_funcdesc; - - /* We need a function descriptor for a local symbol. */ - local_funcdesc = sh_elf_local_funcdesc (abfd); - if (local_funcdesc == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info * sizeof (union gotref); -#ifdef INCLUDE_SHMEDIA - /* Count datalabel local GOT. */ - size *= 2; -#endif - local_funcdesc = (union gotref *) bfd_zalloc (abfd, size); - if (local_funcdesc == NULL) - return FALSE; - sh_elf_local_funcdesc (abfd) = local_funcdesc; - } - local_funcdesc[r_symndx].refcount += 1; - - if (r_type == R_SH_FUNCDESC) - { - if (!bfd_link_pic (info)) - htab->srofixup->size += 4; - else - htab->root.srelgot->size += sizeof (Elf32_External_Rela); - } - } - else - { - sh_elf_hash_entry (h)->funcdesc.refcount++; - if (r_type == R_SH_FUNCDESC) - sh_elf_hash_entry (h)->abs_funcdesc_refcount++; - - /* If there is a function descriptor reference, then - there should not be any non-FDPIC references. */ - old_got_type = sh_elf_hash_entry (h)->got_type; - if (old_got_type != GOT_FUNCDESC && old_got_type != GOT_UNKNOWN) - { - if (old_got_type == GOT_NORMAL) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as normal and FDPIC symbol"), - abfd, h->root.root.string); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as FDPIC and thread local symbol"), - abfd, h->root.root.string); - } - } - break; - - case R_SH_GOTPLT32: -#ifdef INCLUDE_SHMEDIA - case R_SH_GOTPLT_LOW16: - case R_SH_GOTPLT_MEDLOW16: - case R_SH_GOTPLT_MEDHI16: - case R_SH_GOTPLT_HI16: - case R_SH_GOTPLT10BY4: - case R_SH_GOTPLT10BY8: -#endif - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - - if (h == NULL - || h->forced_local - || ! bfd_link_pic (info) - || info->symbolic - || h->dynindx == -1) - goto force_got; - - h->needs_plt = 1; - h->plt.refcount += 1; - ((struct elf_sh_link_hash_entry *) h)->gotplt_refcount += 1; - - break; - - case R_SH_PLT32: -#ifdef INCLUDE_SHMEDIA - case R_SH_PLT_LOW16: - case R_SH_PLT_MEDLOW16: - case R_SH_PLT_MEDHI16: - case R_SH_PLT_HI16: -#endif - /* 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; - - if (h->forced_local) - break; - - h->needs_plt = 1; - h->plt.refcount += 1; - break; - - case R_SH_DIR32: - case R_SH_REL32: -#ifdef INCLUDE_SHMEDIA - case R_SH_IMM_LOW16_PCREL: - case R_SH_IMM_MEDLOW16_PCREL: - case R_SH_IMM_MEDHI16_PCREL: - case R_SH_IMM_HI16_PCREL: -#endif - if (h != NULL && ! bfd_link_pic (info)) - { - h->non_got_ref = 1; - h->plt.refcount += 1; - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). We account for that - possibility below by storing information in the - dyn_relocs field of the hash table entry. A similar - situation occurs when creating shared libraries and symbol - visibility changes render the symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (r_type != R_SH_REL32 - || (h != NULL - && (! info->symbolic - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (! bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - if (htab->root.dynobj == NULL) - htab->root.dynobj = abfd; - - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->root.dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &((struct elf_sh_link_hash_entry *) h)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. */ - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof (*p); - p = bfd_alloc (htab->root.dynobj, amt); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - if (r_type == R_SH_REL32 -#ifdef INCLUDE_SHMEDIA - || r_type == R_SH_IMM_LOW16_PCREL - || r_type == R_SH_IMM_MEDLOW16_PCREL - || r_type == R_SH_IMM_MEDHI16_PCREL - || r_type == R_SH_IMM_HI16_PCREL -#endif - ) - p->pc_count += 1; - } - - /* Allocate the fixup regardless of whether we need a relocation. - If we end up generating the relocation, we'll unallocate the - fixup. */ - if (htab->fdpic_p && !bfd_link_pic (info) - && r_type == R_SH_DIR32 - && (sec->flags & SEC_ALLOC) != 0) - htab->srofixup->size += 4; - break; - - case R_SH_TLS_LE_32: - if (bfd_link_dll (info)) - { - _bfd_error_handler - (_("%B: TLS local exec code cannot be linked into shared objects"), - abfd); - return FALSE; - } - - break; - - case R_SH_TLS_LDO_32: - /* Nothing to do. */ - break; - - default: - break; - } - } - - return TRUE; -} - -#ifndef sh_elf_set_mach_from_flags -static unsigned int sh_ef_bfd_table[] = { EF_SH_BFD_TABLE }; - -static bfd_boolean -sh_elf_set_mach_from_flags (bfd *abfd) -{ - flagword flags = elf_elfheader (abfd)->e_flags & EF_SH_MACH_MASK; - - if (flags >= ARRAY_SIZE (sh_ef_bfd_table)) - return FALSE; - - if (sh_ef_bfd_table[flags] == 0) - return FALSE; - - bfd_default_set_arch_mach (abfd, bfd_arch_sh, sh_ef_bfd_table[flags]); - - return TRUE; -} - - -/* Reverse table lookup for sh_ef_bfd_table[]. - Given a bfd MACH value from archures.c - return the equivalent ELF flags from the table. - Return -1 if no match is found. */ - -int -sh_elf_get_flags_from_mach (unsigned long mach) -{ - int i = ARRAY_SIZE (sh_ef_bfd_table) - 1; - - for (; i>0; i--) - if (sh_ef_bfd_table[i] == mach) - return i; - - /* shouldn't get here */ - BFD_FAIL(); - - return -1; -} -#endif /* not sh_elf_set_mach_from_flags */ - -#ifndef sh_elf_copy_private_data -/* Copy backend specific data from one object module to another */ - -static bfd_boolean -sh_elf_copy_private_data (bfd * ibfd, bfd * obfd) -{ - if (! is_sh_elf (ibfd) || ! is_sh_elf (obfd)) - return TRUE; - - if (! _bfd_elf_copy_private_bfd_data (ibfd, obfd)) - return FALSE; - - return sh_elf_set_mach_from_flags (obfd); -} -#endif /* not sh_elf_copy_private_data */ - -#ifndef sh_elf_merge_private_data - -/* This function returns the ELF architecture number that - corresponds to the given arch_sh* flags. */ - -int -sh_find_elf_flags (unsigned int arch_set) -{ - extern unsigned long sh_get_bfd_mach_from_arch_set (unsigned int); - unsigned long bfd_mach = sh_get_bfd_mach_from_arch_set (arch_set); - - return sh_elf_get_flags_from_mach (bfd_mach); -} - -/* Merge the architecture type of two BFD files, such that the - resultant architecture supports all the features required - by the two input BFDs. - If the input BFDs are multually incompatible - i.e. one uses - DSP while the other uses FPU - or there is no known architecture - that fits the requirements then an error is emitted. */ - -static bfd_boolean -sh_merge_bfd_arch (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - unsigned int old_arch, new_arch, merged_arch; - - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - old_arch = sh_get_arch_up_from_bfd_mach (bfd_get_mach (obfd)); - new_arch = sh_get_arch_up_from_bfd_mach (bfd_get_mach (ibfd)); - - merged_arch = SH_MERGE_ARCH_SET (old_arch, new_arch); - - if (!SH_VALID_CO_ARCH_SET (merged_arch)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses %s instructions while previous modules " - "use %s instructions"), - ibfd, - SH_ARCH_SET_HAS_DSP (new_arch) ? "dsp" : "floating point", - SH_ARCH_SET_HAS_DSP (new_arch) ? "floating point" : "dsp"); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else if (!SH_VALID_ARCH_SET (merged_arch)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("internal error: merge of architecture '%s' with " - "architecture '%s' produced unknown architecture"), - bfd_printable_name (obfd), - bfd_printable_name (ibfd)); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - bfd_default_set_arch_mach (obfd, bfd_arch_sh, - sh_get_bfd_mach_from_arch_set (merged_arch)); - - return TRUE; -} - -/* This routine initialises the elf flags when required and - calls sh_merge_bfd_arch() to check dsp/fpu compatibility. */ - -static bfd_boolean -sh_elf_merge_private_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - - if (! is_sh_elf (ibfd) || ! is_sh_elf (obfd)) - return TRUE; - - if (! elf_flags_init (obfd)) - { - /* This happens when ld starts out with a 'blank' output file. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - sh_elf_set_mach_from_flags (obfd); - if (elf_elfheader (obfd)->e_flags & EF_SH_FDPIC) - elf_elfheader (obfd)->e_flags &= ~EF_SH_PIC; - } - - if (! sh_merge_bfd_arch (ibfd, info)) - { - _bfd_error_handler (_("%B: uses instructions which are incompatible " - "with instructions used in previous modules"), - ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - elf_elfheader (obfd)->e_flags &= ~EF_SH_MACH_MASK; - elf_elfheader (obfd)->e_flags |= - sh_elf_get_flags_from_mach (bfd_get_mach (obfd)); - - if (fdpic_object_p (ibfd) != fdpic_object_p (obfd)) - { - _bfd_error_handler (_("%B: attempt to mix FDPIC and non-FDPIC objects"), - ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - return TRUE; -} -#endif /* not sh_elf_merge_private_data */ - -/* Override the generic function because we need to store sh_elf_obj_tdata - as the specific tdata. We set also the machine architecture from flags - here. */ - -static bfd_boolean -sh_elf_object_p (bfd *abfd) -{ - if (! sh_elf_set_mach_from_flags (abfd)) - return FALSE; - - return (((elf_elfheader (abfd)->e_flags & EF_SH_FDPIC) != 0) - == fdpic_object_p (abfd)); -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_sh_link_hash_table *htab; - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgotplt; - asection *srelplt; - - bfd_vma plt_index; - bfd_vma got_offset; - Elf_Internal_Rela rel; - bfd_byte *loc; - const struct elf_sh_plt_info *plt_info; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->root.splt; - sgotplt = htab->root.sgotplt; - srelplt = htab->root.srelplt; - BFD_ASSERT (splt != NULL && sgotplt != NULL && srelplt != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = get_plt_index (htab->plt_info, h->plt.offset); - - plt_info = htab->plt_info; - if (plt_info->short_plt != NULL && plt_index <= MAX_SHORT_PLT) - plt_info = plt_info->short_plt; - - /* Get the offset into the .got table of the entry that - corresponds to this function. */ - if (htab->fdpic_p) - /* The offset must be relative to the GOT symbol, twelve bytes - before the end of .got.plt. Each descriptor is eight - bytes. */ - got_offset = plt_index * 8 + 12 - sgotplt->size; - else - /* Each .got entry is 4 bytes. The first three are - reserved. */ - got_offset = (plt_index + 3) * 4; - -#ifdef GOT_BIAS - if (bfd_link_pic (info)) - got_offset -= GOT_BIAS; -#endif - - /* Fill in the entry in the procedure linkage table. */ - memcpy (splt->contents + h->plt.offset, - plt_info->symbol_entry, - plt_info->symbol_entry_size); - - if (bfd_link_pic (info) || htab->fdpic_p) - { - if (plt_info->symbol_fields.got20) - { - bfd_reloc_status_type r; - r = install_movi20_field (output_bfd, got_offset, - splt->owner, splt, splt->contents, - h->plt.offset - + plt_info->symbol_fields.got_entry); - BFD_ASSERT (r == bfd_reloc_ok); - } - else - install_plt_field (output_bfd, FALSE, got_offset, - (splt->contents - + h->plt.offset - + plt_info->symbol_fields.got_entry)); - } - else - { - BFD_ASSERT (!plt_info->symbol_fields.got20); - - install_plt_field (output_bfd, FALSE, - (sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset), - (splt->contents - + h->plt.offset - + plt_info->symbol_fields.got_entry)); - if (htab->vxworks_p) - { - unsigned int reachable_plts, plts_per_4k; - int distance; - - /* Divide the PLT into groups. The first group contains - REACHABLE_PLTS entries and the other groups contain - PLTS_PER_4K entries. Entries in the first group can - branch directly to .plt; those in later groups branch - to the last element of the previous group. */ - /* ??? It would be better to create multiple copies of - the common resolver stub. */ - reachable_plts = ((4096 - - plt_info->plt0_entry_size - - (plt_info->symbol_fields.plt + 4)) - / plt_info->symbol_entry_size) + 1; - plts_per_4k = (4096 / plt_info->symbol_entry_size); - if (plt_index < reachable_plts) - distance = -(h->plt.offset - + plt_info->symbol_fields.plt); - else - distance = -(((plt_index - reachable_plts) % plts_per_4k + 1) - * plt_info->symbol_entry_size); - - /* Install the 'bra' with this offset. */ - bfd_put_16 (output_bfd, - 0xa000 | (0x0fff & ((distance - 4) / 2)), - (splt->contents - + h->plt.offset - + plt_info->symbol_fields.plt)); - } - else - install_plt_field (output_bfd, TRUE, - splt->output_section->vma + splt->output_offset, - (splt->contents - + h->plt.offset - + plt_info->symbol_fields.plt)); - } - - /* Make got_offset relative to the start of .got.plt. */ -#ifdef GOT_BIAS - if (bfd_link_pic (info)) - got_offset += GOT_BIAS; -#endif - if (htab->fdpic_p) - got_offset = plt_index * 8; - - if (plt_info->symbol_fields.reloc_offset != MINUS_ONE) - install_plt_field (output_bfd, FALSE, - plt_index * sizeof (Elf32_External_Rela), - (splt->contents - + h->plt.offset - + plt_info->symbol_fields.reloc_offset)); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + plt_info->symbol_resolve_offset), - sgotplt->contents + got_offset); - if (htab->fdpic_p) - bfd_put_32 (output_bfd, - sh_elf_osec_to_segment (output_bfd, splt->output_section), - sgotplt->contents + got_offset + 4); - - /* Fill in the entry in the .rela.plt section. */ - rel.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset); - if (htab->fdpic_p) - rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_FUNCDESC_VALUE); - else - rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_JMP_SLOT); - rel.r_addend = 0; -#ifdef GOT_BIAS - rel.r_addend = GOT_BIAS; -#endif - loc = srelplt->contents + plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - - if (htab->vxworks_p && !bfd_link_pic (info)) - { - /* Create the .rela.plt.unloaded relocations for this PLT entry. - Begin by pointing LOC to the first such relocation. */ - loc = (htab->srelplt2->contents - + (plt_index * 2 + 1) * sizeof (Elf32_External_Rela)); - - /* Create a .rela.plt.unloaded R_SH_DIR32 relocation - for the PLT entry's pointer to the .got.plt entry. */ - rel.r_offset = (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + plt_info->symbol_fields.got_entry); - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_SH_DIR32); - rel.r_addend = got_offset; - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - - /* Create a .rela.plt.unloaded R_SH_DIR32 relocation for - the .got.plt entry, which initially points to .plt. */ - rel.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset); - rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_SH_DIR32); - rel.r_addend = 0; - 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 alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (h->got.offset != (bfd_vma) -1 - && sh_elf_hash_entry (h)->got_type != GOT_TLS_GD - && sh_elf_hash_entry (h)->got_type != GOT_TLS_IE - && sh_elf_hash_entry (h)->got_type != GOT_FUNCDESC) - { - asection *sgot; - asection *srelgot; - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - sgot = htab->root.sgot; - srelgot = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srelgot != NULL); - - rel.r_offset = (sgot->output_section->vma - + 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 (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - { - if (htab->fdpic_p) - { - asection *sec = h->root.u.def.section; - int dynindx - = elf_section_data (sec->output_section)->dynindx; - - rel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_offset); - } - else - { - rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_GLOB_DAT); - rel.r_addend = 0; - } - - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } - -#ifdef INCLUDE_SHMEDIA - { - struct elf_sh_link_hash_entry *eh; - - eh = (struct elf_sh_link_hash_entry *) h; - if (eh->datalabel_got.offset != (bfd_vma) -1) - { - asection *sgot; - asection *srelgot; - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* This symbol has a datalabel entry in the global offset table. - Set it up. */ - - sgot = htab->root.sgot; - srelgot = htab->root.srelgot; - BFD_ASSERT (sgot != NULL && srelgot != NULL); - - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (eh->datalabel_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 (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - { - if (htab->fdpic_p) - { - asection *sec = h->root.u.def.section; - int dynindx - = elf_section_data (sec->output_section)->dynindx; - - rel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_offset); - } - else - { - rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - } - else - { - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents - + eh->datalabel_got.offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_GLOB_DAT); - rel.r_addend = 0; - } - - loc = srelgot->contents; - loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } - } -#endif - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* This symbol needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (htab->root.dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - 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_SH_COPY); - rel.r_addend = 0; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. On VxWorks, - _GLOBAL_OFFSET_TABLE_ is not absolute: it is relative to the - ".got" section. */ - if (h == htab->root.hdynamic - || (!htab->vxworks_p && h == htab->root.hgot)) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - struct elf_sh_link_hash_table *htab; - asection *sgotplt; - asection *sdyn; - - htab = sh_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - sgotplt = htab->root.sgotplt; - sdyn = bfd_get_linker_section (htab->root.dynobj, ".dynamic"); - - if (htab->root.dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sgotplt != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; -#ifdef INCLUDE_SHMEDIA - const char *name; -#endif - - bfd_elf32_swap_dyn_in (htab->root.dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - if (htab->vxworks_p - && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - -#ifdef INCLUDE_SHMEDIA - case DT_INIT: - name = info->init_function; - goto get_sym; - - case DT_FINI: - name = info->fini_function; - get_sym: - if (dyn.d_un.d_val != 0) - { - struct elf_link_hash_entry *h; - - h = elf_link_hash_lookup (&htab->root, name, - FALSE, FALSE, TRUE); - if (h != NULL && (h->other & STO_SH5_ISA32)) - { - dyn.d_un.d_val |= 1; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - break; -#endif - - case DT_PLTGOT: - BFD_ASSERT (htab->root.hgot != NULL); - s = htab->root.hgot->root.u.def.section; - dyn.d_un.d_ptr = htab->root.hgot->root.u.def.value - + s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - s = htab->root.srelplt->output_section; - BFD_ASSERT (s != NULL); - dyn.d_un.d_ptr = s->vma; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = htab->root.srelplt->output_section; - BFD_ASSERT (s != NULL); - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = htab->root.splt; - if (splt && splt->size > 0 && htab->plt_info->plt0_entry) - { - unsigned int i; - - memcpy (splt->contents, - htab->plt_info->plt0_entry, - htab->plt_info->plt0_entry_size); - for (i = 0; i < ARRAY_SIZE (htab->plt_info->plt0_got_fields); i++) - if (htab->plt_info->plt0_got_fields[i] != MINUS_ONE) - install_plt_field (output_bfd, FALSE, - (sgotplt->output_section->vma - + sgotplt->output_offset - + (i * 4)), - (splt->contents - + htab->plt_info->plt0_got_fields[i])); - - if (htab->vxworks_p) - { - /* Finalize the .rela.plt.unloaded contents. */ - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* Create a .rela.plt.unloaded R_SH_DIR32 relocation for the - first PLT entry's pointer to _GLOBAL_OFFSET_TABLE_ + 8. */ - loc = htab->srelplt2->contents; - rel.r_offset = (splt->output_section->vma - + splt->output_offset - + htab->plt_info->plt0_got_fields[2]); - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_SH_DIR32); - rel.r_addend = 8; - bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - - /* Fix up the remaining .rela.plt.unloaded relocations. - They may have the wrong symbol index for _G_O_T_ or - _P_L_T_ depending on the order in which symbols were - output. */ - while (loc < htab->srelplt2->contents + htab->srelplt2->size) - { - /* The PLT entry's pointer to the .got.plt slot. */ - bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); - rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, - R_SH_DIR32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - - /* The .got.plt slot's pointer to .plt. */ - bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); - rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, - R_SH_DIR32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - loc += sizeof (Elf32_External_Rela); - } - } - - /* UnixWare sets the entsize of .plt to 4, although that doesn't - really seem like the right value. */ - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgotplt && sgotplt->size > 0 && !htab->fdpic_p) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgotplt->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8); - } - - if (sgotplt && sgotplt->size > 0) - elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4; - - /* At the very end of the .rofixup section is a pointer to the GOT. */ - if (htab->fdpic_p && htab->srofixup != NULL) - { - struct elf_link_hash_entry *hgot = htab->root.hgot; - bfd_vma got_value = hgot->root.u.def.value - + hgot->root.u.def.section->output_section->vma - + hgot->root.u.def.section->output_offset; - - sh_elf_add_rofixup (output_bfd, htab->srofixup, got_value); - - /* Make sure we allocated and generated the same number of fixups. */ - BFD_ASSERT (htab->srofixup->reloc_count * 4 == htab->srofixup->size); - } - - if (htab->srelfuncdesc) - BFD_ASSERT (htab->srelfuncdesc->reloc_count * sizeof (Elf32_External_Rela) - == htab->srelfuncdesc->size); - - if (htab->root.srelgot) - BFD_ASSERT (htab->root.srelgot->reloc_count * sizeof (Elf32_External_Rela) - == htab->root.srelgot->size); - - return TRUE; -} - -static enum elf_reloc_type_class -sh_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_SH_RELATIVE: - return reloc_class_relative; - case R_SH_JMP_SLOT: - return reloc_class_plt; - case R_SH_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -#if !defined SH_TARGET_ALREADY_DEFINED -/* Support for Linux core dump NOTE sections. */ - -static bfd_boolean -elf32_shlin_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 168: /* Linux/SH */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 92; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf32_shlin_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* Linux/SH 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; -} -#endif /* not SH_TARGET_ALREADY_DEFINED */ - - -/* 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 -sh_elf_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - const struct elf_sh_plt_info *plt_info; - - plt_info = get_plt_info (plt->owner, (plt->owner->flags & DYNAMIC) != 0); - return plt->vma + get_plt_offset (plt_info, i); -} - -/* Decide whether to attempt to turn absptr or lsda encodings in - shared libraries into pcrel within the given input section. */ - -static bfd_boolean -sh_elf_use_relative_eh_frame (bfd *input_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - asection *eh_frame_section ATTRIBUTE_UNUSED) -{ - struct elf_sh_link_hash_table *htab = sh_elf_hash_table (info); - - /* We can't use PC-relative encodings in FDPIC binaries, in general. */ - if (htab->fdpic_p) - return FALSE; - - return TRUE; -} - -/* Adjust the contents of an eh_frame_hdr section before they're output. */ - -static bfd_byte -sh_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) -{ - struct elf_sh_link_hash_table *htab = sh_elf_hash_table (info); - struct elf_link_hash_entry *h; - - if (!htab->fdpic_p) - return _bfd_elf_encode_eh_address (abfd, info, osec, offset, loc_sec, - loc_offset, encoded); - - h = htab->root.hgot; - BFD_ASSERT (h && h->root.type == bfd_link_hash_defined); - - if (! h || (sh_elf_osec_to_segment (abfd, osec) - == sh_elf_osec_to_segment (abfd, loc_sec->output_section))) - return _bfd_elf_encode_eh_address (abfd, info, osec, offset, - loc_sec, loc_offset, encoded); - - BFD_ASSERT (sh_elf_osec_to_segment (abfd, osec) - == (sh_elf_osec_to_segment - (abfd, h->root.u.def.section->output_section))); - - *encoded = osec->vma + offset - - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - - return DW_EH_PE_datarel | DW_EH_PE_sdata4; -} - -#if !defined SH_TARGET_ALREADY_DEFINED -#define TARGET_BIG_SYM sh_elf32_vec -#define TARGET_BIG_NAME "elf32-sh" -#define TARGET_LITTLE_SYM sh_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-shl" -#endif - -#define ELF_ARCH bfd_arch_sh -#define ELF_TARGET_ID SH_ELF_DATA -#define ELF_MACHINE_CODE EM_SH -#ifdef __QNXTARGET__ -#define ELF_MAXPAGESIZE 0x1000 -#else -#define ELF_MAXPAGESIZE 0x80 -#endif - -#define elf_symbol_leading_char '_' - -#define bfd_elf32_bfd_reloc_type_lookup sh_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - sh_elf_reloc_name_lookup -#define elf_info_to_howto sh_elf_info_to_howto -#define bfd_elf32_bfd_relax_section sh_elf_relax_section -#define elf_backend_relocate_section sh_elf_relocate_section -#define bfd_elf32_bfd_get_relocated_section_contents \ - sh_elf_get_relocated_section_contents -#define bfd_elf32_mkobject sh_elf_mkobject -#define elf_backend_object_p sh_elf_object_p -#define bfd_elf32_bfd_copy_private_bfd_data \ - sh_elf_copy_private_data -#define bfd_elf32_bfd_merge_private_bfd_data \ - sh_elf_merge_private_data - -#define elf_backend_gc_mark_hook sh_elf_gc_mark_hook -#define elf_backend_check_relocs sh_elf_check_relocs -#define elf_backend_copy_indirect_symbol \ - sh_elf_copy_indirect_symbol -#define elf_backend_create_dynamic_sections \ - sh_elf_create_dynamic_sections -#define bfd_elf32_bfd_link_hash_table_create \ - sh_elf_link_hash_table_create -#define elf_backend_adjust_dynamic_symbol \ - sh_elf_adjust_dynamic_symbol -#define elf_backend_always_size_sections \ - sh_elf_always_size_sections -#define elf_backend_size_dynamic_sections \ - sh_elf_size_dynamic_sections -#define elf_backend_omit_section_dynsym sh_elf_omit_section_dynsym -#define elf_backend_finish_dynamic_symbol \ - sh_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - sh_elf_finish_dynamic_sections -#define elf_backend_reloc_type_class sh_elf_reloc_type_class -#define elf_backend_plt_sym_val sh_elf_plt_sym_val -#define elf_backend_can_make_relative_eh_frame \ - sh_elf_use_relative_eh_frame -#define elf_backend_can_make_lsda_relative_eh_frame \ - sh_elf_use_relative_eh_frame -#define elf_backend_encode_eh_address \ - sh_elf_encode_eh_address - -#define elf_backend_stack_align 8 -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 12 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#if !defined INCLUDE_SHMEDIA && !defined SH_TARGET_ALREADY_DEFINED - -#include "elf32-target.h" - -/* NetBSD support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh_elf32_nbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sh-nbsd" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh_elf32_nbsd_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-shl-nbsd" -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x10000 -#undef ELF_COMMONPAGESIZE -#undef elf_symbol_leading_char -#define elf_symbol_leading_char 0 -#undef elf32_bed -#define elf32_bed elf32_sh_nbsd_bed - -#include "elf32-target.h" - - -/* Linux support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh_elf32_linux_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-shbig-linux" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh_elf32_linux_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-sh-linux" -#undef ELF_COMMONPAGESIZE -#define ELF_COMMONPAGESIZE 0x1000 - -#undef elf_backend_grok_prstatus -#define elf_backend_grok_prstatus elf32_shlin_grok_prstatus -#undef elf_backend_grok_psinfo -#define elf_backend_grok_psinfo elf32_shlin_grok_psinfo -#undef elf32_bed -#define elf32_bed elf32_sh_lin_bed - -#include "elf32-target.h" - - -/* FDPIC support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh_elf32_fdpic_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-shbig-fdpic" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh_elf32_fdpic_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-sh-fdpic" - -#undef elf32_bed -#define elf32_bed elf32_sh_fd_bed - -#include "elf32-target.h" - -#undef elf_backend_modify_program_headers - -/* VxWorks support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh_elf32_vxworks_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sh-vxworks" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh_elf32_vxworks_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-shl-vxworks" -#undef elf32_bed -#define elf32_bed elf32_sh_vxworks_bed - -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 1 -#undef elf_symbol_leading_char -#define elf_symbol_leading_char '_' -#define elf_backend_want_got_underscore 1 -#undef elf_backend_grok_prstatus -#undef elf_backend_grok_psinfo -#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 -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x1000 -#undef ELF_COMMONPAGESIZE - -#include "elf32-target.h" - -#endif /* neither INCLUDE_SHMEDIA nor SH_TARGET_ALREADY_DEFINED */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-sh64-com.c b/sdcc/support/sdbinutils/bfd/elf32-sh64-com.c deleted file mode 100644 index 1b69f88df..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sh64-com.c +++ /dev/null @@ -1,245 +0,0 @@ -/* SuperH SH64-specific support for 32-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define SH64_ELF - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/sh.h" -#include "elf32-sh64.h" -#include "../opcodes/sh64-opc.h" - -static bfd_boolean sh64_address_in_cranges - (asection *cranges, bfd_vma, sh64_elf_crange *); - -/* Ordering functions of a crange, for the qsort and bsearch calls and for - different endianness. */ - -int -_bfd_sh64_crange_qsort_cmpb (const void *p1, const void *p2) -{ - bfd_vma a1 = bfd_getb32 (p1); - bfd_vma a2 = bfd_getb32 (p2); - - /* Preserve order if there's ambiguous contents. */ - if (a1 == a2) - return (char *) p1 - (char *) p2; - - return a1 - a2; -} - -int -_bfd_sh64_crange_qsort_cmpl (const void *p1, const void *p2) -{ - bfd_vma a1 = (bfd_vma) bfd_getl32 (p1); - bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); - - /* Preserve order if there's ambiguous contents. */ - if (a1 == a2) - return (char *) p1 - (char *) p2; - - return a1 - a2; -} - -int -_bfd_sh64_crange_bsearch_cmpb (const void *p1, const void *p2) -{ - bfd_vma a1 = *(bfd_vma *) p1; - bfd_vma a2 = (bfd_vma) bfd_getb32 (p2); - bfd_size_type size - = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); - - if (a1 >= a2 + size) - return 1; - if (a1 < a2) - return -1; - return 0; -} - -int -_bfd_sh64_crange_bsearch_cmpl (const void *p1, const void *p2) -{ - bfd_vma a1 = *(bfd_vma *) p1; - bfd_vma a2 = (bfd_vma) bfd_getl32 (p2); - bfd_size_type size - = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2); - - if (a1 >= a2 + size) - return 1; - if (a1 < a2) - return -1; - return 0; -} - -/* Check whether a specific address is specified within a .cranges - section. Return FALSE if not found, and TRUE if found, and the region - filled into RANGEP if non-NULL. */ - -static bfd_boolean -sh64_address_in_cranges (asection *cranges, bfd_vma addr, - sh64_elf_crange *rangep) -{ - bfd_byte *cranges_contents; - bfd_byte *found_rangep; - bfd_size_type cranges_size = cranges->size; - - /* If the size is not a multiple of the cranges entry size, then - something is badly wrong. */ - if ((cranges_size % SH64_CRANGE_SIZE) != 0) - return FALSE; - - /* If this section has relocations, then we can't do anything sane. */ - if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC) - return FALSE; - - /* Has some kind soul (or previous call) left processed, sorted contents - for us? */ - if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY) - && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED) - cranges_contents = cranges->contents; - else - { - if (!bfd_malloc_and_get_section (cranges->owner, cranges, - &cranges_contents)) - goto error_return; - - /* Is it sorted? */ - if (elf_section_data (cranges)->this_hdr.sh_type - != SHT_SH5_CR_SORTED) - /* Nope. Lets sort it. */ - qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE, - SH64_CRANGE_SIZE, - bfd_big_endian (cranges->owner) - ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl); - - /* Let's keep it around. */ - cranges->contents = cranges_contents; - bfd_set_section_flags (cranges->owner, cranges, - bfd_get_section_flags (cranges->owner, cranges) - | SEC_IN_MEMORY); - - /* It's sorted now. */ - elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED; - } - - /* Try and find a matching range. */ - found_rangep - = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE, - SH64_CRANGE_SIZE, - bfd_big_endian (cranges->owner) - ? _bfd_sh64_crange_bsearch_cmpb - : _bfd_sh64_crange_bsearch_cmpl); - - /* Fill in a few return values if we found a matching range. */ - if (found_rangep) - { - enum sh64_elf_cr_type cr_type - = bfd_get_16 (cranges->owner, - SH64_CRANGE_CR_TYPE_OFFSET + found_rangep); - bfd_vma cr_addr - = bfd_get_32 (cranges->owner, - SH64_CRANGE_CR_ADDR_OFFSET - + (char *) found_rangep); - bfd_size_type cr_size - = bfd_get_32 (cranges->owner, - SH64_CRANGE_CR_SIZE_OFFSET - + (char *) found_rangep); - - rangep->cr_addr = cr_addr; - rangep->cr_size = cr_size; - rangep->cr_type = cr_type; - - return TRUE; - } - - /* There is a .cranges section, but it does not have a descriptor - matching this address. */ - return FALSE; - -error_return: - if (cranges_contents != NULL) - free (cranges_contents); - return FALSE; -} - -/* Determine what ADDR points to in SEC, and fill in a range descriptor in - *RANGEP if it's non-NULL. */ - -enum sh64_elf_cr_type -sh64_get_contents_type (asection *sec, bfd_vma addr, sh64_elf_crange *rangep) -{ - asection *cranges; - - /* Fill in the range with the boundaries of the section as a default. */ - if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour - && elf_elfheader (sec->owner)->e_type == ET_EXEC) - { - rangep->cr_addr = bfd_get_section_vma (sec->owner, sec); - rangep->cr_size = sec->size; - rangep->cr_type = CRT_NONE; - } - else - return FALSE; - - /* If none of the pertinent bits are set, then it's a SHcompact (or at - least not SHmedia). */ - if ((elf_section_data (sec)->this_hdr.sh_flags - & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0) - { - enum sh64_elf_cr_type cr_type - = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0 - ? CRT_SH5_ISA16 : CRT_DATA); - rangep->cr_type = cr_type; - return cr_type; - } - - /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */ - if ((elf_section_data (sec)->this_hdr.sh_flags - & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32) - { - rangep->cr_type = CRT_SH5_ISA32; - return CRT_SH5_ISA32; - } - - /* Otherwise, we have to look up the .cranges section. */ - cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME); - - if (cranges == NULL) - /* A mixed section but there's no .cranges section. This is probably - bad input; it does not comply to specs. */ - return CRT_NONE; - - /* If this call fails, we will still have CRT_NONE in rangep->cr_type - and that will be suitable to return. */ - sh64_address_in_cranges (cranges, addr, rangep); - - return rangep->cr_type; -} - -/* This is a simpler exported interface for the benefit of gdb et al. */ - -bfd_boolean -sh64_address_is_shmedia (asection *sec, bfd_vma addr) -{ - sh64_elf_crange dummy; - return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32; -} diff --git a/sdcc/support/sdbinutils/bfd/elf32-sh64.c b/sdcc/support/sdbinutils/bfd/elf32-sh64.c deleted file mode 100644 index 51eca0bbc..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sh64.c +++ /dev/null @@ -1,813 +0,0 @@ -/* SuperH SH64-specific support for 32-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define SH64_ELF - -#include "sysdep.h" -#include "bfd.h" -#include "elf-bfd.h" -#include "../opcodes/sh64-opc.h" -#include "elf32-sh64.h" - -/* Add a suffix for datalabel indirection symbols. It must not match any - other symbols; user symbols with or without version or other - decoration. It must only be used internally and not emitted by any - means. */ -#define DATALABEL_SUFFIX " DL" - -/* Used to hold data for function called through bfd_map_over_sections. */ -struct sh64_find_section_vma_data - { - asection *section; - bfd_vma addr; - }; - -static bfd_boolean sh64_elf_new_section_hook - (bfd *, asection *); -static bfd_boolean sh64_elf_copy_private_data - (bfd *, bfd *); -static bfd_boolean sh64_elf_merge_private_data - (bfd *, struct bfd_link_info *); -static bfd_boolean sh64_elf_fake_sections - (bfd *, Elf_Internal_Shdr *, asection *); -static bfd_boolean sh64_elf_set_private_flags - (bfd *, flagword); -static bfd_boolean sh64_elf_set_mach_from_flags - (bfd *); -static bfd_boolean shmedia_prepare_reloc - (struct bfd_link_info *, bfd *, asection *, bfd_byte *, - const Elf_Internal_Rela *, bfd_vma *); -static int sh64_elf_get_symbol_type - (Elf_Internal_Sym *, int); -static bfd_boolean sh64_elf_add_symbol_hook - (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, - flagword *, asection **, bfd_vma *); -static int sh64_elf_link_output_symbol_hook - (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *, - struct elf_link_hash_entry *); -static bfd_boolean sh64_backend_section_from_shdr - (bfd *, Elf_Internal_Shdr *, const char *, int); -static void sh64_elf_final_write_processing - (bfd *, bfd_boolean); -static bfd_boolean sh64_bfd_elf_copy_private_section_data - (bfd *, asection *, bfd *, asection *); -static void sh64_find_section_for_address - (bfd *, asection *, void *); - -/* Let elf32-sh.c handle the "bfd_" definitions, so we only have to - intrude with an #ifndef around the function definition. */ -#define sh_elf_copy_private_data sh64_elf_copy_private_data -#define sh_elf_merge_private_data sh64_elf_merge_private_data -#define sh_elf_set_private_flags sh64_elf_set_private_flags -/* Typo in elf32-sh.c (and unlinear name). */ -#define bfd_elf32_bfd_set_private_flags sh64_elf_set_private_flags -#define sh_elf_set_mach_from_flags sh64_elf_set_mach_from_flags - -#define elf_backend_sign_extend_vma 1 -#define elf_backend_fake_sections sh64_elf_fake_sections -#define elf_backend_get_symbol_type sh64_elf_get_symbol_type -#define elf_backend_add_symbol_hook sh64_elf_add_symbol_hook -#define elf_backend_link_output_symbol_hook \ - sh64_elf_link_output_symbol_hook -#define elf_backend_merge_symbol_attribute sh64_elf_merge_symbol_attribute -#define elf_backend_final_write_processing sh64_elf_final_write_processing -#define elf_backend_section_from_shdr sh64_backend_section_from_shdr -#define elf_backend_special_sections sh64_elf_special_sections -#define elf_backend_section_flags sh64_elf_section_flags - -#define bfd_elf32_new_section_hook sh64_elf_new_section_hook - -/* For objcopy, we need to set up sh64_elf_section_data (asection *) from - incoming section flags. This is otherwise done in sh64elf.em when - linking or tc-sh64.c when assembling. */ -#define bfd_elf32_bfd_copy_private_section_data \ - sh64_bfd_elf_copy_private_section_data - -/* This COFF-only function (only compiled with COFF support, making - ELF-only chains problematic) returns TRUE early for SH4, so let's just - define it TRUE here. */ -#define _bfd_sh_align_load_span(a,b,c,d,e,f,g,h,i,j) \ - ((void) f, (void) h, (void) i, TRUE) - -#define GOT_BIAS (-((long)-32768)) -#define INCLUDE_SHMEDIA -#define SH_TARGET_ALREADY_DEFINED -#include "elf32-sh.c" - -/* Tack some extra info on struct bfd_elf_section_data. */ - -static bfd_boolean -sh64_elf_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - struct _sh64_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - -/* Set the SHF_SH5_ISA32 flag for ISA SHmedia code sections, and pass - through SHT_SH5_CR_SORTED on a sorted .cranges section. */ - -bfd_boolean -sh64_elf_fake_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *elf_section_hdr, - asection *asect) -{ - if (sh64_elf_section_data (asect)->sh64_info != NULL) - elf_section_hdr->sh_flags - |= sh64_elf_section_data (asect)->sh64_info->contents_flags; - - /* If this section has the SEC_SORT_ENTRIES flag set, it is a sorted - .cranges section passing through objcopy. */ - if ((bfd_get_section_flags (output_bfd, asect) & SEC_SORT_ENTRIES) != 0 - && strcmp (bfd_get_section_name (output_bfd, asect), - SH64_CRANGES_SECTION_NAME) == 0) - elf_section_hdr->sh_type = SHT_SH5_CR_SORTED; - - return TRUE; -} - -static bfd_boolean -sh64_elf_set_mach_from_flags (bfd *abfd) -{ - flagword flags = elf_elfheader (abfd)->e_flags; - - switch (flags & EF_SH_MACH_MASK) - { - case EF_SH5: - /* These are fit to execute on SH5. Just one but keep the switch - construct to make additions easy. */ - bfd_default_set_arch_mach (abfd, bfd_arch_sh, bfd_mach_sh5); - break; - - default: - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -sh64_elf_section_flags (flagword *flags, - const Elf_Internal_Shdr *hdr) -{ - if (hdr->bfd_section == NULL) - return FALSE; - - if (strcmp (hdr->bfd_section->name, SH64_CRANGES_SECTION_NAME) == 0) - *flags |= SEC_DEBUGGING; - - return TRUE; -} - -static bfd_boolean -sh64_elf_copy_private_data (bfd * ibfd, bfd * obfd) -{ - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - BFD_ASSERT (!elf_flags_init (obfd) - || (elf_elfheader (obfd)->e_flags - == elf_elfheader (ibfd)->e_flags)); - - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - - return _bfd_elf_copy_private_bfd_data (ibfd, obfd); -} - -static bfd_boolean -sh64_elf_merge_private_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, new_flags; - - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (bfd_get_arch_size (ibfd) != bfd_get_arch_size (obfd)) - { - const char *msg; - - if (bfd_get_arch_size (ibfd) == 32 - && bfd_get_arch_size (obfd) == 64) - /* xgettext:c-format */ - msg = _("%B: compiled as 32-bit object and %B is 64-bit"); - else if (bfd_get_arch_size (ibfd) == 64 - && bfd_get_arch_size (obfd) == 32) - /* xgettext:c-format */ - msg = _("%B: compiled as 64-bit object and %B is 32-bit"); - else - /* xgettext:c-format */ - msg = _("%B: object size does not match that of target %B"); - - _bfd_error_handler (msg, ibfd, obfd); - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - old_flags = elf_elfheader (obfd)->e_flags; - new_flags = elf_elfheader (ibfd)->e_flags; - if (! elf_flags_init (obfd)) - { - /* This happens when ld starts out with a 'blank' output file. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = old_flags = new_flags; - } - /* We don't allow linking in non-SH64 code. */ - else if ((new_flags & EF_SH_MACH_MASK) != EF_SH5) - { - _bfd_error_handler - ("%B: uses non-SH64 instructions while previous modules" - " use SH64 instructions", - ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* I can't think of anything sane other than old_flags being EF_SH5 and - that we need to preserve that. */ - elf_elfheader (obfd)->e_flags = old_flags; - return sh64_elf_set_mach_from_flags (obfd); -} - -/* Handle a SH64-specific section when reading an object file. This - is called when bfd_section_from_shdr finds a section with an unknown - type. - - We only recognize SHT_SH5_CR_SORTED, on the .cranges section. */ - -bfd_boolean -sh64_backend_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, - const char *name, int shindex) -{ - flagword flags = 0; - - /* We do like MIPS with a bit switch for recognized types, and returning - FALSE for a recognized section type with an unexpected name. Right - now we only have one recognized type, but that might change. */ - switch (hdr->sh_type) - { - case SHT_SH5_CR_SORTED: - if (strcmp (name, SH64_CRANGES_SECTION_NAME) != 0) - return FALSE; - - /* We set the SEC_SORT_ENTRIES flag so it can be passed on to - sh64_elf_fake_sections, keeping SHT_SH5_CR_SORTED if this object - passes through objcopy. Perhaps it is brittle; the flag can - suddenly be used by other BFD parts, but it seems not really used - anywhere at the moment. */ - flags = SEC_DEBUGGING | SEC_SORT_ENTRIES; - break; - - default: - return FALSE; - } - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - if (flags - && ! bfd_set_section_flags (abfd, hdr->bfd_section, - bfd_get_section_flags (abfd, - hdr->bfd_section) - | flags)) - return FALSE; - - return TRUE; -} - -/* In contrast to sh64_backend_section_from_shdr, this is called for all - sections, but only when copying sections, not when linking or - assembling. We need to set up the sh64_elf_section_data (asection *) - structure for the SH64 ELF section flags to be copied correctly. */ - -bfd_boolean -sh64_bfd_elf_copy_private_section_data (bfd *ibfd, asection *isec, - bfd *obfd, asection *osec) -{ - struct sh64_section_data *sh64_sec_data; - - if (ibfd->xvec->flavour != bfd_target_elf_flavour - || obfd->xvec->flavour != bfd_target_elf_flavour) - return TRUE; - - if (! _bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec)) - return FALSE; - - sh64_sec_data = sh64_elf_section_data (isec)->sh64_info; - if (sh64_sec_data == NULL) - { - sh64_sec_data = bfd_zmalloc (sizeof (struct sh64_section_data)); - - if (sh64_sec_data == NULL) - return FALSE; - - sh64_sec_data->contents_flags - = (elf_section_data (isec)->this_hdr.sh_flags - & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)); - - sh64_elf_section_data (osec)->sh64_info = sh64_sec_data; - } - - return TRUE; -} - -/* Function to keep SH64 specific file flags. */ - -static bfd_boolean -sh64_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (! elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return sh64_elf_set_mach_from_flags (abfd); -} - -/* Called when writing out an object file to decide the type of a symbol. */ - -static int -sh64_elf_get_symbol_type (Elf_Internal_Sym *elf_sym, int type) -{ - if (ELF_ST_TYPE (elf_sym->st_info) == STT_DATALABEL) - return STT_DATALABEL; - - return type; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We must make indirect symbols for undefined symbols marked with - STT_DATALABEL, so relocations passing them will pick up that attribute - and neutralize STO_SH5_ISA32 found on the symbol definition. - - There is a problem, though: We want to fill in the hash-table entry for - this symbol and signal to the caller that no further processing is - needed. But we don't have the index for this hash-table entry. We - rely here on that the current entry is the first hash-entry with NULL, - which seems brittle. Also, iterating over the hash-table to find that - entry is a linear operation on the number of symbols in this input - file, and this function should take constant time, so that's not good - too. Only comfort is that DataLabel references should only be found in - hand-written assembly code and thus be rare. FIXME: Talk maintainers - into adding an option to elf_add_symbol_hook (preferably) for the index - or the hash entry, alternatively adding the index to Elf_Internal_Sym - (not so good). */ - -static bfd_boolean -sh64_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, const char **namep, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, bfd_vma *valp) -{ - /* We want to do this for relocatable as well as final linking. */ - if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL - && is_elf_hash_table (info->hash)) - { - struct elf_link_hash_entry *h; - - /* For relocatable links, we register the DataLabel sym in its own - right, and tweak the name when it's output. Otherwise, we make - an indirect symbol of it. */ - flagword flags - = bfd_link_relocatable (info) || info->emitrelocations - ? BSF_GLOBAL : BSF_GLOBAL | BSF_INDIRECT; - - char *dl_name - = bfd_malloc (strlen (*namep) + sizeof (DATALABEL_SUFFIX)); - struct elf_link_hash_entry ** sym_hash = elf_sym_hashes (abfd); - - BFD_ASSERT (sym_hash != NULL); - - /* Allocation may fail. */ - if (dl_name == NULL) - return FALSE; - - strcpy (dl_name, *namep); - strcat (dl_name, DATALABEL_SUFFIX); - - h = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (info->hash, dl_name, FALSE, FALSE, FALSE); - - if (h == NULL) - { - /* No previous datalabel symbol. Make one. */ - struct bfd_link_hash_entry *bh = NULL; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - if (! _bfd_generic_link_add_one_symbol (info, abfd, dl_name, - flags, *secp, *valp, - *namep, FALSE, - bed->collect, &bh)) - { - free (dl_name); - return FALSE; - } - - h = (struct elf_link_hash_entry *) bh; - h->non_elf = 0; - h->type = STT_DATALABEL; - } - else - /* If a new symbol was created, it holds the allocated name. - Otherwise, we don't need it anymore and should deallocate it. */ - free (dl_name); - - if (h->type != STT_DATALABEL - || ((bfd_link_relocatable (info) || info->emitrelocations) - && h->root.type != bfd_link_hash_undefined) - || (! bfd_link_relocatable (info) && !info->emitrelocations - && h->root.type != bfd_link_hash_indirect)) - { - /* Make sure we don't get confused on invalid input. */ - _bfd_error_handler - (_("%B: encountered datalabel symbol in input"), abfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Now find the hash-table slot for this entry and fill it in. */ - while (*sym_hash != NULL) - sym_hash++; - *sym_hash = h; - - /* Signal to caller to skip this symbol - we've handled it. */ - *namep = NULL; - } - - return TRUE; -} - -/* This hook function is called before the linker writes out a global - symbol. For relocatable links, DataLabel symbols will be present in - linker output. We cut off the special suffix on those symbols, so the - right name appears in the output. - - When linking and emitting relocations, there can appear global symbols - that are not referenced by relocs, but rather only implicitly through - DataLabel references, a relation that is not visible to the linker. - Since no stripping of global symbols in done when doing such linking, - we don't need to look up and make sure to emit the main symbol for each - DataLabel symbol. */ - -static int -sh64_elf_link_output_symbol_hook (struct bfd_link_info *info, - const char *cname, - Elf_Internal_Sym *sym, - asection *input_sec ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - char *name = (char *) cname; - - if (bfd_link_relocatable (info) || info->emitrelocations) - { - if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL) - name[strlen (name) - strlen (DATALABEL_SUFFIX)] = 0; - } - - return 1; -} - -/* Check a SH64-specific reloc and put the value to relocate to into - RELOCATION, ready to pass to _bfd_final_link_relocate. Return FALSE if - bad value, TRUE if ok. */ - -static bfd_boolean -shmedia_prepare_reloc (struct bfd_link_info *info, bfd *abfd, - asection *input_section, bfd_byte *contents, - const Elf_Internal_Rela *rel, bfd_vma *relocation) -{ - bfd_vma disp, dropped; - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_SH_PT_16: - /* Check the lowest bit of the destination field. If it is 1, we - check the ISA type of the destination (i.e. the low bit of the - "relocation" value, and emit an error if the instruction does not - match). If it is 0, we change a PTA to PTB. There should never - be a PTB that should change to a PTA; that indicates a toolchain - error; a mismatch with GAS. */ - { - char *msg = NULL; - bfd_vma insn = bfd_get_32 (abfd, contents + rel->r_offset); - - if (insn & (1 << 10)) - { - /* Check matching insn and ISA (address of target). */ - if ((insn & SHMEDIA_PTB_BIT) != 0 - && ((*relocation + rel->r_addend) & 1) != 0) - msg = _("PTB mismatch: a SHmedia address (bit 0 == 1)"); - else if ((insn & SHMEDIA_PTB_BIT) == 0 - && ((*relocation + rel->r_addend) & 1) == 0) - msg = _("PTA mismatch: a SHcompact address (bit 0 == 0)"); - - if (msg != NULL) - (*info->callbacks->reloc_dangerous) - (info, msg, abfd, input_section, rel->r_offset); - } - else - { - /* We shouldn't get here with a PTB insn and a R_SH_PT_16. It - means GAS output does not match expectations; a PTA or PTB - expressed as such (or a PT found at assembly to be PTB) - would match the test above, and PT expansion with an - unknown destination (or when relaxing) will get us here. */ - if ((insn & SHMEDIA_PTB_BIT) != 0) - { - _bfd_error_handler - (_("%B: GAS error: unexpected PTB insn with R_SH_PT_16"), - input_section->owner); - return FALSE; - } - - /* Change the PTA to a PTB, if destination indicates so. */ - if (((*relocation + rel->r_addend) & 1) == 0) - bfd_put_32 (abfd, insn | SHMEDIA_PTB_BIT, - contents + rel->r_offset); - } - } - - case R_SH_SHMEDIA_CODE: - case R_SH_DIR5U: - case R_SH_DIR6S: - case R_SH_DIR6U: - case R_SH_DIR10S: - case R_SH_DIR10SW: - case R_SH_DIR10SL: - case R_SH_DIR10SQ: - case R_SH_IMMS16: - case R_SH_IMMU16: - case R_SH_IMM_LOW16: - case R_SH_IMM_LOW16_PCREL: - case R_SH_IMM_MEDLOW16: - case R_SH_IMM_MEDLOW16_PCREL: - case R_SH_IMM_MEDHI16: - case R_SH_IMM_MEDHI16_PCREL: - case R_SH_IMM_HI16: - case R_SH_IMM_HI16_PCREL: - case R_SH_64: - case R_SH_64_PCREL: - break; - - default: - return FALSE; - } - - disp = (*relocation & 0xf); - dropped = 0; - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_SH_DIR10SW: dropped = disp & 1; break; - case R_SH_DIR10SL: dropped = disp & 3; break; - case R_SH_DIR10SQ: dropped = disp & 7; break; - } - if (dropped != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: error: unaligned relocation type %d at %#Lx reloc %#Lx"), - input_section->owner, (int) ELF32_R_TYPE (rel->r_info), - rel->r_offset, *relocation); - return FALSE; - } - - return TRUE; -} - -/* Helper function to locate the section holding a certain address. This - is called via bfd_map_over_sections. */ - -static void -sh64_find_section_for_address (bfd *abfd ATTRIBUTE_UNUSED, - asection *section, void *data) -{ - bfd_vma vma; - bfd_size_type size; - - struct sh64_find_section_vma_data *fsec_datap - = (struct sh64_find_section_vma_data *) data; - - /* Return if already found. */ - if (fsec_datap->section) - return; - - /* If this section isn't part of the addressable contents, skip it. */ - if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) - return; - - vma = bfd_get_section_vma (abfd, section); - if (fsec_datap->addr < vma) - return; - - size = section->size; - if (fsec_datap->addr >= vma + size) - return; - - fsec_datap->section = section; -} - -/* Make sure to write out the generated entries in the .cranges section - when doing partial linking, and set bit 0 on the entry address if it - points to SHmedia code and write sorted .cranges entries when writing - executables (final linking and objcopy). */ - -static void -sh64_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - bfd_vma ld_generated_cranges_size; - asection *cranges - = bfd_get_section_by_name (abfd, SH64_CRANGES_SECTION_NAME); - - /* If no new .cranges were added, the generic ELF linker parts will - write it all out. If not, we need to write them out when doing - partial linking. For a final link, we will sort them and write them - all out further below. */ - if (linker - && cranges != NULL - && elf_elfheader (abfd)->e_type != ET_EXEC - && (ld_generated_cranges_size - = sh64_elf_section_data (cranges)->sh64_info->cranges_growth) != 0) - { - bfd_vma incoming_cranges_size - = cranges->size - ld_generated_cranges_size; - - if (! bfd_set_section_contents (abfd, cranges, - cranges->contents - + incoming_cranges_size, - cranges->output_offset - + incoming_cranges_size, - ld_generated_cranges_size)) - { - bfd_set_error (bfd_error_file_truncated); - _bfd_error_handler - (_("%B: could not write out added .cranges entries"), abfd); - } - } - - /* Only set entry address bit 0 and sort .cranges when linking to an - executable; never with objcopy or strip. */ - if (linker && elf_elfheader (abfd)->e_type == ET_EXEC) - { - struct sh64_find_section_vma_data fsec_data; - sh64_elf_crange dummy; - - /* For a final link, set the low bit of the entry address to - reflect whether or not it is a SHmedia address. - FIXME: Perhaps we shouldn't do this if the entry address was - supplied numerically, but we currently lack the infrastructure to - recognize that: The entry symbol, and info whether it is numeric - or a symbol name is kept private in the linker. */ - fsec_data.addr = elf_elfheader (abfd)->e_entry; - fsec_data.section = NULL; - - bfd_map_over_sections (abfd, sh64_find_section_for_address, - &fsec_data); - if (fsec_data.section - && (sh64_get_contents_type (fsec_data.section, - elf_elfheader (abfd)->e_entry, - &dummy) == CRT_SH5_ISA32)) - elf_elfheader (abfd)->e_entry |= 1; - - /* If we have a .cranges section, sort the entries. */ - if (cranges != NULL) - { - bfd_size_type cranges_size = cranges->size; - - /* We know we always have these in memory at this time. */ - BFD_ASSERT (cranges->contents != NULL); - - /* The .cranges may already have been sorted in the process of - finding out the ISA-type of the entry address. If not, we do - it here. */ - if (elf_section_data (cranges)->this_hdr.sh_type - != SHT_SH5_CR_SORTED) - { - qsort (cranges->contents, cranges_size / SH64_CRANGE_SIZE, - SH64_CRANGE_SIZE, - bfd_big_endian (cranges->owner) - ? _bfd_sh64_crange_qsort_cmpb - : _bfd_sh64_crange_qsort_cmpl); - elf_section_data (cranges)->this_hdr.sh_type - = SHT_SH5_CR_SORTED; - } - - /* We need to write it out in whole as sorted. */ - if (! bfd_set_section_contents (abfd, cranges, - cranges->contents, - cranges->output_offset, - cranges_size)) - { - bfd_set_error (bfd_error_file_truncated); - _bfd_error_handler - (_("%B: could not write out sorted .cranges entries"), abfd); - } - } - } -} - -/* Merge non visibility st_other attribute when the symbol comes from - a dynamic object. */ -static void -sh64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic ATTRIBUTE_UNUSED) -{ - if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0) - { - unsigned char other; - - /* Take the balance of OTHER from the definition. */ - other = (definition ? isym->st_other : h->other); - other &= ~ ELF_ST_VISIBILITY (-1); - h->other = other | ELF_ST_VISIBILITY (h->other); - } - - return; -} - -static const struct bfd_elf_special_section sh64_elf_special_sections[] = -{ - { STRING_COMMA_LEN (".cranges"), 0, SHT_PROGBITS, 0 }, - { NULL, 0, 0, 0, 0 } -}; - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh64_elf32_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sh64" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh64_elf32_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-sh64l" - -#include "elf32-target.h" - -/* NetBSD support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh64_elf32_nbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sh64-nbsd" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh64_elf32_nbsd_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-sh64l-nbsd" -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x10000 -#undef ELF_COMMONPAGESIZE -#undef elf_symbol_leading_char -#define elf_symbol_leading_char 0 -#undef elf32_bed -#define elf32_bed elf32_sh64_nbsd_bed - -#include "elf32-target.h" - -/* Linux support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh64_elf32_linux_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sh64big-linux" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh64_elf32_linux_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-sh64-linux" -#undef elf32_bed -#define elf32_bed elf32_sh64_lin_bed -#undef ELF_COMMONPAGESIZE -#define ELF_COMMONPAGESIZE 0x1000 - -#include "elf32-target.h" - diff --git a/sdcc/support/sdbinutils/bfd/elf32-sh64.h b/sdcc/support/sdbinutils/bfd/elf32-sh64.h deleted file mode 100644 index 83065e7a8..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sh64.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SH ELF support for BFD. - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#ifndef ELF32_SH64_H -#define ELF32_SH64_H - -#define SH64_CRANGES_SECTION_NAME ".cranges" -enum sh64_elf_cr_type { - CRT_NONE = 0, - CRT_DATA = 1, - CRT_SH5_ISA16 = 2, - CRT_SH5_ISA32 = 3 -}; - -/* The official definition is this: - - typedef struct { - Elf32_Addr cr_addr; - Elf32_Word cr_size; - Elf32_Half cr_type; - } Elf32_CRange; - - but we have no use for that exact type. Instead we use this struct for - the internal representation. */ -typedef struct { - bfd_vma cr_addr; - bfd_size_type cr_size; - enum sh64_elf_cr_type cr_type; -} sh64_elf_crange; - -#define SH64_CRANGE_SIZE (4 + 4 + 2) -#define SH64_CRANGE_CR_ADDR_OFFSET 0 -#define SH64_CRANGE_CR_SIZE_OFFSET 4 -#define SH64_CRANGE_CR_TYPE_OFFSET (4 + 4) - -/* Get the contents type of an arbitrary address, or return CRT_NONE. */ -extern enum sh64_elf_cr_type sh64_get_contents_type - (asection *, bfd_vma, sh64_elf_crange *); - -/* Simpler interface. - FIXME: This seems redundant now that we export the interface above. */ -extern bfd_boolean sh64_address_is_shmedia - (asection *, bfd_vma); - -extern int _bfd_sh64_crange_qsort_cmpb - (const void *, const void *); -extern int _bfd_sh64_crange_qsort_cmpl - (const void *, const void *); -extern int _bfd_sh64_crange_bsearch_cmpb - (const void *, const void *); -extern int _bfd_sh64_crange_bsearch_cmpl - (const void *, const void *); - -struct sh64_section_data -{ - flagword contents_flags; - - /* Only used in the cranges section, but we don't have an official - backend-specific bfd field. */ - bfd_size_type cranges_growth; -}; - -struct _sh64_elf_section_data -{ - struct bfd_elf_section_data elf; - struct sh64_section_data *sh64_info; -}; - -#define sh64_elf_section_data(sec) \ - ((struct _sh64_elf_section_data *) elf_section_data (sec)) - -#endif /* ELF32_SH64_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-sparc.c b/sdcc/support/sdbinutils/bfd/elf32-sparc.c deleted file mode 100644 index e8ca810d4..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-sparc.c +++ /dev/null @@ -1,360 +0,0 @@ -/* SPARC-specific support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/sparc.h" -#include "opcode/sparc.h" -#include "elfxx-sparc.h" -#include "elf-vxworks.h" - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf32_sparc_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 260: /* Solaris prpsinfo_t. */ - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 84, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 100, 80); - break; - - case 336: /* Solaris psinfo_t. */ - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 88, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 104, 80); - break; - } - - return TRUE; -} - -/* Functions for dealing with the e_flags field. - - We don't define set_private_flags or copy_private_bfd_data because - the only currently defined values are based on the bfd mach number, - so we use the latter instead and defer setting e_flags until the - file is written out. */ - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf32_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - bfd_boolean error; - unsigned long ibfd_mach; - /* FIXME: This should not be static. */ - static unsigned long previous_ibfd_e_flags = (unsigned long) -1; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - error = FALSE; - - ibfd_mach = bfd_get_mach (ibfd); - if (bfd_mach_sparc_64bit_p (ibfd_mach)) - { - error = TRUE; - _bfd_error_handler - (_("%B: compiled for a 64 bit system and target is 32 bit"), ibfd); - } - else if ((ibfd->flags & DYNAMIC) == 0) - { - if (bfd_get_mach (obfd) < ibfd_mach) - bfd_set_arch_mach (obfd, bfd_arch_sparc, ibfd_mach); - } - - if (((elf_elfheader (ibfd)->e_flags & EF_SPARC_LEDATA) - != previous_ibfd_e_flags) - && previous_ibfd_e_flags != (unsigned long) -1) - { - _bfd_error_handler - (_("%B: linking little endian files with big endian files"), ibfd); - error = TRUE; - } - previous_ibfd_e_flags = elf_elfheader (ibfd)->e_flags & EF_SPARC_LEDATA; - - if (error) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info); -} - -/* The final processing done just before writing out the object file. - We need to set the e_machine field appropriately. */ - -static void -elf32_sparc_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - switch (bfd_get_mach (abfd)) - { - case bfd_mach_sparc : - case bfd_mach_sparc_sparclet : - case bfd_mach_sparc_sparclite : - break; /* nothing to do */ - case bfd_mach_sparc_v8plus : - elf_elfheader (abfd)->e_machine = EM_SPARC32PLUS; - elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; - elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS; - break; - case bfd_mach_sparc_v8plusa : - elf_elfheader (abfd)->e_machine = EM_SPARC32PLUS; - elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; - elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS | EF_SPARC_SUN_US1; - break; - case bfd_mach_sparc_v8plusb : - case bfd_mach_sparc_v8plusc : - case bfd_mach_sparc_v8plusd : - case bfd_mach_sparc_v8pluse : - case bfd_mach_sparc_v8plusv : - case bfd_mach_sparc_v8plusm : - case bfd_mach_sparc_v8plusm8 : - elf_elfheader (abfd)->e_machine = EM_SPARC32PLUS; - elf_elfheader (abfd)->e_flags &=~ EF_SPARC_32PLUS_MASK; - elf_elfheader (abfd)->e_flags |= EF_SPARC_32PLUS | EF_SPARC_SUN_US1 - | EF_SPARC_SUN_US3; - break; - case bfd_mach_sparc_sparclite_le : - elf_elfheader (abfd)->e_flags |= EF_SPARC_LEDATA; - break; - default : - abort (); - break; - } -} - -static enum elf_reloc_type_class -elf32_sparc_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_SPARC_RELATIVE: - return reloc_class_relative; - case R_SPARC_JMP_SLOT: - return reloc_class_plt; - case R_SPARC_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Hook called by the linker routine which adds symbols from an object - file. */ - -static bfd_boolean -elf32_sparc_add_symbol_hook (bfd * abfd, - struct bfd_link_info * info, - Elf_Internal_Sym * sym, - const char ** namep ATTRIBUTE_UNUSED, - flagword * flagsp ATTRIBUTE_UNUSED, - asection ** secp ATTRIBUTE_UNUSED, - bfd_vma * valp ATTRIBUTE_UNUSED) -{ - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - return TRUE; -} - -#define TARGET_BIG_SYM sparc_elf32_vec -#define TARGET_BIG_NAME "elf32-sparc" -#define ELF_ARCH bfd_arch_sparc -#define ELF_TARGET_ID SPARC_ELF_DATA -#define ELF_MACHINE_CODE EM_SPARC -#define ELF_MACHINE_ALT1 EM_SPARC32PLUS -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x2000 - -#define bfd_elf32_bfd_merge_private_bfd_data \ - elf32_sparc_merge_private_bfd_data -#define elf_backend_final_write_processing \ - elf32_sparc_final_write_processing -#define elf_backend_grok_psinfo elf32_sparc_grok_psinfo -#define elf_backend_reloc_type_class elf32_sparc_reloc_type_class - -#define elf_info_to_howto _bfd_sparc_elf_info_to_howto -#define bfd_elf32_bfd_reloc_type_lookup _bfd_sparc_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - _bfd_sparc_elf_reloc_name_lookup -#define bfd_elf32_bfd_link_hash_table_create \ - _bfd_sparc_elf_link_hash_table_create -#define bfd_elf32_bfd_relax_section _bfd_sparc_elf_relax_section -#define bfd_elf32_new_section_hook _bfd_sparc_elf_new_section_hook -#define elf_backend_copy_indirect_symbol \ - _bfd_sparc_elf_copy_indirect_symbol -#define elf_backend_create_dynamic_sections \ - _bfd_sparc_elf_create_dynamic_sections -#define elf_backend_check_relocs _bfd_sparc_elf_check_relocs -#define elf_backend_adjust_dynamic_symbol \ - _bfd_sparc_elf_adjust_dynamic_symbol -#define elf_backend_omit_section_dynsym _bfd_sparc_elf_omit_section_dynsym -#define elf_backend_size_dynamic_sections \ - _bfd_sparc_elf_size_dynamic_sections -#define elf_backend_relocate_section _bfd_sparc_elf_relocate_section -#define elf_backend_finish_dynamic_symbol \ - _bfd_sparc_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_sparc_elf_finish_dynamic_sections -#define bfd_elf32_mkobject _bfd_sparc_elf_mkobject -#define elf_backend_object_p _bfd_sparc_elf_object_p -#define elf_backend_gc_mark_hook _bfd_sparc_elf_gc_mark_hook -#define elf_backend_plt_sym_val _bfd_sparc_elf_plt_sym_val -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_fixup_symbol _bfd_sparc_elf_fixup_symbol - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 0 -#define elf_backend_want_plt_sym 1 -#define elf_backend_got_header_size 4 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 - -#define elf_backend_add_symbol_hook elf32_sparc_add_symbol_hook - -#define elf_backend_linux_prpsinfo32_ugid16 TRUE - -#include "elf32-target.h" - -/* Solaris 2. */ - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sparc_elf32_sol2_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sparc-sol2" - -#undef elf32_bed -#define elf32_bed elf32_sparc_sol2_bed - -/* The 32-bit static TLS arena size is rounded to the nearest 8-byte - boundary. */ -#undef elf_backend_static_tls_alignment -#define elf_backend_static_tls_alignment 8 - -#undef elf_backend_strtab_flags -#define elf_backend_strtab_flags SHF_STRINGS - -static bfd_boolean -elf32_sparc_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED, - bfd *obfd ATTRIBUTE_UNUSED, - const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *osection ATTRIBUTE_UNUSED) -{ - /* PR 19938: FIXME: Need to add code for setting the sh_info - and sh_link fields of Solaris specific section types. */ - return FALSE; -} - -#undef elf_backend_copy_special_section_fields -#define elf_backend_copy_special_section_fields elf32_sparc_copy_solaris_special_section_fields - -#include "elf32-target.h" - -/* A wrapper around _bfd_sparc_elf_link_hash_table_create that identifies - the target system as VxWorks. */ - -static struct bfd_link_hash_table * -elf32_sparc_vxworks_link_hash_table_create (bfd *abfd) -{ - struct bfd_link_hash_table *ret; - - ret = _bfd_sparc_elf_link_hash_table_create (abfd); - if (ret) - { - struct _bfd_sparc_elf_link_hash_table *htab; - - htab = (struct _bfd_sparc_elf_link_hash_table *) ret; - htab->is_vxworks = 1; - } - return ret; -} - -/* A final_write_processing hook that does both the SPARC- and VxWorks- - specific handling. */ - -static void -elf32_sparc_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) -{ - elf32_sparc_final_write_processing (abfd, linker); - elf_vxworks_final_write_processing (abfd, linker); -} - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sparc_elf32_vxworks_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-sparc-vxworks" - -#undef ELF_MINPAGESIZE -#define ELF_MINPAGESIZE 0x1000 - -#undef bfd_elf32_bfd_link_hash_table_create -#define bfd_elf32_bfd_link_hash_table_create \ - elf32_sparc_vxworks_link_hash_table_create - -#undef elf_backend_want_got_plt -#define elf_backend_want_got_plt 1 -#undef elf_backend_plt_readonly -#define elf_backend_plt_readonly 1 -#undef elf_backend_got_header_size -#define elf_backend_got_header_size 12 -#undef elf_backend_dtrel_excludes_plt -#define elf_backend_dtrel_excludes_plt 1 -#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 \ - elf32_sparc_vxworks_final_write_processing -#undef elf_backend_static_tls_alignment -#undef elf_backend_strtab_flags -#undef elf_backend_copy_special_section_fields - -#undef elf32_bed -#define elf32_bed sparc_elf_vxworks_bed - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-spu.c b/sdcc/support/sdbinutils/bfd/elf32-spu.c deleted file mode 100644 index 941ae58ee..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-spu.c +++ /dev/null @@ -1,5512 +0,0 @@ -/* SPU specific support for 32-bit ELF - - Copyright (C) 2006-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "libiberty.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/spu.h" -#include "elf32-spu.h" - -/* We use RELA style relocs. Don't define USE_REL. */ - -static bfd_reloc_status_type spu_elf_rel9 (bfd *, arelent *, asymbol *, - void *, asection *, - bfd *, char **); - -/* Values of type 'enum elf_spu_reloc_type' are used to index this - array, so it must be declared in the order of that type. */ - -static reloc_howto_type elf_howto_table[] = { - HOWTO (R_SPU_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_NONE", - FALSE, 0, 0x00000000, FALSE), - HOWTO (R_SPU_ADDR10, 4, 2, 10, FALSE, 14, complain_overflow_bitfield, - bfd_elf_generic_reloc, "SPU_ADDR10", - FALSE, 0, 0x00ffc000, FALSE), - HOWTO (R_SPU_ADDR16, 2, 2, 16, FALSE, 7, complain_overflow_bitfield, - bfd_elf_generic_reloc, "SPU_ADDR16", - FALSE, 0, 0x007fff80, FALSE), - HOWTO (R_SPU_ADDR16_HI, 16, 2, 16, FALSE, 7, complain_overflow_bitfield, - bfd_elf_generic_reloc, "SPU_ADDR16_HI", - FALSE, 0, 0x007fff80, FALSE), - HOWTO (R_SPU_ADDR16_LO, 0, 2, 16, FALSE, 7, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_ADDR16_LO", - FALSE, 0, 0x007fff80, FALSE), - HOWTO (R_SPU_ADDR18, 0, 2, 18, FALSE, 7, complain_overflow_bitfield, - bfd_elf_generic_reloc, "SPU_ADDR18", - FALSE, 0, 0x01ffff80, FALSE), - HOWTO (R_SPU_ADDR32, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_ADDR32", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_SPU_REL16, 2, 2, 16, TRUE, 7, complain_overflow_bitfield, - bfd_elf_generic_reloc, "SPU_REL16", - FALSE, 0, 0x007fff80, TRUE), - HOWTO (R_SPU_ADDR7, 0, 2, 7, FALSE, 14, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_ADDR7", - FALSE, 0, 0x001fc000, FALSE), - HOWTO (R_SPU_REL9, 2, 2, 9, TRUE, 0, complain_overflow_signed, - spu_elf_rel9, "SPU_REL9", - FALSE, 0, 0x0180007f, TRUE), - HOWTO (R_SPU_REL9I, 2, 2, 9, TRUE, 0, complain_overflow_signed, - spu_elf_rel9, "SPU_REL9I", - FALSE, 0, 0x0000c07f, TRUE), - HOWTO (R_SPU_ADDR10I, 0, 2, 10, FALSE, 14, complain_overflow_signed, - bfd_elf_generic_reloc, "SPU_ADDR10I", - FALSE, 0, 0x00ffc000, FALSE), - HOWTO (R_SPU_ADDR16I, 0, 2, 16, FALSE, 7, complain_overflow_signed, - bfd_elf_generic_reloc, "SPU_ADDR16I", - FALSE, 0, 0x007fff80, FALSE), - HOWTO (R_SPU_REL32, 0, 2, 32, TRUE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_REL32", - FALSE, 0, 0xffffffff, TRUE), - HOWTO (R_SPU_ADDR16X, 0, 2, 16, FALSE, 7, complain_overflow_bitfield, - bfd_elf_generic_reloc, "SPU_ADDR16X", - FALSE, 0, 0x007fff80, FALSE), - HOWTO (R_SPU_PPU32, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_PPU32", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_SPU_PPU64, 0, 4, 64, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_PPU64", - FALSE, 0, -1, FALSE), - HOWTO (R_SPU_ADD_PIC, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "SPU_ADD_PIC", - FALSE, 0, 0x00000000, FALSE), -}; - -static struct bfd_elf_special_section const spu_elf_special_sections[] = { - { "._ea", 4, 0, SHT_PROGBITS, SHF_WRITE }, - { ".toe", 4, 0, SHT_NOBITS, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } -}; - -static enum elf_spu_reloc_type -spu_elf_bfd_to_reloc_type (bfd_reloc_code_real_type code) -{ - switch (code) - { - default: - return (enum elf_spu_reloc_type) -1; - case BFD_RELOC_NONE: - return R_SPU_NONE; - case BFD_RELOC_SPU_IMM10W: - return R_SPU_ADDR10; - case BFD_RELOC_SPU_IMM16W: - return R_SPU_ADDR16; - case BFD_RELOC_SPU_LO16: - return R_SPU_ADDR16_LO; - case BFD_RELOC_SPU_HI16: - return R_SPU_ADDR16_HI; - case BFD_RELOC_SPU_IMM18: - return R_SPU_ADDR18; - case BFD_RELOC_SPU_PCREL16: - return R_SPU_REL16; - case BFD_RELOC_SPU_IMM7: - return R_SPU_ADDR7; - case BFD_RELOC_SPU_IMM8: - return R_SPU_NONE; - case BFD_RELOC_SPU_PCREL9a: - return R_SPU_REL9; - case BFD_RELOC_SPU_PCREL9b: - return R_SPU_REL9I; - case BFD_RELOC_SPU_IMM10: - return R_SPU_ADDR10I; - case BFD_RELOC_SPU_IMM16: - return R_SPU_ADDR16I; - case BFD_RELOC_32: - return R_SPU_ADDR32; - case BFD_RELOC_32_PCREL: - return R_SPU_REL32; - case BFD_RELOC_SPU_PPU32: - return R_SPU_PPU32; - case BFD_RELOC_SPU_PPU64: - return R_SPU_PPU64; - case BFD_RELOC_SPU_ADD_PIC: - return R_SPU_ADD_PIC; - } -} - -static void -spu_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - enum elf_spu_reloc_type r_type; - - r_type = (enum elf_spu_reloc_type) ELF32_R_TYPE (dst->r_info); - /* PR 17512: file: 90c2a92e. */ - if (r_type >= R_SPU_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised SPU reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_SPU_NONE; - } - cache_ptr->howto = &elf_howto_table[(int) r_type]; -} - -static reloc_howto_type * -spu_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - enum elf_spu_reloc_type r_type = spu_elf_bfd_to_reloc_type (code); - - if (r_type == (enum elf_spu_reloc_type) -1) - return NULL; - - return elf_howto_table + r_type; -} - -static reloc_howto_type * -spu_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - return NULL; -} - -/* Apply R_SPU_REL9 and R_SPU_REL9I relocs. */ - -static bfd_reloc_status_type -spu_elf_rel9 (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - bfd_size_type octets; - bfd_vma val; - long insn; - - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - octets = reloc_entry->address * bfd_octets_per_byte (abfd); - - /* Get symbol value. */ - val = 0; - if (!bfd_is_com_section (symbol->section)) - val = symbol->value; - if (symbol->section->output_section) - val += symbol->section->output_section->vma; - - val += reloc_entry->addend; - - /* Make it pc-relative. */ - val -= input_section->output_section->vma + input_section->output_offset; - - val >>= 2; - if (val + 256 >= 512) - return bfd_reloc_overflow; - - insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); - - /* Move two high bits of value to REL9I and REL9 position. - The mask will take care of selecting the right field. */ - val = (val & 0x7f) | ((val & 0x180) << 7) | ((val & 0x180) << 16); - insn &= ~reloc_entry->howto->dst_mask; - insn |= val & reloc_entry->howto->dst_mask; - bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); - return bfd_reloc_ok; -} - -static bfd_boolean -spu_elf_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - struct _spu_elf_section_data *sdata; - - sdata = bfd_zalloc (abfd, sizeof (*sdata)); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - -/* Set up overlay info for executables. */ - -static bfd_boolean -spu_elf_object_p (bfd *abfd) -{ - if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) - { - unsigned int i, num_ovl, num_buf; - Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; - Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd); - Elf_Internal_Phdr *last_phdr = NULL; - - for (num_buf = 0, num_ovl = 0, i = 0; i < ehdr->e_phnum; i++, phdr++) - if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_OVERLAY) != 0) - { - unsigned int j; - - ++num_ovl; - if (last_phdr == NULL - || ((last_phdr->p_vaddr ^ phdr->p_vaddr) & 0x3ffff) != 0) - ++num_buf; - last_phdr = phdr; - for (j = 1; j < elf_numsections (abfd); j++) - { - Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[j]; - - if (ELF_SECTION_SIZE (shdr, phdr) != 0 - && ELF_SECTION_IN_SEGMENT (shdr, phdr)) - { - asection *sec = shdr->bfd_section; - spu_elf_section_data (sec)->u.o.ovl_index = num_ovl; - spu_elf_section_data (sec)->u.o.ovl_buf = num_buf; - } - } - } - } - return TRUE; -} - -/* Specially mark defined symbols named _EAR_* with BSF_KEEP so that - strip --strip-unneeded will not remove them. */ - -static void -spu_elf_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) -{ - if (sym->name != NULL - && sym->section != bfd_abs_section_ptr - && strncmp (sym->name, "_EAR_", 5) == 0) - sym->flags |= BSF_KEEP; -} - -/* SPU ELF linker hash table. */ - -struct spu_link_hash_table -{ - struct elf_link_hash_table elf; - - struct spu_elf_params *params; - - /* Shortcuts to overlay sections. */ - asection *ovtab; - asection *init; - asection *toe; - asection **ovl_sec; - - /* Count of stubs in each overlay section. */ - unsigned int *stub_count; - - /* The stub section for each overlay section. */ - asection **stub_sec; - - struct elf_link_hash_entry *ovly_entry[2]; - - /* Number of overlay buffers. */ - unsigned int num_buf; - - /* Total number of overlays. */ - unsigned int num_overlays; - - /* For soft icache. */ - unsigned int line_size_log2; - unsigned int num_lines_log2; - unsigned int fromelem_size_log2; - - /* How much memory we have. */ - unsigned int local_store; - - /* Count of overlay stubs needed in non-overlay area. */ - unsigned int non_ovly_stub; - - /* Pointer to the fixup section */ - asection *sfixup; - - /* Set on error. */ - unsigned int stub_err : 1; -}; - -/* Hijack the generic got fields for overlay stub accounting. */ - -struct got_entry -{ - struct got_entry *next; - unsigned int ovl; - union { - bfd_vma addend; - bfd_vma br_addr; - }; - bfd_vma stub_addr; -}; - -#define spu_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == SPU_ELF_DATA ? ((struct spu_link_hash_table *) ((p)->hash)) : NULL) - -struct call_info -{ - struct function_info *fun; - struct call_info *next; - unsigned int count; - unsigned int max_depth; - unsigned int is_tail : 1; - unsigned int is_pasted : 1; - unsigned int broken_cycle : 1; - unsigned int priority : 13; -}; - -struct function_info -{ - /* List of functions called. Also branches to hot/cold part of - function. */ - struct call_info *call_list; - /* For hot/cold part of function, point to owner. */ - struct function_info *start; - /* Symbol at start of function. */ - union { - Elf_Internal_Sym *sym; - struct elf_link_hash_entry *h; - } u; - /* Function section. */ - asection *sec; - asection *rodata; - /* Where last called from, and number of sections called from. */ - asection *last_caller; - unsigned int call_count; - /* Address range of (this part of) function. */ - bfd_vma lo, hi; - /* Offset where we found a store of lr, or -1 if none found. */ - bfd_vma lr_store; - /* Offset where we found the stack adjustment insn. */ - bfd_vma sp_adjust; - /* Stack usage. */ - int stack; - /* Distance from root of call tree. Tail and hot/cold branches - count as one deeper. We aren't counting stack frames here. */ - unsigned int depth; - /* Set if global symbol. */ - unsigned int global : 1; - /* Set if known to be start of function (as distinct from a hunk - in hot/cold section. */ - unsigned int is_func : 1; - /* Set if not a root node. */ - unsigned int non_root : 1; - /* Flags used during call tree traversal. It's cheaper to replicate - the visit flags than have one which needs clearing after a traversal. */ - unsigned int visit1 : 1; - unsigned int visit2 : 1; - unsigned int marking : 1; - unsigned int visit3 : 1; - unsigned int visit4 : 1; - unsigned int visit5 : 1; - unsigned int visit6 : 1; - unsigned int visit7 : 1; -}; - -struct spu_elf_stack_info -{ - int num_fun; - int max_fun; - /* Variable size array describing functions, one per contiguous - address range belonging to a function. */ - struct function_info fun[1]; -}; - -static struct function_info *find_function (asection *, bfd_vma, - struct bfd_link_info *); - -/* Create a spu ELF linker hash table. */ - -static struct bfd_link_hash_table * -spu_elf_link_hash_table_create (bfd *abfd) -{ - struct spu_link_hash_table *htab; - - htab = bfd_zmalloc (sizeof (*htab)); - if (htab == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, - _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry), - SPU_ELF_DATA)) - { - free (htab); - return NULL; - } - - htab->elf.init_got_refcount.refcount = 0; - htab->elf.init_got_refcount.glist = NULL; - htab->elf.init_got_offset.offset = 0; - htab->elf.init_got_offset.glist = NULL; - return &htab->elf.root; -} - -void -spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params) -{ - bfd_vma max_branch_log2; - - struct spu_link_hash_table *htab = spu_hash_table (info); - htab->params = params; - htab->line_size_log2 = bfd_log2 (htab->params->line_size); - htab->num_lines_log2 = bfd_log2 (htab->params->num_lines); - - /* For the software i-cache, we provide a "from" list whose size - is a power-of-two number of quadwords, big enough to hold one - byte per outgoing branch. Compute this number here. */ - max_branch_log2 = bfd_log2 (htab->params->max_branch); - htab->fromelem_size_log2 = max_branch_log2 > 4 ? max_branch_log2 - 4 : 0; -} - -/* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP - to (hash, NULL) for global symbols, and (NULL, sym) for locals. Set - *SYMSECP to the symbol's section. *LOCSYMSP caches local syms. */ - -static bfd_boolean -get_sym_h (struct elf_link_hash_entry **hp, - Elf_Internal_Sym **symp, - asection **symsecp, - Elf_Internal_Sym **locsymsp, - unsigned long r_symndx, - bfd *ibfd) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - - if (r_symndx >= symtab_hdr->sh_info) - { - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); - struct elf_link_hash_entry *h; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (hp != NULL) - *hp = h; - - if (symp != NULL) - *symp = NULL; - - if (symsecp != NULL) - { - asection *symsec = NULL; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - symsec = h->root.u.def.section; - *symsecp = symsec; - } - } - else - { - Elf_Internal_Sym *sym; - Elf_Internal_Sym *locsyms = *locsymsp; - - if (locsyms == NULL) - { - locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (locsyms == NULL) - locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, - symtab_hdr->sh_info, - 0, NULL, NULL, NULL); - if (locsyms == NULL) - return FALSE; - *locsymsp = locsyms; - } - sym = locsyms + r_symndx; - - if (hp != NULL) - *hp = NULL; - - if (symp != NULL) - *symp = sym; - - if (symsecp != NULL) - *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx); - } - - return TRUE; -} - -/* Create the note section if not already present. This is done early so - that the linker maps the sections to the right place in the output. */ - -bfd_boolean -spu_elf_create_sections (struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - bfd *ibfd; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - if (bfd_get_section_by_name (ibfd, SPU_PTNOTE_SPUNAME) != NULL) - break; - - if (ibfd == NULL) - { - /* Make SPU_PTNOTE_SPUNAME section. */ - asection *s; - size_t name_len; - size_t size; - bfd_byte *data; - flagword flags; - - ibfd = info->input_bfds; - flags = SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY; - s = bfd_make_section_anyway_with_flags (ibfd, SPU_PTNOTE_SPUNAME, flags); - if (s == NULL - || !bfd_set_section_alignment (ibfd, s, 4)) - return FALSE; - - name_len = strlen (bfd_get_filename (info->output_bfd)) + 1; - size = 12 + ((sizeof (SPU_PLUGIN_NAME) + 3) & -4); - size += (name_len + 3) & -4; - - if (!bfd_set_section_size (ibfd, s, size)) - return FALSE; - - data = bfd_zalloc (ibfd, size); - if (data == NULL) - return FALSE; - - bfd_put_32 (ibfd, sizeof (SPU_PLUGIN_NAME), data + 0); - bfd_put_32 (ibfd, name_len, data + 4); - bfd_put_32 (ibfd, 1, data + 8); - memcpy (data + 12, SPU_PLUGIN_NAME, sizeof (SPU_PLUGIN_NAME)); - memcpy (data + 12 + ((sizeof (SPU_PLUGIN_NAME) + 3) & -4), - bfd_get_filename (info->output_bfd), name_len); - s->contents = data; - } - - if (htab->params->emit_fixups) - { - asection *s; - flagword flags; - - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = ibfd; - ibfd = htab->elf.dynobj; - flags = (SEC_LOAD | SEC_ALLOC | SEC_READONLY | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - s = bfd_make_section_anyway_with_flags (ibfd, ".fixup", flags); - if (s == NULL || !bfd_set_section_alignment (ibfd, s, 2)) - return FALSE; - htab->sfixup = s; - } - - return TRUE; -} - -/* qsort predicate to sort sections by vma. */ - -static int -sort_sections (const void *a, const void *b) -{ - const asection *const *s1 = a; - const asection *const *s2 = b; - bfd_signed_vma delta = (*s1)->vma - (*s2)->vma; - - if (delta != 0) - return delta < 0 ? -1 : 1; - - return (*s1)->index - (*s2)->index; -} - -/* Identify overlays in the output bfd, and number them. - Returns 0 on error, 1 if no overlays, 2 if overlays. */ - -int -spu_elf_find_overlays (struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - asection **alloc_sec; - unsigned int i, n, ovl_index, num_buf; - asection *s; - bfd_vma ovl_end; - static const char *const entry_names[2][2] = { - { "__ovly_load", "__icache_br_handler" }, - { "__ovly_return", "__icache_call_handler" } - }; - - if (info->output_bfd->section_count < 2) - return 1; - - alloc_sec - = bfd_malloc (info->output_bfd->section_count * sizeof (*alloc_sec)); - if (alloc_sec == NULL) - return 0; - - /* Pick out all the alloced sections. */ - for (n = 0, s = info->output_bfd->sections; s != NULL; s = s->next) - if ((s->flags & SEC_ALLOC) != 0 - && (s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != SEC_THREAD_LOCAL - && s->size != 0) - alloc_sec[n++] = s; - - if (n == 0) - { - free (alloc_sec); - return 1; - } - - /* Sort them by vma. */ - qsort (alloc_sec, n, sizeof (*alloc_sec), sort_sections); - - ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size; - if (htab->params->ovly_flavour == ovly_soft_icache) - { - unsigned int prev_buf = 0, set_id = 0; - - /* Look for an overlapping vma to find the first overlay section. */ - bfd_vma vma_start = 0; - - for (i = 1; i < n; i++) - { - s = alloc_sec[i]; - if (s->vma < ovl_end) - { - asection *s0 = alloc_sec[i - 1]; - vma_start = s0->vma; - ovl_end = (s0->vma - + ((bfd_vma) 1 - << (htab->num_lines_log2 + htab->line_size_log2))); - --i; - break; - } - else - ovl_end = s->vma + s->size; - } - - /* Now find any sections within the cache area. */ - for (ovl_index = 0, num_buf = 0; i < n; i++) - { - s = alloc_sec[i]; - if (s->vma >= ovl_end) - break; - - /* A section in an overlay area called .ovl.init is not - an overlay, in the sense that it might be loaded in - by the overlay manager, but rather the initial - section contents for the overlay buffer. */ - if (strncmp (s->name, ".ovl.init", 9) != 0) - { - num_buf = ((s->vma - vma_start) >> htab->line_size_log2) + 1; - set_id = (num_buf == prev_buf)? set_id + 1 : 0; - prev_buf = num_buf; - - if ((s->vma - vma_start) & (htab->params->line_size - 1)) - { - info->callbacks->einfo (_("%X%P: overlay section %A " - "does not start on a cache line.\n"), - s); - bfd_set_error (bfd_error_bad_value); - return 0; - } - else if (s->size > htab->params->line_size) - { - info->callbacks->einfo (_("%X%P: overlay section %A " - "is larger than a cache line.\n"), - s); - bfd_set_error (bfd_error_bad_value); - return 0; - } - - alloc_sec[ovl_index++] = s; - spu_elf_section_data (s)->u.o.ovl_index - = (set_id << htab->num_lines_log2) + num_buf; - spu_elf_section_data (s)->u.o.ovl_buf = num_buf; - } - } - - /* Ensure there are no more overlay sections. */ - for ( ; i < n; i++) - { - s = alloc_sec[i]; - if (s->vma < ovl_end) - { - info->callbacks->einfo (_("%X%P: overlay section %A " - "is not in cache area.\n"), - alloc_sec[i-1]); - bfd_set_error (bfd_error_bad_value); - return 0; - } - else - ovl_end = s->vma + s->size; - } - } - else - { - /* Look for overlapping vmas. Any with overlap must be overlays. - Count them. Also count the number of overlay regions. */ - for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++) - { - s = alloc_sec[i]; - if (s->vma < ovl_end) - { - asection *s0 = alloc_sec[i - 1]; - - if (spu_elf_section_data (s0)->u.o.ovl_index == 0) - { - ++num_buf; - if (strncmp (s0->name, ".ovl.init", 9) != 0) - { - alloc_sec[ovl_index] = s0; - spu_elf_section_data (s0)->u.o.ovl_index = ++ovl_index; - spu_elf_section_data (s0)->u.o.ovl_buf = num_buf; - } - else - ovl_end = s->vma + s->size; - } - if (strncmp (s->name, ".ovl.init", 9) != 0) - { - alloc_sec[ovl_index] = s; - spu_elf_section_data (s)->u.o.ovl_index = ++ovl_index; - spu_elf_section_data (s)->u.o.ovl_buf = num_buf; - if (s0->vma != s->vma) - { - /* xgettext:c-format */ - info->callbacks->einfo (_("%X%P: overlay sections %A " - "and %A do not start at the " - "same address.\n"), - s0, s); - bfd_set_error (bfd_error_bad_value); - return 0; - } - if (ovl_end < s->vma + s->size) - ovl_end = s->vma + s->size; - } - } - else - ovl_end = s->vma + s->size; - } - } - - htab->num_overlays = ovl_index; - htab->num_buf = num_buf; - htab->ovl_sec = alloc_sec; - - if (ovl_index == 0) - return 1; - - for (i = 0; i < 2; i++) - { - const char *name; - struct elf_link_hash_entry *h; - - name = entry_names[i][htab->params->ovly_flavour]; - h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); - if (h == NULL) - return 0; - - if (h->root.type == bfd_link_hash_new) - { - h->root.type = bfd_link_hash_undefined; - h->ref_regular = 1; - h->ref_regular_nonweak = 1; - h->non_elf = 0; - } - htab->ovly_entry[i] = h; - } - - return 2; -} - -/* Non-zero to use bra in overlay stubs rather than br. */ -#define BRA_STUBS 0 - -#define BRA 0x30000000 -#define BRASL 0x31000000 -#define BR 0x32000000 -#define BRSL 0x33000000 -#define NOP 0x40200000 -#define LNOP 0x00200000 -#define ILA 0x42000000 - -/* Return true for all relative and absolute branch instructions. - bra 00110000 0.. - brasl 00110001 0.. - br 00110010 0.. - brsl 00110011 0.. - brz 00100000 0.. - brnz 00100001 0.. - brhz 00100010 0.. - brhnz 00100011 0.. */ - -static bfd_boolean -is_branch (const unsigned char *insn) -{ - return (insn[0] & 0xec) == 0x20 && (insn[1] & 0x80) == 0; -} - -/* Return true for all indirect branch instructions. - bi 00110101 000 - bisl 00110101 001 - iret 00110101 010 - bisled 00110101 011 - biz 00100101 000 - binz 00100101 001 - bihz 00100101 010 - bihnz 00100101 011 */ - -static bfd_boolean -is_indirect_branch (const unsigned char *insn) -{ - return (insn[0] & 0xef) == 0x25 && (insn[1] & 0x80) == 0; -} - -/* Return true for branch hint instructions. - hbra 0001000.. - hbrr 0001001.. */ - -static bfd_boolean -is_hint (const unsigned char *insn) -{ - return (insn[0] & 0xfc) == 0x10; -} - -/* True if INPUT_SECTION might need overlay stubs. */ - -static bfd_boolean -maybe_needs_stubs (asection *input_section) -{ - /* No stubs for debug sections and suchlike. */ - if ((input_section->flags & SEC_ALLOC) == 0) - return FALSE; - - /* No stubs for link-once sections that will be discarded. */ - if (input_section->output_section == bfd_abs_section_ptr) - return FALSE; - - /* Don't create stubs for .eh_frame references. */ - if (strcmp (input_section->name, ".eh_frame") == 0) - return FALSE; - - return TRUE; -} - -enum _stub_type -{ - no_stub, - call_ovl_stub, - br000_ovl_stub, - br001_ovl_stub, - br010_ovl_stub, - br011_ovl_stub, - br100_ovl_stub, - br101_ovl_stub, - br110_ovl_stub, - br111_ovl_stub, - nonovl_stub, - stub_error -}; - -/* Return non-zero if this reloc symbol should go via an overlay stub. - Return 2 if the stub must be in non-overlay area. */ - -static enum _stub_type -needs_ovl_stub (struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym, - asection *sym_sec, - asection *input_section, - Elf_Internal_Rela *irela, - bfd_byte *contents, - struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - enum elf_spu_reloc_type r_type; - unsigned int sym_type; - bfd_boolean branch, hint, call; - enum _stub_type ret = no_stub; - bfd_byte insn[4]; - - if (sym_sec == NULL - || sym_sec->output_section == bfd_abs_section_ptr - || spu_elf_section_data (sym_sec->output_section) == NULL) - return ret; - - if (h != NULL) - { - /* Ensure no stubs for user supplied overlay manager syms. */ - if (h == htab->ovly_entry[0] || h == htab->ovly_entry[1]) - return ret; - - /* setjmp always goes via an overlay stub, because then the return - and hence the longjmp goes via __ovly_return. That magically - makes setjmp/longjmp between overlays work. */ - if (strncmp (h->root.root.string, "setjmp", 6) == 0 - && (h->root.root.string[6] == '\0' || h->root.root.string[6] == '@')) - ret = call_ovl_stub; - } - - if (h != NULL) - sym_type = h->type; - else - sym_type = ELF_ST_TYPE (sym->st_info); - - r_type = ELF32_R_TYPE (irela->r_info); - branch = FALSE; - hint = FALSE; - call = FALSE; - if (r_type == R_SPU_REL16 || r_type == R_SPU_ADDR16) - { - if (contents == NULL) - { - contents = insn; - if (!bfd_get_section_contents (input_section->owner, - input_section, - contents, - irela->r_offset, 4)) - return stub_error; - } - else - contents += irela->r_offset; - - branch = is_branch (contents); - hint = is_hint (contents); - if (branch || hint) - { - call = (contents[0] & 0xfd) == 0x31; - if (call - && sym_type != STT_FUNC - && contents != insn) - { - /* It's common for people to write assembly and forget - to give function symbols the right type. Handle - calls to such symbols, but warn so that (hopefully) - people will fix their code. We need the symbol - type to be correct to distinguish function pointer - initialisation from other pointer initialisations. */ - const char *sym_name; - - if (h != NULL) - sym_name = h->root.root.string; - else - { - Elf_Internal_Shdr *symtab_hdr; - symtab_hdr = &elf_tdata (input_section->owner)->symtab_hdr; - sym_name = bfd_elf_sym_name (input_section->owner, - symtab_hdr, - sym, - sym_sec); - } - _bfd_error_handler - /* xgettext:c-format */ - (_("warning: call to non-function symbol %s defined in %B"), - sym_name, sym_sec->owner); - - } - } - } - - if ((!branch && htab->params->ovly_flavour == ovly_soft_icache) - || (sym_type != STT_FUNC - && !(branch || hint) - && (sym_sec->flags & SEC_CODE) == 0)) - return no_stub; - - /* Usually, symbols in non-overlay sections don't need stubs. */ - if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0 - && !htab->params->non_overlay_stubs) - return ret; - - /* A reference from some other section to a symbol in an overlay - section needs a stub. */ - if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index - != spu_elf_section_data (input_section->output_section)->u.o.ovl_index) - { - unsigned int lrlive = 0; - if (branch) - lrlive = (contents[1] & 0x70) >> 4; - - if (!lrlive && (call || sym_type == STT_FUNC)) - ret = call_ovl_stub; - else - ret = br000_ovl_stub + lrlive; - } - - /* If this insn isn't a branch then we are possibly taking the - address of a function and passing it out somehow. Soft-icache code - always generates inline code to do indirect branches. */ - if (!(branch || hint) - && sym_type == STT_FUNC - && htab->params->ovly_flavour != ovly_soft_icache) - ret = nonovl_stub; - - return ret; -} - -static bfd_boolean -count_stub (struct spu_link_hash_table *htab, - bfd *ibfd, - asection *isec, - enum _stub_type stub_type, - struct elf_link_hash_entry *h, - const Elf_Internal_Rela *irela) -{ - unsigned int ovl = 0; - struct got_entry *g, **head; - bfd_vma addend; - - /* If this instruction is a branch or call, we need a stub - for it. One stub per function per overlay. - If it isn't a branch, then we are taking the address of - this function so need a stub in the non-overlay area - for it. One stub per function. */ - if (stub_type != nonovl_stub) - ovl = spu_elf_section_data (isec->output_section)->u.o.ovl_index; - - if (h != NULL) - head = &h->got.glist; - else - { - if (elf_local_got_ents (ibfd) == NULL) - { - bfd_size_type amt = (elf_tdata (ibfd)->symtab_hdr.sh_info - * sizeof (*elf_local_got_ents (ibfd))); - elf_local_got_ents (ibfd) = bfd_zmalloc (amt); - if (elf_local_got_ents (ibfd) == NULL) - return FALSE; - } - head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info); - } - - if (htab->params->ovly_flavour == ovly_soft_icache) - { - htab->stub_count[ovl] += 1; - return TRUE; - } - - addend = 0; - if (irela != NULL) - addend = irela->r_addend; - - if (ovl == 0) - { - struct got_entry *gnext; - - for (g = *head; g != NULL; g = g->next) - if (g->addend == addend && g->ovl == 0) - break; - - if (g == NULL) - { - /* Need a new non-overlay area stub. Zap other stubs. */ - for (g = *head; g != NULL; g = gnext) - { - gnext = g->next; - if (g->addend == addend) - { - htab->stub_count[g->ovl] -= 1; - free (g); - } - } - } - } - else - { - for (g = *head; g != NULL; g = g->next) - if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) - break; - } - - if (g == NULL) - { - g = bfd_malloc (sizeof *g); - if (g == NULL) - return FALSE; - g->ovl = ovl; - g->addend = addend; - g->stub_addr = (bfd_vma) -1; - g->next = *head; - *head = g; - - htab->stub_count[ovl] += 1; - } - - return TRUE; -} - -/* Support two sizes of overlay stubs, a slower more compact stub of two - instructions, and a faster stub of four instructions. - Soft-icache stubs are four or eight words. */ - -static unsigned int -ovl_stub_size (struct spu_elf_params *params) -{ - return 16 << params->ovly_flavour >> params->compact_stub; -} - -static unsigned int -ovl_stub_size_log2 (struct spu_elf_params *params) -{ - return 4 + params->ovly_flavour - params->compact_stub; -} - -/* Two instruction overlay stubs look like: - - brsl $75,__ovly_load - .word target_ovl_and_address - - ovl_and_address is a word with the overlay number in the top 14 bits - and local store address in the bottom 18 bits. - - Four instruction overlay stubs look like: - - ila $78,ovl_number - lnop - ila $79,target_address - br __ovly_load - - Software icache stubs are: - - .word target_index - .word target_ia; - .word lrlive_branchlocalstoreaddr; - brasl $75,__icache_br_handler - .quad xor_pattern -*/ - -static bfd_boolean -build_stub (struct bfd_link_info *info, - bfd *ibfd, - asection *isec, - enum _stub_type stub_type, - struct elf_link_hash_entry *h, - const Elf_Internal_Rela *irela, - bfd_vma dest, - asection *dest_sec) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - unsigned int ovl, dest_ovl, set_id; - struct got_entry *g, **head; - asection *sec; - bfd_vma addend, from, to, br_dest, patt; - unsigned int lrlive; - - ovl = 0; - if (stub_type != nonovl_stub) - ovl = spu_elf_section_data (isec->output_section)->u.o.ovl_index; - - if (h != NULL) - head = &h->got.glist; - else - head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info); - - addend = 0; - if (irela != NULL) - addend = irela->r_addend; - - if (htab->params->ovly_flavour == ovly_soft_icache) - { - g = bfd_malloc (sizeof *g); - if (g == NULL) - return FALSE; - g->ovl = ovl; - g->br_addr = 0; - if (irela != NULL) - g->br_addr = (irela->r_offset - + isec->output_offset - + isec->output_section->vma); - g->next = *head; - *head = g; - } - else - { - for (g = *head; g != NULL; g = g->next) - if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) - break; - if (g == NULL) - abort (); - - if (g->ovl == 0 && ovl != 0) - return TRUE; - - if (g->stub_addr != (bfd_vma) -1) - return TRUE; - } - - sec = htab->stub_sec[ovl]; - dest += dest_sec->output_offset + dest_sec->output_section->vma; - from = sec->size + sec->output_offset + sec->output_section->vma; - g->stub_addr = from; - to = (htab->ovly_entry[0]->root.u.def.value - + htab->ovly_entry[0]->root.u.def.section->output_offset - + htab->ovly_entry[0]->root.u.def.section->output_section->vma); - - if (((dest | to | from) & 3) != 0) - { - htab->stub_err = 1; - return FALSE; - } - dest_ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index; - - if (htab->params->ovly_flavour == ovly_normal - && !htab->params->compact_stub) - { - bfd_put_32 (sec->owner, ILA + ((dest_ovl << 7) & 0x01ffff80) + 78, - sec->contents + sec->size); - bfd_put_32 (sec->owner, LNOP, - sec->contents + sec->size + 4); - bfd_put_32 (sec->owner, ILA + ((dest << 7) & 0x01ffff80) + 79, - sec->contents + sec->size + 8); - if (!BRA_STUBS) - bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80), - sec->contents + sec->size + 12); - else - bfd_put_32 (sec->owner, BRA + ((to << 5) & 0x007fff80), - sec->contents + sec->size + 12); - } - else if (htab->params->ovly_flavour == ovly_normal - && htab->params->compact_stub) - { - if (!BRA_STUBS) - bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75, - sec->contents + sec->size); - else - bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75, - sec->contents + sec->size); - bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18), - sec->contents + sec->size + 4); - } - else if (htab->params->ovly_flavour == ovly_soft_icache - && htab->params->compact_stub) - { - lrlive = 0; - if (stub_type == nonovl_stub) - ; - else if (stub_type == call_ovl_stub) - /* A brsl makes lr live and *(*sp+16) is live. - Tail calls have the same liveness. */ - lrlive = 5; - else if (!htab->params->lrlive_analysis) - /* Assume stack frame and lr save. */ - lrlive = 1; - else if (irela != NULL) - { - /* Analyse branch instructions. */ - struct function_info *caller; - bfd_vma off; - - caller = find_function (isec, irela->r_offset, info); - if (caller->start == NULL) - off = irela->r_offset; - else - { - struct function_info *found = NULL; - - /* Find the earliest piece of this function that - has frame adjusting instructions. We might - see dynamic frame adjustment (eg. for alloca) - in some later piece, but functions using - alloca always set up a frame earlier. Frame - setup instructions are always in one piece. */ - if (caller->lr_store != (bfd_vma) -1 - || caller->sp_adjust != (bfd_vma) -1) - found = caller; - while (caller->start != NULL) - { - caller = caller->start; - if (caller->lr_store != (bfd_vma) -1 - || caller->sp_adjust != (bfd_vma) -1) - found = caller; - } - if (found != NULL) - caller = found; - off = (bfd_vma) -1; - } - - if (off > caller->sp_adjust) - { - if (off > caller->lr_store) - /* Only *(*sp+16) is live. */ - lrlive = 1; - else - /* If no lr save, then we must be in a - leaf function with a frame. - lr is still live. */ - lrlive = 4; - } - else if (off > caller->lr_store) - { - /* Between lr save and stack adjust. */ - lrlive = 3; - /* This should never happen since prologues won't - be split here. */ - BFD_ASSERT (0); - } - else - /* On entry to function. */ - lrlive = 5; - - if (stub_type != br000_ovl_stub - && lrlive != stub_type - br000_ovl_stub) - /* xgettext:c-format */ - info->callbacks->einfo (_("%A:0x%v lrlive .brinfo (%u) differs " - "from analysis (%u)\n"), - isec, irela->r_offset, lrlive, - stub_type - br000_ovl_stub); - } - - /* If given lrlive info via .brinfo, use it. */ - if (stub_type > br000_ovl_stub) - lrlive = stub_type - br000_ovl_stub; - - if (ovl == 0) - to = (htab->ovly_entry[1]->root.u.def.value - + htab->ovly_entry[1]->root.u.def.section->output_offset - + htab->ovly_entry[1]->root.u.def.section->output_section->vma); - - /* The branch that uses this stub goes to stub_addr + 4. We'll - set up an xor pattern that can be used by the icache manager - to modify this branch to go directly to its destination. */ - g->stub_addr += 4; - br_dest = g->stub_addr; - if (irela == NULL) - { - /* Except in the case of _SPUEAR_ stubs, the branch in - question is the one in the stub itself. */ - BFD_ASSERT (stub_type == nonovl_stub); - g->br_addr = g->stub_addr; - br_dest = to; - } - - set_id = ((dest_ovl - 1) >> htab->num_lines_log2) + 1; - bfd_put_32 (sec->owner, (set_id << 18) | (dest & 0x3ffff), - sec->contents + sec->size); - bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75, - sec->contents + sec->size + 4); - bfd_put_32 (sec->owner, (lrlive << 29) | (g->br_addr & 0x3ffff), - sec->contents + sec->size + 8); - patt = dest ^ br_dest; - if (irela != NULL && ELF32_R_TYPE (irela->r_info) == R_SPU_REL16) - patt = (dest - g->br_addr) ^ (br_dest - g->br_addr); - bfd_put_32 (sec->owner, (patt << 5) & 0x007fff80, - sec->contents + sec->size + 12); - - if (ovl == 0) - /* Extra space for linked list entries. */ - sec->size += 16; - } - else - abort (); - - sec->size += ovl_stub_size (htab->params); - - if (htab->params->emit_stub_syms) - { - size_t len; - char *name; - int add; - - len = 8 + sizeof (".ovl_call.") - 1; - if (h != NULL) - len += strlen (h->root.root.string); - else - len += 8 + 1 + 8; - add = 0; - if (irela != NULL) - add = (int) irela->r_addend & 0xffffffff; - if (add != 0) - len += 1 + 8; - name = bfd_malloc (len + 1); - if (name == NULL) - return FALSE; - - sprintf (name, "%08x.ovl_call.", g->ovl); - if (h != NULL) - strcpy (name + 8 + sizeof (".ovl_call.") - 1, h->root.root.string); - else - sprintf (name + 8 + sizeof (".ovl_call.") - 1, "%x:%x", - dest_sec->id & 0xffffffff, - (int) ELF32_R_SYM (irela->r_info) & 0xffffffff); - if (add != 0) - sprintf (name + len - 9, "+%x", add); - - h = elf_link_hash_lookup (&htab->elf, name, TRUE, TRUE, FALSE); - free (name); - if (h == NULL) - return FALSE; - if (h->root.type == bfd_link_hash_new) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = sec; - h->size = ovl_stub_size (htab->params); - h->root.u.def.value = sec->size - h->size; - h->type = STT_FUNC; - h->ref_regular = 1; - h->def_regular = 1; - h->ref_regular_nonweak = 1; - h->forced_local = 1; - h->non_elf = 0; - } - } - - return TRUE; -} - -/* Called via elf_link_hash_traverse to allocate stubs for any _SPUEAR_ - symbols. */ - -static bfd_boolean -allocate_spuear_stubs (struct elf_link_hash_entry *h, void *inf) -{ - /* Symbols starting with _SPUEAR_ need a stub because they may be - invoked by the PPU. */ - struct bfd_link_info *info = inf; - struct spu_link_hash_table *htab = spu_hash_table (info); - asection *sym_sec; - - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->def_regular - && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0 - && (sym_sec = h->root.u.def.section) != NULL - && sym_sec->output_section != bfd_abs_section_ptr - && spu_elf_section_data (sym_sec->output_section) != NULL - && (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0 - || htab->params->non_overlay_stubs)) - { - return count_stub (htab, NULL, NULL, nonovl_stub, h, NULL); - } - - return TRUE; -} - -static bfd_boolean -build_spuear_stubs (struct elf_link_hash_entry *h, void *inf) -{ - /* Symbols starting with _SPUEAR_ need a stub because they may be - invoked by the PPU. */ - struct bfd_link_info *info = inf; - struct spu_link_hash_table *htab = spu_hash_table (info); - asection *sym_sec; - - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->def_regular - && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0 - && (sym_sec = h->root.u.def.section) != NULL - && sym_sec->output_section != bfd_abs_section_ptr - && spu_elf_section_data (sym_sec->output_section) != NULL - && (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0 - || htab->params->non_overlay_stubs)) - { - return build_stub (info, NULL, NULL, nonovl_stub, h, NULL, - h->root.u.def.value, sym_sec); - } - - return TRUE; -} - -/* Size or build stubs. */ - -static bfd_boolean -process_stubs (struct bfd_link_info *info, bfd_boolean build) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - bfd *ibfd; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - extern const bfd_target spu_elf32_vec; - Elf_Internal_Shdr *symtab_hdr; - asection *isec; - Elf_Internal_Sym *local_syms = NULL; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - if (symtab_hdr->sh_info == 0) - continue; - - /* Walk over each section attached to the input bfd. */ - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more to do. */ - if ((isec->flags & SEC_RELOC) == 0 - || isec->reloc_count == 0) - continue; - - if (!maybe_needs_stubs (isec)) - continue; - - /* Get the relocs. */ - internal_relocs = _bfd_elf_link_read_relocs (ibfd, isec, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + isec->reloc_count; - for (; irela < irelaend; irela++) - { - enum elf_spu_reloc_type r_type; - unsigned int r_indx; - asection *sym_sec; - Elf_Internal_Sym *sym; - struct elf_link_hash_entry *h; - enum _stub_type stub_type; - - r_type = ELF32_R_TYPE (irela->r_info); - r_indx = ELF32_R_SYM (irela->r_info); - - if (r_type >= R_SPU_max) - { - bfd_set_error (bfd_error_bad_value); - error_ret_free_internal: - if (elf_section_data (isec)->relocs != internal_relocs) - free (internal_relocs); - error_ret_free_local: - if (local_syms != NULL - && (symtab_hdr->contents - != (unsigned char *) local_syms)) - free (local_syms); - return FALSE; - } - - /* Determine the reloc target section. */ - if (!get_sym_h (&h, &sym, &sym_sec, &local_syms, r_indx, ibfd)) - goto error_ret_free_internal; - - stub_type = needs_ovl_stub (h, sym, sym_sec, isec, irela, - NULL, info); - if (stub_type == no_stub) - continue; - else if (stub_type == stub_error) - goto error_ret_free_internal; - - if (htab->stub_count == NULL) - { - bfd_size_type amt; - amt = (htab->num_overlays + 1) * sizeof (*htab->stub_count); - htab->stub_count = bfd_zmalloc (amt); - if (htab->stub_count == NULL) - goto error_ret_free_internal; - } - - if (!build) - { - if (!count_stub (htab, ibfd, isec, stub_type, h, irela)) - goto error_ret_free_internal; - } - else - { - bfd_vma dest; - - if (h != NULL) - dest = h->root.u.def.value; - else - dest = sym->st_value; - dest += irela->r_addend; - if (!build_stub (info, ibfd, isec, stub_type, h, irela, - dest, sym_sec)) - goto error_ret_free_internal; - } - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (isec)->relocs != internal_relocs) - free (internal_relocs); - } - - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - { - if (!info->keep_memory) - free (local_syms); - else - symtab_hdr->contents = (unsigned char *) local_syms; - } - } - - return TRUE; -} - -/* Allocate space for overlay call and return stubs. - Return 0 on error, 1 if no overlays, 2 otherwise. */ - -int -spu_elf_size_stubs (struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab; - bfd *ibfd; - bfd_size_type amt; - flagword flags; - unsigned int i; - asection *stub; - - if (!process_stubs (info, FALSE)) - return 0; - - htab = spu_hash_table (info); - elf_link_hash_traverse (&htab->elf, allocate_spuear_stubs, info); - if (htab->stub_err) - return 0; - - ibfd = info->input_bfds; - if (htab->stub_count != NULL) - { - amt = (htab->num_overlays + 1) * sizeof (*htab->stub_sec); - htab->stub_sec = bfd_zmalloc (amt); - if (htab->stub_sec == NULL) - return 0; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY); - stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); - htab->stub_sec[0] = stub; - if (stub == NULL - || !bfd_set_section_alignment (ibfd, stub, - ovl_stub_size_log2 (htab->params))) - return 0; - stub->size = htab->stub_count[0] * ovl_stub_size (htab->params); - if (htab->params->ovly_flavour == ovly_soft_icache) - /* Extra space for linked list entries. */ - stub->size += htab->stub_count[0] * 16; - - for (i = 0; i < htab->num_overlays; ++i) - { - asection *osec = htab->ovl_sec[i]; - unsigned int ovl = spu_elf_section_data (osec)->u.o.ovl_index; - stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); - htab->stub_sec[ovl] = stub; - if (stub == NULL - || !bfd_set_section_alignment (ibfd, stub, - ovl_stub_size_log2 (htab->params))) - return 0; - stub->size = htab->stub_count[ovl] * ovl_stub_size (htab->params); - } - } - - if (htab->params->ovly_flavour == ovly_soft_icache) - { - /* Space for icache manager tables. - a) Tag array, one quadword per cache line. - b) Rewrite "to" list, one quadword per cache line. - c) Rewrite "from" list, one byte per outgoing branch (rounded up to - a power-of-two number of full quadwords) per cache line. */ - - flags = SEC_ALLOC; - htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); - if (htab->ovtab == NULL - || !bfd_set_section_alignment (ibfd, htab->ovtab, 4)) - return 0; - - htab->ovtab->size = (16 + 16 + (16 << htab->fromelem_size_log2)) - << htab->num_lines_log2; - - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; - htab->init = bfd_make_section_anyway_with_flags (ibfd, ".ovini", flags); - if (htab->init == NULL - || !bfd_set_section_alignment (ibfd, htab->init, 4)) - return 0; - - htab->init->size = 16; - } - else if (htab->stub_count == NULL) - return 1; - else - { - /* htab->ovtab consists of two arrays. - . struct { - . u32 vma; - . u32 size; - . u32 file_off; - . u32 buf; - . } _ovly_table[]; - . - . struct { - . u32 mapped; - . } _ovly_buf_table[]; - . */ - - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; - htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); - if (htab->ovtab == NULL - || !bfd_set_section_alignment (ibfd, htab->ovtab, 4)) - return 0; - - htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4; - } - - htab->toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC); - if (htab->toe == NULL - || !bfd_set_section_alignment (ibfd, htab->toe, 4)) - return 0; - htab->toe->size = 16; - - return 2; -} - -/* Called from ld to place overlay manager data sections. This is done - after the overlay manager itself is loaded, mainly so that the - linker's htab->init section is placed after any other .ovl.init - sections. */ - -void -spu_elf_place_overlay_data (struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - unsigned int i; - - if (htab->stub_sec != NULL) - { - (*htab->params->place_spu_section) (htab->stub_sec[0], NULL, ".text"); - - for (i = 0; i < htab->num_overlays; ++i) - { - asection *osec = htab->ovl_sec[i]; - unsigned int ovl = spu_elf_section_data (osec)->u.o.ovl_index; - (*htab->params->place_spu_section) (htab->stub_sec[ovl], osec, NULL); - } - } - - if (htab->params->ovly_flavour == ovly_soft_icache) - (*htab->params->place_spu_section) (htab->init, NULL, ".ovl.init"); - - if (htab->ovtab != NULL) - { - const char *ovout = ".data"; - if (htab->params->ovly_flavour == ovly_soft_icache) - ovout = ".bss"; - (*htab->params->place_spu_section) (htab->ovtab, NULL, ovout); - } - - if (htab->toe != NULL) - (*htab->params->place_spu_section) (htab->toe, NULL, ".toe"); -} - -/* Functions to handle embedded spu_ovl.o object. */ - -static void * -ovl_mgr_open (struct bfd *nbfd ATTRIBUTE_UNUSED, void *stream) -{ - return stream; -} - -static file_ptr -ovl_mgr_pread (struct bfd *abfd ATTRIBUTE_UNUSED, - void *stream, - void *buf, - file_ptr nbytes, - file_ptr offset) -{ - struct _ovl_stream *os; - size_t count; - size_t max; - - os = (struct _ovl_stream *) stream; - max = (const char *) os->end - (const char *) os->start; - - if ((ufile_ptr) offset >= max) - return 0; - - count = nbytes; - if (count > max - offset) - count = max - offset; - - memcpy (buf, (const char *) os->start + offset, count); - return count; -} - -static int -ovl_mgr_stat (struct bfd *abfd ATTRIBUTE_UNUSED, - void *stream, - struct stat *sb) -{ - struct _ovl_stream *os = (struct _ovl_stream *) stream; - - memset (sb, 0, sizeof (*sb)); - sb->st_size = (const char *) os->end - (const char *) os->start; - return 0; -} - -bfd_boolean -spu_elf_open_builtin_lib (bfd **ovl_bfd, const struct _ovl_stream *stream) -{ - *ovl_bfd = bfd_openr_iovec ("builtin ovl_mgr", - "elf32-spu", - ovl_mgr_open, - (void *) stream, - ovl_mgr_pread, - NULL, - ovl_mgr_stat); - return *ovl_bfd != NULL; -} - -static unsigned int -overlay_index (asection *sec) -{ - if (sec == NULL - || sec->output_section == bfd_abs_section_ptr) - return 0; - return spu_elf_section_data (sec->output_section)->u.o.ovl_index; -} - -/* Define an STT_OBJECT symbol. */ - -static struct elf_link_hash_entry * -define_ovtab_symbol (struct spu_link_hash_table *htab, const char *name) -{ - struct elf_link_hash_entry *h; - - h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); - if (h == NULL) - return NULL; - - if (h->root.type != bfd_link_hash_defined - || !h->def_regular) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = htab->ovtab; - h->type = STT_OBJECT; - h->ref_regular = 1; - h->def_regular = 1; - h->ref_regular_nonweak = 1; - h->non_elf = 0; - } - else if (h->root.u.def.section->owner != NULL) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B is not allowed to define %s"), - h->root.u.def.section->owner, - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - else - { - _bfd_error_handler (_("you are not allowed to define %s in a script"), - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return NULL; - } - - return h; -} - -/* Fill in all stubs and the overlay tables. */ - -static bfd_boolean -spu_elf_build_stubs (struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - struct elf_link_hash_entry *h; - bfd_byte *p; - asection *s; - bfd *obfd; - unsigned int i; - - if (htab->num_overlays != 0) - { - for (i = 0; i < 2; i++) - { - h = htab->ovly_entry[i]; - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->def_regular) - { - s = h->root.u.def.section->output_section; - if (spu_elf_section_data (s)->u.o.ovl_index) - { - _bfd_error_handler (_("%s in overlay section"), - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - } - } - - if (htab->stub_sec != NULL) - { - for (i = 0; i <= htab->num_overlays; i++) - if (htab->stub_sec[i]->size != 0) - { - htab->stub_sec[i]->contents = bfd_zalloc (htab->stub_sec[i]->owner, - htab->stub_sec[i]->size); - if (htab->stub_sec[i]->contents == NULL) - return FALSE; - htab->stub_sec[i]->rawsize = htab->stub_sec[i]->size; - htab->stub_sec[i]->size = 0; - } - - /* Fill in all the stubs. */ - process_stubs (info, TRUE); - if (!htab->stub_err) - elf_link_hash_traverse (&htab->elf, build_spuear_stubs, info); - - if (htab->stub_err) - { - _bfd_error_handler (_("overlay stub relocation overflow")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - for (i = 0; i <= htab->num_overlays; i++) - { - if (htab->stub_sec[i]->size != htab->stub_sec[i]->rawsize) - { - _bfd_error_handler (_("stubs don't match calculated size")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - htab->stub_sec[i]->rawsize = 0; - } - } - - if (htab->ovtab == NULL || htab->ovtab->size == 0) - return TRUE; - - htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size); - if (htab->ovtab->contents == NULL) - return FALSE; - - p = htab->ovtab->contents; - if (htab->params->ovly_flavour == ovly_soft_icache) - { - bfd_vma off; - - h = define_ovtab_symbol (htab, "__icache_tag_array"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 0; - h->size = 16 << htab->num_lines_log2; - off = h->size; - - h = define_ovtab_symbol (htab, "__icache_tag_array_size"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 16 << htab->num_lines_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_rewrite_to"); - if (h == NULL) - return FALSE; - h->root.u.def.value = off; - h->size = 16 << htab->num_lines_log2; - off += h->size; - - h = define_ovtab_symbol (htab, "__icache_rewrite_to_size"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 16 << htab->num_lines_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_rewrite_from"); - if (h == NULL) - return FALSE; - h->root.u.def.value = off; - h->size = 16 << (htab->fromelem_size_log2 + htab->num_lines_log2); - off += h->size; - - h = define_ovtab_symbol (htab, "__icache_rewrite_from_size"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 16 << (htab->fromelem_size_log2 - + htab->num_lines_log2); - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_log2_fromelemsize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->fromelem_size_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_base"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->ovl_sec[0]->vma; - h->root.u.def.section = bfd_abs_section_ptr; - h->size = htab->num_buf << htab->line_size_log2; - - h = define_ovtab_symbol (htab, "__icache_linesize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 1 << htab->line_size_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_log2_linesize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->line_size_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_neg_log2_linesize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = -htab->line_size_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_cachesize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 1 << (htab->num_lines_log2 + htab->line_size_log2); - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_log2_cachesize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_lines_log2 + htab->line_size_log2; - h->root.u.def.section = bfd_abs_section_ptr; - - h = define_ovtab_symbol (htab, "__icache_neg_log2_cachesize"); - if (h == NULL) - return FALSE; - h->root.u.def.value = -(htab->num_lines_log2 + htab->line_size_log2); - h->root.u.def.section = bfd_abs_section_ptr; - - if (htab->init != NULL && htab->init->size != 0) - { - htab->init->contents = bfd_zalloc (htab->init->owner, - htab->init->size); - if (htab->init->contents == NULL) - return FALSE; - - h = define_ovtab_symbol (htab, "__icache_fileoff"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 0; - h->root.u.def.section = htab->init; - h->size = 8; - } - } - else - { - /* Write out _ovly_table. */ - /* set low bit of .size to mark non-overlay area as present. */ - p[7] = 1; - obfd = htab->ovtab->output_section->owner; - for (s = obfd->sections; s != NULL; s = s->next) - { - unsigned int ovl_index = spu_elf_section_data (s)->u.o.ovl_index; - - if (ovl_index != 0) - { - unsigned long off = ovl_index * 16; - unsigned int ovl_buf = spu_elf_section_data (s)->u.o.ovl_buf; - - bfd_put_32 (htab->ovtab->owner, s->vma, p + off); - bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, - p + off + 4); - /* file_off written later in spu_elf_modify_program_headers. */ - bfd_put_32 (htab->ovtab->owner, ovl_buf, p + off + 12); - } - } - - h = define_ovtab_symbol (htab, "_ovly_table"); - if (h == NULL) - return FALSE; - h->root.u.def.value = 16; - h->size = htab->num_overlays * 16; - - h = define_ovtab_symbol (htab, "_ovly_table_end"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_overlays * 16 + 16; - h->size = 0; - - h = define_ovtab_symbol (htab, "_ovly_buf_table"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_overlays * 16 + 16; - h->size = htab->num_buf * 4; - - h = define_ovtab_symbol (htab, "_ovly_buf_table_end"); - if (h == NULL) - return FALSE; - h->root.u.def.value = htab->num_overlays * 16 + 16 + htab->num_buf * 4; - h->size = 0; - } - - h = define_ovtab_symbol (htab, "_EAR_"); - if (h == NULL) - return FALSE; - h->root.u.def.section = htab->toe; - h->root.u.def.value = 0; - h->size = 16; - - return TRUE; -} - -/* Check that all loadable section VMAs lie in the range - LO .. HI inclusive, and stash some parameters for --auto-overlay. */ - -asection * -spu_elf_check_vma (struct bfd_link_info *info) -{ - struct elf_segment_map *m; - unsigned int i; - struct spu_link_hash_table *htab = spu_hash_table (info); - bfd *abfd = info->output_bfd; - bfd_vma hi = htab->params->local_store_hi; - bfd_vma lo = htab->params->local_store_lo; - - htab->local_store = hi + 1 - lo; - - for (m = elf_seg_map (abfd); m != NULL; m = m->next) - if (m->p_type == PT_LOAD) - for (i = 0; i < m->count; i++) - if (m->sections[i]->size != 0 - && (m->sections[i]->vma < lo - || m->sections[i]->vma > hi - || m->sections[i]->vma + m->sections[i]->size - 1 > hi)) - return m->sections[i]; - - return NULL; -} - -/* OFFSET in SEC (presumably) is the beginning of a function prologue. - Search for stack adjusting insns, and return the sp delta. - If a store of lr is found save the instruction offset to *LR_STORE. - If a stack adjusting instruction is found, save that offset to - *SP_ADJUST. */ - -static int -find_function_stack_adjust (asection *sec, - bfd_vma offset, - bfd_vma *lr_store, - bfd_vma *sp_adjust) -{ - int reg[128]; - - memset (reg, 0, sizeof (reg)); - for ( ; offset + 4 <= sec->size; offset += 4) - { - unsigned char buf[4]; - int rt, ra; - int imm; - - /* Assume no relocs on stack adjusing insns. */ - if (!bfd_get_section_contents (sec->owner, sec, buf, offset, 4)) - break; - - rt = buf[3] & 0x7f; - ra = ((buf[2] & 0x3f) << 1) | (buf[3] >> 7); - - if (buf[0] == 0x24 /* stqd */) - { - if (rt == 0 /* lr */ && ra == 1 /* sp */) - *lr_store = offset; - continue; - } - - /* Partly decoded immediate field. */ - imm = (buf[1] << 9) | (buf[2] << 1) | (buf[3] >> 7); - - if (buf[0] == 0x1c /* ai */) - { - imm >>= 7; - imm = (imm ^ 0x200) - 0x200; - reg[rt] = reg[ra] + imm; - - if (rt == 1 /* sp */) - { - if (reg[rt] > 0) - break; - *sp_adjust = offset; - return reg[rt]; - } - } - else if (buf[0] == 0x18 && (buf[1] & 0xe0) == 0 /* a */) - { - int rb = ((buf[1] & 0x1f) << 2) | ((buf[2] & 0xc0) >> 6); - - reg[rt] = reg[ra] + reg[rb]; - if (rt == 1) - { - if (reg[rt] > 0) - break; - *sp_adjust = offset; - return reg[rt]; - } - } - else if (buf[0] == 0x08 && (buf[1] & 0xe0) == 0 /* sf */) - { - int rb = ((buf[1] & 0x1f) << 2) | ((buf[2] & 0xc0) >> 6); - - reg[rt] = reg[rb] - reg[ra]; - if (rt == 1) - { - if (reg[rt] > 0) - break; - *sp_adjust = offset; - return reg[rt]; - } - } - else if ((buf[0] & 0xfc) == 0x40 /* il, ilh, ilhu, ila */) - { - if (buf[0] >= 0x42 /* ila */) - imm |= (buf[0] & 1) << 17; - else - { - imm &= 0xffff; - - if (buf[0] == 0x40 /* il */) - { - if ((buf[1] & 0x80) == 0) - continue; - imm = (imm ^ 0x8000) - 0x8000; - } - else if ((buf[1] & 0x80) == 0 /* ilhu */) - imm <<= 16; - } - reg[rt] = imm; - continue; - } - else if (buf[0] == 0x60 && (buf[1] & 0x80) != 0 /* iohl */) - { - reg[rt] |= imm & 0xffff; - continue; - } - else if (buf[0] == 0x04 /* ori */) - { - imm >>= 7; - imm = (imm ^ 0x200) - 0x200; - reg[rt] = reg[ra] | imm; - continue; - } - else if (buf[0] == 0x32 && (buf[1] & 0x80) != 0 /* fsmbi */) - { - reg[rt] = ( ((imm & 0x8000) ? 0xff000000 : 0) - | ((imm & 0x4000) ? 0x00ff0000 : 0) - | ((imm & 0x2000) ? 0x0000ff00 : 0) - | ((imm & 0x1000) ? 0x000000ff : 0)); - continue; - } - else if (buf[0] == 0x16 /* andbi */) - { - imm >>= 7; - imm &= 0xff; - imm |= imm << 8; - imm |= imm << 16; - reg[rt] = reg[ra] & imm; - continue; - } - else if (buf[0] == 0x33 && imm == 1 /* brsl .+4 */) - { - /* Used in pic reg load. Say rt is trashed. Won't be used - in stack adjust, but we need to continue past this branch. */ - reg[rt] = 0; - continue; - } - else if (is_branch (buf) || is_indirect_branch (buf)) - /* If we hit a branch then we must be out of the prologue. */ - break; - } - - return 0; -} - -/* qsort predicate to sort symbols by section and value. */ - -static Elf_Internal_Sym *sort_syms_syms; -static asection **sort_syms_psecs; - -static int -sort_syms (const void *a, const void *b) -{ - Elf_Internal_Sym *const *s1 = a; - Elf_Internal_Sym *const *s2 = b; - asection *sec1,*sec2; - bfd_signed_vma delta; - - sec1 = sort_syms_psecs[*s1 - sort_syms_syms]; - sec2 = sort_syms_psecs[*s2 - sort_syms_syms]; - - if (sec1 != sec2) - return sec1->index - sec2->index; - - delta = (*s1)->st_value - (*s2)->st_value; - if (delta != 0) - return delta < 0 ? -1 : 1; - - delta = (*s2)->st_size - (*s1)->st_size; - if (delta != 0) - return delta < 0 ? -1 : 1; - - return *s1 < *s2 ? -1 : 1; -} - -/* Allocate a struct spu_elf_stack_info with MAX_FUN struct function_info - entries for section SEC. */ - -static struct spu_elf_stack_info * -alloc_stack_info (asection *sec, int max_fun) -{ - struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); - bfd_size_type amt; - - amt = sizeof (struct spu_elf_stack_info); - amt += (max_fun - 1) * sizeof (struct function_info); - sec_data->u.i.stack_info = bfd_zmalloc (amt); - if (sec_data->u.i.stack_info != NULL) - sec_data->u.i.stack_info->max_fun = max_fun; - return sec_data->u.i.stack_info; -} - -/* Add a new struct function_info describing a (part of a) function - starting at SYM_H. Keep the array sorted by address. */ - -static struct function_info * -maybe_insert_function (asection *sec, - void *sym_h, - bfd_boolean global, - bfd_boolean is_func) -{ - struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); - struct spu_elf_stack_info *sinfo = sec_data->u.i.stack_info; - int i; - bfd_vma off, size; - - if (sinfo == NULL) - { - sinfo = alloc_stack_info (sec, 20); - if (sinfo == NULL) - return NULL; - } - - if (!global) - { - Elf_Internal_Sym *sym = sym_h; - off = sym->st_value; - size = sym->st_size; - } - else - { - struct elf_link_hash_entry *h = sym_h; - off = h->root.u.def.value; - size = h->size; - } - - for (i = sinfo->num_fun; --i >= 0; ) - if (sinfo->fun[i].lo <= off) - break; - - if (i >= 0) - { - /* Don't add another entry for an alias, but do update some - info. */ - if (sinfo->fun[i].lo == off) - { - /* Prefer globals over local syms. */ - if (global && !sinfo->fun[i].global) - { - sinfo->fun[i].global = TRUE; - sinfo->fun[i].u.h = sym_h; - } - if (is_func) - sinfo->fun[i].is_func = TRUE; - return &sinfo->fun[i]; - } - /* Ignore a zero-size symbol inside an existing function. */ - else if (sinfo->fun[i].hi > off && size == 0) - return &sinfo->fun[i]; - } - - if (sinfo->num_fun >= sinfo->max_fun) - { - bfd_size_type amt = sizeof (struct spu_elf_stack_info); - bfd_size_type old = amt; - - old += (sinfo->max_fun - 1) * sizeof (struct function_info); - sinfo->max_fun += 20 + (sinfo->max_fun >> 1); - amt += (sinfo->max_fun - 1) * sizeof (struct function_info); - sinfo = bfd_realloc (sinfo, amt); - if (sinfo == NULL) - return NULL; - memset ((char *) sinfo + old, 0, amt - old); - sec_data->u.i.stack_info = sinfo; - } - - if (++i < sinfo->num_fun) - memmove (&sinfo->fun[i + 1], &sinfo->fun[i], - (sinfo->num_fun - i) * sizeof (sinfo->fun[i])); - sinfo->fun[i].is_func = is_func; - sinfo->fun[i].global = global; - sinfo->fun[i].sec = sec; - if (global) - sinfo->fun[i].u.h = sym_h; - else - sinfo->fun[i].u.sym = sym_h; - sinfo->fun[i].lo = off; - sinfo->fun[i].hi = off + size; - sinfo->fun[i].lr_store = -1; - sinfo->fun[i].sp_adjust = -1; - sinfo->fun[i].stack = -find_function_stack_adjust (sec, off, - &sinfo->fun[i].lr_store, - &sinfo->fun[i].sp_adjust); - sinfo->num_fun += 1; - return &sinfo->fun[i]; -} - -/* Return the name of FUN. */ - -static const char * -func_name (struct function_info *fun) -{ - asection *sec; - bfd *ibfd; - Elf_Internal_Shdr *symtab_hdr; - - while (fun->start != NULL) - fun = fun->start; - - if (fun->global) - return fun->u.h->root.root.string; - - sec = fun->sec; - if (fun->u.sym->st_name == 0) - { - size_t len = strlen (sec->name); - char *name = bfd_malloc (len + 10); - if (name == NULL) - return "(null)"; - sprintf (name, "%s+%lx", sec->name, - (unsigned long) fun->u.sym->st_value & 0xffffffff); - return name; - } - ibfd = sec->owner; - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - return bfd_elf_sym_name (ibfd, symtab_hdr, fun->u.sym, sec); -} - -/* Read the instruction at OFF in SEC. Return true iff the instruction - is a nop, lnop, or stop 0 (all zero insn). */ - -static bfd_boolean -is_nop (asection *sec, bfd_vma off) -{ - unsigned char insn[4]; - - if (off + 4 > sec->size - || !bfd_get_section_contents (sec->owner, sec, insn, off, 4)) - return FALSE; - if ((insn[0] & 0xbf) == 0 && (insn[1] & 0xe0) == 0x20) - return TRUE; - if (insn[0] == 0 && insn[1] == 0 && insn[2] == 0 && insn[3] == 0) - return TRUE; - return FALSE; -} - -/* Extend the range of FUN to cover nop padding up to LIMIT. - Return TRUE iff some instruction other than a NOP was found. */ - -static bfd_boolean -insns_at_end (struct function_info *fun, bfd_vma limit) -{ - bfd_vma off = (fun->hi + 3) & -4; - - while (off < limit && is_nop (fun->sec, off)) - off += 4; - if (off < limit) - { - fun->hi = off; - return TRUE; - } - fun->hi = limit; - return FALSE; -} - -/* Check and fix overlapping function ranges. Return TRUE iff there - are gaps in the current info we have about functions in SEC. */ - -static bfd_boolean -check_function_ranges (asection *sec, struct bfd_link_info *info) -{ - struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); - struct spu_elf_stack_info *sinfo = sec_data->u.i.stack_info; - int i; - bfd_boolean gaps = FALSE; - - if (sinfo == NULL) - return FALSE; - - for (i = 1; i < sinfo->num_fun; i++) - if (sinfo->fun[i - 1].hi > sinfo->fun[i].lo) - { - /* Fix overlapping symbols. */ - const char *f1 = func_name (&sinfo->fun[i - 1]); - const char *f2 = func_name (&sinfo->fun[i]); - - /* xgettext:c-format */ - info->callbacks->einfo (_("warning: %s overlaps %s\n"), f1, f2); - sinfo->fun[i - 1].hi = sinfo->fun[i].lo; - } - else if (insns_at_end (&sinfo->fun[i - 1], sinfo->fun[i].lo)) - gaps = TRUE; - - if (sinfo->num_fun == 0) - gaps = TRUE; - else - { - if (sinfo->fun[0].lo != 0) - gaps = TRUE; - if (sinfo->fun[sinfo->num_fun - 1].hi > sec->size) - { - const char *f1 = func_name (&sinfo->fun[sinfo->num_fun - 1]); - - info->callbacks->einfo (_("warning: %s exceeds section size\n"), f1); - sinfo->fun[sinfo->num_fun - 1].hi = sec->size; - } - else if (insns_at_end (&sinfo->fun[sinfo->num_fun - 1], sec->size)) - gaps = TRUE; - } - return gaps; -} - -/* Search current function info for a function that contains address - OFFSET in section SEC. */ - -static struct function_info * -find_function (asection *sec, bfd_vma offset, struct bfd_link_info *info) -{ - struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); - struct spu_elf_stack_info *sinfo = sec_data->u.i.stack_info; - int lo, hi, mid; - - lo = 0; - hi = sinfo->num_fun; - while (lo < hi) - { - mid = (lo + hi) / 2; - if (offset < sinfo->fun[mid].lo) - hi = mid; - else if (offset >= sinfo->fun[mid].hi) - lo = mid + 1; - else - return &sinfo->fun[mid]; - } - /* xgettext:c-format */ - info->callbacks->einfo (_("%A:0x%v not found in function table\n"), - sec, offset); - bfd_set_error (bfd_error_bad_value); - return NULL; -} - -/* Add CALLEE to CALLER call list if not already present. Return TRUE - if CALLEE was new. If this function return FALSE, CALLEE should - be freed. */ - -static bfd_boolean -insert_callee (struct function_info *caller, struct call_info *callee) -{ - struct call_info **pp, *p; - - for (pp = &caller->call_list; (p = *pp) != NULL; pp = &p->next) - if (p->fun == callee->fun) - { - /* Tail calls use less stack than normal calls. Retain entry - for normal call over one for tail call. */ - p->is_tail &= callee->is_tail; - if (!p->is_tail) - { - p->fun->start = NULL; - p->fun->is_func = TRUE; - } - p->count += callee->count; - /* Reorder list so most recent call is first. */ - *pp = p->next; - p->next = caller->call_list; - caller->call_list = p; - return FALSE; - } - callee->next = caller->call_list; - caller->call_list = callee; - return TRUE; -} - -/* Copy CALL and insert the copy into CALLER. */ - -static bfd_boolean -copy_callee (struct function_info *caller, const struct call_info *call) -{ - struct call_info *callee; - callee = bfd_malloc (sizeof (*callee)); - if (callee == NULL) - return FALSE; - *callee = *call; - if (!insert_callee (caller, callee)) - free (callee); - return TRUE; -} - -/* We're only interested in code sections. Testing SEC_IN_MEMORY excludes - overlay stub sections. */ - -static bfd_boolean -interesting_section (asection *s) -{ - return (s->output_section != bfd_abs_section_ptr - && ((s->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_IN_MEMORY)) - == (SEC_ALLOC | SEC_LOAD | SEC_CODE)) - && s->size != 0); -} - -/* Rummage through the relocs for SEC, looking for function calls. - If CALL_TREE is true, fill in call graph. If CALL_TREE is false, - mark destination symbols on calls as being functions. Also - look at branches, which may be tail calls or go to hot/cold - section part of same function. */ - -static bfd_boolean -mark_functions_via_relocs (asection *sec, - struct bfd_link_info *info, - int call_tree) -{ - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - Elf_Internal_Shdr *symtab_hdr; - void *psyms; - unsigned int priority = 0; - static bfd_boolean warned; - - if (!interesting_section (sec) - || sec->reloc_count == 0) - return TRUE; - - internal_relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - return FALSE; - - symtab_hdr = &elf_tdata (sec->owner)->symtab_hdr; - psyms = &symtab_hdr->contents; - irela = internal_relocs; - irelaend = irela + sec->reloc_count; - for (; irela < irelaend; irela++) - { - enum elf_spu_reloc_type r_type; - unsigned int r_indx; - asection *sym_sec; - Elf_Internal_Sym *sym; - struct elf_link_hash_entry *h; - bfd_vma val; - bfd_boolean nonbranch, is_call; - struct function_info *caller; - struct call_info *callee; - - r_type = ELF32_R_TYPE (irela->r_info); - nonbranch = r_type != R_SPU_REL16 && r_type != R_SPU_ADDR16; - - r_indx = ELF32_R_SYM (irela->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, psyms, r_indx, sec->owner)) - return FALSE; - - if (sym_sec == NULL - || sym_sec->output_section == bfd_abs_section_ptr) - continue; - - is_call = FALSE; - if (!nonbranch) - { - unsigned char insn[4]; - - if (!bfd_get_section_contents (sec->owner, sec, insn, - irela->r_offset, 4)) - return FALSE; - if (is_branch (insn)) - { - is_call = (insn[0] & 0xfd) == 0x31; - priority = insn[1] & 0x0f; - priority <<= 8; - priority |= insn[2]; - priority <<= 8; - priority |= insn[3]; - priority >>= 7; - if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) - != (SEC_ALLOC | SEC_LOAD | SEC_CODE)) - { - if (!warned) - info->callbacks->einfo - /* xgettext:c-format */ - (_("%B(%A+0x%v): call to non-code section" - " %B(%A), analysis incomplete\n"), - sec->owner, sec, irela->r_offset, - sym_sec->owner, sym_sec); - warned = TRUE; - continue; - } - } - else - { - nonbranch = TRUE; - if (is_hint (insn)) - continue; - } - } - - if (nonbranch) - { - /* For --auto-overlay, count possible stubs we need for - function pointer references. */ - unsigned int sym_type; - if (h) - sym_type = h->type; - else - sym_type = ELF_ST_TYPE (sym->st_info); - if (sym_type == STT_FUNC) - { - if (call_tree && spu_hash_table (info)->params->auto_overlay) - spu_hash_table (info)->non_ovly_stub += 1; - /* If the symbol type is STT_FUNC then this must be a - function pointer initialisation. */ - continue; - } - /* Ignore data references. */ - if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) - != (SEC_ALLOC | SEC_LOAD | SEC_CODE)) - continue; - /* Otherwise we probably have a jump table reloc for - a switch statement or some other reference to a - code label. */ - } - - if (h) - val = h->root.u.def.value; - else - val = sym->st_value; - val += irela->r_addend; - - if (!call_tree) - { - struct function_info *fun; - - if (irela->r_addend != 0) - { - Elf_Internal_Sym *fake = bfd_zmalloc (sizeof (*fake)); - if (fake == NULL) - return FALSE; - fake->st_value = val; - fake->st_shndx - = _bfd_elf_section_from_bfd_section (sym_sec->owner, sym_sec); - sym = fake; - } - if (sym) - fun = maybe_insert_function (sym_sec, sym, FALSE, is_call); - else - fun = maybe_insert_function (sym_sec, h, TRUE, is_call); - if (fun == NULL) - return FALSE; - if (irela->r_addend != 0 - && fun->u.sym != sym) - free (sym); - continue; - } - - caller = find_function (sec, irela->r_offset, info); - if (caller == NULL) - return FALSE; - callee = bfd_malloc (sizeof *callee); - if (callee == NULL) - return FALSE; - - callee->fun = find_function (sym_sec, val, info); - if (callee->fun == NULL) - return FALSE; - callee->is_tail = !is_call; - callee->is_pasted = FALSE; - callee->broken_cycle = FALSE; - callee->priority = priority; - callee->count = nonbranch? 0 : 1; - if (callee->fun->last_caller != sec) - { - callee->fun->last_caller = sec; - callee->fun->call_count += 1; - } - if (!insert_callee (caller, callee)) - free (callee); - else if (!is_call - && !callee->fun->is_func - && callee->fun->stack == 0) - { - /* This is either a tail call or a branch from one part of - the function to another, ie. hot/cold section. If the - destination has been called by some other function then - it is a separate function. We also assume that functions - are not split across input files. */ - if (sec->owner != sym_sec->owner) - { - callee->fun->start = NULL; - callee->fun->is_func = TRUE; - } - else if (callee->fun->start == NULL) - { - struct function_info *caller_start = caller; - while (caller_start->start) - caller_start = caller_start->start; - - if (caller_start != callee->fun) - callee->fun->start = caller_start; - } - else - { - struct function_info *callee_start; - struct function_info *caller_start; - callee_start = callee->fun; - while (callee_start->start) - callee_start = callee_start->start; - caller_start = caller; - while (caller_start->start) - caller_start = caller_start->start; - if (caller_start != callee_start) - { - callee->fun->start = NULL; - callee->fun->is_func = TRUE; - } - } - } - } - - return TRUE; -} - -/* Handle something like .init or .fini, which has a piece of a function. - These sections are pasted together to form a single function. */ - -static bfd_boolean -pasted_function (asection *sec) -{ - struct bfd_link_order *l; - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - Elf_Internal_Sym *fake; - struct function_info *fun, *fun_start; - - fake = bfd_zmalloc (sizeof (*fake)); - if (fake == NULL) - return FALSE; - fake->st_value = 0; - fake->st_size = sec->size; - fake->st_shndx - = _bfd_elf_section_from_bfd_section (sec->owner, sec); - fun = maybe_insert_function (sec, fake, FALSE, FALSE); - if (!fun) - return FALSE; - - /* Find a function immediately preceding this section. */ - fun_start = NULL; - for (l = sec->output_section->map_head.link_order; l != NULL; l = l->next) - { - if (l->u.indirect.section == sec) - { - if (fun_start != NULL) - { - struct call_info *callee = bfd_malloc (sizeof *callee); - if (callee == NULL) - return FALSE; - - fun->start = fun_start; - callee->fun = fun; - callee->is_tail = TRUE; - callee->is_pasted = TRUE; - callee->broken_cycle = FALSE; - callee->priority = 0; - callee->count = 1; - if (!insert_callee (fun_start, callee)) - free (callee); - return TRUE; - } - break; - } - if (l->type == bfd_indirect_link_order - && (sec_data = spu_elf_section_data (l->u.indirect.section)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL - && sinfo->num_fun != 0) - fun_start = &sinfo->fun[sinfo->num_fun - 1]; - } - - /* Don't return an error if we did not find a function preceding this - section. The section may have incorrect flags. */ - return TRUE; -} - -/* Map address ranges in code sections to functions. */ - -static bfd_boolean -discover_functions (struct bfd_link_info *info) -{ - bfd *ibfd; - int bfd_idx; - Elf_Internal_Sym ***psym_arr; - asection ***sec_arr; - bfd_boolean gaps = FALSE; - - bfd_idx = 0; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - bfd_idx++; - - psym_arr = bfd_zmalloc (bfd_idx * sizeof (*psym_arr)); - if (psym_arr == NULL) - return FALSE; - sec_arr = bfd_zmalloc (bfd_idx * sizeof (*sec_arr)); - if (sec_arr == NULL) - return FALSE; - - for (ibfd = info->input_bfds, bfd_idx = 0; - ibfd != NULL; - ibfd = ibfd->link.next, bfd_idx++) - { - extern const bfd_target spu_elf32_vec; - Elf_Internal_Shdr *symtab_hdr; - asection *sec; - size_t symcount; - Elf_Internal_Sym *syms, *sy, **psyms, **psy; - asection **psecs, **p; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - /* Read all the symbols. */ - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - symcount = symtab_hdr->sh_size / symtab_hdr->sh_entsize; - if (symcount == 0) - { - if (!gaps) - for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next) - if (interesting_section (sec)) - { - gaps = TRUE; - break; - } - continue; - } - - if (symtab_hdr->contents != NULL) - { - /* Don't use cached symbols since the generic ELF linker - code only reads local symbols, and we need globals too. */ - free (symtab_hdr->contents); - symtab_hdr->contents = NULL; - } - syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, 0, - NULL, NULL, NULL); - symtab_hdr->contents = (void *) syms; - if (syms == NULL) - return FALSE; - - /* Select defined function symbols that are going to be output. */ - psyms = bfd_malloc ((symcount + 1) * sizeof (*psyms)); - if (psyms == NULL) - return FALSE; - psym_arr[bfd_idx] = psyms; - psecs = bfd_malloc (symcount * sizeof (*psecs)); - if (psecs == NULL) - return FALSE; - sec_arr[bfd_idx] = psecs; - for (psy = psyms, p = psecs, sy = syms; sy < syms + symcount; ++p, ++sy) - if (ELF_ST_TYPE (sy->st_info) == STT_NOTYPE - || ELF_ST_TYPE (sy->st_info) == STT_FUNC) - { - asection *s; - - *p = s = bfd_section_from_elf_index (ibfd, sy->st_shndx); - if (s != NULL && interesting_section (s)) - *psy++ = sy; - } - symcount = psy - psyms; - *psy = NULL; - - /* Sort them by section and offset within section. */ - sort_syms_syms = syms; - sort_syms_psecs = psecs; - qsort (psyms, symcount, sizeof (*psyms), sort_syms); - - /* Now inspect the function symbols. */ - for (psy = psyms; psy < psyms + symcount; ) - { - asection *s = psecs[*psy - syms]; - Elf_Internal_Sym **psy2; - - for (psy2 = psy; ++psy2 < psyms + symcount; ) - if (psecs[*psy2 - syms] != s) - break; - - if (!alloc_stack_info (s, psy2 - psy)) - return FALSE; - psy = psy2; - } - - /* First install info about properly typed and sized functions. - In an ideal world this will cover all code sections, except - when partitioning functions into hot and cold sections, - and the horrible pasted together .init and .fini functions. */ - for (psy = psyms; psy < psyms + symcount; ++psy) - { - sy = *psy; - if (ELF_ST_TYPE (sy->st_info) == STT_FUNC) - { - asection *s = psecs[sy - syms]; - if (!maybe_insert_function (s, sy, FALSE, TRUE)) - return FALSE; - } - } - - for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next) - if (interesting_section (sec)) - gaps |= check_function_ranges (sec, info); - } - - if (gaps) - { - /* See if we can discover more function symbols by looking at - relocations. */ - for (ibfd = info->input_bfds, bfd_idx = 0; - ibfd != NULL; - ibfd = ibfd->link.next, bfd_idx++) - { - asection *sec; - - if (psym_arr[bfd_idx] == NULL) - continue; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (!mark_functions_via_relocs (sec, info, FALSE)) - return FALSE; - } - - for (ibfd = info->input_bfds, bfd_idx = 0; - ibfd != NULL; - ibfd = ibfd->link.next, bfd_idx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *sec; - Elf_Internal_Sym *syms, *sy, **psyms, **psy; - asection **psecs; - - if ((psyms = psym_arr[bfd_idx]) == NULL) - continue; - - psecs = sec_arr[bfd_idx]; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - syms = (Elf_Internal_Sym *) symtab_hdr->contents; - - gaps = FALSE; - for (sec = ibfd->sections; sec != NULL && !gaps; sec = sec->next) - if (interesting_section (sec)) - gaps |= check_function_ranges (sec, info); - if (!gaps) - continue; - - /* Finally, install all globals. */ - for (psy = psyms; (sy = *psy) != NULL; ++psy) - { - asection *s; - - s = psecs[sy - syms]; - - /* Global syms might be improperly typed functions. */ - if (ELF_ST_TYPE (sy->st_info) != STT_FUNC - && ELF_ST_BIND (sy->st_info) == STB_GLOBAL) - { - if (!maybe_insert_function (s, sy, FALSE, FALSE)) - return FALSE; - } - } - } - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - extern const bfd_target spu_elf32_vec; - asection *sec; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - /* Some of the symbols we've installed as marking the - beginning of functions may have a size of zero. Extend - the range of such functions to the beginning of the - next symbol of interest. */ - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (interesting_section (sec)) - { - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - - sec_data = spu_elf_section_data (sec); - sinfo = sec_data->u.i.stack_info; - if (sinfo != NULL && sinfo->num_fun != 0) - { - int fun_idx; - bfd_vma hi = sec->size; - - for (fun_idx = sinfo->num_fun; --fun_idx >= 0; ) - { - sinfo->fun[fun_idx].hi = hi; - hi = sinfo->fun[fun_idx].lo; - } - - sinfo->fun[0].lo = 0; - } - /* No symbols in this section. Must be .init or .fini - or something similar. */ - else if (!pasted_function (sec)) - return FALSE; - } - } - } - - for (ibfd = info->input_bfds, bfd_idx = 0; - ibfd != NULL; - ibfd = ibfd->link.next, bfd_idx++) - { - if (psym_arr[bfd_idx] == NULL) - continue; - - free (psym_arr[bfd_idx]); - free (sec_arr[bfd_idx]); - } - - free (psym_arr); - free (sec_arr); - - return TRUE; -} - -/* Iterate over all function_info we have collected, calling DOIT on - each node if ROOT_ONLY is false. Only call DOIT on root nodes - if ROOT_ONLY. */ - -static bfd_boolean -for_each_node (bfd_boolean (*doit) (struct function_info *, - struct bfd_link_info *, - void *), - struct bfd_link_info *info, - void *param, - int root_only) -{ - bfd *ibfd; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - extern const bfd_target spu_elf32_vec; - asection *sec; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - - if ((sec_data = spu_elf_section_data (sec)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL) - { - int i; - for (i = 0; i < sinfo->num_fun; ++i) - if (!root_only || !sinfo->fun[i].non_root) - if (!doit (&sinfo->fun[i], info, param)) - return FALSE; - } - } - } - return TRUE; -} - -/* Transfer call info attached to struct function_info entries for - all of a given function's sections to the first entry. */ - -static bfd_boolean -transfer_calls (struct function_info *fun, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - void *param ATTRIBUTE_UNUSED) -{ - struct function_info *start = fun->start; - - if (start != NULL) - { - struct call_info *call, *call_next; - - while (start->start != NULL) - start = start->start; - for (call = fun->call_list; call != NULL; call = call_next) - { - call_next = call->next; - if (!insert_callee (start, call)) - free (call); - } - fun->call_list = NULL; - } - return TRUE; -} - -/* Mark nodes in the call graph that are called by some other node. */ - -static bfd_boolean -mark_non_root (struct function_info *fun, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - void *param ATTRIBUTE_UNUSED) -{ - struct call_info *call; - - if (fun->visit1) - return TRUE; - fun->visit1 = TRUE; - for (call = fun->call_list; call; call = call->next) - { - call->fun->non_root = TRUE; - mark_non_root (call->fun, 0, 0); - } - return TRUE; -} - -/* Remove cycles from the call graph. Set depth of nodes. */ - -static bfd_boolean -remove_cycles (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - struct call_info **callp, *call; - unsigned int depth = *(unsigned int *) param; - unsigned int max_depth = depth; - - fun->depth = depth; - fun->visit2 = TRUE; - fun->marking = TRUE; - - callp = &fun->call_list; - while ((call = *callp) != NULL) - { - call->max_depth = depth + !call->is_pasted; - if (!call->fun->visit2) - { - if (!remove_cycles (call->fun, info, &call->max_depth)) - return FALSE; - if (max_depth < call->max_depth) - max_depth = call->max_depth; - } - else if (call->fun->marking) - { - struct spu_link_hash_table *htab = spu_hash_table (info); - - if (!htab->params->auto_overlay - && htab->params->stack_analysis) - { - const char *f1 = func_name (fun); - const char *f2 = func_name (call->fun); - - /* xgettext:c-format */ - info->callbacks->info (_("Stack analysis will ignore the call " - "from %s to %s\n"), - f1, f2); - } - - call->broken_cycle = TRUE; - } - callp = &call->next; - } - fun->marking = FALSE; - *(unsigned int *) param = max_depth; - return TRUE; -} - -/* Check that we actually visited all nodes in remove_cycles. If we - didn't, then there is some cycle in the call graph not attached to - any root node. Arbitrarily choose a node in the cycle as a new - root and break the cycle. */ - -static bfd_boolean -mark_detached_root (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - if (fun->visit2) - return TRUE; - fun->non_root = FALSE; - *(unsigned int *) param = 0; - return remove_cycles (fun, info, param); -} - -/* Populate call_list for each function. */ - -static bfd_boolean -build_call_tree (struct bfd_link_info *info) -{ - bfd *ibfd; - unsigned int depth; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - extern const bfd_target spu_elf32_vec; - asection *sec; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (!mark_functions_via_relocs (sec, info, TRUE)) - return FALSE; - } - - /* Transfer call info from hot/cold section part of function - to main entry. */ - if (!spu_hash_table (info)->params->auto_overlay - && !for_each_node (transfer_calls, info, 0, FALSE)) - return FALSE; - - /* Find the call graph root(s). */ - if (!for_each_node (mark_non_root, info, 0, FALSE)) - return FALSE; - - /* Remove cycles from the call graph. We start from the root node(s) - so that we break cycles in a reasonable place. */ - depth = 0; - if (!for_each_node (remove_cycles, info, &depth, TRUE)) - return FALSE; - - return for_each_node (mark_detached_root, info, &depth, FALSE); -} - -/* qsort predicate to sort calls by priority, max_depth then count. */ - -static int -sort_calls (const void *a, const void *b) -{ - struct call_info *const *c1 = a; - struct call_info *const *c2 = b; - int delta; - - delta = (*c2)->priority - (*c1)->priority; - if (delta != 0) - return delta; - - delta = (*c2)->max_depth - (*c1)->max_depth; - if (delta != 0) - return delta; - - delta = (*c2)->count - (*c1)->count; - if (delta != 0) - return delta; - - return (char *) c1 - (char *) c2; -} - -struct _mos_param { - unsigned int max_overlay_size; -}; - -/* Set linker_mark and gc_mark on any sections that we will put in - overlays. These flags are used by the generic ELF linker, but we - won't be continuing on to bfd_elf_final_link so it is OK to use - them. linker_mark is clear before we get here. Set segment_mark - on sections that are part of a pasted function (excluding the last - section). - - Set up function rodata section if --overlay-rodata. We don't - currently include merged string constant rodata sections since - - Sort the call graph so that the deepest nodes will be visited - first. */ - -static bfd_boolean -mark_overlay_section (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - struct call_info *call; - unsigned int count; - struct _mos_param *mos_param = param; - struct spu_link_hash_table *htab = spu_hash_table (info); - - if (fun->visit4) - return TRUE; - - fun->visit4 = TRUE; - if (!fun->sec->linker_mark - && (htab->params->ovly_flavour != ovly_soft_icache - || htab->params->non_ia_text - || strncmp (fun->sec->name, ".text.ia.", 9) == 0 - || strcmp (fun->sec->name, ".init") == 0 - || strcmp (fun->sec->name, ".fini") == 0)) - { - unsigned int size; - - fun->sec->linker_mark = 1; - fun->sec->gc_mark = 1; - fun->sec->segment_mark = 0; - /* Ensure SEC_CODE is set on this text section (it ought to - be!), and SEC_CODE is clear on rodata sections. We use - this flag to differentiate the two overlay section types. */ - fun->sec->flags |= SEC_CODE; - - size = fun->sec->size; - if (htab->params->auto_overlay & OVERLAY_RODATA) - { - char *name = NULL; - - /* Find the rodata section corresponding to this function's - text section. */ - if (strcmp (fun->sec->name, ".text") == 0) - { - name = bfd_malloc (sizeof (".rodata")); - if (name == NULL) - return FALSE; - memcpy (name, ".rodata", sizeof (".rodata")); - } - else if (strncmp (fun->sec->name, ".text.", 6) == 0) - { - size_t len = strlen (fun->sec->name); - name = bfd_malloc (len + 3); - if (name == NULL) - return FALSE; - memcpy (name, ".rodata", sizeof (".rodata")); - memcpy (name + 7, fun->sec->name + 5, len - 4); - } - else if (strncmp (fun->sec->name, ".gnu.linkonce.t.", 16) == 0) - { - size_t len = strlen (fun->sec->name) + 1; - name = bfd_malloc (len); - if (name == NULL) - return FALSE; - memcpy (name, fun->sec->name, len); - name[14] = 'r'; - } - - if (name != NULL) - { - asection *rodata = NULL; - asection *group_sec = elf_section_data (fun->sec)->next_in_group; - if (group_sec == NULL) - rodata = bfd_get_section_by_name (fun->sec->owner, name); - else - while (group_sec != NULL && group_sec != fun->sec) - { - if (strcmp (group_sec->name, name) == 0) - { - rodata = group_sec; - break; - } - group_sec = elf_section_data (group_sec)->next_in_group; - } - fun->rodata = rodata; - if (fun->rodata) - { - size += fun->rodata->size; - if (htab->params->line_size != 0 - && size > htab->params->line_size) - { - size -= fun->rodata->size; - fun->rodata = NULL; - } - else - { - fun->rodata->linker_mark = 1; - fun->rodata->gc_mark = 1; - fun->rodata->flags &= ~SEC_CODE; - } - } - free (name); - } - } - if (mos_param->max_overlay_size < size) - mos_param->max_overlay_size = size; - } - - for (count = 0, call = fun->call_list; call != NULL; call = call->next) - count += 1; - - if (count > 1) - { - struct call_info **calls = bfd_malloc (count * sizeof (*calls)); - if (calls == NULL) - return FALSE; - - for (count = 0, call = fun->call_list; call != NULL; call = call->next) - calls[count++] = call; - - qsort (calls, count, sizeof (*calls), sort_calls); - - fun->call_list = NULL; - while (count != 0) - { - --count; - calls[count]->next = fun->call_list; - fun->call_list = calls[count]; - } - free (calls); - } - - for (call = fun->call_list; call != NULL; call = call->next) - { - if (call->is_pasted) - { - /* There can only be one is_pasted call per function_info. */ - BFD_ASSERT (!fun->sec->segment_mark); - fun->sec->segment_mark = 1; - } - if (!call->broken_cycle - && !mark_overlay_section (call->fun, info, param)) - return FALSE; - } - - /* Don't put entry code into an overlay. The overlay manager needs - a stack! Also, don't mark .ovl.init as an overlay. */ - if (fun->lo + fun->sec->output_offset + fun->sec->output_section->vma - == info->output_bfd->start_address - || strncmp (fun->sec->output_section->name, ".ovl.init", 9) == 0) - { - fun->sec->linker_mark = 0; - if (fun->rodata != NULL) - fun->rodata->linker_mark = 0; - } - return TRUE; -} - -/* If non-zero then unmark functions called from those within sections - that we need to unmark. Unfortunately this isn't reliable since the - call graph cannot know the destination of function pointer calls. */ -#define RECURSE_UNMARK 0 - -struct _uos_param { - asection *exclude_input_section; - asection *exclude_output_section; - unsigned long clearing; -}; - -/* Undo some of mark_overlay_section's work. */ - -static bfd_boolean -unmark_overlay_section (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - struct call_info *call; - struct _uos_param *uos_param = param; - unsigned int excluded = 0; - - if (fun->visit5) - return TRUE; - - fun->visit5 = TRUE; - - excluded = 0; - if (fun->sec == uos_param->exclude_input_section - || fun->sec->output_section == uos_param->exclude_output_section) - excluded = 1; - - if (RECURSE_UNMARK) - uos_param->clearing += excluded; - - if (RECURSE_UNMARK ? uos_param->clearing : excluded) - { - fun->sec->linker_mark = 0; - if (fun->rodata) - fun->rodata->linker_mark = 0; - } - - for (call = fun->call_list; call != NULL; call = call->next) - if (!call->broken_cycle - && !unmark_overlay_section (call->fun, info, param)) - return FALSE; - - if (RECURSE_UNMARK) - uos_param->clearing -= excluded; - return TRUE; -} - -struct _cl_param { - unsigned int lib_size; - asection **lib_sections; -}; - -/* Add sections we have marked as belonging to overlays to an array - for consideration as non-overlay sections. The array consist of - pairs of sections, (text,rodata), for functions in the call graph. */ - -static bfd_boolean -collect_lib_sections (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - struct _cl_param *lib_param = param; - struct call_info *call; - unsigned int size; - - if (fun->visit6) - return TRUE; - - fun->visit6 = TRUE; - if (!fun->sec->linker_mark || !fun->sec->gc_mark || fun->sec->segment_mark) - return TRUE; - - size = fun->sec->size; - if (fun->rodata) - size += fun->rodata->size; - - if (size <= lib_param->lib_size) - { - *lib_param->lib_sections++ = fun->sec; - fun->sec->gc_mark = 0; - if (fun->rodata && fun->rodata->linker_mark && fun->rodata->gc_mark) - { - *lib_param->lib_sections++ = fun->rodata; - fun->rodata->gc_mark = 0; - } - else - *lib_param->lib_sections++ = NULL; - } - - for (call = fun->call_list; call != NULL; call = call->next) - if (!call->broken_cycle) - collect_lib_sections (call->fun, info, param); - - return TRUE; -} - -/* qsort predicate to sort sections by call count. */ - -static int -sort_lib (const void *a, const void *b) -{ - asection *const *s1 = a; - asection *const *s2 = b; - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - int delta; - - delta = 0; - if ((sec_data = spu_elf_section_data (*s1)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL) - { - int i; - for (i = 0; i < sinfo->num_fun; ++i) - delta -= sinfo->fun[i].call_count; - } - - if ((sec_data = spu_elf_section_data (*s2)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL) - { - int i; - for (i = 0; i < sinfo->num_fun; ++i) - delta += sinfo->fun[i].call_count; - } - - if (delta != 0) - return delta; - - return s1 - s2; -} - -/* Remove some sections from those marked to be in overlays. Choose - those that are called from many places, likely library functions. */ - -static unsigned int -auto_ovl_lib_functions (struct bfd_link_info *info, unsigned int lib_size) -{ - bfd *ibfd; - asection **lib_sections; - unsigned int i, lib_count; - struct _cl_param collect_lib_param; - struct function_info dummy_caller; - struct spu_link_hash_table *htab; - - memset (&dummy_caller, 0, sizeof (dummy_caller)); - lib_count = 0; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - extern const bfd_target spu_elf32_vec; - asection *sec; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (sec->linker_mark - && sec->size < lib_size - && (sec->flags & SEC_CODE) != 0) - lib_count += 1; - } - lib_sections = bfd_malloc (lib_count * 2 * sizeof (*lib_sections)); - if (lib_sections == NULL) - return (unsigned int) -1; - collect_lib_param.lib_size = lib_size; - collect_lib_param.lib_sections = lib_sections; - if (!for_each_node (collect_lib_sections, info, &collect_lib_param, - TRUE)) - return (unsigned int) -1; - lib_count = (collect_lib_param.lib_sections - lib_sections) / 2; - - /* Sort sections so that those with the most calls are first. */ - if (lib_count > 1) - qsort (lib_sections, lib_count, 2 * sizeof (*lib_sections), sort_lib); - - htab = spu_hash_table (info); - for (i = 0; i < lib_count; i++) - { - unsigned int tmp, stub_size; - asection *sec; - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - - sec = lib_sections[2 * i]; - /* If this section is OK, its size must be less than lib_size. */ - tmp = sec->size; - /* If it has a rodata section, then add that too. */ - if (lib_sections[2 * i + 1]) - tmp += lib_sections[2 * i + 1]->size; - /* Add any new overlay call stubs needed by the section. */ - stub_size = 0; - if (tmp < lib_size - && (sec_data = spu_elf_section_data (sec)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL) - { - int k; - struct call_info *call; - - for (k = 0; k < sinfo->num_fun; ++k) - for (call = sinfo->fun[k].call_list; call; call = call->next) - if (call->fun->sec->linker_mark) - { - struct call_info *p; - for (p = dummy_caller.call_list; p; p = p->next) - if (p->fun == call->fun) - break; - if (!p) - stub_size += ovl_stub_size (htab->params); - } - } - if (tmp + stub_size < lib_size) - { - struct call_info **pp, *p; - - /* This section fits. Mark it as non-overlay. */ - lib_sections[2 * i]->linker_mark = 0; - if (lib_sections[2 * i + 1]) - lib_sections[2 * i + 1]->linker_mark = 0; - lib_size -= tmp + stub_size; - /* Call stubs to the section we just added are no longer - needed. */ - pp = &dummy_caller.call_list; - while ((p = *pp) != NULL) - if (!p->fun->sec->linker_mark) - { - lib_size += ovl_stub_size (htab->params); - *pp = p->next; - free (p); - } - else - pp = &p->next; - /* Add new call stubs to dummy_caller. */ - if ((sec_data = spu_elf_section_data (sec)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL) - { - int k; - struct call_info *call; - - for (k = 0; k < sinfo->num_fun; ++k) - for (call = sinfo->fun[k].call_list; - call; - call = call->next) - if (call->fun->sec->linker_mark) - { - struct call_info *callee; - callee = bfd_malloc (sizeof (*callee)); - if (callee == NULL) - return (unsigned int) -1; - *callee = *call; - if (!insert_callee (&dummy_caller, callee)) - free (callee); - } - } - } - } - while (dummy_caller.call_list != NULL) - { - struct call_info *call = dummy_caller.call_list; - dummy_caller.call_list = call->next; - free (call); - } - for (i = 0; i < 2 * lib_count; i++) - if (lib_sections[i]) - lib_sections[i]->gc_mark = 1; - free (lib_sections); - return lib_size; -} - -/* Build an array of overlay sections. The deepest node's section is - added first, then its parent node's section, then everything called - from the parent section. The idea being to group sections to - minimise calls between different overlays. */ - -static bfd_boolean -collect_overlays (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - struct call_info *call; - bfd_boolean added_fun; - asection ***ovly_sections = param; - - if (fun->visit7) - return TRUE; - - fun->visit7 = TRUE; - for (call = fun->call_list; call != NULL; call = call->next) - if (!call->is_pasted && !call->broken_cycle) - { - if (!collect_overlays (call->fun, info, ovly_sections)) - return FALSE; - break; - } - - added_fun = FALSE; - if (fun->sec->linker_mark && fun->sec->gc_mark) - { - fun->sec->gc_mark = 0; - *(*ovly_sections)++ = fun->sec; - if (fun->rodata && fun->rodata->linker_mark && fun->rodata->gc_mark) - { - fun->rodata->gc_mark = 0; - *(*ovly_sections)++ = fun->rodata; - } - else - *(*ovly_sections)++ = NULL; - added_fun = TRUE; - - /* Pasted sections must stay with the first section. We don't - put pasted sections in the array, just the first section. - Mark subsequent sections as already considered. */ - if (fun->sec->segment_mark) - { - struct function_info *call_fun = fun; - do - { - for (call = call_fun->call_list; call != NULL; call = call->next) - if (call->is_pasted) - { - call_fun = call->fun; - call_fun->sec->gc_mark = 0; - if (call_fun->rodata) - call_fun->rodata->gc_mark = 0; - break; - } - if (call == NULL) - abort (); - } - while (call_fun->sec->segment_mark); - } - } - - for (call = fun->call_list; call != NULL; call = call->next) - if (!call->broken_cycle - && !collect_overlays (call->fun, info, ovly_sections)) - return FALSE; - - if (added_fun) - { - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - - if ((sec_data = spu_elf_section_data (fun->sec)) != NULL - && (sinfo = sec_data->u.i.stack_info) != NULL) - { - int i; - for (i = 0; i < sinfo->num_fun; ++i) - if (!collect_overlays (&sinfo->fun[i], info, ovly_sections)) - return FALSE; - } - } - - return TRUE; -} - -struct _sum_stack_param { - size_t cum_stack; - size_t overall_stack; - bfd_boolean emit_stack_syms; -}; - -/* Descend the call graph for FUN, accumulating total stack required. */ - -static bfd_boolean -sum_stack (struct function_info *fun, - struct bfd_link_info *info, - void *param) -{ - struct call_info *call; - struct function_info *max; - size_t stack, cum_stack; - const char *f1; - bfd_boolean has_call; - struct _sum_stack_param *sum_stack_param = param; - struct spu_link_hash_table *htab; - - cum_stack = fun->stack; - sum_stack_param->cum_stack = cum_stack; - if (fun->visit3) - return TRUE; - - has_call = FALSE; - max = NULL; - for (call = fun->call_list; call; call = call->next) - { - if (call->broken_cycle) - continue; - if (!call->is_pasted) - has_call = TRUE; - if (!sum_stack (call->fun, info, sum_stack_param)) - return FALSE; - stack = sum_stack_param->cum_stack; - /* Include caller stack for normal calls, don't do so for - tail calls. fun->stack here is local stack usage for - this function. */ - if (!call->is_tail || call->is_pasted || call->fun->start != NULL) - stack += fun->stack; - if (cum_stack < stack) - { - cum_stack = stack; - max = call->fun; - } - } - - sum_stack_param->cum_stack = cum_stack; - stack = fun->stack; - /* Now fun->stack holds cumulative stack. */ - fun->stack = cum_stack; - fun->visit3 = TRUE; - - if (!fun->non_root - && sum_stack_param->overall_stack < cum_stack) - sum_stack_param->overall_stack = cum_stack; - - htab = spu_hash_table (info); - if (htab->params->auto_overlay) - return TRUE; - - f1 = func_name (fun); - if (htab->params->stack_analysis) - { - if (!fun->non_root) - info->callbacks->info (" %s: 0x%v\n", f1, (bfd_vma) cum_stack); - info->callbacks->minfo ("%s: 0x%v 0x%v\n", - f1, (bfd_vma) stack, (bfd_vma) cum_stack); - - if (has_call) - { - info->callbacks->minfo (_(" calls:\n")); - for (call = fun->call_list; call; call = call->next) - if (!call->is_pasted && !call->broken_cycle) - { - const char *f2 = func_name (call->fun); - const char *ann1 = call->fun == max ? "*" : " "; - const char *ann2 = call->is_tail ? "t" : " "; - - info->callbacks->minfo (" %s%s %s\n", ann1, ann2, f2); - } - } - } - - if (sum_stack_param->emit_stack_syms) - { - char *name = bfd_malloc (18 + strlen (f1)); - struct elf_link_hash_entry *h; - - if (name == NULL) - return FALSE; - - if (fun->global || ELF_ST_BIND (fun->u.sym->st_info) == STB_GLOBAL) - sprintf (name, "__stack_%s", f1); - else - sprintf (name, "__stack_%x_%s", fun->sec->id & 0xffffffff, f1); - - h = elf_link_hash_lookup (&htab->elf, name, TRUE, TRUE, FALSE); - free (name); - if (h != NULL - && (h->root.type == bfd_link_hash_new - || h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = bfd_abs_section_ptr; - h->root.u.def.value = cum_stack; - h->size = 0; - h->type = 0; - h->ref_regular = 1; - h->def_regular = 1; - h->ref_regular_nonweak = 1; - h->forced_local = 1; - h->non_elf = 0; - } - } - - return TRUE; -} - -/* SEC is part of a pasted function. Return the call_info for the - next section of this function. */ - -static struct call_info * -find_pasted_call (asection *sec) -{ - struct _spu_elf_section_data *sec_data = spu_elf_section_data (sec); - struct spu_elf_stack_info *sinfo = sec_data->u.i.stack_info; - struct call_info *call; - int k; - - for (k = 0; k < sinfo->num_fun; ++k) - for (call = sinfo->fun[k].call_list; call != NULL; call = call->next) - if (call->is_pasted) - return call; - abort (); - return 0; -} - -/* qsort predicate to sort bfds by file name. */ - -static int -sort_bfds (const void *a, const void *b) -{ - bfd *const *abfd1 = a; - bfd *const *abfd2 = b; - - return filename_cmp ((*abfd1)->filename, (*abfd2)->filename); -} - -static unsigned int -print_one_overlay_section (FILE *script, - unsigned int base, - unsigned int count, - unsigned int ovlynum, - unsigned int *ovly_map, - asection **ovly_sections, - struct bfd_link_info *info) -{ - unsigned int j; - - for (j = base; j < count && ovly_map[j] == ovlynum; j++) - { - asection *sec = ovly_sections[2 * j]; - - if (fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) - return -1; - if (sec->segment_mark) - { - struct call_info *call = find_pasted_call (sec); - while (call != NULL) - { - struct function_info *call_fun = call->fun; - sec = call_fun->sec; - if (fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) - return -1; - for (call = call_fun->call_list; call; call = call->next) - if (call->is_pasted) - break; - } - } - } - - for (j = base; j < count && ovly_map[j] == ovlynum; j++) - { - asection *sec = ovly_sections[2 * j + 1]; - if (sec != NULL - && fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) - return -1; - - sec = ovly_sections[2 * j]; - if (sec->segment_mark) - { - struct call_info *call = find_pasted_call (sec); - while (call != NULL) - { - struct function_info *call_fun = call->fun; - sec = call_fun->rodata; - if (sec != NULL - && fprintf (script, " %s%c%s (%s)\n", - (sec->owner->my_archive != NULL - ? sec->owner->my_archive->filename : ""), - info->path_separator, - sec->owner->filename, - sec->name) <= 0) - return -1; - for (call = call_fun->call_list; call; call = call->next) - if (call->is_pasted) - break; - } - } - } - - return j; -} - -/* Handle --auto-overlay. */ - -static void -spu_elf_auto_overlay (struct bfd_link_info *info) -{ - bfd *ibfd; - bfd **bfd_arr; - struct elf_segment_map *m; - unsigned int fixed_size, lo, hi; - unsigned int reserved; - struct spu_link_hash_table *htab; - unsigned int base, i, count, bfd_count; - unsigned int region, ovlynum; - asection **ovly_sections, **ovly_p; - unsigned int *ovly_map; - FILE *script; - unsigned int total_overlay_size, overlay_size; - const char *ovly_mgr_entry; - struct elf_link_hash_entry *h; - struct _mos_param mos_param; - struct _uos_param uos_param; - struct function_info dummy_caller; - - /* Find the extents of our loadable image. */ - lo = (unsigned int) -1; - hi = 0; - for (m = elf_seg_map (info->output_bfd); m != NULL; m = m->next) - if (m->p_type == PT_LOAD) - for (i = 0; i < m->count; i++) - if (m->sections[i]->size != 0) - { - if (m->sections[i]->vma < lo) - lo = m->sections[i]->vma; - if (m->sections[i]->vma + m->sections[i]->size - 1 > hi) - hi = m->sections[i]->vma + m->sections[i]->size - 1; - } - fixed_size = hi + 1 - lo; - - if (!discover_functions (info)) - goto err_exit; - - if (!build_call_tree (info)) - goto err_exit; - - htab = spu_hash_table (info); - reserved = htab->params->auto_overlay_reserved; - if (reserved == 0) - { - struct _sum_stack_param sum_stack_param; - - sum_stack_param.emit_stack_syms = 0; - sum_stack_param.overall_stack = 0; - if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) - goto err_exit; - reserved = (sum_stack_param.overall_stack - + htab->params->extra_stack_space); - } - - /* No need for overlays if everything already fits. */ - if (fixed_size + reserved <= htab->local_store - && htab->params->ovly_flavour != ovly_soft_icache) - { - htab->params->auto_overlay = 0; - return; - } - - uos_param.exclude_input_section = 0; - uos_param.exclude_output_section - = bfd_get_section_by_name (info->output_bfd, ".interrupt"); - - ovly_mgr_entry = "__ovly_load"; - if (htab->params->ovly_flavour == ovly_soft_icache) - ovly_mgr_entry = "__icache_br_handler"; - h = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry, - FALSE, FALSE, FALSE); - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->def_regular) - { - /* We have a user supplied overlay manager. */ - uos_param.exclude_input_section = h->root.u.def.section; - } - else - { - /* If no user overlay manager, spu_elf_load_ovl_mgr will add our - builtin version to .text, and will adjust .text size. */ - fixed_size += (*htab->params->spu_elf_load_ovl_mgr) (); - } - - /* Mark overlay sections, and find max overlay section size. */ - mos_param.max_overlay_size = 0; - if (!for_each_node (mark_overlay_section, info, &mos_param, TRUE)) - goto err_exit; - - /* We can't put the overlay manager or interrupt routines in - overlays. */ - uos_param.clearing = 0; - if ((uos_param.exclude_input_section - || uos_param.exclude_output_section) - && !for_each_node (unmark_overlay_section, info, &uos_param, TRUE)) - goto err_exit; - - bfd_count = 0; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - ++bfd_count; - bfd_arr = bfd_malloc (bfd_count * sizeof (*bfd_arr)); - if (bfd_arr == NULL) - goto err_exit; - - /* Count overlay sections, and subtract their sizes from "fixed_size". */ - count = 0; - bfd_count = 0; - total_overlay_size = 0; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - extern const bfd_target spu_elf32_vec; - asection *sec; - unsigned int old_count; - - if (ibfd->xvec != &spu_elf32_vec) - continue; - - old_count = count; - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (sec->linker_mark) - { - if ((sec->flags & SEC_CODE) != 0) - count += 1; - fixed_size -= sec->size; - total_overlay_size += sec->size; - } - else if ((sec->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD) - && sec->output_section->owner == info->output_bfd - && strncmp (sec->output_section->name, ".ovl.init", 9) == 0) - fixed_size -= sec->size; - if (count != old_count) - bfd_arr[bfd_count++] = ibfd; - } - - /* Since the overlay link script selects sections by file name and - section name, ensure that file names are unique. */ - if (bfd_count > 1) - { - bfd_boolean ok = TRUE; - - qsort (bfd_arr, bfd_count, sizeof (*bfd_arr), sort_bfds); - for (i = 1; i < bfd_count; ++i) - if (filename_cmp (bfd_arr[i - 1]->filename, bfd_arr[i]->filename) == 0) - { - if (bfd_arr[i - 1]->my_archive == bfd_arr[i]->my_archive) - { - if (bfd_arr[i - 1]->my_archive && bfd_arr[i]->my_archive) - /* xgettext:c-format */ - info->callbacks->einfo (_("%s duplicated in %s\n"), - bfd_arr[i]->filename, - bfd_arr[i]->my_archive->filename); - else - info->callbacks->einfo (_("%s duplicated\n"), - bfd_arr[i]->filename); - ok = FALSE; - } - } - if (!ok) - { - info->callbacks->einfo (_("sorry, no support for duplicate " - "object files in auto-overlay script\n")); - bfd_set_error (bfd_error_bad_value); - goto err_exit; - } - } - free (bfd_arr); - - fixed_size += reserved; - fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params); - if (fixed_size + mos_param.max_overlay_size <= htab->local_store) - { - if (htab->params->ovly_flavour == ovly_soft_icache) - { - /* Stubs in the non-icache area are bigger. */ - fixed_size += htab->non_ovly_stub * 16; - /* Space for icache manager tables. - a) Tag array, one quadword per cache line. - - word 0: ia address of present line, init to zero. */ - fixed_size += 16 << htab->num_lines_log2; - /* b) Rewrite "to" list, one quadword per cache line. */ - fixed_size += 16 << htab->num_lines_log2; - /* c) Rewrite "from" list, one byte per outgoing branch (rounded up - to a power-of-two number of full quadwords) per cache line. */ - fixed_size += 16 << (htab->fromelem_size_log2 - + htab->num_lines_log2); - /* d) Pointer to __ea backing store (toe), 1 quadword. */ - fixed_size += 16; - } - else - { - /* Guess number of overlays. Assuming overlay buffer is on - average only half full should be conservative. */ - ovlynum = (total_overlay_size * 2 * htab->params->num_lines - / (htab->local_store - fixed_size)); - /* Space for _ovly_table[], _ovly_buf_table[] and toe. */ - fixed_size += ovlynum * 16 + 16 + 4 + 16; - } - } - - if (fixed_size + mos_param.max_overlay_size > htab->local_store) - /* xgettext:c-format */ - info->callbacks->einfo (_("non-overlay size of 0x%v plus maximum overlay " - "size of 0x%v exceeds local store\n"), - (bfd_vma) fixed_size, - (bfd_vma) mos_param.max_overlay_size); - - /* Now see if we should put some functions in the non-overlay area. */ - else if (fixed_size < htab->params->auto_overlay_fixed) - { - unsigned int max_fixed, lib_size; - - max_fixed = htab->local_store - mos_param.max_overlay_size; - if (max_fixed > htab->params->auto_overlay_fixed) - max_fixed = htab->params->auto_overlay_fixed; - lib_size = max_fixed - fixed_size; - lib_size = auto_ovl_lib_functions (info, lib_size); - if (lib_size == (unsigned int) -1) - goto err_exit; - fixed_size = max_fixed - lib_size; - } - - /* Build an array of sections, suitably sorted to place into - overlays. */ - ovly_sections = bfd_malloc (2 * count * sizeof (*ovly_sections)); - if (ovly_sections == NULL) - goto err_exit; - ovly_p = ovly_sections; - if (!for_each_node (collect_overlays, info, &ovly_p, TRUE)) - goto err_exit; - count = (size_t) (ovly_p - ovly_sections) / 2; - ovly_map = bfd_malloc (count * sizeof (*ovly_map)); - if (ovly_map == NULL) - goto err_exit; - - memset (&dummy_caller, 0, sizeof (dummy_caller)); - overlay_size = (htab->local_store - fixed_size) / htab->params->num_lines; - if (htab->params->line_size != 0) - overlay_size = htab->params->line_size; - base = 0; - ovlynum = 0; - while (base < count) - { - unsigned int size = 0, rosize = 0, roalign = 0; - - for (i = base; i < count; i++) - { - asection *sec, *rosec; - unsigned int tmp, rotmp; - unsigned int num_stubs; - struct call_info *call, *pasty; - struct _spu_elf_section_data *sec_data; - struct spu_elf_stack_info *sinfo; - unsigned int k; - - /* See whether we can add this section to the current - overlay without overflowing our overlay buffer. */ - sec = ovly_sections[2 * i]; - tmp = align_power (size, sec->alignment_power) + sec->size; - rotmp = rosize; - rosec = ovly_sections[2 * i + 1]; - if (rosec != NULL) - { - rotmp = align_power (rotmp, rosec->alignment_power) + rosec->size; - if (roalign < rosec->alignment_power) - roalign = rosec->alignment_power; - } - if (align_power (tmp, roalign) + rotmp > overlay_size) - break; - if (sec->segment_mark) - { - /* Pasted sections must stay together, so add their - sizes too. */ - pasty = find_pasted_call (sec); - while (pasty != NULL) - { - struct function_info *call_fun = pasty->fun; - tmp = (align_power (tmp, call_fun->sec->alignment_power) - + call_fun->sec->size); - if (call_fun->rodata) - { - rotmp = (align_power (rotmp, - call_fun->rodata->alignment_power) - + call_fun->rodata->size); - if (roalign < rosec->alignment_power) - roalign = rosec->alignment_power; - } - for (pasty = call_fun->call_list; pasty; pasty = pasty->next) - if (pasty->is_pasted) - break; - } - } - if (align_power (tmp, roalign) + rotmp > overlay_size) - break; - - /* If we add this section, we might need new overlay call - stubs. Add any overlay section calls to dummy_call. */ - pasty = NULL; - sec_data = spu_elf_section_data (sec); - sinfo = sec_data->u.i.stack_info; - for (k = 0; k < (unsigned) sinfo->num_fun; ++k) - for (call = sinfo->fun[k].call_list; call; call = call->next) - if (call->is_pasted) - { - BFD_ASSERT (pasty == NULL); - pasty = call; - } - else if (call->fun->sec->linker_mark) - { - if (!copy_callee (&dummy_caller, call)) - goto err_exit; - } - while (pasty != NULL) - { - struct function_info *call_fun = pasty->fun; - pasty = NULL; - for (call = call_fun->call_list; call; call = call->next) - if (call->is_pasted) - { - BFD_ASSERT (pasty == NULL); - pasty = call; - } - else if (!copy_callee (&dummy_caller, call)) - goto err_exit; - } - - /* Calculate call stub size. */ - num_stubs = 0; - for (call = dummy_caller.call_list; call; call = call->next) - { - unsigned int stub_delta = 1; - - if (htab->params->ovly_flavour == ovly_soft_icache) - stub_delta = call->count; - num_stubs += stub_delta; - - /* If the call is within this overlay, we won't need a - stub. */ - for (k = base; k < i + 1; k++) - if (call->fun->sec == ovly_sections[2 * k]) - { - num_stubs -= stub_delta; - break; - } - } - if (htab->params->ovly_flavour == ovly_soft_icache - && num_stubs > htab->params->max_branch) - break; - if (align_power (tmp, roalign) + rotmp - + num_stubs * ovl_stub_size (htab->params) > overlay_size) - break; - size = tmp; - rosize = rotmp; - } - - if (i == base) - { - /* xgettext:c-format */ - info->callbacks->einfo (_("%B:%A%s exceeds overlay size\n"), - ovly_sections[2 * i]->owner, - ovly_sections[2 * i], - ovly_sections[2 * i + 1] ? " + rodata" : ""); - bfd_set_error (bfd_error_bad_value); - goto err_exit; - } - - while (dummy_caller.call_list != NULL) - { - struct call_info *call = dummy_caller.call_list; - dummy_caller.call_list = call->next; - free (call); - } - - ++ovlynum; - while (base < i) - ovly_map[base++] = ovlynum; - } - - script = htab->params->spu_elf_open_overlay_script (); - - if (htab->params->ovly_flavour == ovly_soft_icache) - { - if (fprintf (script, "SECTIONS\n{\n") <= 0) - goto file_err; - - if (fprintf (script, - " . = ALIGN (%u);\n" - " .ovl.init : { *(.ovl.init) }\n" - " . = ABSOLUTE (ADDR (.ovl.init));\n", - htab->params->line_size) <= 0) - goto file_err; - - base = 0; - ovlynum = 1; - while (base < count) - { - unsigned int indx = ovlynum - 1; - unsigned int vma, lma; - - vma = (indx & (htab->params->num_lines - 1)) << htab->line_size_log2; - lma = vma + (((indx >> htab->num_lines_log2) + 1) << 18); - - if (fprintf (script, " .ovly%u ABSOLUTE (ADDR (.ovl.init)) + %u " - ": AT (LOADADDR (.ovl.init) + %u) {\n", - ovlynum, vma, lma) <= 0) - goto file_err; - - base = print_one_overlay_section (script, base, count, ovlynum, - ovly_map, ovly_sections, info); - if (base == (unsigned) -1) - goto file_err; - - if (fprintf (script, " }\n") <= 0) - goto file_err; - - ovlynum++; - } - - if (fprintf (script, " . = ABSOLUTE (ADDR (.ovl.init)) + %u;\n", - 1 << (htab->num_lines_log2 + htab->line_size_log2)) <= 0) - goto file_err; - - if (fprintf (script, "}\nINSERT AFTER .toe;\n") <= 0) - goto file_err; - } - else - { - if (fprintf (script, "SECTIONS\n{\n") <= 0) - goto file_err; - - if (fprintf (script, - " . = ALIGN (16);\n" - " .ovl.init : { *(.ovl.init) }\n" - " . = ABSOLUTE (ADDR (.ovl.init));\n") <= 0) - goto file_err; - - for (region = 1; region <= htab->params->num_lines; region++) - { - ovlynum = region; - base = 0; - while (base < count && ovly_map[base] < ovlynum) - base++; - - if (base == count) - break; - - if (region == 1) - { - /* We need to set lma since we are overlaying .ovl.init. */ - if (fprintf (script, - " OVERLAY : AT (ALIGN (LOADADDR (.ovl.init) + SIZEOF (.ovl.init), 16))\n {\n") <= 0) - goto file_err; - } - else - { - if (fprintf (script, " OVERLAY :\n {\n") <= 0) - goto file_err; - } - - while (base < count) - { - if (fprintf (script, " .ovly%u {\n", ovlynum) <= 0) - goto file_err; - - base = print_one_overlay_section (script, base, count, ovlynum, - ovly_map, ovly_sections, info); - if (base == (unsigned) -1) - goto file_err; - - if (fprintf (script, " }\n") <= 0) - goto file_err; - - ovlynum += htab->params->num_lines; - while (base < count && ovly_map[base] < ovlynum) - base++; - } - - if (fprintf (script, " }\n") <= 0) - goto file_err; - } - - if (fprintf (script, "}\nINSERT BEFORE .text;\n") <= 0) - goto file_err; - } - - free (ovly_map); - free (ovly_sections); - - if (fclose (script) != 0) - goto file_err; - - if (htab->params->auto_overlay & AUTO_RELINK) - (*htab->params->spu_elf_relink) (); - - xexit (0); - - file_err: - bfd_set_error (bfd_error_system_call); - err_exit: - info->callbacks->einfo (_("%F%P: auto overlay error: %E\n")); - xexit (1); -} - -/* Provide an estimate of total stack required. */ - -static bfd_boolean -spu_elf_stack_analysis (struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab; - struct _sum_stack_param sum_stack_param; - - if (!discover_functions (info)) - return FALSE; - - if (!build_call_tree (info)) - return FALSE; - - htab = spu_hash_table (info); - if (htab->params->stack_analysis) - { - info->callbacks->info (_("Stack size for call graph root nodes.\n")); - info->callbacks->minfo (_("\nStack size for functions. " - "Annotations: '*' max stack, 't' tail call\n")); - } - - sum_stack_param.emit_stack_syms = htab->params->emit_stack_syms; - sum_stack_param.overall_stack = 0; - if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) - return FALSE; - - if (htab->params->stack_analysis) - info->callbacks->info (_("Maximum stack required is 0x%v\n"), - (bfd_vma) sum_stack_param.overall_stack); - return TRUE; -} - -/* Perform a final link. */ - -static bfd_boolean -spu_elf_final_link (bfd *output_bfd, struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - - if (htab->params->auto_overlay) - spu_elf_auto_overlay (info); - - if ((htab->params->stack_analysis - || (htab->params->ovly_flavour == ovly_soft_icache - && htab->params->lrlive_analysis)) - && !spu_elf_stack_analysis (info)) - info->callbacks->einfo (_("%X%P: stack/lrlive analysis error: %E\n")); - - if (!spu_elf_build_stubs (info)) - info->callbacks->einfo (_("%F%P: can not build overlay stubs: %E\n")); - - return bfd_elf_final_link (output_bfd, info); -} - -/* Called when not normally emitting relocs, ie. !bfd_link_relocatable (info) - and !info->emitrelocations. Returns a count of special relocs - that need to be emitted. */ - -static unsigned int -spu_elf_count_relocs (struct bfd_link_info *info, asection *sec) -{ - Elf_Internal_Rela *relocs; - unsigned int count = 0; - - relocs = _bfd_elf_link_read_relocs (sec->owner, sec, NULL, NULL, - info->keep_memory); - if (relocs != NULL) - { - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend = relocs + sec->reloc_count; - - for (rel = relocs; rel < relend; rel++) - { - int r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) - ++count; - } - - if (elf_section_data (sec)->relocs != relocs) - free (relocs); - } - - return count; -} - -/* Functions for adding fixup records to .fixup */ - -#define FIXUP_RECORD_SIZE 4 - -#define FIXUP_PUT(output_bfd,htab,index,addr) \ - bfd_put_32 (output_bfd, addr, \ - htab->sfixup->contents + FIXUP_RECORD_SIZE * (index)) -#define FIXUP_GET(output_bfd,htab,index) \ - bfd_get_32 (output_bfd, \ - htab->sfixup->contents + FIXUP_RECORD_SIZE * (index)) - -/* Store OFFSET in .fixup. This assumes it will be called with an - increasing OFFSET. When this OFFSET fits with the last base offset, - it just sets a bit, otherwise it adds a new fixup record. */ -static void -spu_elf_emit_fixup (bfd * output_bfd, struct bfd_link_info *info, - bfd_vma offset) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - asection *sfixup = htab->sfixup; - bfd_vma qaddr = offset & ~(bfd_vma) 15; - bfd_vma bit = ((bfd_vma) 8) >> ((offset & 15) >> 2); - if (sfixup->reloc_count == 0) - { - FIXUP_PUT (output_bfd, htab, 0, qaddr | bit); - sfixup->reloc_count++; - } - else - { - bfd_vma base = FIXUP_GET (output_bfd, htab, sfixup->reloc_count - 1); - if (qaddr != (base & ~(bfd_vma) 15)) - { - if ((sfixup->reloc_count + 1) * FIXUP_RECORD_SIZE > sfixup->size) - _bfd_error_handler (_("fatal error while creating .fixup")); - FIXUP_PUT (output_bfd, htab, sfixup->reloc_count, qaddr | bit); - sfixup->reloc_count++; - } - else - FIXUP_PUT (output_bfd, htab, sfixup->reloc_count - 1, base | bit); - } -} - -/* Apply RELOCS to CONTENTS of INPUT_SECTION from INPUT_BFD. */ - -static int -spu_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - struct spu_link_hash_table *htab; - asection *ea; - int ret = TRUE; - bfd_boolean emit_these_relocs = FALSE; - bfd_boolean is_ea_sym; - bfd_boolean stubs; - unsigned int iovl = 0; - - htab = spu_hash_table (info); - stubs = (htab->stub_sec != NULL - && maybe_needs_stubs (input_section)); - iovl = overlay_index (input_section); - ea = bfd_get_section_by_name (output_bfd, "._ea"); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd)); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned int r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - const char *sym_name; - bfd_vma relocation; - bfd_vma addend; - bfd_reloc_status_type r; - bfd_boolean unresolved_reloc; - enum _stub_type stub_type; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - howto = elf_howto_table + r_type; - unresolved_reloc = FALSE; - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - if (sym_hashes == NULL) - return FALSE; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - h = ((struct elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &h->root)); - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - 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 if (!bfd_link_relocatable (info) - && !(r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64)) - { - bfd_boolean err; - err = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR - || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT); - (*info->callbacks->undefined_symbol) (info, - h->root.root.string, - input_bfd, - input_section, - rel->r_offset, err); - } - sym_name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - /* Change "a rt,ra,rb" to "ai rt,ra,0". */ - if (r_type == R_SPU_ADD_PIC - && h != NULL - && !(h->def_regular || ELF_COMMON_DEF_P (h))) - { - bfd_byte *loc = contents + rel->r_offset; - loc[0] = 0x1c; - loc[1] = 0x00; - loc[2] &= 0x3f; - } - - is_ea_sym = (ea != NULL - && sec != NULL - && sec->output_section == ea); - - /* If this symbol is in an overlay area, we may need to relocate - to the overlay stub. */ - addend = rel->r_addend; - if (stubs - && !is_ea_sym - && (stub_type = needs_ovl_stub (h, sym, sec, input_section, rel, - contents, info)) != no_stub) - { - unsigned int ovl = 0; - struct got_entry *g, **head; - - if (stub_type != nonovl_stub) - ovl = iovl; - - if (h != NULL) - head = &h->got.glist; - else - head = elf_local_got_ents (input_bfd) + r_symndx; - - for (g = *head; g != NULL; g = g->next) - if (htab->params->ovly_flavour == ovly_soft_icache - ? (g->ovl == ovl - && g->br_addr == (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma)) - : g->addend == addend && (g->ovl == ovl || g->ovl == 0)) - break; - if (g == NULL) - abort (); - - relocation = g->stub_addr; - addend = 0; - } - else - { - /* For soft icache, encode the overlay index into addresses. */ - if (htab->params->ovly_flavour == ovly_soft_icache - && (r_type == R_SPU_ADDR16_HI - || r_type == R_SPU_ADDR32 || r_type == R_SPU_REL32) - && !is_ea_sym) - { - unsigned int ovl = overlay_index (sec); - if (ovl != 0) - { - unsigned int set_id = ((ovl - 1) >> htab->num_lines_log2) + 1; - relocation += set_id << 18; - } - } - } - - if (htab->params->emit_fixups && !bfd_link_relocatable (info) - && (input_section->flags & SEC_ALLOC) != 0 - && r_type == R_SPU_ADDR32) - { - bfd_vma offset; - offset = rel->r_offset + input_section->output_section->vma - + input_section->output_offset; - spu_elf_emit_fixup (output_bfd, info, offset); - } - - if (unresolved_reloc) - ; - else if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) - { - if (is_ea_sym) - { - /* ._ea is a special section that isn't allocated in SPU - memory, but rather occupies space in PPU memory as - part of an embedded ELF image. If this reloc is - against a symbol defined in ._ea, then transform the - reloc into an equivalent one without a symbol - relative to the start of the ELF image. */ - rel->r_addend += (relocation - - ea->vma - + elf_section_data (ea)->this_hdr.sh_offset); - rel->r_info = ELF32_R_INFO (0, r_type); - } - emit_these_relocs = TRUE; - continue; - } - else if (is_ea_sym) - unresolved_reloc = TRUE; - - if (unresolved_reloc - && _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%s+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - bfd_get_section_name (input_bfd, input_section), - rel->r_offset, - howto->name, - sym_name); - ret = FALSE; - } - - r = _bfd_final_link_relocate (howto, - input_bfd, - input_section, - contents, - rel->r_offset, relocation, addend); - - if (r != bfd_reloc_ok) - { - const char *msg = (const char *) 0; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), sym_name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, sym_name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous error"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - ret = FALSE; - (*info->callbacks->warning) (info, msg, sym_name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - if (ret - && emit_these_relocs - && !info->emitrelocations) - { - Elf_Internal_Rela *wrel; - Elf_Internal_Shdr *rel_hdr; - - wrel = rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) - *wrel++ = *rel; - } - input_section->reloc_count = wrel - relocs; - /* Backflips for _bfd_elf_link_output_relocs. */ - rel_hdr = _bfd_elf_single_rel_hdr (input_section); - rel_hdr->sh_size = input_section->reloc_count * rel_hdr->sh_entsize; - ret = 2; - } - - return ret; -} - -static bfd_boolean -spu_elf_finish_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Adjust _SPUEAR_ syms to point at their overlay stubs. */ - -static int -spu_elf_output_symbol_hook (struct bfd_link_info *info, - const char *sym_name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *sym_sec ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - - if (!bfd_link_relocatable (info) - && htab->stub_sec != NULL - && h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->def_regular - && strncmp (h->root.root.string, "_SPUEAR_", 8) == 0) - { - struct got_entry *g; - - for (g = h->got.glist; g != NULL; g = g->next) - if (htab->params->ovly_flavour == ovly_soft_icache - ? g->br_addr == g->stub_addr - : g->addend == 0 && g->ovl == 0) - { - sym->st_shndx = (_bfd_elf_section_from_bfd_section - (htab->stub_sec[0]->output_section->owner, - htab->stub_sec[0]->output_section)); - sym->st_value = g->stub_addr; - break; - } - } - - return 1; -} - -static int spu_plugin = 0; - -void -spu_elf_plugin (int val) -{ - spu_plugin = val; -} - -/* Set ELF header e_type for plugins. */ - -static void -spu_elf_post_process_headers (bfd *abfd, struct bfd_link_info *info) -{ - if (spu_plugin) - { - Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - - i_ehdrp->e_type = ET_DYN; - } - - _bfd_elf_post_process_headers (abfd, info); -} - -/* We may add an extra PT_LOAD segment for .toe. We also need extra - segments for overlays. */ - -static int -spu_elf_additional_program_headers (bfd *abfd, struct bfd_link_info *info) -{ - int extra = 0; - asection *sec; - - if (info != NULL) - { - struct spu_link_hash_table *htab = spu_hash_table (info); - extra = htab->num_overlays; - } - - if (extra) - ++extra; - - sec = bfd_get_section_by_name (abfd, ".toe"); - if (sec != NULL && (sec->flags & SEC_LOAD) != 0) - ++extra; - - return extra; -} - -/* Remove .toe section from other PT_LOAD segments and put it in - a segment of its own. Put overlays in separate segments too. */ - -static bfd_boolean -spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) -{ - asection *toe, *s; - struct elf_segment_map *m, *m_overlay; - struct elf_segment_map **p, **p_overlay; - unsigned int i; - - if (info == NULL) - return TRUE; - - toe = bfd_get_section_by_name (abfd, ".toe"); - for (m = elf_seg_map (abfd); m != NULL; m = m->next) - if (m->p_type == PT_LOAD && m->count > 1) - for (i = 0; i < m->count; i++) - if ((s = m->sections[i]) == toe - || spu_elf_section_data (s)->u.o.ovl_index != 0) - { - struct elf_segment_map *m2; - bfd_vma amt; - - if (i + 1 < m->count) - { - amt = sizeof (struct elf_segment_map); - amt += (m->count - (i + 2)) * sizeof (m->sections[0]); - m2 = bfd_zalloc (abfd, amt); - if (m2 == NULL) - return FALSE; - m2->count = m->count - (i + 1); - memcpy (m2->sections, m->sections + i + 1, - m2->count * sizeof (m->sections[0])); - m2->p_type = PT_LOAD; - m2->next = m->next; - m->next = m2; - } - m->count = 1; - if (i != 0) - { - m->count = i; - amt = sizeof (struct elf_segment_map); - m2 = bfd_zalloc (abfd, amt); - if (m2 == NULL) - return FALSE; - m2->p_type = PT_LOAD; - m2->count = 1; - m2->sections[0] = s; - m2->next = m->next; - m->next = m2; - } - break; - } - - - /* Some SPU ELF loaders ignore the PF_OVERLAY flag and just load all - PT_LOAD segments. This can cause the .ovl.init section to be - overwritten with the contents of some overlay segment. To work - around this issue, we ensure that all PF_OVERLAY segments are - sorted first amongst the program headers; this ensures that even - with a broken loader, the .ovl.init section (which is not marked - as PF_OVERLAY) will be placed into SPU local store on startup. */ - - /* Move all overlay segments onto a separate list. */ - p = &elf_seg_map (abfd); - p_overlay = &m_overlay; - while (*p != NULL) - { - if ((*p)->p_type == PT_LOAD && (*p)->count == 1 - && spu_elf_section_data ((*p)->sections[0])->u.o.ovl_index != 0) - { - m = *p; - *p = m->next; - *p_overlay = m; - p_overlay = &m->next; - continue; - } - - p = &((*p)->next); - } - - /* Re-insert overlay segments at the head of the segment map. */ - *p_overlay = elf_seg_map (abfd); - elf_seg_map (abfd) = m_overlay; - - return TRUE; -} - -/* Tweak the section type of .note.spu_name. */ - -static bfd_boolean -spu_elf_fake_sections (bfd *obfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, - asection *sec) -{ - if (strcmp (sec->name, SPU_PTNOTE_SPUNAME) == 0) - hdr->sh_type = SHT_NOTE; - return TRUE; -} - -/* Tweak phdrs before writing them out. */ - -static int -spu_elf_modify_program_headers (bfd *abfd, struct bfd_link_info *info) -{ - const struct elf_backend_data *bed; - struct elf_obj_tdata *tdata; - Elf_Internal_Phdr *phdr, *last; - struct spu_link_hash_table *htab; - unsigned int count; - unsigned int i; - - if (info == NULL) - return TRUE; - - bed = get_elf_backend_data (abfd); - tdata = elf_tdata (abfd); - phdr = tdata->phdr; - count = elf_program_header_size (abfd) / bed->s->sizeof_phdr; - htab = spu_hash_table (info); - if (htab->num_overlays != 0) - { - struct elf_segment_map *m; - unsigned int o; - - for (i = 0, m = elf_seg_map (abfd); m; ++i, m = m->next) - if (m->count != 0 - && (o = spu_elf_section_data (m->sections[0])->u.o.ovl_index) != 0) - { - /* Mark this as an overlay header. */ - phdr[i].p_flags |= PF_OVERLAY; - - if (htab->ovtab != NULL && htab->ovtab->size != 0 - && htab->params->ovly_flavour != ovly_soft_icache) - { - bfd_byte *p = htab->ovtab->contents; - unsigned int off = o * 16 + 8; - - /* Write file_off into _ovly_table. */ - bfd_put_32 (htab->ovtab->owner, phdr[i].p_offset, p + off); - } - } - /* Soft-icache has its file offset put in .ovl.init. */ - if (htab->init != NULL && htab->init->size != 0) - { - bfd_vma val = elf_section_data (htab->ovl_sec[0])->this_hdr.sh_offset; - - bfd_put_32 (htab->init->owner, val, htab->init->contents + 4); - } - } - - /* Round up p_filesz and p_memsz of PT_LOAD segments to multiples - of 16. This should always be possible when using the standard - linker scripts, but don't create overlapping segments if - someone is playing games with linker scripts. */ - last = NULL; - for (i = count; i-- != 0; ) - if (phdr[i].p_type == PT_LOAD) - { - unsigned adjust; - - adjust = -phdr[i].p_filesz & 15; - if (adjust != 0 - && last != NULL - && phdr[i].p_offset + phdr[i].p_filesz > last->p_offset - adjust) - break; - - adjust = -phdr[i].p_memsz & 15; - if (adjust != 0 - && last != NULL - && phdr[i].p_filesz != 0 - && phdr[i].p_vaddr + phdr[i].p_memsz > last->p_vaddr - adjust - && phdr[i].p_vaddr + phdr[i].p_memsz <= last->p_vaddr) - break; - - if (phdr[i].p_filesz != 0) - last = &phdr[i]; - } - - if (i == (unsigned int) -1) - for (i = count; i-- != 0; ) - if (phdr[i].p_type == PT_LOAD) - { - unsigned adjust; - - adjust = -phdr[i].p_filesz & 15; - phdr[i].p_filesz += adjust; - - adjust = -phdr[i].p_memsz & 15; - phdr[i].p_memsz += adjust; - } - - return TRUE; -} - -bfd_boolean -spu_elf_size_sections (bfd * output_bfd, struct bfd_link_info *info) -{ - struct spu_link_hash_table *htab = spu_hash_table (info); - if (htab->params->emit_fixups) - { - asection *sfixup = htab->sfixup; - int fixup_count = 0; - bfd *ibfd; - size_t size; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *isec; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - /* Walk over each section attached to the input bfd. */ - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - bfd_vma base_end; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((isec->flags & SEC_ALLOC) == 0 - || (isec->flags & SEC_RELOC) == 0 - || isec->reloc_count == 0) - continue; - - /* Get the relocs. */ - internal_relocs = - _bfd_elf_link_read_relocs (ibfd, isec, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - return FALSE; - - /* 1 quadword can contain up to 4 R_SPU_ADDR32 - relocations. They are stored in a single word by - saving the upper 28 bits of the address and setting the - lower 4 bits to a bit mask of the words that have the - relocation. BASE_END keeps track of the next quadword. */ - irela = internal_relocs; - irelaend = irela + isec->reloc_count; - base_end = 0; - for (; irela < irelaend; irela++) - if (ELF32_R_TYPE (irela->r_info) == R_SPU_ADDR32 - && irela->r_offset >= base_end) - { - base_end = (irela->r_offset & ~(bfd_vma) 15) + 16; - fixup_count++; - } - } - } - - /* We always have a NULL fixup as a sentinel */ - size = (fixup_count + 1) * FIXUP_RECORD_SIZE; - if (!bfd_set_section_size (output_bfd, sfixup, size)) - return FALSE; - sfixup->contents = (bfd_byte *) bfd_zalloc (info->input_bfds, size); - if (sfixup->contents == NULL) - return FALSE; - } - return TRUE; -} - -#define TARGET_BIG_SYM spu_elf32_vec -#define TARGET_BIG_NAME "elf32-spu" -#define ELF_ARCH bfd_arch_spu -#define ELF_TARGET_ID SPU_ELF_DATA -#define ELF_MACHINE_CODE EM_SPU -/* This matches the alignment need for DMA. */ -#define ELF_MAXPAGESIZE 0x80 -#define elf_backend_rela_normal 1 -#define elf_backend_can_gc_sections 1 - -#define bfd_elf32_bfd_reloc_type_lookup spu_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup -#define elf_info_to_howto spu_elf_info_to_howto -#define elf_backend_count_relocs spu_elf_count_relocs -#define elf_backend_relocate_section spu_elf_relocate_section -#define elf_backend_finish_dynamic_sections spu_elf_finish_dynamic_sections -#define elf_backend_symbol_processing spu_elf_backend_symbol_processing -#define elf_backend_link_output_symbol_hook spu_elf_output_symbol_hook -#define elf_backend_object_p spu_elf_object_p -#define bfd_elf32_new_section_hook spu_elf_new_section_hook -#define bfd_elf32_bfd_link_hash_table_create spu_elf_link_hash_table_create - -#define elf_backend_additional_program_headers spu_elf_additional_program_headers -#define elf_backend_modify_segment_map spu_elf_modify_segment_map -#define elf_backend_modify_program_headers spu_elf_modify_program_headers -#define elf_backend_post_process_headers spu_elf_post_process_headers -#define elf_backend_fake_sections spu_elf_fake_sections -#define elf_backend_special_sections spu_elf_special_sections -#define bfd_elf32_bfd_final_link spu_elf_final_link - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-spu.h b/sdcc/support/sdbinutils/bfd/elf32-spu.h deleted file mode 100644 index 06960411c..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-spu.h +++ /dev/null @@ -1,125 +0,0 @@ -/* SPU specific support for 32-bit ELF. - - Copyright (C) 2006-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -struct spu_elf_params -{ - /* Stash various callbacks for --auto-overlay. */ - void (*place_spu_section) (asection *, asection *, const char *); - bfd_size_type (*spu_elf_load_ovl_mgr) (void); - FILE *(*spu_elf_open_overlay_script) (void); - void (*spu_elf_relink) (void); - - /* Bit 0 set if --auto-overlay. - Bit 1 set if --auto-relink. - Bit 2 set if --overlay-rodata. */ - unsigned int auto_overlay : 3; -#define AUTO_OVERLAY 1 -#define AUTO_RELINK 2 -#define OVERLAY_RODATA 4 - - /* Type of overlays, enum _ovly_flavour. */ - unsigned int ovly_flavour : 1; - unsigned int compact_stub : 1; - - /* Set if we should emit symbols for stubs. */ - unsigned int emit_stub_syms : 1; - - /* Set if we want stubs on calls out of overlay regions to - non-overlay regions. */ - unsigned int non_overlay_stubs : 1; - - /* Set if lr liveness analysis should be done. */ - unsigned int lrlive_analysis : 1; - - /* Set if stack size analysis should be done. */ - unsigned int stack_analysis : 1; - - /* Set if __stack_* syms will be emitted. */ - unsigned int emit_stack_syms : 1; - - /* Set if non-icache code should be allowed in icache lines. */ - unsigned int non_ia_text : 1; - - /* Set when the .fixup section should be generated. */ - unsigned int emit_fixups : 1; - - /* Range of valid addresses for loadable sections. */ - bfd_vma local_store_lo; - bfd_vma local_store_hi; - - /* Control --auto-overlay feature. */ - unsigned int num_lines; - unsigned int line_size; - unsigned int max_branch; - unsigned int auto_overlay_fixed; - unsigned int auto_overlay_reserved; - int extra_stack_space; -}; - -/* Extra info kept for SPU sections. */ - -struct spu_elf_stack_info; - -struct _spu_elf_section_data -{ - struct bfd_elf_section_data elf; - - union { - /* Info kept for input sections. */ - struct { - /* Stack analysis info kept for this section. */ - struct spu_elf_stack_info *stack_info; - } i; - - /* Info kept for output sections. */ - struct { - /* Non-zero for overlay output sections. */ - unsigned int ovl_index; - unsigned int ovl_buf; - } o; - } u; -}; - -#define spu_elf_section_data(sec) \ - ((struct _spu_elf_section_data *) elf_section_data (sec)) - -enum _ovly_flavour -{ - ovly_normal, - ovly_soft_icache -}; - -struct _ovl_stream -{ - const void *start; - const void *end; -}; - -extern void spu_elf_setup (struct bfd_link_info *, struct spu_elf_params *); -extern void spu_elf_plugin (int); -extern bfd_boolean spu_elf_open_builtin_lib (bfd **, - const struct _ovl_stream *); -extern bfd_boolean spu_elf_create_sections (struct bfd_link_info *); -extern bfd_boolean spu_elf_size_sections (bfd *, struct bfd_link_info *); -extern int spu_elf_find_overlays (struct bfd_link_info *); -extern int spu_elf_size_stubs (struct bfd_link_info *); -extern void spu_elf_place_overlay_data (struct bfd_link_info *); -extern asection *spu_elf_check_vma (struct bfd_link_info *); diff --git a/sdcc/support/sdbinutils/bfd/elf32-tic6x.c b/sdcc/support/sdbinutils/bfd/elf32-tic6x.c deleted file mode 100644 index 758b6a810..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-tic6x.c +++ /dev/null @@ -1,4387 +0,0 @@ -/* 32-bit ELF support for TI C6X - Copyright (C) 2010-2018 Free Software Foundation, Inc. - Contributed by Joseph Myers - Bernd Schmidt - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include -#include "bfd.h" -#include "libbfd.h" -#include "libiberty.h" -#include "elf-bfd.h" -#include "elf/tic6x.h" -#include "elf32-tic6x.h" - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld-uClibc.so.0" - -/* DSBT binaries have a default 128K stack. */ -#define DEFAULT_STACK_SIZE 0x20000 - -/* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE 24 - -/* TI C6X ELF linker hash table. */ - -struct elf32_tic6x_link_hash_table -{ - struct elf_link_hash_table elf; - - /* C6X specific command line arguments. */ - struct elf32_tic6x_params params; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* The output BFD, for convenience. */ - bfd *obfd; - - /* The .dsbt section. */ - asection *dsbt; -}; - -/* Get the TI C6X ELF linker hash table from a link_info structure. */ - -#define elf32_tic6x_hash_table(p) \ - ((struct elf32_tic6x_link_hash_table *) ((p)->hash)) - -/* TI C6X ELF linker hash entry. */ - -struct elf32_tic6x_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; -}; - -typedef enum -{ - DELETE_EXIDX_ENTRY, - INSERT_EXIDX_CANTUNWIND_AT_END -} -tic6x_unwind_edit_type; - -/* A (sorted) list of edits to apply to an unwind table. */ -typedef struct tic6x_unwind_table_edit -{ - tic6x_unwind_edit_type type; - /* Note: we sometimes want to insert an unwind entry corresponding to a - section different from the one we're currently writing out, so record the - (text) section this edit relates to here. */ - asection *linked_section; - unsigned int index; - struct tic6x_unwind_table_edit *next; -} -tic6x_unwind_table_edit; - -typedef struct _tic6x_elf_section_data -{ - /* Information about mapping symbols. */ - struct bfd_elf_section_data elf; - /* Information about unwind tables. */ - union - { - /* Unwind info attached to a text section. */ - struct - { - asection *tic6x_exidx_sec; - } text; - - /* Unwind info attached to an .c6xabi.exidx section. */ - struct - { - tic6x_unwind_table_edit *unwind_edit_list; - tic6x_unwind_table_edit *unwind_edit_tail; - } exidx; - } u; -} -_tic6x_elf_section_data; - -#define elf32_tic6x_section_data(sec) \ - ((_tic6x_elf_section_data *) elf_section_data (sec)) - -struct elf32_tic6x_obj_tdata -{ - struct elf_obj_tdata root; - - /* Whether to use RELA relocations when generating relocations. - This is a per-object flag to allow the assembler to generate REL - relocations for use in linker testcases. */ - bfd_boolean use_rela_p; -}; - -#define elf32_tic6x_tdata(abfd) \ - ((struct elf32_tic6x_obj_tdata *) (abfd)->tdata.any) - -#define is_tic6x_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == TIC6X_ELF_DATA) - -/* C6X ELF uses two common sections. One is the usual one, and the - other is for small objects. All the small objects are kept - together, and then referenced via the gp pointer, which yields - faster assembler code. This is what we use for the small common - section. This approach is copied from ecoff.c. */ -static asection tic6x_elf_scom_section; -static asymbol tic6x_elf_scom_symbol; -static asymbol *tic6x_elf_scom_symbol_ptr; - -static reloc_howto_type elf32_tic6x_howto_table[] = -{ - HOWTO (R_C6000_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S21, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S21", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0fffff80, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S12, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S12", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0fff0000, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S10, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 13, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S10", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fe000, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S7, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S7", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007f0000, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_ABS_S16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS_S16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS_L16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS_L16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS_H16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS_H16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_U15_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_U15_B", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_U15_H, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_U15_H", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_U15_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_U15_W", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_S16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_S16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_L16_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_L16_B", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_L16_H, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_L16_H", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_L16_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_L16_W", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_H16_B, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_H16_B", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_H16_H, /* type */ - 17, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_H16_H", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_H16_W, /* type */ - 18, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_H16_W", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_GOT_U15_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_GOT_U15_W",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_GOT_L16_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_GOT_L16_W",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_GOT_H16_W, /* type */ - 18, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_GOT_H16_W",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_DSBT_INDEX, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_DSBT_INDEX", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_PREL31, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 31, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PREL31", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x7fffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_JUMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_EHTYPE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_EHTYPE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_H16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_H16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_L16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_L16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff80, /* dst_mask */ - TRUE), /* pcrel_offset */ - EMPTY_HOWTO (31), - EMPTY_HOWTO (32), - EMPTY_HOWTO (33), - EMPTY_HOWTO (34), - EMPTY_HOWTO (35), - EMPTY_HOWTO (36), - EMPTY_HOWTO (37), - EMPTY_HOWTO (38), - EMPTY_HOWTO (39), - EMPTY_HOWTO (40), - EMPTY_HOWTO (41), - EMPTY_HOWTO (42), - EMPTY_HOWTO (43), - EMPTY_HOWTO (44), - EMPTY_HOWTO (45), - EMPTY_HOWTO (46), - EMPTY_HOWTO (47), - EMPTY_HOWTO (48), - EMPTY_HOWTO (49), - EMPTY_HOWTO (50), - EMPTY_HOWTO (51), - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - EMPTY_HOWTO (60), - EMPTY_HOWTO (61), - EMPTY_HOWTO (62), - EMPTY_HOWTO (63), - EMPTY_HOWTO (64), - EMPTY_HOWTO (65), - EMPTY_HOWTO (66), - EMPTY_HOWTO (67), - EMPTY_HOWTO (68), - EMPTY_HOWTO (69), - EMPTY_HOWTO (70), - EMPTY_HOWTO (71), - EMPTY_HOWTO (72), - EMPTY_HOWTO (73), - EMPTY_HOWTO (74), - EMPTY_HOWTO (75), - EMPTY_HOWTO (76), - EMPTY_HOWTO (77), - EMPTY_HOWTO (78), - EMPTY_HOWTO (79), - EMPTY_HOWTO (80), - EMPTY_HOWTO (81), - EMPTY_HOWTO (82), - EMPTY_HOWTO (83), - EMPTY_HOWTO (84), - EMPTY_HOWTO (85), - EMPTY_HOWTO (86), - EMPTY_HOWTO (87), - EMPTY_HOWTO (88), - EMPTY_HOWTO (89), - EMPTY_HOWTO (90), - EMPTY_HOWTO (91), - EMPTY_HOWTO (92), - EMPTY_HOWTO (93), - EMPTY_HOWTO (94), - EMPTY_HOWTO (95), - EMPTY_HOWTO (96), - EMPTY_HOWTO (97), - EMPTY_HOWTO (98), - EMPTY_HOWTO (99), - EMPTY_HOWTO (100), - EMPTY_HOWTO (101), - EMPTY_HOWTO (102), - EMPTY_HOWTO (103), - EMPTY_HOWTO (104), - EMPTY_HOWTO (105), - EMPTY_HOWTO (106), - EMPTY_HOWTO (107), - EMPTY_HOWTO (108), - EMPTY_HOWTO (109), - EMPTY_HOWTO (110), - EMPTY_HOWTO (111), - EMPTY_HOWTO (112), - EMPTY_HOWTO (113), - EMPTY_HOWTO (114), - EMPTY_HOWTO (115), - EMPTY_HOWTO (116), - EMPTY_HOWTO (117), - EMPTY_HOWTO (118), - EMPTY_HOWTO (119), - EMPTY_HOWTO (120), - EMPTY_HOWTO (121), - EMPTY_HOWTO (122), - EMPTY_HOWTO (123), - EMPTY_HOWTO (124), - EMPTY_HOWTO (125), - EMPTY_HOWTO (126), - EMPTY_HOWTO (127), - EMPTY_HOWTO (128), - EMPTY_HOWTO (129), - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - EMPTY_HOWTO (133), - EMPTY_HOWTO (134), - EMPTY_HOWTO (135), - EMPTY_HOWTO (136), - EMPTY_HOWTO (137), - EMPTY_HOWTO (138), - EMPTY_HOWTO (139), - EMPTY_HOWTO (140), - EMPTY_HOWTO (141), - EMPTY_HOWTO (142), - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - EMPTY_HOWTO (145), - EMPTY_HOWTO (146), - EMPTY_HOWTO (147), - EMPTY_HOWTO (148), - EMPTY_HOWTO (149), - EMPTY_HOWTO (150), - EMPTY_HOWTO (151), - EMPTY_HOWTO (152), - EMPTY_HOWTO (153), - EMPTY_HOWTO (154), - EMPTY_HOWTO (155), - EMPTY_HOWTO (156), - EMPTY_HOWTO (157), - EMPTY_HOWTO (158), - EMPTY_HOWTO (159), - EMPTY_HOWTO (160), - EMPTY_HOWTO (161), - EMPTY_HOWTO (162), - EMPTY_HOWTO (163), - EMPTY_HOWTO (164), - EMPTY_HOWTO (165), - EMPTY_HOWTO (166), - EMPTY_HOWTO (167), - EMPTY_HOWTO (168), - EMPTY_HOWTO (169), - EMPTY_HOWTO (170), - EMPTY_HOWTO (171), - EMPTY_HOWTO (172), - EMPTY_HOWTO (173), - EMPTY_HOWTO (174), - EMPTY_HOWTO (175), - EMPTY_HOWTO (176), - EMPTY_HOWTO (177), - EMPTY_HOWTO (178), - EMPTY_HOWTO (179), - EMPTY_HOWTO (180), - EMPTY_HOWTO (181), - EMPTY_HOWTO (182), - EMPTY_HOWTO (183), - EMPTY_HOWTO (184), - EMPTY_HOWTO (185), - EMPTY_HOWTO (186), - EMPTY_HOWTO (187), - EMPTY_HOWTO (188), - EMPTY_HOWTO (189), - EMPTY_HOWTO (190), - EMPTY_HOWTO (191), - EMPTY_HOWTO (192), - EMPTY_HOWTO (193), - EMPTY_HOWTO (194), - EMPTY_HOWTO (195), - EMPTY_HOWTO (196), - EMPTY_HOWTO (197), - EMPTY_HOWTO (198), - EMPTY_HOWTO (199), - EMPTY_HOWTO (200), - EMPTY_HOWTO (201), - EMPTY_HOWTO (202), - EMPTY_HOWTO (203), - EMPTY_HOWTO (204), - EMPTY_HOWTO (205), - EMPTY_HOWTO (206), - EMPTY_HOWTO (207), - EMPTY_HOWTO (208), - EMPTY_HOWTO (209), - EMPTY_HOWTO (210), - EMPTY_HOWTO (211), - EMPTY_HOWTO (212), - EMPTY_HOWTO (213), - EMPTY_HOWTO (214), - EMPTY_HOWTO (215), - EMPTY_HOWTO (216), - EMPTY_HOWTO (217), - EMPTY_HOWTO (218), - EMPTY_HOWTO (219), - EMPTY_HOWTO (220), - EMPTY_HOWTO (221), - EMPTY_HOWTO (222), - EMPTY_HOWTO (223), - EMPTY_HOWTO (224), - EMPTY_HOWTO (225), - EMPTY_HOWTO (226), - EMPTY_HOWTO (227), - EMPTY_HOWTO (228), - EMPTY_HOWTO (229), - EMPTY_HOWTO (230), - EMPTY_HOWTO (231), - EMPTY_HOWTO (232), - EMPTY_HOWTO (233), - EMPTY_HOWTO (234), - EMPTY_HOWTO (235), - EMPTY_HOWTO (236), - EMPTY_HOWTO (237), - EMPTY_HOWTO (238), - EMPTY_HOWTO (239), - EMPTY_HOWTO (240), - EMPTY_HOWTO (241), - EMPTY_HOWTO (242), - EMPTY_HOWTO (243), - EMPTY_HOWTO (244), - EMPTY_HOWTO (245), - EMPTY_HOWTO (246), - EMPTY_HOWTO (247), - EMPTY_HOWTO (248), - EMPTY_HOWTO (249), - EMPTY_HOWTO (250), - EMPTY_HOWTO (251), - EMPTY_HOWTO (252), - HOWTO (R_C6000_ALIGN, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ALIGN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_FPHEAD, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_FPHEAD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_NOCMP, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_NOCMP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -static reloc_howto_type elf32_tic6x_howto_table_rel[] = -{ - HOWTO (R_C6000_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_NONE", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS8", /* name */ - TRUE, /* partial_inplace */ - 0x000000ff, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S21, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S21", /* name */ - TRUE, /* partial_inplace */ - 0x0fffff80, /* src_mask */ - 0x0fffff80, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S12, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - TRUE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S12", /* name */ - TRUE, /* partial_inplace */ - 0x0fff0000, /* src_mask */ - 0x0fff0000, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S10, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 13, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S10", /* name */ - TRUE, /* partial_inplace */ - 0x007fe000, /* src_mask */ - 0x007fe000, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_PCR_S7, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 16, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PCR_S7", /* name */ - TRUE, /* partial_inplace */ - 0x007f0000, /* src_mask */ - 0x007f0000, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_ABS_S16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS_S16", /* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_ABS_L16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ABS_L16", /* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (R_C6000_ABS_H16), - HOWTO (R_C6000_SBR_U15_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_U15_B", /* name */ - TRUE, /* partial_inplace */ - 0x007fff00, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_U15_H, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_U15_H", /* name */ - TRUE, /* partial_inplace */ - 0x007fff00, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_U15_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_U15_W", /* name */ - TRUE, /* partial_inplace */ - 0x007fff00, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_S16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_S16", /* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_L16_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_L16_B", /* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_L16_H, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_L16_H", /* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_L16_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_L16_W", /* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (R_C6000_SBR_H16_B), - EMPTY_HOWTO (R_C6000_SBR_H16_H), - EMPTY_HOWTO (R_C6000_SBR_H16_W), - HOWTO (R_C6000_SBR_GOT_U15_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_GOT_U15_W",/* name */ - TRUE, /* partial_inplace */ - 0x007fff00, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_SBR_GOT_L16_W, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 7, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_SBR_GOT_L16_W",/* name */ - TRUE, /* partial_inplace */ - 0x007fff80, /* src_mask */ - 0x007fff80, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (R_C6000_SBR_GOT_H16_W), - HOWTO (R_C6000_DSBT_INDEX, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 15, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_unsigned,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_DSBT_INDEX", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0x007fff00, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_PREL31, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 31, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_PREL31", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0x7fffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - HOWTO (R_C6000_COPY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_COPY", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_JUMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_EHTYPE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_EHTYPE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - EMPTY_HOWTO (R_C6000_PCR_H16), - EMPTY_HOWTO (R_C6000_PCR_L16), - EMPTY_HOWTO (31), - EMPTY_HOWTO (32), - EMPTY_HOWTO (33), - EMPTY_HOWTO (34), - EMPTY_HOWTO (35), - EMPTY_HOWTO (36), - EMPTY_HOWTO (37), - EMPTY_HOWTO (38), - EMPTY_HOWTO (39), - EMPTY_HOWTO (40), - EMPTY_HOWTO (41), - EMPTY_HOWTO (42), - EMPTY_HOWTO (43), - EMPTY_HOWTO (44), - EMPTY_HOWTO (45), - EMPTY_HOWTO (46), - EMPTY_HOWTO (47), - EMPTY_HOWTO (48), - EMPTY_HOWTO (49), - EMPTY_HOWTO (50), - EMPTY_HOWTO (51), - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - EMPTY_HOWTO (60), - EMPTY_HOWTO (61), - EMPTY_HOWTO (62), - EMPTY_HOWTO (63), - EMPTY_HOWTO (64), - EMPTY_HOWTO (65), - EMPTY_HOWTO (66), - EMPTY_HOWTO (67), - EMPTY_HOWTO (68), - EMPTY_HOWTO (69), - EMPTY_HOWTO (70), - EMPTY_HOWTO (71), - EMPTY_HOWTO (72), - EMPTY_HOWTO (73), - EMPTY_HOWTO (74), - EMPTY_HOWTO (75), - EMPTY_HOWTO (76), - EMPTY_HOWTO (77), - EMPTY_HOWTO (78), - EMPTY_HOWTO (79), - EMPTY_HOWTO (80), - EMPTY_HOWTO (81), - EMPTY_HOWTO (82), - EMPTY_HOWTO (83), - EMPTY_HOWTO (84), - EMPTY_HOWTO (85), - EMPTY_HOWTO (86), - EMPTY_HOWTO (87), - EMPTY_HOWTO (88), - EMPTY_HOWTO (89), - EMPTY_HOWTO (90), - EMPTY_HOWTO (91), - EMPTY_HOWTO (92), - EMPTY_HOWTO (93), - EMPTY_HOWTO (94), - EMPTY_HOWTO (95), - EMPTY_HOWTO (96), - EMPTY_HOWTO (97), - EMPTY_HOWTO (98), - EMPTY_HOWTO (99), - EMPTY_HOWTO (100), - EMPTY_HOWTO (101), - EMPTY_HOWTO (102), - EMPTY_HOWTO (103), - EMPTY_HOWTO (104), - EMPTY_HOWTO (105), - EMPTY_HOWTO (106), - EMPTY_HOWTO (107), - EMPTY_HOWTO (108), - EMPTY_HOWTO (109), - EMPTY_HOWTO (110), - EMPTY_HOWTO (111), - EMPTY_HOWTO (112), - EMPTY_HOWTO (113), - EMPTY_HOWTO (114), - EMPTY_HOWTO (115), - EMPTY_HOWTO (116), - EMPTY_HOWTO (117), - EMPTY_HOWTO (118), - EMPTY_HOWTO (119), - EMPTY_HOWTO (120), - EMPTY_HOWTO (121), - EMPTY_HOWTO (122), - EMPTY_HOWTO (123), - EMPTY_HOWTO (124), - EMPTY_HOWTO (125), - EMPTY_HOWTO (126), - EMPTY_HOWTO (127), - EMPTY_HOWTO (128), - EMPTY_HOWTO (129), - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - EMPTY_HOWTO (133), - EMPTY_HOWTO (134), - EMPTY_HOWTO (135), - EMPTY_HOWTO (136), - EMPTY_HOWTO (137), - EMPTY_HOWTO (138), - EMPTY_HOWTO (139), - EMPTY_HOWTO (140), - EMPTY_HOWTO (141), - EMPTY_HOWTO (142), - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - EMPTY_HOWTO (145), - EMPTY_HOWTO (146), - EMPTY_HOWTO (147), - EMPTY_HOWTO (148), - EMPTY_HOWTO (149), - EMPTY_HOWTO (150), - EMPTY_HOWTO (151), - EMPTY_HOWTO (152), - EMPTY_HOWTO (153), - EMPTY_HOWTO (154), - EMPTY_HOWTO (155), - EMPTY_HOWTO (156), - EMPTY_HOWTO (157), - EMPTY_HOWTO (158), - EMPTY_HOWTO (159), - EMPTY_HOWTO (160), - EMPTY_HOWTO (161), - EMPTY_HOWTO (162), - EMPTY_HOWTO (163), - EMPTY_HOWTO (164), - EMPTY_HOWTO (165), - EMPTY_HOWTO (166), - EMPTY_HOWTO (167), - EMPTY_HOWTO (168), - EMPTY_HOWTO (169), - EMPTY_HOWTO (170), - EMPTY_HOWTO (171), - EMPTY_HOWTO (172), - EMPTY_HOWTO (173), - EMPTY_HOWTO (174), - EMPTY_HOWTO (175), - EMPTY_HOWTO (176), - EMPTY_HOWTO (177), - EMPTY_HOWTO (178), - EMPTY_HOWTO (179), - EMPTY_HOWTO (180), - EMPTY_HOWTO (181), - EMPTY_HOWTO (182), - EMPTY_HOWTO (183), - EMPTY_HOWTO (184), - EMPTY_HOWTO (185), - EMPTY_HOWTO (186), - EMPTY_HOWTO (187), - EMPTY_HOWTO (188), - EMPTY_HOWTO (189), - EMPTY_HOWTO (190), - EMPTY_HOWTO (191), - EMPTY_HOWTO (192), - EMPTY_HOWTO (193), - EMPTY_HOWTO (194), - EMPTY_HOWTO (195), - EMPTY_HOWTO (196), - EMPTY_HOWTO (197), - EMPTY_HOWTO (198), - EMPTY_HOWTO (199), - EMPTY_HOWTO (200), - EMPTY_HOWTO (201), - EMPTY_HOWTO (202), - EMPTY_HOWTO (203), - EMPTY_HOWTO (204), - EMPTY_HOWTO (205), - EMPTY_HOWTO (206), - EMPTY_HOWTO (207), - EMPTY_HOWTO (208), - EMPTY_HOWTO (209), - EMPTY_HOWTO (210), - EMPTY_HOWTO (211), - EMPTY_HOWTO (212), - EMPTY_HOWTO (213), - EMPTY_HOWTO (214), - EMPTY_HOWTO (215), - EMPTY_HOWTO (216), - EMPTY_HOWTO (217), - EMPTY_HOWTO (218), - EMPTY_HOWTO (219), - EMPTY_HOWTO (220), - EMPTY_HOWTO (221), - EMPTY_HOWTO (222), - EMPTY_HOWTO (223), - EMPTY_HOWTO (224), - EMPTY_HOWTO (225), - EMPTY_HOWTO (226), - EMPTY_HOWTO (227), - EMPTY_HOWTO (228), - EMPTY_HOWTO (229), - EMPTY_HOWTO (230), - EMPTY_HOWTO (231), - EMPTY_HOWTO (232), - EMPTY_HOWTO (233), - EMPTY_HOWTO (234), - EMPTY_HOWTO (235), - EMPTY_HOWTO (236), - EMPTY_HOWTO (237), - EMPTY_HOWTO (238), - EMPTY_HOWTO (239), - EMPTY_HOWTO (240), - EMPTY_HOWTO (241), - EMPTY_HOWTO (242), - EMPTY_HOWTO (243), - EMPTY_HOWTO (244), - EMPTY_HOWTO (245), - EMPTY_HOWTO (246), - EMPTY_HOWTO (247), - EMPTY_HOWTO (248), - EMPTY_HOWTO (249), - EMPTY_HOWTO (250), - EMPTY_HOWTO (251), - EMPTY_HOWTO (252), - HOWTO (R_C6000_ALIGN, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_ALIGN", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_FPHEAD, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_FPHEAD", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_C6000_NOCMP, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_C6000_NOCMP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - -/* Map BFD relocations to ELF relocations. */ - -typedef struct -{ - bfd_reloc_code_real_type bfd_reloc_val; - enum elf_tic6x_reloc_type elf_reloc_val; -} tic6x_reloc_map; - -static const tic6x_reloc_map elf32_tic6x_reloc_map[] = - { - { BFD_RELOC_NONE, R_C6000_NONE }, - { BFD_RELOC_32, R_C6000_ABS32 }, - { BFD_RELOC_16, R_C6000_ABS16 }, - { BFD_RELOC_8, R_C6000_ABS8 }, - { BFD_RELOC_C6000_PCR_S21, R_C6000_PCR_S21 }, - { BFD_RELOC_C6000_PCR_S12, R_C6000_PCR_S12 }, - { BFD_RELOC_C6000_PCR_S10, R_C6000_PCR_S10 }, - { BFD_RELOC_C6000_PCR_S7, R_C6000_PCR_S7 }, - { BFD_RELOC_C6000_ABS_S16, R_C6000_ABS_S16 }, - { BFD_RELOC_C6000_ABS_L16, R_C6000_ABS_L16 }, - { BFD_RELOC_C6000_ABS_H16, R_C6000_ABS_H16 }, - { BFD_RELOC_C6000_SBR_U15_B, R_C6000_SBR_U15_B }, - { BFD_RELOC_C6000_SBR_U15_H, R_C6000_SBR_U15_H }, - { BFD_RELOC_C6000_SBR_U15_W, R_C6000_SBR_U15_W }, - { BFD_RELOC_C6000_SBR_S16, R_C6000_SBR_S16 }, - { BFD_RELOC_C6000_SBR_L16_B, R_C6000_SBR_L16_B }, - { BFD_RELOC_C6000_SBR_L16_H, R_C6000_SBR_L16_H }, - { BFD_RELOC_C6000_SBR_L16_W, R_C6000_SBR_L16_W }, - { BFD_RELOC_C6000_SBR_H16_B, R_C6000_SBR_H16_B }, - { BFD_RELOC_C6000_SBR_H16_H, R_C6000_SBR_H16_H }, - { BFD_RELOC_C6000_SBR_H16_W, R_C6000_SBR_H16_W }, - { BFD_RELOC_C6000_SBR_GOT_U15_W, R_C6000_SBR_GOT_U15_W }, - { BFD_RELOC_C6000_SBR_GOT_L16_W, R_C6000_SBR_GOT_L16_W }, - { BFD_RELOC_C6000_SBR_GOT_H16_W, R_C6000_SBR_GOT_H16_W }, - { BFD_RELOC_C6000_DSBT_INDEX, R_C6000_DSBT_INDEX }, - { BFD_RELOC_C6000_PREL31, R_C6000_PREL31 }, - { BFD_RELOC_C6000_COPY, R_C6000_COPY }, - { BFD_RELOC_C6000_JUMP_SLOT, R_C6000_JUMP_SLOT }, - { BFD_RELOC_C6000_EHTYPE, R_C6000_EHTYPE }, - { BFD_RELOC_C6000_PCR_H16, R_C6000_PCR_H16 }, - { BFD_RELOC_C6000_PCR_L16, R_C6000_PCR_L16 }, - { BFD_RELOC_C6000_ALIGN, R_C6000_ALIGN }, - { BFD_RELOC_C6000_FPHEAD, R_C6000_FPHEAD }, - { BFD_RELOC_C6000_NOCMP, R_C6000_NOCMP } - }; - -static reloc_howto_type * -elf32_tic6x_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_tic6x_reloc_map); i++) - if (elf32_tic6x_reloc_map[i].bfd_reloc_val == code) - { - enum elf_tic6x_reloc_type elf_reloc_val; - reloc_howto_type *howto; - - elf_reloc_val = elf32_tic6x_reloc_map[i].elf_reloc_val; - if (elf32_tic6x_tdata (abfd)->use_rela_p) - howto = &elf32_tic6x_howto_table[elf_reloc_val]; - else - howto = &elf32_tic6x_howto_table_rel[elf_reloc_val]; - - /* Some relocations are RELA-only; do not return them for - REL. */ - if (howto->name == NULL) - howto = NULL; - - return howto; - } - - return NULL; -} - -static reloc_howto_type * -elf32_tic6x_reloc_name_lookup (bfd *abfd, const char *r_name) -{ - if (elf32_tic6x_tdata (abfd)->use_rela_p) - { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_tic6x_howto_table); i++) - if (elf32_tic6x_howto_table[i].name != NULL - && strcasecmp (elf32_tic6x_howto_table[i].name, r_name) == 0) - return &elf32_tic6x_howto_table[i]; - } - else - { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_tic6x_howto_table_rel); i++) - if (elf32_tic6x_howto_table_rel[i].name != NULL - && strcasecmp (elf32_tic6x_howto_table_rel[i].name, r_name) == 0) - return &elf32_tic6x_howto_table_rel[i]; - } - - return NULL; -} - -static void -elf32_tic6x_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (elf_reloc->r_info); - if (r_type >= ARRAY_SIZE (elf32_tic6x_howto_table)) - bfd_reloc->howto = NULL; - else - bfd_reloc->howto = &elf32_tic6x_howto_table[r_type]; -} - -static void -elf32_tic6x_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (elf_reloc->r_info); - if (r_type >= ARRAY_SIZE (elf32_tic6x_howto_table_rel)) - bfd_reloc->howto = NULL; - else - bfd_reloc->howto = &elf32_tic6x_howto_table_rel[r_type]; -} - -void -elf32_tic6x_set_use_rela_p (bfd *abfd, bfd_boolean use_rela_p) -{ - elf32_tic6x_tdata (abfd)->use_rela_p = use_rela_p; -} - -/* Create an entry in a C6X ELF linker hash table. */ - -static struct bfd_hash_entry * -elf32_tic6x_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 elf32_tic6x_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 elf32_tic6x_link_hash_entry *eh; - - eh = (struct elf32_tic6x_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - } - - return entry; -} - -/* Create a C6X ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf32_tic6x_link_hash_table_create (bfd *abfd) -{ - struct elf32_tic6x_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf32_tic6x_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - elf32_tic6x_link_hash_newfunc, - sizeof (struct elf32_tic6x_link_hash_entry), - TIC6X_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->obfd = abfd; - ret->elf.is_relocatable_executable = 1; - - return &ret->elf.root; -} - -static bfd_boolean -elf32_tic6x_final_link (bfd *abfd, struct bfd_link_info *info) -{ - if (bfd_link_pic (info)) - { - obj_attribute *out_attr; - out_attr = elf_known_obj_attributes_proc (abfd); - if (out_attr[Tag_ABI_PIC].i == 0) - { - _bfd_error_handler (_("warning: generating a shared library " - "containing non-PIC code")); - } - if (out_attr[Tag_ABI_PID].i == 0) - { - _bfd_error_handler (_("warning: generating a shared library " - "containing non-PID code")); - } - } - /* Invoke the regular ELF backend linker to do all the work. */ - if (!bfd_elf_final_link (abfd, info)) - return FALSE; - - return TRUE; -} - -/* Called to pass PARAMS to the backend. We store them in the hash table - associated with INFO. */ - -void -elf32_tic6x_setup (struct bfd_link_info *info, - struct elf32_tic6x_params *params) -{ - struct elf32_tic6x_link_hash_table *htab = elf32_tic6x_hash_table (info); - htab->params = *params; -} - -/* Determine if we're dealing with a DSBT object. */ - -static bfd_boolean -elf32_tic6x_using_dsbt (bfd *abfd) -{ - return bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_PROC, - Tag_ABI_DSBT); -} - -/* Create .plt, .rela.plt, .got, .got.plt, .rela.got and .dsbt - sections in DYNOBJ, and set up shortcuts to them in our hash - table. */ - -static bfd_boolean -elf32_tic6x_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf32_tic6x_link_hash_table *htab; - flagword flags; - - htab = elf32_tic6x_hash_table (info); - if (htab == NULL) - return FALSE; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - /* Create .dsbt */ - flags = (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->dsbt = bfd_make_section_anyway_with_flags (dynobj, ".dsbt", - flags); - if (htab->dsbt == NULL - || ! bfd_set_section_alignment (dynobj, htab->dsbt, 2) - || ! bfd_set_section_alignment (dynobj, htab->elf.splt, 5)) - return FALSE; - - return TRUE; -} - -static bfd_boolean -elf32_tic6x_mkobject (bfd *abfd) -{ - bfd_boolean ret; - - ret = bfd_elf_allocate_object (abfd, sizeof (struct elf32_tic6x_obj_tdata), - TIC6X_ELF_DATA); - if (ret) - elf32_tic6x_set_use_rela_p (abfd, TRUE); - return ret; -} - -/* Install relocation RELA into section SRELA, incrementing its - reloc_count. */ - -static void -elf32_tic6x_install_rela (bfd *output_bfd, asection *srela, - Elf_Internal_Rela *rela) -{ - bfd_byte *loc; - bfd_vma off = srela->reloc_count++ * sizeof (Elf32_External_Rela); - loc = srela->contents + off; - BFD_ASSERT (off < srela->size); - bfd_elf32_swap_reloca_out (output_bfd, rela, loc); -} - -/* Create a dynamic reloc against the GOT at offset OFFSET. The contents - of the GOT at this offset have been initialized with the relocation. */ - -static void -elf32_tic6x_make_got_dynreloc (bfd *output_bfd, - struct elf32_tic6x_link_hash_table *htab, - asection *sym_sec, bfd_vma offset) -{ - asection *sgot = htab->elf.sgot; - Elf_Internal_Rela outrel; - int dynindx; - - outrel.r_offset = sgot->output_section->vma + sgot->output_offset + offset; - outrel.r_addend = bfd_get_32 (output_bfd, sgot->contents + offset); - if (sym_sec && sym_sec->output_section - && ! bfd_is_abs_section (sym_sec->output_section) - && ! bfd_is_und_section (sym_sec->output_section)) - { - dynindx = elf_section_data (sym_sec->output_section)->dynindx; - outrel.r_addend -= sym_sec->output_section->vma; - } - else - { - dynindx = 0; - } - outrel.r_info = ELF32_R_INFO (dynindx, R_C6000_ABS32); - elf32_tic6x_install_rela (output_bfd, htab->elf.srelgot, &outrel); -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf32_tic6x_finish_dynamic_symbol (bfd * output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym * sym) -{ - struct elf32_tic6x_link_hash_table *htab; - - htab = elf32_tic6x_hash_table (info); - - if (h->plt.offset != (bfd_vma) -1) - { - bfd_vma plt_index; - bfd_vma got_section_offset, got_dp_offset, rela_offset; - Elf_Internal_Rela rela; - bfd_byte *loc; - asection *plt, *gotplt, *relplt; - const struct elf_backend_data *bed; - - bed = get_elf_backend_data (output_bfd); - - BFD_ASSERT (htab->elf.splt != NULL); - plt = htab->elf.splt; - gotplt = htab->elf.sgotplt; - relplt = htab->elf.srelplt; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - - if ((h->dynindx == -1 - && !((h->forced_local || bfd_link_executable (info)) - && h->def_regular - && h->type == STT_GNU_IFUNC)) - || plt == NULL - || gotplt == NULL - || relplt == 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. - - 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. - - For static executables, we don't reserve anything. */ - - plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; - got_section_offset = plt_index + bed->got_header_size / 4; - got_dp_offset = got_section_offset + htab->params.dsbt_size; - rela_offset = plt_index * sizeof (Elf32_External_Rela); - - got_section_offset *= 4; - - /* Fill in the entry in the procedure linkage table. */ - - /* ldw .d2t2 *+B14($GOT(f)), b2 */ - bfd_put_32 (output_bfd, got_dp_offset << 8 | 0x0100006e, - plt->contents + h->plt.offset); - /* mvk .s2 low(rela_offset), b0 */ - bfd_put_32 (output_bfd, (rela_offset & 0xffff) << 7 | 0x0000002a, - plt->contents + h->plt.offset + 4); - /* mvkh .s2 high(rela_offset), b0 */ - bfd_put_32 (output_bfd, ((rela_offset >> 16) & 0xffff) << 7 | 0x0000006a, - plt->contents + h->plt.offset + 8); - /* nop 2 */ - bfd_put_32 (output_bfd, 0x00002000, - plt->contents + h->plt.offset + 12); - /* b .s2 b2 */ - bfd_put_32 (output_bfd, 0x00080362, - plt->contents + h->plt.offset + 16); - /* nop 5 */ - bfd_put_32 (output_bfd, 0x00008000, - plt->contents + h->plt.offset + 20); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (plt->output_section->vma + plt->output_offset), - gotplt->contents + got_section_offset); - - /* Fill in the entry in the .rel.plt section. */ - rela.r_offset = (gotplt->output_section->vma - + gotplt->output_offset - + got_section_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_C6000_JUMP_SLOT); - rela.r_addend = 0; - loc = relplt->contents + rela_offset; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. */ - sym->st_shndx = SHN_UNDEF; - sym->st_value = 0; - } - } - - if (h->got.offset != (bfd_vma) -1) - { - asection *sgot; - asection *srela; - - /* This symbol has an entry in the global offset table. - Set it up. */ - - sgot = htab->elf.sgot; - srela = htab->elf.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (SYMBOLIC_BIND (info, h) - || h->dynindx == -1 || h->forced_local) && h->def_regular) - { - asection *s = h->root.u.def.section; - elf32_tic6x_make_got_dynreloc (output_bfd, htab, s, - h->got.offset & ~(bfd_vma) 1); - } - else - { - Elf_Internal_Rela outrel; - bfd_put_32 (output_bfd, (bfd_vma) 0, - sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset & ~(bfd_vma) 1)); - outrel.r_info = ELF32_R_INFO (h->dynindx, R_C6000_ABS32); - outrel.r_addend = 0; - - elf32_tic6x_install_rela (output_bfd, srela, &outrel); - } - } - - if (h->needs_copy) - { - Elf_Internal_Rela rel; - asection *s; - - /* 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->elf.srelbss == NULL - || htab->elf.sreldynrelro == 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_C6000_COPY); - rel.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - - elf32_tic6x_install_rela (output_bfd, s, &rel); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Unwinding tables are not referenced directly. This pass marks them as - required if the corresponding code section is marked. */ - -static bfd_boolean -elf32_tic6x_gc_mark_extra_sections (struct bfd_link_info *info, - elf_gc_mark_hook_fn gc_mark_hook) -{ - bfd *sub; - Elf_Internal_Shdr **elf_shdrp; - bfd_boolean again; - - _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); - - /* Marking EH data may cause additional code sections to be marked, - requiring multiple passes. */ - again = TRUE; - while (again) - { - again = FALSE; - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - asection *o; - - if (! is_tic6x_elf (sub)) - continue; - - elf_shdrp = elf_elfsections (sub); - for (o = sub->sections; o != NULL; o = o->next) - { - Elf_Internal_Shdr *hdr; - - hdr = &elf_section_data (o)->this_hdr; - if (hdr->sh_type == SHT_C6000_UNWIND - && hdr->sh_link - && hdr->sh_link < elf_numsections (sub) - && !o->gc_mark - && elf_shdrp[hdr->sh_link]->bfd_section->gc_mark) - { - again = TRUE; - if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) - return FALSE; - } - } - } - } - - return TRUE; -} - -/* Return TRUE if this is an unwinding table index. */ - -static bfd_boolean -is_tic6x_elf_unwind_section_name (const char *name) -{ - return (CONST_STRNEQ (name, ELF_STRING_C6000_unwind) - || CONST_STRNEQ (name, ELF_STRING_C6000_unwind_once)); -} - - -/* Set the type and flags for an unwinding index table. We do this by - the section name, which is a hack, but ought to work. */ - -static bfd_boolean -elf32_tic6x_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, asection *sec) -{ - const char * name; - - name = bfd_get_section_name (abfd, sec); - - if (is_tic6x_elf_unwind_section_name (name)) - { - hdr->sh_type = SHT_C6000_UNWIND; - hdr->sh_flags |= SHF_LINK_ORDER; - } - - return TRUE; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - struct elf32_tic6x_link_hash_entry *eh - = (struct elf32_tic6x_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) - return p->sec; - } - return NULL; -} - -/* 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 -elf32_tic6x_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf32_tic6x_link_hash_table *htab; - bfd *dynobj; - asection *s, *srel; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic && h->ref_regular && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (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; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - h->non_got_ref = def->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 (bfd_link_pic (info)) - 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 = elf32_tic6x_hash_table (info); - if (htab == NULL) - return FALSE; - - /* 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_C6000_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_READONLY) != 0) - { - s = htab->elf.sdynrelro; - srel = htab->elf.sreldynrelro; - } - else - { - s = htab->elf.sdynbss; - srel = htab->elf.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -static bfd_boolean -elf32_tic6x_new_section_hook (bfd *abfd, asection *sec) -{ - bfd_boolean ret; - - /* Allocate target specific section data. */ - if (!sec->used_by_bfd) - { - _tic6x_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = (_tic6x_elf_section_data *) bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - ret = _bfd_elf_new_section_hook (abfd, sec); - sec->use_rela_p = elf32_tic6x_tdata (abfd)->use_rela_p; - - return ret; -} - -/* Return true if relocation REL against section SEC is a REL rather - than RELA relocation. RELOCS is the first relocation in the - section and ABFD is the bfd that contains SEC. */ - -static bfd_boolean -elf32_tic6x_rel_relocation_p (bfd *abfd, asection *sec, - const Elf_Internal_Rela *relocs, - const Elf_Internal_Rela *rel) -{ - Elf_Internal_Shdr *rel_hdr; - const struct elf_backend_data *bed; - - /* To determine which flavor of relocation this is, we depend on the - fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR. */ - rel_hdr = elf_section_data (sec)->rel.hdr; - if (rel_hdr == NULL) - return FALSE; - bed = get_elf_backend_data (abfd); - return ((size_t) (rel - relocs) - < NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel); -} - -/* We need dynamic symbols for every section, since segments can - relocate independently. */ -static bfd_boolean -elf32_tic6x_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - 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: - return FALSE; - - /* There shouldn't be section relative relocations - against any other section. */ - default: - return TRUE; - } -} - -static bfd_boolean -elf32_tic6x_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 elf32_tic6x_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - bfd_boolean ok = TRUE; - - htab = elf32_tic6x_hash_table (info); - symtab_hdr = & elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel ++) - { - int r_type; - unsigned long r_symndx; - arelent bfd_reloc; - reloc_howto_type *howto; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma off, off2, relocation; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - struct bfd_link_hash_entry *sbh; - bfd_boolean is_rel; - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - is_rel = elf32_tic6x_rel_relocation_p (input_bfd, input_section, - relocs, rel); - - if (is_rel) - elf32_tic6x_info_to_howto_rel (input_bfd, &bfd_reloc, rel); - else - elf32_tic6x_info_to_howto (input_bfd, &bfd_reloc, rel); - howto = bfd_reloc.howto; - if (howto == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - 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, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - if (is_rel - && sym != NULL - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - rel->r_addend = 0; - relocation = sec->output_offset + sym->st_value; - r = _bfd_relocate_contents (howto, input_bfd, relocation, - contents + rel->r_offset); - goto done_reloc; - } - continue; - } - - switch (r_type) - { - case R_C6000_NONE: - case R_C6000_ALIGN: - case R_C6000_FPHEAD: - case R_C6000_NOCMP: - /* No action needed. */ - continue; - - case R_C6000_PCR_S21: - /* A branch to an undefined weak symbol is turned into a - "b .s2 B3" instruction if the existing insn is of the - form "b .s2 symbol". */ - if (h ? h->root.type == bfd_link_hash_undefweak - && (htab->elf.splt == NULL || h->plt.offset == (bfd_vma) -1) - : r_symndx != STN_UNDEF && bfd_is_und_section (sec)) - { - unsigned long oldval; - oldval = bfd_get_32 (input_bfd, contents + rel->r_offset); - - if ((oldval & 0x7e) == 0x12) - { - oldval &= 0xF0000001; - bfd_put_32 (input_bfd, oldval | 0x000c0362, - contents + rel->r_offset); - r = bfd_reloc_ok; - goto done_reloc; - } - } - /* Fall through. */ - - case R_C6000_PCR_S12: - case R_C6000_PCR_S10: - case R_C6000_PCR_S7: - if (h != NULL - && h->plt.offset != (bfd_vma) -1 - && htab->elf.splt != NULL) - { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); - } - - /* Generic PC-relative handling produces a value relative to - the exact location of the relocation. Adjust it to be - relative to the start of the fetch packet instead. */ - relocation += (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset) & 0x1f; - unresolved_reloc = FALSE; - break; - - case R_C6000_PCR_H16: - case R_C6000_PCR_L16: - off = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - /* These must be calculated as R = S - FP(FP(PC) - A). - PC, here, is the value we just computed in OFF. RELOCATION - has the address of S + A. */ - relocation -= rel->r_addend; - off2 = ((off & ~(bfd_vma)0x1f) - rel->r_addend) & (bfd_vma)~0x1f; - off2 = relocation - off2; - relocation = off + off2; - break; - - case R_C6000_DSBT_INDEX: - relocation = elf32_tic6x_hash_table (info)->params.dsbt_index; - if (!bfd_link_pic (info) || relocation != 0) - break; - - /* fall through */ - case R_C6000_ABS32: - case R_C6000_ABS16: - case R_C6000_ABS8: - case R_C6000_ABS_S16: - case R_C6000_ABS_L16: - case R_C6000_ABS_H16: - /* When generating a shared object or relocatable executable, these - relocations are copied into the output file to be resolved at - run time. */ - if ((bfd_link_pic (info) || elf32_tic6x_using_dsbt (output_bfd)) - && (input_section->flags & SEC_ALLOC) - && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - { - Elf_Internal_Rela outrel; - bfd_boolean skip, relocate; - asection *sreloc; - - unresolved_reloc = FALSE; - - sreloc = elf_section_data (input_section)->sreloc; - BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL); - - skip = FALSE; - relocate = FALSE; - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if (h != NULL - && h->dynindx != -1 - && (!bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !h->def_regular)) - { - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - long indx; - - outrel.r_addend = relocation + rel->r_addend; - - if (bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - outrel.r_addend -= osec->vma; - BFD_ASSERT (indx != 0); - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - } - - elf32_tic6x_install_rela (output_bfd, sreloc, &outrel); - - /* 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; - } - - /* Generic logic OK. */ - break; - - case R_C6000_SBR_U15_B: - case R_C6000_SBR_U15_H: - case R_C6000_SBR_U15_W: - case R_C6000_SBR_S16: - case R_C6000_SBR_L16_B: - case R_C6000_SBR_L16_H: - case R_C6000_SBR_L16_W: - case R_C6000_SBR_H16_B: - case R_C6000_SBR_H16_H: - case R_C6000_SBR_H16_W: - sbh = bfd_link_hash_lookup (info->hash, "__c6xabi_DSBT_BASE", - FALSE, FALSE, TRUE); - if (sbh != NULL - && (sbh->type == bfd_link_hash_defined - || sbh->type == bfd_link_hash_defweak)) - { - if (h ? (h->root.type == bfd_link_hash_undefweak - && (htab->elf.splt == NULL - || h->plt.offset == (bfd_vma) -1)) - : r_symndx != STN_UNDEF && bfd_is_und_section (sec)) - relocation = 0; - else - relocation -= (sbh->u.def.value - + sbh->u.def.section->output_section->vma - + sbh->u.def.section->output_offset); - } - else - { - _bfd_error_handler (_("%B: SB-relative relocation but " - "__c6xabi_DSBT_BASE not defined"), - input_bfd); - ok = FALSE; - continue; - } - break; - - case R_C6000_SBR_GOT_U15_W: - case R_C6000_SBR_GOT_L16_W: - case R_C6000_SBR_GOT_H16_W: - case R_C6000_EHTYPE: - /* Relocation is to the entry for this symbol in the global - offset table. */ - if (htab->elf.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, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && 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->elf.sgot->contents + off); - h->got.offset |= 1; - - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && !(ELF_ST_VISIBILITY (h->other) - && h->root.type == bfd_link_hash_undefweak)) - elf32_tic6x_make_got_dynreloc (output_bfd, htab, sec, - off); - } - } - 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->elf.sgot->contents + off); - - if (bfd_link_pic (info) || elf32_tic6x_using_dsbt (output_bfd)) - elf32_tic6x_make_got_dynreloc (output_bfd, htab, sec, off); - - local_got_offsets[r_symndx] |= 1; - } - } - - if (off >= (bfd_vma) -2) - abort (); - - if (htab->dsbt) - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - htab->dsbt->output_section->vma - - htab->dsbt->output_offset); - else - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - htab->elf.sgotplt->output_section->vma - - htab->elf.sgotplt->output_offset); - - if (rel->r_addend != 0) - { - /* We can't do anything for a relocation which is against - a symbol *plus offset*. GOT holds relocations for - symbols. Make this an error; the compiler isn't - allowed to pass us these kinds of things. */ - if (h == NULL) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with non-zero addend %Ld" - " against local symbol"), - input_bfd, - input_section, - elf32_tic6x_howto_table[r_type].name, - rel->r_addend); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B, section %A: relocation %s with non-zero addend %Ld" - " against symbol `%s'"), - input_bfd, - input_section, - elf32_tic6x_howto_table[r_type].name, - rel->r_addend, - h->root.root.string[0] != '\0' ? h->root.root.string - : _("[whose name is lost]")); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - break; - - case R_C6000_PREL31: - if (h != NULL - && h->plt.offset != (bfd_vma) -1 - && htab->elf.splt != NULL) - { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); - } - break; - - case R_C6000_COPY: - /* Invalid in relocatable object. */ - default: - /* Unknown relocation. */ - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - input_bfd, r_type); - ok = FALSE; - continue; - } - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - done_reloc: - if (r == bfd_reloc_ok - && howto->complain_on_overflow == complain_overflow_bitfield) - { - /* Generic overflow handling accepts cases the ABI says - should be rejected for R_C6000_ABS16 and - R_C6000_ABS8. */ - bfd_vma value = (relocation + rel->r_addend) & 0xffffffff; - bfd_vma sbit = 1 << (howto->bitsize - 1); - bfd_vma sbits = (-(bfd_vma) sbit) & 0xffffffff; - bfd_vma value_sbits = value & sbits; - - if (value_sbits != 0 - && value_sbits != sbit - && value_sbits != sbits) - r = bfd_reloc_overflow; - } - - if (r != bfd_reloc_ok) - { - const char *name; - const char *error_message; - - 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); - } - - switch (r) - { - case bfd_reloc_overflow: - /* If the overflowing reloc was to an undefined symbol, - we have already printed one error message and there - is no point complaining again. */ - if (!h || h->root.type != bfd_link_hash_undefined) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) (info, name, input_bfd, - input_section, - rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - error_message = _("out of range"); - goto common_error; - - case bfd_reloc_notsupported: - error_message = _("unsupported relocation"); - goto common_error; - - case bfd_reloc_dangerous: - error_message = _("dangerous relocation"); - goto common_error; - - default: - error_message = _("unknown error"); - /* Fall through. */ - - common_error: - BFD_ASSERT (error_message != NULL); - (*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, rel->r_offset); - break; - } - } - } - - return ok; -} - - -/* 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 -elf32_tic6x_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - struct elf32_tic6x_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 (bfd_link_relocatable (info)) - return TRUE; - - htab = elf32_tic6x_hash_table (info); - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - - /* Create dynamic sections for relocatable executables so that we can - copy relocations. */ - if ((bfd_link_pic (info) || elf32_tic6x_using_dsbt (abfd)) - && ! htab->elf.dynamic_sections_created) - { - if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) - return FALSE; - } - - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned int r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *isym; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), - abfd, r_symndx); - return FALSE; - } - - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - h = NULL; - } - else - { - isym = NULL; - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (r_type) - { - case R_C6000_PCR_S21: - case R_C6000_PREL31: - /* 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_C6000_SBR_GOT_U15_W: - case R_C6000_SBR_GOT_L16_W: - case R_C6000_SBR_GOT_H16_W: - case R_C6000_EHTYPE: - /* This symbol requires a global offset table entry. */ - if (h != NULL) - { - h->got.refcount += 1; - } - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= (sizeof (bfd_signed_vma) - + 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; - } - local_got_refcounts[r_symndx] += 1; - } - - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } - break; - - case R_C6000_DSBT_INDEX: - /* We'd like to check for nonzero dsbt_index here, but it's - set up only after check_relocs is called. Instead, we - store the number of R_C6000_DSBT_INDEX relocs in the - pc_count field, and potentially discard the extra space - in elf32_tic6x_allocate_dynrelocs. */ - if (!bfd_link_pic (info)) - break; - - /* fall through */ - case R_C6000_ABS32: - case R_C6000_ABS16: - case R_C6000_ABS8: - case R_C6000_ABS_S16: - case R_C6000_ABS_L16: - case R_C6000_ABS_H16: - /* 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 ((bfd_link_pic (info) || elf32_tic6x_using_dsbt (abfd)) - && (sec->flags & SEC_ALLOC) != 0) - { - struct elf_dyn_relocs *p; - struct elf_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) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, /*rela? */ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - { - head = &((struct elf32_tic6x_link_hash_entry *) h)->dyn_relocs; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - void **vpp; - asection *s; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_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_C6000_DSBT_INDEX) - p->pc_count += 1; - } - break; - - case R_C6000_SBR_U15_B: - case R_C6000_SBR_U15_H: - case R_C6000_SBR_U15_W: - case R_C6000_SBR_S16: - case R_C6000_SBR_L16_B: - case R_C6000_SBR_L16_H: - case R_C6000_SBR_L16_W: - case R_C6000_SBR_H16_B: - case R_C6000_SBR_H16_H: - case R_C6000_SBR_H16_W: - if (h != NULL && bfd_link_executable (info)) - { - /* For B14-relative addresses, we might need a copy - reloc. */ - h->non_got_ref = 1; - } - break; - - default: - break; - } - } - - return TRUE; -} - -static bfd_boolean -elf32_tic6x_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - switch (sym->st_shndx) - { - case SHN_TIC6X_SCOMMON: - *secp = bfd_make_section_old_way (abfd, ".scommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - (void) bfd_set_section_alignment (abfd, *secp, bfd_log2 (sym->st_value)); - break; - } - - return TRUE; -} - -static void -elf32_tic6x_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym) -{ - elf_symbol_type *elfsym; - - elfsym = (elf_symbol_type *) asym; - switch (elfsym->internal_elf_sym.st_shndx) - { - case SHN_TIC6X_SCOMMON: - if (tic6x_elf_scom_section.name == NULL) - { - /* Initialize the small common section. */ - tic6x_elf_scom_section.name = ".scommon"; - tic6x_elf_scom_section.flags = SEC_IS_COMMON; - tic6x_elf_scom_section.output_section = &tic6x_elf_scom_section; - tic6x_elf_scom_section.symbol = &tic6x_elf_scom_symbol; - tic6x_elf_scom_section.symbol_ptr_ptr = &tic6x_elf_scom_symbol_ptr; - tic6x_elf_scom_symbol.name = ".scommon"; - tic6x_elf_scom_symbol.flags = BSF_SECTION_SYM; - tic6x_elf_scom_symbol.section = &tic6x_elf_scom_section; - tic6x_elf_scom_symbol_ptr = &tic6x_elf_scom_symbol; - } - asym->section = &tic6x_elf_scom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - } -} - -static int -elf32_tic6x_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - /* If we see a common symbol, which implies a relocatable link, then - if a symbol was small common in an input file, mark it as small - common in the output file. */ - if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0) - sym->st_shndx = SHN_TIC6X_SCOMMON; - - return 1; -} - -static bfd_boolean -elf32_tic6x_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) - { - *retval = SHN_TIC6X_SCOMMON; - return TRUE; - } - - return FALSE; -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -elf32_tic6x_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct elf32_tic6x_link_hash_table *htab; - struct elf32_tic6x_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - eh = (struct elf32_tic6x_link_hash_entry *) h; - info = (struct bfd_link_info *) inf; - htab = elf32_tic6x_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 (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - asection *s = htab->elf.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 (! bfd_link_pic (info) && !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->elf.sgotplt->size += 4; - /* We also need to make an entry in the .rel.plt section. */ - htab->elf.srelplt->size += sizeof (Elf32_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - if (h->got.refcount > 0) - { - asection *s; - - /* 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->elf.sgot; - h->got.offset = s->size; - s->size += 4; - - if (!(ELF_ST_VISIBILITY (h->other) - && h->root.type == bfd_link_hash_undefweak)) - htab->elf.srelgot->size += sizeof (Elf32_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* Discard relocs on undefined weak syms with non-default - visibility. */ - if (bfd_link_pic (info) || elf32_tic6x_using_dsbt (htab->obfd)) - { - /* We use the pc_count field to hold the number of - R_C6000_DSBT_INDEX relocs. */ - if (htab->params.dsbt_index != 0) - { - struct elf_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; - } - } - - 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; - } - } - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc; - - sreloc = elf_section_data (p->sec)->sreloc; - - BFD_ASSERT (sreloc != NULL); - sreloc->size += p->count * sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf32_tic6x_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - struct elf32_tic6x_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = elf32_tic6x_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 (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (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; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = ((struct elf_dyn_relocs *) - elf_section_data (s)->local_dynrel); - p != NULL; - p = p->next) - { - if (!bfd_is_abs_section (p->sec) - && bfd_is_abs_section (p->sec->output_section)) - { - /* Input section has been discarded, either because - it is a copy of a linkonce section or due to - linker script /DISCARD/, so we'll be discarding - the relocs too. */ - } - else if (p->count != 0) - { - srel = elf_section_data (p->sec)->sreloc; - srel->size += p->count * sizeof (Elf32_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - s = htab->elf.sgot; - srel = htab->elf.srelgot; - for (; local_got < end_local_got; ++local_got) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += 4; - - if (bfd_link_pic (info) || elf32_tic6x_using_dsbt (output_bfd)) - { - srel->size += sizeof (Elf32_External_Rela); - } - } - else - *local_got = (bfd_vma) -1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, elf32_tic6x_allocate_dynrelocs, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - bfd_boolean strip_section = TRUE; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->dsbt) - s->size = 4 * htab->params.dsbt_size; - else if (s == htab->elf.splt - || s == htab->elf.sgot - || s == htab->elf.sgotplt - || s == htab->elf.sdynbss - || s == htab->elf.sdynrelro) - { - /* 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; - - /* Round up the size of the PLT section to a multiple of 32. */ - if (s == htab->elf.splt && s->size > 0) - s->size = (s->size + 31) & ~(bfd_vma)31; - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 - && s != htab->elf.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - else - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is mostly to handle .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_C6000_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 elf32_tic6x_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (!add_dynamic_entry (DT_C6000_DSBT_BASE, 0) - || !add_dynamic_entry (DT_C6000_DSBT_SIZE, htab->params.dsbt_size) - || !add_dynamic_entry (DT_C6000_DSBT_INDEX, - htab->params.dsbt_index)) - return FALSE; - - if (htab->elf.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - - /* If any dynamic relocs apply to a read-only section, - then we need a DT_TEXTREL entry. */ - if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* This function is called after all the input files have been read, - and the input sections have been assigned to output sections. */ - -static bfd_boolean -elf32_tic6x_always_size_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - if (elf32_tic6x_using_dsbt (output_bfd) && !bfd_link_relocatable (info) - && !bfd_elf_stack_segment_size (output_bfd, info, - "__stacksize", DEFAULT_STACK_SIZE)) - return FALSE; - - return TRUE; -} - -static bfd_boolean -elf32_tic6x_finish_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf32_tic6x_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - - htab = elf32_tic6x_hash_table (info); - dynobj = htab->elf.dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf32_External_Dyn * dyncon; - Elf32_External_Dyn * dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_C6000_DSBT_BASE: - s = htab->dsbt; - dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset); - break; - - case DT_PLTGOT: - s = htab->elf.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_JMPREL: - s = htab->elf.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - s = htab->elf.srelplt; - dyn.d_un.d_val = s->size; - break; - } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - /* Fill in the first entry in the procedure linkage table. */ - if (htab->elf.splt && htab->elf.splt->size > 0) - { - bfd_vma got_offs = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - - htab->dsbt->output_section->vma - - htab->dsbt->output_offset) / 4; - - /* ldw .D2T2 *+b14[$GOT(0)],b2 */ - bfd_put_32 (output_bfd, got_offs << 8 | 0x0100006e, - htab->elf.splt->contents); - /* ldw .D2T2 *+b14[$GOT(4)],b1 */ - bfd_put_32 (output_bfd, (got_offs + 1) << 8 | 0x0080006e, - htab->elf.splt->contents + 4); - /* nop 3 */ - bfd_put_32 (output_bfd, 0x00004000, - htab->elf.splt->contents + 8); - /* b .s2 b2 */ - bfd_put_32 (output_bfd, 0x00080362, - htab->elf.splt->contents + 12); - /* nop 5 */ - bfd_put_32 (output_bfd, 0x00008000, - htab->elf.splt->contents + 16); - - elf_section_data (htab->elf.splt->output_section) - ->this_hdr.sh_entsize = PLT_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 -elf32_tic6x_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + (i + 1) * PLT_ENTRY_SIZE; -} - -static int -elf32_tic6x_obj_attrs_arg_type (int tag) -{ - if (tag == Tag_ABI_compatibility) - return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL; - else if (tag & 1) - return ATTR_TYPE_FLAG_STR_VAL; - else - return ATTR_TYPE_FLAG_INT_VAL; -} - -static int -elf32_tic6x_obj_attrs_order (int num) -{ - if (num == LEAST_KNOWN_OBJ_ATTRIBUTE) - return Tag_ABI_conformance; - if ((num - 1) < Tag_ABI_conformance) - return num - 1; - return num; -} - -static bfd_boolean -elf32_tic6x_obj_attrs_handle_unknown (bfd *abfd, int tag) -{ - if ((tag & 127) < 64) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: error: unknown mandatory EABI object attribute %d"), - abfd, tag); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: unknown EABI object attribute %d"), - abfd, tag); - return TRUE; - } -} - -/* Merge the Tag_ISA attribute values ARCH1 and ARCH2 - and return the merged value. At present, all merges succeed, so no - return value for errors is defined. */ - -int -elf32_tic6x_merge_arch_attributes (int arch1, int arch2) -{ - int min_arch, max_arch; - - min_arch = (arch1 < arch2 ? arch1 : arch2); - max_arch = (arch1 > arch2 ? arch1 : arch2); - - /* In most cases, the numerically greatest value is the correct - merged value, but merging C64 and C67 results in C674X. */ - if ((min_arch == C6XABI_Tag_ISA_C67X - || min_arch == C6XABI_Tag_ISA_C67XP) - && (max_arch == C6XABI_Tag_ISA_C64X - || max_arch == C6XABI_Tag_ISA_C64XP)) - return C6XABI_Tag_ISA_C674X; - - return max_arch; -} - -/* Convert a Tag_ABI_array_object_alignment or - Tag_ABI_array_object_align_expected tag value TAG to a - corresponding alignment value; return the alignment, or -1 for an - unknown tag value. */ - -static int -elf32_tic6x_tag_to_array_alignment (int tag) -{ - switch (tag) - { - case 0: - return 8; - - case 1: - return 4; - - case 2: - return 16; - - default: - return -1; - } -} - -/* Convert a Tag_ABI_array_object_alignment or - Tag_ABI_array_object_align_expected alignment ALIGN to a - corresponding tag value; return the tag value. */ - -static int -elf32_tic6x_array_alignment_to_tag (int align) -{ - switch (align) - { - case 8: - return 0; - - case 4: - return 1; - - case 16: - return 2; - - default: - abort (); - } -} - -/* Merge attributes from IBFD and OBFD, returning TRUE if the merge - succeeded, FALSE otherwise. */ - -static bfd_boolean -elf32_tic6x_merge_attributes (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - bfd_boolean result = TRUE; - obj_attribute *in_attr; - obj_attribute *out_attr; - int i; - int array_align_in, array_align_out, array_expect_in, array_expect_out; - - if (!elf_known_obj_attributes_proc (obfd)[0].i) - { - /* This is the first object. Copy the attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - out_attr = elf_known_obj_attributes_proc (obfd); - - /* Use the Tag_null value to indicate the attributes have been - initialized. */ - out_attr[0].i = 1; - - return TRUE; - } - - in_attr = elf_known_obj_attributes_proc (ibfd); - out_attr = elf_known_obj_attributes_proc (obfd); - - /* No specification yet for handling of unknown attributes, so just - ignore them and handle known ones. */ - - if (out_attr[Tag_ABI_stack_align_preserved].i - < in_attr[Tag_ABI_stack_align_needed].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B requires more stack alignment than %B preserves"), - ibfd, obfd); - result = FALSE; - } - if (in_attr[Tag_ABI_stack_align_preserved].i - < out_attr[Tag_ABI_stack_align_needed].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B requires more stack alignment than %B preserves"), - obfd, ibfd); - result = FALSE; - } - - array_align_in = elf32_tic6x_tag_to_array_alignment - (in_attr[Tag_ABI_array_object_alignment].i); - if (array_align_in == -1) - { - _bfd_error_handler - (_("error: unknown Tag_ABI_array_object_alignment value in %B"), - ibfd); - result = FALSE; - } - array_align_out = elf32_tic6x_tag_to_array_alignment - (out_attr[Tag_ABI_array_object_alignment].i); - if (array_align_out == -1) - { - _bfd_error_handler - (_("error: unknown Tag_ABI_array_object_alignment value in %B"), - obfd); - result = FALSE; - } - array_expect_in = elf32_tic6x_tag_to_array_alignment - (in_attr[Tag_ABI_array_object_align_expected].i); - if (array_expect_in == -1) - { - _bfd_error_handler - (_("error: unknown Tag_ABI_array_object_align_expected value in %B"), - ibfd); - result = FALSE; - } - array_expect_out = elf32_tic6x_tag_to_array_alignment - (out_attr[Tag_ABI_array_object_align_expected].i); - if (array_expect_out == -1) - { - _bfd_error_handler - (_("error: unknown Tag_ABI_array_object_align_expected value in %B"), - obfd); - result = FALSE; - } - - if (array_align_out < array_expect_in) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B requires more array alignment than %B preserves"), - ibfd, obfd); - result = FALSE; - } - if (array_align_in < array_expect_out) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B requires more array alignment than %B preserves"), - obfd, ibfd); - result = FALSE; - } - - for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) - { - switch (i) - { - case Tag_ISA: - out_attr[i].i = elf32_tic6x_merge_arch_attributes (in_attr[i].i, - out_attr[i].i); - break; - - case Tag_ABI_wchar_t: - if (out_attr[i].i == 0) - out_attr[i].i = in_attr[i].i; - if (out_attr[i].i != 0 - && in_attr[i].i != 0 - && out_attr[i].i != in_attr[i].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("warning: %B and %B differ in wchar_t size"), obfd, ibfd); - } - break; - - case Tag_ABI_stack_align_needed: - if (out_attr[i].i < in_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_ABI_stack_align_preserved: - if (out_attr[i].i > in_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_ABI_DSBT: - if (out_attr[i].i != in_attr[i].i) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("warning: %B and %B differ in whether code is " - "compiled for DSBT"), - obfd, ibfd); - } - break; - - case Tag_ABI_PIC: - case Tag_ABI_PID: - if (out_attr[i].i > in_attr[i].i) - out_attr[i].i = in_attr[i].i; - break; - - case Tag_ABI_array_object_alignment: - if (array_align_out != -1 - && array_align_in != -1 - && array_align_out > array_align_in) - out_attr[i].i - = elf32_tic6x_array_alignment_to_tag (array_align_in); - break; - - case Tag_ABI_array_object_align_expected: - if (array_expect_out != -1 - && array_expect_in != -1 - && array_expect_out < array_expect_in) - out_attr[i].i - = elf32_tic6x_array_alignment_to_tag (array_expect_in); - break; - - case Tag_ABI_conformance: - /* Merging for this attribute is not specified. As on ARM, - treat a missing attribute as no claim to conform and only - merge identical values. */ - if (out_attr[i].s == NULL - || in_attr[i].s == NULL - || strcmp (out_attr[i].s, - in_attr[i].s) != 0) - out_attr[i].s = NULL; - break; - - case Tag_ABI_compatibility: - /* Merged in _bfd_elf_merge_object_attributes. */ - break; - - default: - result - = result && _bfd_elf_merge_unknown_attribute_low (ibfd, obfd, i); - break; - } - - if (in_attr[i].type && !out_attr[i].type) - out_attr[i].type = in_attr[i].type; - } - - /* Merge Tag_ABI_compatibility attributes and any common GNU ones. */ - if (!_bfd_elf_merge_object_attributes (ibfd, info)) - return FALSE; - - result &= _bfd_elf_merge_unknown_attribute_list (ibfd, obfd); - - return result; -} - -static bfd_boolean -elf32_tic6x_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if (! is_tic6x_elf (ibfd) || ! is_tic6x_elf (info->output_bfd)) - return TRUE; - - if (!elf32_tic6x_merge_attributes (ibfd, info)) - return FALSE; - - return TRUE; -} - -/* Add a new unwind edit to the list described by HEAD, TAIL. If TINDEX is zero, - adds the edit to the start of the list. (The list must be built in order of - ascending TINDEX: the function's callers are primarily responsible for - maintaining that condition). */ - -static void -elf32_tic6x_add_unwind_table_edit (tic6x_unwind_table_edit **head, - tic6x_unwind_table_edit **tail, - tic6x_unwind_edit_type type, - asection *linked_section, - unsigned int tindex) -{ - tic6x_unwind_table_edit *new_edit = (tic6x_unwind_table_edit *) - xmalloc (sizeof (tic6x_unwind_table_edit)); - - new_edit->type = type; - new_edit->linked_section = linked_section; - new_edit->index = tindex; - - if (tindex > 0) - { - new_edit->next = NULL; - - if (*tail) - (*tail)->next = new_edit; - - (*tail) = new_edit; - - if (!*head) - (*head) = new_edit; - } - else - { - new_edit->next = *head; - - if (!*tail) - *tail = new_edit; - - *head = new_edit; - } -} - -static _tic6x_elf_section_data * -get_tic6x_elf_section_data (asection * sec) -{ - if (sec && sec->owner && is_tic6x_elf (sec->owner)) - return elf32_tic6x_section_data (sec); - else - return NULL; -} - - -/* Increase the size of EXIDX_SEC by ADJUST bytes. ADJUST must be negative. */ -static void -elf32_tic6x_adjust_exidx_size (asection *exidx_sec, int adjust) -{ - asection *out_sec; - - if (!exidx_sec->rawsize) - exidx_sec->rawsize = exidx_sec->size; - - bfd_set_section_size (exidx_sec->owner, exidx_sec, exidx_sec->size + adjust); - out_sec = exidx_sec->output_section; - /* Adjust size of output section. */ - bfd_set_section_size (out_sec->owner, out_sec, out_sec->size +adjust); -} - -/* Insert an EXIDX_CANTUNWIND marker at the end of a section. */ -static void -elf32_tic6x_insert_cantunwind_after (asection *text_sec, asection *exidx_sec) -{ - struct _tic6x_elf_section_data *exidx_data; - - exidx_data = get_tic6x_elf_section_data (exidx_sec); - elf32_tic6x_add_unwind_table_edit ( - &exidx_data->u.exidx.unwind_edit_list, - &exidx_data->u.exidx.unwind_edit_tail, - INSERT_EXIDX_CANTUNWIND_AT_END, text_sec, UINT_MAX); - - elf32_tic6x_adjust_exidx_size (exidx_sec, 8); -} - -/* Scan .cx6abi.exidx tables, and create a list describing edits which - should be made to those tables, such that: - - 1. Regions without unwind data are marked with EXIDX_CANTUNWIND entries. - 2. Duplicate entries are merged together (EXIDX_CANTUNWIND, or unwind - codes which have been inlined into the index). - - If MERGE_EXIDX_ENTRIES is false, duplicate entries are not merged. - - The edits are applied when the tables are written - (in elf32_tic6x_write_section). -*/ - -bfd_boolean -elf32_tic6x_fix_exidx_coverage (asection **text_section_order, - unsigned int num_text_sections, - struct bfd_link_info *info, - bfd_boolean merge_exidx_entries) -{ - bfd *inp; - unsigned int last_second_word = 0, i; - asection *last_exidx_sec = NULL; - asection *last_text_sec = NULL; - int last_unwind_type = -1; - - /* Walk over all EXIDX sections, and create backlinks from the corrsponding - text sections. */ - for (inp = info->input_bfds; inp != NULL; inp = inp->link.next) - { - asection *sec; - - for (sec = inp->sections; sec != NULL; sec = sec->next) - { - struct bfd_elf_section_data *elf_sec = elf_section_data (sec); - Elf_Internal_Shdr *hdr = &elf_sec->this_hdr; - - if (!hdr || hdr->sh_type != SHT_C6000_UNWIND) - continue; - - if (elf_sec->linked_to) - { - Elf_Internal_Shdr *linked_hdr - = &elf_section_data (elf_sec->linked_to)->this_hdr; - struct _tic6x_elf_section_data *linked_sec_tic6x_data - = get_tic6x_elf_section_data (linked_hdr->bfd_section); - - if (linked_sec_tic6x_data == NULL) - continue; - - /* Link this .c6xabi.exidx section back from the - text section it describes. */ - linked_sec_tic6x_data->u.text.tic6x_exidx_sec = sec; - } - } - } - - /* Walk all text sections in order of increasing VMA. Eilminate duplicate - index table entries (EXIDX_CANTUNWIND and inlined unwind opcodes), - and add EXIDX_CANTUNWIND entries for sections with no unwind table data. */ - - for (i = 0; i < num_text_sections; i++) - { - asection *sec = text_section_order[i]; - asection *exidx_sec; - struct _tic6x_elf_section_data *tic6x_data - = get_tic6x_elf_section_data (sec); - struct _tic6x_elf_section_data *exidx_data; - bfd_byte *contents = NULL; - int deleted_exidx_bytes = 0; - bfd_vma j; - tic6x_unwind_table_edit *unwind_edit_head = NULL; - tic6x_unwind_table_edit *unwind_edit_tail = NULL; - Elf_Internal_Shdr *hdr; - bfd *ibfd; - - if (tic6x_data == NULL) - continue; - - exidx_sec = tic6x_data->u.text.tic6x_exidx_sec; - if (exidx_sec == NULL) - { - /* Section has no unwind data. */ - if (last_unwind_type == 0 || !last_exidx_sec) - continue; - - /* Ignore zero sized sections. */ - if (sec->size == 0) - continue; - - elf32_tic6x_insert_cantunwind_after (last_text_sec, last_exidx_sec); - last_unwind_type = 0; - continue; - } - - /* Skip /DISCARD/ sections. */ - if (bfd_is_abs_section (exidx_sec->output_section)) - continue; - - hdr = &elf_section_data (exidx_sec)->this_hdr; - if (hdr->sh_type != SHT_C6000_UNWIND) - continue; - - exidx_data = get_tic6x_elf_section_data (exidx_sec); - if (exidx_data == NULL) - continue; - - ibfd = exidx_sec->owner; - - if (hdr->contents != NULL) - contents = hdr->contents; - else if (! bfd_malloc_and_get_section (ibfd, exidx_sec, &contents)) - /* An error? */ - continue; - - for (j = 0; j < hdr->sh_size; j += 8) - { - unsigned int second_word = bfd_get_32 (ibfd, contents + j + 4); - int unwind_type; - int elide = 0; - - /* An EXIDX_CANTUNWIND entry. */ - if (second_word == 1) - { - if (last_unwind_type == 0) - elide = 1; - unwind_type = 0; - } - /* Inlined unwinding data. Merge if equal to previous. */ - else if ((second_word & 0x80000000) != 0) - { - if (merge_exidx_entries - && last_second_word == second_word - && last_unwind_type == 1) - elide = 1; - unwind_type = 1; - last_second_word = second_word; - } - /* Normal table entry. In theory we could merge these too, - but duplicate entries are likely to be much less common. */ - else - unwind_type = 2; - - if (elide) - { - elf32_tic6x_add_unwind_table_edit (&unwind_edit_head, - &unwind_edit_tail, DELETE_EXIDX_ENTRY, NULL, j / 8); - - deleted_exidx_bytes += 8; - } - - last_unwind_type = unwind_type; - } - - /* Free contents if we allocated it ourselves. */ - if (contents != hdr->contents) - free (contents); - - /* Record edits to be applied later (in elf32_tic6x_write_section). */ - exidx_data->u.exidx.unwind_edit_list = unwind_edit_head; - exidx_data->u.exidx.unwind_edit_tail = unwind_edit_tail; - - if (deleted_exidx_bytes > 0) - elf32_tic6x_adjust_exidx_size (exidx_sec, -deleted_exidx_bytes); - - last_exidx_sec = exidx_sec; - last_text_sec = sec; - } - - /* Add terminating CANTUNWIND entry. */ - if (last_exidx_sec && last_unwind_type != 0) - elf32_tic6x_insert_cantunwind_after (last_text_sec, last_exidx_sec); - - return TRUE; -} - -/* Add ADDEND to lower 31 bits of VAL, leaving other bits unmodified. */ - -static unsigned long -elf32_tic6x_add_low31 (unsigned long val, bfd_vma addend) -{ - return (val & ~0x7ffffffful) | ((val + addend) & 0x7ffffffful); -} - -/* Copy an .c6xabi.exidx table entry, adding OFFSET to (applied) PREL31 - relocations. OFFSET is in bytes, and will be scaled before encoding. */ - - -static void -elf32_tic6x_copy_exidx_entry (bfd *output_bfd, bfd_byte *to, bfd_byte *from, - bfd_vma offset) -{ - unsigned long first_word = bfd_get_32 (output_bfd, from); - unsigned long second_word = bfd_get_32 (output_bfd, from + 4); - - offset >>= 1; - /* High bit of first word is supposed to be zero. */ - if ((first_word & 0x80000000ul) == 0) - first_word = elf32_tic6x_add_low31 (first_word, offset); - - /* If the high bit of the first word is clear, and the bit pattern is not 0x1 - (EXIDX_CANTUNWIND), this is an offset to an .c6xabi.extab entry. */ - if ((second_word != 0x1) && ((second_word & 0x80000000ul) == 0)) - second_word = elf32_tic6x_add_low31 (second_word, offset); - - bfd_put_32 (output_bfd, first_word, to); - bfd_put_32 (output_bfd, second_word, to + 4); -} - -/* Do the actual mangling of exception index tables. */ - -static bfd_boolean -elf32_tic6x_write_section (bfd *output_bfd, - struct bfd_link_info *link_info, - asection *sec, - bfd_byte *contents) -{ - _tic6x_elf_section_data *tic6x_data; - struct elf32_tic6x_link_hash_table *globals - = elf32_tic6x_hash_table (link_info); - bfd_vma offset = sec->output_section->vma + sec->output_offset; - - if (globals == NULL) - return FALSE; - - /* If this section has not been allocated an _tic6x_elf_section_data - structure then we cannot record anything. */ - tic6x_data = get_tic6x_elf_section_data (sec); - if (tic6x_data == NULL) - return FALSE; - - if (tic6x_data->elf.this_hdr.sh_type != SHT_C6000_UNWIND) - return FALSE; - - tic6x_unwind_table_edit *edit_node - = tic6x_data->u.exidx.unwind_edit_list; - /* Now, sec->size is the size of the section we will write. The original - size (before we merged duplicate entries and inserted EXIDX_CANTUNWIND - markers) was sec->rawsize. (This isn't the case if we perform no - edits, then rawsize will be zero and we should use size). */ - bfd_byte *edited_contents = (bfd_byte *) bfd_malloc (sec->size); - unsigned int input_size = sec->rawsize ? sec->rawsize : sec->size; - unsigned int in_index, out_index; - bfd_vma add_to_offsets = 0; - - for (in_index = 0, out_index = 0; in_index * 8 < input_size || edit_node;) - { - if (edit_node) - { - unsigned int edit_index = edit_node->index; - - if (in_index < edit_index && in_index * 8 < input_size) - { - elf32_tic6x_copy_exidx_entry (output_bfd, - edited_contents + out_index * 8, - contents + in_index * 8, add_to_offsets); - out_index++; - in_index++; - } - else if (in_index == edit_index - || (in_index * 8 >= input_size - && edit_index == UINT_MAX)) - { - switch (edit_node->type) - { - case DELETE_EXIDX_ENTRY: - in_index++; - add_to_offsets += 8; - break; - - case INSERT_EXIDX_CANTUNWIND_AT_END: - { - asection *text_sec = edit_node->linked_section; - bfd_vma text_offset = text_sec->output_section->vma - + text_sec->output_offset - + text_sec->size; - bfd_vma exidx_offset = offset + out_index * 8; - unsigned long prel31_offset; - - /* Note: this is meant to be equivalent to an - R_C6000_PREL31 relocation. These synthetic - EXIDX_CANTUNWIND markers are not relocated by the - usual BFD method. */ - prel31_offset = ((text_offset - exidx_offset) >> 1) - & 0x7ffffffful; - - /* First address we can't unwind. */ - bfd_put_32 (output_bfd, prel31_offset, - &edited_contents[out_index * 8]); - - /* Code for EXIDX_CANTUNWIND. */ - bfd_put_32 (output_bfd, 0x1, - &edited_contents[out_index * 8 + 4]); - - out_index++; - add_to_offsets -= 8; - } - break; - } - - edit_node = edit_node->next; - } - } - else - { - /* No more edits, copy remaining entries verbatim. */ - elf32_tic6x_copy_exidx_entry (output_bfd, - edited_contents + out_index * 8, - contents + in_index * 8, add_to_offsets); - out_index++; - in_index++; - } - } - - if (!(sec->flags & SEC_EXCLUDE) && !(sec->flags & SEC_NEVER_LOAD)) - bfd_set_section_contents (output_bfd, sec->output_section, - edited_contents, - (file_ptr) sec->output_offset, sec->size); - - return TRUE; -} - -#define TARGET_LITTLE_SYM tic6x_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-tic6x-le" -#define TARGET_BIG_SYM tic6x_elf32_be_vec -#define TARGET_BIG_NAME "elf32-tic6x-be" -#define ELF_ARCH bfd_arch_tic6x -#define ELF_TARGET_ID TIC6X_ELF_DATA -#define ELF_MACHINE_CODE EM_TI_C6000 -#define ELF_MAXPAGESIZE 0x1000 -#define bfd_elf32_bfd_reloc_type_lookup elf32_tic6x_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf32_tic6x_reloc_name_lookup -#define bfd_elf32_bfd_merge_private_bfd_data elf32_tic6x_merge_private_bfd_data -#define bfd_elf32_mkobject elf32_tic6x_mkobject -#define bfd_elf32_bfd_link_hash_table_create elf32_tic6x_link_hash_table_create -#define bfd_elf32_new_section_hook elf32_tic6x_new_section_hook -#define elf_backend_stack_align 8 -#define elf_backend_can_gc_sections 1 -#define elf_backend_default_use_rela_p 1 -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_obj_attrs_arg_type elf32_tic6x_obj_attrs_arg_type -#define elf_backend_obj_attrs_handle_unknown elf32_tic6x_obj_attrs_handle_unknown -#define elf_backend_obj_attrs_order elf32_tic6x_obj_attrs_order -#define elf_backend_obj_attrs_section ".c6xabi.attributes" -#define elf_backend_obj_attrs_section_type SHT_C6000_ATTRIBUTES -#define elf_backend_obj_attrs_vendor "c6xabi" -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 1 -#define elf_backend_want_dynbss 1 -#define elf_backend_want_dynrelro 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_rela_normal 1 -#define elf_backend_got_header_size 8 -#define elf_backend_fake_sections elf32_tic6x_fake_sections -#define elf_backend_gc_mark_extra_sections elf32_tic6x_gc_mark_extra_sections -#define elf_backend_create_dynamic_sections \ - elf32_tic6x_create_dynamic_sections -#define elf_backend_adjust_dynamic_symbol \ - elf32_tic6x_adjust_dynamic_symbol -#define elf_backend_check_relocs elf32_tic6x_check_relocs -#define elf_backend_add_symbol_hook elf32_tic6x_add_symbol_hook -#define elf_backend_symbol_processing elf32_tic6x_symbol_processing -#define elf_backend_link_output_symbol_hook \ - elf32_tic6x_link_output_symbol_hook -#define elf_backend_section_from_bfd_section \ - elf32_tic6x_section_from_bfd_section -#define elf_backend_relocate_section elf32_tic6x_relocate_section -#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible -#define elf_backend_finish_dynamic_symbol \ - elf32_tic6x_finish_dynamic_symbol -#define elf_backend_always_size_sections \ - elf32_tic6x_always_size_sections -#define elf_backend_size_dynamic_sections \ - elf32_tic6x_size_dynamic_sections -#define elf_backend_finish_dynamic_sections \ - elf32_tic6x_finish_dynamic_sections -#define bfd_elf32_bfd_final_link \ - elf32_tic6x_final_link -#define elf_backend_write_section elf32_tic6x_write_section -#define elf_info_to_howto elf32_tic6x_info_to_howto -#define elf_info_to_howto_rel elf32_tic6x_info_to_howto_rel - -#undef elf_backend_omit_section_dynsym -#define elf_backend_omit_section_dynsym elf32_tic6x_link_omit_section_dynsym -#define elf_backend_plt_sym_val elf32_tic6x_plt_sym_val - -#include "elf32-target.h" - -#undef elf32_bed -#define elf32_bed elf32_tic6x_linux_bed - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM tic6x_elf32_linux_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-tic6x-linux-le" -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM tic6x_elf32_linux_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-tic6x-linux-be" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_C6000_LINUX - -#include "elf32-target.h" - -#undef elf32_bed -#define elf32_bed elf32_tic6x_elf_bed - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM tic6x_elf32_c6000_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-tic6x-elf-le" -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM tic6x_elf32_c6000_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf32-tic6x-elf-be" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_C6000_ELFABI - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-tic6x.h b/sdcc/support/sdbinutils/bfd/elf32-tic6x.h deleted file mode 100644 index 3ce9c74b7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-tic6x.h +++ /dev/null @@ -1,42 +0,0 @@ -/* 32-bit ELF support for TI C6X - Copyright (C) 2010-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int elf32_tic6x_merge_arch_attributes (int, int); - -/* This function is provided for use from the assembler. */ - -extern void elf32_tic6x_set_use_rela_p (bfd *, bfd_boolean); - -struct elf32_tic6x_params -{ - int dsbt_index; - int dsbt_size; -}; - -extern void elf32_tic6x_setup (struct bfd_link_info *, - struct elf32_tic6x_params *); - -#ifdef __cplusplus -} -#endif diff --git a/sdcc/support/sdbinutils/bfd/elf32-tilegx.c b/sdcc/support/sdbinutils/bfd/elf32-tilegx.c deleted file mode 100644 index cbbbad9a9..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-tilegx.c +++ /dev/null @@ -1,134 +0,0 @@ -/* TILE-Gx-specific support for 32-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elfxx-tilegx.h" -#include "elf32-tilegx.h" - - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -tilegx_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - if (note->descsz != TILEGX_PRSTATUS_SIZEOF) - return FALSE; - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = - bfd_get_16 (abfd, note->descdata + TILEGX_PRSTATUS_OFFSET_PR_CURSIG); - - /* pr_pid */ - elf_tdata (abfd)->core->pid = - bfd_get_32 (abfd, note->descdata + TILEGX_PRSTATUS_OFFSET_PR_PID); - - /* pr_reg */ - offset = TILEGX_PRSTATUS_OFFSET_PR_REG; - size = TILEGX_GREGSET_T_SIZE; - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -tilegx_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - if (note->descsz != TILEGX_PRPSINFO_SIZEOF) - return FALSE; - - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + TILEGX_PRPSINFO_OFFSET_PR_FNAME, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + TILEGX_PRPSINFO_OFFSET_PR_PSARGS, ELF_PR_PSARGS_SIZE); - - - /* 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; -} - - -#define ELF_ARCH bfd_arch_tilegx -#define ELF_TARGET_ID TILEGX_ELF_DATA -#define ELF_MACHINE_CODE EM_TILEGX -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x10000 - -#define TARGET_BIG_SYM tilegx_elf32_be_vec -#define TARGET_BIG_NAME "elf32-tilegx-be" -#define TARGET_LITTLE_SYM tilegx_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-tilegx-le" - -#define elf_backend_reloc_type_class tilegx_reloc_type_class - -#define bfd_elf32_bfd_reloc_name_lookup tilegx_reloc_name_lookup -#define bfd_elf32_bfd_link_hash_table_create tilegx_elf_link_hash_table_create -#define bfd_elf32_bfd_reloc_type_lookup tilegx_reloc_type_lookup -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_tilegx_elf_merge_private_bfd_data - -#define elf_backend_copy_indirect_symbol tilegx_elf_copy_indirect_symbol -#define elf_backend_create_dynamic_sections tilegx_elf_create_dynamic_sections -#define elf_backend_check_relocs tilegx_elf_check_relocs -#define elf_backend_adjust_dynamic_symbol tilegx_elf_adjust_dynamic_symbol -#define elf_backend_omit_section_dynsym tilegx_elf_omit_section_dynsym -#define elf_backend_size_dynamic_sections tilegx_elf_size_dynamic_sections -#define elf_backend_relocate_section tilegx_elf_relocate_section -#define elf_backend_finish_dynamic_symbol tilegx_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections tilegx_elf_finish_dynamic_sections -#define elf_backend_gc_mark_hook tilegx_elf_gc_mark_hook -#define elf_backend_plt_sym_val tilegx_elf_plt_sym_val -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto tilegx_info_to_howto_rela -#define elf_backend_grok_prstatus tilegx_elf_grok_prstatus -#define elf_backend_grok_psinfo tilegx_elf_grok_psinfo -#define elf_backend_additional_program_headers tilegx_additional_program_headers - -#define elf_backend_init_index_section _bfd_elf_init_1_index_section - -#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 -/* Align PLT mod 64 byte L2 line size. */ -#define elf_backend_plt_alignment 6 -#define elf_backend_want_plt_sym 1 -#define elf_backend_got_header_size 4 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_default_execstack 0 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-tilegx.h b/sdcc/support/sdbinutils/bfd/elf32-tilegx.h deleted file mode 100644 index 4f1e53ad7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-tilegx.h +++ /dev/null @@ -1,38 +0,0 @@ -/* TILE-Gx-specific support for 32-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_TILEGX_H -#define _ELF32_TILEGX_H - -/* This file contains sizes and offsets of Linux data structures. */ - -#define TILEGX_PRSTATUS_SIZEOF 592 -#define TILEGX_PRSTATUS_OFFSET_PR_CURSIG 12 -#define TILEGX_PRSTATUS_OFFSET_PR_PID 24 -#define TILEGX_PRSTATUS_OFFSET_PR_REG 72 - -#define TILEGX_PRPSINFO_SIZEOF 128 -#define TILEGX_PRPSINFO_OFFSET_PR_FNAME 32 -#define TILEGX_PRPSINFO_OFFSET_PR_PSARGS 48 -#define ELF_PR_PSARGS_SIZE 80 - -#define TILEGX_GREGSET_T_SIZE 512 - -#endif /* _ELF32_TILEGX_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-tilepro.c b/sdcc/support/sdbinutils/bfd/elf32-tilepro.c deleted file mode 100644 index 96ba98dad..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-tilepro.c +++ /dev/null @@ -1,3895 +0,0 @@ -/* TILEPro-specific support for 32-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/tilepro.h" -#include "opcode/tilepro.h" -#include "libiberty.h" -#include "elf32-tilepro.h" - -#define TILEPRO_BYTES_PER_WORD 4 - -static reloc_howto_type tilepro_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_TILEPRO_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_TILEPRO_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_TILEPRO_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_TILEPRO_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit pc-relative relocation. */ - HOWTO (R_TILEPRO_32_PCREL,/* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_32_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit pc-relative relocation. */ - HOWTO (R_TILEPRO_16_PCREL,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* An 8 bit pc-relative relocation. */ - HOWTO (R_TILEPRO_8_PCREL, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_8_PCREL",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit relocation without overflow. */ - HOWTO (R_TILEPRO_LO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high order 16 bits of an address. */ - HOWTO (R_TILEPRO_HI16, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high order 16 bits of an address, plus 1 if the contents of - the low 16 bits, treated as a signed number, is negative. */ - HOWTO (R_TILEPRO_HA16, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_HA16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_COPY, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_GLOB_DAT, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_JMP_SLOT, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_RELATIVE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_BROFF_X1, /* type */ - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_BROFF_X1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_JOFFLONG_X1, /* type */ - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 29, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_JOFFLONG_X1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_JOFFLONG_X1_PLT, /* type */ - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 29, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_JOFFLONG_X1_PLT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - -#define TILEPRO_IMM_HOWTO(name, size, bitsize) \ - HOWTO (name, 0, size, bitsize, FALSE, 0, \ - complain_overflow_signed, bfd_elf_generic_reloc, \ - #name, FALSE, 0, -1, FALSE) - -#define TILEPRO_UIMM_HOWTO(name, size, bitsize) \ - HOWTO (name, 0, size, bitsize, FALSE, 0, \ - complain_overflow_unsigned, bfd_elf_generic_reloc, \ - #name, FALSE, 0, -1, FALSE) - - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_X0, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_Y0, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_X1, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_Y1, 0, 8), - TILEPRO_UIMM_HOWTO(R_TILEPRO_MT_IMM15_X1, 1, 15), - TILEPRO_UIMM_HOWTO(R_TILEPRO_MF_IMM15_X1, 1, 15), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM16_X0, 1, 16), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM16_X1, 1, 16), - -#define TILEPRO_IMM16_HOWTO(name, rshift) \ - HOWTO (name, rshift, 1, 16, FALSE, 0, \ - complain_overflow_dont, bfd_elf_generic_reloc, \ - #name, FALSE, 0, 0xffff, FALSE) - - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_HA, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_HA, 16), - - /* PC-relative offsets. */ - - HOWTO (R_TILEPRO_IMM16_X0_PCREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X0_PCREL",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_IMM16_X1_PCREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X1_PCREL",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - -#define TILEPRO_IMM16_HOWTO_PCREL(name, rshift) \ - HOWTO (name, rshift, 1, 16, TRUE, 0, \ - complain_overflow_dont, bfd_elf_generic_reloc, \ - #name, FALSE, 0, 0xffff, TRUE) - - TILEPRO_IMM16_HOWTO_PCREL (R_TILEPRO_IMM16_X0_LO_PCREL, 0), - TILEPRO_IMM16_HOWTO_PCREL (R_TILEPRO_IMM16_X1_LO_PCREL, 0), - TILEPRO_IMM16_HOWTO_PCREL (R_TILEPRO_IMM16_X0_HI_PCREL, 16), - TILEPRO_IMM16_HOWTO_PCREL (R_TILEPRO_IMM16_X1_HI_PCREL, 16), - TILEPRO_IMM16_HOWTO_PCREL (R_TILEPRO_IMM16_X0_HA_PCREL, 16), - TILEPRO_IMM16_HOWTO_PCREL (R_TILEPRO_IMM16_X1_HA_PCREL, 16), - - /* Byte offset into GOT for a particular symbol. */ - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM16_X0_GOT, 1, 16), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM16_X1_GOT, 1, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_GOT_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_GOT_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_GOT_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_GOT_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_GOT_HA, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_GOT_HA, 16), - - TILEPRO_UIMM_HOWTO(R_TILEPRO_MMSTART_X0, 0, 5), - TILEPRO_UIMM_HOWTO(R_TILEPRO_MMEND_X0, 0, 5), - TILEPRO_UIMM_HOWTO(R_TILEPRO_MMSTART_X1, 0, 5), - TILEPRO_UIMM_HOWTO(R_TILEPRO_MMEND_X1, 0, 5), - - TILEPRO_UIMM_HOWTO(R_TILEPRO_SHAMT_X0, 0, 5), - TILEPRO_UIMM_HOWTO(R_TILEPRO_SHAMT_X1, 0, 5), - TILEPRO_UIMM_HOWTO(R_TILEPRO_SHAMT_Y0, 0, 5), - TILEPRO_UIMM_HOWTO(R_TILEPRO_SHAMT_Y1, 0, 5), - - TILEPRO_IMM_HOWTO(R_TILEPRO_DEST_IMM8_X1, 0, 8), - - /* These relocs are currently not defined. */ - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - - HOWTO (R_TILEPRO_TLS_GD_CALL, /* type */ - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 29, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_TLS_GD_CALL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_X0_TLS_GD_ADD, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_X1_TLS_GD_ADD, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_Y0_TLS_GD_ADD, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_IMM8_Y1_TLS_GD_ADD, 0, 8), - TILEPRO_IMM_HOWTO(R_TILEPRO_TLS_IE_LOAD, 0, 8), - - /* Offsets into the GOT of TLS Descriptors. */ - - HOWTO (R_TILEPRO_IMM16_X0_TLS_GD,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X0_TLS_GD",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_IMM16_X1_TLS_GD,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X1_TLS_GD",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_GD_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_GD_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_GD_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_GD_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_GD_HA, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_GD_HA, 16), - - /* Offsets into the GOT of TLS Descriptors. */ - - HOWTO (R_TILEPRO_IMM16_X0_TLS_IE,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X0_TLS_IE",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_IMM16_X1_TLS_IE,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X1_TLS_IE",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_IE_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_IE_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_IE_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_IE_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_IE_HA, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_IE_HA, 16), - - /* These are common with the Solaris TLS implementation. */ - HOWTO(R_TILEPRO_TLS_DTPMOD32, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_TILEPRO_TLS_DTPMOD32", - FALSE, 0, 0, TRUE), - HOWTO(R_TILEPRO_TLS_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_TILEPRO_TLS_DTPOFF32", - FALSE, 0, 0xFFFFFFFF, TRUE), - HOWTO(R_TILEPRO_TLS_TPOFF32, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_TILEPRO_TLS_TPOFF32", - FALSE, 0, 0, TRUE), - - HOWTO (R_TILEPRO_IMM16_X0_TLS_LE,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X0_TLS_LE",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_TILEPRO_IMM16_X1_TLS_LE,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_TILEPRO_IMM16_X1_TLS_LE",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - -1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_LE_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_LE_LO, 0), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_LE_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_LE_HI, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X0_TLS_LE_HA, 16), - TILEPRO_IMM16_HOWTO (R_TILEPRO_IMM16_X1_TLS_LE_HA, 16), -}; - -static reloc_howto_type tilepro_elf_howto_table2 [] = -{ - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_TILEPRO_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_TILEPRO_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_TILEPRO_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_TILEPRO_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Map BFD reloc types to TILEPRO ELF reloc types. */ - -typedef struct tilepro_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int tilepro_reloc_val; - reloc_howto_type * table; -} reloc_map; - -static const reloc_map tilepro_reloc_map [] = -{ -#define TH_REMAP(bfd, tilepro) \ - { bfd, tilepro, tilepro_elf_howto_table }, - - /* Standard relocations. */ - TH_REMAP (BFD_RELOC_NONE, R_TILEPRO_NONE) - TH_REMAP (BFD_RELOC_32, R_TILEPRO_32) - TH_REMAP (BFD_RELOC_16, R_TILEPRO_16) - TH_REMAP (BFD_RELOC_8, R_TILEPRO_8) - TH_REMAP (BFD_RELOC_32_PCREL, R_TILEPRO_32_PCREL) - TH_REMAP (BFD_RELOC_16_PCREL, R_TILEPRO_16_PCREL) - TH_REMAP (BFD_RELOC_8_PCREL, R_TILEPRO_8_PCREL) - TH_REMAP (BFD_RELOC_LO16, R_TILEPRO_LO16) - TH_REMAP (BFD_RELOC_HI16, R_TILEPRO_HI16) - TH_REMAP (BFD_RELOC_HI16_S, R_TILEPRO_HA16) - - /* Custom relocations. */ - TH_REMAP (BFD_RELOC_TILEPRO_COPY, R_TILEPRO_COPY) - TH_REMAP (BFD_RELOC_TILEPRO_GLOB_DAT, R_TILEPRO_GLOB_DAT) - TH_REMAP (BFD_RELOC_TILEPRO_JMP_SLOT, R_TILEPRO_JMP_SLOT) - TH_REMAP (BFD_RELOC_TILEPRO_RELATIVE, R_TILEPRO_RELATIVE) - TH_REMAP (BFD_RELOC_TILEPRO_BROFF_X1, R_TILEPRO_BROFF_X1) - TH_REMAP (BFD_RELOC_TILEPRO_JOFFLONG_X1, R_TILEPRO_JOFFLONG_X1) - TH_REMAP (BFD_RELOC_TILEPRO_JOFFLONG_X1_PLT, R_TILEPRO_JOFFLONG_X1_PLT) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_X0, R_TILEPRO_IMM8_X0) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_Y0, R_TILEPRO_IMM8_Y0) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_X1, R_TILEPRO_IMM8_X1) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_Y1, R_TILEPRO_IMM8_Y1) - TH_REMAP (BFD_RELOC_TILEPRO_DEST_IMM8_X1, R_TILEPRO_DEST_IMM8_X1) - TH_REMAP (BFD_RELOC_TILEPRO_MT_IMM15_X1, R_TILEPRO_MT_IMM15_X1) - TH_REMAP (BFD_RELOC_TILEPRO_MF_IMM15_X1, R_TILEPRO_MF_IMM15_X1) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0, R_TILEPRO_IMM16_X0) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1, R_TILEPRO_IMM16_X1) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_LO, R_TILEPRO_IMM16_X0_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_LO, R_TILEPRO_IMM16_X1_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_HI, R_TILEPRO_IMM16_X0_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_HI, R_TILEPRO_IMM16_X1_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_HA, R_TILEPRO_IMM16_X0_HA) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_HA, R_TILEPRO_IMM16_X1_HA) - - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_PCREL, R_TILEPRO_IMM16_X0_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_PCREL, R_TILEPRO_IMM16_X1_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_LO_PCREL, R_TILEPRO_IMM16_X0_LO_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_LO_PCREL, R_TILEPRO_IMM16_X1_LO_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_HI_PCREL, R_TILEPRO_IMM16_X0_HI_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_HI_PCREL, R_TILEPRO_IMM16_X1_HI_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_HA_PCREL, R_TILEPRO_IMM16_X0_HA_PCREL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_HA_PCREL, R_TILEPRO_IMM16_X1_HA_PCREL) - - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_GOT, R_TILEPRO_IMM16_X0_GOT) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_GOT, R_TILEPRO_IMM16_X1_GOT) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_GOT_LO, R_TILEPRO_IMM16_X0_GOT_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_GOT_LO, R_TILEPRO_IMM16_X1_GOT_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_GOT_HI, R_TILEPRO_IMM16_X0_GOT_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_GOT_HI, R_TILEPRO_IMM16_X1_GOT_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_GOT_HA, R_TILEPRO_IMM16_X0_GOT_HA) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_GOT_HA, R_TILEPRO_IMM16_X1_GOT_HA) - - TH_REMAP (BFD_RELOC_TILEPRO_MMSTART_X0, R_TILEPRO_MMSTART_X0) - TH_REMAP (BFD_RELOC_TILEPRO_MMEND_X0, R_TILEPRO_MMEND_X0) - TH_REMAP (BFD_RELOC_TILEPRO_MMSTART_X1, R_TILEPRO_MMSTART_X1) - TH_REMAP (BFD_RELOC_TILEPRO_MMEND_X1, R_TILEPRO_MMEND_X1) - TH_REMAP (BFD_RELOC_TILEPRO_SHAMT_X0, R_TILEPRO_SHAMT_X0) - TH_REMAP (BFD_RELOC_TILEPRO_SHAMT_X1, R_TILEPRO_SHAMT_X1) - TH_REMAP (BFD_RELOC_TILEPRO_SHAMT_Y0, R_TILEPRO_SHAMT_Y0) - TH_REMAP (BFD_RELOC_TILEPRO_SHAMT_Y1, R_TILEPRO_SHAMT_Y1) - - TH_REMAP (BFD_RELOC_TILEPRO_TLS_GD_CALL, R_TILEPRO_TLS_GD_CALL) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_X0_TLS_GD_ADD, R_TILEPRO_IMM8_X0_TLS_GD_ADD) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_X1_TLS_GD_ADD, R_TILEPRO_IMM8_X1_TLS_GD_ADD) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_Y0_TLS_GD_ADD, R_TILEPRO_IMM8_Y0_TLS_GD_ADD) - TH_REMAP (BFD_RELOC_TILEPRO_IMM8_Y1_TLS_GD_ADD, R_TILEPRO_IMM8_Y1_TLS_GD_ADD) - TH_REMAP (BFD_RELOC_TILEPRO_TLS_IE_LOAD, R_TILEPRO_TLS_IE_LOAD) - - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD, R_TILEPRO_IMM16_X0_TLS_GD) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD, R_TILEPRO_IMM16_X1_TLS_GD) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_LO, R_TILEPRO_IMM16_X0_TLS_GD_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_LO, R_TILEPRO_IMM16_X1_TLS_GD_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HI, R_TILEPRO_IMM16_X0_TLS_GD_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HI, R_TILEPRO_IMM16_X1_TLS_GD_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_GD_HA, R_TILEPRO_IMM16_X0_TLS_GD_HA) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_GD_HA, R_TILEPRO_IMM16_X1_TLS_GD_HA) - - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE, R_TILEPRO_IMM16_X0_TLS_IE) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE, R_TILEPRO_IMM16_X1_TLS_IE) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_LO, R_TILEPRO_IMM16_X0_TLS_IE_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_LO, R_TILEPRO_IMM16_X1_TLS_IE_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HI, R_TILEPRO_IMM16_X0_TLS_IE_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HI, R_TILEPRO_IMM16_X1_TLS_IE_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_IE_HA, R_TILEPRO_IMM16_X0_TLS_IE_HA) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_IE_HA, R_TILEPRO_IMM16_X1_TLS_IE_HA) - - TH_REMAP (BFD_RELOC_TILEPRO_TLS_DTPMOD32, R_TILEPRO_TLS_DTPMOD32) - TH_REMAP (BFD_RELOC_TILEPRO_TLS_DTPOFF32, R_TILEPRO_TLS_DTPOFF32) - TH_REMAP (BFD_RELOC_TILEPRO_TLS_TPOFF32, R_TILEPRO_TLS_TPOFF32) - - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE, R_TILEPRO_IMM16_X0_TLS_LE) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE, R_TILEPRO_IMM16_X1_TLS_LE) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_LO, R_TILEPRO_IMM16_X0_TLS_LE_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_LO, R_TILEPRO_IMM16_X1_TLS_LE_LO) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HI, R_TILEPRO_IMM16_X0_TLS_LE_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HI, R_TILEPRO_IMM16_X1_TLS_LE_HI) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X0_TLS_LE_HA, R_TILEPRO_IMM16_X0_TLS_LE_HA) - TH_REMAP (BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA, R_TILEPRO_IMM16_X1_TLS_LE_HA) - -#undef TH_REMAP - - { BFD_RELOC_VTABLE_INHERIT, R_TILEPRO_GNU_VTINHERIT, tilepro_elf_howto_table2 }, - { BFD_RELOC_VTABLE_ENTRY, R_TILEPRO_GNU_VTENTRY, tilepro_elf_howto_table2 }, -}; - - - -/* TILEPRO ELF linker hash entry. */ - -struct tilepro_elf_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_IE 4 - unsigned char tls_type; -}; - -#define tilepro_elf_hash_entry(ent) \ - ((struct tilepro_elf_link_hash_entry *)(ent)) - -struct _bfd_tilepro_elf_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char *local_got_tls_type; -}; - -#define _bfd_tilepro_elf_tdata(abfd) \ - ((struct _bfd_tilepro_elf_obj_tdata *) (abfd)->tdata.any) - -#define _bfd_tilepro_elf_local_got_tls_type(abfd) \ - (_bfd_tilepro_elf_tdata (abfd)->local_got_tls_type) - -#define is_tilepro_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == TILEPRO_ELF_DATA) - -/* Allocate TILEPro ELF private object data. */ - -static bfd_boolean -tilepro_elf_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, - sizeof (struct _bfd_tilepro_elf_obj_tdata), - TILEPRO_ELF_DATA); -} - -#include "elf/common.h" -#include "elf/internal.h" - -struct tilepro_elf_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Small local sym to section mapping cache. */ - struct sym_cache sym_cache; -}; - -/* Get the Tilepro ELF linker hash table from a link_info structure. */ -#define tilepro_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == TILEPRO_ELF_DATA \ - ? ((struct tilepro_elf_link_hash_table *) ((p)->hash)) : NULL) - -static reloc_howto_type * -tilepro_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (tilepro_reloc_map); i--;) - { - const reloc_map * entry; - - entry = tilepro_reloc_map + i; - - if (entry->bfd_reloc_val == code) - return entry->table + (entry->tilepro_reloc_val - - entry->table[0].type); - } - - return NULL; -} - -static reloc_howto_type * -tilepro_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (tilepro_elf_howto_table) - / sizeof (tilepro_elf_howto_table[0])); - i++) - if (tilepro_elf_howto_table[i].name != NULL - && strcasecmp (tilepro_elf_howto_table[i].name, r_name) == 0) - return &tilepro_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an TILEPro ELF reloc. */ - -static void -tilepro_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - - if (r_type <= (unsigned int) R_TILEPRO_IMM16_X1_TLS_LE_HA) - cache_ptr->howto = &tilepro_elf_howto_table [r_type]; - else if (r_type - R_TILEPRO_GNU_VTINHERIT - <= (unsigned int) R_TILEPRO_GNU_VTENTRY) - cache_ptr->howto - = &tilepro_elf_howto_table2 [r_type - R_TILEPRO_GNU_VTINHERIT]; - else - abort (); -} - -typedef tilepro_bundle_bits (*tilepro_create_func)(int); - -static const tilepro_create_func reloc_to_create_func[] = -{ - /* The first fourteen relocation types don't correspond to operands */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - - /* The remaining relocations are used for immediate operands */ - create_BrOff_X1, - create_JOffLong_X1, - create_JOffLong_X1, - create_Imm8_X0, - create_Imm8_Y0, - create_Imm8_X1, - create_Imm8_Y1, - create_MT_Imm15_X1, - create_MF_Imm15_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_MMStart_X0, - create_MMEnd_X0, - create_MMStart_X1, - create_MMEnd_X1, - create_ShAmt_X0, - create_ShAmt_X1, - create_ShAmt_Y0, - create_ShAmt_Y1, - - create_Dest_Imm8_X1, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - - NULL, - NULL, - NULL, - - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, - create_Imm16_X0, - create_Imm16_X1, -}; - -#define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -tilepro_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - if (note->descsz != TILEPRO_PRSTATUS_SIZEOF) - return FALSE; - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = - bfd_get_16 (abfd, note->descdata + TILEPRO_PRSTATUS_OFFSET_PR_CURSIG); - - /* pr_pid */ - elf_tdata (abfd)->core->pid = - bfd_get_32 (abfd, note->descdata + TILEPRO_PRSTATUS_OFFSET_PR_PID); - - /* pr_reg */ - offset = TILEPRO_PRSTATUS_OFFSET_PR_REG; - size = TILEPRO_GREGSET_T_SIZE; - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -tilepro_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - if (note->descsz != TILEPRO_PRPSINFO_SIZEOF) - return FALSE; - - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, - note->descdata + TILEPRO_PRPSINFO_OFFSET_PR_FNAME, - 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, - note->descdata + TILEPRO_PRPSINFO_OFFSET_PR_PSARGS, - ELF_PR_PSARGS_SIZE); - - - /* 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; -} - - -static void -tilepro_elf_append_rela_32 (bfd *abfd, asection *s, Elf_Internal_Rela *rel) -{ - Elf32_External_Rela *loc32; - - loc32 = (Elf32_External_Rela *) s->contents; - loc32 += s->reloc_count++; - bfd_elf32_swap_reloca_out (abfd, rel, (bfd_byte *) loc32); -} - -/* PLT/GOT stuff */ - -/* The procedure linkage table starts with the following header: - - { - rli r29, r29, 16 - lwadd r28, r27, 4 - } - lw r27, r27 - { - info 10 ## SP not offset, return PC in LR - jr r27 - } - - Subsequent entries are the following, jumping to the header at the end: - - lnk r28 -1: - { - auli r28, r28, <_GLOBAL_OFFSET_TABLE_ - 1b + MY_GOT_OFFSET> - auli r27, r28, <_GLOBAL_OFFSET_TABLE_ - 1b> - } - { - addli r28, r28, <_GLOBAL_OFFSET_TABLE_ - 1b + MY_GOT_OFFSET> - addli r27, r27, <_GLOBAL_OFFSET_TABLE_ - 1b> - } - { - auli r29, zero, MY_PLT_INDEX - lw r28, r28 - } - { - info 10 ## SP not offset, return PC in LR - jr r28 - } - - We initially store MY_PLT_INDEX in the high bits so that we can use the all - 16 bits as an unsigned offset; if we use the low bits we would get an - unwanted sign extension. The PLT header then rotates the index to get the - right value, before calling the resolution routine. This computation can - fit in unused bundle slots so it's free. - - This code sequence lets the code at at the start of the PLT determine - which PLT entry was executed by examining 'r29'. - - Note that MY_PLT_INDEX skips over the header entries, so the first - actual jump table entry has index zero. -*/ - -#define PLT_HEADER_SIZE_IN_BUNDLES 3 -#define PLT_ENTRY_SIZE_IN_BUNDLES 5 - -#define PLT_HEADER_SIZE \ - (PLT_HEADER_SIZE_IN_BUNDLES * TILEPRO_BUNDLE_SIZE_IN_BYTES) -#define PLT_ENTRY_SIZE \ - (PLT_ENTRY_SIZE_IN_BUNDLES * TILEPRO_BUNDLE_SIZE_IN_BYTES) - -/* The size in bytes of an entry in the global offset table. */ - -#define GOT_ENTRY_SIZE TILEPRO_BYTES_PER_WORD - -#define GOTPLT_HEADER_SIZE (2 * GOT_ENTRY_SIZE) - - -static const bfd_byte -tilepro_plt0_entry[PLT_HEADER_SIZE] = -{ - 0x5d, 0x07, 0x03, 0x70, - 0x6e, 0x23, 0xd0, 0x30, /* { rli r29, r29, 16 ; lwadd r28, r27, 4 } */ - 0x00, 0x50, 0xba, 0x6d, - 0x00, 0x08, 0x6d, 0xdc, /* { lw r27, r27 } */ - 0xff, 0xaf, 0x10, 0x50, - 0x60, 0x03, 0x18, 0x08, /* { info 10 ; jr r27 } */ -}; - -static const bfd_byte -tilepro_short_plt_entry[PLT_ENTRY_SIZE] = -{ - 0x00, 0x50, 0x16, 0x70, - 0x0e, 0x00, 0x1a, 0x08, /* { lnk r28 } */ - 0x1c, 0x07, 0x00, 0xa0, - 0x8d, 0x03, 0x00, 0x18, /* { addli r28, r28, 0 ; addli r27, r28, 0 } */ - 0xdd, 0x0f, 0x00, 0x30, - 0x8e, 0x73, 0x0b, 0x40, /* { auli r29, zero, 0 ; lw r28, r28 } */ - 0xff, 0xaf, 0x10, 0x50, - 0x80, 0x03, 0x18, 0x08, /* { info 10 ; jr r28 } */ - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -static const bfd_byte -tilepro_long_plt_entry[PLT_ENTRY_SIZE] = -{ - 0x00, 0x50, 0x16, 0x70, - 0x0e, 0x00, 0x1a, 0x08, /* { lnk r28 } */ - 0x1c, 0x07, 0x00, 0xb0, - 0x8d, 0x03, 0x00, 0x20, /* { auli r28, r28, 0 ; auli r27, r28, 0 } */ - 0x1c, 0x07, 0x00, 0xa0, - 0x6d, 0x03, 0x00, 0x18, /* { addli r28, r28, 0 ; addli r27, r27, 0 } */ - 0xdd, 0x0f, 0x00, 0x30, - 0x8e, 0x73, 0x0b, 0x40, /* { auli r29, zero, 0 ; lw r28, r28 } */ - 0xff, 0xaf, 0x10, 0x50, - 0x80, 0x03, 0x18, 0x08, /* { info 10 ; jr r28 } */ -}; - -static bfd_vma -tilepro_ha16(bfd_vma vma) -{ - return ((vma >> 16) + ((vma >> 15) & 1)) & 0xffff; -} - -static int -tilepro_plt_entry_build (asection *splt, asection *sgotplt, bfd_vma offset, - bfd_vma *r_offset) -{ - int plt_index = (offset - PLT_ENTRY_SIZE) / PLT_ENTRY_SIZE; - int got_offset = plt_index * GOT_ENTRY_SIZE + GOTPLT_HEADER_SIZE; - tilepro_bundle_bits *pc; - - /* Compute the distance from the got entry to the lnk. */ - bfd_signed_vma dist_got_entry = sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset - - splt->output_section->vma - - splt->output_offset - - offset - - TILEPRO_BUNDLE_SIZE_IN_BYTES; - - /* Compute the distance to GOTPLT[0]. */ - bfd_signed_vma dist_got0 = dist_got_entry - got_offset; - - /* Check whether we can use the short plt entry with 16-bit offset. */ - bfd_boolean short_plt_entry = - (dist_got_entry <= 0x7fff && dist_got0 >= -0x8000); - - /* Copy the plt entry template. */ - memcpy (splt->contents + offset, - short_plt_entry ? tilepro_short_plt_entry : tilepro_long_plt_entry, - PLT_ENTRY_SIZE); - - /* Write the immediate offsets. */ - pc = (tilepro_bundle_bits *)(splt->contents + offset); - pc++; - - if (!short_plt_entry) - { - /* { auli r28, r28, &GOTPLT[MY_GOT_INDEX] ; auli r27, r28, &GOTPLT[0] } */ - *pc++ |= create_Imm16_X0 (tilepro_ha16 (dist_got_entry)) - | create_Imm16_X1 (tilepro_ha16 (dist_got0)); - } - - /* { addli r28, r28, &GOTPLT[MY_GOT_INDEX] ; addli r27, r28, &GOTPLT[0] } or - { addli r28, r28, &GOTPLT[MY_GOT_INDEX] ; addli r27, r27, &GOTPLT[0] } */ - *pc++ |= create_Imm16_X0 (dist_got_entry) - | create_Imm16_X1 (dist_got0); - - /* { auli r29, zero, MY_PLT_INDEX ; lw r28, r28 } */ - *pc |= create_Imm16_X0 (plt_index); - - /* Set the relocation offset. */ - *r_offset = got_offset; - - return plt_index; -} - -#define TILEPRO_ELF_RELA_BYTES (sizeof(Elf32_External_Rela)) - - -/* Create an entry in an TILEPro 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 tilepro_elf_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 tilepro_elf_link_hash_entry *eh; - - eh = (struct tilepro_elf_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - eh->tls_type = GOT_UNKNOWN; - } - - return entry; -} - -/* Create a TILEPRO ELF linker hash table. */ - -static struct bfd_link_hash_table * -tilepro_elf_link_hash_table_create (bfd *abfd) -{ - struct tilepro_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct tilepro_elf_link_hash_table); - - ret = (struct tilepro_elf_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, - sizeof (struct tilepro_elf_link_hash_entry), - TILEPRO_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->elf.root; -} - -/* Create the .got section. */ - -static bfd_boolean -tilepro_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags; - asection *s, *s_got; - struct elf_link_hash_entry *h; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab = elf_hash_table (info); - - /* This function may be called more than once. */ - if (htab->sgot != NULL) - return TRUE; - - flags = bed->dynamic_sec_flags; - - s = bfd_make_section_with_flags (abfd, - (bed->rela_plts_and_copies_p - ? ".rela.got" : ".rel.got"), - (bed->dynamic_sec_flags - | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - htab->srelgot = s; - - s = s_got = bfd_make_section_with_flags (abfd, ".got", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - htab->sgot = s; - - /* The first bit of the global offset table is the header. */ - s->size += bed->got_header_size; - - if (bed->want_got_plt) - { - s = bfd_make_section_with_flags (abfd, ".got.plt", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->sgotplt = s; - - /* Reserve room for the header. */ - s->size += GOTPLT_HEADER_SIZE; - } - - if (bed->want_got_sym) - { - /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got - 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_got, - "_GLOBAL_OFFSET_TABLE_"); - elf_hash_table (info)->hgot = h; - if (h == NULL) - 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 -tilepro_elf_create_dynamic_sections (bfd *dynobj, - struct bfd_link_info *info) -{ - if (!tilepro_elf_create_got_section (dynobj, info)) - return FALSE; - - return _bfd_elf_create_dynamic_sections (dynobj, info); -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -tilepro_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct tilepro_elf_link_hash_entry *edir, *eind; - - edir = (struct tilepro_elf_link_hash_entry *) dir; - eind = (struct tilepro_elf_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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; - } - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -static int -tilepro_tls_translate_to_le (int r_type) -{ - switch (r_type) - { - case R_TILEPRO_IMM16_X0_TLS_GD: - case R_TILEPRO_IMM16_X0_TLS_IE: - return R_TILEPRO_IMM16_X0_TLS_LE; - - case R_TILEPRO_IMM16_X1_TLS_GD: - case R_TILEPRO_IMM16_X1_TLS_IE: - return R_TILEPRO_IMM16_X1_TLS_LE; - - case R_TILEPRO_IMM16_X0_TLS_GD_LO: - case R_TILEPRO_IMM16_X0_TLS_IE_LO: - return R_TILEPRO_IMM16_X0_TLS_LE_LO; - - case R_TILEPRO_IMM16_X1_TLS_GD_LO: - case R_TILEPRO_IMM16_X1_TLS_IE_LO: - return R_TILEPRO_IMM16_X1_TLS_LE_LO; - - case R_TILEPRO_IMM16_X0_TLS_GD_HI: - case R_TILEPRO_IMM16_X0_TLS_IE_HI: - return R_TILEPRO_IMM16_X0_TLS_LE_HI; - - case R_TILEPRO_IMM16_X1_TLS_GD_HI: - case R_TILEPRO_IMM16_X1_TLS_IE_HI: - return R_TILEPRO_IMM16_X1_TLS_LE_HI; - - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - return R_TILEPRO_IMM16_X0_TLS_LE_HA; - - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - return R_TILEPRO_IMM16_X1_TLS_LE_HA; - } - return r_type; -} - -static int -tilepro_tls_translate_to_ie (int r_type) -{ - switch (r_type) - { - case R_TILEPRO_IMM16_X0_TLS_GD: - case R_TILEPRO_IMM16_X0_TLS_IE: - return R_TILEPRO_IMM16_X0_TLS_IE; - - case R_TILEPRO_IMM16_X1_TLS_GD: - case R_TILEPRO_IMM16_X1_TLS_IE: - return R_TILEPRO_IMM16_X1_TLS_IE; - - case R_TILEPRO_IMM16_X0_TLS_GD_LO: - case R_TILEPRO_IMM16_X0_TLS_IE_LO: - return R_TILEPRO_IMM16_X0_TLS_IE_LO; - - case R_TILEPRO_IMM16_X1_TLS_GD_LO: - case R_TILEPRO_IMM16_X1_TLS_IE_LO: - return R_TILEPRO_IMM16_X1_TLS_IE_LO; - - case R_TILEPRO_IMM16_X0_TLS_GD_HI: - case R_TILEPRO_IMM16_X0_TLS_IE_HI: - return R_TILEPRO_IMM16_X0_TLS_IE_HI; - - case R_TILEPRO_IMM16_X1_TLS_GD_HI: - case R_TILEPRO_IMM16_X1_TLS_IE_HI: - return R_TILEPRO_IMM16_X1_TLS_IE_HI; - - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - return R_TILEPRO_IMM16_X0_TLS_IE_HA; - - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - return R_TILEPRO_IMM16_X1_TLS_IE_HA; - } - return r_type; -} - -static int -tilepro_elf_tls_transition (struct bfd_link_info *info, int r_type, - int is_local) -{ - if (!bfd_link_executable (info)) - return r_type; - - if (is_local) - return tilepro_tls_translate_to_le (r_type); - else - return tilepro_tls_translate_to_ie (r_type); -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -tilepro_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - struct tilepro_elf_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; - int num_relocs; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = tilepro_elf_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - sreloc = NULL; - - num_relocs = sec->reloc_count; - - BFD_ASSERT (is_tilepro_elf (abfd) || num_relocs == 0); - - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - rel_end = relocs + num_relocs; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned int r_symndx; - struct elf_link_hash_entry *h; - int tls_type; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _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 = tilepro_elf_tls_transition (info, r_type, h == NULL); - switch (r_type) - { - case R_TILEPRO_IMM16_X0_TLS_LE: - case R_TILEPRO_IMM16_X1_TLS_LE: - case R_TILEPRO_IMM16_X0_TLS_LE_LO: - case R_TILEPRO_IMM16_X1_TLS_LE_LO: - case R_TILEPRO_IMM16_X0_TLS_LE_HI: - case R_TILEPRO_IMM16_X1_TLS_LE_HI: - case R_TILEPRO_IMM16_X0_TLS_LE_HA: - case R_TILEPRO_IMM16_X1_TLS_LE_HA: - if (!bfd_link_executable (info)) - goto r_tilepro_plt32; - break; - - case R_TILEPRO_IMM16_X0_TLS_GD: - case R_TILEPRO_IMM16_X1_TLS_GD: - case R_TILEPRO_IMM16_X0_TLS_GD_LO: - case R_TILEPRO_IMM16_X1_TLS_GD_LO: - case R_TILEPRO_IMM16_X0_TLS_GD_HI: - case R_TILEPRO_IMM16_X1_TLS_GD_HI: - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - BFD_ASSERT (bfd_link_pic (info)); - tls_type = GOT_TLS_GD; - goto have_got_reference; - - case R_TILEPRO_IMM16_X0_TLS_IE: - case R_TILEPRO_IMM16_X1_TLS_IE: - case R_TILEPRO_IMM16_X0_TLS_IE_LO: - case R_TILEPRO_IMM16_X1_TLS_IE_LO: - case R_TILEPRO_IMM16_X0_TLS_IE_HI: - case R_TILEPRO_IMM16_X1_TLS_IE_HI: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - tls_type = GOT_TLS_IE; - if (!bfd_link_executable (info)) - info->flags |= DF_STATIC_TLS; - goto have_got_reference; - - case R_TILEPRO_IMM16_X0_GOT: - case R_TILEPRO_IMM16_X1_GOT: - case R_TILEPRO_IMM16_X0_GOT_LO: - case R_TILEPRO_IMM16_X1_GOT_LO: - case R_TILEPRO_IMM16_X0_GOT_HI: - case R_TILEPRO_IMM16_X1_GOT_HI: - case R_TILEPRO_IMM16_X0_GOT_HA: - case R_TILEPRO_IMM16_X1_GOT_HA: - tls_type = GOT_NORMAL; - /* Fall Through */ - - have_got_reference: - /* This symbol requires a global offset table entry. */ - { - int old_tls_type; - - if (h != NULL) - { - h->got.refcount += 1; - old_tls_type = tilepro_elf_hash_entry(h)->tls_type; - } - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= (sizeof (bfd_signed_vma) + sizeof(char)); - local_got_refcounts = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - _bfd_tilepro_elf_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx] += 1; - old_tls_type = - _bfd_tilepro_elf_local_got_tls_type (abfd) [r_symndx]; - } - - /* If a TLS symbol is accessed using IE at least once, - there is no point to use dynamic model for it. */ - if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN - && (old_tls_type != GOT_TLS_GD - || tls_type != GOT_TLS_IE)) - { - if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD) - tls_type = old_tls_type; - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%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) - tilepro_elf_hash_entry (h)->tls_type = tls_type; - else - _bfd_tilepro_elf_local_got_tls_type (abfd) [r_symndx] = - tls_type; - } - } - - if (htab->elf.sgot == NULL) - { - if (!tilepro_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } - break; - - case R_TILEPRO_TLS_GD_CALL: - if (!bfd_link_executable (info)) - { - /* These are basically R_TILEPRO_JOFFLONG_X1_PLT relocs - against __tls_get_addr. */ - struct bfd_link_hash_entry *bh = NULL; - if (! _bfd_generic_link_add_one_symbol (info, abfd, - "__tls_get_addr", 0, - bfd_und_section_ptr, 0, - NULL, FALSE, FALSE, - &bh)) - return FALSE; - h = (struct elf_link_hash_entry *) bh; - } - else - break; - /* Fall through */ - - case R_TILEPRO_JOFFLONG_X1_PLT: - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - - if (h != NULL) - { - h->needs_plt = 1; - h->plt.refcount += 1; - } - break; - - case R_TILEPRO_32_PCREL: - case R_TILEPRO_16_PCREL: - case R_TILEPRO_8_PCREL: - case R_TILEPRO_IMM16_X0_PCREL: - case R_TILEPRO_IMM16_X1_PCREL: - case R_TILEPRO_IMM16_X0_LO_PCREL: - case R_TILEPRO_IMM16_X1_LO_PCREL: - case R_TILEPRO_IMM16_X0_HI_PCREL: - case R_TILEPRO_IMM16_X1_HI_PCREL: - case R_TILEPRO_IMM16_X0_HA_PCREL: - case R_TILEPRO_IMM16_X1_HA_PCREL: - if (h != NULL) - h->non_got_ref = 1; - - if (h != NULL - && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - break; - /* Fall through. */ - - case R_TILEPRO_32: - case R_TILEPRO_16: - case R_TILEPRO_8: - case R_TILEPRO_LO16: - case R_TILEPRO_HI16: - case R_TILEPRO_HA16: - case R_TILEPRO_COPY: - case R_TILEPRO_GLOB_DAT: - case R_TILEPRO_JMP_SLOT: - case R_TILEPRO_RELATIVE: - case R_TILEPRO_BROFF_X1: - case R_TILEPRO_JOFFLONG_X1: - case R_TILEPRO_IMM8_X0: - case R_TILEPRO_IMM8_Y0: - case R_TILEPRO_IMM8_X1: - case R_TILEPRO_IMM8_Y1: - case R_TILEPRO_DEST_IMM8_X1: - case R_TILEPRO_MT_IMM15_X1: - case R_TILEPRO_MF_IMM15_X1: - case R_TILEPRO_IMM16_X0: - case R_TILEPRO_IMM16_X1: - case R_TILEPRO_IMM16_X0_LO: - case R_TILEPRO_IMM16_X1_LO: - case R_TILEPRO_IMM16_X0_HI: - case R_TILEPRO_IMM16_X1_HI: - case R_TILEPRO_IMM16_X0_HA: - case R_TILEPRO_IMM16_X1_HA: - case R_TILEPRO_MMSTART_X0: - case R_TILEPRO_MMEND_X0: - case R_TILEPRO_MMSTART_X1: - case R_TILEPRO_MMEND_X1: - case R_TILEPRO_SHAMT_X0: - case R_TILEPRO_SHAMT_X1: - case R_TILEPRO_SHAMT_Y0: - case R_TILEPRO_SHAMT_Y1: - if (h != NULL) - h->non_got_ref = 1; - - r_tilepro_plt32: - if (h != NULL && !bfd_link_pic (info)) - { - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - h->plt.refcount += 1; - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). In case of a weak definition, - DEF_REGULAR may be cleared later by a strong definition in - a shared library. We account for that possibility below by - storing information in the relocs_copied field of the hash - table entry. A similar situation occurs when creating - shared libraries and symbol visibility changes render the - symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (! tilepro_elf_howto_table[r_type].pc_relative - || (h != NULL - && (! info->symbolic - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (!bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - /* When creating a shared object, we must copy these - relocs into the output file. We create a reloc - section in dynobj and make room for the reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = - &((struct tilepro_elf_link_hash_entry *) h)->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = ((struct elf_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 (tilepro_elf_howto_table[r_type].pc_relative) - p->pc_count += 1; - } - - break; - - case R_TILEPRO_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - - case R_TILEPRO_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - default: - break; - } - } - - return TRUE; -} - - -static asection * -tilepro_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - { - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_TILEPRO_GNU_VTINHERIT: - case R_TILEPRO_GNU_VTENTRY: - return NULL; - } - } - - /* FIXME: The test here, in check_relocs and in relocate_section - dealing with TLS optimization, ought to be !bfd_link_executable (info). */ - if (bfd_link_pic (info)) - { - struct bfd_link_hash_entry *bh; - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_TILEPRO_TLS_GD_CALL: - /* This reloc implicitly references __tls_get_addr. We know - another reloc will reference the same symbol as the one - on this reloc, so the real symbol and section will be - gc marked when processing the other reloc. That lets - us handle __tls_get_addr here. */ - bh = NULL; - if (! _bfd_generic_link_add_one_symbol (info, sec->owner, - "__tls_get_addr", 0, - bfd_und_section_ptr, - 0, NULL, FALSE, - FALSE, &bh)) - return NULL; - h = (struct elf_link_hash_entry *) bh; - BFD_ASSERT (h != NULL); - h->mark = 1; - if (h->is_weakalias) - weakdef (h)->mark = 1; - sym = NULL; - } - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = tilepro_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* 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 -tilepro_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct tilepro_elf_link_hash_table *htab; - asection *s, *srel; - - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - - /* Make sure we know what is going on here. */ - BFD_ASSERT (htab->elf.dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later - (although we could actually do it here). */ - 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 R_TILEPRO_JOFFLONG_X1_PLT - 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 - R_TILEPRO_JOFFLONG_X1 relocation instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - return TRUE; - } - else - h->plt.offset = (bfd_vma) -1; - - /* If this is a weak symbol, and there is a real definition, the - processor independent code will have arranged for us to see the - real definition first, and we can just use the same value. */ - if (h->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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 we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (!readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - /* We must generate a R_TILEPRO_COPY reloc to tell the dynamic linker - to copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rel.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = htab->elf.sdynrelro; - srel = htab->elf.sreldynrelro; - } - else - { - s = htab->elf.sdynbss; - srel = htab->elf.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - srel->size += TILEPRO_ELF_RELA_BYTES; - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct tilepro_elf_link_hash_table *htab; - struct tilepro_elf_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - - 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 (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) - { - asection *s = htab->elf.splt; - - /* Allocate room for the header. */ - 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 (! bfd_link_pic (info) - && !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. */ - htab->elf.sgotplt->size += GOT_ENTRY_SIZE; - - /* We also need to make an entry in the .rela.plt section. */ - htab->elf.srelplt->size += TILEPRO_ELF_RELA_BYTES; - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - /* If a TLS_IE symbol is now local to the binary, make it a TLS_LE - requiring no TLS entry. */ - if (h->got.refcount > 0 - && bfd_link_executable (info) - && h->dynindx == -1 - && tilepro_elf_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 = tilepro_elf_hash_entry(h)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->elf.sgot; - h->got.offset = s->size; - s->size += TILEPRO_BYTES_PER_WORD; - /* R_TILEPRO_IMM16_Xn_TLS_GD entries need 2 consecutive GOT slots. */ - if (tls_type == GOT_TLS_GD) - s->size += TILEPRO_BYTES_PER_WORD; - dyn = htab->elf.dynamic_sections_created; - /* R_TILEPRO_IMM16_Xn_TLS_IE_xxx needs one dynamic relocation, - R_TILEPRO_IMM16_Xn_TLS_GD_xxx needs two if local symbol and two if - global. */ - if (tls_type == GOT_TLS_GD || tls_type == GOT_TLS_IE) - htab->elf.srelgot->size += 2 * TILEPRO_ELF_RELA_BYTES; - else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h)) - htab->elf.srelgot->size += TILEPRO_ELF_RELA_BYTES; - } - else - h->got.offset = (bfd_vma) -1; - - eh = (struct tilepro_elf_link_hash_entry *) h; - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_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 - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; - - /* Make sure undefined weak symbols are output as a dynamic - symbol in PIEs. */ - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - - if (!h->non_got_ref - && ((h->def_dynamic - && !h->def_regular) - || (htab->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 * TILEPRO_ELF_RELA_BYTES; - } - - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Return true if the dynamic symbol for a given section should be - omitted when creating a shared library. */ - -static bfd_boolean -tilepro_elf_omit_section_dynsym (bfd *output_bfd, - struct bfd_link_info *info, - asection *p) -{ - /* We keep the .got section symbol so that explicit relocations - against the _GLOBAL_OFFSET_TABLE_ symbol emitted in PIC mode - can be turned into relocations against the .got symbol. */ - if (strcmp (p->name, ".got") == 0) - return FALSE; - - return _bfd_elf_link_omit_section_dynsym (output_bfd, info, p); -} - -/* Set the sizes of the dynamic sections. */ - -#define ELF32_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -static bfd_boolean -tilepro_elf_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - (void)output_bfd; - - struct tilepro_elf_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd *ibfd; - - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - dynobj = htab->elf.dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF32_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF32_DYNAMIC_INTERPRETER; - } - } - - /* Set up .got offsets for local syms, and space for local dynamic - relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - bfd_signed_vma *local_got; - bfd_signed_vma *end_local_got; - char *local_tls_type; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (! is_tilepro_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = 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 * TILEPRO_ELF_RELA_BYTES; - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - { - info->flags |= DF_TEXTREL; - - info->callbacks->minfo (_("%B: dynamic relocation in read-only section `%A'\n"), - p->sec->owner, p->sec); - } - } - } - } - - local_got = elf_local_got_refcounts (ibfd); - if (!local_got) - continue; - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - local_tls_type = _bfd_tilepro_elf_local_got_tls_type (ibfd); - s = htab->elf.sgot; - srel = htab->elf.srelgot; - for (; local_got < end_local_got; ++local_got, ++local_tls_type) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += TILEPRO_BYTES_PER_WORD; - if (*local_tls_type == GOT_TLS_GD) - s->size += TILEPRO_BYTES_PER_WORD; - if (bfd_link_pic (info) - || *local_tls_type == GOT_TLS_GD - || *local_tls_type == GOT_TLS_IE) - srel->size += TILEPRO_ELF_RELA_BYTES; - } - else - *local_got = (bfd_vma) -1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* If the .got section is more than 0x8000 bytes, we add - 0x8000 to the value of _GLOBAL_OFFSET_TABLE_, so that 16 - bit relocations have a greater chance of working. */ - if (htab->elf.sgot->size >= 0x8000 - && elf_hash_table (info)->hgot->root.u.def.value == 0) - elf_hash_table (info)->hgot->root.u.def.value = 0x8000; - } - - if (htab->elf.sgotplt) - { - struct elf_link_hash_entry *got; - got = elf_link_hash_lookup (elf_hash_table (info), - "_GLOBAL_OFFSET_TABLE_", - FALSE, FALSE, FALSE); - - /* Don't allocate .got.plt section if there are no GOT nor PLT - entries and there is no refeence to _GLOBAL_OFFSET_TABLE_. */ - if ((got == NULL - || !got->ref_regular_nonweak) - && (htab->elf.sgotplt->size - == GOTPLT_HEADER_SIZE) - && (htab->elf.splt == NULL - || htab->elf.splt->size == 0) - && (htab->elf.sgot == NULL - || (htab->elf.sgot->size - == get_elf_backend_data (output_bfd)->got_header_size))) - htab->elf.sgotplt->size = 0; - } - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->elf.splt - || s == htab->elf.sgot - || s == htab->elf.sgotplt - || s == htab->elf.sdynbss - || s == htab->elf.sdynrelro) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (strncmp (s->name, ".rela", 5) == 0) - { - if (s->size != 0) - { - /* 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. */ - 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. Zero the memory - for the benefit of .rela.plt, which has 4 unused entries - at the beginning, and we don't want garbage. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in tilepro_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->elf.srelplt->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 (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, TILEPRO_ELF_RELA_BYTES)) - 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, maybe_set_textrel, info); - - if (info->flags & DF_TEXTREL) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Return the base VMA address which should be subtracted from real addresses - when resolving @dtpoff relocation. - This is PT_TLS segment p_vaddr. */ - -static bfd_vma -dtpoff_base (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 R_TILEPRO_TLS_TPOFF32. */ - -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 (address - htab->tls_sec->vma); -} - -/* Replace the MASK bits in ADDR with those in INSN, for the next - TILEPRO_BUNDLE_SIZE_IN_BYTES bytes. */ - -static void -tilepro_replace_insn (bfd_byte *addr, const bfd_byte *mask, - const bfd_byte *insn) -{ - int i; - for (i = 0; i < TILEPRO_BUNDLE_SIZE_IN_BYTES; i++) - { - addr[i] = (addr[i] & ~mask[i]) | (insn[i] & mask[i]); - } -} - -/* Mask to extract the bits corresponding to an instruction in a - specific pipe of a bundle. */ -static const bfd_byte insn_mask_X1[] = { - 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x7f -}; - -/* Mask to extract the bits corresponding to an instruction in a - specific pipe of a bundle, minus the destination operand and the - first source operand. */ -static const bfd_byte insn_mask_X0_no_dest_no_srca[] = { - 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00 -}; - -static const bfd_byte insn_mask_X1_no_dest_no_srca[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f -}; - -static const bfd_byte insn_mask_Y0_no_dest_no_srca[] = { - 0x00, 0xf0, 0x0f, 0x78, 0x00, 0x00, 0x00, 0x00 -}; - -static const bfd_byte insn_mask_Y1_no_dest_no_srca[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x78 -}; - -/* Mask to extract the first source operand of an instruction. */ -static const bfd_byte srca_mask_X0[] = { - 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const bfd_byte srca_mask_X1[] = { - 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00 -}; - -/* Various instructions synthesized to support tls references. */ - -/* move r0, r0 in the X1 pipe, used for tls le. */ -static const bfd_byte insn_tls_le_move_X1[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x33, 0x08 -}; - -/* move r0, zero in the X0 and X1 pipe, used for tls le. */ -static const bfd_byte insn_tls_le_move_zero_X0X1[] = { - 0xc0, 0xff, 0xcf, 0x00, 0xe0, 0xff, 0x33, 0x08 -}; - -/* lw r0, r0 in the X1 pipe, used for tls ie. */ -static const bfd_byte insn_tls_ie_lw_X1[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0b, 0x40 -}; - -/* add r0, r0, tp in various pipes, used for tls ie. */ -static const bfd_byte insn_tls_ie_add_X0X1[] = { - 0x00, 0x50, 0x0f, 0x00, 0x00, 0xa8, 0x07, 0x08 -}; -static const bfd_byte insn_tls_ie_add_Y0Y1[] = { - 0x00, 0x50, 0x03, 0x08, 0x00, 0xa8, 0x01, 0x8c -}; - -/* move r0, r0 in various pipes, used for tls gd. */ -static const bfd_byte insn_tls_gd_add_X0X1[] = { - 0x00, 0xf0, 0xcf, 0x00, 0x00, 0xf8, 0x33, 0x08 -}; -static const bfd_byte insn_tls_gd_add_Y0Y1[] = { - 0x00, 0xf0, 0x0b, 0x18, 0x00, 0xf8, 0x05, 0x9c -}; - -/* Relocate an TILEPRO ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures. - - This function is responsible for adjusting the section contents as - necessary, and (if generating a relocatable output file) adjusting - the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -tilepro_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - struct tilepro_elf_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - bfd_vma got_base; - asection *sreloc; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - int num_relocs; - - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - if (elf_hash_table (info)->hgot == NULL) - got_base = 0; - else - got_base = elf_hash_table (info)->hgot->root.u.def.value; - - sreloc = elf_section_data (input_section)->sreloc; - - rel = relocs; - num_relocs = input_section->reloc_count; - relend = relocs + num_relocs; - for (; rel < relend; rel++) - { - int r_type, tls_type; - bfd_boolean is_tls_iele, is_tls_le; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - tilepro_create_func create_func; - asection *sec; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name; - bfd_vma off; - bfd_boolean is_plt = FALSE; - bfd_boolean resolved_to_zero; - bfd_boolean unresolved_reloc; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_TILEPRO_GNU_VTINHERIT - || r_type == R_TILEPRO_GNU_VTENTRY) - continue; - - if ((unsigned int)r_type >= NELEMS(tilepro_elf_howto_table)) - return _bfd_unrecognized_reloc (input_bfd, input_section, r_type); - - howto = tilepro_elf_howto_table + r_type; - - /* This is a final link. */ - r_symndx = ELF32_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 ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - if (warned) - { - /* To avoid generating warning messages about truncated - relocations, set the relocation's address to be the same as - the start of this section. */ - if (input_section->output_section != NULL) - relocation = input_section->output_section->vma; - else - relocation = 0; - } - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (r_type) - { - case R_TILEPRO_TLS_GD_CALL: - case R_TILEPRO_IMM8_X0_TLS_GD_ADD: - case R_TILEPRO_IMM8_Y0_TLS_GD_ADD: - case R_TILEPRO_IMM8_X1_TLS_GD_ADD: - case R_TILEPRO_IMM8_Y1_TLS_GD_ADD: - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = - _bfd_tilepro_elf_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - tls_type = tilepro_elf_hash_entry(h)->tls_type; - - is_tls_iele = (bfd_link_executable (info) || tls_type == GOT_TLS_IE); - is_tls_le = is_tls_iele && (bfd_link_executable (info) - && (h == NULL || h->dynindx == -1)); - - if (r_type == R_TILEPRO_TLS_GD_CALL) - { - if (is_tls_le) - { - /* GD -> LE */ - tilepro_replace_insn (contents + rel->r_offset, - insn_mask_X1, insn_tls_le_move_X1); - continue; - } - else if (is_tls_iele) - { - /* GD -> IE */ - tilepro_replace_insn (contents + rel->r_offset, - insn_mask_X1, insn_tls_ie_lw_X1); - continue; - } - - /* GD -> GD */ - h = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (info->hash, "__tls_get_addr", FALSE, - FALSE, TRUE); - BFD_ASSERT (h != NULL); - r_type = R_TILEPRO_JOFFLONG_X1_PLT; - howto = tilepro_elf_howto_table + r_type; - } - else if (r_type == R_TILEPRO_IMM16_X0_TLS_GD_HA - || r_type == R_TILEPRO_IMM16_X0_TLS_IE_HA) - { - if (is_tls_le) - tilepro_replace_insn (contents + rel->r_offset, srca_mask_X0, - insn_tls_le_move_zero_X0X1); - } - else if (r_type == R_TILEPRO_IMM16_X1_TLS_GD_HA - || r_type == R_TILEPRO_IMM16_X1_TLS_IE_HA) - { - if (is_tls_le) - tilepro_replace_insn (contents + rel->r_offset, srca_mask_X1, - insn_tls_le_move_zero_X0X1); - } - else - { - const bfd_byte *mask = NULL; - const bfd_byte *add_insn = NULL; - - switch (r_type) - { - case R_TILEPRO_IMM8_X0_TLS_GD_ADD: - add_insn = is_tls_iele ? insn_tls_ie_add_X0X1 - : insn_tls_gd_add_X0X1; - mask = insn_mask_X0_no_dest_no_srca; - break; - case R_TILEPRO_IMM8_X1_TLS_GD_ADD: - add_insn = is_tls_iele ? insn_tls_ie_add_X0X1 - : insn_tls_gd_add_X0X1; - mask = insn_mask_X1_no_dest_no_srca; - break; - case R_TILEPRO_IMM8_Y0_TLS_GD_ADD: - add_insn = is_tls_iele ? insn_tls_ie_add_Y0Y1 - : insn_tls_gd_add_Y0Y1; - mask = insn_mask_Y0_no_dest_no_srca; - break; - case R_TILEPRO_IMM8_Y1_TLS_GD_ADD: - add_insn = is_tls_iele ? insn_tls_ie_add_Y0Y1 - : insn_tls_gd_add_Y0Y1; - mask = insn_mask_Y1_no_dest_no_srca; - break; - } - - tilepro_replace_insn (contents + rel->r_offset, mask, add_insn); - - continue; - } - break; - case R_TILEPRO_TLS_IE_LOAD: - if (bfd_link_executable (info) && (h == NULL || h->dynindx == -1)) - /* IE -> LE */ - tilepro_replace_insn (contents + rel->r_offset, - insn_mask_X1_no_dest_no_srca, - insn_tls_le_move_X1); - else - /* IE -> IE */ - tilepro_replace_insn (contents + rel->r_offset, - insn_mask_X1_no_dest_no_srca, - insn_tls_ie_lw_X1); - continue; - break; - default: - break; - } - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch (r_type) - { - case R_TILEPRO_IMM16_X0_GOT: - case R_TILEPRO_IMM16_X1_GOT: - case R_TILEPRO_IMM16_X0_GOT_LO: - case R_TILEPRO_IMM16_X1_GOT_LO: - case R_TILEPRO_IMM16_X0_GOT_HI: - case R_TILEPRO_IMM16_X1_GOT_HI: - case R_TILEPRO_IMM16_X0_GOT_HA: - case R_TILEPRO_IMM16_X1_GOT_HA: - /* Relocation is to the entry for this symbol in the global - offset table. */ - if (htab->elf.sgot == NULL) - abort (); - - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - dyn = elf_hash_table (info)->dynamic_sections_created; - - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h))) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple - of 4 for 32-bit, we use the least significant bit - to record whether we have initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_32 (output_bfd, relocation, - htab->elf.sgot->contents + off); - h->got.offset |= 1; - } - } - else - unresolved_reloc = FALSE; - } - else - { - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 4 on 32-bit. - We use the least significant bit to record - whether we have already processed this entry. */ - if ((off & 1) != 0) - off &= ~1; - else - { - if (bfd_link_pic (info)) - { - asection *s; - Elf_Internal_Rela outrel; - - /* We need to generate a R_TILEPRO_RELATIVE reloc - for the dynamic linker. */ - s = htab->elf.srelgot; - BFD_ASSERT (s != NULL); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_TILEPRO_RELATIVE); - outrel.r_addend = relocation; - relocation = 0; - tilepro_elf_append_rela_32 (output_bfd, s, &outrel); - } - - bfd_put_32 (output_bfd, relocation, - htab->elf.sgot->contents + off); - local_got_offsets[r_symndx] |= 1; - } - } - relocation = off - got_base; - break; - - case R_TILEPRO_JOFFLONG_X1_PLT: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - BFD_ASSERT (h != NULL); - - if (h->plt.offset == (bfd_vma) -1 || htab->elf.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->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); - unresolved_reloc = FALSE; - break; - - case R_TILEPRO_32_PCREL: - case R_TILEPRO_16_PCREL: - case R_TILEPRO_8_PCREL: - case R_TILEPRO_IMM16_X0_PCREL: - case R_TILEPRO_IMM16_X1_PCREL: - case R_TILEPRO_IMM16_X0_LO_PCREL: - case R_TILEPRO_IMM16_X1_LO_PCREL: - case R_TILEPRO_IMM16_X0_HI_PCREL: - case R_TILEPRO_IMM16_X1_HI_PCREL: - case R_TILEPRO_IMM16_X0_HA_PCREL: - case R_TILEPRO_IMM16_X1_HA_PCREL: - if (h != NULL - && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) - break; - /* Fall through. */ - case R_TILEPRO_32: - case R_TILEPRO_16: - case R_TILEPRO_8: - case R_TILEPRO_LO16: - case R_TILEPRO_HI16: - case R_TILEPRO_HA16: - case R_TILEPRO_COPY: - case R_TILEPRO_GLOB_DAT: - case R_TILEPRO_JMP_SLOT: - case R_TILEPRO_RELATIVE: - case R_TILEPRO_BROFF_X1: - case R_TILEPRO_JOFFLONG_X1: - case R_TILEPRO_IMM8_X0: - case R_TILEPRO_IMM8_Y0: - case R_TILEPRO_IMM8_X1: - case R_TILEPRO_IMM8_Y1: - case R_TILEPRO_DEST_IMM8_X1: - case R_TILEPRO_MT_IMM15_X1: - case R_TILEPRO_MF_IMM15_X1: - case R_TILEPRO_IMM16_X0: - case R_TILEPRO_IMM16_X1: - case R_TILEPRO_IMM16_X0_LO: - case R_TILEPRO_IMM16_X1_LO: - case R_TILEPRO_IMM16_X0_HI: - case R_TILEPRO_IMM16_X1_HI: - case R_TILEPRO_IMM16_X0_HA: - case R_TILEPRO_IMM16_X1_HA: - case R_TILEPRO_MMSTART_X0: - case R_TILEPRO_MMEND_X0: - case R_TILEPRO_MMSTART_X1: - case R_TILEPRO_MMEND_X1: - case R_TILEPRO_SHAMT_X0: - case R_TILEPRO_SHAMT_X1: - case R_TILEPRO_SHAMT_Y0: - case R_TILEPRO_SHAMT_Y1: - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - if ((bfd_link_pic (info) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && (! howto->pc_relative - || !SYMBOL_CALLS_LOCAL (info, h))) - || (!bfd_link_pic (info) - && 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_boolean skip, relocate = FALSE; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - BFD_ASSERT (sreloc != NULL); - - skip = FALSE; - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - switch (r_type) - { - case R_TILEPRO_32_PCREL: - case R_TILEPRO_16_PCREL: - case R_TILEPRO_8_PCREL: - /* If the symbol is not dynamic, we should not keep - a dynamic relocation. But an .rela.* slot has been - allocated for it, output R_TILEPRO_NONE. - FIXME: Add code tracking needed dynamic relocs as - e.g. i386 has. */ - if (h->dynindx == -1) - skip = TRUE, relocate = TRUE; - break; - } - - if (skip) - memset (&outrel, 0, sizeof outrel); - /* h->dynindx may be -1 if the symbol was marked to - become local. */ - else if (h != NULL && - h->dynindx != -1 - && (! is_plt - || !bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !h->def_regular)) - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - if (r_type == R_TILEPRO_32) - { - outrel.r_info = ELF32_R_INFO (0, R_TILEPRO_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - long indx; - - outrel.r_addend = relocation + rel->r_addend; - - if (is_plt) - sec = htab->elf.splt; - - if (bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. */ - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - - if (indx == 0) - { - osec = htab->elf.text_index_section; - indx = elf_section_data (osec)->dynindx; - } - - /* FIXME: we really should be able to link non-pic - shared libraries. */ - if (indx == 0) - { - BFD_FAIL (); - _bfd_error_handler - (_("%B: probably compiled without -fPIC?"), - input_bfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - } - } - - tilepro_elf_append_rela_32 (output_bfd, sreloc, &outrel); - - /* This reloc will be computed at runtime, so there's no - need to do anything now. */ - if (! relocate) - continue; - } - break; - - case R_TILEPRO_IMM16_X0_TLS_LE: - case R_TILEPRO_IMM16_X1_TLS_LE: - case R_TILEPRO_IMM16_X0_TLS_LE_LO: - case R_TILEPRO_IMM16_X1_TLS_LE_LO: - case R_TILEPRO_IMM16_X0_TLS_LE_HI: - case R_TILEPRO_IMM16_X1_TLS_LE_HI: - case R_TILEPRO_IMM16_X0_TLS_LE_HA: - case R_TILEPRO_IMM16_X1_TLS_LE_HA: - if (!bfd_link_executable (info)) - { - Elf_Internal_Rela outrel; - bfd_boolean skip; - - BFD_ASSERT (sreloc != NULL); - skip = FALSE; - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE; - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - if (skip) - memset (&outrel, 0, sizeof outrel); - else - { - outrel.r_info = ELF32_R_INFO (0, r_type); - outrel.r_addend = relocation - dtpoff_base (info) - + rel->r_addend; - } - - tilepro_elf_append_rela_32 (output_bfd, sreloc, &outrel); - continue; - } - relocation = tpoff (info, relocation); - break; - - case R_TILEPRO_IMM16_X0_TLS_GD: - case R_TILEPRO_IMM16_X1_TLS_GD: - case R_TILEPRO_IMM16_X0_TLS_GD_LO: - case R_TILEPRO_IMM16_X1_TLS_GD_LO: - case R_TILEPRO_IMM16_X0_TLS_GD_HI: - case R_TILEPRO_IMM16_X1_TLS_GD_HI: - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - case R_TILEPRO_IMM16_X0_TLS_IE: - case R_TILEPRO_IMM16_X1_TLS_IE: - case R_TILEPRO_IMM16_X0_TLS_IE_LO: - case R_TILEPRO_IMM16_X1_TLS_IE_LO: - case R_TILEPRO_IMM16_X0_TLS_IE_HI: - case R_TILEPRO_IMM16_X1_TLS_IE_HI: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - r_type = tilepro_elf_tls_transition (info, r_type, h == NULL); - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type - = _bfd_tilepro_elf_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - { - tls_type = tilepro_elf_hash_entry(h)->tls_type; - if (bfd_link_executable (info) - && h->dynindx == -1 - && tls_type == GOT_TLS_IE) - r_type = tilepro_tls_translate_to_le (r_type); - } - if (tls_type == GOT_TLS_IE) - r_type = tilepro_tls_translate_to_ie (r_type); - - if (r_type == R_TILEPRO_IMM16_X0_TLS_LE - || r_type == R_TILEPRO_IMM16_X1_TLS_LE - || r_type == R_TILEPRO_IMM16_X0_TLS_LE_LO - || r_type == R_TILEPRO_IMM16_X1_TLS_LE_LO - || r_type == R_TILEPRO_IMM16_X0_TLS_LE_HI - || r_type == R_TILEPRO_IMM16_X1_TLS_LE_HI - || r_type == R_TILEPRO_IMM16_X0_TLS_LE_HA - || r_type == R_TILEPRO_IMM16_X1_TLS_LE_HA) - { - relocation = tpoff (info, relocation); - break; - } - - if (h != NULL) - { - off = h->got.offset; - h->got.offset |= 1; - } - else - { - BFD_ASSERT (local_got_offsets != NULL); - off = local_got_offsets[r_symndx]; - local_got_offsets[r_symndx] |= 1; - } - - if (htab->elf.sgot == NULL) - abort (); - - if ((off & 1) != 0) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - int indx = 0; - bfd_boolean need_relocs = FALSE; - - if (htab->elf.srelgot == NULL) - abort (); - - if (h != NULL) - { - bfd_boolean dyn; - dyn = htab->elf.dynamic_sections_created; - - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - && (!bfd_link_pic (info) - || !SYMBOL_REFERENCES_LOCAL (info, h))) - { - indx = h->dynindx; - } - } - - /* The GOT entries have not been initialized yet. Do it - now, and emit any relocations. */ - if ((bfd_link_pic (info) || indx != 0) - && (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - need_relocs = TRUE; - - switch (r_type) - { - case R_TILEPRO_IMM16_X0_TLS_IE: - case R_TILEPRO_IMM16_X1_TLS_IE: - case R_TILEPRO_IMM16_X0_TLS_IE_LO: - case R_TILEPRO_IMM16_X1_TLS_IE_LO: - case R_TILEPRO_IMM16_X0_TLS_IE_HI: - case R_TILEPRO_IMM16_X1_TLS_IE_HI: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - if (need_relocs) { - bfd_put_32 (output_bfd, 0, htab->elf.sgot->contents + off); - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - outrel.r_addend = 0; - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - outrel.r_info = ELF32_R_INFO (indx, R_TILEPRO_TLS_TPOFF32); - tilepro_elf_append_rela_32 (output_bfd, htab->elf.srelgot, - &outrel); - } else { - bfd_put_32 (output_bfd, tpoff (info, relocation), - htab->elf.sgot->contents + off); - } - break; - - case R_TILEPRO_IMM16_X0_TLS_GD: - case R_TILEPRO_IMM16_X1_TLS_GD: - case R_TILEPRO_IMM16_X0_TLS_GD_LO: - case R_TILEPRO_IMM16_X1_TLS_GD_LO: - case R_TILEPRO_IMM16_X0_TLS_GD_HI: - case R_TILEPRO_IMM16_X1_TLS_GD_HI: - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - if (need_relocs) { - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - outrel.r_addend = 0; - outrel.r_info = ELF32_R_INFO (indx, R_TILEPRO_TLS_DTPMOD32); - bfd_put_32 (output_bfd, 0, htab->elf.sgot->contents + off); - tilepro_elf_append_rela_32 (output_bfd, htab->elf.srelgot, - &outrel); - if (indx == 0) - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_32 (output_bfd, - relocation - dtpoff_base (info), - (htab->elf.sgot->contents + off + - TILEPRO_BYTES_PER_WORD)); - } - else - { - bfd_put_32 (output_bfd, 0, - (htab->elf.sgot->contents + off + - TILEPRO_BYTES_PER_WORD)); - outrel.r_info = ELF32_R_INFO (indx, - R_TILEPRO_TLS_DTPOFF32); - outrel.r_offset += TILEPRO_BYTES_PER_WORD; - tilepro_elf_append_rela_32 (output_bfd, - htab->elf.srelgot, &outrel); - } - } - - else { - /* If we are not emitting relocations for a - general dynamic reference, then we must be in a - static link or an executable link with the - symbol binding locally. Mark it as belonging - to module 1, the executable. */ - bfd_put_32 (output_bfd, 1, - htab->elf.sgot->contents + off ); - bfd_put_32 (output_bfd, relocation - dtpoff_base (info), - htab->elf.sgot->contents + off + - TILEPRO_BYTES_PER_WORD); - } - break; - } - } - - if (off >= (bfd_vma) -2) - abort (); - - relocation = off - got_base; - unresolved_reloc = FALSE; - howto = tilepro_elf_howto_table + r_type; - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - - r = bfd_reloc_continue; - - /* For the _HA types, we add 0x8000 so that if bit 15 is set, - * we will increment bit 16. The howto->rightshift takes care - * of the rest for us. */ - switch (r_type) - { - case R_TILEPRO_HA16: - case R_TILEPRO_IMM16_X0_HA: - case R_TILEPRO_IMM16_X1_HA: - case R_TILEPRO_IMM16_X0_HA_PCREL: - case R_TILEPRO_IMM16_X1_HA_PCREL: - case R_TILEPRO_IMM16_X0_GOT_HA: - case R_TILEPRO_IMM16_X1_GOT_HA: - case R_TILEPRO_IMM16_X0_TLS_GD_HA: - case R_TILEPRO_IMM16_X1_TLS_GD_HA: - case R_TILEPRO_IMM16_X0_TLS_IE_HA: - case R_TILEPRO_IMM16_X1_TLS_IE_HA: - relocation += 0x8000; - break; - } - - /* Get the operand creation function, if any. */ - create_func = reloc_to_create_func[r_type]; - if (create_func == NULL) - { - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - } - else - { - if (howto->pc_relative) - { - relocation -= - input_section->output_section->vma + input_section->output_offset; - if (howto->pcrel_offset) - relocation -= rel->r_offset; - } - - bfd_byte *data; - - /* Add the relocation addend if any to the final target value */ - relocation += rel->r_addend; - - /* Do basic range checking */ - r = bfd_check_overflow (howto->complain_on_overflow, - howto->bitsize, - howto->rightshift, - 32, - relocation); - - /* - * Write the relocated value out into the raw section data. - * Don't put a relocation out in the .rela section. - */ - tilepro_bundle_bits mask = create_func(-1); - tilepro_bundle_bits value = create_func(relocation >> howto->rightshift); - - /* Only touch bytes while the mask is not 0, so we - don't write to out of bounds memory if this is actually - a 16-bit switch instruction. */ - for (data = contents + rel->r_offset; mask != 0; data++) - { - bfd_byte byte_mask = (bfd_byte)mask; - *data = (*data & ~byte_mask) | ((bfd_byte)value & byte_mask); - mask >>= 8; - value >>= 8; - } - } - - if (r != bfd_reloc_ok) - { - const char *msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -tilepro_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct tilepro_elf_link_hash_table *htab; - - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *srela; - asection *sgotplt; - Elf_Internal_Rela rela; - bfd_byte *loc; - bfd_vma r_offset; - - int rela_index; - - /* This symbol has an entry in the PLT. Set it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->elf.splt; - srela = htab->elf.srelplt; - sgotplt = htab->elf.sgotplt; - - if (splt == NULL || srela == NULL) - abort (); - - /* Fill in the entry in the procedure linkage table. */ - rela_index = tilepro_plt_entry_build (splt, sgotplt, h->plt.offset, - &r_offset); - - /* Fill in the entry in the global offset table, which initially points - to the beginning of the plt. */ - bfd_put_32 (output_bfd, splt->output_section->vma + splt->output_offset, - sgotplt->contents + r_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset - + r_offset); - rela.r_addend = 0; - rela.r_info = ELF32_R_INFO (h->dynindx, R_TILEPRO_JMP_SLOT); - - loc = srela->contents + rela_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - /* If the symbol is weak, we do need to clear the value. - Otherwise, the PLT entry would provide a definition for - the symbol even if the symbol wasn't defined anywhere, - and so the symbol would never be NULL. */ - if (!h->ref_regular_nonweak) - sym->st_value = 0; - } - } - - if (h->got.offset != (bfd_vma) -1 - && tilepro_elf_hash_entry(h)->tls_type != GOT_TLS_GD - && tilepro_elf_hash_entry(h)->tls_type != GOT_TLS_IE) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - - /* This symbol has an entry in the GOT. Set it up. */ - - sgot = htab->elf.sgot; - srela = htab->elf.srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset &~ (bfd_vma) 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic || h->dynindx == -1) - && h->def_regular) - { - asection *sec = h->root.u.def.section; - rela.r_info = ELF32_R_INFO (0, R_TILEPRO_RELATIVE); - rela.r_addend = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } - else - { - rela.r_info = ELF32_R_INFO (h->dynindx, R_TILEPRO_GLOB_DAT); - rela.r_addend = 0; - } - - bfd_put_32 (output_bfd, 0, - sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - tilepro_elf_append_rela_32 (output_bfd, srela, &rela); - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - - /* This symbols needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_TILEPRO_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - tilepro_elf_append_rela_32 (output_bfd, s, &rela); - } - - /* Mark some specially defined symbols as absolute. */ - if (h == htab->elf.hdynamic - || (h == htab->elf.hgot || h == htab->elf.hplt)) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -tilepro_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, - bfd *dynobj, asection *sdyn, - asection *splt ATTRIBUTE_UNUSED) -{ - Elf32_External_Dyn *dyncon, *dynconend; - struct tilepro_elf_link_hash_table *htab; - - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_PLTGOT: - s = htab->elf.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - case DT_JMPREL: - s = htab->elf.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - case DT_PLTRELSZ: - s = htab->elf.srelplt; - dyn.d_un.d_val = s->size; - break; - default: - continue; - } - - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - return TRUE; -} - -static bfd_boolean -tilepro_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - struct tilepro_elf_link_hash_table *htab; - - htab = tilepro_elf_hash_table (info); - BFD_ASSERT (htab != NULL); - dynobj = htab->elf.dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - bfd_boolean ret; - - splt = htab->elf.splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - ret = tilepro_finish_dyn (output_bfd, info, dynobj, sdyn, splt); - - if (!ret) - return ret; - - /* Fill in the first entry in the procedure linkage table. */ - if (splt->size > 0) - { - memcpy (splt->contents, tilepro_plt0_entry, PLT_HEADER_SIZE); - memset (splt->contents + PLT_HEADER_SIZE, 0, - PLT_ENTRY_SIZE - PLT_HEADER_SIZE); - } - - if (elf_section_data (splt->output_section) != NULL) - elf_section_data (splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; - } - - if (htab->elf.sgotplt) - { - if (bfd_is_abs_section (htab->elf.sgotplt->output_section)) - { - _bfd_error_handler - (_("discarded output section: `%A'"), htab->elf.sgotplt); - return FALSE; - } - - if (htab->elf.sgotplt->size > 0) - { - /* Write the first two entries in .got.plt, needed for the dynamic - linker. */ - bfd_put_32 (output_bfd, (bfd_vma) -1, - htab->elf.sgotplt->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, - htab->elf.sgotplt->contents + GOT_ENTRY_SIZE); - } - - elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize - = GOT_ENTRY_SIZE; - } - - if (htab->elf.sgot) - { - if (htab->elf.sgot->size > 0) - { - /* Set the first entry in the global offset table to the address of - the dynamic section. */ - bfd_vma val = (sdyn ? - sdyn->output_section->vma + sdyn->output_offset : - 0); - bfd_put_32 (output_bfd, val, htab->elf.sgot->contents); - } - - elf_section_data (htab->elf.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 -tilepro_elf_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + (i + 1) * PLT_ENTRY_SIZE; -} - -static enum elf_reloc_type_class -tilepro_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_TILEPRO_RELATIVE: - return reloc_class_relative; - case R_TILEPRO_JMP_SLOT: - return reloc_class_plt; - case R_TILEPRO_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -static int -tilepro_additional_program_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - /* Each .intrpt section specified by the user adds another PT_LOAD - header since the sections are discontiguous. */ - static const char intrpt_sections[4][9] = - { - ".intrpt0", ".intrpt1", ".intrpt2", ".intrpt3" - }; - int count = 0; - int i; - - for (i = 0; i < 4; i++) - { - asection *sec = bfd_get_section_by_name (abfd, intrpt_sections[i]); - if (sec != NULL && (sec->flags & SEC_LOAD) != 0) - ++count; - } - - /* Add four "padding" headers in to leave room in case a custom linker - script does something fancy. Otherwise ld complains that it ran - out of program headers and refuses to link. */ - count += 4; - - return count; -} - -#define ELF_ARCH bfd_arch_tilepro -#define ELF_TARGET_ID TILEPRO_ELF_DATA -#define ELF_MACHINE_CODE EM_TILEPRO -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x10000 - -#define TARGET_LITTLE_SYM tilepro_elf32_vec -#define TARGET_LITTLE_NAME "elf32-tilepro" - -#define elf_backend_reloc_type_class tilepro_reloc_type_class - -#define bfd_elf32_bfd_reloc_name_lookup tilepro_reloc_name_lookup -#define bfd_elf32_bfd_link_hash_table_create tilepro_elf_link_hash_table_create -#define bfd_elf32_bfd_reloc_type_lookup tilepro_reloc_type_lookup - -#define elf_backend_copy_indirect_symbol tilepro_elf_copy_indirect_symbol -#define elf_backend_create_dynamic_sections tilepro_elf_create_dynamic_sections -#define elf_backend_check_relocs tilepro_elf_check_relocs -#define elf_backend_adjust_dynamic_symbol tilepro_elf_adjust_dynamic_symbol -#define elf_backend_omit_section_dynsym tilepro_elf_omit_section_dynsym -#define elf_backend_size_dynamic_sections tilepro_elf_size_dynamic_sections -#define elf_backend_relocate_section tilepro_elf_relocate_section -#define elf_backend_finish_dynamic_symbol tilepro_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections tilepro_elf_finish_dynamic_sections -#define elf_backend_gc_mark_hook tilepro_elf_gc_mark_hook -#define elf_backend_plt_sym_val tilepro_elf_plt_sym_val -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto tilepro_info_to_howto_rela -#define elf_backend_grok_prstatus tilepro_elf_grok_prstatus -#define elf_backend_grok_psinfo tilepro_elf_grok_psinfo -#define elf_backend_additional_program_headers tilepro_additional_program_headers - -#define bfd_elf32_mkobject tilepro_elf_mkobject - -#define elf_backend_init_index_section _bfd_elf_init_1_index_section - -#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 -/* Align PLT mod 64 byte L2 line size. */ -#define elf_backend_plt_alignment 6 -#define elf_backend_want_plt_sym 1 -#define elf_backend_got_header_size GOT_ENTRY_SIZE -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_default_execstack 0 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-tilepro.h b/sdcc/support/sdbinutils/bfd/elf32-tilepro.h deleted file mode 100644 index 8cd6966fb..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-tilepro.h +++ /dev/null @@ -1,38 +0,0 @@ -/* TILEPro-specific support for 32-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_TILEPRO_H -#define _ELF32_TILEPRO_H - -/* This file contains sizes and offsets of Linux data structures. */ - -#define TILEPRO_PRSTATUS_SIZEOF 332 -#define TILEPRO_PRSTATUS_OFFSET_PR_CURSIG 12 -#define TILEPRO_PRSTATUS_OFFSET_PR_PID 24 -#define TILEPRO_PRSTATUS_OFFSET_PR_REG 72 - -#define TILEPRO_PRPSINFO_SIZEOF 128 -#define TILEPRO_PRPSINFO_OFFSET_PR_FNAME 32 -#define TILEPRO_PRPSINFO_OFFSET_PR_PSARGS 48 -#define ELF_PR_PSARGS_SIZE 80 - -#define TILEPRO_GREGSET_T_SIZE 256 - -#endif /* _ELF32_TILEPRO_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-v850.c b/sdcc/support/sdbinutils/bfd/elf32-v850.c deleted file mode 100644 index 99c060afc..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-v850.c +++ /dev/null @@ -1,4287 +0,0 @@ -/* V850-specific support for 32-bit ELF - Copyright (C) 1996-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* XXX FIXME: This code is littered with 32bit int, 16bit short, 8bit char - dependencies. As is the gas & simulator code for the v850. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/v850.h" -#include "libiberty.h" - -/* Sign-extend a 17-bit number. */ -#define SEXT17(x) ((((x) & 0x1ffff) ^ 0x10000) - 0x10000) - -/* Sign-extend a 22-bit number. */ -#define SEXT22(x) ((((x) & 0x3fffff) ^ 0x200000) - 0x200000) - -static reloc_howto_type v850_elf_howto_table[]; - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -v850_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd_boolean ret = TRUE; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - unsigned int r_type; - int other = 0; - const char *common = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - -#ifdef DEBUG - _bfd_error_handler ("v850_elf_check_relocs called for section %A in %B", - sec, abfd); -#endif - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - r_type = ELF32_R_TYPE (rel->r_info); - switch (r_type) - { - default: - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_V850_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_V850_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_V850_SDA_16_16_SPLIT_OFFSET: - case R_V850_SDA_16_16_OFFSET: - case R_V850_SDA_15_16_OFFSET: - case R_V810_GPWLO_1: - case R_V850_HWLO: - case R_V850_HWLO_1: - other = V850_OTHER_SDA; - common = ".scommon"; - goto small_data_common; - - case R_V850_ZDA_16_16_SPLIT_OFFSET: - case R_V850_ZDA_16_16_OFFSET: - case R_V850_ZDA_15_16_OFFSET: - other = V850_OTHER_ZDA; - common = ".zcommon"; - goto small_data_common; - - case R_V850_TDA_4_4_OFFSET: - case R_V850_TDA_4_5_OFFSET: - case R_V850_TDA_7_7_OFFSET: - case R_V850_TDA_6_8_OFFSET: - case R_V850_TDA_7_8_OFFSET: - case R_V850_TDA_16_16_OFFSET: - other = V850_OTHER_TDA; - common = ".tcommon"; - /* fall through */ - -#define V850_OTHER_MASK (V850_OTHER_TDA | V850_OTHER_SDA | V850_OTHER_ZDA) - - small_data_common: - if (h) - { - /* Flag which type of relocation was used. */ - h->other |= other; - if ((h->other & V850_OTHER_MASK) != (other & V850_OTHER_MASK) - && (h->other & V850_OTHER_ERROR) == 0) - { - const char * msg; - static char buff[200]; /* XXX */ - - switch (h->other & V850_OTHER_MASK) - { - default: - msg = _("Variable `%s' cannot occupy in multiple small data regions"); - break; - case V850_OTHER_SDA | V850_OTHER_ZDA | V850_OTHER_TDA: - msg = _("Variable `%s' can only be in one of the small, zero, and tiny data regions"); - break; - case V850_OTHER_SDA | V850_OTHER_ZDA: - msg = _("Variable `%s' cannot be in both small and zero data regions simultaneously"); - break; - case V850_OTHER_SDA | V850_OTHER_TDA: - msg = _("Variable `%s' cannot be in both small and tiny data regions simultaneously"); - break; - case V850_OTHER_ZDA | V850_OTHER_TDA: - msg = _("Variable `%s' cannot be in both zero and tiny data regions simultaneously"); - break; - } - - sprintf (buff, msg, h->root.root.string); - info->callbacks->warning (info, buff, h->root.root.string, - abfd, h->root.u.def.section, - (bfd_vma) 0); - - bfd_set_error (bfd_error_bad_value); - h->other |= V850_OTHER_ERROR; - ret = FALSE; - } - } - - if (h && h->root.type == bfd_link_hash_common - && h->root.u.c.p - && !strcmp (bfd_get_section_name (abfd, h->root.u.c.p->section), "COMMON")) - { - asection * section; - - section = h->root.u.c.p->section = bfd_make_section_old_way (abfd, common); - section->flags |= SEC_IS_COMMON; - } - -#ifdef DEBUG - fprintf (stderr, "v850_elf_check_relocs, found %s relocation for %s%s\n", - v850_elf_howto_table[ (int)r_type ].name, - (h && h->root.root.string) ? h->root.root.string : "", - (h->root.type == bfd_link_hash_common) ? ", symbol is common" : ""); -#endif - break; - } - } - - return ret; -} - -/* In the old version, when an entry was checked out from the table, - it was deleted. This produced an error if the entry was needed - more than once, as the second attempted retry failed. - - In the current version, the entry is not deleted, instead we set - the field 'found' to TRUE. If a second lookup matches the same - entry, then we know that the hi16s reloc has already been updated - and does not need to be updated a second time. - - TODO - TOFIX: If it is possible that we need to restore 2 different - addresses from the same table entry, where the first generates an - overflow, whilst the second do not, then this code will fail. */ - -typedef struct hi16s_location -{ - bfd_vma addend; - bfd_byte * address; - unsigned long counter; - bfd_boolean found; - struct hi16s_location * next; -} -hi16s_location; - -static hi16s_location * previous_hi16s; -static hi16s_location * free_hi16s; -static unsigned long hi16s_counter; - -static void -remember_hi16s_reloc (bfd *abfd, bfd_vma addend, bfd_byte *address) -{ - hi16s_location * entry = NULL; - bfd_size_type amt = sizeof (* free_hi16s); - - /* Find a free structure. */ - if (free_hi16s == NULL) - free_hi16s = bfd_zalloc (abfd, amt); - - entry = free_hi16s; - free_hi16s = free_hi16s->next; - - entry->addend = addend; - entry->address = address; - entry->counter = hi16s_counter ++; - entry->found = FALSE; - entry->next = previous_hi16s; - previous_hi16s = entry; - - /* Cope with wrap around of our counter. */ - if (hi16s_counter == 0) - { - /* XXX: Assume that all counter entries differ only in their low 16 bits. */ - for (entry = previous_hi16s; entry != NULL; entry = entry->next) - entry->counter &= 0xffff; - - hi16s_counter = 0x10000; - } -} - -static bfd_byte * -find_remembered_hi16s_reloc (bfd_vma addend, bfd_boolean *already_found) -{ - hi16s_location *match = NULL; - hi16s_location *entry; - bfd_byte *addr; - - /* Search the table. Record the most recent entry that matches. */ - for (entry = previous_hi16s; entry; entry = entry->next) - { - if (entry->addend == addend - && (match == NULL || match->counter < entry->counter)) - { - match = entry; - } - } - - if (match == NULL) - return NULL; - - /* Extract the address. */ - addr = match->address; - - /* Remember if this entry has already been used before. */ - if (already_found) - * already_found = match->found; - - /* Note that this entry has now been used. */ - match->found = TRUE; - - return addr; -} - -/* Calculate the final operand value for a R_V850_LO16 or - R_V850_LO16_SPLIT_OFFSET. *INSN is the current operand value and - ADDEND is the sum of the relocation symbol and offset. Store the - operand value in *INSN and return true on success. - - The assembler has already done some of this: If the value stored in - the instruction has its 15th bit set, (counting from zero) then the - assembler will have added 1 to the value stored in the associated - HI16S reloc. So for example, these relocations: - - movhi hi( fred ), r0, r1 - movea lo( fred ), r1, r1 - - will store 0 in the value fields for the MOVHI and MOVEA instructions - and addend will be the address of fred, but for these instructions: - - movhi hi( fred + 0x123456 ), r0, r1 - movea lo( fred + 0x123456 ), r1, r1 - - the value stored in the MOVHI instruction will be 0x12 and the value - stored in the MOVEA instruction will be 0x3456. If however the - instructions were: - - movhi hi( fred + 0x10ffff ), r0, r1 - movea lo( fred + 0x10ffff ), r1, r1 - - then the value stored in the MOVHI instruction would be 0x11 (not - 0x10) and the value stored in the MOVEA instruction would be 0xffff. - Thus (assuming for the moment that the addend is 0), at run time the - MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction - adds 0xffffffff (sign extension!) producing 0x10ffff. Similarly if - the instructions were: - - movhi hi( fred - 1 ), r0, r1 - movea lo( fred - 1 ), r1, r1 - - then 0 is stored in the MOVHI instruction and -1 is stored in the - MOVEA instruction. - - Overflow can occur if the addition of the value stored in the - instruction plus the addend sets the 15th bit when before it was clear. - This is because the 15th bit will be sign extended into the high part, - thus reducing its value by one, but since the 15th bit was originally - clear, the assembler will not have added 1 to the previous HI16S reloc - to compensate for this effect. For example: - - movhi hi( fred + 0x123456 ), r0, r1 - movea lo( fred + 0x123456 ), r1, r1 - - The value stored in HI16S reloc is 0x12, the value stored in the LO16 - reloc is 0x3456. If we assume that the address of fred is 0x00007000 - then the relocations become: - - HI16S: 0x0012 + (0x00007000 >> 16) = 0x12 - LO16: 0x3456 + (0x00007000 & 0xffff) = 0xa456 - - but when the instructions are executed, the MOVEA instruction's value - is signed extended, so the sum becomes: - - 0x00120000 - + 0xffffa456 - ------------ - 0x0011a456 but 'fred + 0x123456' = 0x0012a456 - - Note that if the 15th bit was set in the value stored in the LO16 - reloc, then we do not have to do anything: - - movhi hi( fred + 0x10ffff ), r0, r1 - movea lo( fred + 0x10ffff ), r1, r1 - - HI16S: 0x0011 + (0x00007000 >> 16) = 0x11 - LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff - - 0x00110000 - + 0x00006fff - ------------ - 0x00116fff = fred + 0x10ffff = 0x7000 + 0x10ffff - - Overflow can also occur if the computation carries into the 16th bit - and it also results in the 15th bit having the same value as the 15th - bit of the original value. What happens is that the HI16S reloc - will have already examined the 15th bit of the original value and - added 1 to the high part if the bit is set. This compensates for the - sign extension of 15th bit of the result of the computation. But now - there is a carry into the 16th bit, and this has not been allowed for. - - So, for example if fred is at address 0xf000: - - movhi hi( fred + 0xffff ), r0, r1 [bit 15 of the offset is set] - movea lo( fred + 0xffff ), r1, r1 - - HI16S: 0x0001 + (0x0000f000 >> 16) = 0x0001 - LO16: 0xffff + (0x0000f000 & 0xffff) = 0xefff (carry into bit 16 is lost) - - 0x00010000 - + 0xffffefff - ------------ - 0x0000efff but 'fred + 0xffff' = 0x0001efff - - Similarly, if the 15th bit remains clear, but overflow occurs into - the 16th bit then (assuming the address of fred is 0xf000): - - movhi hi( fred + 0x7000 ), r0, r1 [bit 15 of the offset is clear] - movea lo( fred + 0x7000 ), r1, r1 - - HI16S: 0x0000 + (0x0000f000 >> 16) = 0x0000 - LO16: 0x7000 + (0x0000f000 & 0xffff) = 0x6fff (carry into bit 16 is lost) - - 0x00000000 - + 0x00006fff - ------------ - 0x00006fff but 'fred + 0x7000' = 0x00016fff - - Note - there is no need to change anything if a carry occurs, and the - 15th bit changes its value from being set to being clear, as the HI16S - reloc will have already added in 1 to the high part for us: - - movhi hi( fred + 0xffff ), r0, r1 [bit 15 of the offset is set] - movea lo( fred + 0xffff ), r1, r1 - - HI16S: 0x0001 + (0x00007000 >> 16) - LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff (carry into bit 16 is lost) - - 0x00010000 - + 0x00006fff (bit 15 not set, so the top half is zero) - ------------ - 0x00016fff which is right (assuming that fred is at 0x7000) - - but if the 15th bit goes from being clear to being set, then we must - once again handle overflow: - - movhi hi( fred + 0x7000 ), r0, r1 [bit 15 of the offset is clear] - movea lo( fred + 0x7000 ), r1, r1 - - HI16S: 0x0000 + (0x0000ffff >> 16) - LO16: 0x7000 + (0x0000ffff & 0xffff) = 0x6fff (carry into bit 16) - - 0x00000000 - + 0x00006fff (bit 15 not set, so the top half is zero) - ------------ - 0x00006fff which is wrong (assuming that fred is at 0xffff). */ - -static bfd_boolean -v850_elf_perform_lo16_relocation (bfd *abfd, unsigned long *insn, - unsigned long addend) -{ -#define BIT15_SET(x) ((x) & 0x8000) -#define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff) - - if ((BIT15_SET (*insn + addend) && ! BIT15_SET (addend)) - || (OVERFLOWS (addend, *insn) - && ((! BIT15_SET (*insn)) || (BIT15_SET (addend))))) - { - bfd_boolean already_updated; - bfd_byte *hi16s_address = find_remembered_hi16s_reloc - (addend, & already_updated); - - /* Amend the matching HI16_S relocation. */ - if (hi16s_address != NULL) - { - if (! already_updated) - { - unsigned long hi_insn = bfd_get_16 (abfd, hi16s_address); - hi_insn += 1; - bfd_put_16 (abfd, hi_insn, hi16s_address); - } - } - else - { - _bfd_error_handler (_("FAILED to find previous HI16 reloc")); - return FALSE; - } - } -#undef OVERFLOWS -#undef BIT15_SET - - /* Do not complain if value has top bit set, as this has been - anticipated. */ - *insn = (*insn + addend) & 0xffff; - return TRUE; -} - -/* FIXME: The code here probably ought to be removed and the code in reloc.c - allowed to do its stuff instead. At least for most of the relocs, anyway. */ - -static bfd_reloc_status_type -v850_elf_perform_relocation (bfd *abfd, - unsigned int r_type, - bfd_vma addend, - bfd_byte *address) -{ - unsigned long insn; - unsigned long result; - bfd_signed_vma saddend = (bfd_signed_vma) addend; - - switch (r_type) - { - default: -#ifdef DEBUG - fprintf (stderr, "%B: reloc number %d not recognised\n", abfd, r_type); -#endif - return bfd_reloc_notsupported; - - case R_V850_REL32: - case R_V850_ABS32: - case R_V810_WORD: - case R_V850_PC32: - bfd_put_32 (abfd, addend, address); - return bfd_reloc_ok; - - case R_V850_WLO23: - case R_V850_23: - insn = bfd_get_32 (abfd, address); - insn &= ~((0x7f << 4) | (0x7fff80 << (16-7))); - insn |= ((addend & 0x7f) << 4) | ((addend & 0x7fff80) << (16-7)); - bfd_put_32 (abfd, (bfd_vma) insn, address); - return bfd_reloc_ok; - - case R_V850_PCR22: - case R_V850_22_PCREL: - if (saddend > 0x1fffff || saddend < -0x200000) - return bfd_reloc_overflow; - - if ((addend % 2) != 0) - return bfd_reloc_dangerous; - - insn = bfd_get_32 (abfd, address); - insn &= ~0xfffe003f; - insn |= (((addend & 0xfffe) << 16) | ((addend & 0x3f0000) >> 16)); - bfd_put_32 (abfd, (bfd_vma) insn, address); - return bfd_reloc_ok; - - case R_V850_PC17: - case R_V850_17_PCREL: - if (saddend > 0xffff || saddend < -0x10000) - return bfd_reloc_overflow; - - if ((addend % 2) != 0) - return bfd_reloc_dangerous; - - insn = bfd_get_32 (abfd, address); - insn &= ~ 0xfffe0010; - insn |= ((addend & 0xfffe) << 16) | ((addend & 0x10000) >> (16-4)); - break; - - case R_V850_PC16U: - case R_V850_16_PCREL: - if ((saddend < -0xffff) || (saddend > 0)) - return bfd_reloc_overflow; - - if ((addend % 2) != 0) - return bfd_reloc_dangerous; - - insn = bfd_get_16 (abfd, address); - insn &= ~0xfffe; - insn |= (-addend & 0xfffe); - break; - - case R_V850_PC9: - case R_V850_9_PCREL: - if (saddend > 0xff || saddend < -0x100) - return bfd_reloc_overflow; - - if ((addend % 2) != 0) - return bfd_reloc_dangerous; - - insn = bfd_get_16 (abfd, address); - insn &= ~ 0xf870; - insn |= ((addend & 0x1f0) << 7) | ((addend & 0x0e) << 3); - break; - - case R_V810_WHI: - case R_V850_HI16: - addend += (bfd_get_16 (abfd, address) << 16); - addend = (addend >> 16); - insn = addend; - break; - - case R_V810_WHI1: - case R_V850_HI16_S: - /* Remember where this relocation took place. */ - remember_hi16s_reloc (abfd, addend, address); - - addend += (bfd_get_16 (abfd, address) << 16); - addend = (addend >> 16) + ((addend & 0x8000) != 0); - - /* This relocation cannot overflow. */ - if (addend > 0xffff) - addend = 0; - - insn = addend; - break; - - case R_V810_WLO: - case R_V850_LO16: - insn = bfd_get_16 (abfd, address); - if (! v850_elf_perform_lo16_relocation (abfd, &insn, addend)) - return bfd_reloc_overflow; - break; - - case R_V810_BYTE: - case R_V850_8: - addend += (char) bfd_get_8 (abfd, address); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x7f || saddend < -0x80) - return bfd_reloc_overflow; - - bfd_put_8 (abfd, addend, address); - return bfd_reloc_ok; - - case R_V850_CALLT_16_16_OFFSET: - addend += bfd_get_16 (abfd, address); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0xffff || saddend < 0) - return bfd_reloc_overflow; - - insn = addend; - break; - - case R_V850_CALLT_15_16_OFFSET: - insn = bfd_get_16 (abfd, address); - - addend += insn & 0xfffe; - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0xffff || saddend < 0) - return bfd_reloc_overflow; - - insn = (0xfffe & addend) - | (insn & ~0xfffe); - break; - - case R_V850_CALLT_6_7_OFFSET: - insn = bfd_get_16 (abfd, address); - addend += ((insn & 0x3f) << 1); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x7e || saddend < 0) - return bfd_reloc_overflow; - - if (addend & 1) - return bfd_reloc_dangerous; - - insn &= 0xff80; - insn |= (addend >> 1); - break; - - case R_V850_16: - case R_V810_HWORD: - case R_V850_SDA_16_16_OFFSET: - case R_V850_ZDA_16_16_OFFSET: - case R_V850_TDA_16_16_OFFSET: - addend += bfd_get_16 (abfd, address); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x7fff || saddend < -0x8000) - return bfd_reloc_overflow; - - insn = addend; - break; - - case R_V850_16_S1: - case R_V850_SDA_15_16_OFFSET: - case R_V850_ZDA_15_16_OFFSET: - case R_V810_GPWLO_1: - insn = bfd_get_16 (abfd, address); - addend += (insn & 0xfffe); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x7ffe || saddend < -0x8000) - return bfd_reloc_overflow; - - if (addend & 1) - return bfd_reloc_dangerous; - - insn = (addend &~ (bfd_vma) 1) | (insn & 1); - break; - - case R_V850_TDA_6_8_OFFSET: - insn = bfd_get_16 (abfd, address); - addend += ((insn & 0x7e) << 1); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0xfc || saddend < 0) - return bfd_reloc_overflow; - - if (addend & 3) - return bfd_reloc_dangerous; - - insn &= 0xff81; - insn |= (addend >> 1); - break; - - case R_V850_TDA_7_8_OFFSET: - insn = bfd_get_16 (abfd, address); - addend += ((insn & 0x7f) << 1); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0xfe || saddend < 0) - return bfd_reloc_overflow; - - if (addend & 1) - return bfd_reloc_dangerous; - - insn &= 0xff80; - insn |= (addend >> 1); - break; - - case R_V850_TDA_7_7_OFFSET: - insn = bfd_get_16 (abfd, address); - addend += insn & 0x7f; - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x7f || saddend < 0) - return bfd_reloc_overflow; - - insn &= 0xff80; - insn |= addend; - break; - - case R_V850_TDA_4_5_OFFSET: - insn = bfd_get_16 (abfd, address); - addend += ((insn & 0xf) << 1); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x1e || saddend < 0) - return bfd_reloc_overflow; - - if (addend & 1) - return bfd_reloc_dangerous; - - insn &= 0xfff0; - insn |= (addend >> 1); - break; - - case R_V850_TDA_4_4_OFFSET: - insn = bfd_get_16 (abfd, address); - addend += insn & 0xf; - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0xf || saddend < 0) - return bfd_reloc_overflow; - - insn &= 0xfff0; - insn |= addend; - break; - - case R_V810_WLO_1: - case R_V850_HWLO: - case R_V850_HWLO_1: - case R_V850_LO16_S1: - insn = bfd_get_16 (abfd, address); - result = insn & 0xfffe; - if (! v850_elf_perform_lo16_relocation (abfd, &result, addend)) - return bfd_reloc_overflow; - if (result & 1) - return bfd_reloc_overflow; - insn = (result & 0xfffe) - | (insn & ~0xfffe); - bfd_put_16 (abfd, insn, address); - return bfd_reloc_ok; - - case R_V850_BLO: - case R_V850_LO16_SPLIT_OFFSET: - insn = bfd_get_32 (abfd, address); - result = ((insn & 0xfffe0000) >> 16) | ((insn & 0x20) >> 5); - if (! v850_elf_perform_lo16_relocation (abfd, &result, addend)) - return bfd_reloc_overflow; - insn = (((result << 16) & 0xfffe0000) - | ((result << 5) & 0x20) - | (insn & ~0xfffe0020)); - bfd_put_32 (abfd, insn, address); - return bfd_reloc_ok; - - case R_V850_16_SPLIT_OFFSET: - case R_V850_SDA_16_16_SPLIT_OFFSET: - case R_V850_ZDA_16_16_SPLIT_OFFSET: - insn = bfd_get_32 (abfd, address); - addend += ((insn & 0xfffe0000) >> 16) + ((insn & 0x20) >> 5); - - saddend = (bfd_signed_vma) addend; - - if (saddend > 0x7fff || saddend < -0x8000) - return bfd_reloc_overflow; - - insn &= 0x0001ffdf; - insn |= (addend & 1) << 5; - insn |= (addend &~ (bfd_vma) 1) << 16; - - bfd_put_32 (abfd, (bfd_vma) insn, address); - return bfd_reloc_ok; - - case R_V850_GNU_VTINHERIT: - case R_V850_GNU_VTENTRY: - return bfd_reloc_ok; - - } - - bfd_put_16 (abfd, (bfd_vma) insn, address); - return bfd_reloc_ok; -} - -/* Insert the addend into the instruction. */ - -static bfd_reloc_status_type -v850_elf_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc, - asymbol *symbol, - void * data ATTRIBUTE_UNUSED, - asection *isection, - bfd *obfd, - char **err ATTRIBUTE_UNUSED) -{ - long relocation; - - /* If there is an output BFD, - and the symbol is not a section name (which is only defined at final link time), - and either we are not putting the addend into the instruction - or the addend is zero, so there is nothing to add into the instruction - then just fixup the address and return. */ - if (obfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! reloc->howto->partial_inplace - || reloc->addend == 0)) - { - reloc->address += isection->output_offset; - return bfd_reloc_ok; - } - - /* Catch relocs involving undefined symbols. */ - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && obfd == NULL) - return bfd_reloc_undefined; - - /* We handle final linking of some relocs ourselves. */ - - /* Is the address of the relocation really within the section? */ - if (reloc->address > bfd_get_section_limit (abfd, isection)) - return bfd_reloc_outofrange; - - /* Work out which section the relocation is targeted at and the - initial relocation command value. */ - - if (reloc->howto->pc_relative) - return bfd_reloc_ok; - - /* Get symbol value. (Common symbols are special.) */ - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - /* Convert input-section-relative symbol value to absolute + addend. */ - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc->addend; - - reloc->addend = relocation; - return bfd_reloc_ok; -} - -/* This function is used for relocs which are only used - for relaxing, which the linker should otherwise ignore. */ - -static bfd_reloc_status_type -v850_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} -/* Note: It is REQUIRED that the 'type' value of each entry - in this array match the index of the entry in the array. - SeeAlso: RELOC_NUBMER in include/elf/v850.h. */ -static reloc_howto_type v850_elf_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_V850_NONE, /* Type. */ - 0, /* Rightshift. */ - 3, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_V850_NONE", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A PC relative 9 bit branch. */ - HOWTO (R_V850_9_PCREL, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 9, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_9_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x00ffffff, /* Src_mask. */ - 0x00ffffff, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A PC relative 22 bit branch. */ - HOWTO (R_V850_22_PCREL, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 22, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_22_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x07ffff80, /* Src_mask. */ - 0x07ffff80, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* High 16 bits of symbol value. */ - HOWTO (R_V850_HI16_S, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_HI16_S", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* High 16 bits of symbol value. */ - HOWTO (R_V850_HI16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_HI16", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_V850_LO16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_LO16", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* Simple 32bit reloc. */ - HOWTO (R_V850_ABS32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_ABS32", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* Simple 16bit reloc. */ - HOWTO (R_V850_16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_V850_16", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* Simple 8bit reloc. */ - HOWTO (R_V850_8, /* Type. */ - 0, /* Rightshift. */ - 0, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - bfd_elf_generic_reloc, /* Special_function. */ - "R_V850_8", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xff, /* Src_mask. */ - 0xff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit offset from the short data area pointer. */ - HOWTO (R_V850_SDA_16_16_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_SDA_16_16_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 15 bit offset from the short data area pointer. */ - HOWTO (R_V850_SDA_15_16_OFFSET, /* Type. */ - 1, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 1, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_SDA_15_16_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfffe, /* Src_mask. */ - 0xfffe, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit offset from the zero data area pointer. */ - HOWTO (R_V850_ZDA_16_16_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_ZDA_16_16_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 15 bit offset from the zero data area pointer. */ - HOWTO (R_V850_ZDA_15_16_OFFSET, /* Type. */ - 1, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 1, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_ZDA_15_16_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfffe, /* Src_mask. */ - 0xfffe, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 6 bit offset from the tiny data area pointer. */ - HOWTO (R_V850_TDA_6_8_OFFSET, /* Type. */ - 2, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - FALSE, /* PC_relative. */ - 1, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_TDA_6_8_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x7e, /* Src_mask. */ - 0x7e, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 8 bit offset from the tiny data area pointer. */ - HOWTO (R_V850_TDA_7_8_OFFSET, /* Type. */ - 1, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 8, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_TDA_7_8_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x7f, /* Src_mask. */ - 0x7f, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 7 bit offset from the tiny data area pointer. */ - HOWTO (R_V850_TDA_7_7_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 7, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_TDA_7_7_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x7f, /* Src_mask. */ - 0x7f, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit offset from the tiny data area pointer! */ - HOWTO (R_V850_TDA_16_16_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_TDA_16_16_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xfff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 5 bit offset from the tiny data area pointer. */ - HOWTO (R_V850_TDA_4_5_OFFSET, /* Type. */ - 1, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 5, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_TDA_4_5_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x0f, /* Src_mask. */ - 0x0f, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 4 bit offset from the tiny data area pointer. */ - HOWTO (R_V850_TDA_4_4_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 4, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_TDA_4_4_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x0f, /* Src_mask. */ - 0x0f, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit offset from the short data area pointer. */ - HOWTO (R_V850_SDA_16_16_SPLIT_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_SDA_16_16_SPLIT_OFFSET",/* Name. */ - FALSE, /* Partial_inplace. */ - 0xfffe0020, /* Src_mask. */ - 0xfffe0020, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit offset from the zero data area pointer. */ - HOWTO (R_V850_ZDA_16_16_SPLIT_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_ZDA_16_16_SPLIT_OFFSET",/* Name. */ - FALSE, /* Partial_inplace. */ - 0xfffe0020, /* Src_mask. */ - 0xfffe0020, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 6 bit offset from the call table base pointer. */ - HOWTO (R_V850_CALLT_6_7_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 7, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_CALLT_6_7_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x3f, /* Src_mask. */ - 0x3f, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* 16 bit offset from the call table base pointer. */ - HOWTO (R_V850_CALLT_16_16_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_CALLT_16_16_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_V850_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_V850_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_V850_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_V850_GNU_VTENTRY", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* Indicates a .longcall pseudo-op. The compiler will generate a .longcall - pseudo-op when it finds a function call which can be relaxed. */ - HOWTO (R_V850_LONGCALL, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - v850_elf_ignore_reloc, /* Special_function. */ - "R_V850_LONGCALL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* Indicates a .longjump pseudo-op. The compiler will generate a - .longjump pseudo-op when it finds a branch which can be relaxed. */ - HOWTO (R_V850_LONGJUMP, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_signed, /* Complain_on_overflow. */ - v850_elf_ignore_reloc, /* Special_function. */ - "R_V850_LONGJUMP", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - HOWTO (R_V850_ALIGN, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 0, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_unsigned, /* Complain_on_overflow. */ - v850_elf_ignore_reloc, /* Special_function. */ - "R_V850_ALIGN", /* Name. */ - FALSE, /* Partial_inplace. */ - 0, /* Src_mask. */ - 0, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* Simple pc-relative 32bit reloc. */ - HOWTO (R_V850_REL32, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 32, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_REL32", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffffffff, /* Src_mask. */ - 0xffffffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* An ld.bu version of R_V850_LO16. */ - HOWTO (R_V850_LO16_SPLIT_OFFSET, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_LO16_SPLIT_OFFSET", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfffe0020, /* Src_mask. */ - 0xfffe0020, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* A unsigned PC relative 16 bit loop. */ - HOWTO (R_V850_16_PCREL, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_16_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xfffe, /* Src_mask. */ - 0xfffe, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A PC relative 17 bit branch. */ - HOWTO (R_V850_17_PCREL, /* Type. */ - 0, /* Rightshift. */ - 2, /* Size (0 = byte, 1 = short, 2 = long). */ - 17, /* Bitsize. */ - TRUE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_bitfield, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_17_PCREL", /* Name. */ - FALSE, /* Partial_inplace. */ - 0x0010fffe, /* Src_mask. */ - 0x0010fffe, /* Dst_mask. */ - TRUE), /* PCrel_offset. */ - - /* A 23bit offset ld/st. */ - HOWTO (R_V850_23, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 23, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_23", /* name. */ - FALSE, /* partial_inplace. */ - 0xffff07f0, /* src_mask. */ - 0xffff07f0, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* A PC relative 32 bit branch. */ - HOWTO (R_V850_32_PCREL, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - TRUE, /* pc_relative. */ - 1, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_32_PCREL", /* name. */ - FALSE, /* partial_inplace. */ - 0xfffffffe, /* src_mask. */ - 0xfffffffe, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - /* A absolute 32 bit branch. */ - HOWTO (R_V850_32_ABS, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - TRUE, /* pc_relative. */ - 1, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_32_ABS", /* name. */ - FALSE, /* partial_inplace. */ - 0xfffffffe, /* src_mask. */ - 0xfffffffe, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* High 16 bits of symbol value. */ - HOWTO (R_V850_HI16, /* Type. */ - 0, /* Rightshift. */ - 1, /* Size (0 = byte, 1 = short, 2 = long). */ - 16, /* Bitsize. */ - FALSE, /* PC_relative. */ - 0, /* Bitpos. */ - complain_overflow_dont, /* Complain_on_overflow. */ - v850_elf_reloc, /* Special_function. */ - "R_V850_HI16", /* Name. */ - FALSE, /* Partial_inplace. */ - 0xffff, /* Src_mask. */ - 0xffff, /* Dst_mask. */ - FALSE), /* PCrel_offset. */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_V850_16_S1, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 1, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_16_S1", /* name. */ - FALSE, /* partial_inplace. */ - 0xfffe, /* src_mask. */ - 0xfffe, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_V850_LO16_S1, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 1, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_LO16_S1", /* name. */ - FALSE, /* partial_inplace. */ - 0xfffe, /* src_mask. */ - 0xfffe, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* 16 bit offset from the call table base pointer. */ - HOWTO (R_V850_CALLT_15_16_OFFSET, /* type. */ - 1, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 1, /* bitpos. */ - complain_overflow_dont, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_CALLT_15_16_OFFSET", /* name. */ - FALSE, /* partial_inplace. */ - 0xfffe, /* src_mask. */ - 0xfffe, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* Like R_V850_32 PCREL, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_V850_32_GOTPCREL, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - TRUE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - v850_elf_reloc, /* special_function. */ - "R_V850_32_GOTPCREL", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - /* Like R_V850_SDA_, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_V850_16_GOT, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_16_GOT", /* name. */ - FALSE, /* partial_inplace. */ - 0xffff, /* src_mask. */ - 0xffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_V850_32_GOT, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_32_GOT", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* Like R_V850_22_PCREL, but referring to the procedure linkage table - entry for the symbol. */ - HOWTO (R_V850_22_PLT, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 22, /* bitsize. */ - TRUE, /* pc_relative. */ - 7, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_22_PLT", /* name. */ - FALSE, /* partial_inplace. */ - 0x07ffff80, /* src_mask. */ - 0x07ffff80, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_V850_32_PLT, /* type. */ - 1, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - TRUE, /* pc_relative. */ - 1, /* bitpos. */ - complain_overflow_signed, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_32_PLT", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_V850_COPY, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long). */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_COPY", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* Like R_M32R_24, but used when setting global offset table - entries. */ - HOWTO (R_V850_GLOB_DAT, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_GLOB_DAT", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* Marks a procedure linkage table entry for a symbol. */ - HOWTO (R_V850_JMP_SLOT, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_JMP_SLOT", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - /* Used only by the dynamic linker. When the object is run, this - longword is set to the load address of the object, plus the - addend. */ - HOWTO (R_V850_RELATIVE, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_RELATIVE", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_V850_16_GOTOFF, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_16_GOTOFF", /* name. */ - FALSE, /* partial_inplace. */ - 0xffff, /* src_mask. */ - 0xffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_V850_32_GOTOFF, /* type. */ - 0, /* rightshift. */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_bitfield, /* complain_on_overflow. */ - bfd_elf_generic_reloc, /* special_function. */ - "R_V850_32_GOTOFF", /* name. */ - FALSE, /* partial_inplace. */ - 0xffffffff, /* src_mask. */ - 0xffffffff, /* dst_mask. */ - FALSE), /* pcrel_offset. */ - - HOWTO (R_V850_CODE, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - v850_elf_ignore_reloc, /* special_function. */ - "R_V850_CODE", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - - HOWTO (R_V850_DATA, /* type. */ - 0, /* rightshift. */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize. */ - FALSE, /* pc_relative. */ - 0, /* bitpos. */ - complain_overflow_unsigned, /* complain_on_overflow. */ - v850_elf_ignore_reloc, /* special_function. */ - "R_V850_DATA", /* name. */ - FALSE, /* partial_inplace. */ - 0, /* src_mask. */ - 0, /* dst_mask. */ - TRUE), /* pcrel_offset. */ - -}; - -/* Map BFD reloc types to V850 ELF reloc types. */ - -struct v850_elf_reloc_map -{ - /* BFD_RELOC_V850_CALLT_16_16_OFFSET is 258, which will not fix in an - unsigned char. */ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int elf_reloc_val; -}; - -static const struct v850_elf_reloc_map v850_elf_reloc_map[] = -{ - { BFD_RELOC_NONE, R_V850_NONE }, - { BFD_RELOC_V850_9_PCREL, R_V850_9_PCREL }, - { BFD_RELOC_V850_22_PCREL, R_V850_22_PCREL }, - { BFD_RELOC_HI16_S, R_V850_HI16_S }, - { BFD_RELOC_HI16, R_V850_HI16 }, - { BFD_RELOC_LO16, R_V850_LO16 }, - { BFD_RELOC_32, R_V850_ABS32 }, - { BFD_RELOC_32_PCREL, R_V850_REL32 }, - { BFD_RELOC_16, R_V850_16 }, - { BFD_RELOC_8, R_V850_8 }, - { BFD_RELOC_V850_SDA_16_16_OFFSET, R_V850_SDA_16_16_OFFSET }, - { BFD_RELOC_V850_SDA_15_16_OFFSET, R_V850_SDA_15_16_OFFSET }, - { BFD_RELOC_V850_ZDA_16_16_OFFSET, R_V850_ZDA_16_16_OFFSET }, - { BFD_RELOC_V850_ZDA_15_16_OFFSET, R_V850_ZDA_15_16_OFFSET }, - { BFD_RELOC_V850_TDA_6_8_OFFSET, R_V850_TDA_6_8_OFFSET }, - { BFD_RELOC_V850_TDA_7_8_OFFSET, R_V850_TDA_7_8_OFFSET }, - { BFD_RELOC_V850_TDA_7_7_OFFSET, R_V850_TDA_7_7_OFFSET }, - { BFD_RELOC_V850_TDA_16_16_OFFSET, R_V850_TDA_16_16_OFFSET }, - { BFD_RELOC_V850_TDA_4_5_OFFSET, R_V850_TDA_4_5_OFFSET }, - { BFD_RELOC_V850_TDA_4_4_OFFSET, R_V850_TDA_4_4_OFFSET }, - { BFD_RELOC_V850_LO16_SPLIT_OFFSET, R_V850_LO16_SPLIT_OFFSET }, - { BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET }, - { BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET }, - { BFD_RELOC_V850_CALLT_6_7_OFFSET, R_V850_CALLT_6_7_OFFSET }, - { BFD_RELOC_V850_CALLT_16_16_OFFSET, R_V850_CALLT_16_16_OFFSET }, - { BFD_RELOC_VTABLE_INHERIT, R_V850_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_V850_GNU_VTENTRY }, - { BFD_RELOC_V850_LONGCALL, R_V850_LONGCALL }, - { BFD_RELOC_V850_LONGJUMP, R_V850_LONGJUMP }, - { BFD_RELOC_V850_ALIGN, R_V850_ALIGN }, - { BFD_RELOC_V850_16_PCREL, R_V850_16_PCREL }, - { BFD_RELOC_V850_17_PCREL, R_V850_17_PCREL }, - { BFD_RELOC_V850_23, R_V850_23 }, - { BFD_RELOC_V850_32_PCREL, R_V850_32_PCREL }, - { BFD_RELOC_V850_32_ABS, R_V850_32_ABS }, - { BFD_RELOC_V850_16_SPLIT_OFFSET, R_V850_HI16 }, - { BFD_RELOC_V850_16_S1, R_V850_16_S1 }, - { BFD_RELOC_V850_LO16_S1, R_V850_LO16_S1 }, - { BFD_RELOC_V850_CALLT_15_16_OFFSET, R_V850_CALLT_15_16_OFFSET }, - { BFD_RELOC_V850_32_GOTPCREL, R_V850_32_GOTPCREL }, - { BFD_RELOC_V850_16_GOT, R_V850_16_GOT }, - { BFD_RELOC_V850_32_GOT, R_V850_32_GOT }, - { BFD_RELOC_V850_22_PLT_PCREL, R_V850_22_PLT }, - { BFD_RELOC_V850_32_PLT_PCREL, R_V850_32_PLT }, - { BFD_RELOC_V850_COPY, R_V850_COPY }, - { BFD_RELOC_V850_GLOB_DAT, R_V850_GLOB_DAT }, - { BFD_RELOC_V850_JMP_SLOT, R_V850_JMP_SLOT }, - { BFD_RELOC_V850_RELATIVE, R_V850_RELATIVE }, - { BFD_RELOC_V850_16_GOTOFF, R_V850_16_GOTOFF }, - { BFD_RELOC_V850_32_GOTOFF, R_V850_32_GOTOFF }, - { BFD_RELOC_V850_CODE, R_V850_CODE }, - { BFD_RELOC_V850_DATA, R_V850_DATA }, -}; - -#define V800_RELOC(name,sz,bit,shift,complain,pcrel,resolver) \ - HOWTO (name, shift, sz, bit, pcrel, 0, complain_overflow_ ## complain, \ - bfd_elf_ ## resolver ## _reloc, #name, FALSE, 0, ~0, FALSE) - -#define V800_EMPTY(name) EMPTY_HOWTO (name - R_V810_NONE) - -#define bfd_elf_v850_reloc v850_elf_reloc - -/* Note: It is REQUIRED that the 'type' value (R_V810_...) of each entry - in this array match the index of the entry in the array minus 0x30. - See: bfd_elf_v850_relocate_section(), v800_elf_reloc_type_lookup() - and v800_elf_info_to_howto(). */ - -static reloc_howto_type v800_elf_howto_table[] = -{ - V800_RELOC (R_V810_NONE, 0, 0, 0, dont, FALSE, generic), /* Type = 0x30 */ - V800_RELOC (R_V810_BYTE, 0, 8, 0, dont, FALSE, generic), - V800_RELOC (R_V810_HWORD, 1, 16, 0, dont, FALSE, generic), - V800_RELOC (R_V810_WORD, 2, 32, 0, dont, FALSE, generic), - V800_RELOC (R_V810_WLO, 1, 16, 0, dont, FALSE, generic), - V800_RELOC (R_V810_WHI, 1, 16, 0, dont, FALSE, generic), - V800_RELOC (R_V810_WHI1, 1, 16, 0, dont, FALSE, generic), - V800_RELOC (R_V810_GPBYTE, 0, 8, 0, dont, FALSE, v850), - V800_RELOC (R_V810_GPHWORD, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_GPWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V810_GPWLO, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_GPWHI, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_GPWHI1, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V850_HWLO, 1, 16, 0, dont, FALSE, generic), - V800_EMPTY (R_V810_reserved1), - V800_RELOC (R_V850_EP7BIT, 0, 7, 0, unsigned, FALSE, v850), - V800_RELOC (R_V850_EPHBYTE, 0, 8, 1, unsigned, FALSE, v850), - V800_RELOC (R_V850_EPWBYTE, 0, 8, 2, unsigned, FALSE, v850), - V800_RELOC (R_V850_REGHWLO, 1, 16, 0, dont, FALSE, v850), - V800_EMPTY (R_V810_reserved2), - V800_RELOC (R_V850_GPHWLO, 1, 16, 0, dont, FALSE, v850), - V800_EMPTY (R_V810_reserved3), - V800_RELOC (R_V850_PCR22, 2, 22, 0, signed, TRUE, generic), - V800_RELOC (R_V850_BLO, 2, 24, 0, dont, FALSE, v850), - V800_RELOC (R_V850_EP4BIT, 0, 4, 0, unsigned, FALSE, v850), - V800_RELOC (R_V850_EP5BIT, 0, 5, 0, unsigned, FALSE, v850), - V800_RELOC (R_V850_REGBLO, 2, 24, 0, dont, FALSE, v850), - V800_RELOC (R_V850_GPBLO, 2, 24, 0, dont, FALSE, v850), - V800_RELOC (R_V810_WLO_1, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_GPWLO_1, 1, 16, 0, signed, FALSE, v850), - V800_RELOC (R_V850_BLO_1, 2, 16, 0, signed, FALSE, v850), - V800_RELOC (R_V850_HWLO_1, 1, 16, 0, signed, FALSE, v850), - V800_EMPTY (R_V810_reserved4), - V800_RELOC (R_V850_GPBLO_1, 2, 16, 1, signed, FALSE, v850), - V800_RELOC (R_V850_GPHWLO_1, 1, 16, 1, signed, FALSE, v850), - V800_EMPTY (R_V810_reserved5), - V800_RELOC (R_V850_EPBLO, 2, 16, 1, signed, FALSE, v850), - V800_RELOC (R_V850_EPHWLO, 1, 16, 1, signed, FALSE, v850), - V800_EMPTY (R_V810_reserved6), - V800_RELOC (R_V850_EPWLO_N, 1, 16, 1, signed, FALSE, v850), - V800_RELOC (R_V850_PC32, 2, 32, 1, signed, TRUE, v850), - V800_RELOC (R_V850_W23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_GPW23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_EPW23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_B23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_GPB23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_EPB23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_PC16U, 1, 16, 1, unsigned, TRUE, generic), - V800_RELOC (R_V850_PC17, 2, 17, 1, signed, TRUE, generic), - V800_RELOC (R_V850_DW8, 2, 8, 2, signed, FALSE, v850), - V800_RELOC (R_V850_GPDW8, 2, 8, 2, signed, FALSE, v850), - V800_RELOC (R_V850_EPDW8, 2, 8, 2, signed, FALSE, v850), - V800_RELOC (R_V850_PC9, 1, 9, 3, signed, TRUE, v850), - V800_RELOC (R_V810_REGBYTE, 0, 8, 0, dont, FALSE, v850), - V800_RELOC (R_V810_REGHWORD, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_REGWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V810_REGWLO, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_REGWHI, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_REGWHI1, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V850_REGW23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_REGB23BIT, 2, 23, 1, signed, FALSE, v850), - V800_RELOC (R_V850_REGDW8, 2, 8, 2, signed, FALSE, v850), - V800_RELOC (R_V810_EPBYTE, 0, 8, 0, dont, FALSE, v850), - V800_RELOC (R_V810_EPHWORD, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_EPWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V850_WLO23, 2, 32, 1, dont, FALSE, v850), - V800_RELOC (R_V850_WORD_E, 2, 32, 1, dont, FALSE, v850), - V800_RELOC (R_V850_REGWORD_E, 2, 32, 1, dont, FALSE, v850), - V800_RELOC (R_V850_WORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V850_GPWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V850_REGWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V850_EPWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPBYTE, 0, 8, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPHWORD, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPWORD, 2, 32, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPWLO, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPWHI, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPWHI1, 1, 16, 0, dont, FALSE, v850), - V800_RELOC (R_V850_TPHWLO, 1, 16, 1, dont, FALSE, v850), - V800_RELOC (R_V850_TPBLO, 2, 24, 0, dont, FALSE, v850), - V800_RELOC (R_V810_TPWLO_1, 1, 16, 0, signed, FALSE, v850), - V800_RELOC (R_V850_TPBLO_1, 2, 16, 0, signed, FALSE, v850), - V800_RELOC (R_V850_TPHWLO_1, 1, 16, 0, signed, FALSE, v850), - V800_RELOC (R_V850_TP23BIT, 2, 23, 0, signed, FALSE, v850), - V800_RELOC (R_V850_TPW23BIT, 2, 23, 0, signed, FALSE, v850), - V800_RELOC (R_V850_TPDW8, 2, 8, 0, signed, FALSE, v850) -}; - -/* Map a bfd relocation into the appropriate howto structure. */ - -static reloc_howto_type * -v850_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (v850_elf_reloc_map); i --;) - if (v850_elf_reloc_map[i].bfd_reloc_val == code) - { - unsigned int elf_reloc_val = v850_elf_reloc_map[i].elf_reloc_val; - - BFD_ASSERT (v850_elf_howto_table[elf_reloc_val].type == elf_reloc_val); - - return v850_elf_howto_table + elf_reloc_val; - } - - return NULL; -} - -static reloc_howto_type * -v850_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (v850_elf_howto_table) / sizeof (v850_elf_howto_table[0]); - i++) - if (v850_elf_howto_table[i].name != NULL - && strcasecmp (v850_elf_howto_table[i].name, r_name) == 0) - return &v850_elf_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an V850 ELF reloc. */ - -static void -v850_elf_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_V850_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid V850 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &v850_elf_howto_table[r_type]; -} - -/* Set the howto pointer for a V850 ELF reloc (type RELA). */ - -static void -v850_elf_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_V850_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid V850 reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &v850_elf_howto_table[r_type]; -} - -static bfd_boolean -v850_elf_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - return ( (name[0] == '.' && (name[1] == 'L' || name[1] == '.')) - || (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')); -} - -static bfd_boolean -v850_elf_is_target_special_symbol (bfd *abfd, asymbol *sym) -{ - return v850_elf_is_local_label_name (abfd, sym->name); -} - -/* We overload some of the bfd_reloc error codes for own purposes. */ -#define bfd_reloc_gp_not_found bfd_reloc_other -#define bfd_reloc_ep_not_found bfd_reloc_continue -#define bfd_reloc_ctbp_not_found (bfd_reloc_dangerous + 1) - -/* Perform a relocation as part of a final link. */ - -static bfd_reloc_status_type -v850_elf_final_link_relocate (reloc_howto_type *howto, - bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section, - bfd_byte *contents, - bfd_vma offset, - bfd_vma value, - bfd_vma addend, - struct bfd_link_info *info, - asection *sym_sec, - int is_local ATTRIBUTE_UNUSED) -{ - unsigned int r_type = howto->type; - bfd_byte *hit_data = contents + offset; - - /* Adjust the value according to the relocation. */ - switch (r_type) - { - case R_V850_PC9: - case R_V850_9_PCREL: - value -= (input_section->output_section->vma - + input_section->output_offset); - value -= offset; - break; - - case R_V850_PC16U: - case R_V850_16_PCREL: - value -= (input_section->output_section->vma - + input_section->output_offset - + offset); - - /* If the sign extension will corrupt the value then we have overflowed. */ - if ((value & 0xffff0000) != 0xffff0000) - return bfd_reloc_overflow; - - break; - - case R_V850_PC17: - case R_V850_17_PCREL: - value -= (input_section->output_section->vma - + input_section->output_offset - + offset); - - /* If the sign extension will corrupt the value then we have overflowed. */ - if (((value & 0xffff0000) != 0x0) && ((value & 0xffff0000) != 0xffff0000)) - return bfd_reloc_overflow; - - value = SEXT17 (value); - break; - - case R_V850_PCR22: - case R_V850_22_PCREL: - value -= (input_section->output_section->vma - + input_section->output_offset - + offset); - - /* If the sign extension will corrupt the value then we have overflowed. */ - if (((value & 0xffe00000) != 0x0) && ((value & 0xffe00000) != 0xffe00000)) - return bfd_reloc_overflow; - - /* Only the bottom 22 bits of the PC are valid. */ - value = SEXT22 (value); - break; - - case R_V850_PC32: - case R_V850_32_PCREL: - value -= (input_section->output_section->vma - + input_section->output_offset - + offset); - break; - - case R_V850_32_ABS: - case R_V850_23: - case R_V850_HI16_S: - case R_V850_HI16: - case R_V850_LO16: - case R_V850_LO16_S1: - case R_V850_LO16_SPLIT_OFFSET: - case R_V850_16: - case R_V850_ABS32: - case R_V850_8: - case R_V810_BYTE: - case R_V810_HWORD: - case R_V810_WORD: - case R_V810_WLO: - case R_V810_WHI: - case R_V810_WHI1: - case R_V810_WLO_1: - case R_V850_WLO23: - case R_V850_BLO: - break; - - case R_V850_ZDA_15_16_OFFSET: - case R_V850_ZDA_16_16_OFFSET: - case R_V850_ZDA_16_16_SPLIT_OFFSET: - if (sym_sec == NULL) - return bfd_reloc_undefined; - - value -= sym_sec->output_section->vma; - break; - - case R_V850_SDA_15_16_OFFSET: - case R_V850_SDA_16_16_OFFSET: - case R_V850_SDA_16_16_SPLIT_OFFSET: - case R_V810_GPWLO_1: - { - unsigned long gp; - struct bfd_link_hash_entry * h; - - if (sym_sec == NULL) - return bfd_reloc_undefined; - - /* Get the value of __gp. */ - h = bfd_link_hash_lookup (info->hash, "__gp", FALSE, FALSE, TRUE); - if (h == NULL - || h->type != bfd_link_hash_defined) - return bfd_reloc_gp_not_found; - - gp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= sym_sec->output_section->vma; - value -= (gp - sym_sec->output_section->vma); - } - break; - - case R_V850_TDA_4_4_OFFSET: - case R_V850_TDA_4_5_OFFSET: - case R_V850_TDA_7_7_OFFSET: - case R_V850_TDA_7_8_OFFSET: - case R_V850_TDA_6_8_OFFSET: - case R_V850_TDA_16_16_OFFSET: - { - unsigned long ep; - struct bfd_link_hash_entry * h; - - /* Get the value of __ep. */ - h = bfd_link_hash_lookup (info->hash, "__ep", FALSE, FALSE, TRUE); - if (h == NULL - || h->type != bfd_link_hash_defined) - return bfd_reloc_ep_not_found; - - ep = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= ep; - } - break; - - case R_V850_CALLT_6_7_OFFSET: - { - unsigned long ctbp; - struct bfd_link_hash_entry * h; - - /* Get the value of __ctbp. */ - h = bfd_link_hash_lookup (info->hash, "__ctbp", FALSE, FALSE, TRUE); - if (h == NULL - || h->type != bfd_link_hash_defined) - return bfd_reloc_ctbp_not_found; - - ctbp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - value -= ctbp; - } - break; - - case R_V850_CALLT_15_16_OFFSET: - case R_V850_CALLT_16_16_OFFSET: - { - unsigned long ctbp; - struct bfd_link_hash_entry * h; - - if (sym_sec == NULL) - return bfd_reloc_undefined; - - /* Get the value of __ctbp. */ - h = bfd_link_hash_lookup (info->hash, "__ctbp", FALSE, FALSE, TRUE); - if (h == NULL - || h->type != bfd_link_hash_defined) - return bfd_reloc_ctbp_not_found; - - ctbp = (h->u.def.value - + h->u.def.section->output_section->vma - + h->u.def.section->output_offset); - - value -= sym_sec->output_section->vma; - value -= (ctbp - sym_sec->output_section->vma); - } - break; - - case R_V850_NONE: - case R_V810_NONE: - case R_V850_GNU_VTINHERIT: - case R_V850_GNU_VTENTRY: - case R_V850_LONGCALL: - case R_V850_LONGJUMP: - case R_V850_ALIGN: - return bfd_reloc_ok; - - default: -#ifdef DEBUG - fprintf (stderr, "%B: reloc number %d not recognised\n", input_bfd, r_type); -#endif - return bfd_reloc_notsupported; - } - - /* Perform the relocation. */ - return v850_elf_perform_relocation (input_bfd, r_type, value + addend, hit_data); -} - -/* Relocate an V850 ELF section. */ - -static bfd_boolean -v850_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - /* Reset the list of remembered HI16S relocs to empty. */ - free_hi16s = previous_hi16s; - previous_hi16s = NULL; - hi16s_counter = 0; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - unsigned int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_V850_GNU_VTENTRY - || r_type == R_V850_GNU_VTINHERIT) - continue; - - if (bfd_get_arch (input_bfd) == bfd_arch_v850_rh850) - howto = v800_elf_howto_table + (r_type - R_V810_NONE); - else - howto = v850_elf_howto_table + r_type; - - BFD_ASSERT (r_type == howto->type); - - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - /* Note - this check is delayed until now as it is possible and - valid to have a file without any symbols but with relocs that - can be processed. */ - if (sym_hashes == NULL) - { - info->callbacks->warning - (info, "no hash table available", - NULL, input_bfd, input_section, (bfd_vma) 0); - - return FALSE; - } - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - /* FIXME: We should use the addend, but the COFF relocations don't. */ - r = v850_elf_final_link_relocate (howto, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - info, sec, h == NULL); - - if (r != bfd_reloc_ok) - { - const char * name; - const char * msg = NULL; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch ((int) r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - goto common_error; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - goto common_error; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - goto common_error; - - case bfd_reloc_gp_not_found: - msg = _("could not locate special linker symbol __gp"); - goto common_error; - - case bfd_reloc_ep_not_found: - msg = _("could not locate special linker symbol __ep"); - goto common_error; - - case bfd_reloc_ctbp_not_found: - msg = _("could not locate special linker symbol __ctbp"); - goto common_error; - - default: - msg = _("internal error: unknown error"); - /* fall through */ - - common_error: - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - break; - } - } - } - - return TRUE; -} - -static asection * -v850_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_V850_GNU_VTINHERIT: - case R_V850_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -static void -v850_set_note (bfd * abfd, asection * s, enum v850_notes note, unsigned int val) -{ - bfd_byte * data = s->contents + ((note - 1) * SIZEOF_V850_NOTE); - - bfd_put_32 (abfd, 4, data + 0); - bfd_put_32 (abfd, 4, data + 4); - bfd_put_32 (abfd, note, data + 8); - memcpy (data + 12, V850_NOTE_NAME, 4); - bfd_put_32 (abfd, val, data + 16); -} - -/* Create the note section if not already present. This is done early so - that the linker maps the sections to the right place in the output. */ - -static asection * -v850_elf_make_note_section (bfd * abfd) -{ - asection *s; - bfd_byte *data; - flagword flags; - enum v850_notes id; - - /* Make the note section. */ - flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_MERGE; - - s = bfd_make_section_anyway_with_flags (abfd, V850_NOTE_SECNAME, flags); - if (s == NULL) - return NULL; - - if (!bfd_set_section_alignment (abfd, s, 2)) - return NULL; - - /* Allocate space for all known notes. */ - if (!bfd_set_section_size (abfd, s, NUM_V850_NOTES * SIZEOF_V850_NOTE)) - return NULL; - - data = bfd_zalloc (abfd, NUM_V850_NOTES * SIZEOF_V850_NOTE); - if (data == NULL) - return NULL; - - s->contents = data; - - /* Provide default (= uninitilaised) values for all of the notes. */ - for (id = V850_NOTE_ALIGNMENT; id <= NUM_V850_NOTES; id++) - v850_set_note (abfd, s, id, 0); - - return s; -} - -/* Create the note section if not already present. This is done early so - that the linker maps the sections to the right place in the output. */ - -bfd_boolean -v850_elf_create_sections (struct bfd_link_info * info) -{ - bfd * ibfd; - - /* If we already have a note section, do not make another. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - if (bfd_get_section_by_name (ibfd, V850_NOTE_SECNAME) != NULL) - return TRUE; - - return v850_elf_make_note_section (info->input_bfds) != NULL; -} - -bfd_boolean -v850_elf_set_note (bfd * abfd, enum v850_notes note, unsigned int val) -{ - asection * notes = bfd_get_section_by_name (abfd, V850_NOTE_SECNAME); - - if (val > 2) - /* At the moment, no known note has a value over 2. */ - return FALSE; - - if (notes == NULL) - notes = v850_elf_make_note_section (abfd); - if (notes == NULL) - return FALSE; - - v850_set_note (abfd, notes, note, val); - return TRUE; -} - -/* Copy a v850 note section from one object module to another. */ - -static void -v850_elf_copy_notes (bfd *ibfd, bfd *obfd) -{ - asection * onotes; - asection * inotes; - - /* If the output bfd does not have a note section, then - skip the merge. The normal input to output section - copying will take care of everythng for us. */ - if ((onotes = bfd_get_section_by_name (obfd, V850_NOTE_SECNAME)) == NULL) - return; - - if ((inotes = bfd_get_section_by_name (ibfd, V850_NOTE_SECNAME)) == NULL) - return; - - if (bfd_section_size (ibfd, inotes) == bfd_section_size (obfd, onotes)) - { - bfd_byte * icont; - bfd_byte * ocont; - - if ((icont = elf_section_data (inotes)->this_hdr.contents) == NULL) - BFD_ASSERT (bfd_malloc_and_get_section (ibfd, inotes, & icont)); - - if ((ocont = elf_section_data (onotes)->this_hdr.contents) == NULL) - /* If the output is being stripped then it is possible for - the notes section to disappear. In this case do nothing. */ - return; - - /* Copy/overwrite notes from the input to the output. */ - memcpy (ocont, icont, bfd_section_size (obfd, onotes)); - } -} - -/* Copy backend specific data from one object module to another. */ - -static bfd_boolean -v850_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - v850_elf_copy_notes (ibfd, obfd); - return _bfd_elf_copy_private_bfd_data (ibfd, obfd); -} -#define bfd_elf32_bfd_copy_private_bfd_data v850_elf_copy_private_bfd_data - -static bfd_boolean -v850_elf_merge_notes (bfd * ibfd, bfd *obfd) -{ - asection * onotes; - asection * inotes; - bfd_boolean result = TRUE; - - /* If the output bfd does not have a note section, then - skip the merge. The normal input to output section - copying will take care of everythng for us. */ - if ((onotes = bfd_get_section_by_name (obfd, V850_NOTE_SECNAME)) == NULL) - return TRUE; - - if ((inotes = bfd_get_section_by_name (ibfd, V850_NOTE_SECNAME)) != NULL) - { - enum v850_notes id; - bfd_byte * icont; - bfd_byte * ocont; - - BFD_ASSERT (bfd_section_size (ibfd, inotes) == bfd_section_size (obfd, onotes)); - - if ((icont = elf_section_data (inotes)->this_hdr.contents) == NULL) - BFD_ASSERT (bfd_malloc_and_get_section (ibfd, inotes, & icont)); - - if ((ocont = elf_section_data (onotes)->this_hdr.contents) == NULL) - BFD_ASSERT (bfd_malloc_and_get_section (obfd, onotes, & ocont)); - - for (id = V850_NOTE_ALIGNMENT; id <= NUM_V850_NOTES; id++) - { - unsigned int ival; - unsigned int oval; - bfd_byte * idata = icont + ((id - 1) * SIZEOF_V850_NOTE) + 16; - bfd_byte * odata = ocont + ((id - 1) * SIZEOF_V850_NOTE) + 16; - - ival = bfd_get_32 (ibfd, idata); - oval = bfd_get_32 (obfd, odata); - - if (ival == 0 || ival == oval) - continue; - - if (oval == 0) - { - bfd_put_32 (obfd, ival, odata); - v850_set_note (obfd, onotes, id, ival); - continue; - } - - /* We have a mismatch. The ABI defines how to handle - this siutation on a per note type basis. */ - switch (id) - { - case V850_NOTE_ALIGNMENT: - if (oval == EF_RH850_DATA_ALIGN4) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B needs 8-byte alignment but %B is set for 4-byte alignment"), - ibfd, obfd); - result = FALSE; - } - else - /* ibfd uses 4-byte alignment, obfd uses 8-byte alignment. - Leave the obfd alignment as it is. */ - BFD_ASSERT (oval == EF_RH850_DATA_ALIGN8); - - break; - - case V850_NOTE_DATA_SIZE: - if (oval == EF_RH850_DOUBLE32) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses 64-bit doubles but " - "%B uses 32-bit doubles"), ibfd, obfd); - result = FALSE; - } - else - /* ibfd uses 32-bit doubles, obfd uses 64-bit doubles. - This is acceptable. Honest, that is what the ABI says. */ - BFD_ASSERT (oval == EF_RH850_DOUBLE64); - break; - - case V850_NOTE_FPU_INFO: - if (oval == EF_RH850_FPU20) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B uses FPU-3.0 but %B only supports FPU-2.0"), - ibfd, obfd); - result = FALSE; - } - else - /* ibfd uses FPU-2.0, obfd uses FPU-3.0. Leave obfd as it is. */ - BFD_ASSERT (oval == EF_RH850_FPU30); - - break; - - default: - /* None of the other conflicts matter. - Stick with the current output values. */ - break; - } - } - - /* FIXME: We should also check for conflicts between the notes - and the EF flags in the ELF header. */ - } - - return result; -} - -static void -print_v850_note (bfd * abfd, FILE * file, bfd_byte * data, enum v850_notes id) -{ - unsigned int value = bfd_get_32 (abfd, data + ((id - 1) * SIZEOF_V850_NOTE) + 16); - - switch (id) - { - case V850_NOTE_ALIGNMENT: - fprintf (file, _(" alignment of 8-byte entities: ")); - switch (value) - { - case EF_RH850_DATA_ALIGN4: fprintf (file, _("4-byte")); break; - case EF_RH850_DATA_ALIGN8: fprintf (file, _("8-byte")); break; - case 0: fprintf (file, _("not set")); break; - default: fprintf (file, _("unknown: %x"), value); break; - } - fputc ('\n', file); - break; - - case V850_NOTE_DATA_SIZE: - fprintf (file, _(" size of doubles: ")); - switch (value) - { - case EF_RH850_DOUBLE32: fprintf (file, _("4-bytes")); break; - case EF_RH850_DOUBLE64: fprintf (file, _("8-bytes")); break; - case 0: fprintf (file, _("not set")); break; - default: fprintf (file, _("unknown: %x"), value); break; - } - fputc ('\n', file); - break; - - case V850_NOTE_FPU_INFO: - fprintf (file, _(" FPU support required: ")); - switch (value) - { - case EF_RH850_FPU20: fprintf (file, _("FPU-2.0")); break; - case EF_RH850_FPU30: fprintf (file, _("FPU-3.0")); break; - case 0: fprintf (file, _("none")); break; - default: fprintf (file, _("unknown: %x"), value); break; - } - fputc ('\n', file); - break; - - case V850_NOTE_SIMD_INFO: - fprintf (file, _("SIMD use: ")); - switch (value) - { - case EF_RH850_SIMD: fprintf (file, _("yes")); break; - case 0: fprintf (file, _("no")); break; - default: fprintf (file, _("unknown: %x"), value); break; - } - fputc ('\n', file); - break; - - case V850_NOTE_CACHE_INFO: - fprintf (file, _("CACHE use: ")); - switch (value) - { - case EF_RH850_CACHE: fprintf (file, _("yes")); break; - case 0: fprintf (file, _("no")); break; - default: fprintf (file, _("unknown: %x"), value); break; - } - fputc ('\n', file); - break; - - case V850_NOTE_MMU_INFO: - fprintf (file, _("MMU use: ")); - switch (value) - { - case EF_RH850_MMU: fprintf (file, _("yes")); break; - case 0: fprintf (file, _("no")); break; - default: fprintf (file, _("unknown: %x"), value); break; - } - fputc ('\n', file); - break; - - default: - BFD_ASSERT (0); - } -} - -static void -v850_elf_print_notes (bfd * abfd, FILE * file) -{ - asection * notes = bfd_get_section_by_name (abfd, V850_NOTE_SECNAME); - enum v850_notes id; - - if (notes == NULL || notes->contents == NULL) - return; - - BFD_ASSERT (bfd_section_size (abfd, notes) == NUM_V850_NOTES * SIZEOF_V850_NOTE); - - for (id = V850_NOTE_ALIGNMENT; id <= NUM_V850_NOTES; id++) - print_v850_note (abfd, file, notes->contents, id); -} - -/* Set the right machine number and architecture. */ - -static bfd_boolean -v850_elf_object_p (bfd *abfd) -{ - enum bfd_architecture arch; - unsigned long mach; - - switch (elf_elfheader (abfd)->e_machine) - { - case EM_V800: - arch = bfd_arch_v850_rh850; - mach = (elf_elfheader (abfd)->e_flags & EF_V800_850E3) - ? bfd_mach_v850e3v5 : bfd_mach_v850e2v3; - break; - - case EM_CYGNUS_V850: - case EM_V850: - arch = bfd_arch_v850; - switch (elf_elfheader (abfd)->e_flags & EF_V850_ARCH) - { - default: - case E_V850_ARCH: mach = bfd_mach_v850; break; - case E_V850E_ARCH: mach = bfd_mach_v850e; break; - case E_V850E1_ARCH: mach = bfd_mach_v850e1; break; - case E_V850E2_ARCH: mach = bfd_mach_v850e2; break; - case E_V850E2V3_ARCH: mach = bfd_mach_v850e2v3; break; - case E_V850E3V5_ARCH: mach = bfd_mach_v850e3v5; break; - } - break; - - default: - return FALSE; - } - - return bfd_default_set_arch_mach (abfd, arch, mach); -} - -/* Store the machine number in the flags field. */ - -static void -v850_elf_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_arch (abfd)) - { - case bfd_arch_v850_rh850: - val = EF_RH850_ABI; - if (bfd_get_mach (abfd) == bfd_mach_v850e3v5) - val |= EF_V800_850E3; - elf_elfheader (abfd)->e_flags |= val; - break; - - case bfd_arch_v850: - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_v850: val = E_V850_ARCH; break; - case bfd_mach_v850e: val = E_V850E_ARCH; break; - case bfd_mach_v850e1: val = E_V850E1_ARCH; break; - case bfd_mach_v850e2: val = E_V850E2_ARCH; break; - case bfd_mach_v850e2v3: val = E_V850E2V3_ARCH; break; - case bfd_mach_v850e3v5: val = E_V850E3V5_ARCH; break; - } - elf_elfheader (abfd)->e_flags &=~ EF_V850_ARCH; - elf_elfheader (abfd)->e_flags |= val; - break; - default: - break; - } -} - -/* Function to keep V850 specific file flags. */ - -static bfd_boolean -v850_elf_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file - to the output object file when linking. */ - -static bfd_boolean -v850_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - bfd_boolean result = TRUE; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - result &= v850_elf_merge_notes (ibfd, obfd); - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - /* If the input is the default architecture then do not - bother setting the flags for the output architecture, - instead allow future merges to do this. If no future - merges ever set these flags then they will retain their - unitialised values, which surprise surprise, correspond - to the default values. */ - if (bfd_get_arch_info (ibfd)->the_default) - return TRUE; - - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - result &= bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd)); - - return result; - } - - /* Check flag compatibility. */ - if (in_flags == out_flags) - return result; - - if (bfd_get_arch (obfd) == bfd_arch_v850_rh850) - { - if ((in_flags & EF_V800_850E3) != (out_flags & EF_V800_850E3)) - { - _bfd_error_handler - (_("%B: Architecture mismatch with previous modules"), ibfd); - elf_elfheader (obfd)->e_flags |= EF_V800_850E3; - } - - return result; - } - - if ((in_flags & EF_V850_ARCH) != (out_flags & EF_V850_ARCH) - && (in_flags & EF_V850_ARCH) != E_V850_ARCH) - { - /* Allow earlier architecture binaries to be linked with later binaries. - Set the output binary to the later architecture, except for v850e1, - which we set to v850e. */ - if ( (in_flags & EF_V850_ARCH) == E_V850E1_ARCH - && (out_flags & EF_V850_ARCH) == E_V850E_ARCH) - return result; - - if ( (in_flags & EF_V850_ARCH) == E_V850_ARCH - && (out_flags & EF_V850_ARCH) == E_V850E_ARCH) - { - elf_elfheader (obfd)->e_flags = - ((out_flags & ~ EF_V850_ARCH) | E_V850E_ARCH); - return result; - } - - if (( (in_flags & EF_V850_ARCH) == E_V850_ARCH - || (in_flags & EF_V850_ARCH) == E_V850E_ARCH) - && (out_flags & EF_V850_ARCH) == E_V850E2_ARCH) - { - elf_elfheader (obfd)->e_flags = - ((out_flags & ~ EF_V850_ARCH) | E_V850E2_ARCH); - return result; - } - - if (( (in_flags & EF_V850_ARCH) == E_V850_ARCH - || (in_flags & EF_V850_ARCH) == E_V850E_ARCH - || (in_flags & EF_V850_ARCH) == E_V850E2_ARCH) - && (out_flags & EF_V850_ARCH) == E_V850E2V3_ARCH) - { - elf_elfheader (obfd)->e_flags = - ((out_flags & ~ EF_V850_ARCH) | E_V850E2V3_ARCH); - return result; - } - - if (( (in_flags & EF_V850_ARCH) == E_V850_ARCH - || (in_flags & EF_V850_ARCH) == E_V850E_ARCH - || (in_flags & EF_V850_ARCH) == E_V850E2_ARCH - || (in_flags & EF_V850_ARCH) == E_V850E2V3_ARCH) - && (out_flags & EF_V850_ARCH) == E_V850E3V5_ARCH) - { - elf_elfheader (obfd)->e_flags = - ((out_flags & ~ EF_V850_ARCH) | E_V850E3V5_ARCH); - return result; - } - - _bfd_error_handler - (_("%B: Architecture mismatch with previous modules"), ibfd); - } - - return result; -} - -/* Display the flags field. */ - -static bfd_boolean -v850_elf_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE * file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* xgettext:c-format. */ - fprintf (file, _("private flags = %lx: "), elf_elfheader (abfd)->e_flags); - - if (bfd_get_arch (abfd) == bfd_arch_v850_rh850) - { - if ((elf_elfheader (abfd)->e_flags & EF_RH850_ABI) != EF_RH850_ABI) - fprintf (file, _("unknown v850 architecture")); - else if (elf_elfheader (abfd)->e_flags & EF_V800_850E3) - fprintf (file, _("v850 E3 architecture")); - else - fprintf (file, _("v850 architecture")); - } - else - { - switch (elf_elfheader (abfd)->e_flags & EF_V850_ARCH) - { - default: - case E_V850_ARCH: fprintf (file, _("v850 architecture")); break; - case E_V850E_ARCH: fprintf (file, _("v850e architecture")); break; - case E_V850E1_ARCH: fprintf (file, _("v850e1 architecture")); break; - case E_V850E2_ARCH: fprintf (file, _("v850e2 architecture")); break; - case E_V850E2V3_ARCH: fprintf (file, _("v850e2v3 architecture")); break; - case E_V850E3V5_ARCH: fprintf (file, _("v850e3v5 architecture")); break; - } - } - - fputc ('\n', file); - - v850_elf_print_notes (abfd, file); - - return TRUE; -} - -/* V850 ELF uses four common sections. One is the usual one, and the - others are for (small) objects in one of the special data areas: - small, tiny and zero. All the objects are kept together, and then - referenced via the gp register, the ep register or the r0 register - respectively, which yields smaller, faster assembler code. This - approach is copied from elf32-mips.c. */ - -static asection v850_elf_scom_section; -static asymbol v850_elf_scom_symbol; -static asymbol * v850_elf_scom_symbol_ptr; -static asection v850_elf_tcom_section; -static asymbol v850_elf_tcom_symbol; -static asymbol * v850_elf_tcom_symbol_ptr; -static asection v850_elf_zcom_section; -static asymbol v850_elf_zcom_symbol; -static asymbol * v850_elf_zcom_symbol_ptr; - -/* Given a BFD section, try to locate the - corresponding ELF section index. */ - -static bfd_boolean -v850_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - int *retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) - *retval = SHN_V850_SCOMMON; - else if (strcmp (bfd_get_section_name (abfd, sec), ".tcommon") == 0) - *retval = SHN_V850_TCOMMON; - else if (strcmp (bfd_get_section_name (abfd, sec), ".zcommon") == 0) - *retval = SHN_V850_ZCOMMON; - else - return FALSE; - - return TRUE; -} - -/* Handle the special V850 section numbers that a symbol may use. */ - -static void -v850_elf_symbol_processing (bfd *abfd, asymbol *asym) -{ - elf_symbol_type * elfsym = (elf_symbol_type *) asym; - unsigned int indx; - - indx = elfsym->internal_elf_sym.st_shndx; - - /* If the section index is an "ordinary" index, then it may - refer to a v850 specific section created by the assembler. - Check the section's type and change the index it matches. - - FIXME: Should we alter the st_shndx field as well ? */ - - if (indx < elf_numsections (abfd)) - switch (elf_elfsections (abfd)[indx]->sh_type) - { - case SHT_V850_SCOMMON: - indx = SHN_V850_SCOMMON; - break; - - case SHT_V850_TCOMMON: - indx = SHN_V850_TCOMMON; - break; - - case SHT_V850_ZCOMMON: - indx = SHN_V850_ZCOMMON; - break; - - default: - break; - } - - switch (indx) - { - case SHN_V850_SCOMMON: - if (v850_elf_scom_section.name == NULL) - { - /* Initialize the small common section. */ - v850_elf_scom_section.name = ".scommon"; - v850_elf_scom_section.flags = SEC_IS_COMMON | SEC_ALLOC | SEC_DATA; - v850_elf_scom_section.output_section = & v850_elf_scom_section; - v850_elf_scom_section.symbol = & v850_elf_scom_symbol; - v850_elf_scom_section.symbol_ptr_ptr = & v850_elf_scom_symbol_ptr; - v850_elf_scom_symbol.name = ".scommon"; - v850_elf_scom_symbol.flags = BSF_SECTION_SYM; - v850_elf_scom_symbol.section = & v850_elf_scom_section; - v850_elf_scom_symbol_ptr = & v850_elf_scom_symbol; - } - asym->section = & v850_elf_scom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - - case SHN_V850_TCOMMON: - if (v850_elf_tcom_section.name == NULL) - { - /* Initialize the tcommon section. */ - v850_elf_tcom_section.name = ".tcommon"; - v850_elf_tcom_section.flags = SEC_IS_COMMON; - v850_elf_tcom_section.output_section = & v850_elf_tcom_section; - v850_elf_tcom_section.symbol = & v850_elf_tcom_symbol; - v850_elf_tcom_section.symbol_ptr_ptr = & v850_elf_tcom_symbol_ptr; - v850_elf_tcom_symbol.name = ".tcommon"; - v850_elf_tcom_symbol.flags = BSF_SECTION_SYM; - v850_elf_tcom_symbol.section = & v850_elf_tcom_section; - v850_elf_tcom_symbol_ptr = & v850_elf_tcom_symbol; - } - asym->section = & v850_elf_tcom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - - case SHN_V850_ZCOMMON: - if (v850_elf_zcom_section.name == NULL) - { - /* Initialize the zcommon section. */ - v850_elf_zcom_section.name = ".zcommon"; - v850_elf_zcom_section.flags = SEC_IS_COMMON; - v850_elf_zcom_section.output_section = & v850_elf_zcom_section; - v850_elf_zcom_section.symbol = & v850_elf_zcom_symbol; - v850_elf_zcom_section.symbol_ptr_ptr = & v850_elf_zcom_symbol_ptr; - v850_elf_zcom_symbol.name = ".zcommon"; - v850_elf_zcom_symbol.flags = BSF_SECTION_SYM; - v850_elf_zcom_symbol.section = & v850_elf_zcom_section; - v850_elf_zcom_symbol_ptr = & v850_elf_zcom_symbol; - } - asym->section = & v850_elf_zcom_section; - asym->value = elfsym->internal_elf_sym.st_size; - break; - } -} - -/* Hook called by the linker routine which adds symbols from an object - file. We must handle the special v850 section numbers here. */ - -static bfd_boolean -v850_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - unsigned int indx = sym->st_shndx; - - /* If the section index is an "ordinary" index, then it may - refer to a v850 specific section created by the assembler. - Check the section's type and change the index it matches. - - FIXME: Should we alter the st_shndx field as well ? */ - - if (indx < elf_numsections (abfd)) - switch (elf_elfsections (abfd)[indx]->sh_type) - { - case SHT_V850_SCOMMON: - indx = SHN_V850_SCOMMON; - break; - - case SHT_V850_TCOMMON: - indx = SHN_V850_TCOMMON; - break; - - case SHT_V850_ZCOMMON: - indx = SHN_V850_ZCOMMON; - break; - - default: - break; - } - - switch (indx) - { - case SHN_V850_SCOMMON: - *secp = bfd_make_section_old_way (abfd, ".scommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - - case SHN_V850_TCOMMON: - *secp = bfd_make_section_old_way (abfd, ".tcommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - - case SHN_V850_ZCOMMON: - *secp = bfd_make_section_old_way (abfd, ".zcommon"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - -static int -v850_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - /* If we see a common symbol, which implies a relocatable link, then - if a symbol was in a special common section in an input file, mark - it as a special common in the output file. */ - - if (sym->st_shndx == SHN_COMMON) - { - if (strcmp (input_sec->name, ".scommon") == 0) - sym->st_shndx = SHN_V850_SCOMMON; - else if (strcmp (input_sec->name, ".tcommon") == 0) - sym->st_shndx = SHN_V850_TCOMMON; - else if (strcmp (input_sec->name, ".zcommon") == 0) - sym->st_shndx = SHN_V850_ZCOMMON; - } - - /* The price we pay for using h->other unused bits as flags in the - linker is cleaning up after ourselves. */ - - sym->st_other &= ~(V850_OTHER_SDA | V850_OTHER_ZDA | V850_OTHER_TDA - | V850_OTHER_ERROR); - - return 1; -} - -static bfd_boolean -v850_elf_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) -{ - /* There ought to be a place to keep ELF backend specific flags, but - at the moment there isn't one. We just keep track of the - sections by their name, instead. */ - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - switch (hdr->sh_type) - { - case SHT_V850_SCOMMON: - case SHT_V850_TCOMMON: - case SHT_V850_ZCOMMON: - if (! bfd_set_section_flags (abfd, hdr->bfd_section, - (bfd_get_section_flags (abfd, - hdr->bfd_section) - | SEC_IS_COMMON))) - return FALSE; - } - - return TRUE; -} - -/* Set the correct type for a V850 ELF section. We do this - by the section name, which is a hack, but ought to work. */ - -static bfd_boolean -v850_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr, - asection *sec) -{ - const char * name; - - name = bfd_get_section_name (abfd, sec); - - if (strcmp (name, ".scommon") == 0) - hdr->sh_type = SHT_V850_SCOMMON; - else if (strcmp (name, ".tcommon") == 0) - hdr->sh_type = SHT_V850_TCOMMON; - else if (strcmp (name, ".zcommon") == 0) - hdr->sh_type = SHT_V850_ZCOMMON; - /* Tweak the section type of .note.renesas. */ - else if (strcmp (name, V850_NOTE_SECNAME) == 0) - { - hdr->sh_type = SHT_RENESAS_INFO; - hdr->sh_entsize = SIZEOF_V850_NOTE; - } - - return TRUE; -} - -/* Delete some bytes from a section while relaxing. */ - -static bfd_boolean -v850_elf_relax_delete_bytes (bfd *abfd, - asection *sec, - bfd_vma addr, - bfd_vma toaddr, - int count) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf32_External_Sym *extsyms; - Elf32_External_Sym *esym; - Elf32_External_Sym *esymend; - int sym_index; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - struct elf_link_hash_entry *sym_hash; - Elf_External_Sym_Shndx *shndx; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - extsyms = (Elf32_External_Sym *) symtab_hdr->contents; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - contents = elf_section_data (sec)->this_hdr.contents; - - /* The deletion must stop at the next ALIGN reloc for an alignment - power larger than the number of bytes we are deleting. */ - - /* Actually delete the bytes. */ -#if (DEBUG_RELAX & 2) - fprintf (stderr, "relax_delete: contents: sec: %s %p .. %p %x\n", - sec->name, addr, toaddr, count ); -#endif - memmove (contents + addr, contents + addr + count, - toaddr - addr - count); - memset (contents + toaddr-count, 0, count); - - /* Adjust all the relocs. */ - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - if (elf_symtab_shndx_list (abfd)) - { - Elf_Internal_Shdr *shndx_hdr; - - shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; - shndx = (Elf_External_Sym_Shndx *) shndx_hdr->contents; - } - else - { - shndx = NULL; - } - - for (; irel < irelend; irel++) - { - bfd_vma raddr, paddr, symval; - Elf_Internal_Sym isym; - - /* Get the new reloc address. */ - raddr = irel->r_offset; - if ((raddr >= (addr + count) && raddr < toaddr)) - irel->r_offset -= count; - - if (raddr >= addr && raddr < addr + count) - { - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - (int) R_V850_NONE); - continue; - } - - if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN) - continue; - - bfd_elf32_swap_symbol_in (abfd, - extsyms + ELF32_R_SYM (irel->r_info), - shndx ? shndx + ELF32_R_SYM (irel->r_info) : NULL, - & isym); - - if (isym.st_shndx != sec_shndx) - continue; - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - symval = isym.st_value; -#if (DEBUG_RELAX & 2) - { - char * name = bfd_elf_string_from_elf_section - (abfd, symtab_hdr->sh_link, isym.st_name); - fprintf (stderr, - "relax_delete: local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n", - sec->name, name, isym.st_name, - sec->output_section->vma, sec->output_offset, - isym.st_value, irel->r_addend); - } -#endif - } - else - { - unsigned long indx; - struct elf_link_hash_entry * h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - - h = elf_sym_hashes (abfd) [indx]; - BFD_ASSERT (h != NULL); - - symval = h->root.u.def.value; -#if (DEBUG_RELAX & 2) - fprintf (stderr, - "relax_delete: defined: sec: %s, name: %s, value: %x + %x + %x addend %x\n", - sec->name, h->root.root.string, h->root.u.def.value, - sec->output_section->vma, sec->output_offset, irel->r_addend); -#endif - } - - paddr = symval + irel->r_addend; - - if ( (symval >= addr + count && symval < toaddr) - && (paddr < addr + count || paddr >= toaddr)) - irel->r_addend += count; - else if ( (symval < addr + count || symval >= toaddr) - && (paddr >= addr + count && paddr < toaddr)) - irel->r_addend -= count; - } - - /* Adjust the local symbols defined in this section. */ - esym = extsyms; - esymend = esym + symtab_hdr->sh_info; - - for (; esym < esymend; esym++, shndx = (shndx ? shndx + 1 : NULL)) - { - Elf_Internal_Sym isym; - - bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym); - - if (isym.st_shndx == sec_shndx - && isym.st_value >= addr + count - && isym.st_value < toaddr) - { - isym.st_value -= count; - - if (isym.st_value + isym.st_size >= toaddr) - isym.st_size += count; - - bfd_elf32_swap_symbol_out (abfd, & isym, esym, shndx); - } - else if (isym.st_shndx == sec_shndx - && isym.st_value < addr + count) - { - if (isym.st_value+isym.st_size >= addr + count - && isym.st_value+isym.st_size < toaddr) - isym.st_size -= count; - - if (isym.st_value >= addr - && isym.st_value < addr + count) - isym.st_value = addr; - - bfd_elf32_swap_symbol_out (abfd, & isym, esym, shndx); - } - } - - /* Now adjust the global symbols defined in this section. */ - esym = extsyms + symtab_hdr->sh_info; - esymend = extsyms + (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)); - - for (sym_index = 0; esym < esymend; esym ++, sym_index ++) - { - Elf_Internal_Sym isym; - - bfd_elf32_swap_symbol_in (abfd, esym, shndx, & isym); - sym_hash = elf_sym_hashes (abfd) [sym_index]; - - if (isym.st_shndx == sec_shndx - && ((sym_hash)->root.type == bfd_link_hash_defined - || (sym_hash)->root.type == bfd_link_hash_defweak) - && (sym_hash)->root.u.def.section == sec - && (sym_hash)->root.u.def.value >= addr + count - && (sym_hash)->root.u.def.value < toaddr) - { - if ((sym_hash)->root.u.def.value + isym.st_size >= toaddr) - { - isym.st_size += count; - bfd_elf32_swap_symbol_out (abfd, & isym, esym, shndx); - } - - (sym_hash)->root.u.def.value -= count; - } - else if (isym.st_shndx == sec_shndx - && ((sym_hash)->root.type == bfd_link_hash_defined - || (sym_hash)->root.type == bfd_link_hash_defweak) - && (sym_hash)->root.u.def.section == sec - && (sym_hash)->root.u.def.value < addr + count) - { - if ((sym_hash)->root.u.def.value+isym.st_size >= addr + count - && (sym_hash)->root.u.def.value+isym.st_size < toaddr) - isym.st_size -= count; - - if ((sym_hash)->root.u.def.value >= addr - && (sym_hash)->root.u.def.value < addr + count) - (sym_hash)->root.u.def.value = addr; - - bfd_elf32_swap_symbol_out (abfd, & isym, esym, shndx); - } - - if (shndx) - ++ shndx; - } - - return TRUE; -} - -#define NOP_OPCODE (0x0000) -#define MOVHI 0x0640 /* 4byte. */ -#define MOVHI_MASK 0x07e0 -#define MOVHI_R1(insn) ((insn) & 0x1f) /* 4byte. */ -#define MOVHI_R2(insn) ((insn) >> 11) -#define MOVEA 0x0620 /* 2byte. */ -#define MOVEA_MASK 0x07e0 -#define MOVEA_R1(insn) ((insn) & 0x1f) -#define MOVEA_R2(insn) ((insn) >> 11) -#define JARL_4 0x00040780 /* 4byte. */ -#define JARL_4_MASK 0xFFFF07FF -#define JARL_R2(insn) (int)(((insn) & (~JARL_4_MASK)) >> 11) -#define ADD_I 0x0240 /* 2byte. */ -#define ADD_I_MASK 0x07e0 -#define ADD_I5(insn) ((((insn) & 0x001f) << 11) >> 11) /* 2byte. */ -#define ADD_R2(insn) ((insn) >> 11) -#define JMP_R 0x0060 /* 2byte. */ -#define JMP_R_MASK 0xFFE0 -#define JMP_R1(insn) ((insn) & 0x1f) - -static bfd_boolean -v850_elf_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Rela *irelalign = NULL; - Elf_Internal_Sym *isymbuf = NULL; - bfd_byte *contents = NULL; - bfd_vma addr = 0; - bfd_vma toaddr; - int align_pad_size = 0; - bfd_boolean result = TRUE; - - *again = FALSE; - - if (bfd_link_relocatable (link_info) - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0) - return TRUE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, NULL, link_info->keep_memory)); - if (internal_relocs == NULL) - goto error_return; - - irelend = internal_relocs + sec->reloc_count; - - while (addr < sec->size) - { - toaddr = sec->size; - - for (irel = internal_relocs; irel < irelend; irel ++) - if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN - && irel->r_offset > addr - && irel->r_offset < toaddr) - toaddr = irel->r_offset; - -#ifdef DEBUG_RELAX - fprintf (stderr, "relax region 0x%x to 0x%x align pad %d\n", - addr, toaddr, align_pad_size); -#endif - if (irelalign) - { - bfd_vma alignto; - bfd_vma alignmoveto; - - alignmoveto = BFD_ALIGN (addr - align_pad_size, 1 << irelalign->r_addend); - alignto = BFD_ALIGN (addr, 1 << irelalign->r_addend); - - if (alignmoveto < alignto) - { - bfd_vma i; - - align_pad_size = alignto - alignmoveto; -#ifdef DEBUG_RELAX - fprintf (stderr, "relax move region 0x%x to 0x%x delete size 0x%x\n", - alignmoveto, toaddr, align_pad_size); -#endif - if (!v850_elf_relax_delete_bytes (abfd, sec, alignmoveto, - toaddr, align_pad_size)) - goto error_return; - - for (i = BFD_ALIGN (toaddr - align_pad_size, 1); - (i + 1) < toaddr; i += 2) - bfd_put_16 (abfd, NOP_OPCODE, contents + i); - - addr = alignmoveto; - } - else - align_pad_size = 0; - } - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma laddr; - bfd_vma addend; - bfd_vma symval; - int insn[5]; - int no_match = -1; - Elf_Internal_Rela *hi_irelfn; - Elf_Internal_Rela *lo_irelfn; - Elf_Internal_Rela *irelcall; - bfd_signed_vma foff; - unsigned int r_type; - - if (! (irel->r_offset >= addr && irel->r_offset < toaddr - && (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGCALL - || ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGJUMP))) - continue; - -#ifdef DEBUG_RELAX - fprintf (stderr, "relax check r_info 0x%x r_offset 0x%x r_addend 0x%x\n", - irel->r_info, - irel->r_offset, - irel->r_addend ); -#endif - - /* Get the section contents. */ - if (contents == NULL) - { - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - } - - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - laddr = irel->r_offset; - - if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGCALL) - { - /* Check code for -mlong-calls output. */ - if (laddr + 16 <= (bfd_vma) sec->size) - { - insn[0] = bfd_get_16 (abfd, contents + laddr); - insn[1] = bfd_get_16 (abfd, contents + laddr + 4); - insn[2] = bfd_get_32 (abfd, contents + laddr + 8); - insn[3] = bfd_get_16 (abfd, contents + laddr + 12); - insn[4] = bfd_get_16 (abfd, contents + laddr + 14); - - if ((insn[0] & MOVHI_MASK) != MOVHI - || MOVHI_R1 (insn[0]) != 0) - no_match = 0; - - if (no_match < 0 - && ((insn[1] & MOVEA_MASK) != MOVEA - || MOVHI_R2 (insn[0]) != MOVEA_R1 (insn[1]))) - no_match = 1; - - if (no_match < 0 - && (insn[2] & JARL_4_MASK) != JARL_4) - no_match = 2; - - if (no_match < 0 - && ((insn[3] & ADD_I_MASK) != ADD_I - || ADD_I5 (insn[3]) != 4 - || JARL_R2 (insn[2]) != ADD_R2 (insn[3]))) - no_match = 3; - - if (no_match < 0 - && ((insn[4] & JMP_R_MASK) != JMP_R - || MOVEA_R2 (insn[1]) != JMP_R1 (insn[4]))) - no_match = 4; - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGCALL points to " - "unrecognized insns"), - abfd, irel->r_offset); - continue; - } - - if (no_match >= 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGCALL points to " - "unrecognized insn %#x"), - abfd, - irel->r_offset + no_match, - insn[no_match]); - continue; - } - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - - for (hi_irelfn = internal_relocs; hi_irelfn < irelend; hi_irelfn ++) - { - r_type = ELF32_R_TYPE (hi_irelfn->r_info); - - if (hi_irelfn->r_offset == laddr + 2 - && (r_type == (int) R_V850_HI16_S || r_type == (int) R_V810_WHI1)) - break; - } - - for (lo_irelfn = internal_relocs; lo_irelfn < irelend; lo_irelfn ++) - { - r_type = ELF32_R_TYPE (lo_irelfn->r_info); - - if (lo_irelfn->r_offset == laddr + 6 - && (r_type == (int) R_V850_LO16 || r_type == (int) R_V810_WLO)) - break; - } - - for (irelcall = internal_relocs; irelcall < irelend; irelcall ++) - { - r_type = ELF32_R_TYPE (irelcall->r_info); - - if (irelcall->r_offset == laddr + 8 - && (r_type == (int) R_V850_22_PCREL || r_type == (int) R_V850_PCR22)) - break; - } - - if ( hi_irelfn == irelend - || lo_irelfn == irelend - || irelcall == irelend) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGCALL points to " - "unrecognized reloc"), - abfd, irel->r_offset); - - continue; - } - - if (ELF32_R_SYM (irelcall->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym * isym; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (irelcall->r_info); - - symval = isym->st_value; - } - else - { - unsigned long indx; - struct elf_link_hash_entry * h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irelcall->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if ( h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = h->root.u.def.value; - } - - if (symval + irelcall->r_addend != irelcall->r_offset + 4) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGCALL points to " - "unrecognized reloc %#Lx"), - abfd, irel->r_offset, - irelcall->r_offset); - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isym; - asection *sym_sec; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (hi_irelfn->r_info); - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if ( h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - addend = irel->r_addend; - - foff = (symval + addend - - (irel->r_offset - + sec->output_section->vma - + sec->output_offset - + 4)); -#ifdef DEBUG_RELAX - fprintf (stderr, "relax longcall r_offset 0x%x ptr 0x%x symbol 0x%x addend 0x%x distance 0x%x\n", - irel->r_offset, - (irel->r_offset - + sec->output_section->vma - + sec->output_offset), - symval, addend, foff); -#endif - - if (foff < -0x100000 || foff >= 0x100000) - /* After all that work, we can't shorten this function call. */ - continue; - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (bfd_byte *) isymbuf; - - /* Replace the long call with a jarl. */ - if (bfd_get_arch (abfd) == bfd_arch_v850_rh850) - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_PCR22); - else - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_22_PCREL); - - addend = 0; - - if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info) - /* If this needs to be changed because of future relaxing, - it will be handled here like other internal IND12W - relocs. */ - bfd_put_32 (abfd, - 0x00000780 | (JARL_R2 (insn[2])<<11) | ((addend << 16) & 0xffff) | ((addend >> 16) & 0xf), - contents + irel->r_offset); - else - /* We can't fully resolve this yet, because the external - symbol value may be changed by future relaxing. - We let the final link phase handle it. */ - bfd_put_32 (abfd, 0x00000780 | (JARL_R2 (insn[2])<<11), - contents + irel->r_offset); - - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE); - irelcall->r_info = - ELF32_R_INFO (ELF32_R_SYM (irelcall->r_info), R_V850_NONE); - - if (! v850_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 4, toaddr, 12)) - goto error_return; - - align_pad_size += 12; - } - else if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_LONGJUMP) - { - /* Check code for -mlong-jumps output. */ - if (laddr + 10 <= (bfd_vma) sec->size) - { - insn[0] = bfd_get_16 (abfd, contents + laddr); - insn[1] = bfd_get_16 (abfd, contents + laddr + 4); - insn[2] = bfd_get_16 (abfd, contents + laddr + 8); - - if ((insn[0] & MOVHI_MASK) != MOVHI - || MOVHI_R1 (insn[0]) != 0) - no_match = 0; - - if (no_match < 0 - && ((insn[1] & MOVEA_MASK) != MOVEA - || MOVHI_R2 (insn[0]) != MOVEA_R1 (insn[1]))) - no_match = 1; - - if (no_match < 0 - && ((insn[2] & JMP_R_MASK) != JMP_R - || MOVEA_R2 (insn[1]) != JMP_R1 (insn[2]))) - no_match = 4; - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGJUMP points to " - "unrecognized insns"), - abfd, irel->r_offset); - continue; - } - - if (no_match >= 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGJUMP points to " - "unrecognized insn %#x"), - abfd, - irel->r_offset + no_match, - insn[no_match]); - continue; - } - - /* Get the reloc for the address from which the register is - being loaded. This reloc will tell us which function is - actually being called. */ - for (hi_irelfn = internal_relocs; hi_irelfn < irelend; hi_irelfn ++) - { - r_type = ELF32_R_TYPE (hi_irelfn->r_info); - - if (hi_irelfn->r_offset == laddr + 2 - && ((r_type == (int) R_V850_HI16_S) || r_type == (int) R_V810_WHI1)) - break; - } - - for (lo_irelfn = internal_relocs; lo_irelfn < irelend; lo_irelfn ++) - { - r_type = ELF32_R_TYPE (lo_irelfn->r_info); - - if (lo_irelfn->r_offset == laddr + 6 - && (r_type == (int) R_V850_LO16 || r_type == (int) R_V810_WLO)) - break; - } - - if ( hi_irelfn == irelend - || lo_irelfn == irelend) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %#Lx: warning: R_V850_LONGJUMP points to " - "unrecognized reloc"), - abfd, irel->r_offset); - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info) - { - Elf_Internal_Sym * isym; - asection * sym_sec; - - /* A local symbol. */ - isym = isymbuf + ELF32_R_SYM (hi_irelfn->r_info); - - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); -#ifdef DEBUG_RELAX - { - char * name = bfd_elf_string_from_elf_section - (abfd, symtab_hdr->sh_link, isym->st_name); - - fprintf (stderr, "relax long jump local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n", - sym_sec->name, name, isym->st_name, - sym_sec->output_section->vma, - sym_sec->output_offset, - isym->st_value, irel->r_addend); - } -#endif - } - else - { - unsigned long indx; - struct elf_link_hash_entry * h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if ( h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); -#ifdef DEBUG_RELAX - fprintf (stderr, - "relax longjump defined: sec: %s, name: %s, value: %x + %x + %x addend %x\n", - sec->name, h->root.root.string, h->root.u.def.value, - sec->output_section->vma, sec->output_offset, irel->r_addend); -#endif - } - - addend = irel->r_addend; - - foff = (symval + addend - - (irel->r_offset - + sec->output_section->vma - + sec->output_offset - + 4)); -#ifdef DEBUG_RELAX - fprintf (stderr, "relax longjump r_offset 0x%x ptr 0x%x symbol 0x%x addend 0x%x distance 0x%x\n", - irel->r_offset, - (irel->r_offset - + sec->output_section->vma - + sec->output_offset), - symval, addend, foff); -#endif - if (foff < -0x100000 || foff >= 0x100000) - /* After all that work, we can't shorten this function call. */ - continue; - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (bfd_byte *) isymbuf; - - if (foff < -0x100 || foff >= 0x100) - { - /* Replace the long jump with a jr. */ - - if (bfd_get_arch (abfd) == bfd_arch_v850_rh850) - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_PCR22); - else - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_22_PCREL); - - irel->r_addend = addend; - addend = 0; - - if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info) - /* If this needs to be changed because of future relaxing, - it will be handled here like other internal IND12W - relocs. */ - bfd_put_32 (abfd, - 0x00000780 | ((addend << 15) & 0xffff0000) | ((addend >> 17) & 0xf), - contents + irel->r_offset); - else - /* We can't fully resolve this yet, because the external - symbol value may be changed by future relaxing. - We let the final link phase handle it. */ - bfd_put_32 (abfd, 0x00000780, contents + irel->r_offset); - - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE); - if (!v850_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 4, toaddr, 6)) - goto error_return; - - align_pad_size += 6; - } - else - { - /* Replace the long jump with a br. */ - - if (bfd_get_arch (abfd) == bfd_arch_v850_rh850) - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_PC9); - else - irel->r_info = - ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_V850_9_PCREL); - - irel->r_addend = addend; - addend = 0; - - if (ELF32_R_SYM (hi_irelfn->r_info) < symtab_hdr->sh_info) - /* If this needs to be changed because of future relaxing, - it will be handled here like other internal IND12W - relocs. */ - bfd_put_16 (abfd, - 0x0585 | ((addend << 10) & 0xf800) | ((addend << 3) & 0x0070), - contents + irel->r_offset); - else - /* We can't fully resolve this yet, because the external - symbol value may be changed by future relaxing. - We let the final link phase handle it. */ - bfd_put_16 (abfd, 0x0585, contents + irel->r_offset); - - hi_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_V850_NONE); - lo_irelfn->r_info = - ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_V850_NONE); - if (!v850_elf_relax_delete_bytes (abfd, sec, - irel->r_offset + 2, toaddr, 8)) - goto error_return; - - align_pad_size += 8; - } - } - } - - irelalign = NULL; - for (irel = internal_relocs; irel < irelend; irel++) - { - if (ELF32_R_TYPE (irel->r_info) == (int) R_V850_ALIGN - && irel->r_offset == toaddr) - { - irel->r_offset -= align_pad_size; - - if (irelalign == NULL || irelalign->r_addend > irel->r_addend) - irelalign = irel; - } - } - - addr = toaddr; - } - - if (!irelalign) - { -#ifdef DEBUG_RELAX - fprintf (stderr, "relax pad %d shorten %d -> %d\n", - align_pad_size, - sec->size, - sec->size - align_pad_size); -#endif - sec->size -= align_pad_size; - } - - finish: - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != (unsigned char *) contents) - free (contents); - - if (isymbuf != NULL - && symtab_hdr->contents != (bfd_byte *) isymbuf) - free (isymbuf); - - return result; - - error_return: - result = FALSE; - goto finish; -} - -static const struct bfd_elf_special_section v850_elf_special_sections[] = -{ - { STRING_COMMA_LEN (".call_table_data"), 0, SHT_PROGBITS, (SHF_ALLOC + SHF_WRITE) }, - { STRING_COMMA_LEN (".call_table_text"), 0, SHT_PROGBITS, (SHF_ALLOC + SHF_WRITE - + SHF_EXECINSTR) }, - { STRING_COMMA_LEN (".rosdata"), -2, SHT_PROGBITS, (SHF_ALLOC - + SHF_V850_GPREL) }, - { STRING_COMMA_LEN (".rozdata"), -2, SHT_PROGBITS, (SHF_ALLOC - + SHF_V850_R0REL) }, - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, (SHF_ALLOC + SHF_WRITE - + SHF_V850_GPREL) }, - { STRING_COMMA_LEN (".scommon"), -2, SHT_V850_SCOMMON, (SHF_ALLOC + SHF_WRITE - + SHF_V850_GPREL) }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, (SHF_ALLOC + SHF_WRITE - + SHF_V850_GPREL) }, - { STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, (SHF_ALLOC + SHF_WRITE - + SHF_V850_EPREL) }, - { STRING_COMMA_LEN (".tcommon"), -2, SHT_V850_TCOMMON, (SHF_ALLOC + SHF_WRITE - + SHF_V850_R0REL) }, - { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, (SHF_ALLOC + SHF_WRITE - + SHF_V850_EPREL) }, - { STRING_COMMA_LEN (".zbss"), -2, SHT_NOBITS, (SHF_ALLOC + SHF_WRITE - + SHF_V850_R0REL) }, - { STRING_COMMA_LEN (".zcommon"), -2, SHT_V850_ZCOMMON, (SHF_ALLOC + SHF_WRITE - + SHF_V850_R0REL) }, - { STRING_COMMA_LEN (".zdata"), -2, SHT_PROGBITS, (SHF_ALLOC + SHF_WRITE - + SHF_V850_R0REL) }, - { NULL, 0, 0, 0, 0 } -}; - -#define TARGET_LITTLE_SYM v850_elf32_vec -#define TARGET_LITTLE_NAME "elf32-v850" -#define ELF_ARCH bfd_arch_v850 -#define ELF_MACHINE_CODE EM_V850 -#define ELF_MACHINE_ALT1 EM_CYGNUS_V850 -#define ELF_MAXPAGESIZE 0x1000 - -#define elf_info_to_howto v850_elf_info_to_howto_rela -#define elf_info_to_howto_rel v850_elf_info_to_howto_rel - -#define elf_backend_check_relocs v850_elf_check_relocs -#define elf_backend_relocate_section v850_elf_relocate_section -#define elf_backend_object_p v850_elf_object_p -#define elf_backend_final_write_processing v850_elf_final_write_processing -#define elf_backend_section_from_bfd_section v850_elf_section_from_bfd_section -#define elf_backend_symbol_processing v850_elf_symbol_processing -#define elf_backend_add_symbol_hook v850_elf_add_symbol_hook -#define elf_backend_link_output_symbol_hook v850_elf_link_output_symbol_hook -#define elf_backend_section_from_shdr v850_elf_section_from_shdr -#define elf_backend_fake_sections v850_elf_fake_sections -#define elf_backend_gc_mark_hook v850_elf_gc_mark_hook -#define elf_backend_special_sections v850_elf_special_sections - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_is_local_label_name v850_elf_is_local_label_name -#define bfd_elf32_bfd_is_target_special_symbol v850_elf_is_target_special_symbol - -#define bfd_elf32_bfd_reloc_type_lookup v850_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup v850_elf_reloc_name_lookup -#define bfd_elf32_bfd_merge_private_bfd_data v850_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags v850_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data v850_elf_print_private_bfd_data -#define bfd_elf32_bfd_relax_section v850_elf_relax_section - -#define elf_symbol_leading_char '_' - -#undef elf32_bed -#define elf32_bed elf32_v850_bed - -#include "elf32-target.h" - -/* Map BFD reloc types to V800 ELF reloc types. */ - -static const struct v850_elf_reloc_map v800_elf_reloc_map[] = -{ - { BFD_RELOC_NONE, R_V810_NONE }, - { BFD_RELOC_8, R_V810_BYTE }, - { BFD_RELOC_16, R_V810_HWORD }, - { BFD_RELOC_32, R_V810_WORD }, - { BFD_RELOC_LO16, R_V810_WLO }, - { BFD_RELOC_HI16, R_V810_WHI }, - { BFD_RELOC_HI16_S, R_V810_WHI1 }, - { BFD_RELOC_V850_32_PCREL, R_V850_PC32 }, - { BFD_RELOC_V850_22_PCREL, R_V850_PCR22 }, - { BFD_RELOC_V850_17_PCREL, R_V850_PC17 }, - { BFD_RELOC_V850_16_PCREL, R_V850_PC16U }, - { BFD_RELOC_V850_9_PCREL, R_V850_PC9 }, - { BFD_RELOC_V850_LO16_S1, R_V810_WLO_1 }, /* Or R_V850_HWLO or R_V850_HWLO_1. */ - { BFD_RELOC_V850_23, R_V850_WLO23 }, - { BFD_RELOC_V850_LO16_SPLIT_OFFSET, R_V850_BLO }, - { BFD_RELOC_V850_ZDA_16_16_OFFSET, R_V810_HWORD }, - { BFD_RELOC_V850_TDA_16_16_OFFSET, R_V810_HWORD }, - { BFD_RELOC_V850_SDA_16_16_OFFSET, R_V810_HWORD }, - { BFD_RELOC_V850_SDA_15_16_OFFSET, R_V810_GPWLO_1 } -}; - -/* Map a bfd relocation into the appropriate howto structure. */ - -static reloc_howto_type * -v800_elf_reloc_type_lookup (bfd * abfd, bfd_reloc_code_real_type code) -{ - unsigned int i; - - BFD_ASSERT (bfd_get_arch (abfd) == bfd_arch_v850_rh850); - - for (i = ARRAY_SIZE (v800_elf_reloc_map); i --;) - if (v800_elf_reloc_map[i].bfd_reloc_val == code) - { - unsigned int elf_reloc_val = v800_elf_reloc_map[i].elf_reloc_val; - unsigned int idx = elf_reloc_val - R_V810_NONE; - - BFD_ASSERT (v800_elf_howto_table[idx].type == elf_reloc_val); - - return v800_elf_howto_table + idx; - } - -#ifdef DEBUG - fprintf (stderr, "failed to find v800 equiv of bfd reloc code %d\n", code); -#endif - return NULL; -} - -static reloc_howto_type * -v800_elf_reloc_name_lookup (bfd * abfd, const char * r_name) -{ - unsigned int i; - - BFD_ASSERT (bfd_get_arch (abfd) == bfd_arch_v850_rh850); - - for (i = ARRAY_SIZE (v800_elf_howto_table); i--;) - if (v800_elf_howto_table[i].name != NULL - && strcasecmp (v800_elf_howto_table[i].name, r_name) == 0) - return v800_elf_howto_table + i; - - return NULL; -} - - -/* Set the howto pointer in CACHE_PTR for a V800 ELF reloc. */ - -static void -v800_elf_info_to_howto (bfd * abfd, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - - BFD_ASSERT (bfd_get_arch (abfd) == bfd_arch_v850_rh850); - - BFD_ASSERT (r_type < (unsigned int) R_V800_max); - - if (r_type == R_V800_NONE) - r_type = R_V810_NONE; - - BFD_ASSERT (r_type >= (unsigned int) R_V810_NONE); - r_type -= R_V810_NONE; - BFD_ASSERT (r_type < ARRAY_SIZE (v800_elf_howto_table)); - - cache_ptr->howto = v800_elf_howto_table + r_type; -} - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM v800_elf32_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-v850-rh850" -#undef ELF_ARCH -#define ELF_ARCH bfd_arch_v850_rh850 -#undef ELF_MACHINE_CODE -#define ELF_MACHINE_CODE EM_V800 -#undef ELF_MACHINE_ALT1 - -#undef elf32_bed -#define elf32_bed elf32_v850_rh850_bed - -#undef elf_info_to_howto -#define elf_info_to_howto v800_elf_info_to_howto -#undef elf_info_to_howto_rel -#define elf_info_to_howto_rel NULL -#undef bfd_elf32_bfd_reloc_type_lookup -#define bfd_elf32_bfd_reloc_type_lookup v800_elf_reloc_type_lookup -#undef bfd_elf32_bfd_reloc_name_lookup -#define bfd_elf32_bfd_reloc_name_lookup v800_elf_reloc_name_lookup - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-vax.c b/sdcc/support/sdbinutils/bfd/elf32-vax.c deleted file mode 100644 index 54364ed0e..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-vax.c +++ /dev/null @@ -1,1947 +0,0 @@ -/* VAX series support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - Contributed by Matt Thomas . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/vax.h" - -static reloc_howto_type *reloc_type_lookup (bfd *, bfd_reloc_code_real_type); -static void rtype_to_howto (bfd *, arelent *, Elf_Internal_Rela *); -static struct bfd_hash_entry *elf_vax_link_hash_newfunc (struct bfd_hash_entry *, - struct bfd_hash_table *, - const char *); -static struct bfd_link_hash_table *elf_vax_link_hash_table_create (bfd *); -static bfd_boolean elf_vax_check_relocs (bfd *, struct bfd_link_info *, - asection *, const Elf_Internal_Rela *); -static bfd_boolean elf_vax_adjust_dynamic_symbol (struct bfd_link_info *, - struct elf_link_hash_entry *); -static bfd_boolean elf_vax_size_dynamic_sections (bfd *, struct bfd_link_info *); -static bfd_boolean elf_vax_relocate_section (bfd *, struct bfd_link_info *, - bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, - Elf_Internal_Sym *, asection **); -static bfd_boolean elf_vax_finish_dynamic_symbol (bfd *, struct bfd_link_info *, - struct elf_link_hash_entry *, - Elf_Internal_Sym *); -static bfd_boolean elf_vax_finish_dynamic_sections (bfd *, - struct bfd_link_info *); -static bfd_vma elf_vax_plt_sym_val (bfd_vma, const asection *, - const arelent *); - -static bfd_boolean elf32_vax_set_private_flags (bfd *, flagword); -static bfd_boolean elf32_vax_print_private_bfd_data (bfd *, void *); - -static reloc_howto_type howto_table[] = { - HOWTO (R_VAX_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_PC32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_PC32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_VAX_PC16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_PC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_VAX_PC8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_PC8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000000ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_VAX_GOT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_GOT32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - - HOWTO (R_VAX_PLT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_PLT32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - EMPTY_HOWTO (-1), - - HOWTO (R_VAX_COPY, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_JMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_VAX_RELATIVE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VAX_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_VAX_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_VAX_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_VAX_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_VAX_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static void -rtype_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= R_VAX_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised VAX reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_VAX_NONE; - } - cache_ptr->howto = &howto_table[r_type]; -} - -#define elf_info_to_howto rtype_to_howto - -static const struct -{ - bfd_reloc_code_real_type bfd_val; - int elf_val; -} reloc_map[] = { - { BFD_RELOC_NONE, R_VAX_NONE }, - { BFD_RELOC_32, R_VAX_32 }, - { BFD_RELOC_16, R_VAX_16 }, - { BFD_RELOC_8, R_VAX_8 }, - { BFD_RELOC_32_PCREL, R_VAX_PC32 }, - { BFD_RELOC_16_PCREL, R_VAX_PC16 }, - { BFD_RELOC_8_PCREL, R_VAX_PC8 }, - { BFD_RELOC_32_GOT_PCREL, R_VAX_GOT32 }, - { BFD_RELOC_32_PLT_PCREL, R_VAX_PLT32 }, - { BFD_RELOC_NONE, R_VAX_COPY }, - { BFD_RELOC_VAX_GLOB_DAT, R_VAX_GLOB_DAT }, - { BFD_RELOC_VAX_JMP_SLOT, R_VAX_JMP_SLOT }, - { BFD_RELOC_VAX_RELATIVE, R_VAX_RELATIVE }, - { BFD_RELOC_CTOR, R_VAX_32 }, - { BFD_RELOC_VTABLE_INHERIT, R_VAX_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_VAX_GNU_VTENTRY }, -}; - -static reloc_howto_type * -reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) -{ - unsigned int i; - for (i = 0; i < sizeof (reloc_map) / sizeof (reloc_map[0]); i++) - { - if (reloc_map[i].bfd_val == code) - return &howto_table[reloc_map[i].elf_val]; - } - return 0; -} - -static reloc_howto_type * -reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) - if (howto_table[i].name != NULL - && strcasecmp (howto_table[i].name, r_name) == 0) - return &howto_table[i]; - - return NULL; -} - -#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup reloc_name_lookup -#define ELF_ARCH bfd_arch_vax -/* end code generated by elf.el */ - -/* Functions for the VAX ELF linker. */ - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/usr/libexec/ld.elf_so" - -/* The size in bytes of an entry in the procedure linkage table. */ - -#define PLT_ENTRY_SIZE 12 - -/* The first entry in a procedure linkage table looks like this. See - the SVR4 ABI VAX supplement to see how this works. */ - -static const bfd_byte elf_vax_plt0_entry[PLT_ENTRY_SIZE] = -{ - 0xdd, 0xef, /* pushl l^ */ - 0, 0, 0, 0, /* offset to .plt.got + 4 */ - 0x17, 0xff, /* jmp @L^(pc) */ - 0, 0, 0, 0, /* offset to .plt.got + 8 */ -}; - -/* Subsequent entries in a procedure linkage table look like this. */ - -static const bfd_byte elf_vax_plt_entry[PLT_ENTRY_SIZE] = -{ - 0xfc, 0x0f, /* .word ^M */ - 0x16, 0xef, /* jsb L^(pc) */ - 0, 0, 0, 0, /* replaced with offset to start of .plt */ - 0, 0, 0, 0, /* index into .rela.plt */ -}; - -/* The VAX linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that it - can discard PC relative relocs if it doesn't need them when linking - with -Bsymbolic. We store the information in a field extending the - regular ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we have - copied for a given symbol. */ - -struct elf_vax_pcrel_relocs_copied -{ - /* Next section. */ - struct elf_vax_pcrel_relocs_copied *next; - /* A section in dynobj. */ - asection *section; - /* Number of relocs copied in this section. */ - bfd_size_type count; -}; - -/* VAX ELF linker hash entry. */ - -struct elf_vax_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Number of PC relative relocs copied for this symbol. */ - struct elf_vax_pcrel_relocs_copied *pcrel_relocs_copied; - - bfd_vma got_addend; -}; - -/* Declare this now that the above structures are defined. */ - -static bfd_boolean elf_vax_discard_copies (struct elf_vax_link_hash_entry *, - void *); - -/* Declare this now that the above structures are defined. */ - -static bfd_boolean elf_vax_instantiate_got_entries (struct elf_link_hash_entry *, - void *); - -/* Traverse an VAX ELF linker hash table. */ - -#define elf_vax_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - ((table), \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* Create an entry in an VAX ELF linker hash table. */ - -static struct bfd_hash_entry * -elf_vax_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_vax_link_hash_entry *ret = - (struct elf_vax_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = ((struct elf_vax_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_vax_link_hash_entry))); - if (ret == NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_vax_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != NULL) - { - ret->pcrel_relocs_copied = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an VAX ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf_vax_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (ret, abfd, - elf_vax_link_hash_newfunc, - sizeof (struct elf_vax_link_hash_entry), - GENERIC_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root; -} - -/* Keep vax-specific flags in the ELF header */ -static bfd_boolean -elf32_vax_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ -static bfd_boolean -elf32_vax_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword in_flags; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - in_flags = elf_elfheader (ibfd)->e_flags; - - if (!elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - } - - return TRUE; -} - -/* Display the flags field */ -static bfd_boolean -elf32_vax_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* Ignore init flag - it may not be set, despite the flags field containing valid data. */ - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - if (elf_elfheader (abfd)->e_flags & EF_VAX_NONPIC) - fprintf (file, _(" [nonpic]")); - - if (elf_elfheader (abfd)->e_flags & EF_VAX_DFLOAT) - fprintf (file, _(" [d-float]")); - - if (elf_elfheader (abfd)->e_flags & EF_VAX_GFLOAT) - fprintf (file, _(" [g-float]")); - - fputc ('\n', file); - - return TRUE; -} -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -elf_vax_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - 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 (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - 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 long r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_VAX_GOT32: - BFD_ASSERT (h != NULL); - - /* If this is a local symbol, we resolve it directly without - creating a global offset table entry. */ - if (h->forced_local - || h == elf_hash_table (info)->hgot - || h == elf_hash_table (info)->hplt) - break; - - /* This symbol requires a global offset table entry. */ - - if (dynobj == NULL) - { - /* Create the .got section. */ - elf_hash_table (info)->dynobj = dynobj = abfd; - if (!_bfd_elf_create_got_section (dynobj, info)) - return FALSE; - } - - if (h != NULL) - { - struct elf_vax_link_hash_entry *eh; - - eh = (struct elf_vax_link_hash_entry *) h; - if (h->got.refcount == -1) - { - h->got.refcount = 1; - eh->got_addend = rel->r_addend; - } - else - { - h->got.refcount++; - if (eh->got_addend != (bfd_vma) rel->r_addend) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: GOT addend of %Ld to `%s' does" - " not match previous GOT addend of %Ld"), - abfd, rel->r_addend, h->root.root.string, - eh->got_addend); - - } - } - break; - - case R_VAX_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. */ - BFD_ASSERT (h != NULL); - - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - if (h->forced_local) - break; - - h->needs_plt = 1; - if (h->plt.refcount == -1) - h->plt.refcount = 1; - else - h->plt.refcount++; - break; - - case R_VAX_PC8: - case R_VAX_PC16: - case R_VAX_PC32: - /* If we are creating a shared library and this is not a local - symbol, we need to copy the reloc into the shared library. - However when linking with -Bsymbolic and this is a global - symbol which is defined in an object we are including in the - link (i.e., DEF_REGULAR is set), then we can resolve the - reloc directly. At this point we have not seen all the input - files, so it is possible that DEF_REGULAR is not set now but - will be set later (it is never cleared). We account for that - possibility below by storing information in the - pcrel_relocs_copied field of the hash table entry. */ - if (!(bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (!info->symbolic - || !h->def_regular))) - { - if (h != NULL - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !h->forced_local) - { - /* Make sure a plt entry is created for this symbol if - it turns out to be a function defined by a dynamic - object. */ - if (h->plt.refcount == -1) - h->plt.refcount = 1; - else - h->plt.refcount++; - } - break; - } - /* If this is a local symbol, we can resolve it directly. */ - if (h != NULL - && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || h->forced_local)) - break; - - /* Fall through. */ - case R_VAX_8: - case R_VAX_16: - case R_VAX_32: - if (h != NULL && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - { - /* Make sure a plt entry is created for this symbol if it - turns out to be a function defined by a dynamic object. */ - if (h->plt.refcount == -1) - h->plt.refcount = 1; - else - h->plt.refcount++; - } - - /* If we are creating a shared library, we need to copy the - reloc into the shared library. */ - if (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0) - { - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - - if (sec->flags & SEC_READONLY) - info->flags |= DF_TEXTREL; - } - - sreloc->size += sizeof (Elf32_External_Rela); - - /* If we are linking with -Bsymbolic, we count the number of - PC relative relocations we have entered for this symbol, - so that we can discard them again if the symbol is later - defined by a regular object. Note that this function is - only called if we are using a vaxelf linker hash table, - which means that h is really a pointer to an - elf_vax_link_hash_entry. */ - if ((ELF32_R_TYPE (rel->r_info) == R_VAX_PC8 - || ELF32_R_TYPE (rel->r_info) == R_VAX_PC16 - || ELF32_R_TYPE (rel->r_info) == R_VAX_PC32) - && info->symbolic) - { - struct elf_vax_link_hash_entry *eh; - struct elf_vax_pcrel_relocs_copied *p; - - eh = (struct elf_vax_link_hash_entry *) h; - - for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next) - if (p->section == sreloc) - break; - - if (p == NULL) - { - p = ((struct elf_vax_pcrel_relocs_copied *) - bfd_alloc (dynobj, (bfd_size_type) sizeof *p)); - if (p == NULL) - return FALSE; - p->next = eh->pcrel_relocs_copied; - eh->pcrel_relocs_copied = p; - p->section = sreloc; - p->count = 0; - } - - ++p->count; - } - } - - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_VAX_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_VAX_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !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 * -elf_vax_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_VAX_GNU_VTINHERIT: - case R_VAX_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* 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_vax_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj; - asection *s; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (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 PLTxx 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 PCxx reloc instead. */ - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - return TRUE; - } - - s = elf_hash_table (info)->splt; - BFD_ASSERT (s != NULL); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - { - s->size += PLT_ENTRY_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 (!bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = s->size; - } - - h->plt.offset = s->size; - - /* 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. */ - - s = elf_hash_table (info)->sgotplt; - BFD_ASSERT (s != NULL); - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - - s = elf_hash_table (info)->srelplt; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf32_External_Rela); - - return TRUE; - } - - /* Reinitialize the plt offset now that it is not used as a reference - count any more. */ - 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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. */ - - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - /* We must generate a R_VAX_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf32_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* This function is called via elf_link_hash_traverse. It resets GOT - and PLT (.GOT) reference counts back to -1 so normal PC32 relocation - will be done. */ - -static bfd_boolean -elf_vax_discard_got_entries (struct elf_link_hash_entry *h, - void *infoptr ATTRIBUTE_UNUSED) -{ - h->got.refcount = -1; - h->plt.refcount = -1; - - return TRUE; -} - -/* Discard unused dynamic data if this is a static link. */ - -static bfd_boolean -elf_vax_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - - dynobj = elf_hash_table (info)->dynobj; - - if (dynobj && !elf_hash_table (info)->dynamic_sections_created) - { - /* We may have created entries in the .rela.got and .got sections. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got - and .got, which will cause them to get stripped from the output - file below. */ - s = elf_hash_table (info)->srelgot; - if (s != NULL) - s->size = 0; - s = elf_hash_table (info)->sgotplt; - if (s != NULL) - s->size = 0; - s = elf_hash_table (info)->sgot; - if (s != NULL) - s->size = 0; - } - - /* If this is a static link, we need to discard all the got entries we've - recorded. */ - if (!dynobj || !elf_hash_table (info)->dynamic_sections_created) - elf_link_hash_traverse (elf_hash_table (info), - elf_vax_discard_got_entries, - info); - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_vax_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean plt; - bfd_boolean relocs; - bfd_boolean reltext; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - - /* If this is a -Bsymbolic shared link, then we need to discard all PC - relative relocs against symbols defined in a regular object. We - allocated space for them in the check_relocs routine, but we will not - fill them in in the relocate_section routine. */ - if (bfd_link_pic (info) && info->symbolic) - elf_vax_link_hash_traverse (elf_hash_table (info), - elf_vax_discard_copies, - NULL); - - /* If this is a -Bsymbolic shared link, we need to discard all the got - entries we've recorded. Otherwise, we need to instantiate (allocate - space for them). */ - elf_link_hash_traverse (elf_hash_table (info), - elf_vax_instantiate_got_entries, - info); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - asection *target; - - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (strcmp (name, ".rela.plt") != 0) - { - const char *outname; - - relocs = TRUE; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL - entry. .rela.plt is actually associated with - .got.plt, which is never readonly. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 5); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = 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 if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".dynbss") != 0) - { - /* 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. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf_vax_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 (!bfd_link_pic (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - } - - if (reltext || (info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* This function is called via elf_vax_link_hash_traverse if we are - creating a shared object with -Bsymbolic. It discards the space - allocated to copy PC relative relocs against symbols which are defined - in regular objects. We allocated space for them in the check_relocs - routine, but we won't fill them in in the relocate_section routine. */ - -static bfd_boolean -elf_vax_discard_copies (struct elf_vax_link_hash_entry *h, - void * ignore ATTRIBUTE_UNUSED) -{ - struct elf_vax_pcrel_relocs_copied *s; - - /* We only discard relocs for symbols defined in a regular object. */ - if (!h->root.def_regular) - return TRUE; - - for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) - s->section->size -= s->count * sizeof (Elf32_External_Rela); - - return TRUE; -} - -/* This function is called via elf_link_hash_traverse. It looks for - entries that have GOT or PLT (.GOT) references. If creating a shared - object with -Bsymbolic, or the symbol has been forced local, then it - resets the reference count back to -1 so normal PC32 relocation will - be done. Otherwise space in the .got and .rela.got will be reserved - for the symbol. */ - -static bfd_boolean -elf_vax_instantiate_got_entries (struct elf_link_hash_entry *h, void * infoptr) -{ - struct bfd_link_info *info = (struct bfd_link_info *) infoptr; - bfd *dynobj; - asection *sgot; - asection *srelgot; - - /* We don't care about non-GOT (and non-PLT) entries. */ - if (h->got.refcount <= 0 && h->plt.refcount <= 0) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - sgot = elf_hash_table (info)->sgot; - srelgot = elf_hash_table (info)->srelgot; - - if (SYMBOL_REFERENCES_LOCAL (info, h)) - { - h->got.refcount = -1; - h->plt.refcount = -1; - } - else if (h->got.refcount > 0) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (!bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* Allocate space in the .got and .rela.got sections. */ - sgot->size += 4; - srelgot->size += sizeof (Elf32_External_Rela); - } - - return TRUE; -} - -/* Relocate an VAX ELF section. */ - -static bfd_boolean -elf_vax_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma plt_index; - bfd_vma got_offset; - asection *sgot; - asection *splt; - asection *sgotplt; - asection *sreloc; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - sgot = NULL; - splt = NULL; - sgotplt = NULL; - sreloc = NULL; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - 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 relocation; - bfd_reloc_status_type r; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= (int) R_VAX_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - howto = howto_table + r_type; - - r_symndx = ELF32_R_SYM (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc; - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && ((r_type == R_VAX_PLT32 - && h->plt.offset != (bfd_vma) -1 - && !h->forced_local - && elf_hash_table (info)->dynamic_sections_created) - || (r_type == R_VAX_GOT32 - && h->got.offset != (bfd_vma) -1 - && !h->forced_local - && elf_hash_table (info)->dynamic_sections_created - && (! bfd_link_pic (info) - || (! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - || (bfd_link_pic (info) - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular) - && ((input_section->flags & SEC_ALLOC) != 0 - /* DWARF will emit R_VAX_32 relocations in its - sections against symbols defined externally - in shared libraries. We can't do anything - with them here. */ - - || ((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic)) - && (r_type == R_VAX_8 - || r_type == R_VAX_16 - || r_type == R_VAX_32)))) - /* In these cases, we don't need the relocation - value. We check specially because in some - obscure cases sec->output_section will be NULL. */ - relocation = 0; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - switch (r_type) - { - case R_VAX_GOT32: - /* Relocation is to the address of the entry for this symbol - in the global offset table. */ - - /* Resolve a GOTxx reloc against a local symbol directly, - without using the global offset table. */ - if (h == NULL - || h->got.offset == (bfd_vma) -1) - break; - - { - bfd_vma off; - - sgot = elf_hash_table (info)->sgot; - BFD_ASSERT (sgot != NULL); - - off = h->got.offset; - BFD_ASSERT (off < sgot->size); - - bfd_put_32 (output_bfd, rel->r_addend, sgot->contents + off); - - relocation = sgot->output_offset + off; - /* The GOT relocation uses the addend. */ - rel->r_addend = 0; - - /* Change the reference to be indirect. */ - contents[rel->r_offset - 1] |= 0x10; - relocation += sgot->output_section->vma; - } - break; - - case R_VAX_PC32: - /* If we are creating an executable and the function this - reloc refers to is in a shared lib, then we made a PLT - entry for this symbol and need to handle the reloc like - a PLT reloc. */ - if (bfd_link_pic (info)) - goto r_vax_pc32_shared; - /* Fall through. */ - case R_VAX_PLT32: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* Resolve a PLTxx reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL - || h->plt.offset == (bfd_vma) -1) - break; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - sgotplt = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgotplt != NULL); - - 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 two are reserved. */ - got_offset = (plt_index + 3) * 4; - - /* We want the relocation to point into the .got.plt instead - of the plt itself. */ - relocation = (sgotplt->output_section->vma - + sgotplt->output_offset - + got_offset); - contents[rel->r_offset-1] |= 0x10; /* make indirect */ - if (rel->r_addend == 2) - { - h->plt.offset |= 1; - } - else if (rel->r_addend != 0) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: PLT addend of %Ld to `%s'" - " from %A section ignored"), - input_bfd, rel->r_addend, h->root.root.string, input_section); - rel->r_addend = 0; - - break; - - case R_VAX_PC8: - case R_VAX_PC16: - r_vax_pc32_shared: - if (h == NULL - || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || h->forced_local) - break; - /* Fall through. */ - case R_VAX_8: - case R_VAX_16: - case R_VAX_32: - if (bfd_link_pic (info) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) != 0 - && ((r_type != R_VAX_PC8 - && r_type != R_VAX_PC16 - && r_type != R_VAX_PC32) - || ((input_section->flags & SEC_CODE) - && (!info->symbolic - || (!h->def_regular && h->type != STT_SECTION))))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip, relocate; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - 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; - 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 the symbol was marked to - become local. */ - else if (h != NULL - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - if (r_type == R_VAX_32) - { - relocate = TRUE; - outrel.r_info = ELF32_R_INFO (0, R_VAX_RELATIVE); - BFD_ASSERT (bfd_get_signed_32 (input_bfd, - &contents[rel->r_offset]) == 0); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - long indx; - - if (bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. */ - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - if (indx == 0) - { - struct elf_link_hash_table *htab; - htab = elf_hash_table (info); - osec = htab->text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); - } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - outrel.r_addend = relocation + rel->r_addend; - } - } - - if ((input_section->flags & SEC_CODE) != 0 - || (ELF32_R_TYPE (outrel.r_info) != R_VAX_32 - && ELF32_R_TYPE (outrel.r_info) != R_VAX_RELATIVE - && ELF32_R_TYPE (outrel.r_info) != R_VAX_COPY - && ELF32_R_TYPE (outrel.r_info) != R_VAX_JMP_SLOT - && ELF32_R_TYPE (outrel.r_info) != R_VAX_GLOB_DAT)) - { - if (h != NULL) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: %s relocation against symbol `%s'" - " from %A section"), - input_bfd, howto->name, h->root.root.string, - input_section); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: warning: %s relocation to %#Lx from %A section"), - input_bfd, howto->name, outrel.r_addend, - input_section); - } - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - - /* This reloc will be computed at runtime, so there's no - need to do anything now, except for R_VAX_32 - relocations that have been turned into - R_VAX_RELATIVE. */ - if (!relocate) - continue; - } - - break; - - case R_VAX_GNU_VTINHERIT: - case R_VAX_GNU_VTENTRY: - /* These are no-ops in the end. */ - continue; - - default: - break; - } - - /* VAX PCREL relocations are from the end of relocation, not the start. - So subtract the difference from the relocation amount since we can't - add it to the offset. */ - if (howto->pc_relative && howto->pcrel_offset) - relocation -= bfd_get_reloc_size(howto); - - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - { - const char *name; - - if (h != NULL) - name = NULL; - 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); - } - info->callbacks->reloc_overflow - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - } - break; - } - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_vax_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - bfd *dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgot; - asection *srela; - bfd_vma plt_index; - bfd_vma got_offset; - bfd_vma addend; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol has an entry in the procedure linkage table. Set - it up. */ - BFD_ASSERT (h->dynindx != -1); - - splt = elf_hash_table (info)->splt; - sgot = elf_hash_table (info)->sgotplt; - srela = elf_hash_table (info)->srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL); - - addend = 2 * (h->plt.offset & 1); - h->plt.offset &= ~1; - - /* 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 two are reserved. */ - got_offset = (plt_index + 3) * 4; - - /* Fill in the entry in the procedure linkage table. */ - memcpy (splt->contents + h->plt.offset, elf_vax_plt_entry, - PLT_ENTRY_SIZE); - - /* The offset is relative to the first extension word. */ - bfd_put_32 (output_bfd, - -(h->plt.offset + 8), - splt->contents + h->plt.offset + 4); - - bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela), - splt->contents + h->plt.offset + 8); - - /* Fill in the entry in the global offset table. */ - bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset) + addend, - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_VAX_JMP_SLOT); - rela.r_addend = addend; - loc = srela->contents + plt_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (h->got.offset != (bfd_vma) -1) - { - asection *sgot; - asection *srela; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol has an entry in the global offset table. Set it - up. */ - sgot = elf_hash_table (info)->sgot; - srela = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srela != NULL); - - rela.r_offset = (sgot->output_section->vma - + sgot->output_offset - + h->got.offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_VAX_GLOB_DAT); - rela.r_addend = bfd_get_signed_32 (output_bfd, - sgot->contents + h->got.offset); - - loc = srela->contents; - loc += srela->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - rela.r_offset = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - rela.r_info = ELF32_R_INFO (h->dynindx, R_VAX_COPY); - rela.r_addend = 0; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf_vax_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sgot; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - sgot = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgot != NULL); - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - Elf32_External_Dyn *dyncon, *dynconend; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - asection *s; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_PLTGOT: - s = elf_hash_table (info)->sgotplt; - goto get_vma; - case DT_JMPREL: - s = elf_hash_table (info)->srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = elf_hash_table (info)->srelplt; - dyn.d_un.d_val = s->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - if (splt->size > 0) - { - memcpy (splt->contents, elf_vax_plt0_entry, PLT_ENTRY_SIZE); - bfd_put_32 (output_bfd, - (sgot->output_section->vma - + sgot->output_offset + 4 - - (splt->output_section->vma + 6)), - splt->contents + 2); - bfd_put_32 (output_bfd, - (sgot->output_section->vma - + sgot->output_offset + 8 - - (splt->output_section->vma + 12)), - splt->contents + 8); - elf_section_data (splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - } - - if (elf_section_data (sgot->output_section) != NULL) - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; - - return TRUE; -} - -static enum elf_reloc_type_class -elf_vax_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_VAX_RELATIVE: - return reloc_class_relative; - case R_VAX_JMP_SLOT: - return reloc_class_plt; - case R_VAX_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -static bfd_vma -elf_vax_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 vax_elf32_vec -#define TARGET_LITTLE_NAME "elf32-vax" -#define ELF_MACHINE_CODE EM_VAX -#define ELF_MAXPAGESIZE 0x1000 - -#define elf_backend_create_dynamic_sections \ - _bfd_elf_create_dynamic_sections -#define bfd_elf32_bfd_link_hash_table_create \ - elf_vax_link_hash_table_create -#define bfd_elf32_bfd_final_link bfd_elf_gc_common_final_link - -#define elf_backend_check_relocs elf_vax_check_relocs -#define elf_backend_adjust_dynamic_symbol \ - elf_vax_adjust_dynamic_symbol -#define elf_backend_always_size_sections \ - elf_vax_always_size_sections -#define elf_backend_size_dynamic_sections \ - elf_vax_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_relocate_section elf_vax_relocate_section -#define elf_backend_finish_dynamic_symbol \ - elf_vax_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf_vax_finish_dynamic_sections -#define elf_backend_reloc_type_class elf_vax_reloc_type_class -#define elf_backend_gc_mark_hook elf_vax_gc_mark_hook -#define elf_backend_plt_sym_val elf_vax_plt_sym_val -#define bfd_elf32_bfd_merge_private_bfd_data \ - elf32_vax_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags \ - elf32_vax_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - elf32_vax_print_private_bfd_data - -#define elf_backend_can_gc_sections 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 16 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-visium.c b/sdcc/support/sdbinutils/bfd/elf32-visium.c deleted file mode 100644 index 45f3337d4..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-visium.c +++ /dev/null @@ -1,875 +0,0 @@ -/* Visium-specific support for 32-bit ELF. - - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "sysdep.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/visium.h" - -static bfd_reloc_status_type visium_elf_howto_parity_reloc - (bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **); - -static reloc_howto_type visium_elf_howto_table[] = { - /* This reloc does nothing. */ - HOWTO (R_VISIUM_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation. */ - HOWTO (R_VISIUM_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_8", /* name */ - FALSE, /* partial_inplace */ - 0x00, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_VISIUM_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_16", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_VISIUM_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_32", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - - /* A 8 bit PC relative relocation. */ - HOWTO (R_VISIUM_8_PCREL, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_8_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x00, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit PC relative relocation. */ - HOWTO (R_VISIUM_16_PCREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_16_PCREL", /* name */ - FALSE, /* partial inplace */ - 0x0000, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32-bit PC relative relocation. */ - HOWTO (R_VISIUM_32_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_VISIUM_32_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16-bit PC word relative offset, relative to start of instruction - and always in the second half of the instruction. */ - HOWTO (R_VISIUM_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_PC16", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The high 16 bits of symbol value. */ - HOWTO (R_VISIUM_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_HI16", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The low 16 bits of symbol value. */ - HOWTO (R_VISIUM_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_LO16", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit immediate value. */ - HOWTO (R_VISIUM_IM16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_IM16", /* name */ - FALSE, /* partial_inplace */ - 0x0000000, /* src_mask */ - 0x000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high 16 bits of symbol value, pc relative. */ - HOWTO (R_VISIUM_HI16_PCREL, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_HI16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The low 16 bits of symbol value, pc relative. */ - HOWTO (R_VISIUM_LO16_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_LO16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit immediate value, pc relative. */ - HOWTO (R_VISIUM_IM16_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - visium_elf_howto_parity_reloc, /* special_function */ - "R_VISIUM_IM16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000000, /* src_mask */ - 0x000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - -}; - -/* GNU extension to record C++ vtable hierarchy. */ -static reloc_howto_type visium_elf_vtinherit_howto = - HOWTO (R_VISIUM_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_VISIUM_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* GNU extension to record C++ vtable member usage. */ -static reloc_howto_type visium_elf_vtentry_howto = - HOWTO (R_VISIUM_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_VISIUM_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Return the parity bit for INSN shifted to its final position. */ - -static bfd_vma -visium_parity_bit (bfd_vma insn) -{ - bfd_vma p = 0; - int i; - - for (i = 0; i < 31; i++) - { - p ^= (insn & 1); - insn >>= 1; - } - - return p << 31; -} - -/* This "special function" will only be used when the input and - output files have different formats ie. when generating S-records - directly using "--oformat srec". Otherwise we use - _bfd_final_link_relocate which uses a howto structure, but does - not use the special_function field. - - It sets instruction parity to even. This cannot be done by a howto. */ - -static bfd_reloc_status_type -visium_elf_howto_parity_reloc (bfd * input_bfd, arelent *reloc_entry, - asymbol *symbol, PTR data, - asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_reloc_status_type ret; - bfd_vma relocation; - bfd_byte *inplace_address; - bfd_vma insn; - const bfd_vma signmask = 0xffff8000; - - /* This part is from bfd_elf_generic_reloc. - If we're relocating, and this an external symbol, we don't want - to change anything. */ - if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* Now do the reloc in the usual way. */ - - /* Sanity check the address (offset in section). */ - if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section)) - return bfd_reloc_outofrange; - - ret = bfd_reloc_ok; - if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) - ret = bfd_reloc_undefined; - - if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL) - relocation = 0; - else - relocation = symbol->value; - - /* Only do this for a final link. */ - if (output_bfd == (bfd *) NULL) - { - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - } - - relocation += reloc_entry->addend; - inplace_address = (bfd_byte *) data + reloc_entry->address; - insn = bfd_get_32 (input_bfd, inplace_address); - - if (reloc_entry->howto->pc_relative) - { - relocation -= input_section->output_section->vma - + input_section->output_offset; - relocation -= reloc_entry->address; - } - - switch (reloc_entry->howto->type) - { - case R_VISIUM_PC16: - relocation >>= 2; - if (ret == bfd_reloc_ok && (relocation & signmask) != 0 - && (relocation & signmask) != signmask) - ret = bfd_reloc_overflow; - relocation &= 0xffff; - break; - case R_VISIUM_HI16: - case R_VISIUM_HI16_PCREL: - relocation = (relocation >> 16) & 0xffff; - break; - case R_VISIUM_LO16: - case R_VISIUM_LO16_PCREL: - relocation &= 0xffff; - break; - case R_VISIUM_IM16: - case R_VISIUM_IM16_PCREL: - if (ret == bfd_reloc_ok && (relocation & 0xffff0000) != 0) - ret = bfd_reloc_overflow; - relocation &= 0xffff; - break; - } - insn = (insn & 0x7fff0000) | relocation; - insn |= visium_parity_bit (insn); - bfd_put_32 (input_bfd, insn, inplace_address); - - if (output_bfd != (bfd *) NULL) - reloc_entry->address += input_section->output_offset; - - return ret; -} - -static reloc_howto_type * -visium_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - /* Note that the visium_elf_howto_table is indexed by the R_ - constants. Thus, the order that the howto records appear in the - table *must* match the order of the relocation types defined in - include/elf/visium.h. */ - switch (code) - { - case BFD_RELOC_NONE: - return &visium_elf_howto_table[(int) R_VISIUM_NONE]; - case BFD_RELOC_8: - return &visium_elf_howto_table[(int) R_VISIUM_8]; - case BFD_RELOC_16: - return &visium_elf_howto_table[(int) R_VISIUM_16]; - case BFD_RELOC_32: - return &visium_elf_howto_table[(int) R_VISIUM_32]; - case BFD_RELOC_8_PCREL: - return &visium_elf_howto_table[(int) R_VISIUM_8_PCREL]; - case BFD_RELOC_16_PCREL: - return &visium_elf_howto_table[(int) R_VISIUM_16_PCREL]; - case BFD_RELOC_32_PCREL: - return &visium_elf_howto_table[(int) R_VISIUM_32_PCREL]; - case BFD_RELOC_VISIUM_REL16: - return &visium_elf_howto_table[(int) R_VISIUM_PC16]; - case BFD_RELOC_VISIUM_HI16: - return &visium_elf_howto_table[(int) R_VISIUM_HI16]; - case BFD_RELOC_VISIUM_LO16: - return &visium_elf_howto_table[(int) R_VISIUM_LO16]; - case BFD_RELOC_VISIUM_IM16: - return &visium_elf_howto_table[(int) R_VISIUM_IM16]; - case BFD_RELOC_VISIUM_HI16_PCREL: - return &visium_elf_howto_table[(int) R_VISIUM_HI16_PCREL]; - case BFD_RELOC_VISIUM_LO16_PCREL: - return &visium_elf_howto_table[(int) R_VISIUM_LO16_PCREL]; - case BFD_RELOC_VISIUM_IM16_PCREL: - return &visium_elf_howto_table[(int) R_VISIUM_IM16_PCREL]; - case BFD_RELOC_VTABLE_INHERIT: - return &visium_elf_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &visium_elf_vtentry_howto; - default: - return NULL; - } -} - -static reloc_howto_type * -visium_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (visium_elf_howto_table) - / sizeof (visium_elf_howto_table[0])); i++) - if (visium_elf_howto_table[i].name != NULL - && strcasecmp (visium_elf_howto_table[i].name, r_name) == 0) - return &visium_elf_howto_table[i]; - - if (strcasecmp (visium_elf_vtinherit_howto.name, r_name) == 0) - return &visium_elf_vtinherit_howto; - if (strcasecmp (visium_elf_vtentry_howto.name, r_name) == 0) - return &visium_elf_vtentry_howto; - - return NULL; -} - -/* Set the howto pointer for a VISIUM ELF reloc. */ - -static void -visium_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - - switch (r_type) - { - case R_VISIUM_GNU_VTINHERIT: - cache_ptr->howto = &visium_elf_vtinherit_howto; - break; - - case R_VISIUM_GNU_VTENTRY: - cache_ptr->howto = &visium_elf_vtentry_howto; - break; - - default: - if (r_type >= (unsigned int) R_VISIUM_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid Visium reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &visium_elf_howto_table[r_type]; - break; - } -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -visium_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_VISIUM_GNU_VTINHERIT: - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_VISIUM_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* Relocate a VISIUM ELF section. */ - -static bfd_boolean -visium_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, bfd *input_bfd, - asection *input_section, bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - for (rel = relocs; rel < relend; rel++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name = NULL; - int r_type; - bfd_vma insn; - - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_type == R_VISIUM_GNU_VTINHERIT || r_type == R_VISIUM_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - - howto = visium_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - /* This is a local symbol. */ - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; - } - else - { - bfd_boolean unresolved_reloc; - bfd_boolean warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - _bfd_clear_contents (howto, input_bfd, input_section, - contents + rel->r_offset); - - rel->r_info = 0; - rel->r_addend = 0; - continue; - } - - if (bfd_link_relocatable (info)) - continue; - - switch (r_type) - { - case R_VISIUM_PC16: - case R_VISIUM_HI16: - case R_VISIUM_LO16: - case R_VISIUM_IM16: - case R_VISIUM_HI16_PCREL: - case R_VISIUM_LO16_PCREL: - case R_VISIUM_IM16_PCREL: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - - /* For instruction relocations, the parity needs correcting. */ - if (r == bfd_reloc_ok) - { - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn = (insn & 0x7fffffff) | visium_parity_bit (insn); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - break; - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - } - - if (r != bfd_reloc_ok) - { - const char *msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* This function is called during section gc to discover the section a - to which a particular relocation refers. Return the section that - should be marked against GC for a given relocation. */ - -static asection * -visium_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, - Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_VISIUM_GNU_VTINHERIT: - case R_VISIUM_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -static void -visium_elf_post_process_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_STANDALONE; - i_ehdrp->e_ident[EI_ABIVERSION] = 1; -} - -/* Function to set the ELF flag bits. */ - -static bfd_boolean -visium_elf_set_private_flags (bfd *abfd, flagword flags) -{ - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Copy backend specific data from one object module to another. */ - -static bfd_boolean -visium_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) -{ - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - BFD_ASSERT (!elf_flags_init (obfd) - || elf_elfheader (obfd)->e_flags == - elf_elfheader (ibfd)->e_flags); - - elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; - elf_flags_init (obfd) = TRUE; - - /* Copy object attributes. */ - _bfd_elf_copy_obj_attributes (ibfd, obfd); - - return TRUE; -} - -/* Merge backend specific data from an object - file to the output object file when linking. */ - -static bfd_boolean -visium_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags; - flagword new_flags; - flagword mismatch; - const char *opt_arch = NULL; - const char *new_opt_with = NULL; - const char *old_opt_with = NULL; - const char *with = "with"; - const char *without = "without"; - const char *mcm = "mcm"; - const char *mcm24 = "mcm24"; - const char *gr6 = "gr6"; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (!elf_flags_init (obfd)) - { - /* First call, no flags set. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - else - { - mismatch = (new_flags ^ old_flags) - & (EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_MCM24 | EF_VISIUM_ARCH_GR6); - if (mismatch & EF_VISIUM_ARCH_GR6) - { - opt_arch = gr6; - new_opt_with = new_flags & EF_VISIUM_ARCH_GR6 ? with : without; - old_opt_with = old_flags & EF_VISIUM_ARCH_GR6 ? with : without; - } - else if (mismatch & EF_VISIUM_ARCH_MCM) - { - opt_arch = mcm; - new_opt_with = new_flags & EF_VISIUM_ARCH_MCM ? with : without; - old_opt_with = old_flags & EF_VISIUM_ARCH_MCM ? with : without; - } - else if (mismatch & EF_VISIUM_ARCH_MCM24) - { - opt_arch = mcm24; - new_opt_with = new_flags & EF_VISIUM_ARCH_MCM24 ? with : without; - old_opt_with = old_flags & EF_VISIUM_ARCH_MCM24 ? with : without; - } - - if (mismatch) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: compiled %s -mtune=%s and linked with modules" - " compiled %s -mtune=%s"), - ibfd, new_opt_with, opt_arch, old_opt_with, opt_arch); - } - - return TRUE; -} - -static bfd_boolean -visium_elf_print_private_bfd_data (bfd *abfd, void *ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - flags = elf_elfheader (abfd)->e_flags; - fprintf (file, _("private flags = 0x%lx:"), (long) flags); - - if (flags & EF_VISIUM_ARCH_GR6) - fprintf (file, " -mtune=gr6"); - else if (flags & EF_VISIUM_ARCH_MCM) - fprintf (file, " -mtune=mcm"); - else if (flags & EF_VISIUM_ARCH_MCM24) - fprintf (file, " -mtune=mcm24"); - - fputc ('\n', file); - return TRUE; -} - -#define ELF_ARCH bfd_arch_visium -#define ELF_MACHINE_CODE EM_VISIUM -#define ELF_MAXPAGESIZE 1 - -#define TARGET_BIG_SYM visium_elf32_vec -#define TARGET_BIG_NAME "elf32-visium" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto visium_info_to_howto_rela -#define elf_backend_relocate_section visium_elf_relocate_section -#define elf_backend_gc_mark_hook visium_elf_gc_mark_hook -#define elf_backend_check_relocs visium_elf_check_relocs -#define elf_backend_rela_normal 1 - -#define elf_backend_can_gc_sections 1 - -#define bfd_elf32_bfd_reloc_type_lookup visium_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup visium_reloc_name_lookup - -#define bfd_elf32_bfd_set_private_flags visium_elf_set_private_flags -#define bfd_elf32_bfd_copy_private_bfd_data visium_elf_copy_private_bfd_data -#define bfd_elf32_bfd_merge_private_bfd_data visium_elf_merge_private_bfd_data -#define bfd_elf32_bfd_print_private_bfd_data visium_elf_print_private_bfd_data -#define elf_backend_post_process_headers visium_elf_post_process_headers - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-wasm32.c b/sdcc/support/sdbinutils/bfd/elf32-wasm32.c deleted file mode 100644 index 5205bef60..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-wasm32.c +++ /dev/null @@ -1,155 +0,0 @@ -/* 32-bit ELF for the WebAssembly target - Copyright (C) 2017-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, - Boston, MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "bfd_stdint.h" -#include "libiberty.h" -#include "elf/wasm32.h" - -static reloc_howto_type elf32_wasm32_howto_table[] = -{ - HOWTO (R_WASM32_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_WASM32_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute */ - HOWTO (R_WASM32_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_WASM32_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* Look up the relocation CODE. */ - -static reloc_howto_type * -elf32_wasm32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_NONE: - return &elf32_wasm32_howto_table[R_WASM32_NONE]; - case BFD_RELOC_32: - return &elf32_wasm32_howto_table[R_WASM32_32]; - default: - break; - } - - return NULL; -} - -/* Look up the relocation R_NAME. */ - -static reloc_howto_type * -elf32_wasm32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf32_wasm32_howto_table); i++) - if (elf32_wasm32_howto_table[i].name != NULL - && strcasecmp (elf32_wasm32_howto_table[i].name, r_name) == 0) - return &elf32_wasm32_howto_table[i]; - - return NULL; -} - -/* Look up the relocation R_TYPE. */ - -static reloc_howto_type * -elf32_wasm32_rtype_to_howto (bfd *abfd, unsigned r_type) -{ - unsigned int i = r_type; - - if (i >= ARRAY_SIZE (elf32_wasm32_howto_table)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) r_type); - i = R_WASM32_NONE; - } - - if (elf32_wasm32_howto_table[i].type != r_type) - return NULL; - - return &elf32_wasm32_howto_table[i]; -} - -/* Translate the ELF-internal relocation RELA into CACHE_PTR. */ - -static void -elf32_wasm32_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - cache_ptr->howto = elf32_wasm32_rtype_to_howto (abfd, r_type); -} - -#define ELF_ARCH bfd_arch_wasm32 -#define ELF_TARGET_ID EM_WEBASSEMBLY -#define ELF_MACHINE_CODE EM_WEBASSEMBLY -/* FIXME we don't have paged executables, see: - https://github.com/pipcet/binutils-gdb/issues/4 */ -#define ELF_MAXPAGESIZE 4096 - -#define TARGET_LITTLE_SYM wasm32_elf32_vec -#define TARGET_LITTLE_NAME "elf32-wasm32" - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 -/* For testing. */ -#define elf_backend_want_dynrelro 1 - -#define elf_info_to_howto elf32_wasm32_info_to_howto_rela -#define elf_info_to_howto_rel NULL - -#define bfd_elf32_bfd_reloc_type_lookup elf32_wasm32_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup elf32_wasm32_reloc_name_lookup - -#define ELF_DYNAMIC_INTERPRETER "/sbin/elf-dynamic-interpreter.so" - -#define elf_backend_want_got_plt 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_got_header_size 0 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-xc16x.c b/sdcc/support/sdbinutils/bfd/elf32-xc16x.c deleted file mode 100644 index 42a3dcaaf..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-xc16x.c +++ /dev/null @@ -1,477 +0,0 @@ -/* Infineon XC16X-specific support for 16-bit ELF. - Copyright (C) 2006-2018 Free Software Foundation, Inc. - Contributed by KPIT Cummins Infosystems - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/xc16x.h" -#include "dwarf2.h" -#include "libiberty.h" - -static reloc_howto_type xc16x_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_XC16X_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_XC16X_ABS_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_ABS_8", /* name */ - TRUE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_XC16X_ABS_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_ABS_16", /* name */ - TRUE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_XC16X_ABS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_ABS_32", /* name */ - TRUE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - - /* A PC relative 8 bit relocation. */ - HOWTO (R_XC16X_8_PCREL, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 8, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_8_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Relocation regarding page number. */ - HOWTO (R_XC16X_PAG, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_PAG", /* name */ - TRUE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - - /* Relocation regarding page number. */ - HOWTO (R_XC16X_POF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_POF", /* name */ - TRUE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - - /* Relocation regarding segment number. */ - HOWTO (R_XC16X_SEG, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_SEG", /* name */ - TRUE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relocation regarding segment offset. */ - HOWTO (R_XC16X_SOF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XC16X_SOF", /* name */ - TRUE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE) /* pcrel_offset */ -}; - - -/* Map BFD reloc types to XC16X ELF reloc types. */ - -struct xc16x_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int xc16x_reloc_val; -}; - -static const struct xc16x_reloc_map xc16x_reloc_map [] = -{ - { BFD_RELOC_NONE, R_XC16X_NONE }, - { BFD_RELOC_8, R_XC16X_ABS_8 }, - { BFD_RELOC_16, R_XC16X_ABS_16 }, - { BFD_RELOC_32, R_XC16X_ABS_32 }, - { BFD_RELOC_8_PCREL, R_XC16X_8_PCREL }, - { BFD_RELOC_XC16X_PAG, R_XC16X_PAG}, - { BFD_RELOC_XC16X_POF, R_XC16X_POF}, - { BFD_RELOC_XC16X_SEG, R_XC16X_SEG}, - { BFD_RELOC_XC16X_SOF, R_XC16X_SOF}, -}; - - -/* This function is used to search for correct relocation type from - howto structure. */ - -static reloc_howto_type * -xc16x_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (xc16x_reloc_map); --i;) - if (xc16x_reloc_map [i].bfd_reloc_val == code) - return & xc16x_elf_howto_table [xc16x_reloc_map[i].xc16x_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -xc16x_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (xc16x_elf_howto_table) / sizeof (xc16x_elf_howto_table[0]); - i++) - if (xc16x_elf_howto_table[i].name != NULL - && strcasecmp (xc16x_elf_howto_table[i].name, r_name) == 0) - return &xc16x_elf_howto_table[i]; - - return NULL; -} - -/* For a particular operand this function is - called to finalise the type of relocation. */ - -static void -elf32_xc16x_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r; - unsigned int i; - - r = ELF32_R_TYPE (elf_reloc->r_info); - for (i = 0; i < ARRAY_SIZE (xc16x_elf_howto_table); i++) - if (xc16x_elf_howto_table[i].type == r) - { - bfd_reloc->howto = &xc16x_elf_howto_table[i]; - return; - } - abort (); -} - -static bfd_reloc_status_type -elf32_xc16x_final_link_relocate (unsigned long r_type, - bfd *input_bfd, - bfd *output_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd_byte *contents, - bfd_vma offset, - bfd_vma value, - bfd_vma addend, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sym_sec ATTRIBUTE_UNUSED, - int is_local ATTRIBUTE_UNUSED) -{ - bfd_byte *hit_data = contents + offset; - bfd_vma val1; - - switch (r_type) - { - case R_XC16X_NONE: - return bfd_reloc_ok; - - case R_XC16X_ABS_16: - value += addend; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_XC16X_8_PCREL: - bfd_put_8 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - /* Following case is to find page number from actual - address for this divide value by 16k i.e. page size. */ - - case R_XC16X_PAG: - value += addend; - value /= 0x4000; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - /* Following case is to find page offset from actual address - for this take modulo of value by 16k i.e. page size. */ - - case R_XC16X_POF: - value += addend; - value %= 0x4000; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - /* Following case is to find segment number from actual - address for this divide value by 64k i.e. segment size. */ - - case R_XC16X_SEG: - value += addend; - value /= 0x10000; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - /* Following case is to find segment offset from actual address - for this take modulo of value by 64k i.e. segment size. */ - - case R_XC16X_SOF: - value += addend; - value %= 0x10000; - bfd_put_16 (input_bfd, value, hit_data); - return bfd_reloc_ok; - - case R_XC16X_ABS_32: - if (!strstr (input_section->name,".debug")) - { - value += addend; - val1 = value; - value %= 0x4000; - val1 /= 0x4000; - val1 = val1 << 16; - value += val1; - bfd_put_32 (input_bfd, value, hit_data); - } - else - { - value += addend; - bfd_put_32 (input_bfd, value, hit_data); - } - return bfd_reloc_ok; - - default: - return bfd_reloc_notsupported; - } -} - -static bfd_boolean -elf32_xc16x_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - unsigned int r_type; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - - /* This is a final link. */ - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents cleared. Avoid any special processing. */ - reloc_howto_type *howto; - howto = xc16x_reloc_type_lookup (input_bfd, r_type); - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - } - - if (bfd_link_relocatable (info)) - continue; - - elf32_xc16x_final_link_relocate (r_type, input_bfd, output_bfd, - input_section, - contents, rel->r_offset, - relocation, rel->r_addend, - info, sec, h == NULL); - } - - return TRUE; -} - - -static void -elf32_xc16x_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - unsigned long val; - - switch (bfd_get_mach (abfd)) - { - default: - case bfd_mach_xc16x: - val = 0x1000; - break; - - case bfd_mach_xc16xl: - val = 0x1001; - break; - - case bfd_mach_xc16xs: - val = 0x1002; - break; - } - - elf_elfheader (abfd)->e_flags |= val; -} - -static unsigned long -elf32_xc16x_mach (flagword flags) -{ - switch (flags) - { - case 0x1000: - default: - return bfd_mach_xc16x; - - case 0x1001: - return bfd_mach_xc16xl; - - case 0x1002: - return bfd_mach_xc16xs; - } -} - - -static bfd_boolean -elf32_xc16x_object_p (bfd *abfd) -{ - bfd_default_set_arch_mach (abfd, bfd_arch_xc16x, - elf32_xc16x_mach (elf_elfheader (abfd)->e_flags)); - return TRUE; -} - - -#define ELF_ARCH bfd_arch_xc16x -#define ELF_MACHINE_CODE EM_XC16X -#define ELF_MAXPAGESIZE 0x100 - -#define TARGET_LITTLE_SYM xc16x_elf32_vec -#define TARGET_LITTLE_NAME "elf32-xc16x" -#define elf_backend_final_write_processing elf32_xc16x_final_write_processing -#define elf_backend_object_p elf32_xc16x_object_p -#define elf_backend_can_gc_sections 1 -#define bfd_elf32_bfd_reloc_type_lookup xc16x_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup xc16x_reloc_name_lookup -#define elf_info_to_howto elf32_xc16x_info_to_howto -#define elf_info_to_howto_rel elf32_xc16x_info_to_howto -#define elf_backend_relocate_section elf32_xc16x_relocate_section -#define elf_backend_rela_normal 1 - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-xgate.c b/sdcc/support/sdbinutils/bfd/elf32-xgate.c deleted file mode 100644 index 5a93b5e85..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-xgate.c +++ /dev/null @@ -1,723 +0,0 @@ -/* Freescale XGATE-specific support for 32-bit ELF - Copyright (C) 2010-2018 Free Software Foundation, Inc. - Contributed by Sean Keys(skeys@ipdatasys.com) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf32-xgate.h" -#include "elf/xgate.h" -#include "opcode/xgate.h" -#include "libiberty.h" - -/* Relocation functions. */ -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *, bfd_reloc_code_real_type); -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *, const char *); -static void -xgate_info_to_howto_rel (bfd *, arelent *, Elf_Internal_Rela *); -static bfd_boolean -xgate_elf_set_mach_from_flags (bfd *); -static struct bfd_hash_entry * -stub_hash_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, - const char *); -static struct bfd_link_hash_table* -xgate_elf_bfd_link_hash_table_create (bfd *); - -/* Use REL instead of RELA to save space */ -#define USE_REL 1 - -static reloc_howto_type elf_xgate_howto_table[] = -{ - /* This reloc does nothing. */ - HOWTO (R_XGATE_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit absolute relocation. */ - HOWTO (R_XGATE_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 8 bit PC-rel relocation. */ - HOWTO (R_XGATE_PCREL_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_PCREL_8", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_XGATE_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont /*bitfield */, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. This one is never used for the - code relocation. It's used by gas for -gstabs generation. */ - HOWTO (R_XGATE_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit PC-rel relocation. */ - HOWTO (R_XGATE_PCREL_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_PCREL_16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_XGATE_GNU_VTINHERIT, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - NULL, /* special_function */ - "R_XGATE_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_XGATE_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 1, /* 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_XGATE_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 24 bit relocation. */ - HOWTO (R_XGATE_24, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM8_LO", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16-bit low relocation. */ - HOWTO (R_XGATE_LO16, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM8_HI", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A page relocation. */ - HOWTO (R_XGATE_GPAGE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - xgate_elf_special_reloc,/* special_function */ - "R_XGATE_GPAGE", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 9 bit absolute relocation. */ - HOWTO (R_XGATE_PCREL_9, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_PCREL_9", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 8 bit absolute relocation (upper address). */ - HOWTO (R_XGATE_PCREL_10, /* type */ - 8, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_PCREL_10", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 8 bit absolute relocation. */ - HOWTO (R_XGATE_IMM8_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM8_LO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation (upper address). */ - HOWTO (R_XGATE_IMM8_HI, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM8_HI", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 3 bit absolute relocation. */ - HOWTO (R_XGATE_IMM3, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM3", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 4 bit absolute relocation. */ - HOWTO (R_XGATE_IMM4, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM4", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 5 bit absolute relocation. */ - HOWTO (R_XGATE_IMM5, /* type */ - 8, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XGATE_IMM5", /* name */ - FALSE, /* partial_inplace */ - 0x00ff, /* src_mask */ - 0x00ff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Mark beginning of a jump instruction (any form). */ - HOWTO (R_XGATE_RL_JUMP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - xgate_elf_ignore_reloc, /* special_function */ - "R_XGATE_RL_JUMP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Mark beginning of Gcc relaxation group instruction. */ - HOWTO (R_XGATE_RL_GROUP, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - xgate_elf_ignore_reloc, /* special_function */ - "R_XGATE_RL_GROUP", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -/* Map BFD reloc types to XGATE ELF reloc types. */ - -struct xgate_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct xgate_reloc_map xgate_reloc_map[] = -{ - {BFD_RELOC_NONE, R_XGATE_NONE}, - {BFD_RELOC_8, R_XGATE_8}, - {BFD_RELOC_8_PCREL, R_XGATE_PCREL_8}, - {BFD_RELOC_16_PCREL, R_XGATE_PCREL_16}, - {BFD_RELOC_16, R_XGATE_16}, - {BFD_RELOC_32, R_XGATE_32}, - - {BFD_RELOC_VTABLE_INHERIT, R_XGATE_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_XGATE_GNU_VTENTRY}, - - {BFD_RELOC_XGATE_LO16, R_XGATE_LO16}, - {BFD_RELOC_XGATE_GPAGE, R_XGATE_GPAGE}, - {BFD_RELOC_XGATE_24, R_XGATE_24}, - {BFD_RELOC_XGATE_PCREL_9, R_XGATE_PCREL_9}, - {BFD_RELOC_XGATE_PCREL_10, R_XGATE_PCREL_10}, - {BFD_RELOC_XGATE_IMM8_LO, R_XGATE_IMM8_LO}, - {BFD_RELOC_XGATE_IMM8_HI, R_XGATE_IMM8_HI}, - {BFD_RELOC_XGATE_IMM3, R_XGATE_IMM3}, - {BFD_RELOC_XGATE_IMM4, R_XGATE_IMM4}, - {BFD_RELOC_XGATE_IMM5, R_XGATE_IMM5}, - - {BFD_RELOC_XGATE_RL_JUMP, R_XGATE_RL_JUMP}, - {BFD_RELOC_XGATE_RL_GROUP, R_XGATE_RL_GROUP}, -}; - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (xgate_reloc_map); i++) - if (xgate_reloc_map[i].bfd_reloc_val == code) - return &elf_xgate_howto_table[xgate_reloc_map[i].elf_reloc_val]; - - return NULL; -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (elf_xgate_howto_table); i++) - if (elf_xgate_howto_table[i].name != NULL - && strcasecmp (elf_xgate_howto_table[i].name, r_name) == 0) - return &elf_xgate_howto_table[i]; - - return NULL; -} - -/* Set the howto pointer for an XGATE ELF reloc. */ - -static void -xgate_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_XGATE_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid XGate reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_xgate_howto_table[r_type]; -} - -/* Destroy an XGATE ELF linker hash table. */ - -static void -xgate_elf_bfd_link_hash_table_free (bfd *obfd) -{ - struct xgate_elf_link_hash_table *ret = - (struct xgate_elf_link_hash_table *) obfd->link.hash; - - bfd_hash_table_free (ret->stub_hash_table); - free (ret->stub_hash_table); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create an XGATE ELF linker hash table. */ - -static struct bfd_link_hash_table* -xgate_elf_bfd_link_hash_table_create (bfd *abfd) -{ - struct xgate_elf_link_hash_table *ret; - bfd_size_type amt = sizeof(struct xgate_elf_link_hash_table); - - ret = (struct xgate_elf_link_hash_table *) bfd_zmalloc (amt); - if (ret == (struct xgate_elf_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - _bfd_elf_link_hash_newfunc, sizeof(struct elf_link_hash_entry), - XGATE_ELF_DATA)) - { - free (ret); - return NULL; - } - - /* Init the stub hash table too. */ - amt = sizeof(struct bfd_hash_table); - ret->stub_hash_table = (struct bfd_hash_table*) bfd_zmalloc (amt); - if (ret->stub_hash_table == NULL) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - - if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc, - sizeof(struct elf32_xgate_stub_hash_entry))) - { - free (ret->stub_hash_table); - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - ret->root.root.hash_table_free = xgate_elf_bfd_link_hash_table_free; - - return &ret->root.root; -} - -static bfd_boolean -xgate_elf_set_mach_from_flags (bfd *abfd ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Specific sections: - - The .page0 is a data section that is mapped in [0x0000..0x00FF]. - Page0 accesses are faster on the M68HC12. - - The .vectors is the section that represents the interrupt - vectors. - - The .xgate section is starts in 0xE08800 or as xgate sees it 0x0800. */ -static const struct bfd_elf_special_section elf32_xgate_special_sections[] = -{ - { STRING_COMMA_LEN (".eeprom"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".page0"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".vectors"), 0, SHT_PROGBITS, SHF_ALLOC }, -/*{ STRING_COMMA_LEN (".xgate"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - TODO finish this implementation */ - { NULL, 0, 0, 0, 0 } -}; - -struct xgate_scan_param -{ - struct xgate_page_info* pinfo; - bfd_boolean use_memory_banks; -}; - -/* Assorted hash table functions. */ - -/* Initialize an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table ATTRIBUTE_UNUSED, - const char *string ATTRIBUTE_UNUSED) -{ - return entry; -} - -/* Hook called by the linker routine which adds symbols from an object - file. */ - -bfd_boolean -elf32_xgate_add_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp ATTRIBUTE_UNUSED, - bfd_vma *valp ATTRIBUTE_UNUSED) -{ - /* For some reason the st_target_internal value is not retained - after xgate_frob_symbol is called, hence this temp hack. */ - sym->st_target_internal = 1; - return TRUE; -} - -/* External entry points for sizing and building linker stubs. */ - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ - -int -elf32_xgate_setup_section_lists (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - return 1; -} - -/* Determine and set the size of the stub section for a final link. - The basic idea here is to examine all the relocations looking for - PC-relative calls to a target that is unreachable with any "9-bit PC-REL" - instruction. */ - -bfd_boolean -elf32_xgate_size_stubs (bfd *output_bfd ATTRIBUTE_UNUSED, - bfd *stub_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection * (*add_stub_section) (const char*, asection*) ATTRIBUTE_UNUSED) -{ - return FALSE; -} - -/* Build all the stubs associated with the current output file. The - stubs are kept in a hash table attached to the main linker hash - table. This function is called via xgateelf_finish in the - linker. */ - -bfd_boolean -elf32_xgate_build_stubs (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -void -xgate_elf_get_bank_parameters (struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - return; -} - -/* This function is used for relocs which are only used for relaxing, - which the linker should otherwise ignore. */ - -bfd_reloc_status_type -xgate_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -bfd_reloc_status_type -xgate_elf_special_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry ATTRIBUTE_UNUSED, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd *output_bfd ATTRIBUTE_UNUSED, - char **error_message ATTRIBUTE_UNUSED) -{ - abort (); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -bfd_boolean -elf32_xgate_check_relocs (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - asection *sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Relocate a XGATE/S12x ELF section. */ - -bfd_boolean -elf32_xgate_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *input_bfd ATTRIBUTE_UNUSED, - asection *input_section ATTRIBUTE_UNUSED, - bfd_byte *contents ATTRIBUTE_UNUSED, - Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED, - Elf_Internal_Sym *local_syms ATTRIBUTE_UNUSED, - asection **local_sections ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Set and control ELF flags in ELF header. */ - -bfd_boolean -_bfd_xgate_elf_set_private_flags (bfd *abfd ATTRIBUTE_UNUSED, - flagword flags ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -bfd_boolean -_bfd_xgate_elf_print_private_bfd_data (bfd *abfd, void *ptr) -{ - FILE *file = (FILE *) ptr; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - /* xgettext:c-format */ - fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); - - if (elf_elfheader (abfd)->e_flags & E_XGATE_I32) - fprintf (file, _("[abi=32-bit int, ")); - else - fprintf (file, _("[abi=16-bit int, ")); - - if (elf_elfheader (abfd)->e_flags & E_XGATE_F64) - fprintf (file, _("64-bit double, ")); - else - fprintf (file, _("32-bit double, ")); - if (elf_elfheader (abfd)->e_flags & EF_XGATE_MACH) - fprintf (file, _("cpu=XGATE]")); - else - fprintf (file, _("error reading cpu type from elf private data")); - fputc ('\n', file); - - return TRUE; -} - -void -elf32_xgate_post_process_headers (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *link_info ATTRIBUTE_UNUSED) -{ - -} - -#define ELF_ARCH bfd_arch_xgate -#define ELF_MACHINE_CODE EM_XGATE -#define ELF_TARGET_ID XGATE_ELF_DATA - -#define ELF_MAXPAGESIZE 0x1000 - -#define TARGET_BIG_SYM xgate_elf32_vec -#define TARGET_BIG_NAME "elf32-xgate" - -#define elf_info_to_howto 0 -#define elf_info_to_howto_rel xgate_info_to_howto_rel -#define elf_backend_check_relocs elf32_xgate_check_relocs -#define elf_backend_relocate_section elf32_xgate_relocate_section -#define elf_backend_object_p xgate_elf_set_mach_from_flags -#define elf_backend_final_write_processing 0 -#define elf_backend_can_gc_sections 1 -#define elf_backend_special_sections elf32_xgate_special_sections -#define elf_backend_post_process_headers elf32_xgate_post_process_headers -#define elf_backend_add_symbol_hook elf32_xgate_add_symbol_hook - -#define bfd_elf32_bfd_link_hash_table_create xgate_elf_bfd_link_hash_table_create -#define bfd_elf32_bfd_set_private_flags _bfd_xgate_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data _bfd_xgate_elf_print_private_bfd_data - -#define xgate_stub_hash_lookup(table, string, create, copy) \ - ((struct elf32_xgate_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-xgate.h b/sdcc/support/sdbinutils/bfd/elf32-xgate.h deleted file mode 100644 index 99ab9a493..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-xgate.h +++ /dev/null @@ -1,142 +0,0 @@ -/* Freescale XGATE-specific support for 32-bit ELF - Copyright (C) 2012-2018 Free Software Foundation, Inc. - - Contributed by Sean Keys (skeys@ipdatasys.com) - (Heavily copied from the HC11 port by Stephane Carrez (stcarrez@nerim.fr)) - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF32_XGATE_H -#define _ELF32_XGATE_H - -#include "elf-bfd.h" -#include "bfdlink.h" -#include "elf/xgate.h" - -/* Set and control ELF flags in ELF header. */ -extern bfd_boolean _bfd_xgate_elf_set_private_flags (bfd*,flagword); -extern bfd_boolean _bfd_xgate_elf_print_private_bfd_data (bfd*, void*); - -struct elf32_xgate_stub_hash_entry -{ - /* Base hash table entry structure. */ - struct bfd_hash_entry root; - - /* The stub section. */ - asection *stub_sec; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; -}; - -struct xgate_page_info -{ - bfd_vma bank_virtual; - bfd_vma bank_physical; - bfd_vma bank_physical_end; - bfd_vma bank_mask; - bfd_vma bank_size; - int bank_shift; - int bank_param_initialized; - bfd_vma trampoline_addr; -}; - -struct xgate_elf_link_hash_table -{ - struct elf_link_hash_table root; - struct xgate_page_info pinfo; - - /* The stub hash table. */ - struct bfd_hash_table* stub_hash_table; - - /* Linker stub bfd. */ - bfd *stub_bfd; - - asection* stub_section; - asection* tramp_section; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *); - - /* Assorted information used by elf32_hppa_size_stubs. */ - unsigned int bfd_count; - int top_index; - asection ** input_list; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - bfd_boolean (*size_one_stub) (struct bfd_hash_entry*, void*); - bfd_boolean (*build_one_stub) (struct bfd_hash_entry*, void*); -}; - -/* Get the XGate ELF linker hash table from a link_info structure. */ - -#define xgate_elf_hash_table(p) \ - ((struct xgate_elf_link_hash_table *) ((p)->hash)) - -/* Create a XGATE ELF linker hash table. */ - -extern struct xgate_elf_link_hash_table* xgate_elf_hash_table_create - (bfd *); - -extern void xgate_elf_get_bank_parameters (struct bfd_link_info *); - -/* Return 1 if the address is in banked memory. - This can be applied to a virtual address and to a physical address. */ -extern int xgate_addr_is_banked (struct xgate_page_info *, bfd_vma); - -/* Return the physical address seen by the processor, taking - into account banked memory. */ -extern bfd_vma xgate_phys_addr (struct xgate_page_info *, bfd_vma); - -/* Return the page number corresponding to an address in banked memory. */ -extern bfd_vma xgate_phys_page (struct xgate_page_info *, bfd_vma); - -bfd_reloc_status_type xgate_elf_ignore_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -bfd_reloc_status_type xgate_elf_special_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -bfd_boolean elf32_xgate_check_relocs - (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); -bfd_boolean elf32_xgate_relocate_section - (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); - -bfd_boolean elf32_xgate_add_symbol_hook - (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, - flagword *, asection **, bfd_vma *); - -/* Tweak the OSABI field of the elf header. */ -extern void elf32_xgate_post_process_headers (bfd *, struct bfd_link_info *); - -int elf32_xgate_setup_section_lists (bfd *, struct bfd_link_info *); - -bfd_boolean elf32_xgate_size_stubs - (bfd *, bfd *, struct bfd_link_info *, - asection * (*) (const char *, asection *)); - -bfd_boolean elf32_xgate_build_stubs (bfd * abfd, struct bfd_link_info *); - -#endif /* _ELF32_XGATE_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf32-xstormy16.c b/sdcc/support/sdbinutils/bfd/elf32-xstormy16.c deleted file mode 100644 index 476f9e01a..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-xstormy16.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* Xstormy16-specific support for 32-bit ELF. - Copyright (C) 2000-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/xstormy16.h" -#include "libiberty.h" - -/* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */ - -static bfd_reloc_status_type -xstormy16_elf_24_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - bfd_vma relocation, x; - - if (output_bfd != NULL) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - relocation += reloc_entry->addend; - - x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - x &= 0x0000ff00; - x |= relocation & 0xff; - x |= (relocation << 8) & 0xffff0000; - bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address); - - if (relocation & ~ (bfd_vma) 0xffffff) - return bfd_reloc_overflow; - - return bfd_reloc_ok; -} - -static reloc_howto_type xstormy16_elf_howto_table [] = -{ - /* This reloc does nothing. */ - HOWTO (R_XSTORMY16_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_XSTORMY16_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit absolute relocation. */ - HOWTO (R_XSTORMY16_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_XSTORMY16_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit pc-relative relocation. */ - HOWTO (R_XSTORMY16_PC32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_PC32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit pc-relative relocation. */ - HOWTO (R_XSTORMY16_PC16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_PC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* An 8 bit pc-relative relocation. */ - HOWTO (R_XSTORMY16_PC8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_PC8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 12-bit pc-relative relocation suitable for the branch instructions. */ - HOWTO (R_XSTORMY16_REL_12, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - TRUE, /* pc_relative */ - 1, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_REL_12", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0ffe, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 24-bit absolute relocation suitable for the jump instructions. */ - HOWTO (R_XSTORMY16_24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - xstormy16_elf_24_reloc, /* special_function */ - "R_XSTORMY16_24", /* name */ - TRUE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff00ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit absolute relocation to a function pointer. */ - HOWTO (R_XSTORMY16_FPTR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_FPTR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low order 16 bit value of a high memory address. */ - HOWTO (R_XSTORMY16_LO16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High order 16 bit value of a high memory address. */ - HOWTO (R_XSTORMY16_HI16, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 12 bit absolute relocation. */ - HOWTO (R_XSTORMY16_12, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_XSTORMY16_12", /* name */ - FALSE, /* partial_inplace */ - 0x0000, /* src_mask */ - 0x0fff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static reloc_howto_type xstormy16_elf_howto_table2 [] = -{ - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_XSTORMY16_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_XSTORMY16_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_XSTORMY16_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_XSTORMY16_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - -}; - -/* Map BFD reloc types to XSTORMY16 ELF reloc types. */ - -typedef struct xstormy16_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned int xstormy16_reloc_val; - reloc_howto_type * table; -} reloc_map; - -static const reloc_map xstormy16_reloc_map [] = -{ - { BFD_RELOC_NONE, R_XSTORMY16_NONE, xstormy16_elf_howto_table }, - { BFD_RELOC_32, R_XSTORMY16_32, xstormy16_elf_howto_table }, - { BFD_RELOC_16, R_XSTORMY16_16, xstormy16_elf_howto_table }, - { BFD_RELOC_8, R_XSTORMY16_8, xstormy16_elf_howto_table }, - { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32, xstormy16_elf_howto_table }, - { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16, xstormy16_elf_howto_table }, - { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8, xstormy16_elf_howto_table }, - { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12, xstormy16_elf_howto_table }, - { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24, xstormy16_elf_howto_table }, - { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16, xstormy16_elf_howto_table }, - { BFD_RELOC_LO16, R_XSTORMY16_LO16, xstormy16_elf_howto_table }, - { BFD_RELOC_HI16, R_XSTORMY16_HI16, xstormy16_elf_howto_table }, - { BFD_RELOC_XSTORMY16_12, R_XSTORMY16_12, xstormy16_elf_howto_table }, - { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT, xstormy16_elf_howto_table2 }, - { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY, xstormy16_elf_howto_table2 }, -}; - -static reloc_howto_type * -xstormy16_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = ARRAY_SIZE (xstormy16_reloc_map); i--;) - { - const reloc_map * entry; - - entry = xstormy16_reloc_map + i; - - if (entry->bfd_reloc_val == code) - return entry->table + (entry->xstormy16_reloc_val - - entry->table[0].type); - } - - return NULL; -} - -static reloc_howto_type * -xstormy16_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (xstormy16_elf_howto_table) - / sizeof (xstormy16_elf_howto_table[0])); - i++) - if (xstormy16_elf_howto_table[i].name != NULL - && strcasecmp (xstormy16_elf_howto_table[i].name, r_name) == 0) - return &xstormy16_elf_howto_table[i]; - - for (i = 0; - i < (sizeof (xstormy16_elf_howto_table2) - / sizeof (xstormy16_elf_howto_table2[0])); - i++) - if (xstormy16_elf_howto_table2[i].name != NULL - && strcasecmp (xstormy16_elf_howto_table2[i].name, r_name) == 0) - return &xstormy16_elf_howto_table2[i]; - - return NULL; -} - -/* Set the howto pointer for an XSTORMY16 ELF reloc. */ - -static void -xstormy16_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - - if (r_type <= (unsigned int) R_XSTORMY16_12) - cache_ptr->howto = &xstormy16_elf_howto_table [r_type]; - else if (r_type - R_XSTORMY16_GNU_VTINHERIT - <= (unsigned int) R_XSTORMY16_GNU_VTENTRY) - cache_ptr->howto - = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT]; - else - abort (); -} - -/* We support 16-bit pointers to code above 64k by generating a thunk - below 64k containing a JMPF instruction to the final address. We - cannot, unfortunately, minimize the number of thunks unless the - -relax switch is given, as otherwise we have no idea where the - sections will fall in the address space. */ - -static bfd_boolean -xstormy16_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - const Elf_Internal_Rela *rel, *relend; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Shdr *symtab_hdr; - bfd_vma *local_plt_offsets; - asection *splt; - bfd *dynobj; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata(abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_plt_offsets = elf_local_got_offsets (abfd); - dynobj = elf_hash_table(info)->dynobj; - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; ++rel) - { - unsigned long r_symndx; - struct elf_link_hash_entry *h; - bfd_vma *offset; - - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - /* This relocation describes a 16-bit pointer to a function. - We may need to allocate a thunk in low memory; reserve memory - for it now. */ - case R_XSTORMY16_FPTR16: - if (rel->r_addend != 0) - { - (*info->callbacks->warning) - (info, _("non-zero addend in @fptr reloc"), 0, - abfd, 0, 0); - } - - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - splt = elf_hash_table (info)->splt; - if (splt == NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED - | SEC_READONLY | SEC_CODE); - - splt = bfd_make_section_anyway_with_flags (dynobj, ".plt", - flags); - elf_hash_table (info)->splt = splt; - if (splt == NULL - || ! bfd_set_section_alignment (dynobj, splt, 1)) - return FALSE; - } - - if (h != NULL) - offset = &h->plt.offset; - else - { - if (local_plt_offsets == NULL) - { - size_t size; - unsigned int i; - - size = symtab_hdr->sh_info * sizeof (bfd_vma); - local_plt_offsets = bfd_alloc (abfd, size); - if (local_plt_offsets == NULL) - return FALSE; - elf_local_got_offsets (abfd) = local_plt_offsets; - - for (i = 0; i < symtab_hdr->sh_info; i++) - local_plt_offsets[i] = (bfd_vma) -1; - } - offset = &local_plt_offsets[r_symndx]; - } - - if (*offset == (bfd_vma) -1) - { - *offset = splt->size; - splt->size += 4; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_XSTORMY16_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_XSTORMY16_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* A subroutine of xstormy16_elf_relax_section. If the global symbol H - is within the low 64k, remove any entry for it in the plt. */ - -struct relax_plt_data -{ - asection *splt; - bfd_boolean *again; -}; - -static bfd_boolean -xstormy16_relax_plt_check (struct elf_link_hash_entry *h, void * xdata) -{ - struct relax_plt_data *data = (struct relax_plt_data *) xdata; - - if (h->plt.offset != (bfd_vma) -1) - { - bfd_vma address; - - if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - address = 0; - else - address = (h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset - + h->root.u.def.value); - - if (address <= 0xffff) - { - h->plt.offset = -1; - data->splt->size -= 4; - *data->again = TRUE; - } - } - - return TRUE; -} - -/* A subroutine of xstormy16_elf_relax_section. If the global symbol H - previously had a plt entry, give it a new entry offset. */ - -static bfd_boolean -xstormy16_relax_plt_realloc (struct elf_link_hash_entry *h, void * xdata) -{ - bfd_vma *entry = (bfd_vma *) xdata; - - if (h->plt.offset != (bfd_vma) -1) - { - h->plt.offset = *entry; - *entry += 4; - } - - return TRUE; -} - -static bfd_boolean -xstormy16_elf_relax_section (bfd *dynobj, - asection *splt, - struct bfd_link_info *info, - bfd_boolean *again) -{ - struct relax_plt_data relax_plt_data; - bfd *ibfd; - - /* Assume nothing changes. */ - *again = FALSE; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* We only relax the .plt section at the moment. */ - if (dynobj != elf_hash_table (info)->dynobj - || strcmp (splt->name, ".plt") != 0) - return TRUE; - - /* Quick check for an empty plt. */ - if (splt->size == 0) - return TRUE; - - /* Map across all global symbols; see which ones happen to - fall in the low 64k. */ - relax_plt_data.splt = splt; - relax_plt_data.again = again; - elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check, - &relax_plt_data); - - /* Likewise for local symbols, though that's somewhat less convenient - as we have to walk the list of input bfds and swap in symbol data. */ - for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next) - { - bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf = NULL; - unsigned int idx; - - if (! local_plt_offsets) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (ibfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - return FALSE; - } - - for (idx = 0; idx < symtab_hdr->sh_info; ++idx) - { - Elf_Internal_Sym *isym; - asection *tsec; - bfd_vma address; - - if (local_plt_offsets[idx] == (bfd_vma) -1) - continue; - - isym = &isymbuf[idx]; - if (isym->st_shndx == SHN_UNDEF) - continue; - else if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else - tsec = bfd_section_from_elf_index (ibfd, isym->st_shndx); - - address = (tsec->output_section->vma - + tsec->output_offset - + isym->st_value); - if (address <= 0xffff) - { - local_plt_offsets[idx] = -1; - splt->size -= 4; - *again = TRUE; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - } - - /* If we changed anything, walk the symbols again to reallocate - .plt entry addresses. */ - if (*again && splt->size > 0) - { - bfd_vma entry = 0; - - elf_link_hash_traverse (elf_hash_table (info), - xstormy16_relax_plt_realloc, &entry); - - for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link.next) - { - bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd); - unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info; - unsigned int idx; - - if (! local_plt_offsets) - continue; - - for (idx = 0; idx < nlocals; ++idx) - if (local_plt_offsets[idx] != (bfd_vma) -1) - { - local_plt_offsets[idx] = entry; - entry += 4; - } - } - } - - return TRUE; -} - -static bfd_boolean -xstormy16_elf_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *splt; - - if (bfd_link_relocatable (info)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - return TRUE; - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - splt->contents = bfd_zalloc (dynobj, splt->size); - if (splt->contents == NULL) - return FALSE; - - return TRUE; -} - -/* Relocate an XSTORMY16 ELF section. - - The RELOCATE_SECTION function is called by the new ELF backend linker - to handle the relocations for a section. - - The relocs are always passed as Rela structures; if the section - actually uses Rel structures, the r_addend field will always be - zero. - - This function is responsible for adjusting the section contents as - necessary, and (if using Rela relocs and generating a relocatable - output file) adjusting the reloc addend as necessary. - - This function does not have to worry about setting the reloc - address or the reloc symbol index. - - LOCAL_SYMS is a pointer to the swapped in local symbols. - - LOCAL_SECTIONS is an array giving the section in the input file - corresponding to the st_shndx field of each local symbol. - - The global hash table entry for the global symbols can be found - via elf_sym_hashes (input_bfd). - - When generating relocatable output, this function must handle - STB_LOCAL/STT_SECTION symbols specially. The output symbol is - going to be the section symbol corresponding to the output - section, which means that the addend must be adjusted - accordingly. */ - -static bfd_boolean -xstormy16_elf_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, - bfd * input_bfd, - asection * input_section, - bfd_byte * contents, - Elf_Internal_Rela * relocs, - Elf_Internal_Sym * local_syms, - asection ** local_sections) -{ - Elf_Internal_Shdr * symtab_hdr; - struct elf_link_hash_entry ** sym_hashes; - Elf_Internal_Rela * rel; - Elf_Internal_Rela * relend; - asection *splt; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - splt = elf_hash_table (info)->splt; - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type * howto; - unsigned long r_symndx; - Elf_Internal_Sym * sym; - asection * sec; - struct elf_link_hash_entry * h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char * name = NULL; - int r_type; - - r_type = ELF32_R_TYPE (rel->r_info); - - if ( r_type == R_XSTORMY16_GNU_VTINHERIT - || r_type == R_XSTORMY16_GNU_VTENTRY) - continue; - - r_symndx = ELF32_R_SYM (rel->r_info); - howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean unresolved_reloc, warned, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_XSTORMY16_24: - { - bfd_vma reloc = relocation + rel->r_addend; - unsigned int x; - - x = bfd_get_32 (input_bfd, contents + rel->r_offset); - x &= 0x0000ff00; - x |= reloc & 0xff; - x |= (reloc << 8) & 0xffff0000; - bfd_put_32 (input_bfd, x, contents + rel->r_offset); - - if (reloc & ~0xffffff) - r = bfd_reloc_overflow; - else - r = bfd_reloc_ok; - break; - } - - case R_XSTORMY16_FPTR16: - { - bfd_vma *plt_offset; - - if (h != NULL) - plt_offset = &h->plt.offset; - else - plt_offset = elf_local_got_offsets (input_bfd) + r_symndx; - - if (relocation <= 0xffff) - { - /* If the symbol is in range for a 16-bit address, we should - have deallocated the plt entry in relax_section. */ - BFD_ASSERT (*plt_offset == (bfd_vma) -1); - } - else - { - /* If the symbol is out of range for a 16-bit address, - we must have allocated a plt entry. */ - BFD_ASSERT (*plt_offset != (bfd_vma) -1); - - /* If this is the first time we've processed this symbol, - fill in the plt entry with the correct symbol address. */ - if ((*plt_offset & 1) == 0) - { - unsigned int x; - - x = 0x00000200; /* jmpf */ - x |= relocation & 0xff; - x |= (relocation << 8) & 0xffff0000; - bfd_put_32 (input_bfd, x, splt->contents + *plt_offset); - *plt_offset |= 1; - } - - relocation = (splt->output_section->vma - + splt->output_offset - + (*plt_offset & -2)); - } - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, 0); - break; - } - - default: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - break; - } - - if (r != bfd_reloc_ok) - { - const char * msg = NULL; - - switch (r) - { - case bfd_reloc_overflow: - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - (*info->callbacks->undefined_symbol) - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* This must exist if dynobj is ever set. */ - -static bfd_boolean -xstormy16_elf_finish_dynamic_sections (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj = elf_hash_table (info)->dynobj; - asection *splt = elf_hash_table (info)->splt; - - /* As an extra sanity check, verify that all plt entries have - been filled in. */ - - if (dynobj != NULL && splt != NULL) - { - bfd_byte *contents = splt->contents; - unsigned int i, size = splt->size; - - for (i = 0; i < size; i += 4) - { - unsigned int x = bfd_get_32 (dynobj, contents + i); - - BFD_ASSERT (x != 0); - } - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -xstormy16_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_XSTORMY16_GNU_VTINHERIT: - case R_XSTORMY16_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -#define ELF_ARCH bfd_arch_xstormy16 -#define ELF_MACHINE_CODE EM_XSTORMY16 -#define ELF_MAXPAGESIZE 0x100 - -#define TARGET_LITTLE_SYM xstormy16_elf32_vec -#define TARGET_LITTLE_NAME "elf32-xstormy16" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto xstormy16_info_to_howto_rela -#define elf_backend_relocate_section xstormy16_elf_relocate_section -#define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook -#define elf_backend_check_relocs xstormy16_elf_check_relocs -#define elf_backend_always_size_sections \ - xstormy16_elf_always_size_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_finish_dynamic_sections \ - xstormy16_elf_finish_dynamic_sections - -#define elf_backend_can_gc_sections 1 -#define elf_backend_rela_normal 1 - -#define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - xstormy16_reloc_name_lookup -#define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32-xtensa.c b/sdcc/support/sdbinutils/bfd/elf32-xtensa.c deleted file mode 100644 index b3a7467b7..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32-xtensa.c +++ /dev/null @@ -1,11252 +0,0 @@ -/* Xtensa-specific support for 32-bit ELF. - Copyright (C) 2003-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" - -#include -#include - -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/xtensa.h" -#include "splay-tree.h" -#include "xtensa-isa.h" -#include "xtensa-config.h" - -#define XTENSA_NO_NOP_REMOVAL 0 - -/* Local helper functions. */ - -static bfd_boolean add_extra_plt_sections (struct bfd_link_info *, int); -static char *vsprint_msg (const char *, const char *, int, ...) ATTRIBUTE_PRINTF(2,4); -static bfd_reloc_status_type bfd_elf_xtensa_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_boolean do_fix_for_relocatable_link - (Elf_Internal_Rela *, bfd *, asection *, bfd_byte *); -static void do_fix_for_final_link - (Elf_Internal_Rela *, bfd *, asection *, bfd_byte *, bfd_vma *); - -/* Local functions to handle Xtensa configurability. */ - -static bfd_boolean is_indirect_call_opcode (xtensa_opcode); -static bfd_boolean is_direct_call_opcode (xtensa_opcode); -static bfd_boolean is_windowed_call_opcode (xtensa_opcode); -static xtensa_opcode get_const16_opcode (void); -static xtensa_opcode get_l32r_opcode (void); -static bfd_vma l32r_offset (bfd_vma, bfd_vma); -static int get_relocation_opnd (xtensa_opcode, int); -static int get_relocation_slot (int); -static xtensa_opcode get_relocation_opcode - (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *); -static bfd_boolean is_l32r_relocation - (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *); -static bfd_boolean is_alt_relocation (int); -static bfd_boolean is_operand_relocation (int); -static bfd_size_type insn_decode_len - (bfd_byte *, bfd_size_type, bfd_size_type); -static xtensa_opcode insn_decode_opcode - (bfd_byte *, bfd_size_type, bfd_size_type, int); -static bfd_boolean check_branch_target_aligned - (bfd_byte *, bfd_size_type, bfd_vma, bfd_vma); -static bfd_boolean check_loop_aligned - (bfd_byte *, bfd_size_type, bfd_vma, bfd_vma); -static bfd_boolean check_branch_target_aligned_address (bfd_vma, int); -static bfd_size_type get_asm_simplify_size - (bfd_byte *, bfd_size_type, bfd_size_type); - -/* Functions for link-time code simplifications. */ - -static bfd_reloc_status_type elf_xtensa_do_asm_simplify - (bfd_byte *, bfd_vma, bfd_vma, char **); -static bfd_reloc_status_type contract_asm_expansion - (bfd_byte *, bfd_vma, Elf_Internal_Rela *, char **); -static xtensa_opcode swap_callx_for_call_opcode (xtensa_opcode); -static xtensa_opcode get_expanded_call_opcode (bfd_byte *, int, bfd_boolean *); - -/* Access to internal relocations, section contents and symbols. */ - -static Elf_Internal_Rela *retrieve_internal_relocs - (bfd *, asection *, bfd_boolean); -static void pin_internal_relocs (asection *, Elf_Internal_Rela *); -static void release_internal_relocs (asection *, Elf_Internal_Rela *); -static bfd_byte *retrieve_contents (bfd *, asection *, bfd_boolean); -static void pin_contents (asection *, bfd_byte *); -static void release_contents (asection *, bfd_byte *); -static Elf_Internal_Sym *retrieve_local_syms (bfd *); - -/* Miscellaneous utility functions. */ - -static asection *elf_xtensa_get_plt_section (struct bfd_link_info *, int); -static asection *elf_xtensa_get_gotplt_section (struct bfd_link_info *, int); -static asection *get_elf_r_symndx_section (bfd *, unsigned long); -static struct elf_link_hash_entry *get_elf_r_symndx_hash_entry - (bfd *, unsigned long); -static bfd_vma get_elf_r_symndx_offset (bfd *, unsigned long); -static bfd_boolean is_reloc_sym_weak (bfd *, Elf_Internal_Rela *); -static bfd_boolean pcrel_reloc_fits (xtensa_opcode, int, bfd_vma, bfd_vma); -static bfd_boolean xtensa_is_property_section (asection *); -static bfd_boolean xtensa_is_insntable_section (asection *); -static bfd_boolean xtensa_is_littable_section (asection *); -static bfd_boolean xtensa_is_proptable_section (asection *); -static int internal_reloc_compare (const void *, const void *); -static int internal_reloc_matches (const void *, const void *); -static asection *xtensa_get_property_section (asection *, const char *); -static flagword xtensa_get_property_predef_flags (asection *); - -/* Other functions called directly by the linker. */ - -typedef void (*deps_callback_t) - (asection *, bfd_vma, asection *, bfd_vma, void *); -extern bfd_boolean xtensa_callback_required_dependence - (bfd *, asection *, struct bfd_link_info *, deps_callback_t, void *); - - -/* Globally visible flag for choosing size optimization of NOP removal - instead of branch-target-aware minimization for NOP removal. - When nonzero, narrow all instructions and remove all NOPs possible - around longcall expansions. */ - -int elf32xtensa_size_opt; - - -/* The "new_section_hook" is used to set up a per-section - "xtensa_relax_info" data structure with additional information used - during relaxation. */ - -typedef struct xtensa_relax_info_struct xtensa_relax_info; - - -/* The GNU tools do not easily allow extending interfaces to pass around - the pointer to the Xtensa ISA information, so instead we add a global - variable here (in BFD) that can be used by any of the tools that need - this information. */ - -xtensa_isa xtensa_default_isa; - - -/* When this is true, relocations may have been modified to refer to - symbols from other input files. The per-section list of "fix" - records needs to be checked when resolving relocations. */ - -static bfd_boolean relaxing_section = FALSE; - -/* When this is true, during final links, literals that cannot be - coalesced and their relocations may be moved to other sections. */ - -int elf32xtensa_no_literal_movement = 1; - -/* Rename one of the generic section flags to better document how it - is used here. */ -/* Whether relocations have been processed. */ -#define reloc_done sec_flg0 - -static reloc_howto_type elf_howto_table[] = -{ - HOWTO (R_XTENSA_NONE, 0, 3, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_NONE", - FALSE, 0, 0, FALSE), - HOWTO (R_XTENSA_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_xtensa_reloc, "R_XTENSA_32", - TRUE, 0xffffffff, 0xffffffff, FALSE), - - /* Replace a 32-bit value with a value from the runtime linker (only - used by linker-generated stub functions). The r_addend value is - special: 1 means to substitute a pointer to the runtime linker's - dynamic resolver function; 2 means to substitute the link map for - the shared object. */ - HOWTO (R_XTENSA_RTLD, 0, 2, 32, FALSE, 0, complain_overflow_dont, - NULL, "R_XTENSA_RTLD", FALSE, 0, 0, FALSE), - - HOWTO (R_XTENSA_GLOB_DAT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_XTENSA_GLOB_DAT", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_JMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_XTENSA_JMP_SLOT", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_RELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_XTENSA_RELATIVE", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_PLT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_xtensa_reloc, "R_XTENSA_PLT", - FALSE, 0, 0xffffffff, FALSE), - - EMPTY_HOWTO (7), - - /* Old relocations for backward compatibility. */ - HOWTO (R_XTENSA_OP0, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_OP0", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_OP1, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_OP1", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_OP2, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_OP2", FALSE, 0, 0, TRUE), - - /* Assembly auto-expansion. */ - HOWTO (R_XTENSA_ASM_EXPAND, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_ASM_EXPAND", FALSE, 0, 0, TRUE), - /* Relax assembly auto-expansion. */ - HOWTO (R_XTENSA_ASM_SIMPLIFY, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_ASM_SIMPLIFY", FALSE, 0, 0, TRUE), - - EMPTY_HOWTO (13), - - HOWTO (R_XTENSA_32_PCREL, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_xtensa_reloc, "R_XTENSA_32_PCREL", - FALSE, 0, 0xffffffff, TRUE), - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_XTENSA_GNU_VTINHERIT, 0, 2, 0, FALSE, 0, complain_overflow_dont, - NULL, "R_XTENSA_GNU_VTINHERIT", - FALSE, 0, 0, FALSE), - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_XTENSA_GNU_VTENTRY, 0, 2, 0, FALSE, 0, complain_overflow_dont, - _bfd_elf_rel_vtable_reloc_fn, "R_XTENSA_GNU_VTENTRY", - FALSE, 0, 0, FALSE), - - /* Relocations for supporting difference of symbols. */ - HOWTO (R_XTENSA_DIFF8, 0, 0, 8, FALSE, 0, complain_overflow_signed, - bfd_elf_xtensa_reloc, "R_XTENSA_DIFF8", FALSE, 0, 0xff, FALSE), - HOWTO (R_XTENSA_DIFF16, 0, 1, 16, FALSE, 0, complain_overflow_signed, - bfd_elf_xtensa_reloc, "R_XTENSA_DIFF16", FALSE, 0, 0xffff, FALSE), - HOWTO (R_XTENSA_DIFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed, - bfd_elf_xtensa_reloc, "R_XTENSA_DIFF32", FALSE, 0, 0xffffffff, FALSE), - - /* General immediate operand relocations. */ - HOWTO (R_XTENSA_SLOT0_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT0_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT1_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT1_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT2_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT2_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT3_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT3_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT4_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT4_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT5_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT5_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT6_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT6_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT7_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT7_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT8_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT8_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT9_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT9_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT10_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT10_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT11_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT11_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT12_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT12_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT13_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_OP", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT14_OP, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_OP", FALSE, 0, 0, TRUE), - - /* "Alternate" relocations. The meaning of these is opcode-specific. */ - HOWTO (R_XTENSA_SLOT0_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT0_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT1_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT1_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT2_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT2_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT3_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT3_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT4_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT4_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT5_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT5_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT6_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT6_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT7_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT7_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT8_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT8_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT9_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT9_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT10_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT10_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT11_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT11_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT12_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT12_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT13_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_ALT", FALSE, 0, 0, TRUE), - HOWTO (R_XTENSA_SLOT14_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_ALT", FALSE, 0, 0, TRUE), - - /* TLS relocations. */ - HOWTO (R_XTENSA_TLSDESC_FN, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLSDESC_FN", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_TLSDESC_ARG, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLSDESC_ARG", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_TLS_DTPOFF, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLS_DTPOFF", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLS_TPOFF", - FALSE, 0, 0xffffffff, FALSE), - HOWTO (R_XTENSA_TLS_FUNC, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLS_FUNC", - FALSE, 0, 0, FALSE), - HOWTO (R_XTENSA_TLS_ARG, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLS_ARG", - FALSE, 0, 0, FALSE), - HOWTO (R_XTENSA_TLS_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_xtensa_reloc, "R_XTENSA_TLS_CALL", - FALSE, 0, 0, FALSE), -}; - -#if DEBUG_GEN_RELOC -#define TRACE(str) \ - fprintf (stderr, "Xtensa bfd reloc lookup %d (%s)\n", code, str) -#else -#define TRACE(str) -#endif - -static reloc_howto_type * -elf_xtensa_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[(unsigned) R_XTENSA_NONE ]; - - case BFD_RELOC_32: - TRACE ("BFD_RELOC_32"); - return &elf_howto_table[(unsigned) R_XTENSA_32 ]; - - case BFD_RELOC_32_PCREL: - TRACE ("BFD_RELOC_32_PCREL"); - return &elf_howto_table[(unsigned) R_XTENSA_32_PCREL ]; - - case BFD_RELOC_XTENSA_DIFF8: - TRACE ("BFD_RELOC_XTENSA_DIFF8"); - return &elf_howto_table[(unsigned) R_XTENSA_DIFF8 ]; - - case BFD_RELOC_XTENSA_DIFF16: - TRACE ("BFD_RELOC_XTENSA_DIFF16"); - return &elf_howto_table[(unsigned) R_XTENSA_DIFF16 ]; - - case BFD_RELOC_XTENSA_DIFF32: - TRACE ("BFD_RELOC_XTENSA_DIFF32"); - return &elf_howto_table[(unsigned) R_XTENSA_DIFF32 ]; - - case BFD_RELOC_XTENSA_RTLD: - TRACE ("BFD_RELOC_XTENSA_RTLD"); - return &elf_howto_table[(unsigned) R_XTENSA_RTLD ]; - - case BFD_RELOC_XTENSA_GLOB_DAT: - TRACE ("BFD_RELOC_XTENSA_GLOB_DAT"); - return &elf_howto_table[(unsigned) R_XTENSA_GLOB_DAT ]; - - case BFD_RELOC_XTENSA_JMP_SLOT: - TRACE ("BFD_RELOC_XTENSA_JMP_SLOT"); - return &elf_howto_table[(unsigned) R_XTENSA_JMP_SLOT ]; - - case BFD_RELOC_XTENSA_RELATIVE: - TRACE ("BFD_RELOC_XTENSA_RELATIVE"); - return &elf_howto_table[(unsigned) R_XTENSA_RELATIVE ]; - - case BFD_RELOC_XTENSA_PLT: - TRACE ("BFD_RELOC_XTENSA_PLT"); - return &elf_howto_table[(unsigned) R_XTENSA_PLT ]; - - case BFD_RELOC_XTENSA_OP0: - TRACE ("BFD_RELOC_XTENSA_OP0"); - return &elf_howto_table[(unsigned) R_XTENSA_OP0 ]; - - case BFD_RELOC_XTENSA_OP1: - TRACE ("BFD_RELOC_XTENSA_OP1"); - return &elf_howto_table[(unsigned) R_XTENSA_OP1 ]; - - case BFD_RELOC_XTENSA_OP2: - TRACE ("BFD_RELOC_XTENSA_OP2"); - return &elf_howto_table[(unsigned) R_XTENSA_OP2 ]; - - case BFD_RELOC_XTENSA_ASM_EXPAND: - TRACE ("BFD_RELOC_XTENSA_ASM_EXPAND"); - return &elf_howto_table[(unsigned) R_XTENSA_ASM_EXPAND ]; - - case BFD_RELOC_XTENSA_ASM_SIMPLIFY: - TRACE ("BFD_RELOC_XTENSA_ASM_SIMPLIFY"); - return &elf_howto_table[(unsigned) R_XTENSA_ASM_SIMPLIFY ]; - - case BFD_RELOC_VTABLE_INHERIT: - TRACE ("BFD_RELOC_VTABLE_INHERIT"); - return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTINHERIT ]; - - case BFD_RELOC_VTABLE_ENTRY: - TRACE ("BFD_RELOC_VTABLE_ENTRY"); - return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ]; - - case BFD_RELOC_XTENSA_TLSDESC_FN: - TRACE ("BFD_RELOC_XTENSA_TLSDESC_FN"); - return &elf_howto_table[(unsigned) R_XTENSA_TLSDESC_FN ]; - - case BFD_RELOC_XTENSA_TLSDESC_ARG: - TRACE ("BFD_RELOC_XTENSA_TLSDESC_ARG"); - return &elf_howto_table[(unsigned) R_XTENSA_TLSDESC_ARG ]; - - case BFD_RELOC_XTENSA_TLS_DTPOFF: - TRACE ("BFD_RELOC_XTENSA_TLS_DTPOFF"); - return &elf_howto_table[(unsigned) R_XTENSA_TLS_DTPOFF ]; - - case BFD_RELOC_XTENSA_TLS_TPOFF: - TRACE ("BFD_RELOC_XTENSA_TLS_TPOFF"); - return &elf_howto_table[(unsigned) R_XTENSA_TLS_TPOFF ]; - - case BFD_RELOC_XTENSA_TLS_FUNC: - TRACE ("BFD_RELOC_XTENSA_TLS_FUNC"); - return &elf_howto_table[(unsigned) R_XTENSA_TLS_FUNC ]; - - case BFD_RELOC_XTENSA_TLS_ARG: - TRACE ("BFD_RELOC_XTENSA_TLS_ARG"); - return &elf_howto_table[(unsigned) R_XTENSA_TLS_ARG ]; - - case BFD_RELOC_XTENSA_TLS_CALL: - TRACE ("BFD_RELOC_XTENSA_TLS_CALL"); - return &elf_howto_table[(unsigned) R_XTENSA_TLS_CALL ]; - - default: - if (code >= BFD_RELOC_XTENSA_SLOT0_OP - && code <= BFD_RELOC_XTENSA_SLOT14_OP) - { - unsigned n = (R_XTENSA_SLOT0_OP + - (code - BFD_RELOC_XTENSA_SLOT0_OP)); - return &elf_howto_table[n]; - } - - if (code >= BFD_RELOC_XTENSA_SLOT0_ALT - && code <= BFD_RELOC_XTENSA_SLOT14_ALT) - { - unsigned n = (R_XTENSA_SLOT0_ALT + - (code - BFD_RELOC_XTENSA_SLOT0_ALT)); - return &elf_howto_table[n]; - } - - break; - } - - TRACE ("Unknown"); - return NULL; -} - -static reloc_howto_type * -elf_xtensa_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - return NULL; -} - - -/* Given an ELF "rela" relocation, find the corresponding howto and record - it in the BFD internal arelent representation of the relocation. */ - -static void -elf_xtensa_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF32_R_TYPE (dst->r_info); - - if (r_type >= (unsigned int) R_XTENSA_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid XTENSA reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_howto_table[r_type]; -} - - -/* Functions for the Xtensa ELF linker. */ - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ - -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so" - -/* The size in bytes of an entry in the procedure linkage table. - (This does _not_ include the space for the literals associated with - the PLT entry.) */ - -#define PLT_ENTRY_SIZE 16 - -/* For _really_ large PLTs, we may need to alternate between literals - and code to keep the literals within the 256K range of the L32R - instructions in the code. It's unlikely that anyone would ever need - such a big PLT, but an arbitrary limit on the PLT size would be bad. - Thus, we split the PLT into chunks. Since there's very little - overhead (2 extra literals) for each chunk, the chunk size is kept - small so that the code for handling multiple chunks get used and - tested regularly. With 254 entries, there are 1K of literals for - each chunk, and that seems like a nice round number. */ - -#define PLT_ENTRIES_PER_CHUNK 254 - -/* PLT entries are actually used as stub functions for lazy symbol - resolution. Once the symbol is resolved, the stub function is never - invoked. Note: the 32-byte frame size used here cannot be changed - without a corresponding change in the runtime linker. */ - -static const bfd_byte elf_xtensa_be_plt_entry[][PLT_ENTRY_SIZE] = -{ - { - 0x6c, 0x10, 0x04, /* entry sp, 32 */ - 0x18, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ - 0x1a, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ - 0x1b, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ - 0x0a, 0x80, 0x00, /* jx a8 */ - 0 /* unused */ - }, - { - 0x18, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ - 0x1a, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ - 0x1b, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ - 0x0a, 0x80, 0x00, /* jx a8 */ - 0 /* unused */ - } -}; - -static const bfd_byte elf_xtensa_le_plt_entry[][PLT_ENTRY_SIZE] = -{ - { - 0x36, 0x41, 0x00, /* entry sp, 32 */ - 0x81, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ - 0xa1, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ - 0xb1, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ - 0xa0, 0x08, 0x00, /* jx a8 */ - 0 /* unused */ - }, - { - 0x81, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ - 0xa1, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ - 0xb1, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ - 0xa0, 0x08, 0x00, /* jx a8 */ - 0 /* unused */ - } -}; - -/* The size of the thread control block. */ -#define TCB_SIZE 8 - -struct elf_xtensa_link_hash_entry -{ - struct elf_link_hash_entry elf; - - bfd_signed_vma tlsfunc_refcount; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 /* global or local dynamic */ -#define GOT_TLS_IE 4 /* initial or local exec */ -#define GOT_TLS_ANY (GOT_TLS_GD | GOT_TLS_IE) - unsigned char tls_type; -}; - -#define elf_xtensa_hash_entry(ent) ((struct elf_xtensa_link_hash_entry *)(ent)) - -struct elf_xtensa_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char *local_got_tls_type; - - bfd_signed_vma *local_tlsfunc_refcounts; -}; - -#define elf_xtensa_tdata(abfd) \ - ((struct elf_xtensa_obj_tdata *) (abfd)->tdata.any) - -#define elf_xtensa_local_got_tls_type(abfd) \ - (elf_xtensa_tdata (abfd)->local_got_tls_type) - -#define elf_xtensa_local_tlsfunc_refcounts(abfd) \ - (elf_xtensa_tdata (abfd)->local_tlsfunc_refcounts) - -#define is_xtensa_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == XTENSA_ELF_DATA) - -static bfd_boolean -elf_xtensa_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_xtensa_obj_tdata), - XTENSA_ELF_DATA); -} - -/* Xtensa ELF linker hash table. */ - -struct elf_xtensa_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *sgotloc; - asection *spltlittbl; - - /* Total count of PLT relocations seen during check_relocs. - The actual PLT code must be split into multiple sections and all - the sections have to be created before size_dynamic_sections, - where we figure out the exact number of PLT entries that will be - needed. It is OK if this count is an overestimate, e.g., some - relocations may be removed by GC. */ - int plt_reloc_count; - - struct elf_xtensa_link_hash_entry *tlsbase; -}; - -/* Get the Xtensa ELF linker hash table from a link_info structure. */ - -#define elf_xtensa_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == XTENSA_ELF_DATA ? ((struct elf_xtensa_link_hash_table *) ((p)->hash)) : NULL) - -/* Create an entry in an Xtensa ELF linker hash table. */ - -static struct bfd_hash_entry * -elf_xtensa_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_xtensa_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_xtensa_link_hash_entry *eh = elf_xtensa_hash_entry (entry); - eh->tlsfunc_refcount = 0; - eh->tls_type = GOT_UNKNOWN; - } - - return entry; -} - -/* Create an Xtensa ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf_xtensa_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_entry *tlsbase; - struct elf_xtensa_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_xtensa_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - elf_xtensa_link_hash_newfunc, - sizeof (struct elf_xtensa_link_hash_entry), - XTENSA_ELF_DATA)) - { - free (ret); - return NULL; - } - - /* Create a hash entry for "_TLS_MODULE_BASE_" to speed up checking - for it later. */ - tlsbase = elf_link_hash_lookup (&ret->elf, "_TLS_MODULE_BASE_", - TRUE, FALSE, FALSE); - tlsbase->root.type = bfd_link_hash_new; - tlsbase->root.u.undef.abfd = NULL; - tlsbase->non_elf = 0; - ret->tlsbase = elf_xtensa_hash_entry (tlsbase); - ret->tlsbase->tls_type = GOT_UNKNOWN; - - return &ret->elf.root; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf_xtensa_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_xtensa_link_hash_entry *edir, *eind; - - edir = elf_xtensa_hash_entry (dir); - eind = elf_xtensa_hash_entry (ind); - - if (ind->root.type == bfd_link_hash_indirect) - { - edir->tlsfunc_refcount += eind->tlsfunc_refcount; - eind->tlsfunc_refcount = 0; - - if (dir->got.refcount <= 0) - { - edir->tls_type = eind->tls_type; - eind->tls_type = GOT_UNKNOWN; - } - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -static inline bfd_boolean -elf_xtensa_dynamic_symbol_p (struct elf_link_hash_entry *h, - struct bfd_link_info *info) -{ - /* Check if we should do dynamic things to this symbol. The - "ignore_protected" argument need not be set, because Xtensa code - does not require special handling of STV_PROTECTED to make function - pointer comparisons work properly. The PLT addresses are never - used for function pointers. */ - - return _bfd_elf_dynamic_symbol_p (h, info, 0); -} - - -static int -property_table_compare (const void *ap, const void *bp) -{ - const property_table_entry *a = (const property_table_entry *) ap; - const property_table_entry *b = (const property_table_entry *) bp; - - if (a->address == b->address) - { - if (a->size != b->size) - return (a->size - b->size); - - if ((a->flags & XTENSA_PROP_ALIGN) != (b->flags & XTENSA_PROP_ALIGN)) - return ((b->flags & XTENSA_PROP_ALIGN) - - (a->flags & XTENSA_PROP_ALIGN)); - - if ((a->flags & XTENSA_PROP_ALIGN) - && (GET_XTENSA_PROP_ALIGNMENT (a->flags) - != GET_XTENSA_PROP_ALIGNMENT (b->flags))) - return (GET_XTENSA_PROP_ALIGNMENT (a->flags) - - GET_XTENSA_PROP_ALIGNMENT (b->flags)); - - if ((a->flags & XTENSA_PROP_UNREACHABLE) - != (b->flags & XTENSA_PROP_UNREACHABLE)) - return ((b->flags & XTENSA_PROP_UNREACHABLE) - - (a->flags & XTENSA_PROP_UNREACHABLE)); - - return (a->flags - b->flags); - } - - return (a->address - b->address); -} - - -static int -property_table_matches (const void *ap, const void *bp) -{ - const property_table_entry *a = (const property_table_entry *) ap; - const property_table_entry *b = (const property_table_entry *) bp; - - /* Check if one entry overlaps with the other. */ - if ((b->address >= a->address && b->address < (a->address + a->size)) - || (a->address >= b->address && a->address < (b->address + b->size))) - return 0; - - return (a->address - b->address); -} - - -/* Get the literal table or property table entries for the given - section. Sets TABLE_P and returns the number of entries. On - error, returns a negative value. */ - -static int -xtensa_read_table_entries (bfd *abfd, - asection *section, - property_table_entry **table_p, - const char *sec_name, - bfd_boolean output_addr) -{ - asection *table_section; - bfd_size_type table_size = 0; - bfd_byte *table_data; - property_table_entry *blocks; - int blk, block_count; - bfd_size_type num_records; - Elf_Internal_Rela *internal_relocs, *irel, *rel_end; - bfd_vma section_addr, off; - flagword predef_flags; - bfd_size_type table_entry_size, section_limit; - - if (!section - || !(section->flags & SEC_ALLOC) - || (section->flags & SEC_DEBUGGING)) - { - *table_p = NULL; - return 0; - } - - table_section = xtensa_get_property_section (section, sec_name); - if (table_section) - table_size = table_section->size; - - if (table_size == 0) - { - *table_p = NULL; - return 0; - } - - predef_flags = xtensa_get_property_predef_flags (table_section); - table_entry_size = 12; - if (predef_flags) - table_entry_size -= 4; - - num_records = table_size / table_entry_size; - table_data = retrieve_contents (abfd, table_section, TRUE); - blocks = (property_table_entry *) - bfd_malloc (num_records * sizeof (property_table_entry)); - block_count = 0; - - if (output_addr) - section_addr = section->output_section->vma + section->output_offset; - else - section_addr = section->vma; - - internal_relocs = retrieve_internal_relocs (abfd, table_section, TRUE); - if (internal_relocs && !table_section->reloc_done) - { - qsort (internal_relocs, table_section->reloc_count, - sizeof (Elf_Internal_Rela), internal_reloc_compare); - irel = internal_relocs; - } - else - irel = NULL; - - section_limit = bfd_get_section_limit (abfd, section); - rel_end = internal_relocs + table_section->reloc_count; - - for (off = 0; off < table_size; off += table_entry_size) - { - bfd_vma address = bfd_get_32 (abfd, table_data + off); - - /* Skip any relocations before the current offset. This should help - avoid confusion caused by unexpected relocations for the preceding - table entry. */ - while (irel && - (irel->r_offset < off - || (irel->r_offset == off - && ELF32_R_TYPE (irel->r_info) == R_XTENSA_NONE))) - { - irel += 1; - if (irel >= rel_end) - irel = 0; - } - - if (irel && irel->r_offset == off) - { - bfd_vma sym_off; - unsigned long r_symndx = ELF32_R_SYM (irel->r_info); - BFD_ASSERT (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32); - - if (get_elf_r_symndx_section (abfd, r_symndx) != section) - continue; - - sym_off = get_elf_r_symndx_offset (abfd, r_symndx); - BFD_ASSERT (sym_off == 0); - address += (section_addr + sym_off + irel->r_addend); - } - else - { - if (address < section_addr - || address >= section_addr + section_limit) - continue; - } - - blocks[block_count].address = address; - blocks[block_count].size = bfd_get_32 (abfd, table_data + off + 4); - if (predef_flags) - blocks[block_count].flags = predef_flags; - else - blocks[block_count].flags = bfd_get_32 (abfd, table_data + off + 8); - block_count++; - } - - release_contents (table_section, table_data); - release_internal_relocs (table_section, internal_relocs); - - if (block_count > 0) - { - /* Now sort them into address order for easy reference. */ - qsort (blocks, block_count, sizeof (property_table_entry), - property_table_compare); - - /* Check that the table contents are valid. Problems may occur, - for example, if an unrelocated object file is stripped. */ - for (blk = 1; blk < block_count; blk++) - { - /* The only circumstance where two entries may legitimately - have the same address is when one of them is a zero-size - placeholder to mark a place where fill can be inserted. - The zero-size entry should come first. */ - if (blocks[blk - 1].address == blocks[blk].address && - blocks[blk - 1].size != 0) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B(%A): invalid property table"), - abfd, section); - bfd_set_error (bfd_error_bad_value); - free (blocks); - return -1; - } - } - } - - *table_p = blocks; - return block_count; -} - - -static property_table_entry * -elf_xtensa_find_property_entry (property_table_entry *property_table, - int property_table_size, - bfd_vma addr) -{ - property_table_entry entry; - property_table_entry *rv; - - if (property_table_size == 0) - return NULL; - - entry.address = addr; - entry.size = 1; - entry.flags = 0; - - rv = bsearch (&entry, property_table, property_table_size, - sizeof (property_table_entry), property_table_matches); - return rv; -} - - -static bfd_boolean -elf_xtensa_in_literal_pool (property_table_entry *lit_table, - int lit_table_size, - bfd_vma addr) -{ - if (elf_xtensa_find_property_entry (lit_table, lit_table_size, addr)) - return TRUE; - - return FALSE; -} - - -/* Look through the relocs for a section during the first phase, and - calculate needed space in the dynamic reloc sections. */ - -static bfd_boolean -elf_xtensa_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_xtensa_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; - - if (bfd_link_relocatable (info) || (sec->flags & SEC_ALLOC) == 0) - return TRUE; - - BFD_ASSERT (is_xtensa_elf (abfd)); - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned r_symndx; - struct elf_link_hash_entry *h = NULL; - struct elf_xtensa_link_hash_entry *eh; - int tls_type, old_tls_type; - bfd_boolean is_got = FALSE; - bfd_boolean is_plt = FALSE; - bfd_boolean is_tlsfunc = FALSE; - - r_symndx = ELF32_R_SYM (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), - abfd, r_symndx); - return FALSE; - } - - if (r_symndx >= symtab_hdr->sh_info) - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - eh = elf_xtensa_hash_entry (h); - - switch (r_type) - { - case R_XTENSA_TLSDESC_FN: - if (bfd_link_pic (info)) - { - tls_type = GOT_TLS_GD; - is_got = TRUE; - is_tlsfunc = TRUE; - } - else - tls_type = GOT_TLS_IE; - break; - - case R_XTENSA_TLSDESC_ARG: - if (bfd_link_pic (info)) - { - tls_type = GOT_TLS_GD; - is_got = TRUE; - } - else - { - tls_type = GOT_TLS_IE; - if (h && elf_xtensa_hash_entry (h) != htab->tlsbase) - is_got = TRUE; - } - break; - - case R_XTENSA_TLS_DTPOFF: - if (bfd_link_pic (info)) - tls_type = GOT_TLS_GD; - else - tls_type = GOT_TLS_IE; - break; - - case R_XTENSA_TLS_TPOFF: - tls_type = GOT_TLS_IE; - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - if (bfd_link_pic (info) || h) - is_got = TRUE; - break; - - case R_XTENSA_32: - tls_type = GOT_NORMAL; - is_got = TRUE; - break; - - case R_XTENSA_PLT: - tls_type = GOT_NORMAL; - is_plt = TRUE; - break; - - case R_XTENSA_GNU_VTINHERIT: - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - continue; - - case R_XTENSA_GNU_VTENTRY: - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - continue; - - default: - /* Nothing to do for any other relocations. */ - continue; - } - - if (h) - { - if (is_plt) - { - if (h->plt.refcount <= 0) - { - h->needs_plt = 1; - h->plt.refcount = 1; - } - else - h->plt.refcount += 1; - - /* Keep track of the total PLT relocation count even if we - don't yet know whether the dynamic sections will be - created. */ - htab->plt_reloc_count += 1; - - if (elf_hash_table (info)->dynamic_sections_created) - { - if (! add_extra_plt_sections (info, htab->plt_reloc_count)) - return FALSE; - } - } - else if (is_got) - { - if (h->got.refcount <= 0) - h->got.refcount = 1; - else - h->got.refcount += 1; - } - - if (is_tlsfunc) - eh->tlsfunc_refcount += 1; - - old_tls_type = eh->tls_type; - } - else - { - /* Allocate storage the first time. */ - if (elf_local_got_refcounts (abfd) == NULL) - { - bfd_size_type size = symtab_hdr->sh_info; - void *mem; - - mem = bfd_zalloc (abfd, size * sizeof (bfd_signed_vma)); - if (mem == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = (bfd_signed_vma *) mem; - - mem = bfd_zalloc (abfd, size); - if (mem == NULL) - return FALSE; - elf_xtensa_local_got_tls_type (abfd) = (char *) mem; - - mem = bfd_zalloc (abfd, size * sizeof (bfd_signed_vma)); - if (mem == NULL) - return FALSE; - elf_xtensa_local_tlsfunc_refcounts (abfd) - = (bfd_signed_vma *) mem; - } - - /* This is a global offset table entry for a local symbol. */ - if (is_got || is_plt) - elf_local_got_refcounts (abfd) [r_symndx] += 1; - - if (is_tlsfunc) - elf_xtensa_local_tlsfunc_refcounts (abfd) [r_symndx] += 1; - - old_tls_type = elf_xtensa_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 a dynamic model for it. */ - else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN - && ((old_tls_type & GOT_TLS_GD) == 0 - || (tls_type & GOT_TLS_IE) == 0)) - { - if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_GD)) - tls_type = old_tls_type; - else if ((old_tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_GD)) - tls_type |= old_tls_type; - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%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 (eh) - eh->tls_type = tls_type; - else - elf_xtensa_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - } - - return TRUE; -} - - -static void -elf_xtensa_make_sym_local (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - if (bfd_link_pic (info)) - { - if (h->plt.refcount > 0) - { - /* For shared objects, there's no need for PLT entries for local - symbols (use RELATIVE relocs instead of JMP_SLOT relocs). */ - if (h->got.refcount < 0) - h->got.refcount = 0; - h->got.refcount += h->plt.refcount; - h->plt.refcount = 0; - } - } - else - { - /* Don't need any dynamic relocations at all. */ - h->plt.refcount = 0; - h->got.refcount = 0; - } -} - - -static void -elf_xtensa_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - bfd_boolean force_local) -{ - /* For a shared link, move the plt refcount to the got refcount to leave - space for RELATIVE relocs. */ - elf_xtensa_make_sym_local (info, h); - - _bfd_elf_link_hash_hide_symbol (info, h, force_local); -} - - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -elf_xtensa_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - /* Property sections are marked "KEEP" in the linker scripts, but they - should not cause other sections to be marked. (This approach relies - on elf_xtensa_discard_info to remove property table entries that - describe discarded sections. Alternatively, it might be more - efficient to avoid using "KEEP" in the linker scripts and instead use - the gc_mark_extra_sections hook to mark only the property sections - that describe marked sections. That alternative does not work well - with the current property table sections, which do not correspond - one-to-one with the sections they describe, but that should be fixed - someday.) */ - if (xtensa_is_property_section (sec)) - return NULL; - - if (h != NULL) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_XTENSA_GNU_VTINHERIT: - case R_XTENSA_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - - -/* Create all the dynamic sections. */ - -static bfd_boolean -elf_xtensa_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf_xtensa_link_hash_table *htab; - flagword flags, noalloc_flags; - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - /* First do all the standard stuff. */ - if (! _bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - /* Create any extra PLT sections in case check_relocs has already - been called on all the non-dynamic input files. */ - if (! add_extra_plt_sections (info, htab->plt_reloc_count)) - return FALSE; - - noalloc_flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY); - flags = noalloc_flags | SEC_ALLOC | SEC_LOAD; - - /* Mark the ".got.plt" section READONLY. */ - if (htab->elf.sgotplt == NULL - || ! bfd_set_section_flags (dynobj, htab->elf.sgotplt, flags)) - return FALSE; - - /* Create ".got.loc" (literal tables for use by dynamic linker). */ - htab->sgotloc = bfd_make_section_anyway_with_flags (dynobj, ".got.loc", - flags); - if (htab->sgotloc == NULL - || ! bfd_set_section_alignment (dynobj, htab->sgotloc, 2)) - return FALSE; - - /* Create ".xt.lit.plt" (literal table for ".got.plt*"). */ - htab->spltlittbl = bfd_make_section_anyway_with_flags (dynobj, ".xt.lit.plt", - noalloc_flags); - if (htab->spltlittbl == NULL - || ! bfd_set_section_alignment (dynobj, htab->spltlittbl, 2)) - return FALSE; - - return TRUE; -} - - -static bfd_boolean -add_extra_plt_sections (struct bfd_link_info *info, int count) -{ - bfd *dynobj = elf_hash_table (info)->dynobj; - int chunk; - - /* Iterate over all chunks except 0 which uses the standard ".plt" and - ".got.plt" sections. */ - for (chunk = count / PLT_ENTRIES_PER_CHUNK; chunk > 0; chunk--) - { - char *sname; - flagword flags; - asection *s; - - /* Stop when we find a section has already been created. */ - if (elf_xtensa_get_plt_section (info, chunk)) - break; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY); - - sname = (char *) bfd_malloc (10); - sprintf (sname, ".plt.%u", chunk); - s = bfd_make_section_anyway_with_flags (dynobj, sname, flags | SEC_CODE); - if (s == NULL - || ! bfd_set_section_alignment (dynobj, s, 2)) - return FALSE; - - sname = (char *) bfd_malloc (14); - sprintf (sname, ".got.plt.%u", chunk); - s = bfd_make_section_anyway_with_flags (dynobj, sname, flags); - if (s == NULL - || ! bfd_set_section_alignment (dynobj, s, 2)) - return FALSE; - } - - 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_xtensa_adjust_dynamic_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h) -{ - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object. The - reference must go through the GOT, so there's no need for COPY relocs, - .dynbss, etc. */ - - return TRUE; -} - - -static bfd_boolean -elf_xtensa_allocate_dynrelocs (struct elf_link_hash_entry *h, void *arg) -{ - struct bfd_link_info *info; - struct elf_xtensa_link_hash_table *htab; - struct elf_xtensa_link_hash_entry *eh = elf_xtensa_hash_entry (h); - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) arg; - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - /* If we saw any use of an IE model for this symbol, we can then optimize - away GOT entries for any TLSDESC_FN relocs. */ - if ((eh->tls_type & GOT_TLS_IE) != 0) - { - BFD_ASSERT (h->got.refcount >= eh->tlsfunc_refcount); - h->got.refcount -= eh->tlsfunc_refcount; - } - - if (! elf_xtensa_dynamic_symbol_p (h, info)) - elf_xtensa_make_sym_local (info, h); - - if (h->plt.refcount > 0) - htab->elf.srelplt->size += (h->plt.refcount * sizeof (Elf32_External_Rela)); - - if (h->got.refcount > 0) - htab->elf.srelgot->size += (h->got.refcount * sizeof (Elf32_External_Rela)); - - return TRUE; -} - - -static void -elf_xtensa_allocate_local_got_size (struct bfd_link_info *info) -{ - struct elf_xtensa_link_hash_table *htab; - bfd *i; - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return; - - for (i = info->input_bfds; i; i = i->link.next) - { - bfd_signed_vma *local_got_refcounts; - bfd_size_type j, cnt; - Elf_Internal_Shdr *symtab_hdr; - - local_got_refcounts = elf_local_got_refcounts (i); - if (!local_got_refcounts) - continue; - - symtab_hdr = &elf_tdata (i)->symtab_hdr; - cnt = symtab_hdr->sh_info; - - for (j = 0; j < cnt; ++j) - { - /* If we saw any use of an IE model for this symbol, we can - then optimize away GOT entries for any TLSDESC_FN relocs. */ - if ((elf_xtensa_local_got_tls_type (i) [j] & GOT_TLS_IE) != 0) - { - bfd_signed_vma *tlsfunc_refcount - = &elf_xtensa_local_tlsfunc_refcounts (i) [j]; - BFD_ASSERT (local_got_refcounts[j] >= *tlsfunc_refcount); - local_got_refcounts[j] -= *tlsfunc_refcount; - } - - if (local_got_refcounts[j] > 0) - htab->elf.srelgot->size += (local_got_refcounts[j] - * sizeof (Elf32_External_Rela)); - } - } -} - - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_xtensa_link_hash_table *htab; - bfd *dynobj, *abfd; - asection *s, *srelplt, *splt, *sgotplt, *srelgot, *spltlittbl, *sgotloc; - bfd_boolean relplt, relgot; - int plt_entries, plt_chunks, chunk; - - plt_entries = 0; - plt_chunks = 0; - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - abort (); - srelgot = htab->elf.srelgot; - srelplt = htab->elf.srelplt; - - if (elf_hash_table (info)->dynamic_sections_created) - { - BFD_ASSERT (htab->elf.srelgot != NULL - && htab->elf.srelplt != NULL - && htab->elf.sgot != NULL - && htab->spltlittbl != NULL - && htab->sgotloc != NULL); - - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - if (s == NULL) - abort (); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - - /* Allocate room for one word in ".got". */ - htab->elf.sgot->size = 4; - - /* Allocate space in ".rela.got" for literals that reference global - symbols and space in ".rela.plt" for literals that have PLT - entries. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_xtensa_allocate_dynrelocs, - (void *) info); - - /* If we are generating a shared object, we also need space in - ".rela.got" for R_XTENSA_RELATIVE relocs for literals that - reference local symbols. */ - if (bfd_link_pic (info)) - elf_xtensa_allocate_local_got_size (info); - - /* Allocate space in ".plt" to match the size of ".rela.plt". For - each PLT entry, we need the PLT code plus a 4-byte literal. - For each chunk of ".plt", we also need two more 4-byte - literals, two corresponding entries in ".rela.got", and an - 8-byte entry in ".xt.lit.plt". */ - spltlittbl = htab->spltlittbl; - plt_entries = srelplt->size / sizeof (Elf32_External_Rela); - plt_chunks = - (plt_entries + PLT_ENTRIES_PER_CHUNK - 1) / PLT_ENTRIES_PER_CHUNK; - - /* Iterate over all the PLT chunks, including any extra sections - created earlier because the initial count of PLT relocations - was an overestimate. */ - for (chunk = 0; - (splt = elf_xtensa_get_plt_section (info, chunk)) != NULL; - chunk++) - { - int chunk_entries; - - sgotplt = elf_xtensa_get_gotplt_section (info, chunk); - BFD_ASSERT (sgotplt != NULL); - - if (chunk < plt_chunks - 1) - chunk_entries = PLT_ENTRIES_PER_CHUNK; - else if (chunk == plt_chunks - 1) - chunk_entries = plt_entries - (chunk * PLT_ENTRIES_PER_CHUNK); - else - chunk_entries = 0; - - if (chunk_entries != 0) - { - sgotplt->size = 4 * (chunk_entries + 2); - splt->size = PLT_ENTRY_SIZE * chunk_entries; - srelgot->size += 2 * sizeof (Elf32_External_Rela); - spltlittbl->size += 8; - } - else - { - sgotplt->size = 0; - splt->size = 0; - } - } - - /* Allocate space in ".got.loc" to match the total size of all the - literal tables. */ - sgotloc = htab->sgotloc; - sgotloc->size = spltlittbl->size; - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) - { - if (abfd->flags & DYNAMIC) - continue; - for (s = abfd->sections; s != NULL; s = s->next) - { - if (! discarded_section (s) - && xtensa_is_littable_section (s) - && s != spltlittbl) - sgotloc->size += s->size; - } - } - } - - /* Allocate memory for dynamic sections. */ - relplt = FALSE; - relgot = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - if (strcmp (name, ".rela.plt") == 0) - relplt = TRUE; - else if (strcmp (name, ".rela.got") == 0) - relgot = 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 if (! CONST_STRNEQ (name, ".plt.") - && ! CONST_STRNEQ (name, ".got.plt.") - && strcmp (name, ".got") != 0 - && strcmp (name, ".plt") != 0 - && strcmp (name, ".got.plt") != 0 - && strcmp (name, ".xt.lit.plt") != 0 - && strcmp (name, ".got.loc") != 0) - { - /* 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. We must create the ".plt*" and ".got.plt*" - sections in create_dynamic_sections and/or check_relocs - based on a conservative estimate of the PLT relocation - count, because the sections must be created before the - linker maps input sections to output sections. The - linker does that before size_dynamic_sections, where we - compute the exact size of the PLT, so there may be more - of these sections than are actually needed. */ - s->flags |= SEC_EXCLUDE; - } - else if ((s->flags & SEC_HAS_CONTENTS) != 0) - { - /* Allocate memory for the section contents. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add the special XTENSA_RTLD relocations now. The offsets won't be - known until finish_dynamic_sections, but we need to get the relocs - in place before they are sorted. */ - for (chunk = 0; chunk < plt_chunks; chunk++) - { - Elf_Internal_Rela irela; - bfd_byte *loc; - - irela.r_offset = 0; - irela.r_info = ELF32_R_INFO (0, R_XTENSA_RTLD); - irela.r_addend = 0; - - loc = (srelgot->contents - + srelgot->reloc_count * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &irela, loc); - bfd_elf32_swap_reloca_out (output_bfd, &irela, - loc + sizeof (Elf32_External_Rela)); - srelgot->reloc_count += 2; - } - - /* Add some entries to the .dynamic section. We fill in the - values later, in elf_xtensa_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (relplt) - { - if (!add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relgot) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) - return FALSE; - } - - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_XTENSA_GOT_LOC_OFF, 0) - || !add_dynamic_entry (DT_XTENSA_GOT_LOC_SZ, 0)) - return FALSE; - } -#undef add_dynamic_entry - - return TRUE; -} - -static bfd_boolean -elf_xtensa_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_xtensa_link_hash_table *htab; - asection *tls_sec; - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - tls_sec = htab->elf.tls_sec; - - if (tls_sec && (htab->tlsbase->tls_type & GOT_TLS_ANY) != 0) - { - struct elf_link_hash_entry *tlsbase = &htab->tlsbase->elf; - struct bfd_link_hash_entry *bh = &tlsbase->root; - const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); - - tlsbase->type = STT_TLS; - 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->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); - bfd_vma base; - - /* If tls_sec is NULL, we should have signalled an error already. */ - if (htab->tls_sec == NULL) - return 0; - base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power); - return address - htab->tls_sec->vma + base; -} - -/* Perform the specified relocation. The instruction at (contents + address) - is modified to set one operand to represent the value in "relocation". The - operand position is determined by the relocation type recorded in the - howto. */ - -#define CALL_SEGMENT_BITS (30) -#define CALL_SEGMENT_SIZE (1 << CALL_SEGMENT_BITS) - -static bfd_reloc_status_type -elf_xtensa_do_reloc (reloc_howto_type *howto, - bfd *abfd, - asection *input_section, - bfd_vma relocation, - bfd_byte *contents, - bfd_vma address, - bfd_boolean is_weak_undef, - char **error_message) -{ - xtensa_format fmt; - xtensa_opcode opcode; - xtensa_isa isa = xtensa_default_isa; - static xtensa_insnbuf ibuff = NULL; - static xtensa_insnbuf sbuff = NULL; - bfd_vma self_address; - bfd_size_type input_size; - int opnd, slot; - uint32 newval; - - if (!ibuff) - { - ibuff = xtensa_insnbuf_alloc (isa); - sbuff = xtensa_insnbuf_alloc (isa); - } - - input_size = bfd_get_section_limit (abfd, input_section); - - /* Calculate the PC address for this instruction. */ - self_address = (input_section->output_section->vma - + input_section->output_offset - + address); - - switch (howto->type) - { - case R_XTENSA_NONE: - case R_XTENSA_DIFF8: - case R_XTENSA_DIFF16: - case R_XTENSA_DIFF32: - case R_XTENSA_TLS_FUNC: - case R_XTENSA_TLS_ARG: - case R_XTENSA_TLS_CALL: - return bfd_reloc_ok; - - case R_XTENSA_ASM_EXPAND: - if (!is_weak_undef) - { - /* Check for windowed CALL across a 1GB boundary. */ - opcode = get_expanded_call_opcode (contents + address, - input_size - address, 0); - if (is_windowed_call_opcode (opcode)) - { - if ((self_address >> CALL_SEGMENT_BITS) - != (relocation >> CALL_SEGMENT_BITS)) - { - *error_message = "windowed longcall crosses 1GB boundary; " - "return may fail"; - return bfd_reloc_dangerous; - } - } - } - return bfd_reloc_ok; - - case R_XTENSA_ASM_SIMPLIFY: - { - /* Convert the L32R/CALLX to CALL. */ - bfd_reloc_status_type retval = - elf_xtensa_do_asm_simplify (contents, address, input_size, - error_message); - if (retval != bfd_reloc_ok) - return bfd_reloc_dangerous; - - /* The CALL needs to be relocated. Continue below for that part. */ - address += 3; - self_address += 3; - howto = &elf_howto_table[(unsigned) R_XTENSA_SLOT0_OP ]; - } - break; - - case R_XTENSA_32: - { - bfd_vma x; - x = bfd_get_32 (abfd, contents + address); - x = x + relocation; - bfd_put_32 (abfd, x, contents + address); - } - return bfd_reloc_ok; - - case R_XTENSA_32_PCREL: - bfd_put_32 (abfd, relocation - self_address, contents + address); - return bfd_reloc_ok; - - case R_XTENSA_PLT: - case R_XTENSA_TLSDESC_FN: - case R_XTENSA_TLSDESC_ARG: - case R_XTENSA_TLS_DTPOFF: - case R_XTENSA_TLS_TPOFF: - bfd_put_32 (abfd, relocation, contents + address); - return bfd_reloc_ok; - } - - /* Only instruction slot-specific relocations handled below.... */ - slot = get_relocation_slot (howto->type); - if (slot == XTENSA_UNDEFINED) - { - *error_message = "unexpected relocation"; - return bfd_reloc_dangerous; - } - - /* Read the instruction into a buffer and decode the opcode. */ - xtensa_insnbuf_from_chars (isa, ibuff, contents + address, - input_size - address); - fmt = xtensa_format_decode (isa, ibuff); - if (fmt == XTENSA_UNDEFINED) - { - *error_message = "cannot decode instruction format"; - return bfd_reloc_dangerous; - } - - xtensa_format_get_slot (isa, fmt, slot, ibuff, sbuff); - - opcode = xtensa_opcode_decode (isa, fmt, slot, sbuff); - if (opcode == XTENSA_UNDEFINED) - { - *error_message = "cannot decode instruction opcode"; - return bfd_reloc_dangerous; - } - - /* Check for opcode-specific "alternate" relocations. */ - if (is_alt_relocation (howto->type)) - { - if (opcode == get_l32r_opcode ()) - { - /* Handle the special-case of non-PC-relative L32R instructions. */ - bfd *output_bfd = input_section->output_section->owner; - asection *lit4_sec = bfd_get_section_by_name (output_bfd, ".lit4"); - if (!lit4_sec) - { - *error_message = "relocation references missing .lit4 section"; - return bfd_reloc_dangerous; - } - self_address = ((lit4_sec->vma & ~0xfff) - + 0x40000 - 3); /* -3 to compensate for do_reloc */ - newval = relocation; - opnd = 1; - } - else if (opcode == get_const16_opcode ()) - { - /* ALT used for high 16 bits. */ - newval = relocation >> 16; - opnd = 1; - } - else - { - /* No other "alternate" relocations currently defined. */ - *error_message = "unexpected relocation"; - return bfd_reloc_dangerous; - } - } - else /* Not an "alternate" relocation.... */ - { - if (opcode == get_const16_opcode ()) - { - newval = relocation & 0xffff; - opnd = 1; - } - else - { - /* ...normal PC-relative relocation.... */ - - /* Determine which operand is being relocated. */ - opnd = get_relocation_opnd (opcode, howto->type); - if (opnd == XTENSA_UNDEFINED) - { - *error_message = "unexpected relocation"; - return bfd_reloc_dangerous; - } - - if (!howto->pc_relative) - { - *error_message = "expected PC-relative relocation"; - return bfd_reloc_dangerous; - } - - newval = relocation; - } - } - - /* Apply the relocation. */ - if (xtensa_operand_do_reloc (isa, opcode, opnd, &newval, self_address) - || xtensa_operand_encode (isa, opcode, opnd, &newval) - || xtensa_operand_set_field (isa, opcode, opnd, fmt, slot, - sbuff, newval)) - { - const char *opname = xtensa_opcode_name (isa, opcode); - const char *msg; - - msg = "cannot encode"; - if (is_direct_call_opcode (opcode)) - { - if ((relocation & 0x3) != 0) - msg = "misaligned call target"; - else - msg = "call target out of range"; - } - else if (opcode == get_l32r_opcode ()) - { - if ((relocation & 0x3) != 0) - msg = "misaligned literal target"; - else if (is_alt_relocation (howto->type)) - msg = "literal target out of range (too many literals)"; - else if (self_address > relocation) - msg = "literal target out of range (try using text-section-literals)"; - else - msg = "literal placed after use"; - } - - *error_message = vsprint_msg (opname, ": %s", strlen (msg) + 2, msg); - return bfd_reloc_dangerous; - } - - /* Check for calls across 1GB boundaries. */ - if (is_direct_call_opcode (opcode) - && is_windowed_call_opcode (opcode)) - { - if ((self_address >> CALL_SEGMENT_BITS) - != (relocation >> CALL_SEGMENT_BITS)) - { - *error_message = - "windowed call crosses 1GB boundary; return may fail"; - return bfd_reloc_dangerous; - } - } - - /* Write the modified instruction back out of the buffer. */ - xtensa_format_set_slot (isa, fmt, slot, ibuff, sbuff); - xtensa_insnbuf_to_chars (isa, ibuff, contents + address, - input_size - address); - return bfd_reloc_ok; -} - - -static char * -vsprint_msg (const char *origmsg, const char *fmt, int arglen, ...) -{ - /* To reduce the size of the memory leak, - we only use a single message buffer. */ - static bfd_size_type alloc_size = 0; - static char *message = NULL; - bfd_size_type orig_len, len = 0; - bfd_boolean is_append; - va_list ap; - - va_start (ap, arglen); - - is_append = (origmsg == message); - - orig_len = strlen (origmsg); - len = orig_len + strlen (fmt) + arglen + 20; - if (len > alloc_size) - { - message = (char *) bfd_realloc_or_free (message, len); - alloc_size = len; - } - if (message != NULL) - { - if (!is_append) - memcpy (message, origmsg, orig_len); - vsprintf (message + orig_len, fmt, ap); - } - va_end (ap); - return message; -} - - -/* This function is registered as the "special_function" in the - Xtensa howto for handling simplify operations. - bfd_perform_relocation / bfd_install_relocation use it to - perform (install) the specified relocation. Since this replaces the code - in bfd_perform_relocation, it is basically an Xtensa-specific, - stripped-down version of bfd_perform_relocation. */ - -static bfd_reloc_status_type -bfd_elf_xtensa_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void *data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_vma relocation; - bfd_reloc_status_type flag; - 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; - bfd_boolean is_weak_undef; - - if (!xtensa_default_isa) - xtensa_default_isa = xtensa_isa_init (0, 0); - - /* ELF relocs are against symbols. If we are producing relocatable - output, and the reloc is against an external symbol, 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. This test is similar - to what bfd_elf_generic_reloc does except that it lets relocs with - howto->partial_inplace go through even if the addend is non-zero. - (The real problem is that partial_inplace is set for XTENSA_32 - relocs to begin with, but that's a long story and there's little we - can do about it now....) */ - - if (output_bfd && (symbol->flags & BSF_SECTION_SYM) == 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - /* 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 (output_bfd) - { - 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. Everything except - relocations against section symbols has already been handled - above. */ - - BFD_ASSERT (symbol->flags & BSF_SECTION_SYM); - reloc_entry->addend = relocation; - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - else - { - reloc_entry->address += input_section->output_offset; - reloc_entry->addend = 0; - } - } - - is_weak_undef = (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) != 0); - flag = elf_xtensa_do_reloc (howto, abfd, input_section, relocation, - (bfd_byte *) data, (bfd_vma) octets, - is_weak_undef, error_message); - - if (flag == bfd_reloc_dangerous) - { - /* Add the symbol name to the error message. */ - if (! *error_message) - *error_message = ""; - *error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)", - strlen (symbol->name) + 17, - symbol->name, - (unsigned long) reloc_entry->addend); - } - - return flag; -} - - -/* Set up an entry in the procedure linkage table. */ - -static bfd_vma -elf_xtensa_create_plt_entry (struct bfd_link_info *info, - bfd *output_bfd, - unsigned reloc_index) -{ - asection *splt, *sgotplt; - bfd_vma plt_base, got_base; - bfd_vma code_offset, lit_offset, abi_offset; - int chunk; - - chunk = reloc_index / PLT_ENTRIES_PER_CHUNK; - splt = elf_xtensa_get_plt_section (info, chunk); - sgotplt = elf_xtensa_get_gotplt_section (info, chunk); - BFD_ASSERT (splt != NULL && sgotplt != NULL); - - plt_base = splt->output_section->vma + splt->output_offset; - got_base = sgotplt->output_section->vma + sgotplt->output_offset; - - lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4; - code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE; - - /* Fill in the literal entry. This is the offset of the dynamic - relocation entry. */ - bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela), - sgotplt->contents + lit_offset); - - /* Fill in the entry in the procedure linkage table. */ - memcpy (splt->contents + code_offset, - (bfd_big_endian (output_bfd) - ? elf_xtensa_be_plt_entry[XSHAL_ABI != XTHAL_ABI_WINDOWED] - : elf_xtensa_le_plt_entry[XSHAL_ABI != XTHAL_ABI_WINDOWED]), - PLT_ENTRY_SIZE); - abi_offset = XSHAL_ABI == XTHAL_ABI_WINDOWED ? 3 : 0; - bfd_put_16 (output_bfd, l32r_offset (got_base + 0, - plt_base + code_offset + abi_offset), - splt->contents + code_offset + abi_offset + 1); - bfd_put_16 (output_bfd, l32r_offset (got_base + 4, - plt_base + code_offset + abi_offset + 3), - splt->contents + code_offset + abi_offset + 4); - bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset, - plt_base + code_offset + abi_offset + 6), - splt->contents + code_offset + abi_offset + 7); - - return plt_base + code_offset; -} - - -static bfd_boolean get_indirect_call_dest_reg (xtensa_opcode, unsigned *); - -static bfd_boolean -replace_tls_insn (Elf_Internal_Rela *rel, - bfd *abfd, - asection *input_section, - bfd_byte *contents, - bfd_boolean is_ld_model, - char **error_message) -{ - static xtensa_insnbuf ibuff = NULL; - static xtensa_insnbuf sbuff = NULL; - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - xtensa_opcode old_op, new_op; - bfd_size_type input_size; - int r_type; - unsigned dest_reg, src_reg; - - if (ibuff == NULL) - { - ibuff = xtensa_insnbuf_alloc (isa); - sbuff = xtensa_insnbuf_alloc (isa); - } - - input_size = bfd_get_section_limit (abfd, input_section); - - /* Read the instruction into a buffer and decode the opcode. */ - xtensa_insnbuf_from_chars (isa, ibuff, contents + rel->r_offset, - input_size - rel->r_offset); - fmt = xtensa_format_decode (isa, ibuff); - if (fmt == XTENSA_UNDEFINED) - { - *error_message = "cannot decode instruction format"; - return FALSE; - } - - BFD_ASSERT (xtensa_format_num_slots (isa, fmt) == 1); - xtensa_format_get_slot (isa, fmt, 0, ibuff, sbuff); - - old_op = xtensa_opcode_decode (isa, fmt, 0, sbuff); - if (old_op == XTENSA_UNDEFINED) - { - *error_message = "cannot decode instruction opcode"; - return FALSE; - } - - r_type = ELF32_R_TYPE (rel->r_info); - switch (r_type) - { - case R_XTENSA_TLS_FUNC: - case R_XTENSA_TLS_ARG: - if (old_op != get_l32r_opcode () - || xtensa_operand_get_field (isa, old_op, 0, fmt, 0, - sbuff, &dest_reg) != 0) - { - *error_message = "cannot extract L32R destination for TLS access"; - return FALSE; - } - break; - - case R_XTENSA_TLS_CALL: - if (! get_indirect_call_dest_reg (old_op, &dest_reg) - || xtensa_operand_get_field (isa, old_op, 0, fmt, 0, - sbuff, &src_reg) != 0) - { - *error_message = "cannot extract CALLXn operands for TLS access"; - return FALSE; - } - break; - - default: - abort (); - } - - if (is_ld_model) - { - switch (r_type) - { - case R_XTENSA_TLS_FUNC: - case R_XTENSA_TLS_ARG: - /* Change the instruction to a NOP (or "OR a1, a1, a1" for older - versions of Xtensa). */ - new_op = xtensa_opcode_lookup (isa, "nop"); - if (new_op == XTENSA_UNDEFINED) - { - new_op = xtensa_opcode_lookup (isa, "or"); - if (new_op == XTENSA_UNDEFINED - || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 - || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, - sbuff, 1) != 0 - || xtensa_operand_set_field (isa, new_op, 1, fmt, 0, - sbuff, 1) != 0 - || xtensa_operand_set_field (isa, new_op, 2, fmt, 0, - sbuff, 1) != 0) - { - *error_message = "cannot encode OR for TLS access"; - return FALSE; - } - } - else - { - if (xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0) - { - *error_message = "cannot encode NOP for TLS access"; - return FALSE; - } - } - break; - - case R_XTENSA_TLS_CALL: - /* Read THREADPTR into the CALLX's return value register. */ - new_op = xtensa_opcode_lookup (isa, "rur.threadptr"); - if (new_op == XTENSA_UNDEFINED - || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 - || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, - sbuff, dest_reg + 2) != 0) - { - *error_message = "cannot encode RUR.THREADPTR for TLS access"; - return FALSE; - } - break; - } - } - else - { - switch (r_type) - { - case R_XTENSA_TLS_FUNC: - new_op = xtensa_opcode_lookup (isa, "rur.threadptr"); - if (new_op == XTENSA_UNDEFINED - || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 - || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, - sbuff, dest_reg) != 0) - { - *error_message = "cannot encode RUR.THREADPTR for TLS access"; - return FALSE; - } - break; - - case R_XTENSA_TLS_ARG: - /* Nothing to do. Keep the original L32R instruction. */ - return TRUE; - - case R_XTENSA_TLS_CALL: - /* Add the CALLX's src register (holding the THREADPTR value) - to the first argument register (holding the offset) and put - the result in the CALLX's return value register. */ - new_op = xtensa_opcode_lookup (isa, "add"); - if (new_op == XTENSA_UNDEFINED - || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 - || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, - sbuff, dest_reg + 2) != 0 - || xtensa_operand_set_field (isa, new_op, 1, fmt, 0, - sbuff, dest_reg + 2) != 0 - || xtensa_operand_set_field (isa, new_op, 2, fmt, 0, - sbuff, src_reg) != 0) - { - *error_message = "cannot encode ADD for TLS access"; - return FALSE; - } - break; - } - } - - xtensa_format_set_slot (isa, fmt, 0, ibuff, sbuff); - xtensa_insnbuf_to_chars (isa, ibuff, contents + rel->r_offset, - input_size - rel->r_offset); - - return TRUE; -} - - -#define IS_XTENSA_TLS_RELOC(R_TYPE) \ - ((R_TYPE) == R_XTENSA_TLSDESC_FN \ - || (R_TYPE) == R_XTENSA_TLSDESC_ARG \ - || (R_TYPE) == R_XTENSA_TLS_DTPOFF \ - || (R_TYPE) == R_XTENSA_TLS_TPOFF \ - || (R_TYPE) == R_XTENSA_TLS_FUNC \ - || (R_TYPE) == R_XTENSA_TLS_ARG \ - || (R_TYPE) == R_XTENSA_TLS_CALL) - -/* Relocate an Xtensa ELF section. This is invoked by the linker for - both relocatable and final links. */ - -static bfd_boolean -elf_xtensa_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_xtensa_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - struct elf_link_hash_entry **sym_hashes; - property_table_entry *lit_table = 0; - int ltblsize = 0; - char *local_got_tls_types; - char *error_message = NULL; - bfd_size_type input_size; - int tls_type; - - if (!xtensa_default_isa) - xtensa_default_isa = xtensa_isa_init (0, 0); - - BFD_ASSERT (is_xtensa_elf (input_bfd)); - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - local_got_tls_types = elf_xtensa_local_got_tls_type (input_bfd); - - if (elf_hash_table (info)->dynamic_sections_created) - { - ltblsize = xtensa_read_table_entries (input_bfd, input_section, - &lit_table, XTENSA_LIT_SEC_NAME, - TRUE); - if (ltblsize < 0) - return FALSE; - } - - input_size = bfd_get_section_limit (input_bfd, input_section); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - char sym_type; - const char *name; - asection *sec; - bfd_vma relocation; - bfd_reloc_status_type r; - bfd_boolean is_weak_undef; - bfd_boolean unresolved_reloc; - bfd_boolean warned; - bfd_boolean dynamic_symbol; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == (int) R_XTENSA_GNU_VTINHERIT - || r_type == (int) R_XTENSA_GNU_VTENTRY) - continue; - - if (r_type < 0 || r_type >= (int) R_XTENSA_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - howto = &elf_howto_table[r_type]; - - r_symndx = ELF32_R_SYM (rel->r_info); - - h = NULL; - sym = NULL; - sec = NULL; - is_weak_undef = FALSE; - unresolved_reloc = FALSE; - warned = FALSE; - - if (howto->partial_inplace && !bfd_link_relocatable (info)) - { - /* Because R_XTENSA_32 was made partial_inplace to fix some - problems with DWARF info in partial links, there may be - an addend stored in the contents. Take it out of there - and move it back into the addend field of the reloc. */ - rel->r_addend += bfd_get_32 (input_bfd, contents + rel->r_offset); - bfd_put_32 (input_bfd, 0, contents + rel->r_offset); - } - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sym_type = ELF32_ST_TYPE (sym->st_info); - sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - - if (relocation == 0 - && !unresolved_reloc - && h->root.type == bfd_link_hash_undefweak) - is_weak_undef = TRUE; - - sym_type = h->type; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - bfd_vma dest_addr; - asection * sym_sec = get_elf_r_symndx_section (input_bfd, r_symndx); - - /* This is a relocatable link. - 1) If the reloc is against a section symbol, adjust - according to the output section. - 2) If there is a new target for this relocation, - the new target will be in the same output section. - We adjust the relocation by the output section - difference. */ - - if (relaxing_section) - { - /* Check if this references a section in another input file. */ - if (!do_fix_for_relocatable_link (rel, input_bfd, input_section, - contents)) - return FALSE; - } - - dest_addr = sym_sec->output_section->vma + sym_sec->output_offset - + get_elf_r_symndx_offset (input_bfd, r_symndx) + rel->r_addend; - - if (r_type == R_XTENSA_ASM_SIMPLIFY) - { - error_message = NULL; - /* Convert ASM_SIMPLIFY into the simpler relocation - so that they never escape a relaxing link. */ - r = contract_asm_expansion (contents, input_size, rel, - &error_message); - if (r != bfd_reloc_ok) - (*info->callbacks->reloc_dangerous) - (info, error_message, - input_bfd, input_section, rel->r_offset); - - r_type = ELF32_R_TYPE (rel->r_info); - } - - /* This is a relocatable link, so 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) - { - sym = local_syms + r_symndx; - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - sec = local_sections[r_symndx]; - rel->r_addend += sec->output_offset + sym->st_value; - } - } - - /* If there is an addend with a partial_inplace howto, - then move the addend to the contents. This is a hack - to work around problems with DWARF in relocatable links - with some previous version of BFD. Now we can't easily get - rid of the hack without breaking backward compatibility.... */ - r = bfd_reloc_ok; - howto = &elf_howto_table[r_type]; - if (howto->partial_inplace && rel->r_addend) - { - r = elf_xtensa_do_reloc (howto, input_bfd, input_section, - rel->r_addend, contents, - rel->r_offset, FALSE, - &error_message); - rel->r_addend = 0; - } - else - { - /* Put the correct bits in the target instruction, even - though the relocation will still be present in the output - file. This makes disassembly clearer, as well as - allowing loadable kernel modules to work without needing - relocations on anything other than calls and l32r's. */ - - /* If it is not in the same section, there is nothing we can do. */ - if (r_type >= R_XTENSA_SLOT0_OP && r_type <= R_XTENSA_SLOT14_OP && - sym_sec->output_section == input_section->output_section) - { - r = elf_xtensa_do_reloc (howto, input_bfd, input_section, - dest_addr, contents, - rel->r_offset, FALSE, - &error_message); - } - } - if (r != bfd_reloc_ok) - (*info->callbacks->reloc_dangerous) - (info, error_message, - input_bfd, input_section, rel->r_offset); - - /* Done with work for relocatable link; continue with next reloc. */ - continue; - } - - /* This is a final link. */ - - if (relaxing_section) - { - /* Check if this references a section in another input file. */ - do_fix_for_final_link (rel, input_bfd, input_section, contents, - &relocation); - } - - /* Sanity check the address. */ - if (rel->r_offset >= input_size - && ELF32_R_TYPE (rel->r_info) != R_XTENSA_NONE) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): relocation offset out of range (size=%#Lx)"), - input_bfd, input_section, rel->r_offset, input_size); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (h != NULL) - name = h->root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - - if (r_symndx != STN_UNDEF - && r_type != R_XTENSA_NONE - && (h == NULL - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && IS_XTENSA_TLS_RELOC (r_type) != (sym_type == STT_TLS)) - { - _bfd_error_handler - ((sym_type == STT_TLS - /* xgettext:c-format */ - ? _("%B(%A+%#Lx): %s used with TLS symbol %s") - /* xgettext:c-format */ - : _("%B(%A+%#Lx): %s used with non-TLS symbol %s")), - input_bfd, - input_section, - rel->r_offset, - howto->name, - name); - } - - dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info); - - tls_type = GOT_UNKNOWN; - if (h) - tls_type = elf_xtensa_hash_entry (h)->tls_type; - else if (local_got_tls_types) - tls_type = local_got_tls_types [r_symndx]; - - switch (r_type) - { - case R_XTENSA_32: - case R_XTENSA_PLT: - if (elf_hash_table (info)->dynamic_sections_created - && (input_section->flags & SEC_ALLOC) != 0 - && (dynamic_symbol || bfd_link_pic (info))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - asection *srel; - - if (dynamic_symbol && r_type == R_XTENSA_PLT) - srel = htab->elf.srelplt; - else - srel = htab->elf.srelgot; - - BFD_ASSERT (srel != NULL); - - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - - if ((outrel.r_offset | 1) == (bfd_vma) -1) - memset (&outrel, 0, sizeof outrel); - else - { - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - /* Complain if the relocation is in a read-only section - and not in a literal pool. */ - if ((input_section->flags & SEC_READONLY) != 0 - && !elf_xtensa_in_literal_pool (lit_table, ltblsize, - outrel.r_offset)) - { - error_message = - _("dynamic relocation in read-only section"); - (*info->callbacks->reloc_dangerous) - (info, error_message, - input_bfd, input_section, rel->r_offset); - } - - if (dynamic_symbol) - { - outrel.r_addend = rel->r_addend; - rel->r_addend = 0; - - if (r_type == R_XTENSA_32) - { - outrel.r_info = - ELF32_R_INFO (h->dynindx, R_XTENSA_GLOB_DAT); - relocation = 0; - } - else /* r_type == R_XTENSA_PLT */ - { - outrel.r_info = - ELF32_R_INFO (h->dynindx, R_XTENSA_JMP_SLOT); - - /* Create the PLT entry and set the initial - contents of the literal entry to the address of - the PLT entry. */ - relocation = - elf_xtensa_create_plt_entry (info, output_bfd, - srel->reloc_count); - } - unresolved_reloc = FALSE; - } - else - { - /* Generate a RELATIVE relocation. */ - outrel.r_info = ELF32_R_INFO (0, R_XTENSA_RELATIVE); - outrel.r_addend = 0; - } - } - - loc = (srel->contents - + srel->reloc_count++ * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - BFD_ASSERT (sizeof (Elf32_External_Rela) * srel->reloc_count - <= srel->size); - } - else if (r_type == R_XTENSA_ASM_EXPAND && dynamic_symbol) - { - /* This should only happen for non-PIC code, which is not - supposed to be used on systems with dynamic linking. - Just ignore these relocations. */ - continue; - } - break; - - case R_XTENSA_TLS_TPOFF: - /* Switch to LE model for local symbols in an executable. */ - if (! bfd_link_pic (info) && ! dynamic_symbol) - { - relocation = tpoff (info, relocation); - break; - } - /* fall through */ - - case R_XTENSA_TLSDESC_FN: - case R_XTENSA_TLSDESC_ARG: - { - if (r_type == R_XTENSA_TLSDESC_FN) - { - if (! bfd_link_pic (info) || (tls_type & GOT_TLS_IE) != 0) - r_type = R_XTENSA_NONE; - } - else if (r_type == R_XTENSA_TLSDESC_ARG) - { - if (bfd_link_pic (info)) - { - if ((tls_type & GOT_TLS_IE) != 0) - r_type = R_XTENSA_TLS_TPOFF; - } - else - { - r_type = R_XTENSA_TLS_TPOFF; - if (! dynamic_symbol) - { - relocation = tpoff (info, relocation); - break; - } - } - } - - if (r_type == R_XTENSA_NONE) - /* Nothing to do here; skip to the next reloc. */ - continue; - - if (! elf_hash_table (info)->dynamic_sections_created) - { - error_message = - _("TLS relocation invalid without dynamic sections"); - (*info->callbacks->reloc_dangerous) - (info, error_message, - input_bfd, input_section, rel->r_offset); - } - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - asection *srel = htab->elf.srelgot; - int indx; - - outrel.r_offset = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - /* Complain if the relocation is in a read-only section - and not in a literal pool. */ - if ((input_section->flags & SEC_READONLY) != 0 - && ! elf_xtensa_in_literal_pool (lit_table, ltblsize, - outrel.r_offset)) - { - error_message = - _("dynamic relocation in read-only section"); - (*info->callbacks->reloc_dangerous) - (info, error_message, - input_bfd, input_section, rel->r_offset); - } - - indx = h && h->dynindx != -1 ? h->dynindx : 0; - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - rel->r_addend = 0; - - outrel.r_info = ELF32_R_INFO (indx, r_type); - relocation = 0; - unresolved_reloc = FALSE; - - BFD_ASSERT (srel); - loc = (srel->contents - + srel->reloc_count++ * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); - BFD_ASSERT (sizeof (Elf32_External_Rela) * srel->reloc_count - <= srel->size); - } - } - break; - - case R_XTENSA_TLS_DTPOFF: - if (! bfd_link_pic (info)) - /* Switch from LD model to LE model. */ - relocation = tpoff (info, relocation); - else - relocation -= dtpoff_base (info); - break; - - case R_XTENSA_TLS_FUNC: - case R_XTENSA_TLS_ARG: - case R_XTENSA_TLS_CALL: - /* Check if optimizing to IE or LE model. */ - if ((tls_type & GOT_TLS_IE) != 0) - { - bfd_boolean is_ld_model = - (h && elf_xtensa_hash_entry (h) == htab->tlsbase); - if (! replace_tls_insn (rel, input_bfd, input_section, contents, - is_ld_model, &error_message)) - (*info->callbacks->reloc_dangerous) - (info, error_message, - input_bfd, input_section, rel->r_offset); - - if (r_type != R_XTENSA_TLS_ARG || is_ld_model) - { - /* Skip subsequent relocations on the same instruction. */ - while (rel + 1 < relend && rel[1].r_offset == rel->r_offset) - rel++; - } - } - continue; - - default: - if (elf_hash_table (info)->dynamic_sections_created - && dynamic_symbol && (is_operand_relocation (r_type) - || r_type == R_XTENSA_32_PCREL)) - { - error_message = - vsprint_msg ("invalid relocation for dynamic symbol", ": %s", - strlen (name) + 2, name); - (*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, rel->r_offset); - continue; - } - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - name); - return FALSE; - } - - /* TLS optimizations may have changed r_type; update "howto". */ - howto = &elf_howto_table[r_type]; - - /* There's no point in calling bfd_perform_relocation here. - Just go directly to our "special function". */ - r = elf_xtensa_do_reloc (howto, input_bfd, input_section, - relocation + rel->r_addend, - contents, rel->r_offset, is_weak_undef, - &error_message); - - if (r != bfd_reloc_ok && !warned) - { - BFD_ASSERT (r == bfd_reloc_dangerous || r == bfd_reloc_other); - BFD_ASSERT (error_message != NULL); - - if (rel->r_addend == 0) - error_message = vsprint_msg (error_message, ": %s", - strlen (name) + 2, name); - else - error_message = vsprint_msg (error_message, ": (%s+0x%x)", - strlen (name) + 22, - name, (int) rel->r_addend); - - (*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, rel->r_offset); - } - } - - if (lit_table) - free (lit_table); - - input_section->reloc_done = TRUE; - - return TRUE; -} - - -/* Finish up dynamic symbol handling. There's not much to do here since - the PLT and GOT entries are all set up by relocate_section. */ - -static bfd_boolean -elf_xtensa_finish_dynamic_symbol (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h->needs_plt && !h->def_regular) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. */ - sym->st_shndx = SHN_UNDEF; - /* If the symbol is weak, we do need to clear the value. - Otherwise, the PLT entry would provide a definition for - the symbol even if the symbol wasn't defined anywhere, - and so the symbol would never be NULL. */ - if (!h->ref_regular_nonweak) - sym->st_value = 0; - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - - -/* Combine adjacent literal table entries in the output. Adjacent - entries within each input section may have been removed during - relaxation, but we repeat the process here, even though it's too late - to shrink the output section, because it's important to minimize the - number of literal table entries to reduce the start-up work for the - runtime linker. Returns the number of remaining table entries or -1 - on error. */ - -static int -elf_xtensa_combine_prop_entries (bfd *output_bfd, - asection *sxtlit, - asection *sgotloc) -{ - bfd_byte *contents; - property_table_entry *table; - bfd_size_type section_size, sgotloc_size; - bfd_vma offset; - int n, m, num; - - section_size = sxtlit->size; - BFD_ASSERT (section_size % 8 == 0); - num = section_size / 8; - - sgotloc_size = sgotloc->size; - if (sgotloc_size != section_size) - { - _bfd_error_handler - (_("internal inconsistency in size of .got.loc section")); - return -1; - } - - table = bfd_malloc (num * sizeof (property_table_entry)); - if (table == 0) - return -1; - - /* The ".xt.lit.plt" section has the SEC_IN_MEMORY flag set and this - propagates to the output section, where it doesn't really apply and - where it breaks the following call to bfd_malloc_and_get_section. */ - sxtlit->flags &= ~SEC_IN_MEMORY; - - if (!bfd_malloc_and_get_section (output_bfd, sxtlit, &contents)) - { - if (contents != 0) - free (contents); - free (table); - return -1; - } - - /* There should never be any relocations left at this point, so this - is quite a bit easier than what is done during relaxation. */ - - /* Copy the raw contents into a property table array and sort it. */ - offset = 0; - for (n = 0; n < num; n++) - { - table[n].address = bfd_get_32 (output_bfd, &contents[offset]); - table[n].size = bfd_get_32 (output_bfd, &contents[offset + 4]); - offset += 8; - } - qsort (table, num, sizeof (property_table_entry), property_table_compare); - - for (n = 0; n < num; n++) - { - bfd_boolean remove_entry = FALSE; - - if (table[n].size == 0) - remove_entry = TRUE; - else if (n > 0 - && (table[n-1].address + table[n-1].size == table[n].address)) - { - table[n-1].size += table[n].size; - remove_entry = TRUE; - } - - if (remove_entry) - { - for (m = n; m < num - 1; m++) - { - table[m].address = table[m+1].address; - table[m].size = table[m+1].size; - } - - n--; - num--; - } - } - - /* Copy the data back to the raw contents. */ - offset = 0; - for (n = 0; n < num; n++) - { - bfd_put_32 (output_bfd, table[n].address, &contents[offset]); - bfd_put_32 (output_bfd, table[n].size, &contents[offset + 4]); - offset += 8; - } - - /* Clear the removed bytes. */ - if ((bfd_size_type) (num * 8) < section_size) - memset (&contents[num * 8], 0, section_size - num * 8); - - if (! bfd_set_section_contents (output_bfd, sxtlit, contents, 0, - section_size)) - return -1; - - /* Copy the contents to ".got.loc". */ - memcpy (sgotloc->contents, contents, section_size); - - free (contents); - free (table); - return num; -} - - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf_xtensa_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_xtensa_link_hash_table *htab; - bfd *dynobj; - asection *sdyn, *srelplt, *sgot, *sxtlit, *sgotloc; - Elf32_External_Dyn *dyncon, *dynconend; - int num_xtlit_entries = 0; - - if (! elf_hash_table (info)->dynamic_sections_created) - return TRUE; - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = elf_hash_table (info)->dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - BFD_ASSERT (sdyn != NULL); - - /* Set the first entry in the global offset table to the address of - the dynamic section. */ - sgot = htab->elf.sgot; - if (sgot) - { - BFD_ASSERT (sgot->size == 4); - if (sdyn == NULL) - bfd_put_32 (output_bfd, 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - } - - srelplt = htab->elf.srelplt; - if (srelplt && srelplt->size != 0) - { - asection *sgotplt, *srelgot, *spltlittbl; - int chunk, plt_chunks, plt_entries; - Elf_Internal_Rela irela; - bfd_byte *loc; - unsigned rtld_reloc; - - srelgot = htab->elf.srelgot; - spltlittbl = htab->spltlittbl; - BFD_ASSERT (srelgot != NULL && spltlittbl != NULL); - - /* Find the first XTENSA_RTLD relocation. Presumably the rest - of them follow immediately after.... */ - for (rtld_reloc = 0; rtld_reloc < srelgot->reloc_count; rtld_reloc++) - { - loc = srelgot->contents + rtld_reloc * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_in (output_bfd, loc, &irela); - if (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD) - break; - } - BFD_ASSERT (rtld_reloc < srelgot->reloc_count); - - plt_entries = srelplt->size / sizeof (Elf32_External_Rela); - plt_chunks = - (plt_entries + PLT_ENTRIES_PER_CHUNK - 1) / PLT_ENTRIES_PER_CHUNK; - - for (chunk = 0; chunk < plt_chunks; chunk++) - { - int chunk_entries = 0; - - sgotplt = elf_xtensa_get_gotplt_section (info, chunk); - BFD_ASSERT (sgotplt != NULL); - - /* Emit special RTLD relocations for the first two entries in - each chunk of the .got.plt section. */ - - loc = srelgot->contents + rtld_reloc * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_in (output_bfd, loc, &irela); - BFD_ASSERT (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD); - irela.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset); - irela.r_addend = 1; /* tell rtld to set value to resolver function */ - bfd_elf32_swap_reloca_out (output_bfd, &irela, loc); - rtld_reloc += 1; - BFD_ASSERT (rtld_reloc <= srelgot->reloc_count); - - /* Next literal immediately follows the first. */ - loc += sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_in (output_bfd, loc, &irela); - BFD_ASSERT (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD); - irela.r_offset = (sgotplt->output_section->vma - + sgotplt->output_offset + 4); - /* Tell rtld to set value to object's link map. */ - irela.r_addend = 2; - bfd_elf32_swap_reloca_out (output_bfd, &irela, loc); - rtld_reloc += 1; - BFD_ASSERT (rtld_reloc <= srelgot->reloc_count); - - /* Fill in the literal table. */ - if (chunk < plt_chunks - 1) - chunk_entries = PLT_ENTRIES_PER_CHUNK; - else - chunk_entries = plt_entries - (chunk * PLT_ENTRIES_PER_CHUNK); - - BFD_ASSERT ((unsigned) (chunk + 1) * 8 <= spltlittbl->size); - bfd_put_32 (output_bfd, - sgotplt->output_section->vma + sgotplt->output_offset, - spltlittbl->contents + (chunk * 8) + 0); - bfd_put_32 (output_bfd, - 8 + (chunk_entries * 4), - spltlittbl->contents + (chunk * 8) + 4); - } - - /* All the dynamic relocations have been emitted at this point. - Make sure the relocation sections are the correct size. */ - if (srelgot->size != (sizeof (Elf32_External_Rela) - * srelgot->reloc_count) - || srelplt->size != (sizeof (Elf32_External_Rela) - * srelplt->reloc_count)) - abort (); - - /* The .xt.lit.plt section has just been modified. This must - happen before the code below which combines adjacent literal - table entries, and the .xt.lit.plt contents have to be forced to - the output here. */ - if (! bfd_set_section_contents (output_bfd, - spltlittbl->output_section, - spltlittbl->contents, - spltlittbl->output_offset, - spltlittbl->size)) - return FALSE; - /* Clear SEC_HAS_CONTENTS so the contents won't be output again. */ - spltlittbl->flags &= ~SEC_HAS_CONTENTS; - } - - /* Combine adjacent literal table entries. */ - BFD_ASSERT (! bfd_link_relocatable (info)); - sxtlit = bfd_get_section_by_name (output_bfd, ".xt.lit"); - sgotloc = htab->sgotloc; - BFD_ASSERT (sgotloc); - if (sxtlit) - { - num_xtlit_entries = - elf_xtensa_combine_prop_entries (output_bfd, sxtlit, sgotloc); - if (num_xtlit_entries < 0) - return FALSE; - } - - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_XTENSA_GOT_LOC_SZ: - dyn.d_un.d_val = num_xtlit_entries; - break; - - case DT_XTENSA_GOT_LOC_OFF: - dyn.d_un.d_ptr = (htab->sgotloc->output_section->vma - + htab->sgotloc->output_offset); - break; - - case DT_PLTGOT: - dyn.d_un.d_ptr = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset); - break; - - case DT_JMPREL: - dyn.d_un.d_ptr = (htab->elf.srelplt->output_section->vma - + htab->elf.srelplt->output_offset); - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = htab->elf.srelplt->size; - break; - } - - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - return TRUE; -} - - -/* Functions for dealing with the e_flags field. */ - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf_xtensa_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - unsigned out_mach, in_mach; - flagword out_flag, in_flag; - - /* Check if we have the same endianness. */ - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - /* Don't even pretend to support mixed-format linking. */ - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return FALSE; - - out_flag = elf_elfheader (obfd)->e_flags; - in_flag = elf_elfheader (ibfd)->e_flags; - - out_mach = out_flag & EF_XTENSA_MACH; - in_mach = in_flag & EF_XTENSA_MACH; - if (out_mach != in_mach) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: incompatible machine type. Output is 0x%x. Input is 0x%x"), - ibfd, out_mach, in_mach); - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - if (! elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flag; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd)); - - return TRUE; - } - - if ((out_flag & EF_XTENSA_XT_INSN) != (in_flag & EF_XTENSA_XT_INSN)) - elf_elfheader (obfd)->e_flags &= (~ EF_XTENSA_XT_INSN); - - if ((out_flag & EF_XTENSA_XT_LIT) != (in_flag & EF_XTENSA_XT_LIT)) - elf_elfheader (obfd)->e_flags &= (~ EF_XTENSA_XT_LIT); - - return TRUE; -} - - -static bfd_boolean -elf_xtensa_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags |= flags; - elf_flags_init (abfd) = TRUE; - - return TRUE; -} - - -static bfd_boolean -elf_xtensa_print_private_bfd_data (bfd *abfd, void *farg) -{ - FILE *f = (FILE *) farg; - flagword e_flags = elf_elfheader (abfd)->e_flags; - - fprintf (f, "\nXtensa header:\n"); - if ((e_flags & EF_XTENSA_MACH) == E_XTENSA_MACH) - fprintf (f, "\nMachine = Base\n"); - else - fprintf (f, "\nMachine Id = 0x%x\n", e_flags & EF_XTENSA_MACH); - - fprintf (f, "Insn tables = %s\n", - (e_flags & EF_XTENSA_XT_INSN) ? "true" : "false"); - - fprintf (f, "Literal tables = %s\n", - (e_flags & EF_XTENSA_XT_LIT) ? "true" : "false"); - - return _bfd_elf_print_private_bfd_data (abfd, farg); -} - - -/* Set the right machine number for an Xtensa ELF file. */ - -static bfd_boolean -elf_xtensa_object_p (bfd *abfd) -{ - int mach; - unsigned long arch = elf_elfheader (abfd)->e_flags & EF_XTENSA_MACH; - - switch (arch) - { - case E_XTENSA_MACH: - mach = bfd_mach_xtensa; - break; - default: - return FALSE; - } - - (void) bfd_default_set_arch_mach (abfd, bfd_arch_xtensa, mach); - return TRUE; -} - - -/* The final processing done just before writing out an Xtensa ELF object - file. This gets the Xtensa architecture right based on the machine - number. */ - -static void -elf_xtensa_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - int mach; - unsigned long val; - - switch (mach = bfd_get_mach (abfd)) - { - case bfd_mach_xtensa: - val = E_XTENSA_MACH; - break; - default: - return; - } - - elf_elfheader (abfd)->e_flags &= (~ EF_XTENSA_MACH); - elf_elfheader (abfd)->e_flags |= val; -} - - -static enum elf_reloc_type_class -elf_xtensa_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_XTENSA_RELATIVE: - return reloc_class_relative; - case R_XTENSA_JMP_SLOT: - return reloc_class_plt; - default: - return reloc_class_normal; - } -} - - -static bfd_boolean -elf_xtensa_discard_info_for_section (bfd *abfd, - struct elf_reloc_cookie *cookie, - struct bfd_link_info *info, - asection *sec) -{ - bfd_byte *contents; - bfd_vma offset, actual_offset; - bfd_size_type removed_bytes = 0; - bfd_size_type entry_size; - - if (sec->output_section - && bfd_is_abs_section (sec->output_section)) - return FALSE; - - if (xtensa_is_proptable_section (sec)) - entry_size = 12; - else - entry_size = 8; - - if (sec->size == 0 || sec->size % entry_size != 0) - return FALSE; - - contents = retrieve_contents (abfd, sec, info->keep_memory); - if (!contents) - return FALSE; - - cookie->rels = retrieve_internal_relocs (abfd, sec, info->keep_memory); - if (!cookie->rels) - { - release_contents (sec, contents); - return FALSE; - } - - /* Sort the relocations. They should already be in order when - relaxation is enabled, but it might not be. */ - qsort (cookie->rels, sec->reloc_count, sizeof (Elf_Internal_Rela), - internal_reloc_compare); - - cookie->rel = cookie->rels; - cookie->relend = cookie->rels + sec->reloc_count; - - for (offset = 0; offset < sec->size; offset += entry_size) - { - actual_offset = offset - removed_bytes; - - /* The ...symbol_deleted_p function will skip over relocs but it - won't adjust their offsets, so do that here. */ - while (cookie->rel < cookie->relend - && cookie->rel->r_offset < offset) - { - cookie->rel->r_offset -= removed_bytes; - cookie->rel++; - } - - while (cookie->rel < cookie->relend - && cookie->rel->r_offset == offset) - { - if (bfd_elf_reloc_symbol_deleted_p (offset, cookie)) - { - /* Remove the table entry. (If the reloc type is NONE, then - the entry has already been merged with another and deleted - during relaxation.) */ - if (ELF32_R_TYPE (cookie->rel->r_info) != R_XTENSA_NONE) - { - /* Shift the contents up. */ - if (offset + entry_size < sec->size) - memmove (&contents[actual_offset], - &contents[actual_offset + entry_size], - sec->size - offset - entry_size); - removed_bytes += entry_size; - } - - /* Remove this relocation. */ - cookie->rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - } - - /* Adjust the relocation offset for previous removals. This - should not be done before calling ...symbol_deleted_p - because it might mess up the offset comparisons there. - Make sure the offset doesn't underflow in the case where - the first entry is removed. */ - if (cookie->rel->r_offset >= removed_bytes) - cookie->rel->r_offset -= removed_bytes; - else - cookie->rel->r_offset = 0; - - cookie->rel++; - } - } - - if (removed_bytes != 0) - { - /* Adjust any remaining relocs (shouldn't be any). */ - for (; cookie->rel < cookie->relend; cookie->rel++) - { - if (cookie->rel->r_offset >= removed_bytes) - cookie->rel->r_offset -= removed_bytes; - else - cookie->rel->r_offset = 0; - } - - /* Clear the removed bytes. */ - memset (&contents[sec->size - removed_bytes], 0, removed_bytes); - - pin_contents (sec, contents); - pin_internal_relocs (sec, cookie->rels); - - /* Shrink size. */ - if (sec->rawsize == 0) - sec->rawsize = sec->size; - sec->size -= removed_bytes; - - if (xtensa_is_littable_section (sec)) - { - asection *sgotloc = elf_xtensa_hash_table (info)->sgotloc; - if (sgotloc) - sgotloc->size -= removed_bytes; - } - } - else - { - release_contents (sec, contents); - release_internal_relocs (sec, cookie->rels); - } - - return (removed_bytes != 0); -} - - -static bfd_boolean -elf_xtensa_discard_info (bfd *abfd, - struct elf_reloc_cookie *cookie, - struct bfd_link_info *info) -{ - asection *sec; - bfd_boolean changed = FALSE; - - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (xtensa_is_property_section (sec)) - { - if (elf_xtensa_discard_info_for_section (abfd, cookie, info, sec)) - changed = TRUE; - } - } - - return changed; -} - - -static bfd_boolean -elf_xtensa_ignore_discarded_relocs (asection *sec) -{ - return xtensa_is_property_section (sec); -} - - -static unsigned int -elf_xtensa_action_discarded (asection *sec) -{ - if (strcmp (".xt_except_table", sec->name) == 0) - return 0; - - if (strcmp (".xt_except_desc", sec->name) == 0) - return 0; - - return _bfd_elf_default_action_discarded (sec); -} - - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf_xtensa_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - /* The size for Xtensa is variable, so don't try to recognize the format - based on the size. Just assume this is GNU/Linux. */ - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = note->descsz - offset - 4; - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - - -static bfd_boolean -elf_xtensa_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 128: /* GNU/Linux elf_prpsinfo */ - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 48, 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; -} - - -/* Generic Xtensa configurability stuff. */ - -static xtensa_opcode callx0_op = XTENSA_UNDEFINED; -static xtensa_opcode callx4_op = XTENSA_UNDEFINED; -static xtensa_opcode callx8_op = XTENSA_UNDEFINED; -static xtensa_opcode callx12_op = XTENSA_UNDEFINED; -static xtensa_opcode call0_op = XTENSA_UNDEFINED; -static xtensa_opcode call4_op = XTENSA_UNDEFINED; -static xtensa_opcode call8_op = XTENSA_UNDEFINED; -static xtensa_opcode call12_op = XTENSA_UNDEFINED; - -static void -init_call_opcodes (void) -{ - if (callx0_op == XTENSA_UNDEFINED) - { - callx0_op = xtensa_opcode_lookup (xtensa_default_isa, "callx0"); - callx4_op = xtensa_opcode_lookup (xtensa_default_isa, "callx4"); - callx8_op = xtensa_opcode_lookup (xtensa_default_isa, "callx8"); - callx12_op = xtensa_opcode_lookup (xtensa_default_isa, "callx12"); - call0_op = xtensa_opcode_lookup (xtensa_default_isa, "call0"); - call4_op = xtensa_opcode_lookup (xtensa_default_isa, "call4"); - call8_op = xtensa_opcode_lookup (xtensa_default_isa, "call8"); - call12_op = xtensa_opcode_lookup (xtensa_default_isa, "call12"); - } -} - - -static bfd_boolean -is_indirect_call_opcode (xtensa_opcode opcode) -{ - init_call_opcodes (); - return (opcode == callx0_op - || opcode == callx4_op - || opcode == callx8_op - || opcode == callx12_op); -} - - -static bfd_boolean -is_direct_call_opcode (xtensa_opcode opcode) -{ - init_call_opcodes (); - return (opcode == call0_op - || opcode == call4_op - || opcode == call8_op - || opcode == call12_op); -} - - -static bfd_boolean -is_windowed_call_opcode (xtensa_opcode opcode) -{ - init_call_opcodes (); - return (opcode == call4_op - || opcode == call8_op - || opcode == call12_op - || opcode == callx4_op - || opcode == callx8_op - || opcode == callx12_op); -} - - -static bfd_boolean -get_indirect_call_dest_reg (xtensa_opcode opcode, unsigned *pdst) -{ - unsigned dst = (unsigned) -1; - - init_call_opcodes (); - if (opcode == callx0_op) - dst = 0; - else if (opcode == callx4_op) - dst = 4; - else if (opcode == callx8_op) - dst = 8; - else if (opcode == callx12_op) - dst = 12; - - if (dst == (unsigned) -1) - return FALSE; - - *pdst = dst; - return TRUE; -} - - -static xtensa_opcode -get_const16_opcode (void) -{ - static bfd_boolean done_lookup = FALSE; - static xtensa_opcode const16_opcode = XTENSA_UNDEFINED; - if (!done_lookup) - { - const16_opcode = xtensa_opcode_lookup (xtensa_default_isa, "const16"); - done_lookup = TRUE; - } - return const16_opcode; -} - - -static xtensa_opcode -get_l32r_opcode (void) -{ - static xtensa_opcode l32r_opcode = XTENSA_UNDEFINED; - static bfd_boolean done_lookup = FALSE; - - if (!done_lookup) - { - l32r_opcode = xtensa_opcode_lookup (xtensa_default_isa, "l32r"); - done_lookup = TRUE; - } - return l32r_opcode; -} - - -static bfd_vma -l32r_offset (bfd_vma addr, bfd_vma pc) -{ - bfd_vma offset; - - offset = addr - ((pc+3) & -4); - BFD_ASSERT ((offset & ((1 << 2) - 1)) == 0); - offset = (signed int) offset >> 2; - BFD_ASSERT ((signed int) offset >> 16 == -1); - return offset; -} - - -static int -get_relocation_opnd (xtensa_opcode opcode, int r_type) -{ - xtensa_isa isa = xtensa_default_isa; - int last_immed, last_opnd, opi; - - if (opcode == XTENSA_UNDEFINED) - return XTENSA_UNDEFINED; - - /* Find the last visible PC-relative immediate operand for the opcode. - If there are no PC-relative immediates, then choose the last visible - immediate; otherwise, fail and return XTENSA_UNDEFINED. */ - last_immed = XTENSA_UNDEFINED; - last_opnd = xtensa_opcode_num_operands (isa, opcode); - for (opi = last_opnd - 1; opi >= 0; opi--) - { - if (xtensa_operand_is_visible (isa, opcode, opi) == 0) - continue; - if (xtensa_operand_is_PCrelative (isa, opcode, opi) == 1) - { - last_immed = opi; - break; - } - if (last_immed == XTENSA_UNDEFINED - && xtensa_operand_is_register (isa, opcode, opi) == 0) - last_immed = opi; - } - if (last_immed < 0) - return XTENSA_UNDEFINED; - - /* If the operand number was specified in an old-style relocation, - check for consistency with the operand computed above. */ - if (r_type >= R_XTENSA_OP0 && r_type <= R_XTENSA_OP2) - { - int reloc_opnd = r_type - R_XTENSA_OP0; - if (reloc_opnd != last_immed) - return XTENSA_UNDEFINED; - } - - return last_immed; -} - - -int -get_relocation_slot (int r_type) -{ - switch (r_type) - { - case R_XTENSA_OP0: - case R_XTENSA_OP1: - case R_XTENSA_OP2: - return 0; - - default: - if (r_type >= R_XTENSA_SLOT0_OP && r_type <= R_XTENSA_SLOT14_OP) - return r_type - R_XTENSA_SLOT0_OP; - if (r_type >= R_XTENSA_SLOT0_ALT && r_type <= R_XTENSA_SLOT14_ALT) - return r_type - R_XTENSA_SLOT0_ALT; - break; - } - - return XTENSA_UNDEFINED; -} - - -/* Get the opcode for a relocation. */ - -static xtensa_opcode -get_relocation_opcode (bfd *abfd, - asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *irel) -{ - static xtensa_insnbuf ibuff = NULL; - static xtensa_insnbuf sbuff = NULL; - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - int slot; - - if (contents == NULL) - return XTENSA_UNDEFINED; - - if (bfd_get_section_limit (abfd, sec) <= irel->r_offset) - return XTENSA_UNDEFINED; - - if (ibuff == NULL) - { - ibuff = xtensa_insnbuf_alloc (isa); - sbuff = xtensa_insnbuf_alloc (isa); - } - - /* Decode the instruction. */ - xtensa_insnbuf_from_chars (isa, ibuff, &contents[irel->r_offset], - sec->size - irel->r_offset); - fmt = xtensa_format_decode (isa, ibuff); - slot = get_relocation_slot (ELF32_R_TYPE (irel->r_info)); - if (slot == XTENSA_UNDEFINED) - return XTENSA_UNDEFINED; - xtensa_format_get_slot (isa, fmt, slot, ibuff, sbuff); - return xtensa_opcode_decode (isa, fmt, slot, sbuff); -} - - -bfd_boolean -is_l32r_relocation (bfd *abfd, - asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *irel) -{ - xtensa_opcode opcode; - if (!is_operand_relocation (ELF32_R_TYPE (irel->r_info))) - return FALSE; - opcode = get_relocation_opcode (abfd, sec, contents, irel); - return (opcode == get_l32r_opcode ()); -} - - -static bfd_size_type -get_asm_simplify_size (bfd_byte *contents, - bfd_size_type content_len, - bfd_size_type offset) -{ - bfd_size_type insnlen, size = 0; - - /* Decode the size of the next two instructions. */ - insnlen = insn_decode_len (contents, content_len, offset); - if (insnlen == 0) - return 0; - - size += insnlen; - - insnlen = insn_decode_len (contents, content_len, offset + size); - if (insnlen == 0) - return 0; - - size += insnlen; - return size; -} - - -bfd_boolean -is_alt_relocation (int r_type) -{ - return (r_type >= R_XTENSA_SLOT0_ALT - && r_type <= R_XTENSA_SLOT14_ALT); -} - - -bfd_boolean -is_operand_relocation (int r_type) -{ - switch (r_type) - { - case R_XTENSA_OP0: - case R_XTENSA_OP1: - case R_XTENSA_OP2: - return TRUE; - - default: - if (r_type >= R_XTENSA_SLOT0_OP && r_type <= R_XTENSA_SLOT14_OP) - return TRUE; - if (r_type >= R_XTENSA_SLOT0_ALT && r_type <= R_XTENSA_SLOT14_ALT) - return TRUE; - break; - } - - return FALSE; -} - - -#define MIN_INSN_LENGTH 2 - -/* Return 0 if it fails to decode. */ - -bfd_size_type -insn_decode_len (bfd_byte *contents, - bfd_size_type content_len, - bfd_size_type offset) -{ - int insn_len; - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - static xtensa_insnbuf ibuff = NULL; - - if (offset + MIN_INSN_LENGTH > content_len) - return 0; - - if (ibuff == NULL) - ibuff = xtensa_insnbuf_alloc (isa); - xtensa_insnbuf_from_chars (isa, ibuff, &contents[offset], - content_len - offset); - fmt = xtensa_format_decode (isa, ibuff); - if (fmt == XTENSA_UNDEFINED) - return 0; - insn_len = xtensa_format_length (isa, fmt); - if (insn_len == XTENSA_UNDEFINED) - return 0; - return insn_len; -} - - -/* Decode the opcode for a single slot instruction. - Return 0 if it fails to decode or the instruction is multi-slot. */ - -xtensa_opcode -insn_decode_opcode (bfd_byte *contents, - bfd_size_type content_len, - bfd_size_type offset, - int slot) -{ - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - static xtensa_insnbuf insnbuf = NULL; - static xtensa_insnbuf slotbuf = NULL; - - if (offset + MIN_INSN_LENGTH > content_len) - return XTENSA_UNDEFINED; - - if (insnbuf == NULL) - { - insnbuf = xtensa_insnbuf_alloc (isa); - slotbuf = xtensa_insnbuf_alloc (isa); - } - - xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset], - content_len - offset); - fmt = xtensa_format_decode (isa, insnbuf); - if (fmt == XTENSA_UNDEFINED) - return XTENSA_UNDEFINED; - - if (slot >= xtensa_format_num_slots (isa, fmt)) - return XTENSA_UNDEFINED; - - xtensa_format_get_slot (isa, fmt, slot, insnbuf, slotbuf); - return xtensa_opcode_decode (isa, fmt, slot, slotbuf); -} - - -/* The offset is the offset in the contents. - The address is the address of that offset. */ - -static bfd_boolean -check_branch_target_aligned (bfd_byte *contents, - bfd_size_type content_length, - bfd_vma offset, - bfd_vma address) -{ - bfd_size_type insn_len = insn_decode_len (contents, content_length, offset); - if (insn_len == 0) - return FALSE; - return check_branch_target_aligned_address (address, insn_len); -} - - -static bfd_boolean -check_loop_aligned (bfd_byte *contents, - bfd_size_type content_length, - bfd_vma offset, - bfd_vma address) -{ - bfd_size_type loop_len, insn_len; - xtensa_opcode opcode; - - opcode = insn_decode_opcode (contents, content_length, offset, 0); - if (opcode == XTENSA_UNDEFINED - || xtensa_opcode_is_loop (xtensa_default_isa, opcode) != 1) - { - BFD_ASSERT (FALSE); - return FALSE; - } - - loop_len = insn_decode_len (contents, content_length, offset); - insn_len = insn_decode_len (contents, content_length, offset + loop_len); - if (loop_len == 0 || insn_len == 0) - { - BFD_ASSERT (FALSE); - return FALSE; - } - - return check_branch_target_aligned_address (address + loop_len, insn_len); -} - - -static bfd_boolean -check_branch_target_aligned_address (bfd_vma addr, int len) -{ - if (len == 8) - return (addr % 8 == 0); - return ((addr >> 2) == ((addr + len - 1) >> 2)); -} - - -/* Instruction widening and narrowing. */ - -/* When FLIX is available we need to access certain instructions only - when they are 16-bit or 24-bit instructions. This table caches - information about such instructions by walking through all the - opcodes and finding the smallest single-slot format into which each - can be encoded. */ - -static xtensa_format *op_single_fmt_table = NULL; - - -static void -init_op_single_format_table (void) -{ - xtensa_isa isa = xtensa_default_isa; - xtensa_insnbuf ibuf; - xtensa_opcode opcode; - xtensa_format fmt; - int num_opcodes; - - if (op_single_fmt_table) - return; - - ibuf = xtensa_insnbuf_alloc (isa); - num_opcodes = xtensa_isa_num_opcodes (isa); - - op_single_fmt_table = (xtensa_format *) - bfd_malloc (sizeof (xtensa_format) * num_opcodes); - for (opcode = 0; opcode < num_opcodes; opcode++) - { - op_single_fmt_table[opcode] = XTENSA_UNDEFINED; - for (fmt = 0; fmt < xtensa_isa_num_formats (isa); fmt++) - { - if (xtensa_format_num_slots (isa, fmt) == 1 - && xtensa_opcode_encode (isa, fmt, 0, ibuf, opcode) == 0) - { - xtensa_opcode old_fmt = op_single_fmt_table[opcode]; - int fmt_length = xtensa_format_length (isa, fmt); - if (old_fmt == XTENSA_UNDEFINED - || fmt_length < xtensa_format_length (isa, old_fmt)) - op_single_fmt_table[opcode] = fmt; - } - } - } - xtensa_insnbuf_free (isa, ibuf); -} - - -static xtensa_format -get_single_format (xtensa_opcode opcode) -{ - init_op_single_format_table (); - return op_single_fmt_table[opcode]; -} - - -/* For the set of narrowable instructions we do NOT include the - narrowings beqz -> beqz.n or bnez -> bnez.n because of complexities - involved during linker relaxation that may require these to - re-expand in some conditions. Also, the narrowing "or" -> mov.n - requires special case code to ensure it only works when op1 == op2. */ - -struct string_pair -{ - const char *wide; - const char *narrow; -}; - -struct string_pair narrowable[] = -{ - { "add", "add.n" }, - { "addi", "addi.n" }, - { "addmi", "addi.n" }, - { "l32i", "l32i.n" }, - { "movi", "movi.n" }, - { "ret", "ret.n" }, - { "retw", "retw.n" }, - { "s32i", "s32i.n" }, - { "or", "mov.n" } /* special case only when op1 == op2 */ -}; - -struct string_pair widenable[] = -{ - { "add", "add.n" }, - { "addi", "addi.n" }, - { "addmi", "addi.n" }, - { "beqz", "beqz.n" }, - { "bnez", "bnez.n" }, - { "l32i", "l32i.n" }, - { "movi", "movi.n" }, - { "ret", "ret.n" }, - { "retw", "retw.n" }, - { "s32i", "s32i.n" }, - { "or", "mov.n" } /* special case only when op1 == op2 */ -}; - - -/* Check if an instruction can be "narrowed", i.e., changed from a standard - 3-byte instruction to a 2-byte "density" instruction. If it is valid, - return the instruction buffer holding the narrow instruction. Otherwise, - return 0. The set of valid narrowing are specified by a string table - but require some special case operand checks in some cases. */ - -static xtensa_insnbuf -can_narrow_instruction (xtensa_insnbuf slotbuf, - xtensa_format fmt, - xtensa_opcode opcode) -{ - xtensa_isa isa = xtensa_default_isa; - xtensa_format o_fmt; - unsigned opi; - - static xtensa_insnbuf o_insnbuf = NULL; - static xtensa_insnbuf o_slotbuf = NULL; - - if (o_insnbuf == NULL) - { - o_insnbuf = xtensa_insnbuf_alloc (isa); - o_slotbuf = xtensa_insnbuf_alloc (isa); - } - - for (opi = 0; opi < (sizeof (narrowable)/sizeof (struct string_pair)); opi++) - { - bfd_boolean is_or = (strcmp ("or", narrowable[opi].wide) == 0); - - if (opcode == xtensa_opcode_lookup (isa, narrowable[opi].wide)) - { - uint32 value, newval; - int i, operand_count, o_operand_count; - xtensa_opcode o_opcode; - - /* Address does not matter in this case. We might need to - fix it to handle branches/jumps. */ - bfd_vma self_address = 0; - - o_opcode = xtensa_opcode_lookup (isa, narrowable[opi].narrow); - if (o_opcode == XTENSA_UNDEFINED) - return 0; - o_fmt = get_single_format (o_opcode); - if (o_fmt == XTENSA_UNDEFINED) - return 0; - - if (xtensa_format_length (isa, fmt) != 3 - || xtensa_format_length (isa, o_fmt) != 2) - return 0; - - xtensa_format_encode (isa, o_fmt, o_insnbuf); - operand_count = xtensa_opcode_num_operands (isa, opcode); - o_operand_count = xtensa_opcode_num_operands (isa, o_opcode); - - if (xtensa_opcode_encode (isa, o_fmt, 0, o_slotbuf, o_opcode) != 0) - return 0; - - if (!is_or) - { - if (xtensa_opcode_num_operands (isa, o_opcode) != operand_count) - return 0; - } - else - { - uint32 rawval0, rawval1, rawval2; - - if (o_operand_count + 1 != operand_count - || xtensa_operand_get_field (isa, opcode, 0, - fmt, 0, slotbuf, &rawval0) != 0 - || xtensa_operand_get_field (isa, opcode, 1, - fmt, 0, slotbuf, &rawval1) != 0 - || xtensa_operand_get_field (isa, opcode, 2, - fmt, 0, slotbuf, &rawval2) != 0 - || rawval1 != rawval2 - || rawval0 == rawval1 /* it is a nop */) - return 0; - } - - for (i = 0; i < o_operand_count; ++i) - { - if (xtensa_operand_get_field (isa, opcode, i, fmt, 0, - slotbuf, &value) - || xtensa_operand_decode (isa, opcode, i, &value)) - return 0; - - /* PC-relative branches need adjustment, but - the PC-rel operand will always have a relocation. */ - newval = value; - if (xtensa_operand_do_reloc (isa, o_opcode, i, &newval, - self_address) - || xtensa_operand_encode (isa, o_opcode, i, &newval) - || xtensa_operand_set_field (isa, o_opcode, i, o_fmt, 0, - o_slotbuf, newval)) - return 0; - } - - if (xtensa_format_set_slot (isa, o_fmt, 0, o_insnbuf, o_slotbuf)) - return 0; - - return o_insnbuf; - } - } - return 0; -} - - -/* Attempt to narrow an instruction. If the narrowing is valid, perform - the action in-place directly into the contents and return TRUE. Otherwise, - the return value is FALSE and the contents are not modified. */ - -static bfd_boolean -narrow_instruction (bfd_byte *contents, - bfd_size_type content_length, - bfd_size_type offset) -{ - xtensa_opcode opcode; - bfd_size_type insn_len; - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - xtensa_insnbuf o_insnbuf; - - static xtensa_insnbuf insnbuf = NULL; - static xtensa_insnbuf slotbuf = NULL; - - if (insnbuf == NULL) - { - insnbuf = xtensa_insnbuf_alloc (isa); - slotbuf = xtensa_insnbuf_alloc (isa); - } - - BFD_ASSERT (offset < content_length); - - if (content_length < 2) - return FALSE; - - /* We will hand-code a few of these for a little while. - These have all been specified in the assembler aleady. */ - xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset], - content_length - offset); - fmt = xtensa_format_decode (isa, insnbuf); - if (xtensa_format_num_slots (isa, fmt) != 1) - return FALSE; - - if (xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf) != 0) - return FALSE; - - opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode == XTENSA_UNDEFINED) - return FALSE; - insn_len = xtensa_format_length (isa, fmt); - if (insn_len > content_length) - return FALSE; - - o_insnbuf = can_narrow_instruction (slotbuf, fmt, opcode); - if (o_insnbuf) - { - xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset, - content_length - offset); - return TRUE; - } - - return FALSE; -} - - -/* Check if an instruction can be "widened", i.e., changed from a 2-byte - "density" instruction to a standard 3-byte instruction. If it is valid, - return the instruction buffer holding the wide instruction. Otherwise, - return 0. The set of valid widenings are specified by a string table - but require some special case operand checks in some cases. */ - -static xtensa_insnbuf -can_widen_instruction (xtensa_insnbuf slotbuf, - xtensa_format fmt, - xtensa_opcode opcode) -{ - xtensa_isa isa = xtensa_default_isa; - xtensa_format o_fmt; - unsigned opi; - - static xtensa_insnbuf o_insnbuf = NULL; - static xtensa_insnbuf o_slotbuf = NULL; - - if (o_insnbuf == NULL) - { - o_insnbuf = xtensa_insnbuf_alloc (isa); - o_slotbuf = xtensa_insnbuf_alloc (isa); - } - - for (opi = 0; opi < (sizeof (widenable)/sizeof (struct string_pair)); opi++) - { - bfd_boolean is_or = (strcmp ("or", widenable[opi].wide) == 0); - bfd_boolean is_branch = (strcmp ("beqz", widenable[opi].wide) == 0 - || strcmp ("bnez", widenable[opi].wide) == 0); - - if (opcode == xtensa_opcode_lookup (isa, widenable[opi].narrow)) - { - uint32 value, newval; - int i, operand_count, o_operand_count, check_operand_count; - xtensa_opcode o_opcode; - - /* Address does not matter in this case. We might need to fix it - to handle branches/jumps. */ - bfd_vma self_address = 0; - - o_opcode = xtensa_opcode_lookup (isa, widenable[opi].wide); - if (o_opcode == XTENSA_UNDEFINED) - return 0; - o_fmt = get_single_format (o_opcode); - if (o_fmt == XTENSA_UNDEFINED) - return 0; - - if (xtensa_format_length (isa, fmt) != 2 - || xtensa_format_length (isa, o_fmt) != 3) - return 0; - - xtensa_format_encode (isa, o_fmt, o_insnbuf); - operand_count = xtensa_opcode_num_operands (isa, opcode); - o_operand_count = xtensa_opcode_num_operands (isa, o_opcode); - check_operand_count = o_operand_count; - - if (xtensa_opcode_encode (isa, o_fmt, 0, o_slotbuf, o_opcode) != 0) - return 0; - - if (!is_or) - { - if (xtensa_opcode_num_operands (isa, o_opcode) != operand_count) - return 0; - } - else - { - uint32 rawval0, rawval1; - - if (o_operand_count != operand_count + 1 - || xtensa_operand_get_field (isa, opcode, 0, - fmt, 0, slotbuf, &rawval0) != 0 - || xtensa_operand_get_field (isa, opcode, 1, - fmt, 0, slotbuf, &rawval1) != 0 - || rawval0 == rawval1 /* it is a nop */) - return 0; - } - if (is_branch) - check_operand_count--; - - for (i = 0; i < check_operand_count; i++) - { - int new_i = i; - if (is_or && i == o_operand_count - 1) - new_i = i - 1; - if (xtensa_operand_get_field (isa, opcode, new_i, fmt, 0, - slotbuf, &value) - || xtensa_operand_decode (isa, opcode, new_i, &value)) - return 0; - - /* PC-relative branches need adjustment, but - the PC-rel operand will always have a relocation. */ - newval = value; - if (xtensa_operand_do_reloc (isa, o_opcode, i, &newval, - self_address) - || xtensa_operand_encode (isa, o_opcode, i, &newval) - || xtensa_operand_set_field (isa, o_opcode, i, o_fmt, 0, - o_slotbuf, newval)) - return 0; - } - - if (xtensa_format_set_slot (isa, o_fmt, 0, o_insnbuf, o_slotbuf)) - return 0; - - return o_insnbuf; - } - } - return 0; -} - - -/* Attempt to widen an instruction. If the widening is valid, perform - the action in-place directly into the contents and return TRUE. Otherwise, - the return value is FALSE and the contents are not modified. */ - -static bfd_boolean -widen_instruction (bfd_byte *contents, - bfd_size_type content_length, - bfd_size_type offset) -{ - xtensa_opcode opcode; - bfd_size_type insn_len; - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - xtensa_insnbuf o_insnbuf; - - static xtensa_insnbuf insnbuf = NULL; - static xtensa_insnbuf slotbuf = NULL; - - if (insnbuf == NULL) - { - insnbuf = xtensa_insnbuf_alloc (isa); - slotbuf = xtensa_insnbuf_alloc (isa); - } - - BFD_ASSERT (offset < content_length); - - if (content_length < 2) - return FALSE; - - /* We will hand-code a few of these for a little while. - These have all been specified in the assembler aleady. */ - xtensa_insnbuf_from_chars (isa, insnbuf, &contents[offset], - content_length - offset); - fmt = xtensa_format_decode (isa, insnbuf); - if (xtensa_format_num_slots (isa, fmt) != 1) - return FALSE; - - if (xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf) != 0) - return FALSE; - - opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode == XTENSA_UNDEFINED) - return FALSE; - insn_len = xtensa_format_length (isa, fmt); - if (insn_len > content_length) - return FALSE; - - o_insnbuf = can_widen_instruction (slotbuf, fmt, opcode); - if (o_insnbuf) - { - xtensa_insnbuf_to_chars (isa, o_insnbuf, contents + offset, - content_length - offset); - return TRUE; - } - return FALSE; -} - - -/* Code for transforming CALLs at link-time. */ - -static bfd_reloc_status_type -elf_xtensa_do_asm_simplify (bfd_byte *contents, - bfd_vma address, - bfd_vma content_length, - char **error_message) -{ - static xtensa_insnbuf insnbuf = NULL; - static xtensa_insnbuf slotbuf = NULL; - xtensa_format core_format = XTENSA_UNDEFINED; - xtensa_opcode opcode; - xtensa_opcode direct_call_opcode; - xtensa_isa isa = xtensa_default_isa; - bfd_byte *chbuf = contents + address; - int opn; - - if (insnbuf == NULL) - { - insnbuf = xtensa_insnbuf_alloc (isa); - slotbuf = xtensa_insnbuf_alloc (isa); - } - - if (content_length < address) - { - *error_message = _("Attempt to convert L32R/CALLX to CALL failed"); - return bfd_reloc_other; - } - - opcode = get_expanded_call_opcode (chbuf, content_length - address, 0); - direct_call_opcode = swap_callx_for_call_opcode (opcode); - if (direct_call_opcode == XTENSA_UNDEFINED) - { - *error_message = _("Attempt to convert L32R/CALLX to CALL failed"); - return bfd_reloc_other; - } - - /* Assemble a NOP ("or a1, a1, a1") into the 0 byte offset. */ - core_format = xtensa_format_lookup (isa, "x24"); - opcode = xtensa_opcode_lookup (isa, "or"); - xtensa_opcode_encode (isa, core_format, 0, slotbuf, opcode); - for (opn = 0; opn < 3; opn++) - { - uint32 regno = 1; - xtensa_operand_encode (isa, opcode, opn, ®no); - xtensa_operand_set_field (isa, opcode, opn, core_format, 0, - slotbuf, regno); - } - xtensa_format_encode (isa, core_format, insnbuf); - xtensa_format_set_slot (isa, core_format, 0, insnbuf, slotbuf); - xtensa_insnbuf_to_chars (isa, insnbuf, chbuf, content_length - address); - - /* Assemble a CALL ("callN 0") into the 3 byte offset. */ - xtensa_opcode_encode (isa, core_format, 0, slotbuf, direct_call_opcode); - xtensa_operand_set_field (isa, opcode, 0, core_format, 0, slotbuf, 0); - - xtensa_format_encode (isa, core_format, insnbuf); - xtensa_format_set_slot (isa, core_format, 0, insnbuf, slotbuf); - xtensa_insnbuf_to_chars (isa, insnbuf, chbuf + 3, - content_length - address - 3); - - return bfd_reloc_ok; -} - - -static bfd_reloc_status_type -contract_asm_expansion (bfd_byte *contents, - bfd_vma content_length, - Elf_Internal_Rela *irel, - char **error_message) -{ - bfd_reloc_status_type retval = - elf_xtensa_do_asm_simplify (contents, irel->r_offset, content_length, - error_message); - - if (retval != bfd_reloc_ok) - return bfd_reloc_dangerous; - - /* Update the irel->r_offset field so that the right immediate and - the right instruction are modified during the relocation. */ - irel->r_offset += 3; - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_XTENSA_SLOT0_OP); - return bfd_reloc_ok; -} - - -static xtensa_opcode -swap_callx_for_call_opcode (xtensa_opcode opcode) -{ - init_call_opcodes (); - - if (opcode == callx0_op) return call0_op; - if (opcode == callx4_op) return call4_op; - if (opcode == callx8_op) return call8_op; - if (opcode == callx12_op) return call12_op; - - /* Return XTENSA_UNDEFINED if the opcode is not an indirect call. */ - return XTENSA_UNDEFINED; -} - - -/* Check if "buf" is pointing to a "L32R aN; CALLX aN" or "CONST16 aN; - CONST16 aN; CALLX aN" sequence, and if so, return the CALLX opcode. - If not, return XTENSA_UNDEFINED. */ - -#define L32R_TARGET_REG_OPERAND 0 -#define CONST16_TARGET_REG_OPERAND 0 -#define CALLN_SOURCE_OPERAND 0 - -static xtensa_opcode -get_expanded_call_opcode (bfd_byte *buf, int bufsize, bfd_boolean *p_uses_l32r) -{ - static xtensa_insnbuf insnbuf = NULL; - static xtensa_insnbuf slotbuf = NULL; - xtensa_format fmt; - xtensa_opcode opcode; - xtensa_isa isa = xtensa_default_isa; - uint32 regno, const16_regno, call_regno; - int offset = 0; - - if (insnbuf == NULL) - { - insnbuf = xtensa_insnbuf_alloc (isa); - slotbuf = xtensa_insnbuf_alloc (isa); - } - - xtensa_insnbuf_from_chars (isa, insnbuf, buf, bufsize); - fmt = xtensa_format_decode (isa, insnbuf); - if (fmt == XTENSA_UNDEFINED - || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) - return XTENSA_UNDEFINED; - - opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode == XTENSA_UNDEFINED) - return XTENSA_UNDEFINED; - - if (opcode == get_l32r_opcode ()) - { - if (p_uses_l32r) - *p_uses_l32r = TRUE; - if (xtensa_operand_get_field (isa, opcode, L32R_TARGET_REG_OPERAND, - fmt, 0, slotbuf, ®no) - || xtensa_operand_decode (isa, opcode, L32R_TARGET_REG_OPERAND, - ®no)) - return XTENSA_UNDEFINED; - } - else if (opcode == get_const16_opcode ()) - { - if (p_uses_l32r) - *p_uses_l32r = FALSE; - if (xtensa_operand_get_field (isa, opcode, CONST16_TARGET_REG_OPERAND, - fmt, 0, slotbuf, ®no) - || xtensa_operand_decode (isa, opcode, CONST16_TARGET_REG_OPERAND, - ®no)) - return XTENSA_UNDEFINED; - - /* Check that the next instruction is also CONST16. */ - offset += xtensa_format_length (isa, fmt); - xtensa_insnbuf_from_chars (isa, insnbuf, buf + offset, bufsize - offset); - fmt = xtensa_format_decode (isa, insnbuf); - if (fmt == XTENSA_UNDEFINED - || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) - return XTENSA_UNDEFINED; - opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode != get_const16_opcode ()) - return XTENSA_UNDEFINED; - - if (xtensa_operand_get_field (isa, opcode, CONST16_TARGET_REG_OPERAND, - fmt, 0, slotbuf, &const16_regno) - || xtensa_operand_decode (isa, opcode, CONST16_TARGET_REG_OPERAND, - &const16_regno) - || const16_regno != regno) - return XTENSA_UNDEFINED; - } - else - return XTENSA_UNDEFINED; - - /* Next instruction should be an CALLXn with operand 0 == regno. */ - offset += xtensa_format_length (isa, fmt); - xtensa_insnbuf_from_chars (isa, insnbuf, buf + offset, bufsize - offset); - fmt = xtensa_format_decode (isa, insnbuf); - if (fmt == XTENSA_UNDEFINED - || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) - return XTENSA_UNDEFINED; - opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode == XTENSA_UNDEFINED - || !is_indirect_call_opcode (opcode)) - return XTENSA_UNDEFINED; - - if (xtensa_operand_get_field (isa, opcode, CALLN_SOURCE_OPERAND, - fmt, 0, slotbuf, &call_regno) - || xtensa_operand_decode (isa, opcode, CALLN_SOURCE_OPERAND, - &call_regno)) - return XTENSA_UNDEFINED; - - if (call_regno != regno) - return XTENSA_UNDEFINED; - - return opcode; -} - - -/* Data structures used during relaxation. */ - -/* r_reloc: relocation values. */ - -/* Through the relaxation process, we need to keep track of the values - that will result from evaluating relocations. The standard ELF - relocation structure is not sufficient for this purpose because we're - operating on multiple input files at once, so we need to know which - input file a relocation refers to. The r_reloc structure thus - records both the input file (bfd) and ELF relocation. - - For efficiency, an r_reloc also contains a "target_offset" field to - cache the target-section-relative offset value that is represented by - the relocation. - - The r_reloc also contains a virtual offset that allows multiple - inserted literals to be placed at the same "address" with - different offsets. */ - -typedef struct r_reloc_struct r_reloc; - -struct r_reloc_struct -{ - bfd *abfd; - Elf_Internal_Rela rela; - bfd_vma target_offset; - bfd_vma virtual_offset; -}; - - -/* The r_reloc structure is included by value in literal_value, but not - every literal_value has an associated relocation -- some are simple - constants. In such cases, we set all the fields in the r_reloc - struct to zero. The r_reloc_is_const function should be used to - detect this case. */ - -static bfd_boolean -r_reloc_is_const (const r_reloc *r_rel) -{ - return (r_rel->abfd == NULL); -} - - -static bfd_vma -r_reloc_get_target_offset (const r_reloc *r_rel) -{ - bfd_vma target_offset; - unsigned long r_symndx; - - BFD_ASSERT (!r_reloc_is_const (r_rel)); - r_symndx = ELF32_R_SYM (r_rel->rela.r_info); - target_offset = get_elf_r_symndx_offset (r_rel->abfd, r_symndx); - return (target_offset + r_rel->rela.r_addend); -} - - -static struct elf_link_hash_entry * -r_reloc_get_hash_entry (const r_reloc *r_rel) -{ - unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); - return get_elf_r_symndx_hash_entry (r_rel->abfd, r_symndx); -} - - -static asection * -r_reloc_get_section (const r_reloc *r_rel) -{ - unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); - return get_elf_r_symndx_section (r_rel->abfd, r_symndx); -} - - -static bfd_boolean -r_reloc_is_defined (const r_reloc *r_rel) -{ - asection *sec; - if (r_rel == NULL) - return FALSE; - - sec = r_reloc_get_section (r_rel); - if (sec == bfd_abs_section_ptr - || sec == bfd_com_section_ptr - || sec == bfd_und_section_ptr) - return FALSE; - return TRUE; -} - - -static void -r_reloc_init (r_reloc *r_rel, - bfd *abfd, - Elf_Internal_Rela *irel, - bfd_byte *contents, - bfd_size_type content_length) -{ - int r_type; - reloc_howto_type *howto; - - if (irel) - { - r_rel->rela = *irel; - r_rel->abfd = abfd; - r_rel->target_offset = r_reloc_get_target_offset (r_rel); - r_rel->virtual_offset = 0; - r_type = ELF32_R_TYPE (r_rel->rela.r_info); - howto = &elf_howto_table[r_type]; - if (howto->partial_inplace) - { - bfd_vma inplace_val; - BFD_ASSERT (r_rel->rela.r_offset < content_length); - - inplace_val = bfd_get_32 (abfd, &contents[r_rel->rela.r_offset]); - r_rel->target_offset += inplace_val; - } - } - else - memset (r_rel, 0, sizeof (r_reloc)); -} - - -#if DEBUG - -static void -print_r_reloc (FILE *fp, const r_reloc *r_rel) -{ - if (r_reloc_is_defined (r_rel)) - { - asection *sec = r_reloc_get_section (r_rel); - fprintf (fp, " %s(%s + ", sec->owner->filename, sec->name); - } - else if (r_reloc_get_hash_entry (r_rel)) - fprintf (fp, " %s + ", r_reloc_get_hash_entry (r_rel)->root.root.string); - else - fprintf (fp, " ?? + "); - - fprintf_vma (fp, r_rel->target_offset); - if (r_rel->virtual_offset) - { - fprintf (fp, " + "); - fprintf_vma (fp, r_rel->virtual_offset); - } - - fprintf (fp, ")"); -} - -#endif /* DEBUG */ - - -/* source_reloc: relocations that reference literals. */ - -/* To determine whether literals can be coalesced, we need to first - record all the relocations that reference the literals. The - source_reloc structure below is used for this purpose. The - source_reloc entries are kept in a per-literal-section array, sorted - by offset within the literal section (i.e., target offset). - - The source_sec and r_rel.rela.r_offset fields identify the source of - the relocation. The r_rel field records the relocation value, i.e., - the offset of the literal being referenced. The opnd field is needed - to determine the range of the immediate field to which the relocation - applies, so we can determine whether another literal with the same - value is within range. The is_null field is true when the relocation - is being removed (e.g., when an L32R is being removed due to a CALLX - that is converted to a direct CALL). */ - -typedef struct source_reloc_struct source_reloc; - -struct source_reloc_struct -{ - asection *source_sec; - r_reloc r_rel; - xtensa_opcode opcode; - int opnd; - bfd_boolean is_null; - bfd_boolean is_abs_literal; -}; - - -static void -init_source_reloc (source_reloc *reloc, - asection *source_sec, - const r_reloc *r_rel, - xtensa_opcode opcode, - int opnd, - bfd_boolean is_abs_literal) -{ - reloc->source_sec = source_sec; - reloc->r_rel = *r_rel; - reloc->opcode = opcode; - reloc->opnd = opnd; - reloc->is_null = FALSE; - reloc->is_abs_literal = is_abs_literal; -} - - -/* Find the source_reloc for a particular source offset and relocation - type. Note that the array is sorted by _target_ offset, so this is - just a linear search. */ - -static source_reloc * -find_source_reloc (source_reloc *src_relocs, - int src_count, - asection *sec, - Elf_Internal_Rela *irel) -{ - int i; - - for (i = 0; i < src_count; i++) - { - if (src_relocs[i].source_sec == sec - && src_relocs[i].r_rel.rela.r_offset == irel->r_offset - && (ELF32_R_TYPE (src_relocs[i].r_rel.rela.r_info) - == ELF32_R_TYPE (irel->r_info))) - return &src_relocs[i]; - } - - return NULL; -} - - -static int -source_reloc_compare (const void *ap, const void *bp) -{ - const source_reloc *a = (const source_reloc *) ap; - const source_reloc *b = (const source_reloc *) bp; - - if (a->r_rel.target_offset != b->r_rel.target_offset) - return (a->r_rel.target_offset - b->r_rel.target_offset); - - /* We don't need to sort on these criteria for correctness, - but enforcing a more strict ordering prevents unstable qsort - from behaving differently with different implementations. - Without the code below we get correct but different results - on Solaris 2.7 and 2.8. We would like to always produce the - same results no matter the host. */ - - if ((!a->is_null) - (!b->is_null)) - return ((!a->is_null) - (!b->is_null)); - return internal_reloc_compare (&a->r_rel.rela, &b->r_rel.rela); -} - - -/* Literal values and value hash tables. */ - -/* Literals with the same value can be coalesced. The literal_value - structure records the value of a literal: the "r_rel" field holds the - information from the relocation on the literal (if there is one) and - the "value" field holds the contents of the literal word itself. - - The value_map structure records a literal value along with the - location of a literal holding that value. The value_map hash table - is indexed by the literal value, so that we can quickly check if a - particular literal value has been seen before and is thus a candidate - for coalescing. */ - -typedef struct literal_value_struct literal_value; -typedef struct value_map_struct value_map; -typedef struct value_map_hash_table_struct value_map_hash_table; - -struct literal_value_struct -{ - r_reloc r_rel; - unsigned long value; - bfd_boolean is_abs_literal; -}; - -struct value_map_struct -{ - literal_value val; /* The literal value. */ - r_reloc loc; /* Location of the literal. */ - value_map *next; -}; - -struct value_map_hash_table_struct -{ - unsigned bucket_count; - value_map **buckets; - unsigned count; - bfd_boolean has_last_loc; - r_reloc last_loc; -}; - - -static void -init_literal_value (literal_value *lit, - const r_reloc *r_rel, - unsigned long value, - bfd_boolean is_abs_literal) -{ - lit->r_rel = *r_rel; - lit->value = value; - lit->is_abs_literal = is_abs_literal; -} - - -static bfd_boolean -literal_value_equal (const literal_value *src1, - const literal_value *src2, - bfd_boolean final_static_link) -{ - struct elf_link_hash_entry *h1, *h2; - - if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) - return FALSE; - - if (r_reloc_is_const (&src1->r_rel)) - return (src1->value == src2->value); - - if (ELF32_R_TYPE (src1->r_rel.rela.r_info) - != ELF32_R_TYPE (src2->r_rel.rela.r_info)) - return FALSE; - - if (src1->r_rel.target_offset != src2->r_rel.target_offset) - return FALSE; - - if (src1->r_rel.virtual_offset != src2->r_rel.virtual_offset) - return FALSE; - - if (src1->value != src2->value) - return FALSE; - - /* Now check for the same section (if defined) or the same elf_hash - (if undefined or weak). */ - h1 = r_reloc_get_hash_entry (&src1->r_rel); - h2 = r_reloc_get_hash_entry (&src2->r_rel); - if (r_reloc_is_defined (&src1->r_rel) - && (final_static_link - || ((!h1 || h1->root.type != bfd_link_hash_defweak) - && (!h2 || h2->root.type != bfd_link_hash_defweak)))) - { - if (r_reloc_get_section (&src1->r_rel) - != r_reloc_get_section (&src2->r_rel)) - return FALSE; - } - else - { - /* Require that the hash entries (i.e., symbols) be identical. */ - if (h1 != h2 || h1 == 0) - return FALSE; - } - - if (src1->is_abs_literal != src2->is_abs_literal) - return FALSE; - - return TRUE; -} - - -/* Must be power of 2. */ -#define INITIAL_HASH_RELOC_BUCKET_COUNT 1024 - -static value_map_hash_table * -value_map_hash_table_init (void) -{ - value_map_hash_table *values; - - values = (value_map_hash_table *) - bfd_zmalloc (sizeof (value_map_hash_table)); - values->bucket_count = INITIAL_HASH_RELOC_BUCKET_COUNT; - values->count = 0; - values->buckets = (value_map **) - bfd_zmalloc (sizeof (value_map *) * values->bucket_count); - if (values->buckets == NULL) - { - free (values); - return NULL; - } - values->has_last_loc = FALSE; - - return values; -} - - -static void -value_map_hash_table_delete (value_map_hash_table *table) -{ - free (table->buckets); - free (table); -} - - -static unsigned -hash_bfd_vma (bfd_vma val) -{ - return (val >> 2) + (val >> 10); -} - - -static unsigned -literal_value_hash (const literal_value *src) -{ - unsigned hash_val; - - hash_val = hash_bfd_vma (src->value); - if (!r_reloc_is_const (&src->r_rel)) - { - void *sec_or_hash; - - hash_val += hash_bfd_vma (src->is_abs_literal * 1000); - hash_val += hash_bfd_vma (src->r_rel.target_offset); - hash_val += hash_bfd_vma (src->r_rel.virtual_offset); - - /* Now check for the same section and the same elf_hash. */ - if (r_reloc_is_defined (&src->r_rel)) - sec_or_hash = r_reloc_get_section (&src->r_rel); - else - sec_or_hash = r_reloc_get_hash_entry (&src->r_rel); - hash_val += hash_bfd_vma ((bfd_vma) (size_t) sec_or_hash); - } - return hash_val; -} - - -/* Check if the specified literal_value has been seen before. */ - -static value_map * -value_map_get_cached_value (value_map_hash_table *map, - const literal_value *val, - bfd_boolean final_static_link) -{ - value_map *map_e; - value_map *bucket; - unsigned idx; - - idx = literal_value_hash (val); - idx = idx & (map->bucket_count - 1); - bucket = map->buckets[idx]; - for (map_e = bucket; map_e; map_e = map_e->next) - { - if (literal_value_equal (&map_e->val, val, final_static_link)) - return map_e; - } - return NULL; -} - - -/* Record a new literal value. It is illegal to call this if VALUE - already has an entry here. */ - -static value_map * -add_value_map (value_map_hash_table *map, - const literal_value *val, - const r_reloc *loc, - bfd_boolean final_static_link) -{ - value_map **bucket_p; - unsigned idx; - - value_map *val_e = (value_map *) bfd_zmalloc (sizeof (value_map)); - if (val_e == NULL) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - - BFD_ASSERT (!value_map_get_cached_value (map, val, final_static_link)); - val_e->val = *val; - val_e->loc = *loc; - - idx = literal_value_hash (val); - idx = idx & (map->bucket_count - 1); - bucket_p = &map->buckets[idx]; - - val_e->next = *bucket_p; - *bucket_p = val_e; - map->count++; - /* FIXME: Consider resizing the hash table if we get too many entries. */ - - return val_e; -} - - -/* Lists of text actions (ta_) for narrowing, widening, longcall - conversion, space fill, code & literal removal, etc. */ - -/* The following text actions are generated: - - "ta_remove_insn" remove an instruction or instructions - "ta_remove_longcall" convert longcall to call - "ta_convert_longcall" convert longcall to nop/call - "ta_narrow_insn" narrow a wide instruction - "ta_widen" widen a narrow instruction - "ta_fill" add fill or remove fill - removed < 0 is a fill; branches to the fill address will be - changed to address + fill size (e.g., address - removed) - removed >= 0 branches to the fill address will stay unchanged - "ta_remove_literal" remove a literal; this action is - indicated when a literal is removed - or replaced. - "ta_add_literal" insert a new literal; this action is - indicated when a literal has been moved. - It may use a virtual_offset because - multiple literals can be placed at the - same location. - - For each of these text actions, we also record the number of bytes - removed by performing the text action. In the case of a "ta_widen" - or a "ta_fill" that adds space, the removed_bytes will be negative. */ - -typedef struct text_action_struct text_action; -typedef struct text_action_list_struct text_action_list; -typedef enum text_action_enum_t text_action_t; - -enum text_action_enum_t -{ - ta_none, - ta_remove_insn, /* removed = -size */ - ta_remove_longcall, /* removed = -size */ - ta_convert_longcall, /* removed = 0 */ - ta_narrow_insn, /* removed = -1 */ - ta_widen_insn, /* removed = +1 */ - ta_fill, /* removed = +size */ - ta_remove_literal, - ta_add_literal -}; - - -/* Structure for a text action record. */ -struct text_action_struct -{ - text_action_t action; - asection *sec; /* Optional */ - bfd_vma offset; - bfd_vma virtual_offset; /* Zero except for adding literals. */ - int removed_bytes; - literal_value value; /* Only valid when adding literals. */ -}; - -struct removal_by_action_entry_struct -{ - bfd_vma offset; - int removed; - int eq_removed; - int eq_removed_before_fill; -}; -typedef struct removal_by_action_entry_struct removal_by_action_entry; - -struct removal_by_action_map_struct -{ - unsigned n_entries; - removal_by_action_entry *entry; -}; -typedef struct removal_by_action_map_struct removal_by_action_map; - - -/* List of all of the actions taken on a text section. */ -struct text_action_list_struct -{ - unsigned count; - splay_tree tree; - removal_by_action_map map; -}; - - -static text_action * -find_fill_action (text_action_list *l, asection *sec, bfd_vma offset) -{ - text_action a; - - /* It is not necessary to fill at the end of a section. */ - if (sec->size == offset) - return NULL; - - a.offset = offset; - a.action = ta_fill; - - splay_tree_node node = splay_tree_lookup (l->tree, (splay_tree_key)&a); - if (node) - return (text_action *)node->value; - return NULL; -} - - -static int -compute_removed_action_diff (const text_action *ta, - asection *sec, - bfd_vma offset, - int removed, - int removable_space) -{ - int new_removed; - int current_removed = 0; - - if (ta) - current_removed = ta->removed_bytes; - - BFD_ASSERT (ta == NULL || ta->offset == offset); - BFD_ASSERT (ta == NULL || ta->action == ta_fill); - - /* It is not necessary to fill at the end of a section. Clean this up. */ - if (sec->size == offset) - new_removed = removable_space - 0; - else - { - int space; - int added = -removed - current_removed; - /* Ignore multiples of the section alignment. */ - added = ((1 << sec->alignment_power) - 1) & added; - new_removed = (-added); - - /* Modify for removable. */ - space = removable_space - new_removed; - new_removed = (removable_space - - (((1 << sec->alignment_power) - 1) & space)); - } - return (new_removed - current_removed); -} - - -static void -adjust_fill_action (text_action *ta, int fill_diff) -{ - ta->removed_bytes += fill_diff; -} - - -static int -text_action_compare (splay_tree_key a, splay_tree_key b) -{ - text_action *pa = (text_action *)a; - text_action *pb = (text_action *)b; - static const int action_priority[] = - { - [ta_fill] = 0, - [ta_none] = 1, - [ta_convert_longcall] = 2, - [ta_narrow_insn] = 3, - [ta_remove_insn] = 4, - [ta_remove_longcall] = 5, - [ta_remove_literal] = 6, - [ta_widen_insn] = 7, - [ta_add_literal] = 8, - }; - - if (pa->offset == pb->offset) - { - if (pa->action == pb->action) - return 0; - return action_priority[pa->action] - action_priority[pb->action]; - } - else - return pa->offset < pb->offset ? -1 : 1; -} - -static text_action * -action_first (text_action_list *action_list) -{ - splay_tree_node node = splay_tree_min (action_list->tree); - return node ? (text_action *)node->value : NULL; -} - -static text_action * -action_next (text_action_list *action_list, text_action *action) -{ - splay_tree_node node = splay_tree_successor (action_list->tree, - (splay_tree_key)action); - return node ? (text_action *)node->value : NULL; -} - -/* Add a modification action to the text. For the case of adding or - removing space, modify any current fill and assume that - "unreachable_space" bytes can be freely contracted. Note that a - negative removed value is a fill. */ - -static void -text_action_add (text_action_list *l, - text_action_t action, - asection *sec, - bfd_vma offset, - int removed) -{ - text_action *ta; - text_action a; - - /* It is not necessary to fill at the end of a section. */ - if (action == ta_fill && sec->size == offset) - return; - - /* It is not necessary to fill 0 bytes. */ - if (action == ta_fill && removed == 0) - return; - - a.action = action; - a.offset = offset; - - if (action == ta_fill) - { - splay_tree_node node = splay_tree_lookup (l->tree, (splay_tree_key)&a); - - if (node) - { - ta = (text_action *)node->value; - ta->removed_bytes += removed; - return; - } - } - else - BFD_ASSERT (splay_tree_lookup (l->tree, (splay_tree_key)&a) == NULL); - - ta = (text_action *) bfd_zmalloc (sizeof (text_action)); - ta->action = action; - ta->sec = sec; - ta->offset = offset; - ta->removed_bytes = removed; - splay_tree_insert (l->tree, (splay_tree_key)ta, (splay_tree_value)ta); - ++l->count; -} - - -static void -text_action_add_literal (text_action_list *l, - text_action_t action, - const r_reloc *loc, - const literal_value *value, - int removed) -{ - text_action *ta; - asection *sec = r_reloc_get_section (loc); - bfd_vma offset = loc->target_offset; - bfd_vma virtual_offset = loc->virtual_offset; - - BFD_ASSERT (action == ta_add_literal); - - /* Create a new record and fill it up. */ - ta = (text_action *) bfd_zmalloc (sizeof (text_action)); - ta->action = action; - ta->sec = sec; - ta->offset = offset; - ta->virtual_offset = virtual_offset; - ta->value = *value; - ta->removed_bytes = removed; - - BFD_ASSERT (splay_tree_lookup (l->tree, (splay_tree_key)ta) == NULL); - splay_tree_insert (l->tree, (splay_tree_key)ta, (splay_tree_value)ta); - ++l->count; -} - - -/* Find the total offset adjustment for the relaxations specified by - text_actions, beginning from a particular starting action. This is - typically used from offset_with_removed_text to search an entire list of - actions, but it may also be called directly when adjusting adjacent offsets - so that each search may begin where the previous one left off. */ - -static int -removed_by_actions (text_action_list *action_list, - text_action **p_start_action, - bfd_vma offset, - bfd_boolean before_fill) -{ - text_action *r; - int removed = 0; - - r = *p_start_action; - if (r) - { - splay_tree_node node = splay_tree_lookup (action_list->tree, - (splay_tree_key)r); - BFD_ASSERT (node != NULL && r == (text_action *)node->value); - } - - while (r) - { - if (r->offset > offset) - break; - - if (r->offset == offset - && (before_fill || r->action != ta_fill || r->removed_bytes >= 0)) - break; - - removed += r->removed_bytes; - - r = action_next (action_list, r); - } - - *p_start_action = r; - return removed; -} - - -static bfd_vma -offset_with_removed_text (text_action_list *action_list, bfd_vma offset) -{ - text_action *r = action_first (action_list); - - return offset - removed_by_actions (action_list, &r, offset, FALSE); -} - - -static unsigned -action_list_count (text_action_list *action_list) -{ - return action_list->count; -} - -typedef struct map_action_fn_context_struct map_action_fn_context; -struct map_action_fn_context_struct -{ - int removed; - removal_by_action_map map; - bfd_boolean eq_complete; -}; - -static int -map_action_fn (splay_tree_node node, void *p) -{ - map_action_fn_context *ctx = p; - text_action *r = (text_action *)node->value; - removal_by_action_entry *ientry = ctx->map.entry + ctx->map.n_entries; - - if (ctx->map.n_entries && (ientry - 1)->offset == r->offset) - { - --ientry; - } - else - { - ++ctx->map.n_entries; - ctx->eq_complete = FALSE; - ientry->offset = r->offset; - ientry->eq_removed_before_fill = ctx->removed; - } - - if (!ctx->eq_complete) - { - if (r->action != ta_fill || r->removed_bytes >= 0) - { - ientry->eq_removed = ctx->removed; - ctx->eq_complete = TRUE; - } - else - ientry->eq_removed = ctx->removed + r->removed_bytes; - } - - ctx->removed += r->removed_bytes; - ientry->removed = ctx->removed; - return 0; -} - -static void -map_removal_by_action (text_action_list *action_list) -{ - map_action_fn_context ctx; - - ctx.removed = 0; - ctx.map.n_entries = 0; - ctx.map.entry = bfd_malloc (action_list_count (action_list) * - sizeof (removal_by_action_entry)); - ctx.eq_complete = FALSE; - - splay_tree_foreach (action_list->tree, map_action_fn, &ctx); - action_list->map = ctx.map; -} - -static int -removed_by_actions_map (text_action_list *action_list, bfd_vma offset, - bfd_boolean before_fill) -{ - unsigned a, b; - - if (!action_list->map.entry) - map_removal_by_action (action_list); - - if (!action_list->map.n_entries) - return 0; - - a = 0; - b = action_list->map.n_entries; - - while (b - a > 1) - { - unsigned c = (a + b) / 2; - - if (action_list->map.entry[c].offset <= offset) - a = c; - else - b = c; - } - - if (action_list->map.entry[a].offset < offset) - { - return action_list->map.entry[a].removed; - } - else if (action_list->map.entry[a].offset == offset) - { - return before_fill ? - action_list->map.entry[a].eq_removed_before_fill : - action_list->map.entry[a].eq_removed; - } - else - { - return 0; - } -} - -static bfd_vma -offset_with_removed_text_map (text_action_list *action_list, bfd_vma offset) -{ - int removed = removed_by_actions_map (action_list, offset, FALSE); - return offset - removed; -} - - -/* The find_insn_action routine will only find non-fill actions. */ - -static text_action * -find_insn_action (text_action_list *action_list, bfd_vma offset) -{ - static const text_action_t action[] = - { - ta_convert_longcall, - ta_remove_longcall, - ta_widen_insn, - ta_narrow_insn, - ta_remove_insn, - }; - text_action a; - unsigned i; - - a.offset = offset; - for (i = 0; i < sizeof (action) / sizeof (*action); ++i) - { - splay_tree_node node; - - a.action = action[i]; - node = splay_tree_lookup (action_list->tree, (splay_tree_key)&a); - if (node) - return (text_action *)node->value; - } - return NULL; -} - - -#if DEBUG - -static void -print_action (FILE *fp, text_action *r) -{ - const char *t = "unknown"; - switch (r->action) - { - case ta_remove_insn: - t = "remove_insn"; break; - case ta_remove_longcall: - t = "remove_longcall"; break; - case ta_convert_longcall: - t = "convert_longcall"; break; - case ta_narrow_insn: - t = "narrow_insn"; break; - case ta_widen_insn: - t = "widen_insn"; break; - case ta_fill: - t = "fill"; break; - case ta_none: - t = "none"; break; - case ta_remove_literal: - t = "remove_literal"; break; - case ta_add_literal: - t = "add_literal"; break; - } - - fprintf (fp, "%s: %s[0x%lx] \"%s\" %d\n", - r->sec->owner->filename, - r->sec->name, (unsigned long) r->offset, t, r->removed_bytes); -} - -static int -print_action_list_fn (splay_tree_node node, void *p) -{ - text_action *r = (text_action *)node->value; - - print_action (p, r); - return 0; -} - -static void -print_action_list (FILE *fp, text_action_list *action_list) -{ - fprintf (fp, "Text Action\n"); - splay_tree_foreach (action_list->tree, print_action_list_fn, fp); -} - -#endif /* DEBUG */ - - -/* Lists of literals being coalesced or removed. */ - -/* In the usual case, the literal identified by "from" is being - coalesced with another literal identified by "to". If the literal is - unused and is being removed altogether, "to.abfd" will be NULL. - The removed_literal entries are kept on a per-section list, sorted - by the "from" offset field. */ - -typedef struct removed_literal_struct removed_literal; -typedef struct removed_literal_map_entry_struct removed_literal_map_entry; -typedef struct removed_literal_list_struct removed_literal_list; - -struct removed_literal_struct -{ - r_reloc from; - r_reloc to; - removed_literal *next; -}; - -struct removed_literal_map_entry_struct -{ - bfd_vma addr; - removed_literal *literal; -}; - -struct removed_literal_list_struct -{ - removed_literal *head; - removed_literal *tail; - - unsigned n_map; - removed_literal_map_entry *map; -}; - - -/* Record that the literal at "from" is being removed. If "to" is not - NULL, the "from" literal is being coalesced with the "to" literal. */ - -static void -add_removed_literal (removed_literal_list *removed_list, - const r_reloc *from, - const r_reloc *to) -{ - removed_literal *r, *new_r, *next_r; - - new_r = (removed_literal *) bfd_zmalloc (sizeof (removed_literal)); - - new_r->from = *from; - if (to) - new_r->to = *to; - else - new_r->to.abfd = NULL; - new_r->next = NULL; - - r = removed_list->head; - if (r == NULL) - { - removed_list->head = new_r; - removed_list->tail = new_r; - } - /* Special check for common case of append. */ - else if (removed_list->tail->from.target_offset < from->target_offset) - { - removed_list->tail->next = new_r; - removed_list->tail = new_r; - } - else - { - while (r->from.target_offset < from->target_offset && r->next) - { - r = r->next; - } - next_r = r->next; - r->next = new_r; - new_r->next = next_r; - if (next_r == NULL) - removed_list->tail = new_r; - } -} - -static void -map_removed_literal (removed_literal_list *removed_list) -{ - unsigned n_map = 0; - unsigned i; - removed_literal_map_entry *map = NULL; - removed_literal *r = removed_list->head; - - for (i = 0; r; ++i, r = r->next) - { - if (i == n_map) - { - n_map = (n_map * 2) + 2; - map = bfd_realloc (map, n_map * sizeof (*map)); - } - map[i].addr = r->from.target_offset; - map[i].literal = r; - } - removed_list->map = map; - removed_list->n_map = i; -} - -static int -removed_literal_compare (const void *a, const void *b) -{ - const removed_literal_map_entry *pa = a; - const removed_literal_map_entry *pb = b; - - if (pa->addr == pb->addr) - return 0; - else - return pa->addr < pb->addr ? -1 : 1; -} - -/* Check if the list of removed literals contains an entry for the - given address. Return the entry if found. */ - -static removed_literal * -find_removed_literal (removed_literal_list *removed_list, bfd_vma addr) -{ - removed_literal_map_entry *p; - removed_literal *r = NULL; - - if (removed_list->map == NULL) - map_removed_literal (removed_list); - - p = bsearch (&addr, removed_list->map, removed_list->n_map, - sizeof (*removed_list->map), removed_literal_compare); - if (p) - { - while (p != removed_list->map && (p - 1)->addr == addr) - --p; - r = p->literal; - } - return r; -} - - -#if DEBUG - -static void -print_removed_literals (FILE *fp, removed_literal_list *removed_list) -{ - removed_literal *r; - r = removed_list->head; - if (r) - fprintf (fp, "Removed Literals\n"); - for (; r != NULL; r = r->next) - { - print_r_reloc (fp, &r->from); - fprintf (fp, " => "); - if (r->to.abfd == NULL) - fprintf (fp, "REMOVED"); - else - print_r_reloc (fp, &r->to); - fprintf (fp, "\n"); - } -} - -#endif /* DEBUG */ - - -/* Per-section data for relaxation. */ - -typedef struct reloc_bfd_fix_struct reloc_bfd_fix; - -struct xtensa_relax_info_struct -{ - bfd_boolean is_relaxable_literal_section; - bfd_boolean is_relaxable_asm_section; - int visited; /* Number of times visited. */ - - source_reloc *src_relocs; /* Array[src_count]. */ - int src_count; - int src_next; /* Next src_relocs entry to assign. */ - - removed_literal_list removed_list; - text_action_list action_list; - - reloc_bfd_fix *fix_list; - reloc_bfd_fix *fix_array; - unsigned fix_array_count; - - /* Support for expanding the reloc array that is stored - in the section structure. If the relocations have been - reallocated, the newly allocated relocations will be referenced - here along with the actual size allocated. The relocation - count will always be found in the section structure. */ - Elf_Internal_Rela *allocated_relocs; - unsigned relocs_count; - unsigned allocated_relocs_count; -}; - -struct elf_xtensa_section_data -{ - struct bfd_elf_section_data elf; - xtensa_relax_info relax_info; -}; - - -static bfd_boolean -elf_xtensa_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - struct elf_xtensa_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - - -static xtensa_relax_info * -get_xtensa_relax_info (asection *sec) -{ - struct elf_xtensa_section_data *section_data; - - /* No info available if no section or if it is an output section. */ - if (!sec || sec == sec->output_section) - return NULL; - - section_data = (struct elf_xtensa_section_data *) elf_section_data (sec); - return §ion_data->relax_info; -} - - -static void -init_xtensa_relax_info (asection *sec) -{ - xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); - - relax_info->is_relaxable_literal_section = FALSE; - relax_info->is_relaxable_asm_section = FALSE; - relax_info->visited = 0; - - relax_info->src_relocs = NULL; - relax_info->src_count = 0; - relax_info->src_next = 0; - - relax_info->removed_list.head = NULL; - relax_info->removed_list.tail = NULL; - - relax_info->action_list.tree = splay_tree_new (text_action_compare, - NULL, NULL); - relax_info->action_list.map.n_entries = 0; - relax_info->action_list.map.entry = NULL; - - relax_info->fix_list = NULL; - relax_info->fix_array = NULL; - relax_info->fix_array_count = 0; - - relax_info->allocated_relocs = NULL; - relax_info->relocs_count = 0; - relax_info->allocated_relocs_count = 0; -} - - -/* Coalescing literals may require a relocation to refer to a section in - a different input file, but the standard relocation information - cannot express that. Instead, the reloc_bfd_fix structures are used - to "fix" the relocations that refer to sections in other input files. - These structures are kept on per-section lists. The "src_type" field - records the relocation type in case there are multiple relocations on - the same location. FIXME: This is ugly; an alternative might be to - add new symbols with the "owner" field to some other input file. */ - -struct reloc_bfd_fix_struct -{ - asection *src_sec; - bfd_vma src_offset; - unsigned src_type; /* Relocation type. */ - - asection *target_sec; - bfd_vma target_offset; - bfd_boolean translated; - - reloc_bfd_fix *next; -}; - - -static reloc_bfd_fix * -reloc_bfd_fix_init (asection *src_sec, - bfd_vma src_offset, - unsigned src_type, - asection *target_sec, - bfd_vma target_offset, - bfd_boolean translated) -{ - reloc_bfd_fix *fix; - - fix = (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix)); - fix->src_sec = src_sec; - fix->src_offset = src_offset; - fix->src_type = src_type; - fix->target_sec = target_sec; - fix->target_offset = target_offset; - fix->translated = translated; - - return fix; -} - - -static void -add_fix (asection *src_sec, reloc_bfd_fix *fix) -{ - xtensa_relax_info *relax_info; - - relax_info = get_xtensa_relax_info (src_sec); - fix->next = relax_info->fix_list; - relax_info->fix_list = fix; -} - - -static int -fix_compare (const void *ap, const void *bp) -{ - const reloc_bfd_fix *a = (const reloc_bfd_fix *) ap; - const reloc_bfd_fix *b = (const reloc_bfd_fix *) bp; - - if (a->src_offset != b->src_offset) - return (a->src_offset - b->src_offset); - return (a->src_type - b->src_type); -} - - -static void -cache_fix_array (asection *sec) -{ - unsigned i, count = 0; - reloc_bfd_fix *r; - xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); - - if (relax_info == NULL) - return; - if (relax_info->fix_list == NULL) - return; - - for (r = relax_info->fix_list; r != NULL; r = r->next) - count++; - - relax_info->fix_array = - (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix) * count); - relax_info->fix_array_count = count; - - r = relax_info->fix_list; - for (i = 0; i < count; i++, r = r->next) - { - relax_info->fix_array[count - 1 - i] = *r; - relax_info->fix_array[count - 1 - i].next = NULL; - } - - qsort (relax_info->fix_array, relax_info->fix_array_count, - sizeof (reloc_bfd_fix), fix_compare); -} - - -static reloc_bfd_fix * -get_bfd_fix (asection *sec, bfd_vma offset, unsigned type) -{ - xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); - reloc_bfd_fix *rv; - reloc_bfd_fix key; - - if (relax_info == NULL) - return NULL; - if (relax_info->fix_list == NULL) - return NULL; - - if (relax_info->fix_array == NULL) - cache_fix_array (sec); - - key.src_offset = offset; - key.src_type = type; - rv = bsearch (&key, relax_info->fix_array, relax_info->fix_array_count, - sizeof (reloc_bfd_fix), fix_compare); - return rv; -} - - -/* Section caching. */ - -typedef struct section_cache_struct section_cache_t; - -struct section_cache_struct -{ - asection *sec; - - bfd_byte *contents; /* Cache of the section contents. */ - bfd_size_type content_length; - - property_table_entry *ptbl; /* Cache of the section property table. */ - unsigned pte_count; - - Elf_Internal_Rela *relocs; /* Cache of the section relocations. */ - unsigned reloc_count; -}; - - -static void -init_section_cache (section_cache_t *sec_cache) -{ - memset (sec_cache, 0, sizeof (*sec_cache)); -} - - -static void -free_section_cache (section_cache_t *sec_cache) -{ - if (sec_cache->sec) - { - release_contents (sec_cache->sec, sec_cache->contents); - release_internal_relocs (sec_cache->sec, sec_cache->relocs); - if (sec_cache->ptbl) - free (sec_cache->ptbl); - } -} - - -static bfd_boolean -section_cache_section (section_cache_t *sec_cache, - asection *sec, - struct bfd_link_info *link_info) -{ - bfd *abfd; - property_table_entry *prop_table = NULL; - int ptblsize = 0; - bfd_byte *contents = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - bfd_size_type sec_size; - - if (sec == NULL) - return FALSE; - if (sec == sec_cache->sec) - return TRUE; - - abfd = sec->owner; - sec_size = bfd_get_section_limit (abfd, sec); - - /* Get the contents. */ - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - goto err; - - /* Get the relocations. */ - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - - /* Get the entry table. */ - ptblsize = xtensa_read_table_entries (abfd, sec, &prop_table, - XTENSA_PROP_SEC_NAME, FALSE); - if (ptblsize < 0) - goto err; - - /* Fill in the new section cache. */ - free_section_cache (sec_cache); - init_section_cache (sec_cache); - - sec_cache->sec = sec; - sec_cache->contents = contents; - sec_cache->content_length = sec_size; - sec_cache->relocs = internal_relocs; - sec_cache->reloc_count = sec->reloc_count; - sec_cache->pte_count = ptblsize; - sec_cache->ptbl = prop_table; - - return TRUE; - - err: - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - if (prop_table) - free (prop_table); - return FALSE; -} - - -/* Extended basic blocks. */ - -/* An ebb_struct represents an Extended Basic Block. Within this - range, we guarantee that all instructions are decodable, the - property table entries are contiguous, and no property table - specifies a segment that cannot have instructions moved. This - structure contains caches of the contents, property table and - relocations for the specified section for easy use. The range is - specified by ranges of indices for the byte offset, property table - offsets and relocation offsets. These must be consistent. */ - -typedef struct ebb_struct ebb_t; - -struct ebb_struct -{ - asection *sec; - - bfd_byte *contents; /* Cache of the section contents. */ - bfd_size_type content_length; - - property_table_entry *ptbl; /* Cache of the section property table. */ - unsigned pte_count; - - Elf_Internal_Rela *relocs; /* Cache of the section relocations. */ - unsigned reloc_count; - - bfd_vma start_offset; /* Offset in section. */ - unsigned start_ptbl_idx; /* Offset in the property table. */ - unsigned start_reloc_idx; /* Offset in the relocations. */ - - bfd_vma end_offset; - unsigned end_ptbl_idx; - unsigned end_reloc_idx; - - bfd_boolean ends_section; /* Is this the last ebb in a section? */ - - /* The unreachable property table at the end of this set of blocks; - NULL if the end is not an unreachable block. */ - property_table_entry *ends_unreachable; -}; - - -enum ebb_target_enum -{ - EBB_NO_ALIGN = 0, - EBB_DESIRE_TGT_ALIGN, - EBB_REQUIRE_TGT_ALIGN, - EBB_REQUIRE_LOOP_ALIGN, - EBB_REQUIRE_ALIGN -}; - - -/* proposed_action_struct is similar to the text_action_struct except - that is represents a potential transformation, not one that will - occur. We build a list of these for an extended basic block - and use them to compute the actual actions desired. We must be - careful that the entire set of actual actions we perform do not - break any relocations that would fit if the actions were not - performed. */ - -typedef struct proposed_action_struct proposed_action; - -struct proposed_action_struct -{ - enum ebb_target_enum align_type; /* for the target alignment */ - bfd_vma alignment_pow; - text_action_t action; - bfd_vma offset; - int removed_bytes; - bfd_boolean do_action; /* If false, then we will not perform the action. */ -}; - - -/* The ebb_constraint_struct keeps a set of proposed actions for an - extended basic block. */ - -typedef struct ebb_constraint_struct ebb_constraint; - -struct ebb_constraint_struct -{ - ebb_t ebb; - bfd_boolean start_movable; - - /* Bytes of extra space at the beginning if movable. */ - int start_extra_space; - - enum ebb_target_enum start_align; - - bfd_boolean end_movable; - - /* Bytes of extra space at the end if movable. */ - int end_extra_space; - - unsigned action_count; - unsigned action_allocated; - - /* Array of proposed actions. */ - proposed_action *actions; - - /* Action alignments -- one for each proposed action. */ - enum ebb_target_enum *action_aligns; -}; - - -static void -init_ebb_constraint (ebb_constraint *c) -{ - memset (c, 0, sizeof (ebb_constraint)); -} - - -static void -free_ebb_constraint (ebb_constraint *c) -{ - if (c->actions) - free (c->actions); -} - - -static void -init_ebb (ebb_t *ebb, - asection *sec, - bfd_byte *contents, - bfd_size_type content_length, - property_table_entry *prop_table, - unsigned ptblsize, - Elf_Internal_Rela *internal_relocs, - unsigned reloc_count) -{ - memset (ebb, 0, sizeof (ebb_t)); - ebb->sec = sec; - ebb->contents = contents; - ebb->content_length = content_length; - ebb->ptbl = prop_table; - ebb->pte_count = ptblsize; - ebb->relocs = internal_relocs; - ebb->reloc_count = reloc_count; - ebb->start_offset = 0; - ebb->end_offset = ebb->content_length - 1; - ebb->start_ptbl_idx = 0; - ebb->end_ptbl_idx = ptblsize; - ebb->start_reloc_idx = 0; - ebb->end_reloc_idx = reloc_count; -} - - -/* Extend the ebb to all decodable contiguous sections. The algorithm - for building a basic block around an instruction is to push it - forward until we hit the end of a section, an unreachable block or - a block that cannot be transformed. Then we push it backwards - searching for similar conditions. */ - -static bfd_boolean extend_ebb_bounds_forward (ebb_t *); -static bfd_boolean extend_ebb_bounds_backward (ebb_t *); -static bfd_size_type insn_block_decodable_len - (bfd_byte *, bfd_size_type, bfd_vma, bfd_size_type); - -static bfd_boolean -extend_ebb_bounds (ebb_t *ebb) -{ - if (!extend_ebb_bounds_forward (ebb)) - return FALSE; - if (!extend_ebb_bounds_backward (ebb)) - return FALSE; - return TRUE; -} - - -static bfd_boolean -extend_ebb_bounds_forward (ebb_t *ebb) -{ - property_table_entry *the_entry, *new_entry; - - the_entry = &ebb->ptbl[ebb->end_ptbl_idx]; - - /* Stop when (1) we cannot decode an instruction, (2) we are at - the end of the property tables, (3) we hit a non-contiguous property - table entry, (4) we hit a NO_TRANSFORM region. */ - - while (1) - { - bfd_vma entry_end; - bfd_size_type insn_block_len; - - entry_end = the_entry->address - ebb->sec->vma + the_entry->size; - insn_block_len = - insn_block_decodable_len (ebb->contents, ebb->content_length, - ebb->end_offset, - entry_end - ebb->end_offset); - if (insn_block_len != (entry_end - ebb->end_offset)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): could not decode instruction; " - "possible configuration mismatch"), - ebb->sec->owner, ebb->sec, ebb->end_offset + insn_block_len); - return FALSE; - } - ebb->end_offset += insn_block_len; - - if (ebb->end_offset == ebb->sec->size) - ebb->ends_section = TRUE; - - /* Update the reloc counter. */ - while (ebb->end_reloc_idx + 1 < ebb->reloc_count - && (ebb->relocs[ebb->end_reloc_idx + 1].r_offset - < ebb->end_offset)) - { - ebb->end_reloc_idx++; - } - - if (ebb->end_ptbl_idx + 1 == ebb->pte_count) - return TRUE; - - new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1]; - if (((new_entry->flags & XTENSA_PROP_INSN) == 0) - || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0) - || ((the_entry->flags & XTENSA_PROP_ALIGN) != 0)) - break; - - if (the_entry->address + the_entry->size != new_entry->address) - break; - - the_entry = new_entry; - ebb->end_ptbl_idx++; - } - - /* Quick check for an unreachable or end of file just at the end. */ - if (ebb->end_ptbl_idx + 1 == ebb->pte_count) - { - if (ebb->end_offset == ebb->content_length) - ebb->ends_section = TRUE; - } - else - { - new_entry = &ebb->ptbl[ebb->end_ptbl_idx + 1]; - if ((new_entry->flags & XTENSA_PROP_UNREACHABLE) != 0 - && the_entry->address + the_entry->size == new_entry->address) - ebb->ends_unreachable = new_entry; - } - - /* Any other ending requires exact alignment. */ - return TRUE; -} - - -static bfd_boolean -extend_ebb_bounds_backward (ebb_t *ebb) -{ - property_table_entry *the_entry, *new_entry; - - the_entry = &ebb->ptbl[ebb->start_ptbl_idx]; - - /* Stop when (1) we cannot decode the instructions in the current entry. - (2) we are at the beginning of the property tables, (3) we hit a - non-contiguous property table entry, (4) we hit a NO_TRANSFORM region. */ - - while (1) - { - bfd_vma block_begin; - bfd_size_type insn_block_len; - - block_begin = the_entry->address - ebb->sec->vma; - insn_block_len = - insn_block_decodable_len (ebb->contents, ebb->content_length, - block_begin, - ebb->start_offset - block_begin); - if (insn_block_len != ebb->start_offset - block_begin) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): could not decode instruction; " - "possible configuration mismatch"), - ebb->sec->owner, ebb->sec, ebb->end_offset + insn_block_len); - return FALSE; - } - ebb->start_offset -= insn_block_len; - - /* Update the reloc counter. */ - while (ebb->start_reloc_idx > 0 - && (ebb->relocs[ebb->start_reloc_idx - 1].r_offset - >= ebb->start_offset)) - { - ebb->start_reloc_idx--; - } - - if (ebb->start_ptbl_idx == 0) - return TRUE; - - new_entry = &ebb->ptbl[ebb->start_ptbl_idx - 1]; - if ((new_entry->flags & XTENSA_PROP_INSN) == 0 - || ((new_entry->flags & XTENSA_PROP_NO_TRANSFORM) != 0) - || ((new_entry->flags & XTENSA_PROP_ALIGN) != 0)) - return TRUE; - if (new_entry->address + new_entry->size != the_entry->address) - return TRUE; - - the_entry = new_entry; - ebb->start_ptbl_idx--; - } - return TRUE; -} - - -static bfd_size_type -insn_block_decodable_len (bfd_byte *contents, - bfd_size_type content_len, - bfd_vma block_offset, - bfd_size_type block_len) -{ - bfd_vma offset = block_offset; - - while (offset < block_offset + block_len) - { - bfd_size_type insn_len = 0; - - insn_len = insn_decode_len (contents, content_len, offset); - if (insn_len == 0) - return (offset - block_offset); - offset += insn_len; - } - return (offset - block_offset); -} - - -static void -ebb_propose_action (ebb_constraint *c, - enum ebb_target_enum align_type, - bfd_vma alignment_pow, - text_action_t action, - bfd_vma offset, - int removed_bytes, - bfd_boolean do_action) -{ - proposed_action *act; - - if (c->action_allocated <= c->action_count) - { - unsigned new_allocated, i; - proposed_action *new_actions; - - new_allocated = (c->action_count + 2) * 2; - new_actions = (proposed_action *) - bfd_zmalloc (sizeof (proposed_action) * new_allocated); - - for (i = 0; i < c->action_count; i++) - new_actions[i] = c->actions[i]; - if (c->actions) - free (c->actions); - c->actions = new_actions; - c->action_allocated = new_allocated; - } - - act = &c->actions[c->action_count]; - act->align_type = align_type; - act->alignment_pow = alignment_pow; - act->action = action; - act->offset = offset; - act->removed_bytes = removed_bytes; - act->do_action = do_action; - - c->action_count++; -} - - -/* Access to internal relocations, section contents and symbols. */ - -/* During relaxation, we need to modify relocations, section contents, - and symbol definitions, and we need to keep the original values from - being reloaded from the input files, i.e., we need to "pin" the - modified values in memory. We also want to continue to observe the - setting of the "keep-memory" flag. The following functions wrap the - standard BFD functions to take care of this for us. */ - -static Elf_Internal_Rela * -retrieve_internal_relocs (bfd *abfd, asection *sec, bfd_boolean keep_memory) -{ - Elf_Internal_Rela *internal_relocs; - - if ((sec->flags & SEC_LINKER_CREATED) != 0) - return NULL; - - internal_relocs = elf_section_data (sec)->relocs; - if (internal_relocs == NULL) - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, NULL, keep_memory)); - return internal_relocs; -} - - -static void -pin_internal_relocs (asection *sec, Elf_Internal_Rela *internal_relocs) -{ - elf_section_data (sec)->relocs = internal_relocs; -} - - -static void -release_internal_relocs (asection *sec, Elf_Internal_Rela *internal_relocs) -{ - if (internal_relocs - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); -} - - -static bfd_byte * -retrieve_contents (bfd *abfd, asection *sec, bfd_boolean keep_memory) -{ - bfd_byte *contents; - bfd_size_type sec_size; - - sec_size = bfd_get_section_limit (abfd, sec); - contents = elf_section_data (sec)->this_hdr.contents; - - if (contents == NULL && sec_size != 0) - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - { - if (contents) - free (contents); - return NULL; - } - if (keep_memory) - elf_section_data (sec)->this_hdr.contents = contents; - } - return contents; -} - - -static void -pin_contents (asection *sec, bfd_byte *contents) -{ - elf_section_data (sec)->this_hdr.contents = contents; -} - - -static void -release_contents (asection *sec, bfd_byte *contents) -{ - if (contents && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); -} - - -static Elf_Internal_Sym * -retrieve_local_syms (bfd *input_bfd) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf; - size_t locsymcount; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL && locsymcount != 0) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, - NULL, NULL, NULL); - - /* Save the symbols for this input file so they won't be read again. */ - if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents) - symtab_hdr->contents = (unsigned char *) isymbuf; - - return isymbuf; -} - - -/* Code for link-time relaxation. */ - -/* Initialization for relaxation: */ -static bfd_boolean analyze_relocations (struct bfd_link_info *); -static bfd_boolean find_relaxable_sections - (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); -static bfd_boolean collect_source_relocs - (bfd *, asection *, struct bfd_link_info *); -static bfd_boolean is_resolvable_asm_expansion - (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, struct bfd_link_info *, - bfd_boolean *); -static Elf_Internal_Rela *find_associated_l32r_irel - (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Rela *); -static bfd_boolean compute_text_actions - (bfd *, asection *, struct bfd_link_info *); -static bfd_boolean compute_ebb_proposed_actions (ebb_constraint *); -static bfd_boolean compute_ebb_actions (ebb_constraint *); -typedef struct reloc_range_list_struct reloc_range_list; -static bfd_boolean check_section_ebb_pcrels_fit - (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, - reloc_range_list *, const ebb_constraint *, - const xtensa_opcode *); -static bfd_boolean check_section_ebb_reduces (const ebb_constraint *); -static void text_action_add_proposed - (text_action_list *, const ebb_constraint *, asection *); -static int compute_fill_extra_space (property_table_entry *); - -/* First pass: */ -static bfd_boolean compute_removed_literals - (bfd *, asection *, struct bfd_link_info *, value_map_hash_table *); -static Elf_Internal_Rela *get_irel_at_offset - (asection *, Elf_Internal_Rela *, bfd_vma); -static bfd_boolean is_removable_literal - (const source_reloc *, int, const source_reloc *, int, asection *, - property_table_entry *, int); -static bfd_boolean remove_dead_literal - (bfd *, asection *, struct bfd_link_info *, Elf_Internal_Rela *, - Elf_Internal_Rela *, source_reloc *, property_table_entry *, int); -static bfd_boolean identify_literal_placement - (bfd *, asection *, bfd_byte *, struct bfd_link_info *, - value_map_hash_table *, bfd_boolean *, Elf_Internal_Rela *, int, - source_reloc *, property_table_entry *, int, section_cache_t *, - bfd_boolean); -static bfd_boolean relocations_reach (source_reloc *, int, const r_reloc *); -static bfd_boolean coalesce_shared_literal - (asection *, source_reloc *, property_table_entry *, int, value_map *); -static bfd_boolean move_shared_literal - (asection *, struct bfd_link_info *, source_reloc *, property_table_entry *, - int, const r_reloc *, const literal_value *, section_cache_t *); - -/* Second pass: */ -static bfd_boolean relax_section (bfd *, asection *, struct bfd_link_info *); -static bfd_boolean translate_section_fixes (asection *); -static bfd_boolean translate_reloc_bfd_fix (reloc_bfd_fix *); -static asection *translate_reloc (const r_reloc *, r_reloc *, asection *); -static void shrink_dynamic_reloc_sections - (struct bfd_link_info *, bfd *, asection *, Elf_Internal_Rela *); -static bfd_boolean move_literal - (bfd *, struct bfd_link_info *, asection *, bfd_vma, bfd_byte *, - xtensa_relax_info *, Elf_Internal_Rela **, const literal_value *); -static bfd_boolean relax_property_section - (bfd *, asection *, struct bfd_link_info *); - -/* Third pass: */ -static bfd_boolean relax_section_symbols (bfd *, asection *); - - -static bfd_boolean -elf_xtensa_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - static value_map_hash_table *values = NULL; - static bfd_boolean relocations_analyzed = FALSE; - xtensa_relax_info *relax_info; - - if (!relocations_analyzed) - { - /* Do some overall initialization for relaxation. */ - values = value_map_hash_table_init (); - if (values == NULL) - return FALSE; - relaxing_section = TRUE; - if (!analyze_relocations (link_info)) - return FALSE; - relocations_analyzed = TRUE; - } - *again = FALSE; - - /* Don't mess with linker-created sections. */ - if ((sec->flags & SEC_LINKER_CREATED) != 0) - return TRUE; - - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info != NULL); - - switch (relax_info->visited) - { - case 0: - /* Note: It would be nice to fold this pass into - analyze_relocations, but it is important for this step that the - sections be examined in link order. */ - if (!compute_removed_literals (abfd, sec, link_info, values)) - return FALSE; - *again = TRUE; - break; - - case 1: - if (values) - value_map_hash_table_delete (values); - values = NULL; - if (!relax_section (abfd, sec, link_info)) - return FALSE; - *again = TRUE; - break; - - case 2: - if (!relax_section_symbols (abfd, sec)) - return FALSE; - break; - } - - relax_info->visited++; - return TRUE; -} - - -/* Initialization for relaxation. */ - -/* This function is called once at the start of relaxation. It scans - all the input sections and marks the ones that are relaxable (i.e., - literal sections with L32R relocations against them), and then - collects source_reloc information for all the relocations against - those relaxable sections. During this process, it also detects - longcalls, i.e., calls relaxed by the assembler into indirect - calls, that can be optimized back into direct calls. Within each - extended basic block (ebb) containing an optimized longcall, it - computes a set of "text actions" that can be performed to remove - the L32R associated with the longcall while optionally preserving - branch target alignments. */ - -static bfd_boolean -analyze_relocations (struct bfd_link_info *link_info) -{ - bfd *abfd; - asection *sec; - bfd_boolean is_relaxable = FALSE; - - /* Initialize the per-section relaxation info. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - init_xtensa_relax_info (sec); - } - - /* Mark relaxable sections (and count relocations against each one). */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (!find_relaxable_sections (abfd, sec, link_info, &is_relaxable)) - return FALSE; - } - - /* Bail out if there are no relaxable sections. */ - if (!is_relaxable) - return TRUE; - - /* Allocate space for source_relocs. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - xtensa_relax_info *relax_info; - - relax_info = get_xtensa_relax_info (sec); - if (relax_info->is_relaxable_literal_section - || relax_info->is_relaxable_asm_section) - { - relax_info->src_relocs = (source_reloc *) - bfd_malloc (relax_info->src_count * sizeof (source_reloc)); - } - else - relax_info->src_count = 0; - } - - /* Collect info on relocations against each relaxable section. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (!collect_source_relocs (abfd, sec, link_info)) - return FALSE; - } - - /* Compute the text actions. */ - for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link.next) - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (!compute_text_actions (abfd, sec, link_info)) - return FALSE; - } - - return TRUE; -} - - -/* Find all the sections that might be relaxed. The motivation for - this pass is that collect_source_relocs() needs to record _all_ the - relocations that target each relaxable section. That is expensive - and unnecessary unless the target section is actually going to be - relaxed. This pass identifies all such sections by checking if - they have L32Rs pointing to them. In the process, the total number - of relocations targeting each section is also counted so that we - know how much space to allocate for source_relocs against each - relaxable literal section. */ - -static bfd_boolean -find_relaxable_sections (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *is_relaxable_p) -{ - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents; - bfd_boolean ok = TRUE; - unsigned i; - xtensa_relax_info *source_relax_info; - bfd_boolean is_l32r_reloc; - - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - if (internal_relocs == NULL) - return ok; - - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec->size != 0) - { - ok = FALSE; - goto error_return; - } - - source_relax_info = get_xtensa_relax_info (sec); - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - r_reloc r_rel; - asection *target_sec; - xtensa_relax_info *target_relax_info; - - /* If this section has not already been marked as "relaxable", and - if it contains any ASM_EXPAND relocations (marking expanded - longcalls) that can be optimized into direct calls, then mark - the section as "relaxable". */ - if (source_relax_info - && !source_relax_info->is_relaxable_asm_section - && ELF32_R_TYPE (irel->r_info) == R_XTENSA_ASM_EXPAND) - { - bfd_boolean is_reachable = FALSE; - if (is_resolvable_asm_expansion (abfd, sec, contents, irel, - link_info, &is_reachable) - && is_reachable) - { - source_relax_info->is_relaxable_asm_section = TRUE; - *is_relaxable_p = TRUE; - } - } - - r_reloc_init (&r_rel, abfd, irel, contents, - bfd_get_section_limit (abfd, sec)); - - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); - if (!target_relax_info) - continue; - - /* Count PC-relative operand relocations against the target section. - Note: The conditions tested here must match the conditions under - which init_source_reloc is called in collect_source_relocs(). */ - is_l32r_reloc = FALSE; - if (is_operand_relocation (ELF32_R_TYPE (irel->r_info))) - { - xtensa_opcode opcode = - get_relocation_opcode (abfd, sec, contents, irel); - if (opcode != XTENSA_UNDEFINED) - { - is_l32r_reloc = (opcode == get_l32r_opcode ()); - if (!is_alt_relocation (ELF32_R_TYPE (irel->r_info)) - || is_l32r_reloc) - target_relax_info->src_count++; - } - } - - if (is_l32r_reloc && r_reloc_is_defined (&r_rel)) - { - /* Mark the target section as relaxable. */ - target_relax_info->is_relaxable_literal_section = TRUE; - *is_relaxable_p = TRUE; - } - } - - error_return: - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - return ok; -} - - -/* Record _all_ the relocations that point to relaxable sections, and - get rid of ASM_EXPAND relocs by either converting them to - ASM_SIMPLIFY or by removing them. */ - -static bfd_boolean -collect_source_relocs (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info) -{ - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents; - bfd_boolean ok = TRUE; - unsigned i; - bfd_size_type sec_size; - - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - if (internal_relocs == NULL) - return ok; - - sec_size = bfd_get_section_limit (abfd, sec); - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - { - ok = FALSE; - goto error_return; - } - - /* Record relocations against relaxable literal sections. */ - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - r_reloc r_rel; - asection *target_sec; - xtensa_relax_info *target_relax_info; - - r_reloc_init (&r_rel, abfd, irel, contents, sec_size); - - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); - - if (target_relax_info - && (target_relax_info->is_relaxable_literal_section - || target_relax_info->is_relaxable_asm_section)) - { - xtensa_opcode opcode = XTENSA_UNDEFINED; - int opnd = -1; - bfd_boolean is_abs_literal = FALSE; - - if (is_alt_relocation (ELF32_R_TYPE (irel->r_info))) - { - /* None of the current alternate relocs are PC-relative, - and only PC-relative relocs matter here. However, we - still need to record the opcode for literal - coalescing. */ - opcode = get_relocation_opcode (abfd, sec, contents, irel); - if (opcode == get_l32r_opcode ()) - { - is_abs_literal = TRUE; - opnd = 1; - } - else - opcode = XTENSA_UNDEFINED; - } - else if (is_operand_relocation (ELF32_R_TYPE (irel->r_info))) - { - opcode = get_relocation_opcode (abfd, sec, contents, irel); - opnd = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info)); - } - - if (opcode != XTENSA_UNDEFINED) - { - int src_next = target_relax_info->src_next++; - source_reloc *s_reloc = &target_relax_info->src_relocs[src_next]; - - init_source_reloc (s_reloc, sec, &r_rel, opcode, opnd, - is_abs_literal); - } - } - } - - /* Now get rid of ASM_EXPAND relocations. At this point, the - src_relocs array for the target literal section may still be - incomplete, but it must at least contain the entries for the L32R - relocations associated with ASM_EXPANDs because they were just - added in the preceding loop over the relocations. */ - - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - bfd_boolean is_reachable; - - if (!is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, - &is_reachable)) - continue; - - if (is_reachable) - { - Elf_Internal_Rela *l32r_irel; - r_reloc r_rel; - asection *target_sec; - xtensa_relax_info *target_relax_info; - - /* Mark the source_reloc for the L32R so that it will be - removed in compute_removed_literals(), along with the - associated literal. */ - l32r_irel = find_associated_l32r_irel (abfd, sec, contents, - irel, internal_relocs); - if (l32r_irel == NULL) - continue; - - r_reloc_init (&r_rel, abfd, l32r_irel, contents, sec_size); - - target_sec = r_reloc_get_section (&r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); - - if (target_relax_info - && (target_relax_info->is_relaxable_literal_section - || target_relax_info->is_relaxable_asm_section)) - { - source_reloc *s_reloc; - - /* Search the source_relocs for the entry corresponding to - the l32r_irel. Note: The src_relocs array is not yet - sorted, but it wouldn't matter anyway because we're - searching by source offset instead of target offset. */ - s_reloc = find_source_reloc (target_relax_info->src_relocs, - target_relax_info->src_next, - sec, l32r_irel); - BFD_ASSERT (s_reloc); - s_reloc->is_null = TRUE; - } - - /* Convert this reloc to ASM_SIMPLIFY. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_XTENSA_ASM_SIMPLIFY); - l32r_irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - - pin_internal_relocs (sec, internal_relocs); - } - else - { - /* It is resolvable but doesn't reach. We resolve now - by eliminating the relocation -- the call will remain - expanded into L32R/CALLX. */ - irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - pin_internal_relocs (sec, internal_relocs); - } - } - - error_return: - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - return ok; -} - - -/* Return TRUE if the asm expansion can be resolved. Generally it can - be resolved on a final link or when a partial link locates it in the - same section as the target. Set "is_reachable" flag if the target of - the call is within the range of a direct call, given the current VMA - for this section and the target section. */ - -bfd_boolean -is_resolvable_asm_expansion (bfd *abfd, - asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *irel, - struct bfd_link_info *link_info, - bfd_boolean *is_reachable_p) -{ - asection *target_sec; - bfd_vma target_offset; - r_reloc r_rel; - xtensa_opcode opcode, direct_call_opcode; - bfd_vma self_address; - bfd_vma dest_address; - bfd_boolean uses_l32r; - bfd_size_type sec_size; - - *is_reachable_p = FALSE; - - if (contents == NULL) - return FALSE; - - if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND) - return FALSE; - - sec_size = bfd_get_section_limit (abfd, sec); - opcode = get_expanded_call_opcode (contents + irel->r_offset, - sec_size - irel->r_offset, &uses_l32r); - /* Optimization of longcalls that use CONST16 is not yet implemented. */ - if (!uses_l32r) - return FALSE; - - direct_call_opcode = swap_callx_for_call_opcode (opcode); - if (direct_call_opcode == XTENSA_UNDEFINED) - return FALSE; - - /* Check and see that the target resolves. */ - r_reloc_init (&r_rel, abfd, irel, contents, sec_size); - if (!r_reloc_is_defined (&r_rel)) - return FALSE; - - target_sec = r_reloc_get_section (&r_rel); - target_offset = r_rel.target_offset; - - /* If the target is in a shared library, then it doesn't reach. This - isn't supposed to come up because the compiler should never generate - non-PIC calls on systems that use shared libraries, but the linker - shouldn't crash regardless. */ - if (!target_sec->output_section) - return FALSE; - - /* For relocatable sections, we can only simplify when the output - section of the target is the same as the output section of the - source. */ - if (bfd_link_relocatable (link_info) - && (target_sec->output_section != sec->output_section - || is_reloc_sym_weak (abfd, irel))) - return FALSE; - - if (target_sec->output_section != sec->output_section) - { - /* If the two sections are sufficiently far away that relaxation - might take the call out of range, we can't simplify. For - example, a positive displacement call into another memory - could get moved to a lower address due to literal removal, - but the destination won't move, and so the displacment might - get larger. - - If the displacement is negative, assume the destination could - move as far back as the start of the output section. The - self_address will be at least as far into the output section - as it is prior to relaxation. - - If the displacement is postive, assume the destination will be in - it's pre-relaxed location (because relaxation only makes sections - smaller). The self_address could go all the way to the beginning - of the output section. */ - - dest_address = target_sec->output_section->vma; - self_address = sec->output_section->vma; - - if (sec->output_section->vma > target_sec->output_section->vma) - self_address += sec->output_offset + irel->r_offset + 3; - else - dest_address += bfd_get_section_limit (abfd, target_sec->output_section); - /* Call targets should be four-byte aligned. */ - dest_address = (dest_address + 3) & ~3; - } - else - { - - self_address = (sec->output_section->vma - + sec->output_offset + irel->r_offset + 3); - dest_address = (target_sec->output_section->vma - + target_sec->output_offset + target_offset); - } - - *is_reachable_p = pcrel_reloc_fits (direct_call_opcode, 0, - self_address, dest_address); - - if ((self_address >> CALL_SEGMENT_BITS) != - (dest_address >> CALL_SEGMENT_BITS)) - return FALSE; - - return TRUE; -} - - -static Elf_Internal_Rela * -find_associated_l32r_irel (bfd *abfd, - asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *other_irel, - Elf_Internal_Rela *internal_relocs) -{ - unsigned i; - - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - - if (irel == other_irel) - continue; - if (irel->r_offset != other_irel->r_offset) - continue; - if (is_l32r_relocation (abfd, sec, contents, irel)) - return irel; - } - - return NULL; -} - - -static xtensa_opcode * -build_reloc_opcodes (bfd *abfd, - asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *internal_relocs) -{ - unsigned i; - xtensa_opcode *reloc_opcodes = - (xtensa_opcode *) bfd_malloc (sizeof (xtensa_opcode) * sec->reloc_count); - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - reloc_opcodes[i] = get_relocation_opcode (abfd, sec, contents, irel); - } - return reloc_opcodes; -} - -struct reloc_range_struct -{ - bfd_vma addr; - bfd_boolean add; /* TRUE if start of a range, FALSE otherwise. */ - /* Original irel index in the array of relocations for a section. */ - unsigned irel_index; -}; -typedef struct reloc_range_struct reloc_range; - -typedef struct reloc_range_list_entry_struct reloc_range_list_entry; -struct reloc_range_list_entry_struct -{ - reloc_range_list_entry *next; - reloc_range_list_entry *prev; - Elf_Internal_Rela *irel; - xtensa_opcode opcode; - int opnum; -}; - -struct reloc_range_list_struct -{ - /* The rest of the structure is only meaningful when ok is TRUE. */ - bfd_boolean ok; - - unsigned n_range; /* Number of range markers. */ - reloc_range *range; /* Sorted range markers. */ - - unsigned first; /* Index of a first range element in the list. */ - unsigned last; /* One past index of a last range element in the list. */ - - unsigned n_list; /* Number of list elements. */ - reloc_range_list_entry *reloc; /* */ - reloc_range_list_entry list_root; -}; - -static int -reloc_range_compare (const void *a, const void *b) -{ - const reloc_range *ra = a; - const reloc_range *rb = b; - - if (ra->addr != rb->addr) - return ra->addr < rb->addr ? -1 : 1; - if (ra->add != rb->add) - return ra->add ? -1 : 1; - return 0; -} - -static void -build_reloc_ranges (bfd *abfd, asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *internal_relocs, - xtensa_opcode *reloc_opcodes, - reloc_range_list *list) -{ - unsigned i; - size_t n = 0; - size_t max_n = 0; - reloc_range *ranges = NULL; - reloc_range_list_entry *reloc = - bfd_malloc (sec->reloc_count * sizeof (*reloc)); - - memset (list, 0, sizeof (*list)); - list->ok = TRUE; - - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - int r_type = ELF32_R_TYPE (irel->r_info); - reloc_howto_type *howto = &elf_howto_table[r_type]; - r_reloc r_rel; - - if (r_type == R_XTENSA_ASM_SIMPLIFY - || r_type == R_XTENSA_32_PCREL - || !howto->pc_relative) - continue; - - r_reloc_init (&r_rel, abfd, irel, contents, - bfd_get_section_limit (abfd, sec)); - - if (r_reloc_get_section (&r_rel) != sec) - continue; - - if (n + 2 > max_n) - { - max_n = (max_n + 2) * 2; - ranges = bfd_realloc (ranges, max_n * sizeof (*ranges)); - } - - ranges[n].addr = irel->r_offset; - ranges[n + 1].addr = r_rel.target_offset; - - ranges[n].add = ranges[n].addr < ranges[n + 1].addr; - ranges[n + 1].add = !ranges[n].add; - - ranges[n].irel_index = i; - ranges[n + 1].irel_index = i; - - n += 2; - - reloc[i].irel = irel; - - /* Every relocation won't possibly be checked in the optimized version of - check_section_ebb_pcrels_fit, so this needs to be done here. */ - if (is_alt_relocation (ELF32_R_TYPE (irel->r_info))) - { - /* None of the current alternate relocs are PC-relative, - and only PC-relative relocs matter here. */ - } - else - { - xtensa_opcode opcode; - int opnum; - - if (reloc_opcodes) - opcode = reloc_opcodes[i]; - else - opcode = get_relocation_opcode (abfd, sec, contents, irel); - - if (opcode == XTENSA_UNDEFINED) - { - list->ok = FALSE; - break; - } - - opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info)); - if (opnum == XTENSA_UNDEFINED) - { - list->ok = FALSE; - break; - } - - /* Record relocation opcode and opnum as we've calculated them - anyway and they won't change. */ - reloc[i].opcode = opcode; - reloc[i].opnum = opnum; - } - } - - if (list->ok) - { - ranges = bfd_realloc (ranges, n * sizeof (*ranges)); - qsort (ranges, n, sizeof (*ranges), reloc_range_compare); - - list->n_range = n; - list->range = ranges; - list->reloc = reloc; - list->list_root.prev = &list->list_root; - list->list_root.next = &list->list_root; - } - else - { - free (ranges); - free (reloc); - } -} - -static void reloc_range_list_append (reloc_range_list *list, - unsigned irel_index) -{ - reloc_range_list_entry *entry = list->reloc + irel_index; - - entry->prev = list->list_root.prev; - entry->next = &list->list_root; - entry->prev->next = entry; - entry->next->prev = entry; - ++list->n_list; -} - -static void reloc_range_list_remove (reloc_range_list *list, - unsigned irel_index) -{ - reloc_range_list_entry *entry = list->reloc + irel_index; - - entry->next->prev = entry->prev; - entry->prev->next = entry->next; - --list->n_list; -} - -/* Update relocation list object so that it lists all relocations that cross - [first; last] range. Range bounds should not decrease with successive - invocations. */ -static void reloc_range_list_update_range (reloc_range_list *list, - bfd_vma first, bfd_vma last) -{ - /* This should not happen: EBBs are iterated from lower addresses to higher. - But even if that happens there's no need to break: just flush current list - and start from scratch. */ - if ((list->last > 0 && list->range[list->last - 1].addr > last) || - (list->first > 0 && list->range[list->first - 1].addr >= first)) - { - list->first = 0; - list->last = 0; - list->n_list = 0; - list->list_root.next = &list->list_root; - list->list_root.prev = &list->list_root; - fprintf (stderr, "%s: move backwards requested\n", __func__); - } - - for (; list->last < list->n_range && - list->range[list->last].addr <= last; ++list->last) - if (list->range[list->last].add) - reloc_range_list_append (list, list->range[list->last].irel_index); - - for (; list->first < list->n_range && - list->range[list->first].addr < first; ++list->first) - if (!list->range[list->first].add) - reloc_range_list_remove (list, list->range[list->first].irel_index); -} - -static void free_reloc_range_list (reloc_range_list *list) -{ - free (list->range); - free (list->reloc); -} - -/* The compute_text_actions function will build a list of potential - transformation actions for code in the extended basic block of each - longcall that is optimized to a direct call. From this list we - generate a set of actions to actually perform that optimizes for - space and, if not using size_opt, maintains branch target - alignments. - - These actions to be performed are placed on a per-section list. - The actual changes are performed by relax_section() in the second - pass. */ - -bfd_boolean -compute_text_actions (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info) -{ - xtensa_opcode *reloc_opcodes = NULL; - xtensa_relax_info *relax_info; - bfd_byte *contents; - Elf_Internal_Rela *internal_relocs; - bfd_boolean ok = TRUE; - unsigned i; - property_table_entry *prop_table = 0; - int ptblsize = 0; - bfd_size_type sec_size; - reloc_range_list relevant_relocs; - - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info); - BFD_ASSERT (relax_info->src_next == relax_info->src_count); - - /* Do nothing if the section contains no optimized longcalls. */ - if (!relax_info->is_relaxable_asm_section) - return ok; - - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - - if (internal_relocs) - qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), - internal_reloc_compare); - - sec_size = bfd_get_section_limit (abfd, sec); - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - { - ok = FALSE; - goto error_return; - } - - ptblsize = xtensa_read_table_entries (abfd, sec, &prop_table, - XTENSA_PROP_SEC_NAME, FALSE); - if (ptblsize < 0) - { - ok = FALSE; - goto error_return; - } - - /* Precompute the opcode for each relocation. */ - reloc_opcodes = build_reloc_opcodes (abfd, sec, contents, internal_relocs); - - build_reloc_ranges (abfd, sec, contents, internal_relocs, reloc_opcodes, - &relevant_relocs); - - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - bfd_vma r_offset; - property_table_entry *the_entry; - int ptbl_idx; - ebb_t *ebb; - ebb_constraint ebb_table; - bfd_size_type simplify_size; - - if (irel && ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_SIMPLIFY) - continue; - r_offset = irel->r_offset; - - simplify_size = get_asm_simplify_size (contents, sec_size, r_offset); - if (simplify_size == 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): could not decode instruction for " - "XTENSA_ASM_SIMPLIFY relocation; " - "possible configuration mismatch"), - sec->owner, sec, r_offset); - continue; - } - - /* If the instruction table is not around, then don't do this - relaxation. */ - the_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, - sec->vma + irel->r_offset); - if (the_entry == NULL || XTENSA_NO_NOP_REMOVAL) - { - text_action_add (&relax_info->action_list, - ta_convert_longcall, sec, r_offset, - 0); - continue; - } - - /* If the next longcall happens to be at the same address as an - unreachable section of size 0, then skip forward. */ - ptbl_idx = the_entry - prop_table; - while ((the_entry->flags & XTENSA_PROP_UNREACHABLE) - && the_entry->size == 0 - && ptbl_idx + 1 < ptblsize - && (prop_table[ptbl_idx + 1].address - == prop_table[ptbl_idx].address)) - { - ptbl_idx++; - the_entry++; - } - - if (the_entry->flags & XTENSA_PROP_NO_TRANSFORM) - /* NO_REORDER is OK */ - continue; - - init_ebb_constraint (&ebb_table); - ebb = &ebb_table.ebb; - init_ebb (ebb, sec, contents, sec_size, prop_table, ptblsize, - internal_relocs, sec->reloc_count); - ebb->start_offset = r_offset + simplify_size; - ebb->end_offset = r_offset + simplify_size; - ebb->start_ptbl_idx = ptbl_idx; - ebb->end_ptbl_idx = ptbl_idx; - ebb->start_reloc_idx = i; - ebb->end_reloc_idx = i; - - if (!extend_ebb_bounds (ebb) - || !compute_ebb_proposed_actions (&ebb_table) - || !compute_ebb_actions (&ebb_table) - || !check_section_ebb_pcrels_fit (abfd, sec, contents, - internal_relocs, - &relevant_relocs, - &ebb_table, reloc_opcodes) - || !check_section_ebb_reduces (&ebb_table)) - { - /* If anything goes wrong or we get unlucky and something does - not fit, with our plan because of expansion between - critical branches, just convert to a NOP. */ - - text_action_add (&relax_info->action_list, - ta_convert_longcall, sec, r_offset, 0); - i = ebb_table.ebb.end_reloc_idx; - free_ebb_constraint (&ebb_table); - continue; - } - - text_action_add_proposed (&relax_info->action_list, &ebb_table, sec); - - /* Update the index so we do not go looking at the relocations - we have already processed. */ - i = ebb_table.ebb.end_reloc_idx; - free_ebb_constraint (&ebb_table); - } - - free_reloc_range_list (&relevant_relocs); - -#if DEBUG - if (action_list_count (&relax_info->action_list)) - print_action_list (stderr, &relax_info->action_list); -#endif - -error_return: - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - if (prop_table) - free (prop_table); - if (reloc_opcodes) - free (reloc_opcodes); - - return ok; -} - - -/* Do not widen an instruction if it is preceeded by a - loop opcode. It might cause misalignment. */ - -static bfd_boolean -prev_instr_is_a_loop (bfd_byte *contents, - bfd_size_type content_length, - bfd_size_type offset) -{ - xtensa_opcode prev_opcode; - - if (offset < 3) - return FALSE; - prev_opcode = insn_decode_opcode (contents, content_length, offset-3, 0); - return (xtensa_opcode_is_loop (xtensa_default_isa, prev_opcode) == 1); -} - - -/* Find all of the possible actions for an extended basic block. */ - -bfd_boolean -compute_ebb_proposed_actions (ebb_constraint *ebb_table) -{ - const ebb_t *ebb = &ebb_table->ebb; - unsigned rel_idx = ebb->start_reloc_idx; - property_table_entry *entry, *start_entry, *end_entry; - bfd_vma offset = 0; - xtensa_isa isa = xtensa_default_isa; - xtensa_format fmt; - static xtensa_insnbuf insnbuf = NULL; - static xtensa_insnbuf slotbuf = NULL; - - if (insnbuf == NULL) - { - insnbuf = xtensa_insnbuf_alloc (isa); - slotbuf = xtensa_insnbuf_alloc (isa); - } - - start_entry = &ebb->ptbl[ebb->start_ptbl_idx]; - end_entry = &ebb->ptbl[ebb->end_ptbl_idx]; - - for (entry = start_entry; entry <= end_entry; entry++) - { - bfd_vma start_offset, end_offset; - bfd_size_type insn_len; - - start_offset = entry->address - ebb->sec->vma; - end_offset = entry->address + entry->size - ebb->sec->vma; - - if (entry == start_entry) - start_offset = ebb->start_offset; - if (entry == end_entry) - end_offset = ebb->end_offset; - offset = start_offset; - - if (offset == entry->address - ebb->sec->vma - && (entry->flags & XTENSA_PROP_INSN_BRANCH_TARGET) != 0) - { - enum ebb_target_enum align_type = EBB_DESIRE_TGT_ALIGN; - BFD_ASSERT (offset != end_offset); - if (offset == end_offset) - return FALSE; - - insn_len = insn_decode_len (ebb->contents, ebb->content_length, - offset); - if (insn_len == 0) - goto decode_error; - - if (check_branch_target_aligned_address (offset, insn_len)) - align_type = EBB_REQUIRE_TGT_ALIGN; - - ebb_propose_action (ebb_table, align_type, 0, - ta_none, offset, 0, TRUE); - } - - while (offset != end_offset) - { - Elf_Internal_Rela *irel; - xtensa_opcode opcode; - - while (rel_idx < ebb->end_reloc_idx - && (ebb->relocs[rel_idx].r_offset < offset - || (ebb->relocs[rel_idx].r_offset == offset - && (ELF32_R_TYPE (ebb->relocs[rel_idx].r_info) - != R_XTENSA_ASM_SIMPLIFY)))) - rel_idx++; - - /* Check for longcall. */ - irel = &ebb->relocs[rel_idx]; - if (irel->r_offset == offset - && ELF32_R_TYPE (irel->r_info) == R_XTENSA_ASM_SIMPLIFY) - { - bfd_size_type simplify_size; - - simplify_size = get_asm_simplify_size (ebb->contents, - ebb->content_length, - irel->r_offset); - if (simplify_size == 0) - goto decode_error; - - ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, - ta_convert_longcall, offset, 0, TRUE); - - offset += simplify_size; - continue; - } - - if (offset + MIN_INSN_LENGTH > ebb->content_length) - goto decode_error; - xtensa_insnbuf_from_chars (isa, insnbuf, &ebb->contents[offset], - ebb->content_length - offset); - fmt = xtensa_format_decode (isa, insnbuf); - if (fmt == XTENSA_UNDEFINED) - goto decode_error; - insn_len = xtensa_format_length (isa, fmt); - if (insn_len == (bfd_size_type) XTENSA_UNDEFINED) - goto decode_error; - - if (xtensa_format_num_slots (isa, fmt) != 1) - { - offset += insn_len; - continue; - } - - xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf); - opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode == XTENSA_UNDEFINED) - goto decode_error; - - if ((entry->flags & XTENSA_PROP_INSN_NO_DENSITY) == 0 - && (entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0 - && can_narrow_instruction (slotbuf, fmt, opcode) != 0) - { - /* Add an instruction narrow action. */ - ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, - ta_narrow_insn, offset, 0, FALSE); - } - else if ((entry->flags & XTENSA_PROP_NO_TRANSFORM) == 0 - && can_widen_instruction (slotbuf, fmt, opcode) != 0 - && ! prev_instr_is_a_loop (ebb->contents, - ebb->content_length, offset)) - { - /* Add an instruction widen action. */ - ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, - ta_widen_insn, offset, 0, FALSE); - } - else if (xtensa_opcode_is_loop (xtensa_default_isa, opcode) == 1) - { - /* Check for branch targets. */ - ebb_propose_action (ebb_table, EBB_REQUIRE_LOOP_ALIGN, 0, - ta_none, offset, 0, TRUE); - } - - offset += insn_len; - } - } - - if (ebb->ends_unreachable) - { - ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, - ta_fill, ebb->end_offset, 0, TRUE); - } - - return TRUE; - - decode_error: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): could not decode instruction; " - "possible configuration mismatch"), - ebb->sec->owner, ebb->sec, offset); - return FALSE; -} - - -/* After all of the information has collected about the - transformations possible in an EBB, compute the appropriate actions - here in compute_ebb_actions. We still must check later to make - sure that the actions do not break any relocations. The algorithm - used here is pretty greedy. Basically, it removes as many no-ops - as possible so that the end of the EBB has the same alignment - characteristics as the original. First, it uses narrowing, then - fill space at the end of the EBB, and finally widenings. If that - does not work, it tries again with one fewer no-op removed. The - optimization will only be performed if all of the branch targets - that were aligned before transformation are also aligned after the - transformation. - - When the size_opt flag is set, ignore the branch target alignments, - narrow all wide instructions, and remove all no-ops unless the end - of the EBB prevents it. */ - -bfd_boolean -compute_ebb_actions (ebb_constraint *ebb_table) -{ - unsigned i = 0; - unsigned j; - int removed_bytes = 0; - ebb_t *ebb = &ebb_table->ebb; - unsigned seg_idx_start = 0; - unsigned seg_idx_end = 0; - - /* We perform this like the assembler relaxation algorithm: Start by - assuming all instructions are narrow and all no-ops removed; then - walk through.... */ - - /* For each segment of this that has a solid constraint, check to - see if there are any combinations that will keep the constraint. - If so, use it. */ - for (seg_idx_end = 0; seg_idx_end < ebb_table->action_count; seg_idx_end++) - { - bfd_boolean requires_text_end_align = FALSE; - unsigned longcall_count = 0; - unsigned longcall_convert_count = 0; - unsigned narrowable_count = 0; - unsigned narrowable_convert_count = 0; - unsigned widenable_count = 0; - unsigned widenable_convert_count = 0; - - proposed_action *action = NULL; - int align = (1 << ebb_table->ebb.sec->alignment_power); - - seg_idx_start = seg_idx_end; - - for (i = seg_idx_start; i < ebb_table->action_count; i++) - { - action = &ebb_table->actions[i]; - if (action->action == ta_convert_longcall) - longcall_count++; - if (action->action == ta_narrow_insn) - narrowable_count++; - if (action->action == ta_widen_insn) - widenable_count++; - if (action->action == ta_fill) - break; - if (action->align_type == EBB_REQUIRE_LOOP_ALIGN) - break; - if (action->align_type == EBB_REQUIRE_TGT_ALIGN - && !elf32xtensa_size_opt) - break; - } - seg_idx_end = i; - - if (seg_idx_end == ebb_table->action_count && !ebb->ends_unreachable) - requires_text_end_align = TRUE; - - if (elf32xtensa_size_opt && !requires_text_end_align - && action->align_type != EBB_REQUIRE_LOOP_ALIGN - && action->align_type != EBB_REQUIRE_TGT_ALIGN) - { - longcall_convert_count = longcall_count; - narrowable_convert_count = narrowable_count; - widenable_convert_count = 0; - } - else - { - /* There is a constraint. Convert the max number of longcalls. */ - narrowable_convert_count = 0; - longcall_convert_count = 0; - widenable_convert_count = 0; - - for (j = 0; j < longcall_count; j++) - { - int removed = (longcall_count - j) * 3 & (align - 1); - unsigned desire_narrow = (align - removed) & (align - 1); - unsigned desire_widen = removed; - if (desire_narrow <= narrowable_count) - { - narrowable_convert_count = desire_narrow; - narrowable_convert_count += - (align * ((narrowable_count - narrowable_convert_count) - / align)); - longcall_convert_count = (longcall_count - j); - widenable_convert_count = 0; - break; - } - if (desire_widen <= widenable_count && !elf32xtensa_size_opt) - { - narrowable_convert_count = 0; - longcall_convert_count = longcall_count - j; - widenable_convert_count = desire_widen; - break; - } - } - } - - /* Now the number of conversions are saved. Do them. */ - for (i = seg_idx_start; i < seg_idx_end; i++) - { - action = &ebb_table->actions[i]; - switch (action->action) - { - case ta_convert_longcall: - if (longcall_convert_count != 0) - { - action->action = ta_remove_longcall; - action->do_action = TRUE; - action->removed_bytes += 3; - longcall_convert_count--; - } - break; - case ta_narrow_insn: - if (narrowable_convert_count != 0) - { - action->do_action = TRUE; - action->removed_bytes += 1; - narrowable_convert_count--; - } - break; - case ta_widen_insn: - if (widenable_convert_count != 0) - { - action->do_action = TRUE; - action->removed_bytes -= 1; - widenable_convert_count--; - } - break; - default: - break; - } - } - } - - /* Now we move on to some local opts. Try to remove each of the - remaining longcalls. */ - - if (ebb_table->ebb.ends_section || ebb_table->ebb.ends_unreachable) - { - removed_bytes = 0; - for (i = 0; i < ebb_table->action_count; i++) - { - int old_removed_bytes = removed_bytes; - proposed_action *action = &ebb_table->actions[i]; - - if (action->do_action && action->action == ta_convert_longcall) - { - bfd_boolean bad_alignment = FALSE; - removed_bytes += 3; - for (j = i + 1; j < ebb_table->action_count; j++) - { - proposed_action *new_action = &ebb_table->actions[j]; - bfd_vma offset = new_action->offset; - if (new_action->align_type == EBB_REQUIRE_TGT_ALIGN) - { - if (!check_branch_target_aligned - (ebb_table->ebb.contents, - ebb_table->ebb.content_length, - offset, offset - removed_bytes)) - { - bad_alignment = TRUE; - break; - } - } - if (new_action->align_type == EBB_REQUIRE_LOOP_ALIGN) - { - if (!check_loop_aligned (ebb_table->ebb.contents, - ebb_table->ebb.content_length, - offset, - offset - removed_bytes)) - { - bad_alignment = TRUE; - break; - } - } - if (new_action->action == ta_narrow_insn - && !new_action->do_action - && ebb_table->ebb.sec->alignment_power == 2) - { - /* Narrow an instruction and we are done. */ - new_action->do_action = TRUE; - new_action->removed_bytes += 1; - bad_alignment = FALSE; - break; - } - if (new_action->action == ta_widen_insn - && new_action->do_action - && ebb_table->ebb.sec->alignment_power == 2) - { - /* Narrow an instruction and we are done. */ - new_action->do_action = FALSE; - new_action->removed_bytes += 1; - bad_alignment = FALSE; - break; - } - if (new_action->do_action) - removed_bytes += new_action->removed_bytes; - } - if (!bad_alignment) - { - action->removed_bytes += 3; - action->action = ta_remove_longcall; - action->do_action = TRUE; - } - } - removed_bytes = old_removed_bytes; - if (action->do_action) - removed_bytes += action->removed_bytes; - } - } - - removed_bytes = 0; - for (i = 0; i < ebb_table->action_count; ++i) - { - proposed_action *action = &ebb_table->actions[i]; - if (action->do_action) - removed_bytes += action->removed_bytes; - } - - if ((removed_bytes % (1 << ebb_table->ebb.sec->alignment_power)) != 0 - && ebb->ends_unreachable) - { - proposed_action *action; - int br; - int extra_space; - - BFD_ASSERT (ebb_table->action_count != 0); - action = &ebb_table->actions[ebb_table->action_count - 1]; - BFD_ASSERT (action->action == ta_fill); - BFD_ASSERT (ebb->ends_unreachable->flags & XTENSA_PROP_UNREACHABLE); - - extra_space = compute_fill_extra_space (ebb->ends_unreachable); - br = action->removed_bytes + removed_bytes + extra_space; - br = br & ((1 << ebb->sec->alignment_power ) - 1); - - action->removed_bytes = extra_space - br; - } - return TRUE; -} - - -/* The xlate_map is a sorted array of address mappings designed to - answer the offset_with_removed_text() query with a binary search instead - of a linear search through the section's action_list. */ - -typedef struct xlate_map_entry xlate_map_entry_t; -typedef struct xlate_map xlate_map_t; - -struct xlate_map_entry -{ - unsigned orig_address; - unsigned new_address; - unsigned size; -}; - -struct xlate_map -{ - unsigned entry_count; - xlate_map_entry_t *entry; -}; - - -static int -xlate_compare (const void *a_v, const void *b_v) -{ - const xlate_map_entry_t *a = (const xlate_map_entry_t *) a_v; - const xlate_map_entry_t *b = (const xlate_map_entry_t *) b_v; - if (a->orig_address < b->orig_address) - return -1; - if (a->orig_address > (b->orig_address + b->size - 1)) - return 1; - return 0; -} - - -static bfd_vma -xlate_offset_with_removed_text (const xlate_map_t *map, - text_action_list *action_list, - bfd_vma offset) -{ - void *r; - xlate_map_entry_t *e; - - if (map == NULL) - return offset_with_removed_text (action_list, offset); - - if (map->entry_count == 0) - return offset; - - r = bsearch (&offset, map->entry, map->entry_count, - sizeof (xlate_map_entry_t), &xlate_compare); - e = (xlate_map_entry_t *) r; - - BFD_ASSERT (e != NULL); - if (e == NULL) - return offset; - return e->new_address - e->orig_address + offset; -} - -typedef struct xlate_map_context_struct xlate_map_context; -struct xlate_map_context_struct -{ - xlate_map_t *map; - xlate_map_entry_t *current_entry; - int removed; -}; - -static int -xlate_map_fn (splay_tree_node node, void *p) -{ - text_action *r = (text_action *)node->value; - xlate_map_context *ctx = p; - unsigned orig_size = 0; - - switch (r->action) - { - case ta_none: - case ta_remove_insn: - case ta_convert_longcall: - case ta_remove_literal: - case ta_add_literal: - break; - case ta_remove_longcall: - orig_size = 6; - break; - case ta_narrow_insn: - orig_size = 3; - break; - case ta_widen_insn: - orig_size = 2; - break; - case ta_fill: - break; - } - ctx->current_entry->size = - r->offset + orig_size - ctx->current_entry->orig_address; - if (ctx->current_entry->size != 0) - { - ctx->current_entry++; - ctx->map->entry_count++; - } - ctx->current_entry->orig_address = r->offset + orig_size; - ctx->removed += r->removed_bytes; - ctx->current_entry->new_address = r->offset + orig_size - ctx->removed; - ctx->current_entry->size = 0; - return 0; -} - -/* Build a binary searchable offset translation map from a section's - action list. */ - -static xlate_map_t * -build_xlate_map (asection *sec, xtensa_relax_info *relax_info) -{ - text_action_list *action_list = &relax_info->action_list; - unsigned num_actions = 0; - xlate_map_context ctx; - - ctx.map = (xlate_map_t *) bfd_malloc (sizeof (xlate_map_t)); - - if (ctx.map == NULL) - return NULL; - - num_actions = action_list_count (action_list); - ctx.map->entry = (xlate_map_entry_t *) - bfd_malloc (sizeof (xlate_map_entry_t) * (num_actions + 1)); - if (ctx.map->entry == NULL) - { - free (ctx.map); - return NULL; - } - ctx.map->entry_count = 0; - - ctx.removed = 0; - ctx.current_entry = &ctx.map->entry[0]; - - ctx.current_entry->orig_address = 0; - ctx.current_entry->new_address = 0; - ctx.current_entry->size = 0; - - splay_tree_foreach (action_list->tree, xlate_map_fn, &ctx); - - ctx.current_entry->size = (bfd_get_section_limit (sec->owner, sec) - - ctx.current_entry->orig_address); - if (ctx.current_entry->size != 0) - ctx.map->entry_count++; - - return ctx.map; -} - - -/* Free an offset translation map. */ - -static void -free_xlate_map (xlate_map_t *map) -{ - if (map && map->entry) - free (map->entry); - if (map) - free (map); -} - - -/* Use check_section_ebb_pcrels_fit to make sure that all of the - relocations in a section will fit if a proposed set of actions - are performed. */ - -static bfd_boolean -check_section_ebb_pcrels_fit (bfd *abfd, - asection *sec, - bfd_byte *contents, - Elf_Internal_Rela *internal_relocs, - reloc_range_list *relevant_relocs, - const ebb_constraint *constraint, - const xtensa_opcode *reloc_opcodes) -{ - unsigned i, j; - unsigned n = sec->reloc_count; - Elf_Internal_Rela *irel; - xlate_map_t *xmap = NULL; - bfd_boolean ok = TRUE; - xtensa_relax_info *relax_info; - reloc_range_list_entry *entry = NULL; - - relax_info = get_xtensa_relax_info (sec); - - if (relax_info && sec->reloc_count > 100) - { - xmap = build_xlate_map (sec, relax_info); - /* NULL indicates out of memory, but the slow version - can still be used. */ - } - - if (relevant_relocs && constraint->action_count) - { - if (!relevant_relocs->ok) - { - ok = FALSE; - n = 0; - } - else - { - bfd_vma min_offset, max_offset; - min_offset = max_offset = constraint->actions[0].offset; - - for (i = 1; i < constraint->action_count; ++i) - { - proposed_action *action = &constraint->actions[i]; - bfd_vma offset = action->offset; - - if (offset < min_offset) - min_offset = offset; - if (offset > max_offset) - max_offset = offset; - } - reloc_range_list_update_range (relevant_relocs, min_offset, - max_offset); - n = relevant_relocs->n_list; - entry = &relevant_relocs->list_root; - } - } - else - { - relevant_relocs = NULL; - } - - for (i = 0; i < n; i++) - { - r_reloc r_rel; - bfd_vma orig_self_offset, orig_target_offset; - bfd_vma self_offset, target_offset; - int r_type; - reloc_howto_type *howto; - int self_removed_bytes, target_removed_bytes; - - if (relevant_relocs) - { - entry = entry->next; - irel = entry->irel; - } - else - { - irel = internal_relocs + i; - } - r_type = ELF32_R_TYPE (irel->r_info); - - howto = &elf_howto_table[r_type]; - /* We maintain the required invariant: PC-relative relocations - that fit before linking must fit after linking. Thus we only - need to deal with relocations to the same section that are - PC-relative. */ - if (r_type == R_XTENSA_ASM_SIMPLIFY - || r_type == R_XTENSA_32_PCREL - || !howto->pc_relative) - continue; - - r_reloc_init (&r_rel, abfd, irel, contents, - bfd_get_section_limit (abfd, sec)); - - if (r_reloc_get_section (&r_rel) != sec) - continue; - - orig_self_offset = irel->r_offset; - orig_target_offset = r_rel.target_offset; - - self_offset = orig_self_offset; - target_offset = orig_target_offset; - - if (relax_info) - { - self_offset = - xlate_offset_with_removed_text (xmap, &relax_info->action_list, - orig_self_offset); - target_offset = - xlate_offset_with_removed_text (xmap, &relax_info->action_list, - orig_target_offset); - } - - self_removed_bytes = 0; - target_removed_bytes = 0; - - for (j = 0; j < constraint->action_count; ++j) - { - proposed_action *action = &constraint->actions[j]; - bfd_vma offset = action->offset; - int removed_bytes = action->removed_bytes; - if (offset < orig_self_offset - || (offset == orig_self_offset && action->action == ta_fill - && action->removed_bytes < 0)) - self_removed_bytes += removed_bytes; - if (offset < orig_target_offset - || (offset == orig_target_offset && action->action == ta_fill - && action->removed_bytes < 0)) - target_removed_bytes += removed_bytes; - } - self_offset -= self_removed_bytes; - target_offset -= target_removed_bytes; - - /* Try to encode it. Get the operand and check. */ - if (is_alt_relocation (ELF32_R_TYPE (irel->r_info))) - { - /* None of the current alternate relocs are PC-relative, - and only PC-relative relocs matter here. */ - } - else - { - xtensa_opcode opcode; - int opnum; - - if (relevant_relocs) - { - opcode = entry->opcode; - opnum = entry->opnum; - } - else - { - if (reloc_opcodes) - opcode = reloc_opcodes[relevant_relocs ? - (unsigned)(entry - relevant_relocs->reloc) : i]; - else - opcode = get_relocation_opcode (abfd, sec, contents, irel); - if (opcode == XTENSA_UNDEFINED) - { - ok = FALSE; - break; - } - - opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info)); - if (opnum == XTENSA_UNDEFINED) - { - ok = FALSE; - break; - } - } - - if (!pcrel_reloc_fits (opcode, opnum, self_offset, target_offset)) - { - ok = FALSE; - break; - } - } - } - - if (xmap) - free_xlate_map (xmap); - - return ok; -} - - -static bfd_boolean -check_section_ebb_reduces (const ebb_constraint *constraint) -{ - int removed = 0; - unsigned i; - - for (i = 0; i < constraint->action_count; i++) - { - const proposed_action *action = &constraint->actions[i]; - if (action->do_action) - removed += action->removed_bytes; - } - if (removed < 0) - return FALSE; - - return TRUE; -} - - -void -text_action_add_proposed (text_action_list *l, - const ebb_constraint *ebb_table, - asection *sec) -{ - unsigned i; - - for (i = 0; i < ebb_table->action_count; i++) - { - proposed_action *action = &ebb_table->actions[i]; - - if (!action->do_action) - continue; - switch (action->action) - { - case ta_remove_insn: - case ta_remove_longcall: - case ta_convert_longcall: - case ta_narrow_insn: - case ta_widen_insn: - case ta_fill: - case ta_remove_literal: - text_action_add (l, action->action, sec, action->offset, - action->removed_bytes); - break; - case ta_none: - break; - default: - BFD_ASSERT (0); - break; - } - } -} - - -int -compute_fill_extra_space (property_table_entry *entry) -{ - int fill_extra_space; - - if (!entry) - return 0; - - if ((entry->flags & XTENSA_PROP_UNREACHABLE) == 0) - return 0; - - fill_extra_space = entry->size; - if ((entry->flags & XTENSA_PROP_ALIGN) != 0) - { - /* Fill bytes for alignment: - (2**n)-1 - (addr + (2**n)-1) & (2**n -1) */ - int pow = GET_XTENSA_PROP_ALIGNMENT (entry->flags); - int nsm = (1 << pow) - 1; - bfd_vma addr = entry->address + entry->size; - bfd_vma align_fill = nsm - ((addr + nsm) & nsm); - fill_extra_space += align_fill; - } - return fill_extra_space; -} - - -/* First relaxation pass. */ - -/* If the section contains relaxable literals, check each literal to - see if it has the same value as another literal that has already - been seen, either in the current section or a previous one. If so, - add an entry to the per-section list of removed literals. The - actual changes are deferred until the next pass. */ - -static bfd_boolean -compute_removed_literals (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - value_map_hash_table *values) -{ - xtensa_relax_info *relax_info; - bfd_byte *contents; - Elf_Internal_Rela *internal_relocs; - source_reloc *src_relocs, *rel; - bfd_boolean ok = TRUE; - property_table_entry *prop_table = NULL; - int ptblsize; - int i, prev_i; - bfd_boolean last_loc_is_prev = FALSE; - bfd_vma last_target_offset = 0; - section_cache_t target_sec_cache; - bfd_size_type sec_size; - - init_section_cache (&target_sec_cache); - - /* Do nothing if it is not a relaxable literal section. */ - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info); - if (!relax_info->is_relaxable_literal_section) - return ok; - - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - - sec_size = bfd_get_section_limit (abfd, sec); - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - { - ok = FALSE; - goto error_return; - } - - /* Sort the source_relocs by target offset. */ - src_relocs = relax_info->src_relocs; - qsort (src_relocs, relax_info->src_count, - sizeof (source_reloc), source_reloc_compare); - qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), - internal_reloc_compare); - - ptblsize = xtensa_read_table_entries (abfd, sec, &prop_table, - XTENSA_PROP_SEC_NAME, FALSE); - if (ptblsize < 0) - { - ok = FALSE; - goto error_return; - } - - prev_i = -1; - for (i = 0; i < relax_info->src_count; i++) - { - Elf_Internal_Rela *irel = NULL; - - rel = &src_relocs[i]; - if (get_l32r_opcode () != rel->opcode) - continue; - irel = get_irel_at_offset (sec, internal_relocs, - rel->r_rel.target_offset); - - /* If the relocation on this is not a simple R_XTENSA_32 or - R_XTENSA_PLT then do not consider it. This may happen when - the difference of two symbols is used in a literal. */ - if (irel && (ELF32_R_TYPE (irel->r_info) != R_XTENSA_32 - && ELF32_R_TYPE (irel->r_info) != R_XTENSA_PLT)) - continue; - - /* If the target_offset for this relocation is the same as the - previous relocation, then we've already considered whether the - literal can be coalesced. Skip to the next one.... */ - if (i != 0 && prev_i != -1 - && src_relocs[i-1].r_rel.target_offset == rel->r_rel.target_offset) - continue; - prev_i = i; - - if (last_loc_is_prev && - last_target_offset + 4 != rel->r_rel.target_offset) - last_loc_is_prev = FALSE; - - /* Check if the relocation was from an L32R that is being removed - because a CALLX was converted to a direct CALL, and check if - there are no other relocations to the literal. */ - if (is_removable_literal (rel, i, src_relocs, relax_info->src_count, - sec, prop_table, ptblsize)) - { - if (!remove_dead_literal (abfd, sec, link_info, internal_relocs, - irel, rel, prop_table, ptblsize)) - { - ok = FALSE; - goto error_return; - } - last_target_offset = rel->r_rel.target_offset; - continue; - } - - if (!identify_literal_placement (abfd, sec, contents, link_info, - values, - &last_loc_is_prev, irel, - relax_info->src_count - i, rel, - prop_table, ptblsize, - &target_sec_cache, rel->is_abs_literal)) - { - ok = FALSE; - goto error_return; - } - last_target_offset = rel->r_rel.target_offset; - } - -#if DEBUG - print_removed_literals (stderr, &relax_info->removed_list); - print_action_list (stderr, &relax_info->action_list); -#endif /* DEBUG */ - -error_return: - if (prop_table) - free (prop_table); - free_section_cache (&target_sec_cache); - - release_contents (sec, contents); - release_internal_relocs (sec, internal_relocs); - return ok; -} - - -static Elf_Internal_Rela * -get_irel_at_offset (asection *sec, - Elf_Internal_Rela *internal_relocs, - bfd_vma offset) -{ - unsigned i; - Elf_Internal_Rela *irel; - unsigned r_type; - Elf_Internal_Rela key; - - if (!internal_relocs) - return NULL; - - key.r_offset = offset; - irel = bsearch (&key, internal_relocs, sec->reloc_count, - sizeof (Elf_Internal_Rela), internal_reloc_matches); - if (!irel) - return NULL; - - /* bsearch does not guarantee which will be returned if there are - multiple matches. We need the first that is not an alignment. */ - i = irel - internal_relocs; - while (i > 0) - { - if (internal_relocs[i-1].r_offset != offset) - break; - i--; - } - for ( ; i < sec->reloc_count; i++) - { - irel = &internal_relocs[i]; - r_type = ELF32_R_TYPE (irel->r_info); - if (irel->r_offset == offset && r_type != R_XTENSA_NONE) - return irel; - } - - return NULL; -} - - -bfd_boolean -is_removable_literal (const source_reloc *rel, - int i, - const source_reloc *src_relocs, - int src_count, - asection *sec, - property_table_entry *prop_table, - int ptblsize) -{ - const source_reloc *curr_rel; - property_table_entry *entry; - - if (!rel->is_null) - return FALSE; - - entry = elf_xtensa_find_property_entry (prop_table, ptblsize, - sec->vma + rel->r_rel.target_offset); - if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM)) - return FALSE; - - for (++i; i < src_count; ++i) - { - curr_rel = &src_relocs[i]; - /* If all others have the same target offset.... */ - if (curr_rel->r_rel.target_offset != rel->r_rel.target_offset) - return TRUE; - - if (!curr_rel->is_null - && !xtensa_is_property_section (curr_rel->source_sec) - && !(curr_rel->source_sec->flags & SEC_DEBUGGING)) - return FALSE; - } - return TRUE; -} - - -bfd_boolean -remove_dead_literal (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - Elf_Internal_Rela *internal_relocs, - Elf_Internal_Rela *irel, - source_reloc *rel, - property_table_entry *prop_table, - int ptblsize) -{ - property_table_entry *entry; - xtensa_relax_info *relax_info; - - relax_info = get_xtensa_relax_info (sec); - if (!relax_info) - return FALSE; - - entry = elf_xtensa_find_property_entry (prop_table, ptblsize, - sec->vma + rel->r_rel.target_offset); - - /* Mark the unused literal so that it will be removed. */ - add_removed_literal (&relax_info->removed_list, &rel->r_rel, NULL); - - text_action_add (&relax_info->action_list, - ta_remove_literal, sec, rel->r_rel.target_offset, 4); - - /* If the section is 4-byte aligned, do not add fill. */ - if (sec->alignment_power > 2) - { - int fill_extra_space; - bfd_vma entry_sec_offset; - text_action *fa; - property_table_entry *the_add_entry; - int removed_diff; - - if (entry) - entry_sec_offset = entry->address - sec->vma + entry->size; - else - entry_sec_offset = rel->r_rel.target_offset + 4; - - /* If the literal range is at the end of the section, - do not add fill. */ - the_add_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, - entry_sec_offset); - fill_extra_space = compute_fill_extra_space (the_add_entry); - - fa = find_fill_action (&relax_info->action_list, sec, entry_sec_offset); - removed_diff = compute_removed_action_diff (fa, sec, entry_sec_offset, - -4, fill_extra_space); - if (fa) - adjust_fill_action (fa, removed_diff); - else - text_action_add (&relax_info->action_list, - ta_fill, sec, entry_sec_offset, removed_diff); - } - - /* Zero out the relocation on this literal location. */ - if (irel) - { - if (elf_hash_table (link_info)->dynamic_sections_created) - shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); - - irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - pin_internal_relocs (sec, internal_relocs); - } - - /* Do not modify "last_loc_is_prev". */ - return TRUE; -} - - -bfd_boolean -identify_literal_placement (bfd *abfd, - asection *sec, - bfd_byte *contents, - struct bfd_link_info *link_info, - value_map_hash_table *values, - bfd_boolean *last_loc_is_prev_p, - Elf_Internal_Rela *irel, - int remaining_src_rels, - source_reloc *rel, - property_table_entry *prop_table, - int ptblsize, - section_cache_t *target_sec_cache, - bfd_boolean is_abs_literal) -{ - literal_value val; - value_map *val_map; - xtensa_relax_info *relax_info; - bfd_boolean literal_placed = FALSE; - r_reloc r_rel; - unsigned long value; - bfd_boolean final_static_link; - bfd_size_type sec_size; - - relax_info = get_xtensa_relax_info (sec); - if (!relax_info) - return FALSE; - - sec_size = bfd_get_section_limit (abfd, sec); - - final_static_link = - (!bfd_link_relocatable (link_info) - && !elf_hash_table (link_info)->dynamic_sections_created); - - /* The placement algorithm first checks to see if the literal is - already in the value map. If so and the value map is reachable - from all uses, then the literal is moved to that location. If - not, then we identify the last location where a fresh literal was - placed. If the literal can be safely moved there, then we do so. - If not, then we assume that the literal is not to move and leave - the literal where it is, marking it as the last literal - location. */ - - /* Find the literal value. */ - value = 0; - r_reloc_init (&r_rel, abfd, irel, contents, sec_size); - if (!irel) - { - BFD_ASSERT (rel->r_rel.target_offset < sec_size); - value = bfd_get_32 (abfd, contents + rel->r_rel.target_offset); - } - init_literal_value (&val, &r_rel, value, is_abs_literal); - - /* Check if we've seen another literal with the same value that - is in the same output section. */ - val_map = value_map_get_cached_value (values, &val, final_static_link); - - if (val_map - && (r_reloc_get_section (&val_map->loc)->output_section - == sec->output_section) - && relocations_reach (rel, remaining_src_rels, &val_map->loc) - && coalesce_shared_literal (sec, rel, prop_table, ptblsize, val_map)) - { - /* No change to last_loc_is_prev. */ - literal_placed = TRUE; - } - - /* For relocatable links, do not try to move literals. To do it - correctly might increase the number of relocations in an input - section making the default relocatable linking fail. */ - if (!bfd_link_relocatable (link_info) && !literal_placed - && values->has_last_loc && !(*last_loc_is_prev_p)) - { - asection *target_sec = r_reloc_get_section (&values->last_loc); - if (target_sec && target_sec->output_section == sec->output_section) - { - /* Increment the virtual offset. */ - r_reloc try_loc = values->last_loc; - try_loc.virtual_offset += 4; - - /* There is a last loc that was in the same output section. */ - if (relocations_reach (rel, remaining_src_rels, &try_loc) - && move_shared_literal (sec, link_info, rel, - prop_table, ptblsize, - &try_loc, &val, target_sec_cache)) - { - values->last_loc.virtual_offset += 4; - literal_placed = TRUE; - if (!val_map) - val_map = add_value_map (values, &val, &try_loc, - final_static_link); - else - val_map->loc = try_loc; - } - } - } - - if (!literal_placed) - { - /* Nothing worked, leave the literal alone but update the last loc. */ - values->has_last_loc = TRUE; - values->last_loc = rel->r_rel; - if (!val_map) - val_map = add_value_map (values, &val, &rel->r_rel, final_static_link); - else - val_map->loc = rel->r_rel; - *last_loc_is_prev_p = TRUE; - } - - return TRUE; -} - - -/* Check if the original relocations (presumably on L32R instructions) - identified by reloc[0..N] can be changed to reference the literal - identified by r_rel. If r_rel is out of range for any of the - original relocations, then we don't want to coalesce the original - literal with the one at r_rel. We only check reloc[0..N], where the - offsets are all the same as for reloc[0] (i.e., they're all - referencing the same literal) and where N is also bounded by the - number of remaining entries in the "reloc" array. The "reloc" array - is sorted by target offset so we know all the entries for the same - literal will be contiguous. */ - -static bfd_boolean -relocations_reach (source_reloc *reloc, - int remaining_relocs, - const r_reloc *r_rel) -{ - bfd_vma from_offset, source_address, dest_address; - asection *sec; - int i; - - if (!r_reloc_is_defined (r_rel)) - return FALSE; - - sec = r_reloc_get_section (r_rel); - from_offset = reloc[0].r_rel.target_offset; - - for (i = 0; i < remaining_relocs; i++) - { - if (reloc[i].r_rel.target_offset != from_offset) - break; - - /* Ignore relocations that have been removed. */ - if (reloc[i].is_null) - continue; - - /* The original and new output section for these must be the same - in order to coalesce. */ - if (r_reloc_get_section (&reloc[i].r_rel)->output_section - != sec->output_section) - return FALSE; - - /* Absolute literals in the same output section can always be - combined. */ - if (reloc[i].is_abs_literal) - continue; - - /* A literal with no PC-relative relocations can be moved anywhere. */ - if (reloc[i].opnd != -1) - { - /* Otherwise, check to see that it fits. */ - source_address = (reloc[i].source_sec->output_section->vma - + reloc[i].source_sec->output_offset - + reloc[i].r_rel.rela.r_offset); - dest_address = (sec->output_section->vma - + sec->output_offset - + r_rel->target_offset); - - if (!pcrel_reloc_fits (reloc[i].opcode, reloc[i].opnd, - source_address, dest_address)) - return FALSE; - } - } - - return TRUE; -} - - -/* Move a literal to another literal location because it is - the same as the other literal value. */ - -static bfd_boolean -coalesce_shared_literal (asection *sec, - source_reloc *rel, - property_table_entry *prop_table, - int ptblsize, - value_map *val_map) -{ - property_table_entry *entry; - text_action *fa; - property_table_entry *the_add_entry; - int removed_diff; - xtensa_relax_info *relax_info; - - relax_info = get_xtensa_relax_info (sec); - if (!relax_info) - return FALSE; - - entry = elf_xtensa_find_property_entry - (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset); - if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM)) - return TRUE; - - /* Mark that the literal will be coalesced. */ - add_removed_literal (&relax_info->removed_list, &rel->r_rel, &val_map->loc); - - text_action_add (&relax_info->action_list, - ta_remove_literal, sec, rel->r_rel.target_offset, 4); - - /* If the section is 4-byte aligned, do not add fill. */ - if (sec->alignment_power > 2) - { - int fill_extra_space; - bfd_vma entry_sec_offset; - - if (entry) - entry_sec_offset = entry->address - sec->vma + entry->size; - else - entry_sec_offset = rel->r_rel.target_offset + 4; - - /* If the literal range is at the end of the section, - do not add fill. */ - fill_extra_space = 0; - the_add_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, - entry_sec_offset); - if (the_add_entry && (the_add_entry->flags & XTENSA_PROP_UNREACHABLE)) - fill_extra_space = the_add_entry->size; - - fa = find_fill_action (&relax_info->action_list, sec, entry_sec_offset); - removed_diff = compute_removed_action_diff (fa, sec, entry_sec_offset, - -4, fill_extra_space); - if (fa) - adjust_fill_action (fa, removed_diff); - else - text_action_add (&relax_info->action_list, - ta_fill, sec, entry_sec_offset, removed_diff); - } - - return TRUE; -} - - -/* Move a literal to another location. This may actually increase the - total amount of space used because of alignments so we need to do - this carefully. Also, it may make a branch go out of range. */ - -static bfd_boolean -move_shared_literal (asection *sec, - struct bfd_link_info *link_info, - source_reloc *rel, - property_table_entry *prop_table, - int ptblsize, - const r_reloc *target_loc, - const literal_value *lit_value, - section_cache_t *target_sec_cache) -{ - property_table_entry *the_add_entry, *src_entry, *target_entry = NULL; - text_action *fa, *target_fa; - int removed_diff; - xtensa_relax_info *relax_info, *target_relax_info; - asection *target_sec; - ebb_t *ebb; - ebb_constraint ebb_table; - bfd_boolean relocs_fit; - - /* If this routine always returns FALSE, the literals that cannot be - coalesced will not be moved. */ - if (elf32xtensa_no_literal_movement) - return FALSE; - - relax_info = get_xtensa_relax_info (sec); - if (!relax_info) - return FALSE; - - target_sec = r_reloc_get_section (target_loc); - target_relax_info = get_xtensa_relax_info (target_sec); - - /* Literals to undefined sections may not be moved because they - must report an error. */ - if (bfd_is_und_section (target_sec)) - return FALSE; - - src_entry = elf_xtensa_find_property_entry - (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset); - - if (!section_cache_section (target_sec_cache, target_sec, link_info)) - return FALSE; - - target_entry = elf_xtensa_find_property_entry - (target_sec_cache->ptbl, target_sec_cache->pte_count, - target_sec->vma + target_loc->target_offset); - - if (!target_entry) - return FALSE; - - /* Make sure that we have not broken any branches. */ - relocs_fit = FALSE; - - init_ebb_constraint (&ebb_table); - ebb = &ebb_table.ebb; - init_ebb (ebb, target_sec_cache->sec, target_sec_cache->contents, - target_sec_cache->content_length, - target_sec_cache->ptbl, target_sec_cache->pte_count, - target_sec_cache->relocs, target_sec_cache->reloc_count); - - /* Propose to add 4 bytes + worst-case alignment size increase to - destination. */ - ebb_propose_action (&ebb_table, EBB_NO_ALIGN, 0, - ta_fill, target_loc->target_offset, - -4 - (1 << target_sec->alignment_power), TRUE); - - /* Check all of the PC-relative relocations to make sure they still fit. */ - relocs_fit = check_section_ebb_pcrels_fit (target_sec->owner, target_sec, - target_sec_cache->contents, - target_sec_cache->relocs, NULL, - &ebb_table, NULL); - - if (!relocs_fit) - return FALSE; - - text_action_add_literal (&target_relax_info->action_list, - ta_add_literal, target_loc, lit_value, -4); - - if (target_sec->alignment_power > 2 && target_entry != src_entry) - { - /* May need to add or remove some fill to maintain alignment. */ - int fill_extra_space; - bfd_vma entry_sec_offset; - - entry_sec_offset = - target_entry->address - target_sec->vma + target_entry->size; - - /* If the literal range is at the end of the section, - do not add fill. */ - fill_extra_space = 0; - the_add_entry = - elf_xtensa_find_property_entry (target_sec_cache->ptbl, - target_sec_cache->pte_count, - entry_sec_offset); - if (the_add_entry && (the_add_entry->flags & XTENSA_PROP_UNREACHABLE)) - fill_extra_space = the_add_entry->size; - - target_fa = find_fill_action (&target_relax_info->action_list, - target_sec, entry_sec_offset); - removed_diff = compute_removed_action_diff (target_fa, target_sec, - entry_sec_offset, 4, - fill_extra_space); - if (target_fa) - adjust_fill_action (target_fa, removed_diff); - else - text_action_add (&target_relax_info->action_list, - ta_fill, target_sec, entry_sec_offset, removed_diff); - } - - /* Mark that the literal will be moved to the new location. */ - add_removed_literal (&relax_info->removed_list, &rel->r_rel, target_loc); - - /* Remove the literal. */ - text_action_add (&relax_info->action_list, - ta_remove_literal, sec, rel->r_rel.target_offset, 4); - - /* If the section is 4-byte aligned, do not add fill. */ - if (sec->alignment_power > 2 && target_entry != src_entry) - { - int fill_extra_space; - bfd_vma entry_sec_offset; - - if (src_entry) - entry_sec_offset = src_entry->address - sec->vma + src_entry->size; - else - entry_sec_offset = rel->r_rel.target_offset+4; - - /* If the literal range is at the end of the section, - do not add fill. */ - fill_extra_space = 0; - the_add_entry = elf_xtensa_find_property_entry (prop_table, ptblsize, - entry_sec_offset); - if (the_add_entry && (the_add_entry->flags & XTENSA_PROP_UNREACHABLE)) - fill_extra_space = the_add_entry->size; - - fa = find_fill_action (&relax_info->action_list, sec, entry_sec_offset); - removed_diff = compute_removed_action_diff (fa, sec, entry_sec_offset, - -4, fill_extra_space); - if (fa) - adjust_fill_action (fa, removed_diff); - else - text_action_add (&relax_info->action_list, - ta_fill, sec, entry_sec_offset, removed_diff); - } - - return TRUE; -} - - -/* Second relaxation pass. */ - -static int -action_remove_bytes_fn (splay_tree_node node, void *p) -{ - bfd_size_type *final_size = p; - text_action *action = (text_action *)node->value; - - *final_size -= action->removed_bytes; - return 0; -} - -/* Modify all of the relocations to point to the right spot, and if this - is a relaxable section, delete the unwanted literals and fix the - section size. */ - -bfd_boolean -relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) -{ - Elf_Internal_Rela *internal_relocs; - xtensa_relax_info *relax_info; - bfd_byte *contents; - bfd_boolean ok = TRUE; - unsigned i; - bfd_boolean rv = FALSE; - bfd_boolean virtual_action; - bfd_size_type sec_size; - - sec_size = bfd_get_section_limit (abfd, sec); - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info); - - /* First translate any of the fixes that have been added already. */ - translate_section_fixes (sec); - - /* Handle property sections (e.g., literal tables) specially. */ - if (xtensa_is_property_section (sec)) - { - BFD_ASSERT (!relax_info->is_relaxable_literal_section); - return relax_property_section (abfd, sec, link_info); - } - - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - if (!internal_relocs && !action_list_count (&relax_info->action_list)) - return TRUE; - - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - { - ok = FALSE; - goto error_return; - } - - if (internal_relocs) - { - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel; - xtensa_relax_info *target_relax_info; - bfd_vma source_offset, old_source_offset; - r_reloc r_rel; - unsigned r_type; - asection *target_sec; - - /* Locally change the source address. - Translate the target to the new target address. - If it points to this section and has been removed, - NULLify it. - Write it back. */ - - irel = &internal_relocs[i]; - source_offset = irel->r_offset; - old_source_offset = source_offset; - - r_type = ELF32_R_TYPE (irel->r_info); - r_reloc_init (&r_rel, abfd, irel, contents, - bfd_get_section_limit (abfd, sec)); - - /* If this section could have changed then we may need to - change the relocation's offset. */ - - if (relax_info->is_relaxable_literal_section - || relax_info->is_relaxable_asm_section) - { - pin_internal_relocs (sec, internal_relocs); - - if (r_type != R_XTENSA_NONE - && find_removed_literal (&relax_info->removed_list, - irel->r_offset)) - { - /* Remove this relocation. */ - if (elf_hash_table (link_info)->dynamic_sections_created) - shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); - irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - irel->r_offset = offset_with_removed_text_map - (&relax_info->action_list, irel->r_offset); - continue; - } - - if (r_type == R_XTENSA_ASM_SIMPLIFY) - { - text_action *action = - find_insn_action (&relax_info->action_list, - irel->r_offset); - if (action && (action->action == ta_convert_longcall - || action->action == ta_remove_longcall)) - { - bfd_reloc_status_type retval; - char *error_message = NULL; - - retval = contract_asm_expansion (contents, sec_size, - irel, &error_message); - if (retval != bfd_reloc_ok) - { - (*link_info->callbacks->reloc_dangerous) - (link_info, error_message, abfd, sec, - irel->r_offset); - goto error_return; - } - /* Update the action so that the code that moves - the contents will do the right thing. */ - /* ta_remove_longcall and ta_remove_insn actions are - grouped together in the tree as well as - ta_convert_longcall and ta_none, so that changes below - can be done w/o removing and reinserting action into - the tree. */ - - if (action->action == ta_remove_longcall) - action->action = ta_remove_insn; - else - action->action = ta_none; - /* Refresh the info in the r_rel. */ - r_reloc_init (&r_rel, abfd, irel, contents, sec_size); - r_type = ELF32_R_TYPE (irel->r_info); - } - } - - source_offset = offset_with_removed_text_map - (&relax_info->action_list, irel->r_offset); - irel->r_offset = source_offset; - } - - /* If the target section could have changed then - we may need to change the relocation's target offset. */ - - target_sec = r_reloc_get_section (&r_rel); - - /* For a reference to a discarded section from a DWARF section, - i.e., where action_discarded is PRETEND, the symbol will - eventually be modified to refer to the kept section (at least if - the kept and discarded sections are the same size). Anticipate - that here and adjust things accordingly. */ - if (! elf_xtensa_ignore_discarded_relocs (sec) - && elf_xtensa_action_discarded (sec) == PRETEND - && sec->sec_info_type != SEC_INFO_TYPE_STABS - && target_sec != NULL - && discarded_section (target_sec)) - { - /* It would be natural to call _bfd_elf_check_kept_section - here, but it's not exported from elflink.c. It's also a - fairly expensive check. Adjusting the relocations to the - discarded section is fairly harmless; it will only adjust - some addends and difference values. If it turns out that - _bfd_elf_check_kept_section fails later, it won't matter, - so just compare the section names to find the right group - member. */ - asection *kept = target_sec->kept_section; - if (kept != NULL) - { - if ((kept->flags & SEC_GROUP) != 0) - { - asection *first = elf_next_in_group (kept); - asection *s = first; - - kept = NULL; - while (s != NULL) - { - if (strcmp (s->name, target_sec->name) == 0) - { - kept = s; - break; - } - s = elf_next_in_group (s); - if (s == first) - break; - } - } - } - if (kept != NULL - && ((target_sec->rawsize != 0 - ? target_sec->rawsize : target_sec->size) - == (kept->rawsize != 0 ? kept->rawsize : kept->size))) - target_sec = kept; - } - - target_relax_info = get_xtensa_relax_info (target_sec); - if (target_relax_info - && (target_relax_info->is_relaxable_literal_section - || target_relax_info->is_relaxable_asm_section)) - { - r_reloc new_reloc; - target_sec = translate_reloc (&r_rel, &new_reloc, target_sec); - - if (r_type == R_XTENSA_DIFF8 - || r_type == R_XTENSA_DIFF16 - || r_type == R_XTENSA_DIFF32) - { - bfd_signed_vma diff_value = 0; - bfd_vma new_end_offset, diff_mask = 0; - - if (bfd_get_section_limit (abfd, sec) < old_source_offset) - { - (*link_info->callbacks->reloc_dangerous) - (link_info, _("invalid relocation address"), - abfd, sec, old_source_offset); - goto error_return; - } - - switch (r_type) - { - case R_XTENSA_DIFF8: - diff_value = - bfd_get_signed_8 (abfd, &contents[old_source_offset]); - break; - case R_XTENSA_DIFF16: - diff_value = - bfd_get_signed_16 (abfd, &contents[old_source_offset]); - break; - case R_XTENSA_DIFF32: - diff_value = - bfd_get_signed_32 (abfd, &contents[old_source_offset]); - break; - } - - new_end_offset = offset_with_removed_text_map - (&target_relax_info->action_list, - r_rel.target_offset + diff_value); - diff_value = new_end_offset - new_reloc.target_offset; - - switch (r_type) - { - case R_XTENSA_DIFF8: - diff_mask = 0x7f; - bfd_put_signed_8 (abfd, diff_value, - &contents[old_source_offset]); - break; - case R_XTENSA_DIFF16: - diff_mask = 0x7fff; - bfd_put_signed_16 (abfd, diff_value, - &contents[old_source_offset]); - break; - case R_XTENSA_DIFF32: - diff_mask = 0x7fffffff; - bfd_put_signed_32 (abfd, diff_value, - &contents[old_source_offset]); - break; - } - - /* Check for overflow. Sign bits must be all zeroes or all ones */ - if ((diff_value & ~diff_mask) != 0 && - (diff_value & ~diff_mask) != (-1 & ~diff_mask)) - { - (*link_info->callbacks->reloc_dangerous) - (link_info, _("overflow after relaxation"), - abfd, sec, old_source_offset); - goto error_return; - } - - pin_contents (sec, contents); - } - - /* If the relocation still references a section in the same - input file, modify the relocation directly instead of - adding a "fix" record. */ - if (target_sec->owner == abfd) - { - unsigned r_symndx = ELF32_R_SYM (new_reloc.rela.r_info); - irel->r_info = ELF32_R_INFO (r_symndx, r_type); - irel->r_addend = new_reloc.rela.r_addend; - pin_internal_relocs (sec, internal_relocs); - } - else - { - bfd_vma addend_displacement; - reloc_bfd_fix *fix; - - addend_displacement = - new_reloc.target_offset + new_reloc.virtual_offset; - fix = reloc_bfd_fix_init (sec, source_offset, r_type, - target_sec, - addend_displacement, TRUE); - add_fix (sec, fix); - } - } - } - } - - if ((relax_info->is_relaxable_literal_section - || relax_info->is_relaxable_asm_section) - && action_list_count (&relax_info->action_list)) - { - /* Walk through the planned actions and build up a table - of move, copy and fill records. Use the move, copy and - fill records to perform the actions once. */ - - bfd_size_type final_size, copy_size, orig_insn_size; - bfd_byte *scratch = NULL; - bfd_byte *dup_contents = NULL; - bfd_size_type orig_size = sec->size; - bfd_vma orig_dot = 0; - bfd_vma orig_dot_copied = 0; /* Byte copied already from - orig dot in physical memory. */ - bfd_vma orig_dot_vo = 0; /* Virtual offset from orig_dot. */ - bfd_vma dup_dot = 0; - - text_action *action; - - final_size = sec->size; - - splay_tree_foreach (relax_info->action_list.tree, - action_remove_bytes_fn, &final_size); - scratch = (bfd_byte *) bfd_zmalloc (final_size); - dup_contents = (bfd_byte *) bfd_zmalloc (final_size); - - /* The dot is the current fill location. */ -#if DEBUG - print_action_list (stderr, &relax_info->action_list); -#endif - - for (action = action_first (&relax_info->action_list); action; - action = action_next (&relax_info->action_list, action)) - { - virtual_action = FALSE; - if (action->offset > orig_dot) - { - orig_dot += orig_dot_copied; - orig_dot_copied = 0; - orig_dot_vo = 0; - /* Out of the virtual world. */ - } - - if (action->offset > orig_dot) - { - copy_size = action->offset - orig_dot; - memmove (&dup_contents[dup_dot], &contents[orig_dot], copy_size); - orig_dot += copy_size; - dup_dot += copy_size; - BFD_ASSERT (action->offset == orig_dot); - } - else if (action->offset < orig_dot) - { - if (action->action == ta_fill - && action->offset - action->removed_bytes == orig_dot) - { - /* This is OK because the fill only effects the dup_dot. */ - } - else if (action->action == ta_add_literal) - { - /* TBD. Might need to handle this. */ - } - } - if (action->offset == orig_dot) - { - if (action->virtual_offset > orig_dot_vo) - { - if (orig_dot_vo == 0) - { - /* Need to copy virtual_offset bytes. Probably four. */ - copy_size = action->virtual_offset - orig_dot_vo; - memmove (&dup_contents[dup_dot], - &contents[orig_dot], copy_size); - orig_dot_copied = copy_size; - dup_dot += copy_size; - } - virtual_action = TRUE; - } - else - BFD_ASSERT (action->virtual_offset <= orig_dot_vo); - } - switch (action->action) - { - case ta_remove_literal: - case ta_remove_insn: - BFD_ASSERT (action->removed_bytes >= 0); - orig_dot += action->removed_bytes; - break; - - case ta_narrow_insn: - orig_insn_size = 3; - copy_size = 2; - memmove (scratch, &contents[orig_dot], orig_insn_size); - BFD_ASSERT (action->removed_bytes == 1); - rv = narrow_instruction (scratch, final_size, 0); - BFD_ASSERT (rv); - memmove (&dup_contents[dup_dot], scratch, copy_size); - orig_dot += orig_insn_size; - dup_dot += copy_size; - break; - - case ta_fill: - if (action->removed_bytes >= 0) - orig_dot += action->removed_bytes; - else - { - /* Already zeroed in dup_contents. Just bump the - counters. */ - dup_dot += (-action->removed_bytes); - } - break; - - case ta_none: - BFD_ASSERT (action->removed_bytes == 0); - break; - - case ta_convert_longcall: - case ta_remove_longcall: - /* These will be removed or converted before we get here. */ - BFD_ASSERT (0); - break; - - case ta_widen_insn: - orig_insn_size = 2; - copy_size = 3; - memmove (scratch, &contents[orig_dot], orig_insn_size); - BFD_ASSERT (action->removed_bytes == -1); - rv = widen_instruction (scratch, final_size, 0); - BFD_ASSERT (rv); - memmove (&dup_contents[dup_dot], scratch, copy_size); - orig_dot += orig_insn_size; - dup_dot += copy_size; - break; - - case ta_add_literal: - orig_insn_size = 0; - copy_size = 4; - BFD_ASSERT (action->removed_bytes == -4); - /* TBD -- place the literal value here and insert - into the table. */ - memset (&dup_contents[dup_dot], 0, 4); - pin_internal_relocs (sec, internal_relocs); - pin_contents (sec, contents); - - if (!move_literal (abfd, link_info, sec, dup_dot, dup_contents, - relax_info, &internal_relocs, &action->value)) - goto error_return; - - if (virtual_action) - orig_dot_vo += copy_size; - - orig_dot += orig_insn_size; - dup_dot += copy_size; - break; - - default: - /* Not implemented yet. */ - BFD_ASSERT (0); - break; - } - - BFD_ASSERT (dup_dot <= final_size); - BFD_ASSERT (orig_dot <= orig_size); - } - - orig_dot += orig_dot_copied; - orig_dot_copied = 0; - - if (orig_dot != orig_size) - { - copy_size = orig_size - orig_dot; - BFD_ASSERT (orig_size > orig_dot); - BFD_ASSERT (dup_dot + copy_size == final_size); - memmove (&dup_contents[dup_dot], &contents[orig_dot], copy_size); - orig_dot += copy_size; - dup_dot += copy_size; - } - BFD_ASSERT (orig_size == orig_dot); - BFD_ASSERT (final_size == dup_dot); - - /* Move the dup_contents back. */ - if (final_size > orig_size) - { - /* Contents need to be reallocated. Swap the dup_contents into - contents. */ - sec->contents = dup_contents; - free (contents); - contents = dup_contents; - pin_contents (sec, contents); - } - else - { - BFD_ASSERT (final_size <= orig_size); - memset (contents, 0, orig_size); - memcpy (contents, dup_contents, final_size); - free (dup_contents); - } - free (scratch); - pin_contents (sec, contents); - - if (sec->rawsize == 0) - sec->rawsize = sec->size; - sec->size = final_size; - } - - error_return: - release_internal_relocs (sec, internal_relocs); - release_contents (sec, contents); - return ok; -} - - -static bfd_boolean -translate_section_fixes (asection *sec) -{ - xtensa_relax_info *relax_info; - reloc_bfd_fix *r; - - relax_info = get_xtensa_relax_info (sec); - if (!relax_info) - return TRUE; - - for (r = relax_info->fix_list; r != NULL; r = r->next) - if (!translate_reloc_bfd_fix (r)) - return FALSE; - - return TRUE; -} - - -/* Translate a fix given the mapping in the relax info for the target - section. If it has already been translated, no work is required. */ - -static bfd_boolean -translate_reloc_bfd_fix (reloc_bfd_fix *fix) -{ - reloc_bfd_fix new_fix; - asection *sec; - xtensa_relax_info *relax_info; - removed_literal *removed; - bfd_vma new_offset, target_offset; - - if (fix->translated) - return TRUE; - - sec = fix->target_sec; - target_offset = fix->target_offset; - - relax_info = get_xtensa_relax_info (sec); - if (!relax_info) - { - fix->translated = TRUE; - return TRUE; - } - - new_fix = *fix; - - /* The fix does not need to be translated if the section cannot change. */ - if (!relax_info->is_relaxable_literal_section - && !relax_info->is_relaxable_asm_section) - { - fix->translated = TRUE; - return TRUE; - } - - /* If the literal has been moved and this relocation was on an - opcode, then the relocation should move to the new literal - location. Otherwise, the relocation should move within the - section. */ - - removed = FALSE; - if (is_operand_relocation (fix->src_type)) - { - /* Check if the original relocation is against a literal being - removed. */ - removed = find_removed_literal (&relax_info->removed_list, - target_offset); - } - - if (removed) - { - asection *new_sec; - - /* The fact that there is still a relocation to this literal indicates - that the literal is being coalesced, not simply removed. */ - BFD_ASSERT (removed->to.abfd != NULL); - - /* This was moved to some other address (possibly another section). */ - new_sec = r_reloc_get_section (&removed->to); - if (new_sec != sec) - { - sec = new_sec; - relax_info = get_xtensa_relax_info (sec); - if (!relax_info || - (!relax_info->is_relaxable_literal_section - && !relax_info->is_relaxable_asm_section)) - { - target_offset = removed->to.target_offset; - new_fix.target_sec = new_sec; - new_fix.target_offset = target_offset; - new_fix.translated = TRUE; - *fix = new_fix; - return TRUE; - } - } - target_offset = removed->to.target_offset; - new_fix.target_sec = new_sec; - } - - /* The target address may have been moved within its section. */ - new_offset = offset_with_removed_text (&relax_info->action_list, - target_offset); - - new_fix.target_offset = new_offset; - new_fix.target_offset = new_offset; - new_fix.translated = TRUE; - *fix = new_fix; - return TRUE; -} - - -/* Fix up a relocation to take account of removed literals. */ - -static asection * -translate_reloc (const r_reloc *orig_rel, r_reloc *new_rel, asection *sec) -{ - xtensa_relax_info *relax_info; - removed_literal *removed; - bfd_vma target_offset, base_offset; - - *new_rel = *orig_rel; - - if (!r_reloc_is_defined (orig_rel)) - return sec ; - - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info && (relax_info->is_relaxable_literal_section - || relax_info->is_relaxable_asm_section)); - - target_offset = orig_rel->target_offset; - - removed = FALSE; - if (is_operand_relocation (ELF32_R_TYPE (orig_rel->rela.r_info))) - { - /* Check if the original relocation is against a literal being - removed. */ - removed = find_removed_literal (&relax_info->removed_list, - target_offset); - } - if (removed && removed->to.abfd) - { - asection *new_sec; - - /* The fact that there is still a relocation to this literal indicates - that the literal is being coalesced, not simply removed. */ - BFD_ASSERT (removed->to.abfd != NULL); - - /* This was moved to some other address - (possibly in another section). */ - *new_rel = removed->to; - new_sec = r_reloc_get_section (new_rel); - if (new_sec != sec) - { - sec = new_sec; - relax_info = get_xtensa_relax_info (sec); - if (!relax_info - || (!relax_info->is_relaxable_literal_section - && !relax_info->is_relaxable_asm_section)) - return sec; - } - target_offset = new_rel->target_offset; - } - - /* Find the base offset of the reloc symbol, excluding any addend from the - reloc or from the section contents (for a partial_inplace reloc). Then - find the adjusted values of the offsets due to relaxation. The base - offset is needed to determine the change to the reloc's addend; the reloc - addend should not be adjusted due to relaxations located before the base - offset. */ - - base_offset = r_reloc_get_target_offset (new_rel) - new_rel->rela.r_addend; - if (base_offset <= target_offset) - { - int base_removed = removed_by_actions_map (&relax_info->action_list, - base_offset, FALSE); - int addend_removed = removed_by_actions_map (&relax_info->action_list, - target_offset, FALSE) - - base_removed; - - new_rel->target_offset = target_offset - base_removed - addend_removed; - new_rel->rela.r_addend -= addend_removed; - } - else - { - /* Handle a negative addend. The base offset comes first. */ - int tgt_removed = removed_by_actions_map (&relax_info->action_list, - target_offset, FALSE); - int addend_removed = removed_by_actions_map (&relax_info->action_list, - base_offset, FALSE) - - tgt_removed; - - new_rel->target_offset = target_offset - tgt_removed; - new_rel->rela.r_addend += addend_removed; - } - - return sec; -} - - -/* For dynamic links, there may be a dynamic relocation for each - literal. The number of dynamic relocations must be computed in - size_dynamic_sections, which occurs before relaxation. When a - literal is removed, this function checks if there is a corresponding - dynamic relocation and shrinks the size of the appropriate dynamic - relocation section accordingly. At this point, the contents of the - dynamic relocation sections have not yet been filled in, so there's - nothing else that needs to be done. */ - -static void -shrink_dynamic_reloc_sections (struct bfd_link_info *info, - bfd *abfd, - asection *input_section, - Elf_Internal_Rela *rel) -{ - struct elf_xtensa_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - unsigned long r_symndx; - int r_type; - struct elf_link_hash_entry *h; - bfd_boolean dynamic_symbol; - - htab = elf_xtensa_hash_table (info); - if (htab == NULL) - return; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - r_type = ELF32_R_TYPE (rel->r_info); - r_symndx = ELF32_R_SYM (rel->r_info); - - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info); - - if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT) - && (input_section->flags & SEC_ALLOC) != 0 - && (dynamic_symbol || bfd_link_pic (info))) - { - asection *srel; - bfd_boolean is_plt = FALSE; - - if (dynamic_symbol && r_type == R_XTENSA_PLT) - { - srel = htab->elf.srelplt; - is_plt = TRUE; - } - else - srel = htab->elf.srelgot; - - /* Reduce size of the .rela.* section by one reloc. */ - BFD_ASSERT (srel != NULL); - BFD_ASSERT (srel->size >= sizeof (Elf32_External_Rela)); - srel->size -= sizeof (Elf32_External_Rela); - - if (is_plt) - { - asection *splt, *sgotplt, *srelgot; - int reloc_index, chunk; - - /* Find the PLT reloc index of the entry being removed. This - is computed from the size of ".rela.plt". It is needed to - figure out which PLT chunk to resize. Usually "last index - = size - 1" since the index starts at zero, but in this - context, the size has just been decremented so there's no - need to subtract one. */ - reloc_index = srel->size / sizeof (Elf32_External_Rela); - - chunk = reloc_index / PLT_ENTRIES_PER_CHUNK; - splt = elf_xtensa_get_plt_section (info, chunk); - sgotplt = elf_xtensa_get_gotplt_section (info, chunk); - BFD_ASSERT (splt != NULL && sgotplt != NULL); - - /* Check if an entire PLT chunk has just been eliminated. */ - if (reloc_index % PLT_ENTRIES_PER_CHUNK == 0) - { - /* The two magic GOT entries for that chunk can go away. */ - srelgot = htab->elf.srelgot; - BFD_ASSERT (srelgot != NULL); - srelgot->reloc_count -= 2; - srelgot->size -= 2 * sizeof (Elf32_External_Rela); - sgotplt->size -= 8; - - /* There should be only one entry left (and it will be - removed below). */ - BFD_ASSERT (sgotplt->size == 4); - BFD_ASSERT (splt->size == PLT_ENTRY_SIZE); - } - - BFD_ASSERT (sgotplt->size >= 4); - BFD_ASSERT (splt->size >= PLT_ENTRY_SIZE); - - sgotplt->size -= 4; - splt->size -= PLT_ENTRY_SIZE; - } - } -} - - -/* Take an r_rel and move it to another section. This usually - requires extending the interal_relocation array and pinning it. If - the original r_rel is from the same BFD, we can complete this here. - Otherwise, we add a fix record to let the final link fix the - appropriate address. Contents and internal relocations for the - section must be pinned after calling this routine. */ - -static bfd_boolean -move_literal (bfd *abfd, - struct bfd_link_info *link_info, - asection *sec, - bfd_vma offset, - bfd_byte *contents, - xtensa_relax_info *relax_info, - Elf_Internal_Rela **internal_relocs_p, - const literal_value *lit) -{ - Elf_Internal_Rela *new_relocs = NULL; - size_t new_relocs_count = 0; - Elf_Internal_Rela this_rela; - const r_reloc *r_rel; - - r_rel = &lit->r_rel; - BFD_ASSERT (elf_section_data (sec)->relocs == *internal_relocs_p); - - if (r_reloc_is_const (r_rel)) - bfd_put_32 (abfd, lit->value, contents + offset); - else - { - int r_type; - unsigned i; - reloc_bfd_fix *fix; - unsigned insert_at; - - r_type = ELF32_R_TYPE (r_rel->rela.r_info); - - /* This is the difficult case. We have to create a fix up. */ - this_rela.r_offset = offset; - this_rela.r_info = ELF32_R_INFO (0, r_type); - this_rela.r_addend = - r_rel->target_offset - r_reloc_get_target_offset (r_rel); - bfd_put_32 (abfd, lit->value, contents + offset); - - /* Currently, we cannot move relocations during a relocatable link. */ - BFD_ASSERT (!bfd_link_relocatable (link_info)); - fix = reloc_bfd_fix_init (sec, offset, r_type, - r_reloc_get_section (r_rel), - r_rel->target_offset + r_rel->virtual_offset, - FALSE); - /* We also need to mark that relocations are needed here. */ - sec->flags |= SEC_RELOC; - - translate_reloc_bfd_fix (fix); - /* This fix has not yet been translated. */ - add_fix (sec, fix); - - /* Add the relocation. If we have already allocated our own - space for the relocations and we have room for more, then use - it. Otherwise, allocate new space and move the literals. */ - insert_at = sec->reloc_count; - for (i = 0; i < sec->reloc_count; ++i) - { - if (this_rela.r_offset < (*internal_relocs_p)[i].r_offset) - { - insert_at = i; - break; - } - } - - if (*internal_relocs_p != relax_info->allocated_relocs - || sec->reloc_count + 1 > relax_info->allocated_relocs_count) - { - BFD_ASSERT (relax_info->allocated_relocs == NULL - || sec->reloc_count == relax_info->relocs_count); - - if (relax_info->allocated_relocs_count == 0) - new_relocs_count = (sec->reloc_count + 2) * 2; - else - new_relocs_count = (relax_info->allocated_relocs_count + 2) * 2; - - new_relocs = (Elf_Internal_Rela *) - bfd_zmalloc (sizeof (Elf_Internal_Rela) * (new_relocs_count)); - if (!new_relocs) - return FALSE; - - /* We could handle this more quickly by finding the split point. */ - if (insert_at != 0) - memcpy (new_relocs, *internal_relocs_p, - insert_at * sizeof (Elf_Internal_Rela)); - - new_relocs[insert_at] = this_rela; - - if (insert_at != sec->reloc_count) - memcpy (new_relocs + insert_at + 1, - (*internal_relocs_p) + insert_at, - (sec->reloc_count - insert_at) - * sizeof (Elf_Internal_Rela)); - - if (*internal_relocs_p != relax_info->allocated_relocs) - { - /* The first time we re-allocate, we can only free the - old relocs if they were allocated with bfd_malloc. - This is not true when keep_memory is in effect. */ - if (!link_info->keep_memory) - free (*internal_relocs_p); - } - else - free (*internal_relocs_p); - relax_info->allocated_relocs = new_relocs; - relax_info->allocated_relocs_count = new_relocs_count; - elf_section_data (sec)->relocs = new_relocs; - sec->reloc_count++; - relax_info->relocs_count = sec->reloc_count; - *internal_relocs_p = new_relocs; - } - else - { - if (insert_at != sec->reloc_count) - { - unsigned idx; - for (idx = sec->reloc_count; idx > insert_at; idx--) - (*internal_relocs_p)[idx] = (*internal_relocs_p)[idx-1]; - } - (*internal_relocs_p)[insert_at] = this_rela; - sec->reloc_count++; - if (relax_info->allocated_relocs) - relax_info->relocs_count = sec->reloc_count; - } - } - return TRUE; -} - - -/* This is similar to relax_section except that when a target is moved, - we shift addresses up. We also need to modify the size. This - algorithm does NOT allow for relocations into the middle of the - property sections. */ - -static bfd_boolean -relax_property_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info) -{ - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents; - unsigned i; - bfd_boolean ok = TRUE; - bfd_boolean is_full_prop_section; - size_t last_zfill_target_offset = 0; - asection *last_zfill_target_sec = NULL; - bfd_size_type sec_size; - bfd_size_type entry_size; - - sec_size = bfd_get_section_limit (abfd, sec); - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - { - ok = FALSE; - goto error_return; - } - - is_full_prop_section = xtensa_is_proptable_section (sec); - if (is_full_prop_section) - entry_size = 12; - else - entry_size = 8; - - if (internal_relocs) - { - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel; - xtensa_relax_info *target_relax_info; - unsigned r_type; - asection *target_sec; - literal_value val; - bfd_byte *size_p, *flags_p; - - /* Locally change the source address. - Translate the target to the new target address. - If it points to this section and has been removed, MOVE IT. - Also, don't forget to modify the associated SIZE at - (offset + 4). */ - - irel = &internal_relocs[i]; - r_type = ELF32_R_TYPE (irel->r_info); - if (r_type == R_XTENSA_NONE) - continue; - - /* Find the literal value. */ - r_reloc_init (&val.r_rel, abfd, irel, contents, sec_size); - size_p = &contents[irel->r_offset + 4]; - flags_p = NULL; - if (is_full_prop_section) - flags_p = &contents[irel->r_offset + 8]; - BFD_ASSERT (irel->r_offset + entry_size <= sec_size); - - target_sec = r_reloc_get_section (&val.r_rel); - target_relax_info = get_xtensa_relax_info (target_sec); - - if (target_relax_info - && (target_relax_info->is_relaxable_literal_section - || target_relax_info->is_relaxable_asm_section )) - { - /* Translate the relocation's destination. */ - bfd_vma old_offset = val.r_rel.target_offset; - bfd_vma new_offset; - long old_size, new_size; - int removed_by_old_offset = - removed_by_actions_map (&target_relax_info->action_list, - old_offset, FALSE); - new_offset = old_offset - removed_by_old_offset; - - /* Assert that we are not out of bounds. */ - old_size = bfd_get_32 (abfd, size_p); - new_size = old_size; - - if (old_size == 0) - { - /* Only the first zero-sized unreachable entry is - allowed to expand. In this case the new offset - should be the offset before the fill and the new - size is the expansion size. For other zero-sized - entries the resulting size should be zero with an - offset before or after the fill address depending - on whether the expanding unreachable entry - preceeds it. */ - if (last_zfill_target_sec == 0 - || last_zfill_target_sec != target_sec - || last_zfill_target_offset != old_offset) - { - bfd_vma new_end_offset = new_offset; - - /* Recompute the new_offset, but this time don't - include any fill inserted by relaxation. */ - removed_by_old_offset = - removed_by_actions_map (&target_relax_info->action_list, - old_offset, TRUE); - new_offset = old_offset - removed_by_old_offset; - - /* If it is not unreachable and we have not yet - seen an unreachable at this address, place it - before the fill address. */ - if (flags_p && (bfd_get_32 (abfd, flags_p) - & XTENSA_PROP_UNREACHABLE) != 0) - { - new_size = new_end_offset - new_offset; - - last_zfill_target_sec = target_sec; - last_zfill_target_offset = old_offset; - } - } - } - else - { - int removed_by_old_offset_size = - removed_by_actions_map (&target_relax_info->action_list, - old_offset + old_size, TRUE); - new_size -= removed_by_old_offset_size - removed_by_old_offset; - } - - if (new_size != old_size) - { - bfd_put_32 (abfd, new_size, size_p); - pin_contents (sec, contents); - } - - if (new_offset != old_offset) - { - bfd_vma diff = new_offset - old_offset; - irel->r_addend += diff; - pin_internal_relocs (sec, internal_relocs); - } - } - } - } - - /* Combine adjacent property table entries. This is also done in - finish_dynamic_sections() but at that point it's too late to - reclaim the space in the output section, so we do this twice. */ - - if (internal_relocs && (!bfd_link_relocatable (link_info) - || xtensa_is_littable_section (sec))) - { - Elf_Internal_Rela *last_irel = NULL; - Elf_Internal_Rela *irel, *next_rel, *rel_end; - int removed_bytes = 0; - bfd_vma offset; - flagword predef_flags; - - predef_flags = xtensa_get_property_predef_flags (sec); - - /* Walk over memory and relocations at the same time. - This REQUIRES that the internal_relocs be sorted by offset. */ - qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), - internal_reloc_compare); - - pin_internal_relocs (sec, internal_relocs); - pin_contents (sec, contents); - - next_rel = internal_relocs; - rel_end = internal_relocs + sec->reloc_count; - - BFD_ASSERT (sec->size % entry_size == 0); - - for (offset = 0; offset < sec->size; offset += entry_size) - { - Elf_Internal_Rela *offset_rel, *extra_rel; - bfd_vma bytes_to_remove, size, actual_offset; - bfd_boolean remove_this_rel; - flagword flags; - - /* Find the first relocation for the entry at the current offset. - Adjust the offsets of any extra relocations for the previous - entry. */ - offset_rel = NULL; - if (next_rel) - { - for (irel = next_rel; irel < rel_end; irel++) - { - if ((irel->r_offset == offset - && ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE) - || irel->r_offset > offset) - { - offset_rel = irel; - break; - } - irel->r_offset -= removed_bytes; - } - } - - /* Find the next relocation (if there are any left). */ - extra_rel = NULL; - if (offset_rel) - { - for (irel = offset_rel + 1; irel < rel_end; irel++) - { - if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE) - { - extra_rel = irel; - break; - } - } - } - - /* Check if there are relocations on the current entry. There - should usually be a relocation on the offset field. If there - are relocations on the size or flags, then we can't optimize - this entry. Also, find the next relocation to examine on the - next iteration. */ - if (offset_rel) - { - if (offset_rel->r_offset >= offset + entry_size) - { - next_rel = offset_rel; - /* There are no relocations on the current entry, but we - might still be able to remove it if the size is zero. */ - offset_rel = NULL; - } - else if (offset_rel->r_offset > offset - || (extra_rel - && extra_rel->r_offset < offset + entry_size)) - { - /* There is a relocation on the size or flags, so we can't - do anything with this entry. Continue with the next. */ - next_rel = offset_rel; - continue; - } - else - { - BFD_ASSERT (offset_rel->r_offset == offset); - offset_rel->r_offset -= removed_bytes; - next_rel = offset_rel + 1; - } - } - else - next_rel = NULL; - - remove_this_rel = FALSE; - bytes_to_remove = 0; - actual_offset = offset - removed_bytes; - size = bfd_get_32 (abfd, &contents[actual_offset + 4]); - - if (is_full_prop_section) - flags = bfd_get_32 (abfd, &contents[actual_offset + 8]); - else - flags = predef_flags; - - if (size == 0 - && (flags & XTENSA_PROP_ALIGN) == 0 - && (flags & XTENSA_PROP_UNREACHABLE) == 0) - { - /* Always remove entries with zero size and no alignment. */ - bytes_to_remove = entry_size; - if (offset_rel) - remove_this_rel = TRUE; - } - else if (offset_rel - && ELF32_R_TYPE (offset_rel->r_info) == R_XTENSA_32) - { - if (last_irel) - { - flagword old_flags; - bfd_vma old_size = - bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]); - bfd_vma old_address = - (last_irel->r_addend - + bfd_get_32 (abfd, &contents[last_irel->r_offset])); - bfd_vma new_address = - (offset_rel->r_addend - + bfd_get_32 (abfd, &contents[actual_offset])); - if (is_full_prop_section) - old_flags = bfd_get_32 - (abfd, &contents[last_irel->r_offset + 8]); - else - old_flags = predef_flags; - - if ((ELF32_R_SYM (offset_rel->r_info) - == ELF32_R_SYM (last_irel->r_info)) - && old_address + old_size == new_address - && old_flags == flags - && (old_flags & XTENSA_PROP_INSN_BRANCH_TARGET) == 0 - && (old_flags & XTENSA_PROP_INSN_LOOP_TARGET) == 0) - { - /* Fix the old size. */ - bfd_put_32 (abfd, old_size + size, - &contents[last_irel->r_offset + 4]); - bytes_to_remove = entry_size; - remove_this_rel = TRUE; - } - else - last_irel = offset_rel; - } - else - last_irel = offset_rel; - } - - if (remove_this_rel) - { - offset_rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - offset_rel->r_offset = 0; - } - - if (bytes_to_remove != 0) - { - removed_bytes += bytes_to_remove; - if (offset + bytes_to_remove < sec->size) - memmove (&contents[actual_offset], - &contents[actual_offset + bytes_to_remove], - sec->size - offset - bytes_to_remove); - } - } - - if (removed_bytes) - { - /* Fix up any extra relocations on the last entry. */ - for (irel = next_rel; irel < rel_end; irel++) - irel->r_offset -= removed_bytes; - - /* Clear the removed bytes. */ - memset (&contents[sec->size - removed_bytes], 0, removed_bytes); - - if (sec->rawsize == 0) - sec->rawsize = sec->size; - sec->size -= removed_bytes; - - if (xtensa_is_littable_section (sec)) - { - asection *sgotloc = elf_xtensa_hash_table (link_info)->sgotloc; - if (sgotloc) - sgotloc->size -= removed_bytes; - } - } - } - - error_return: - release_internal_relocs (sec, internal_relocs); - release_contents (sec, contents); - return ok; -} - - -/* Third relaxation pass. */ - -/* Change symbol values to account for removed literals. */ - -bfd_boolean -relax_section_symbols (bfd *abfd, asection *sec) -{ - xtensa_relax_info *relax_info; - unsigned int sec_shndx; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *isymbuf; - unsigned i, num_syms, num_locals; - - relax_info = get_xtensa_relax_info (sec); - BFD_ASSERT (relax_info); - - if (!relax_info->is_relaxable_literal_section - && !relax_info->is_relaxable_asm_section) - return TRUE; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - isymbuf = retrieve_local_syms (abfd); - - num_syms = symtab_hdr->sh_size / sizeof (Elf32_External_Sym); - num_locals = symtab_hdr->sh_info; - - /* Adjust the local symbols defined in this section. */ - for (i = 0; i < num_locals; i++) - { - Elf_Internal_Sym *isym = &isymbuf[i]; - - if (isym->st_shndx == sec_shndx) - { - bfd_vma orig_addr = isym->st_value; - int removed = removed_by_actions_map (&relax_info->action_list, - orig_addr, FALSE); - - isym->st_value -= removed; - if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC) - isym->st_size -= - removed_by_actions_map (&relax_info->action_list, - orig_addr + isym->st_size, FALSE) - - removed; - } - } - - /* Now adjust the global symbols defined in this section. */ - for (i = 0; i < (num_syms - num_locals); i++) - { - struct elf_link_hash_entry *sym_hash; - - sym_hash = elf_sym_hashes (abfd)[i]; - - if (sym_hash->root.type == bfd_link_hash_warning) - sym_hash = (struct elf_link_hash_entry *) sym_hash->root.u.i.link; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec) - { - bfd_vma orig_addr = sym_hash->root.u.def.value; - int removed = removed_by_actions_map (&relax_info->action_list, - orig_addr, FALSE); - - sym_hash->root.u.def.value -= removed; - - if (sym_hash->type == STT_FUNC) - sym_hash->size -= - removed_by_actions_map (&relax_info->action_list, - orig_addr + sym_hash->size, FALSE) - - removed; - } - } - - return TRUE; -} - - -/* "Fix" handling functions, called while performing relocations. */ - -static bfd_boolean -do_fix_for_relocatable_link (Elf_Internal_Rela *rel, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents) -{ - r_reloc r_rel; - asection *sec, *old_sec; - bfd_vma old_offset; - int r_type = ELF32_R_TYPE (rel->r_info); - reloc_bfd_fix *fix; - - if (r_type == R_XTENSA_NONE) - return TRUE; - - fix = get_bfd_fix (input_section, rel->r_offset, r_type); - if (!fix) - return TRUE; - - r_reloc_init (&r_rel, input_bfd, rel, contents, - bfd_get_section_limit (input_bfd, input_section)); - old_sec = r_reloc_get_section (&r_rel); - old_offset = r_rel.target_offset; - - if (!old_sec || !r_reloc_is_defined (&r_rel)) - { - if (r_type != R_XTENSA_ASM_EXPAND) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unexpected fix for %s relocation"), - input_bfd, input_section, rel->r_offset, - elf_howto_table[r_type].name); - return FALSE; - } - /* Leave it be. Resolution will happen in a later stage. */ - } - else - { - sec = fix->target_sec; - rel->r_addend += ((sec->output_offset + fix->target_offset) - - (old_sec->output_offset + old_offset)); - } - return TRUE; -} - - -static void -do_fix_for_final_link (Elf_Internal_Rela *rel, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - bfd_vma *relocationp) -{ - asection *sec; - int r_type = ELF32_R_TYPE (rel->r_info); - reloc_bfd_fix *fix; - bfd_vma fixup_diff; - - if (r_type == R_XTENSA_NONE) - return; - - fix = get_bfd_fix (input_section, rel->r_offset, r_type); - if (!fix) - return; - - sec = fix->target_sec; - - fixup_diff = rel->r_addend; - if (elf_howto_table[fix->src_type].partial_inplace) - { - bfd_vma inplace_val; - BFD_ASSERT (fix->src_offset - < bfd_get_section_limit (input_bfd, input_section)); - inplace_val = bfd_get_32 (input_bfd, &contents[fix->src_offset]); - fixup_diff += inplace_val; - } - - *relocationp = (sec->output_section->vma - + sec->output_offset - + fix->target_offset - fixup_diff); -} - - -/* Miscellaneous utility functions.... */ - -static asection * -elf_xtensa_get_plt_section (struct bfd_link_info *info, int chunk) -{ - bfd *dynobj; - char plt_name[17]; - - if (chunk == 0) - return elf_hash_table (info)->splt; - - dynobj = elf_hash_table (info)->dynobj; - sprintf (plt_name, ".plt.%u", chunk); - return bfd_get_linker_section (dynobj, plt_name); -} - - -static asection * -elf_xtensa_get_gotplt_section (struct bfd_link_info *info, int chunk) -{ - bfd *dynobj; - char got_name[21]; - - if (chunk == 0) - return elf_hash_table (info)->sgotplt; - - dynobj = elf_hash_table (info)->dynobj; - sprintf (got_name, ".got.plt.%u", chunk); - return bfd_get_linker_section (dynobj, got_name); -} - - -/* Get the input section for a given symbol index. - If the symbol is: - . a section symbol, return the section; - . a common symbol, return the common section; - . an undefined symbol, return the undefined section; - . an indirect symbol, follow the links; - . an absolute value, return the absolute section. */ - -static asection * -get_elf_r_symndx_section (bfd *abfd, unsigned long r_symndx) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - asection *target_sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isymbuf; - unsigned int section_index; - - isymbuf = retrieve_local_syms (abfd); - section_index = isymbuf[r_symndx].st_shndx; - - if (section_index == SHN_UNDEF) - target_sec = bfd_und_section_ptr; - else if (section_index == SHN_ABS) - target_sec = bfd_abs_section_ptr; - else if (section_index == SHN_COMMON) - target_sec = bfd_com_section_ptr; - else - target_sec = bfd_section_from_elf_index (abfd, section_index); - } - else - { - unsigned long indx = r_symndx - symtab_hdr->sh_info; - struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - target_sec = h->root.u.def.section; - break; - case bfd_link_hash_common: - target_sec = bfd_com_section_ptr; - break; - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - target_sec = bfd_und_section_ptr; - break; - default: /* New indirect warning. */ - target_sec = bfd_und_section_ptr; - break; - } - } - return target_sec; -} - - -static struct elf_link_hash_entry * -get_elf_r_symndx_hash_entry (bfd *abfd, unsigned long r_symndx) -{ - unsigned long indx; - struct elf_link_hash_entry *h; - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - if (r_symndx < symtab_hdr->sh_info) - return NULL; - - indx = r_symndx - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - 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; - return h; -} - - -/* Get the section-relative offset for a symbol number. */ - -static bfd_vma -get_elf_r_symndx_offset (bfd *abfd, unsigned long r_symndx) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - bfd_vma offset = 0; - - if (r_symndx < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isymbuf; - isymbuf = retrieve_local_syms (abfd); - offset = isymbuf[r_symndx].st_value; - } - else - { - unsigned long indx = r_symndx - symtab_hdr->sh_info; - struct elf_link_hash_entry *h = - elf_sym_hashes (abfd)[indx]; - - 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) - offset = h->root.u.def.value; - } - return offset; -} - - -static bfd_boolean -is_reloc_sym_weak (bfd *abfd, Elf_Internal_Rela *rel) -{ - unsigned long r_symndx = ELF32_R_SYM (rel->r_info); - struct elf_link_hash_entry *h; - - h = get_elf_r_symndx_hash_entry (abfd, r_symndx); - if (h && h->root.type == bfd_link_hash_defweak) - return TRUE; - return FALSE; -} - - -static bfd_boolean -pcrel_reloc_fits (xtensa_opcode opc, - int opnd, - bfd_vma self_address, - bfd_vma dest_address) -{ - xtensa_isa isa = xtensa_default_isa; - uint32 valp = dest_address; - if (xtensa_operand_do_reloc (isa, opc, opnd, &valp, self_address) - || xtensa_operand_encode (isa, opc, opnd, &valp)) - return FALSE; - return TRUE; -} - - -static bfd_boolean -xtensa_is_property_section (asection *sec) -{ - if (xtensa_is_insntable_section (sec) - || xtensa_is_littable_section (sec) - || xtensa_is_proptable_section (sec)) - return TRUE; - - return FALSE; -} - - -static bfd_boolean -xtensa_is_insntable_section (asection *sec) -{ - if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME) - || CONST_STRNEQ (sec->name, ".gnu.linkonce.x.")) - return TRUE; - - return FALSE; -} - - -static bfd_boolean -xtensa_is_littable_section (asection *sec) -{ - if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME) - || CONST_STRNEQ (sec->name, ".gnu.linkonce.p.")) - return TRUE; - - return FALSE; -} - - -static bfd_boolean -xtensa_is_proptable_section (asection *sec) -{ - if (CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME) - || CONST_STRNEQ (sec->name, ".gnu.linkonce.prop.")) - return TRUE; - - return FALSE; -} - - -static int -internal_reloc_compare (const void *ap, const void *bp) -{ - const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap; - const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp; - - if (a->r_offset != b->r_offset) - return (a->r_offset - b->r_offset); - - /* We don't need to sort on these criteria for correctness, - but enforcing a more strict ordering prevents unstable qsort - from behaving differently with different implementations. - Without the code below we get correct but different results - on Solaris 2.7 and 2.8. We would like to always produce the - same results no matter the host. */ - - if (a->r_info != b->r_info) - return (a->r_info - b->r_info); - - return (a->r_addend - b->r_addend); -} - - -static int -internal_reloc_matches (const void *ap, const void *bp) -{ - const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap; - const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp; - - /* Check if one entry overlaps with the other; this shouldn't happen - except when searching for a match. */ - return (a->r_offset - b->r_offset); -} - - -/* Predicate function used to look up a section in a particular group. */ - -static bfd_boolean -match_section_group (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)); -} - - -static int linkonce_len = sizeof (".gnu.linkonce.") - 1; - -static char * -xtensa_property_section_name (asection *sec, const char *base_name) -{ - const char *suffix, *group_name; - char *prop_sec_name; - - group_name = elf_group_name (sec); - if (group_name) - { - suffix = strrchr (sec->name, '.'); - if (suffix == sec->name) - suffix = 0; - prop_sec_name = (char *) bfd_malloc (strlen (base_name) + 1 - + (suffix ? strlen (suffix) : 0)); - strcpy (prop_sec_name, base_name); - if (suffix) - strcat (prop_sec_name, suffix); - } - else if (strncmp (sec->name, ".gnu.linkonce.", linkonce_len) == 0) - { - char *linkonce_kind = 0; - - if (strcmp (base_name, XTENSA_INSN_SEC_NAME) == 0) - linkonce_kind = "x."; - else if (strcmp (base_name, XTENSA_LIT_SEC_NAME) == 0) - linkonce_kind = "p."; - else if (strcmp (base_name, XTENSA_PROP_SEC_NAME) == 0) - linkonce_kind = "prop."; - else - abort (); - - prop_sec_name = (char *) bfd_malloc (strlen (sec->name) - + strlen (linkonce_kind) + 1); - memcpy (prop_sec_name, ".gnu.linkonce.", linkonce_len); - strcpy (prop_sec_name + linkonce_len, linkonce_kind); - - suffix = sec->name + linkonce_len; - /* For backward compatibility, replace "t." instead of inserting - the new linkonce_kind (but not for "prop" sections). */ - if (CONST_STRNEQ (suffix, "t.") && linkonce_kind[1] == '.') - suffix += 2; - strcat (prop_sec_name + linkonce_len, suffix); - } - else - prop_sec_name = strdup (base_name); - - return prop_sec_name; -} - - -static asection * -xtensa_get_property_section (asection *sec, const char *base_name) -{ - char *prop_sec_name; - asection *prop_sec; - - prop_sec_name = xtensa_property_section_name (sec, base_name); - prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name, - match_section_group, - (void *) elf_group_name (sec)); - free (prop_sec_name); - return prop_sec; -} - - -asection * -xtensa_make_property_section (asection *sec, const char *base_name) -{ - char *prop_sec_name; - asection *prop_sec; - - /* Check if the section already exists. */ - prop_sec_name = xtensa_property_section_name (sec, base_name); - prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name, - match_section_group, - (void *) elf_group_name (sec)); - /* If not, create it. */ - if (! prop_sec) - { - flagword flags = (SEC_RELOC | SEC_HAS_CONTENTS | SEC_READONLY); - flags |= (bfd_get_section_flags (sec->owner, sec) - & (SEC_LINK_ONCE | SEC_LINK_DUPLICATES)); - - prop_sec = bfd_make_section_anyway_with_flags - (sec->owner, strdup (prop_sec_name), flags); - if (! prop_sec) - return 0; - - elf_group_name (prop_sec) = elf_group_name (sec); - } - - free (prop_sec_name); - return prop_sec; -} - - -flagword -xtensa_get_property_predef_flags (asection *sec) -{ - if (xtensa_is_insntable_section (sec)) - return (XTENSA_PROP_INSN - | XTENSA_PROP_NO_TRANSFORM - | XTENSA_PROP_INSN_NO_REORDER); - - if (xtensa_is_littable_section (sec)) - return (XTENSA_PROP_LITERAL - | XTENSA_PROP_NO_TRANSFORM - | XTENSA_PROP_INSN_NO_REORDER); - - return 0; -} - - -/* Other functions called directly by the linker. */ - -bfd_boolean -xtensa_callback_required_dependence (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - deps_callback_t callback, - void *closure) -{ - Elf_Internal_Rela *internal_relocs; - bfd_byte *contents; - unsigned i; - bfd_boolean ok = TRUE; - bfd_size_type sec_size; - - sec_size = bfd_get_section_limit (abfd, sec); - - /* ".plt*" sections have no explicit relocations but they contain L32R - instructions that reference the corresponding ".got.plt*" sections. */ - if ((sec->flags & SEC_LINKER_CREATED) != 0 - && CONST_STRNEQ (sec->name, ".plt")) - { - asection *sgotplt; - - /* Find the corresponding ".got.plt*" section. */ - if (sec->name[4] == '\0') - sgotplt = elf_hash_table (link_info)->sgotplt; - else - { - char got_name[14]; - int chunk = 0; - - BFD_ASSERT (sec->name[4] == '.'); - chunk = strtol (&sec->name[5], NULL, 10); - - sprintf (got_name, ".got.plt.%u", chunk); - sgotplt = bfd_get_linker_section (sec->owner, got_name); - } - BFD_ASSERT (sgotplt); - - /* Assume worst-case offsets: L32R at the very end of the ".plt" - section referencing a literal at the very beginning of - ".got.plt". This is very close to the real dependence, anyway. */ - (*callback) (sec, sec_size, sgotplt, 0, closure); - } - - /* Only ELF files are supported for Xtensa. Check here to avoid a segfault - when building uclibc, which runs "ld -b binary /dev/null". */ - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - return ok; - - internal_relocs = retrieve_internal_relocs (abfd, sec, - link_info->keep_memory); - if (internal_relocs == NULL - || sec->reloc_count == 0) - return ok; - - /* Cache the contents for the duration of this scan. */ - contents = retrieve_contents (abfd, sec, link_info->keep_memory); - if (contents == NULL && sec_size != 0) - { - ok = FALSE; - goto error_return; - } - - if (!xtensa_default_isa) - xtensa_default_isa = xtensa_isa_init (0, 0); - - for (i = 0; i < sec->reloc_count; i++) - { - Elf_Internal_Rela *irel = &internal_relocs[i]; - if (is_l32r_relocation (abfd, sec, contents, irel)) - { - r_reloc l32r_rel; - asection *target_sec; - bfd_vma target_offset; - - r_reloc_init (&l32r_rel, abfd, irel, contents, sec_size); - target_sec = NULL; - target_offset = 0; - /* L32Rs must be local to the input file. */ - if (r_reloc_is_defined (&l32r_rel)) - { - target_sec = r_reloc_get_section (&l32r_rel); - target_offset = l32r_rel.target_offset; - } - (*callback) (sec, irel->r_offset, target_sec, target_offset, - closure); - } - } - - error_return: - release_internal_relocs (sec, internal_relocs); - release_contents (sec, contents); - return ok; -} - -/* The default literal sections should always be marked as "code" (i.e., - SHF_EXECINSTR). This is particularly important for the Linux kernel - module loader so that the literals are not placed after the text. */ -static const struct bfd_elf_special_section elf_xtensa_special_sections[] = -{ - { STRING_COMMA_LEN (".fini.literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".init.literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".literal"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { STRING_COMMA_LEN (".xtensa.info"), 0, SHT_NOTE, 0 }, - { NULL, 0, 0, 0, 0 } -}; - -#define ELF_TARGET_ID XTENSA_ELF_DATA -#ifndef ELF_ARCH -#define TARGET_LITTLE_SYM xtensa_elf32_le_vec -#define TARGET_LITTLE_NAME "elf32-xtensa-le" -#define TARGET_BIG_SYM xtensa_elf32_be_vec -#define TARGET_BIG_NAME "elf32-xtensa-be" -#define ELF_ARCH bfd_arch_xtensa - -#define ELF_MACHINE_CODE EM_XTENSA -#define ELF_MACHINE_ALT1 EM_XTENSA_OLD - -#define ELF_MAXPAGESIZE 0x1000 -#endif /* ELF_ARCH */ - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_plt_readonly 1 -#define elf_backend_got_header_size 4 -#define elf_backend_want_dynbss 0 -#define elf_backend_want_got_plt 1 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_info_to_howto elf_xtensa_info_to_howto_rela - -#define bfd_elf32_mkobject elf_xtensa_mkobject - -#define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data -#define bfd_elf32_new_section_hook elf_xtensa_new_section_hook -#define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data -#define bfd_elf32_bfd_relax_section elf_xtensa_relax_section -#define bfd_elf32_bfd_reloc_type_lookup elf_xtensa_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - elf_xtensa_reloc_name_lookup -#define bfd_elf32_bfd_set_private_flags elf_xtensa_set_private_flags -#define bfd_elf32_bfd_link_hash_table_create elf_xtensa_link_hash_table_create - -#define elf_backend_adjust_dynamic_symbol elf_xtensa_adjust_dynamic_symbol -#define elf_backend_check_relocs elf_xtensa_check_relocs -#define elf_backend_create_dynamic_sections elf_xtensa_create_dynamic_sections -#define elf_backend_discard_info elf_xtensa_discard_info -#define elf_backend_ignore_discarded_relocs elf_xtensa_ignore_discarded_relocs -#define elf_backend_final_write_processing elf_xtensa_final_write_processing -#define elf_backend_finish_dynamic_sections elf_xtensa_finish_dynamic_sections -#define elf_backend_finish_dynamic_symbol elf_xtensa_finish_dynamic_symbol -#define elf_backend_gc_mark_hook elf_xtensa_gc_mark_hook -#define elf_backend_grok_prstatus elf_xtensa_grok_prstatus -#define elf_backend_grok_psinfo elf_xtensa_grok_psinfo -#define elf_backend_hide_symbol elf_xtensa_hide_symbol -#define elf_backend_object_p elf_xtensa_object_p -#define elf_backend_reloc_type_class elf_xtensa_reloc_type_class -#define elf_backend_relocate_section elf_xtensa_relocate_section -#define elf_backend_size_dynamic_sections elf_xtensa_size_dynamic_sections -#define elf_backend_always_size_sections elf_xtensa_always_size_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_special_sections elf_xtensa_special_sections -#define elf_backend_action_discarded elf_xtensa_action_discarded -#define elf_backend_copy_indirect_symbol elf_xtensa_copy_indirect_symbol - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf32.c b/sdcc/support/sdbinutils/bfd/elf32.c deleted file mode 100644 index 03edd48da..000000000 --- a/sdcc/support/sdbinutils/bfd/elf32.c +++ /dev/null @@ -1,23 +0,0 @@ -/* ELF 32-bit executable support for BFD. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define ARCH_SIZE 32 - -#include "elfcode.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-alpha.c b/sdcc/support/sdbinutils/bfd/elf64-alpha.c deleted file mode 100644 index db4001cce..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-alpha.c +++ /dev/null @@ -1,5567 +0,0 @@ -/* Alpha specific support for 64-bit ELF - Copyright (C) 1996-2018 Free Software Foundation, Inc. - Contributed by Richard Henderson . - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* We need a published ABI spec for this. Until one comes out, don't - assume this'll remain unchanged forever. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -#include "elf/alpha.h" - -#define ALPHAECOFF - -#define NO_COFF_RELOCS -#define NO_COFF_SYMBOLS -#define NO_COFF_LINENOS - -/* Get the ECOFF swapping routines. Needed for the debug information. */ -#include "coff/internal.h" -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/ecoff.h" -#include "coff/alpha.h" -#include "aout/ar.h" -#include "libcoff.h" -#include "libecoff.h" -#define ECOFF_64 -#include "ecoffswap.h" - - -/* Instruction data for plt generation and relaxation. */ - -#define OP_LDA 0x08 -#define OP_LDAH 0x09 -#define OP_LDQ 0x29 -#define OP_BR 0x30 -#define OP_BSR 0x34 - -#define INSN_LDA (OP_LDA << 26) -#define INSN_LDAH (OP_LDAH << 26) -#define INSN_LDQ (OP_LDQ << 26) -#define INSN_BR (OP_BR << 26) - -#define INSN_ADDQ 0x40000400 -#define INSN_RDUNIQ 0x0000009e -#define INSN_SUBQ 0x40000520 -#define INSN_S4SUBQ 0x40000560 -#define INSN_UNOP 0x2ffe0000 - -#define INSN_JSR 0x68004000 -#define INSN_JMP 0x68000000 -#define INSN_JSR_MASK 0xfc00c000 - -#define INSN_A(I,A) (I | (A << 21)) -#define INSN_AB(I,A,B) (I | (A << 21) | (B << 16)) -#define INSN_ABC(I,A,B,C) (I | (A << 21) | (B << 16) | C) -#define INSN_ABO(I,A,B,O) (I | (A << 21) | (B << 16) | ((O) & 0xffff)) -#define INSN_AD(I,A,D) (I | (A << 21) | (((D) >> 2) & 0x1fffff)) - -/* PLT/GOT Stuff */ - -/* Set by ld emulation. Putting this into the link_info or hash structure - is simply working too hard. */ -#ifdef USE_SECUREPLT -bfd_boolean elf64_alpha_use_secureplt = TRUE; -#else -bfd_boolean elf64_alpha_use_secureplt = FALSE; -#endif - -#define OLD_PLT_HEADER_SIZE 32 -#define OLD_PLT_ENTRY_SIZE 12 -#define NEW_PLT_HEADER_SIZE 36 -#define NEW_PLT_ENTRY_SIZE 4 - -#define PLT_HEADER_SIZE \ - (elf64_alpha_use_secureplt ? NEW_PLT_HEADER_SIZE : OLD_PLT_HEADER_SIZE) -#define PLT_ENTRY_SIZE \ - (elf64_alpha_use_secureplt ? NEW_PLT_ENTRY_SIZE : OLD_PLT_ENTRY_SIZE) - -#define MAX_GOT_SIZE (64*1024) - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so" - - -/* Used to implement multiple .got subsections. */ -struct alpha_elf_got_entry -{ - struct alpha_elf_got_entry *next; - - /* Which .got subsection? */ - bfd *gotobj; - - /* The addend in effect for this entry. */ - bfd_vma addend; - - /* The .got offset for this entry. */ - int got_offset; - - /* The .plt offset for this entry. */ - int plt_offset; - - /* How many references to this entry? */ - int use_count; - - /* The relocation type of this entry. */ - unsigned char reloc_type; - - /* How a LITERAL is used. */ - unsigned char flags; - - /* Have we initialized the dynamic relocation for this entry? */ - unsigned char reloc_done; - - /* Have we adjusted this entry for SEC_MERGE? */ - unsigned char reloc_xlated; -}; - -struct alpha_elf_reloc_entry -{ - struct alpha_elf_reloc_entry *next; - - /* Which .reloc section? */ - asection *srel; - - /* What kind of relocation? */ - unsigned int rtype; - - /* Is this against read-only section? */ - unsigned int reltext : 1; - - /* How many did we find? */ - unsigned long count; -}; - -struct alpha_elf_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* External symbol information. */ - EXTR esym; - - /* Cumulative flags for all the .got entries. */ - int flags; - - /* Contexts in which a literal was referenced. */ -#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01 -#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02 -#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04 -#define ALPHA_ELF_LINK_HASH_LU_JSR 0x08 -#define ALPHA_ELF_LINK_HASH_LU_TLSGD 0x10 -#define ALPHA_ELF_LINK_HASH_LU_TLSLDM 0x20 -#define ALPHA_ELF_LINK_HASH_LU_JSRDIRECT 0x40 -#define ALPHA_ELF_LINK_HASH_LU_PLT 0x38 -#define ALPHA_ELF_LINK_HASH_TLS_IE 0x80 - - /* Used to implement multiple .got subsections. */ - struct alpha_elf_got_entry *got_entries; - - /* Used to count non-got, non-plt relocations for delayed sizing - of relocation sections. */ - struct alpha_elf_reloc_entry *reloc_entries; -}; - -/* Alpha ELF linker hash table. */ - -struct alpha_elf_link_hash_table -{ - struct elf_link_hash_table root; - - /* The head of a list of .got subsections linked through - alpha_elf_tdata(abfd)->got_link_next. */ - bfd *got_list; - - /* The most recent relax pass that we've seen. The GOTs - should be regenerated if this doesn't match. */ - int relax_trip; -}; - -/* Look up an entry in a Alpha ELF linker hash table. */ - -#define alpha_elf_link_hash_lookup(table, string, create, copy, follow) \ - ((struct alpha_elf_link_hash_entry *) \ - elf_link_hash_lookup (&(table)->root, (string), (create), \ - (copy), (follow))) - -/* Traverse a Alpha ELF linker hash table. */ - -#define alpha_elf_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -/* Get the Alpha ELF linker hash table from a link_info structure. */ - -#define alpha_elf_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == ALPHA_ELF_DATA ? ((struct alpha_elf_link_hash_table *) ((p)->hash)) : NULL) - -/* Get the object's symbols as our own entry type. */ - -#define alpha_elf_sym_hashes(abfd) \ - ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd)) - -/* Should we do dynamic things to this symbol? This differs from the - generic version in that we never need to consider function pointer - equality wrt PLT entries -- we don't create a PLT entry if a symbol's - address is ever taken. */ - -static inline bfd_boolean -alpha_elf_dynamic_symbol_p (struct elf_link_hash_entry *h, - struct bfd_link_info *info) -{ - return _bfd_elf_dynamic_symbol_p (h, info, 0); -} - -/* Create an entry in a Alpha ELF linker hash table. */ - -static struct bfd_hash_entry * -elf64_alpha_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct alpha_elf_link_hash_entry *ret = - (struct alpha_elf_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct alpha_elf_link_hash_entry *) NULL) - ret = ((struct alpha_elf_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct alpha_elf_link_hash_entry))); - if (ret == (struct alpha_elf_link_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct alpha_elf_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != (struct alpha_elf_link_hash_entry *) NULL) - { - /* Set local fields. */ - memset (&ret->esym, 0, sizeof (EXTR)); - /* We use -2 as a marker to indicate that the information has - not been set. -1 means there is no associated ifd. */ - ret->esym.ifd = -2; - ret->flags = 0; - ret->got_entries = NULL; - ret->reloc_entries = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create a Alpha ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf64_alpha_bfd_link_hash_table_create (bfd *abfd) -{ - struct alpha_elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct alpha_elf_link_hash_table); - - ret = (struct alpha_elf_link_hash_table *) bfd_zmalloc (amt); - if (ret == (struct alpha_elf_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - elf64_alpha_link_hash_newfunc, - sizeof (struct alpha_elf_link_hash_entry), - ALPHA_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -/* Alpha ELF follows MIPS ELF in using a special find_nearest_line - routine in order to handle the ECOFF debugging information. */ - -struct alpha_elf_find_line -{ - struct ecoff_debug_info d; - struct ecoff_find_line i; -}; - -/* We have some private fields hanging off of the elf_tdata structure. */ - -struct alpha_elf_obj_tdata -{ - struct elf_obj_tdata root; - - /* For every input file, these are the got entries for that object's - local symbols. */ - struct alpha_elf_got_entry ** local_got_entries; - - /* For every input file, this is the object that owns the got that - this input file uses. */ - bfd *gotobj; - - /* For every got, this is a linked list through the objects using this got */ - bfd *in_got_link_next; - - /* For every got, this is a link to the next got subsegment. */ - bfd *got_link_next; - - /* For every got, this is the section. */ - asection *got; - - /* For every got, this is it's total number of words. */ - int total_got_size; - - /* For every got, this is the sum of the number of words required - to hold all of the member object's local got. */ - int local_got_size; - - /* Used by elf64_alpha_find_nearest_line entry point. */ - struct alpha_elf_find_line *find_line_info; - -}; - -#define alpha_elf_tdata(abfd) \ - ((struct alpha_elf_obj_tdata *) (abfd)->tdata.any) - -#define is_alpha_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == ALPHA_ELF_DATA) - -static bfd_boolean -elf64_alpha_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct alpha_elf_obj_tdata), - ALPHA_ELF_DATA); -} - -static bfd_boolean -elf64_alpha_object_p (bfd *abfd) -{ - /* Set the right machine number for an Alpha ELF file. */ - return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0); -} - -/* A relocation function which doesn't do anything. */ - -static bfd_reloc_status_type -elf64_alpha_reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc, - asymbol *sym ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, asection *sec, - bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd) - reloc->address += sec->output_offset; - return bfd_reloc_ok; -} - -/* A relocation function used for an unsupported reloc. */ - -static bfd_reloc_status_type -elf64_alpha_reloc_bad (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc, - asymbol *sym ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, asection *sec, - bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd) - reloc->address += sec->output_offset; - return bfd_reloc_notsupported; -} - -/* Do the work of the GPDISP relocation. */ - -static bfd_reloc_status_type -elf64_alpha_do_reloc_gpdisp (bfd *abfd, bfd_vma gpdisp, bfd_byte *p_ldah, - bfd_byte *p_lda) -{ - bfd_reloc_status_type ret = bfd_reloc_ok; - bfd_vma addend; - unsigned long i_ldah, i_lda; - - i_ldah = bfd_get_32 (abfd, p_ldah); - i_lda = bfd_get_32 (abfd, p_lda); - - /* Complain if the instructions are not correct. */ - if (((i_ldah >> 26) & 0x3f) != 0x09 - || ((i_lda >> 26) & 0x3f) != 0x08) - ret = bfd_reloc_dangerous; - - /* Extract the user-supplied offset, mirroring the sign extensions - that the instructions perform. */ - addend = ((i_ldah & 0xffff) << 16) | (i_lda & 0xffff); - addend = (addend ^ 0x80008000) - 0x80008000; - - gpdisp += addend; - - if ((bfd_signed_vma) gpdisp < -(bfd_signed_vma) 0x80000000 - || (bfd_signed_vma) gpdisp >= (bfd_signed_vma) 0x7fff8000) - ret = bfd_reloc_overflow; - - /* compensate for the sign extension again. */ - i_ldah = ((i_ldah & 0xffff0000) - | (((gpdisp >> 16) + ((gpdisp >> 15) & 1)) & 0xffff)); - i_lda = (i_lda & 0xffff0000) | (gpdisp & 0xffff); - - bfd_put_32 (abfd, (bfd_vma) i_ldah, p_ldah); - bfd_put_32 (abfd, (bfd_vma) i_lda, p_lda); - - return ret; -} - -/* The special function for the GPDISP reloc. */ - -static bfd_reloc_status_type -elf64_alpha_reloc_gpdisp (bfd *abfd, arelent *reloc_entry, - asymbol *sym ATTRIBUTE_UNUSED, void * data, - asection *input_section, bfd *output_bfd, - char **err_msg) -{ - bfd_reloc_status_type ret; - bfd_vma gp, relocation; - bfd_vma high_address; - bfd_byte *p_ldah, *p_lda; - - /* Don't do anything if we're not doing a final link. */ - if (output_bfd) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - high_address = bfd_get_section_limit (abfd, input_section); - if (reloc_entry->address > high_address - || reloc_entry->address + reloc_entry->addend > high_address) - return bfd_reloc_outofrange; - - /* The gp used in the portion of the output object to which this - input object belongs is cached on the input bfd. */ - gp = _bfd_get_gp_value (abfd); - - relocation = (input_section->output_section->vma - + input_section->output_offset - + reloc_entry->address); - - p_ldah = (bfd_byte *) data + reloc_entry->address; - p_lda = p_ldah + reloc_entry->addend; - - ret = elf64_alpha_do_reloc_gpdisp (abfd, gp - relocation, p_ldah, p_lda); - - /* Complain if the instructions are not correct. */ - if (ret == bfd_reloc_dangerous) - *err_msg = _("GPDISP relocation did not find ldah and lda instructions"); - - return ret; -} - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - - -#define SKIP_HOWTO(N) \ - HOWTO(N, 0, 0, 0, 0, 0, complain_overflow_dont, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0) - -static reloc_howto_type elf64_alpha_howto_table[] = -{ - HOWTO (R_ALPHA_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_nil, /* special_function */ - "NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit reference to a symbol. */ - HOWTO (R_ALPHA_REFLONG, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "REFLONG", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 64 bit reference to a symbol. */ - HOWTO (R_ALPHA_REFQUAD, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "REFQUAD", /* name */ - FALSE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit GP relative offset. This is just like REFLONG except - that when the value is used the value of the gp register will be - added in. */ - HOWTO (R_ALPHA_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "GPREL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used for an instruction that refers to memory off the GP register. */ - HOWTO (R_ALPHA_LITERAL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "ELF_LITERAL", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This reloc only appears immediately following an ELF_LITERAL reloc. - It identifies a use of the literal. The symbol index is special: - 1 means the literal address is in the base register of a memory - format instruction; 2 means the literal address is in the byte - offset register of a byte-manipulation instruction; 3 means the - literal address is in the target register of a jsr instruction. - This does not actually do any relocation. */ - HOWTO (R_ALPHA_LITUSE, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_nil, /* special_function */ - "LITUSE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Load the gp register. This is always used for a ldah instruction - which loads the upper 16 bits of the gp register. The symbol - index of the GPDISP instruction is an offset in bytes to the lda - instruction that loads the lower 16 bits. The value to use for - the relocation is the difference between the GP value and the - current location; the load will always be done against a register - holding the current address. - - NOTE: Unlike ECOFF, partial in-place relocation is not done. If - any offset is present in the instructions, it is an offset from - the register to the ldah instruction. This lets us avoid any - stupid hackery like inventing a gp value to do partial relocation - against. Also unlike ECOFF, we do the whole relocation off of - the GPDISP rather than a GPDISP_HI16/GPDISP_LO16 pair. An odd, - space consuming bit, that, since all the information was present - in the GPDISP_HI16 reloc. */ - HOWTO (R_ALPHA_GPDISP, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_gpdisp, /* special_function */ - "GPDISP", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 21 bit branch. */ - HOWTO (R_ALPHA_BRADDR, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "BRADDR", /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A hint for a jump to a register. */ - HOWTO (R_ALPHA_HINT, /* type */ - 2, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 14, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "HINT", /* name */ - FALSE, /* partial_inplace */ - 0x3fff, /* src_mask */ - 0x3fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit PC relative offset. */ - HOWTO (R_ALPHA_SREL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "SREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32 bit PC relative offset. */ - HOWTO (R_ALPHA_SREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "SREL32", /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 64 bit PC relative offset. */ - HOWTO (R_ALPHA_SREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "SREL64", /* name */ - FALSE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Skip 12 - 16; deprecated ECOFF relocs. */ - SKIP_HOWTO (12), - SKIP_HOWTO (13), - SKIP_HOWTO (14), - SKIP_HOWTO (15), - SKIP_HOWTO (16), - - /* The high 16 bits of the displacement from GP to the target. */ - HOWTO (R_ALPHA_GPRELHIGH, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "GPRELHIGH", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The low 16 bits of the displacement from GP to the target. */ - HOWTO (R_ALPHA_GPRELLOW, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "GPRELLOW", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16-bit displacement from the GP to the target. */ - HOWTO (R_ALPHA_GPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "GPREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Skip 20 - 23; deprecated ECOFF relocs. */ - SKIP_HOWTO (20), - SKIP_HOWTO (21), - SKIP_HOWTO (22), - SKIP_HOWTO (23), - - /* Misc ELF relocations. */ - - /* A dynamic relocation to copy the target into our .dynbss section. */ - /* Not generated, as all Alpha objects use PIC, so it is not needed. It - is present because every other ELF has one, but should not be used - because .dynbss is an ugly thing. */ - HOWTO (R_ALPHA_COPY, - 0, - 0, - 0, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "COPY", - FALSE, - 0, - 0, - TRUE), - - /* A dynamic relocation for a .got entry. */ - HOWTO (R_ALPHA_GLOB_DAT, - 0, - 0, - 0, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "GLOB_DAT", - FALSE, - 0, - 0, - TRUE), - - /* A dynamic relocation for a .plt entry. */ - HOWTO (R_ALPHA_JMP_SLOT, - 0, - 0, - 0, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "JMP_SLOT", - FALSE, - 0, - 0, - TRUE), - - /* A dynamic relocation to add the base of the DSO to a 64-bit field. */ - HOWTO (R_ALPHA_RELATIVE, - 0, - 0, - 0, - FALSE, - 0, - complain_overflow_dont, - bfd_elf_generic_reloc, - "RELATIVE", - FALSE, - 0, - 0, - TRUE), - - /* A 21 bit branch that adjusts for gp loads. */ - HOWTO (R_ALPHA_BRSGP, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "BRSGP", /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Creates a tls_index for the symbol in the got. */ - HOWTO (R_ALPHA_TLSGD, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "TLSGD", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Creates a tls_index for the (current) module in the got. */ - HOWTO (R_ALPHA_TLSLDM, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "TLSLDM", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A dynamic relocation for a DTP module entry. */ - HOWTO (R_ALPHA_DTPMOD64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "DTPMOD64", /* name */ - FALSE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Creates a 64-bit offset in the got for the displacement - from DTP to the target. */ - HOWTO (R_ALPHA_GOTDTPREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "GOTDTPREL", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A dynamic relocation for a displacement from DTP to the target. */ - HOWTO (R_ALPHA_DTPREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "DTPREL64", /* name */ - FALSE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high 16 bits of the displacement from DTP to the target. */ - HOWTO (R_ALPHA_DTPRELHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "DTPRELHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The low 16 bits of the displacement from DTP to the target. */ - HOWTO (R_ALPHA_DTPRELLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "DTPRELLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16-bit displacement from DTP to the target. */ - HOWTO (R_ALPHA_DTPREL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "DTPREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Creates a 64-bit offset in the got for the displacement - from TP to the target. */ - HOWTO (R_ALPHA_GOTTPREL, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "GOTTPREL", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A dynamic relocation for a displacement from TP to the target. */ - HOWTO (R_ALPHA_TPREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "TPREL64", /* name */ - FALSE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The high 16 bits of the displacement from TP to the target. */ - HOWTO (R_ALPHA_TPRELHI, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "TPRELHI", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The low 16 bits of the displacement from TP to the target. */ - HOWTO (R_ALPHA_TPRELLO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "TPRELLO", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16-bit displacement from TP to the target. */ - HOWTO (R_ALPHA_TPREL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "TPREL16", /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* A mapping from BFD reloc types to Alpha ELF reloc types. */ - -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - int elf_reloc_val; -}; - -static const struct elf_reloc_map elf64_alpha_reloc_map[] = -{ - {BFD_RELOC_NONE, R_ALPHA_NONE}, - {BFD_RELOC_32, R_ALPHA_REFLONG}, - {BFD_RELOC_64, R_ALPHA_REFQUAD}, - {BFD_RELOC_CTOR, R_ALPHA_REFQUAD}, - {BFD_RELOC_GPREL32, R_ALPHA_GPREL32}, - {BFD_RELOC_ALPHA_ELF_LITERAL, R_ALPHA_LITERAL}, - {BFD_RELOC_ALPHA_LITUSE, R_ALPHA_LITUSE}, - {BFD_RELOC_ALPHA_GPDISP, R_ALPHA_GPDISP}, - {BFD_RELOC_23_PCREL_S2, R_ALPHA_BRADDR}, - {BFD_RELOC_ALPHA_HINT, R_ALPHA_HINT}, - {BFD_RELOC_16_PCREL, R_ALPHA_SREL16}, - {BFD_RELOC_32_PCREL, R_ALPHA_SREL32}, - {BFD_RELOC_64_PCREL, R_ALPHA_SREL64}, - {BFD_RELOC_ALPHA_GPREL_HI16, R_ALPHA_GPRELHIGH}, - {BFD_RELOC_ALPHA_GPREL_LO16, R_ALPHA_GPRELLOW}, - {BFD_RELOC_GPREL16, R_ALPHA_GPREL16}, - {BFD_RELOC_ALPHA_BRSGP, R_ALPHA_BRSGP}, - {BFD_RELOC_ALPHA_TLSGD, R_ALPHA_TLSGD}, - {BFD_RELOC_ALPHA_TLSLDM, R_ALPHA_TLSLDM}, - {BFD_RELOC_ALPHA_DTPMOD64, R_ALPHA_DTPMOD64}, - {BFD_RELOC_ALPHA_GOTDTPREL16, R_ALPHA_GOTDTPREL}, - {BFD_RELOC_ALPHA_DTPREL64, R_ALPHA_DTPREL64}, - {BFD_RELOC_ALPHA_DTPREL_HI16, R_ALPHA_DTPRELHI}, - {BFD_RELOC_ALPHA_DTPREL_LO16, R_ALPHA_DTPRELLO}, - {BFD_RELOC_ALPHA_DTPREL16, R_ALPHA_DTPREL16}, - {BFD_RELOC_ALPHA_GOTTPREL16, R_ALPHA_GOTTPREL}, - {BFD_RELOC_ALPHA_TPREL64, R_ALPHA_TPREL64}, - {BFD_RELOC_ALPHA_TPREL_HI16, R_ALPHA_TPRELHI}, - {BFD_RELOC_ALPHA_TPREL_LO16, R_ALPHA_TPRELLO}, - {BFD_RELOC_ALPHA_TPREL16, R_ALPHA_TPREL16}, -}; - -/* Given a BFD reloc type, return a HOWTO structure. */ - -static reloc_howto_type * -elf64_alpha_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - const struct elf_reloc_map *i, *e; - i = e = elf64_alpha_reloc_map; - e += sizeof (elf64_alpha_reloc_map) / sizeof (struct elf_reloc_map); - for (; i != e; ++i) - { - if (i->bfd_reloc_val == code) - return &elf64_alpha_howto_table[i->elf_reloc_val]; - } - return 0; -} - -static reloc_howto_type * -elf64_alpha_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf64_alpha_howto_table) - / sizeof (elf64_alpha_howto_table[0])); - i++) - if (elf64_alpha_howto_table[i].name != NULL - && strcasecmp (elf64_alpha_howto_table[i].name, r_name) == 0) - return &elf64_alpha_howto_table[i]; - - return NULL; -} - -/* Given an Alpha ELF reloc type, fill in an arelent structure. */ - -static void -elf64_alpha_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned r_type = ELF64_R_TYPE(dst->r_info); - - if (r_type >= R_ALPHA_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: unrecognised Alpha reloc number: %d"), - abfd, r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_ALPHA_NONE; - } - cache_ptr->howto = &elf64_alpha_howto_table[r_type]; -} - -/* These two relocations create a two-word entry in the got. */ -#define alpha_got_entry_size(r_type) \ - (r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8) - -/* This is PT_TLS segment p_vaddr. */ -#define alpha_get_dtprel_base(info) \ - (elf_hash_table (info)->tls_sec->vma) - -/* Main program TLS (whose template starts at PT_TLS p_vaddr) - is assigned offset round(16, PT_TLS p_align). */ -#define alpha_get_tprel_base(info) \ - (elf_hash_table (info)->tls_sec->vma \ - - align_power ((bfd_vma) 16, \ - elf_hash_table (info)->tls_sec->alignment_power)) - -/* Handle an Alpha specific section when reading an object file. This - is called when bfd_section_from_shdr finds a section with an unknown - type. - FIXME: We need to handle the SHF_ALPHA_GPREL flag, but I'm not sure - how to. */ - -static bfd_boolean -elf64_alpha_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) -{ - asection *newsect; - - /* There ought to be a place to keep ELF backend specific flags, but - at the moment there isn't one. We just keep track of the - sections by their name, instead. Fortunately, the ABI gives - suggested names for all the MIPS specific sections, so we will - probably get away with this. */ - switch (hdr->sh_type) - { - case SHT_ALPHA_DEBUG: - if (strcmp (name, ".mdebug") != 0) - return FALSE; - break; - default: - return FALSE; - } - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - newsect = hdr->bfd_section; - - if (hdr->sh_type == SHT_ALPHA_DEBUG) - { - if (! bfd_set_section_flags (abfd, newsect, - (bfd_get_section_flags (abfd, newsect) - | SEC_DEBUGGING))) - return FALSE; - } - - return TRUE; -} - -/* Convert Alpha specific section flags to bfd internal section flags. */ - -static bfd_boolean -elf64_alpha_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr) -{ - if (hdr->sh_flags & SHF_ALPHA_GPREL) - *flags |= SEC_SMALL_DATA; - - return TRUE; -} - -/* Set the correct type for an Alpha ELF section. We do this by the - section name, which is a hack, but ought to work. */ - -static bfd_boolean -elf64_alpha_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) -{ - register const char *name; - - name = bfd_get_section_name (abfd, sec); - - if (strcmp (name, ".mdebug") == 0) - { - hdr->sh_type = SHT_ALPHA_DEBUG; - /* In a shared object on Irix 5.3, the .mdebug section has an - entsize of 0. FIXME: Does this matter? */ - if ((abfd->flags & DYNAMIC) != 0 ) - hdr->sh_entsize = 0; - else - hdr->sh_entsize = 1; - } - else if ((sec->flags & SEC_SMALL_DATA) - || strcmp (name, ".sdata") == 0 - || strcmp (name, ".sbss") == 0 - || strcmp (name, ".lit4") == 0 - || strcmp (name, ".lit8") == 0) - hdr->sh_flags |= SHF_ALPHA_GPREL; - - return TRUE; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it to put .comm items in .sbss, and not .bss. */ - -static bfd_boolean -elf64_alpha_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, bfd_vma *valp) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && sym->st_size <= elf_gp_size (abfd)) - { - /* Common symbols less than or equal to -G nn bytes are - automatically put into .sbss. */ - - asection *scomm = bfd_get_section_by_name (abfd, ".scommon"); - - if (scomm == NULL) - { - scomm = bfd_make_section_with_flags (abfd, ".scommon", - (SEC_ALLOC - | SEC_IS_COMMON - | SEC_LINKER_CREATED)); - if (scomm == NULL) - return FALSE; - } - - *secp = scomm; - *valp = sym->st_size; - } - - return TRUE; -} - -/* Create the .got section. */ - -static bfd_boolean -elf64_alpha_create_got_section (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - flagword flags; - asection *s; - - if (! is_alpha_elf (abfd)) - return FALSE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - - alpha_elf_tdata (abfd)->got = s; - - /* Make sure the object's gotobj is set to itself so that we default - to every object with its own .got. We'll merge .gots later once - we've collected each object's info. */ - alpha_elf_tdata (abfd)->gotobj = abfd; - - return TRUE; -} - -/* Create all the dynamic sections. */ - -static bfd_boolean -elf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - asection *s; - flagword flags; - struct elf_link_hash_entry *h; - - if (! is_alpha_elf (abfd)) - return FALSE; - - /* We need to create .plt, .rela.plt, .got, and .rela.got sections. */ - - flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | (elf64_alpha_use_secureplt ? SEC_READONLY : 0)); - s = bfd_make_section_anyway_with_flags (abfd, ".plt", flags); - elf_hash_table (info)->splt = s; - if (s == NULL || ! bfd_set_section_alignment (abfd, s, 4)) - return FALSE; - - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - h = _bfd_elf_define_linkage_sym (abfd, info, s, - "_PROCEDURE_LINKAGE_TABLE_"); - elf_hash_table (info)->hplt = h; - if (h == NULL) - return FALSE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY); - s = bfd_make_section_anyway_with_flags (abfd, ".rela.plt", flags); - elf_hash_table (info)->srelplt = s; - if (s == NULL || ! bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - - if (elf64_alpha_use_secureplt) - { - flags = SEC_ALLOC | SEC_LINKER_CREATED; - s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); - elf_hash_table (info)->sgotplt = s; - if (s == NULL || ! bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - } - - /* We may or may not have created a .got section for this object, but - we definitely havn't done the rest of the work. */ - - if (alpha_elf_tdata(abfd)->gotobj == NULL) - { - if (!elf64_alpha_create_got_section (abfd, info)) - return FALSE; - } - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED | SEC_READONLY); - s = bfd_make_section_anyway_with_flags (abfd, ".rela.got", flags); - elf_hash_table (info)->srelgot = s; - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - - /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the - dynobj's .got 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, alpha_elf_tdata(abfd)->got, - "_GLOBAL_OFFSET_TABLE_"); - elf_hash_table (info)->hgot = h; - if (h == NULL) - return FALSE; - - return TRUE; -} - -/* Read ECOFF debugging information from a .mdebug section into a - ecoff_debug_info structure. */ - -static bfd_boolean -elf64_alpha_read_ecoff_info (bfd *abfd, asection *section, - struct ecoff_debug_info *debug) -{ - HDRR *symhdr; - const struct ecoff_debug_swap *swap; - char *ext_hdr = NULL; - - swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; - memset (debug, 0, sizeof (*debug)); - - ext_hdr = (char *) bfd_malloc (swap->external_hdr_size); - if (ext_hdr == NULL && swap->external_hdr_size != 0) - goto error_return; - - if (! bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0, - swap->external_hdr_size)) - goto error_return; - - symhdr = &debug->symbolic_header; - (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr); - - /* The symbolic header contains absolute file offsets and sizes to - read. */ -#define READ(ptr, offset, count, size, type) \ - if (symhdr->count == 0) \ - debug->ptr = NULL; \ - else \ - { \ - bfd_size_type amt = (bfd_size_type) size * symhdr->count; \ - debug->ptr = (type) bfd_malloc (amt); \ - if (debug->ptr == NULL) \ - goto error_return; \ - if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \ - || bfd_bread (debug->ptr, amt, abfd) != amt) \ - goto error_return; \ - } - - READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *); - READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *); - READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *); - READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *); - READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *); - READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), - union aux_ext *); - READ (ss, cbSsOffset, issMax, sizeof (char), char *); - READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *); - READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *); - READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *); - READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, void *); -#undef READ - - debug->fdr = NULL; - - return TRUE; - - error_return: - if (ext_hdr != NULL) - free (ext_hdr); - if (debug->line != NULL) - free (debug->line); - if (debug->external_dnr != NULL) - free (debug->external_dnr); - if (debug->external_pdr != NULL) - free (debug->external_pdr); - if (debug->external_sym != NULL) - free (debug->external_sym); - if (debug->external_opt != NULL) - free (debug->external_opt); - if (debug->external_aux != NULL) - free (debug->external_aux); - if (debug->ss != NULL) - free (debug->ss); - if (debug->ssext != NULL) - free (debug->ssext); - if (debug->external_fdr != NULL) - free (debug->external_fdr); - if (debug->external_rfd != NULL) - free (debug->external_rfd); - if (debug->external_ext != NULL) - free (debug->external_ext); - return FALSE; -} - -/* Alpha ELF local labels start with '$'. */ - -static bfd_boolean -elf64_alpha_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - return name[0] == '$'; -} - -static bfd_boolean -elf64_alpha_find_nearest_line (bfd *abfd, asymbol **symbols, - asection *section, bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - unsigned int *discriminator_ptr) -{ - asection *msec; - - if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, - filename_ptr, functionname_ptr, - line_ptr, discriminator_ptr, - dwarf_debug_sections, 0, - &elf_tdata (abfd)->dwarf2_find_line_info)) - return TRUE; - - msec = bfd_get_section_by_name (abfd, ".mdebug"); - if (msec != NULL) - { - flagword origflags; - struct alpha_elf_find_line *fi; - const struct ecoff_debug_swap * const swap = - get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; - - /* If we are called during a link, alpha_elf_final_link may have - cleared the SEC_HAS_CONTENTS field. We force it back on here - if appropriate (which it normally will be). */ - origflags = msec->flags; - if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS) - msec->flags |= SEC_HAS_CONTENTS; - - fi = alpha_elf_tdata (abfd)->find_line_info; - if (fi == NULL) - { - bfd_size_type external_fdr_size; - char *fraw_src; - char *fraw_end; - struct fdr *fdr_ptr; - bfd_size_type amt = sizeof (struct alpha_elf_find_line); - - fi = (struct alpha_elf_find_line *) bfd_zalloc (abfd, amt); - if (fi == NULL) - { - msec->flags = origflags; - return FALSE; - } - - if (!elf64_alpha_read_ecoff_info (abfd, msec, &fi->d)) - { - msec->flags = origflags; - return FALSE; - } - - /* Swap in the FDR information. */ - amt = fi->d.symbolic_header.ifdMax * sizeof (struct fdr); - fi->d.fdr = (struct fdr *) bfd_alloc (abfd, amt); - if (fi->d.fdr == NULL) - { - msec->flags = origflags; - return FALSE; - } - external_fdr_size = swap->external_fdr_size; - fdr_ptr = fi->d.fdr; - fraw_src = (char *) fi->d.external_fdr; - fraw_end = (fraw_src - + fi->d.symbolic_header.ifdMax * external_fdr_size); - for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) - (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr); - - alpha_elf_tdata (abfd)->find_line_info = fi; - - /* Note that we don't bother to ever free this information. - find_nearest_line is either called all the time, as in - objdump -l, so the information should be saved, or it is - rarely called, as in ld error messages, so the memory - wasted is unimportant. Still, it would probably be a - good idea for free_cached_info to throw it away. */ - } - - if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap, - &fi->i, filename_ptr, functionname_ptr, - line_ptr)) - { - msec->flags = origflags; - return TRUE; - } - - msec->flags = origflags; - } - - /* Fall back on the generic ELF find_nearest_line routine. */ - - return _bfd_elf_find_nearest_line (abfd, symbols, section, offset, - filename_ptr, functionname_ptr, - line_ptr, discriminator_ptr); -} - -/* Structure used to pass information to alpha_elf_output_extsym. */ - -struct extsym_info -{ - bfd *abfd; - struct bfd_link_info *info; - struct ecoff_debug_info *debug; - const struct ecoff_debug_swap *swap; - bfd_boolean failed; -}; - -static bfd_boolean -elf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, void * data) -{ - struct extsym_info *einfo = (struct extsym_info *) data; - bfd_boolean strip; - asection *sec, *output_section; - - if (h->root.indx == -2) - strip = FALSE; - else if ((h->root.def_dynamic - || h->root.ref_dynamic - || h->root.root.type == bfd_link_hash_new) - && !h->root.def_regular - && !h->root.ref_regular) - strip = TRUE; - else if (einfo->info->strip == strip_all - || (einfo->info->strip == strip_some - && bfd_hash_lookup (einfo->info->keep_hash, - h->root.root.root.string, - FALSE, FALSE) == NULL)) - strip = TRUE; - else - strip = FALSE; - - if (strip) - return TRUE; - - if (h->esym.ifd == -2) - { - h->esym.jmptbl = 0; - h->esym.cobol_main = 0; - h->esym.weakext = 0; - h->esym.reserved = 0; - h->esym.ifd = ifdNil; - h->esym.asym.value = 0; - h->esym.asym.st = stGlobal; - - if (h->root.root.type != bfd_link_hash_defined - && h->root.root.type != bfd_link_hash_defweak) - h->esym.asym.sc = scAbs; - else - { - const char *name; - - sec = h->root.root.u.def.section; - output_section = sec->output_section; - - /* When making a shared library and symbol h is the one from - the another shared library, OUTPUT_SECTION may be null. */ - if (output_section == NULL) - h->esym.asym.sc = scUndefined; - else - { - name = bfd_section_name (output_section->owner, output_section); - - if (strcmp (name, ".text") == 0) - h->esym.asym.sc = scText; - else if (strcmp (name, ".data") == 0) - h->esym.asym.sc = scData; - else if (strcmp (name, ".sdata") == 0) - h->esym.asym.sc = scSData; - else if (strcmp (name, ".rodata") == 0 - || strcmp (name, ".rdata") == 0) - h->esym.asym.sc = scRData; - else if (strcmp (name, ".bss") == 0) - h->esym.asym.sc = scBss; - else if (strcmp (name, ".sbss") == 0) - h->esym.asym.sc = scSBss; - else if (strcmp (name, ".init") == 0) - h->esym.asym.sc = scInit; - else if (strcmp (name, ".fini") == 0) - h->esym.asym.sc = scFini; - else - h->esym.asym.sc = scAbs; - } - } - - h->esym.asym.reserved = 0; - h->esym.asym.index = indexNil; - } - - if (h->root.root.type == bfd_link_hash_common) - h->esym.asym.value = h->root.root.u.c.size; - else if (h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - { - if (h->esym.asym.sc == scCommon) - h->esym.asym.sc = scBss; - else if (h->esym.asym.sc == scSCommon) - h->esym.asym.sc = scSBss; - - sec = h->root.root.u.def.section; - output_section = sec->output_section; - if (output_section != NULL) - h->esym.asym.value = (h->root.root.u.def.value - + sec->output_offset - + output_section->vma); - else - h->esym.asym.value = 0; - } - - if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, - h->root.root.root.string, - &h->esym)) - { - einfo->failed = TRUE; - return FALSE; - } - - return TRUE; -} - -/* Search for and possibly create a got entry. */ - -static struct alpha_elf_got_entry * -get_got_entry (bfd *abfd, struct alpha_elf_link_hash_entry *h, - unsigned long r_type, unsigned long r_symndx, - bfd_vma r_addend) -{ - struct alpha_elf_got_entry *gotent; - struct alpha_elf_got_entry **slot; - - if (h) - slot = &h->got_entries; - else - { - /* This is a local .got entry -- record for merge. */ - - struct alpha_elf_got_entry **local_got_entries; - - local_got_entries = alpha_elf_tdata(abfd)->local_got_entries; - if (!local_got_entries) - { - bfd_size_type size; - Elf_Internal_Shdr *symtab_hdr; - - symtab_hdr = &elf_tdata(abfd)->symtab_hdr; - size = symtab_hdr->sh_info; - size *= sizeof (struct alpha_elf_got_entry *); - - local_got_entries - = (struct alpha_elf_got_entry **) bfd_zalloc (abfd, size); - if (!local_got_entries) - return NULL; - - alpha_elf_tdata (abfd)->local_got_entries = local_got_entries; - } - - slot = &local_got_entries[r_symndx]; - } - - for (gotent = *slot; gotent ; gotent = gotent->next) - if (gotent->gotobj == abfd - && gotent->reloc_type == r_type - && gotent->addend == r_addend) - break; - - if (!gotent) - { - int entry_size; - bfd_size_type amt; - - amt = sizeof (struct alpha_elf_got_entry); - gotent = (struct alpha_elf_got_entry *) bfd_alloc (abfd, amt); - if (!gotent) - return NULL; - - gotent->gotobj = abfd; - gotent->addend = r_addend; - gotent->got_offset = -1; - gotent->plt_offset = -1; - gotent->use_count = 1; - gotent->reloc_type = r_type; - gotent->reloc_done = 0; - gotent->reloc_xlated = 0; - - gotent->next = *slot; - *slot = gotent; - - entry_size = alpha_got_entry_size (r_type); - alpha_elf_tdata (abfd)->total_got_size += entry_size; - if (!h) - alpha_elf_tdata(abfd)->local_got_size += entry_size; - } - else - gotent->use_count += 1; - - return gotent; -} - -static bfd_boolean -elf64_alpha_want_plt (struct alpha_elf_link_hash_entry *ah) -{ - return ((ah->root.type == STT_FUNC - || ah->root.root.type == bfd_link_hash_undefweak - || ah->root.root.type == bfd_link_hash_undefined) - && (ah->flags & ALPHA_ELF_LINK_HASH_LU_PLT) != 0 - && (ah->flags & ~ALPHA_ELF_LINK_HASH_LU_PLT) == 0); -} - -/* Whether to sort relocs output by ld -r or ld --emit-relocs, by r_offset. - Don't do so for code sections. We want to keep ordering of LITERAL/LITUSE - as is. On the other hand, elf-eh-frame.c processing requires .eh_frame - relocs to be sorted. */ - -static bfd_boolean -elf64_alpha_sort_relocs_p (asection *sec) -{ - return (sec->flags & SEC_CODE) == 0; -} - - -/* Handle dynamic relocations when doing an Alpha ELF link. */ - -static bfd_boolean -elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - bfd *dynobj; - asection *sreloc; - Elf_Internal_Shdr *symtab_hdr; - struct alpha_elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel, *relend; - bfd_size_type amt; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - BFD_ASSERT (is_alpha_elf (abfd)); - - dynobj = elf_hash_table (info)->dynobj; - if (dynobj == NULL) - elf_hash_table (info)->dynobj = dynobj = abfd; - - sreloc = NULL; - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = alpha_elf_sym_hashes (abfd); - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; ++rel) - { - enum { - NEED_GOT = 1, - NEED_GOT_ENTRY = 2, - NEED_DYNREL = 4 - }; - - unsigned long r_symndx, r_type; - struct alpha_elf_link_hash_entry *h; - unsigned int gotent_flags; - bfd_boolean maybe_dynamic; - unsigned int need; - bfd_vma addend; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link; - - /* PR15323, ref flags aren't set for references in the same - object. */ - h->root.ref_regular = 1; - } - - /* We can only get preliminary data on whether a symbol is - locally or externally defined, as not all of the input files - have yet been processed. Do something with what we know, as - this may help reduce memory usage and processing time later. */ - maybe_dynamic = FALSE; - if (h && ((bfd_link_pic (info) - && (!info->symbolic - || info->unresolved_syms_in_shared_libs == RM_IGNORE)) - || !h->root.def_regular - || h->root.root.type == bfd_link_hash_defweak)) - maybe_dynamic = TRUE; - - need = 0; - gotent_flags = 0; - r_type = ELF64_R_TYPE (rel->r_info); - addend = rel->r_addend; - - switch (r_type) - { - case R_ALPHA_LITERAL: - need = NEED_GOT | NEED_GOT_ENTRY; - - /* Remember how this literal is used from its LITUSEs. - This will be important when it comes to decide if we can - create a .plt entry for a function symbol. */ - while (++rel < relend && ELF64_R_TYPE (rel->r_info) == R_ALPHA_LITUSE) - if (rel->r_addend >= 1 && rel->r_addend <= 6) - gotent_flags |= 1 << rel->r_addend; - --rel; - - /* No LITUSEs -- presumably the address is used somehow. */ - if (gotent_flags == 0) - gotent_flags = ALPHA_ELF_LINK_HASH_LU_ADDR; - break; - - case R_ALPHA_GPDISP: - case R_ALPHA_GPREL16: - case R_ALPHA_GPREL32: - case R_ALPHA_GPRELHIGH: - case R_ALPHA_GPRELLOW: - case R_ALPHA_BRSGP: - need = NEED_GOT; - break; - - case R_ALPHA_REFLONG: - case R_ALPHA_REFQUAD: - if (bfd_link_pic (info) || maybe_dynamic) - need = NEED_DYNREL; - break; - - case R_ALPHA_TLSLDM: - /* The symbol for a TLSLDM reloc is ignored. Collapse the - reloc to the STN_UNDEF (0) symbol so that they all match. */ - r_symndx = STN_UNDEF; - h = 0; - maybe_dynamic = FALSE; - /* FALLTHRU */ - - case R_ALPHA_TLSGD: - case R_ALPHA_GOTDTPREL: - need = NEED_GOT | NEED_GOT_ENTRY; - break; - - case R_ALPHA_GOTTPREL: - need = NEED_GOT | NEED_GOT_ENTRY; - gotent_flags = ALPHA_ELF_LINK_HASH_TLS_IE; - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - break; - - case R_ALPHA_TPREL64: - if (bfd_link_dll (info)) - { - info->flags |= DF_STATIC_TLS; - need = NEED_DYNREL; - } - else if (maybe_dynamic) - need = NEED_DYNREL; - break; - } - - if (need & NEED_GOT) - { - if (alpha_elf_tdata(abfd)->gotobj == NULL) - { - if (!elf64_alpha_create_got_section (abfd, info)) - return FALSE; - } - } - - if (need & NEED_GOT_ENTRY) - { - struct alpha_elf_got_entry *gotent; - - gotent = get_got_entry (abfd, h, r_type, r_symndx, addend); - if (!gotent) - return FALSE; - - if (gotent_flags) - { - gotent->flags |= gotent_flags; - if (h) - { - gotent_flags |= h->flags; - h->flags = gotent_flags; - - /* Make a guess as to whether a .plt entry is needed. */ - /* ??? It appears that we won't make it into - adjust_dynamic_symbol for symbols that remain - totally undefined. Copying this check here means - we can create a plt entry for them too. */ - h->root.needs_plt - = (maybe_dynamic && elf64_alpha_want_plt (h)); - } - } - } - - if (need & NEED_DYNREL) - { - /* We need to create the section here now whether we eventually - use it or not so that it gets mapped to an output section by - the linker. If not used, we'll kill it in size_dynamic_sections. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 3, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - if (h) - { - /* Since we havn't seen all of the input symbols yet, we - don't know whether we'll actually need a dynamic relocation - entry for this reloc. So make a record of it. Once we - find out if this thing needs dynamic relocation we'll - expand the relocation sections by the appropriate amount. */ - - struct alpha_elf_reloc_entry *rent; - - for (rent = h->reloc_entries; rent; rent = rent->next) - if (rent->rtype == r_type && rent->srel == sreloc) - break; - - if (!rent) - { - amt = sizeof (struct alpha_elf_reloc_entry); - rent = (struct alpha_elf_reloc_entry *) bfd_alloc (abfd, amt); - if (!rent) - return FALSE; - - rent->srel = sreloc; - rent->rtype = r_type; - rent->count = 1; - rent->reltext = (sec->flags & SEC_READONLY) != 0; - - rent->next = h->reloc_entries; - h->reloc_entries = rent; - } - else - rent->count++; - } - else if (bfd_link_pic (info)) - { - /* If this is a shared library, and the section is to be - loaded into memory, we need a RELATIVE reloc. */ - sreloc->size += sizeof (Elf64_External_Rela); - if (sec->flags & SEC_READONLY) - info->flags |= DF_TEXTREL; - } - } - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -elf64_alpha_gc_mark_hook (asection *sec, struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) -{ - /* These relocations don't really reference a symbol. Instead we store - extra data in their addend slot. Ignore the symbol. */ - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_ALPHA_LITUSE: - case R_ALPHA_GPDISP: - case R_ALPHA_HINT: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* 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_alpha_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj; - asection *s; - struct alpha_elf_link_hash_entry *ah; - - dynobj = elf_hash_table(info)->dynobj; - ah = (struct alpha_elf_link_hash_entry *)h; - - /* Now that we've seen all of the input symbols, finalize our decision - about whether this symbol should get a .plt entry. Irritatingly, it - is common for folk to leave undefined symbols in shared libraries, - and they still expect lazy binding; accept undefined symbols in lieu - of STT_FUNC. */ - if (alpha_elf_dynamic_symbol_p (h, info) && elf64_alpha_want_plt (ah)) - { - h->needs_plt = TRUE; - - s = elf_hash_table(info)->splt; - if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info)) - return FALSE; - - /* We need one plt entry per got subsection. Delay allocation of - the actual plt entries until size_plt_section, called from - size_dynamic_sections or during relaxation. */ - - return TRUE; - } - else - h->needs_plt = FALSE; - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. The Alpha, since it uses .got entries for all - symbols even in regular objects, does not need the hackery of a - .dynbss section and COPY dynamic relocations. */ - - return TRUE; -} - -/* Record STO_ALPHA_NOPV and STO_ALPHA_STD_GPLOAD. */ - -static void -elf64_alpha_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic) -{ - if (!dynamic && definition) - h->other = ((h->other & ELF_ST_VISIBILITY (-1)) - | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); -} - -/* Symbol versioning can create new symbols, and make our old symbols - indirect to the new ones. Consolidate the got and reloc information - in these situations. */ - -static void -elf64_alpha_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct alpha_elf_link_hash_entry *hi - = (struct alpha_elf_link_hash_entry *) ind; - struct alpha_elf_link_hash_entry *hs - = (struct alpha_elf_link_hash_entry *) dir; - - /* Do the merging in the superclass. */ - _bfd_elf_link_hash_copy_indirect(info, dir, ind); - - /* Merge the flags. Whee. */ - hs->flags |= hi->flags; - - /* ??? It's unclear to me what's really supposed to happen when - "merging" defweak and defined symbols, given that we don't - actually throw away the defweak. This more-or-less copies - the logic related to got and plt entries in the superclass. */ - if (ind->root.type != bfd_link_hash_indirect) - return; - - /* Merge the .got entries. Cannibalize the old symbol's list in - doing so, since we don't need it anymore. */ - - if (hs->got_entries == NULL) - hs->got_entries = hi->got_entries; - else - { - struct alpha_elf_got_entry *gi, *gs, *gin, *gsh; - - gsh = hs->got_entries; - for (gi = hi->got_entries; gi ; gi = gin) - { - gin = gi->next; - for (gs = gsh; gs ; gs = gs->next) - if (gi->gotobj == gs->gotobj - && gi->reloc_type == gs->reloc_type - && gi->addend == gs->addend) - { - gs->use_count += gi->use_count; - goto got_found; - } - gi->next = hs->got_entries; - hs->got_entries = gi; - got_found:; - } - } - hi->got_entries = NULL; - - /* And similar for the reloc entries. */ - - if (hs->reloc_entries == NULL) - hs->reloc_entries = hi->reloc_entries; - else - { - struct alpha_elf_reloc_entry *ri, *rs, *rin, *rsh; - - rsh = hs->reloc_entries; - for (ri = hi->reloc_entries; ri ; ri = rin) - { - rin = ri->next; - for (rs = rsh; rs ; rs = rs->next) - if (ri->rtype == rs->rtype && ri->srel == rs->srel) - { - rs->count += ri->count; - goto found_reloc; - } - ri->next = hs->reloc_entries; - hs->reloc_entries = ri; - found_reloc:; - } - } - hi->reloc_entries = NULL; -} - -/* Is it possible to merge two object file's .got tables? */ - -static bfd_boolean -elf64_alpha_can_merge_gots (bfd *a, bfd *b) -{ - int total = alpha_elf_tdata (a)->total_got_size; - bfd *bsub; - - /* Trivial quick fallout test. */ - if (total + alpha_elf_tdata (b)->total_got_size <= MAX_GOT_SIZE) - return TRUE; - - /* By their nature, local .got entries cannot be merged. */ - if ((total += alpha_elf_tdata (b)->local_got_size) > MAX_GOT_SIZE) - return FALSE; - - /* Failing the common trivial comparison, we must effectively - perform the merge. Not actually performing the merge means that - we don't have to store undo information in case we fail. */ - for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next) - { - struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes (bsub); - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (bsub)->symtab_hdr; - int i, n; - - n = NUM_SHDR_ENTRIES (symtab_hdr) - symtab_hdr->sh_info; - for (i = 0; i < n; ++i) - { - struct alpha_elf_got_entry *ae, *be; - struct alpha_elf_link_hash_entry *h; - - h = hashes[i]; - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link; - - for (be = h->got_entries; be ; be = be->next) - { - if (be->use_count == 0) - continue; - if (be->gotobj != b) - continue; - - for (ae = h->got_entries; ae ; ae = ae->next) - if (ae->gotobj == a - && ae->reloc_type == be->reloc_type - && ae->addend == be->addend) - goto global_found; - - total += alpha_got_entry_size (be->reloc_type); - if (total > MAX_GOT_SIZE) - return FALSE; - global_found:; - } - } - } - - return TRUE; -} - -/* Actually merge two .got tables. */ - -static void -elf64_alpha_merge_gots (bfd *a, bfd *b) -{ - int total = alpha_elf_tdata (a)->total_got_size; - bfd *bsub; - - /* Remember local expansion. */ - { - int e = alpha_elf_tdata (b)->local_got_size; - total += e; - alpha_elf_tdata (a)->local_got_size += e; - } - - for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next) - { - struct alpha_elf_got_entry **local_got_entries; - struct alpha_elf_link_hash_entry **hashes; - Elf_Internal_Shdr *symtab_hdr; - int i, n; - - /* Let the local .got entries know they are part of a new subsegment. */ - local_got_entries = alpha_elf_tdata (bsub)->local_got_entries; - if (local_got_entries) - { - n = elf_tdata (bsub)->symtab_hdr.sh_info; - for (i = 0; i < n; ++i) - { - struct alpha_elf_got_entry *ent; - for (ent = local_got_entries[i]; ent; ent = ent->next) - ent->gotobj = a; - } - } - - /* Merge the global .got entries. */ - hashes = alpha_elf_sym_hashes (bsub); - symtab_hdr = &elf_tdata (bsub)->symtab_hdr; - - n = NUM_SHDR_ENTRIES (symtab_hdr) - symtab_hdr->sh_info; - for (i = 0; i < n; ++i) - { - struct alpha_elf_got_entry *ae, *be, **pbe, **start; - struct alpha_elf_link_hash_entry *h; - - h = hashes[i]; - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link; - - pbe = start = &h->got_entries; - while ((be = *pbe) != NULL) - { - if (be->use_count == 0) - { - *pbe = be->next; - memset (be, 0xa5, sizeof (*be)); - goto kill; - } - if (be->gotobj != b) - goto next; - - for (ae = *start; ae ; ae = ae->next) - if (ae->gotobj == a - && ae->reloc_type == be->reloc_type - && ae->addend == be->addend) - { - ae->flags |= be->flags; - ae->use_count += be->use_count; - *pbe = be->next; - memset (be, 0xa5, sizeof (*be)); - goto kill; - } - be->gotobj = a; - total += alpha_got_entry_size (be->reloc_type); - - next:; - pbe = &be->next; - kill:; - } - } - - alpha_elf_tdata (bsub)->gotobj = a; - } - alpha_elf_tdata (a)->total_got_size = total; - - /* Merge the two in_got chains. */ - { - bfd *next; - - bsub = a; - while ((next = alpha_elf_tdata (bsub)->in_got_link_next) != NULL) - bsub = next; - - alpha_elf_tdata (bsub)->in_got_link_next = b; - } -} - -/* Calculate the offsets for the got entries. */ - -static bfd_boolean -elf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h, - void * arg ATTRIBUTE_UNUSED) -{ - struct alpha_elf_got_entry *gotent; - - for (gotent = h->got_entries; gotent; gotent = gotent->next) - if (gotent->use_count > 0) - { - struct alpha_elf_obj_tdata *td; - bfd_size_type *plge; - - td = alpha_elf_tdata (gotent->gotobj); - plge = &td->got->size; - gotent->got_offset = *plge; - *plge += alpha_got_entry_size (gotent->reloc_type); - } - - return TRUE; -} - -static void -elf64_alpha_calc_got_offsets (struct bfd_link_info *info) -{ - bfd *i, *got_list; - struct alpha_elf_link_hash_table * htab; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return; - got_list = htab->got_list; - - /* First, zero out the .got sizes, as we may be recalculating the - .got after optimizing it. */ - for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next) - alpha_elf_tdata(i)->got->size = 0; - - /* Next, fill in the offsets for all the global entries. */ - alpha_elf_link_hash_traverse (htab, - elf64_alpha_calc_got_offsets_for_symbol, - NULL); - - /* Finally, fill in the offsets for the local entries. */ - for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next) - { - bfd_size_type got_offset = alpha_elf_tdata(i)->got->size; - bfd *j; - - for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next) - { - struct alpha_elf_got_entry **local_got_entries, *gotent; - int k, n; - - local_got_entries = alpha_elf_tdata(j)->local_got_entries; - if (!local_got_entries) - continue; - - for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k) - for (gotent = local_got_entries[k]; gotent; gotent = gotent->next) - if (gotent->use_count > 0) - { - gotent->got_offset = got_offset; - got_offset += alpha_got_entry_size (gotent->reloc_type); - } - } - - alpha_elf_tdata(i)->got->size = got_offset; - } -} - -/* Constructs the gots. */ - -static bfd_boolean -elf64_alpha_size_got_sections (struct bfd_link_info *info, - bfd_boolean may_merge) -{ - bfd *i, *got_list, *cur_got_obj = NULL; - struct alpha_elf_link_hash_table * htab; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return FALSE; - got_list = htab->got_list; - - /* On the first time through, pretend we have an existing got list - consisting of all of the input files. */ - if (got_list == NULL) - { - for (i = info->input_bfds; i ; i = i->link.next) - { - bfd *this_got; - - if (! is_alpha_elf (i)) - continue; - - this_got = alpha_elf_tdata (i)->gotobj; - if (this_got == NULL) - continue; - - /* We are assuming no merging has yet occurred. */ - BFD_ASSERT (this_got == i); - - if (alpha_elf_tdata (this_got)->total_got_size > MAX_GOT_SIZE) - { - /* Yikes! A single object file has too many entries. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: .got subsegment exceeds 64K (size %d)"), - i, alpha_elf_tdata (this_got)->total_got_size); - return FALSE; - } - - if (got_list == NULL) - got_list = this_got; - else - alpha_elf_tdata(cur_got_obj)->got_link_next = this_got; - cur_got_obj = this_got; - } - - /* Strange degenerate case of no got references. */ - if (got_list == NULL) - return TRUE; - - htab->got_list = got_list; - } - - cur_got_obj = got_list; - if (cur_got_obj == NULL) - return FALSE; - - if (may_merge) - { - i = alpha_elf_tdata(cur_got_obj)->got_link_next; - while (i != NULL) - { - if (elf64_alpha_can_merge_gots (cur_got_obj, i)) - { - elf64_alpha_merge_gots (cur_got_obj, i); - - alpha_elf_tdata(i)->got->size = 0; - i = alpha_elf_tdata(i)->got_link_next; - alpha_elf_tdata(cur_got_obj)->got_link_next = i; - } - else - { - cur_got_obj = i; - i = alpha_elf_tdata(i)->got_link_next; - } - } - } - - /* Once the gots have been merged, fill in the got offsets for - everything therein. */ - elf64_alpha_calc_got_offsets (info); - - return TRUE; -} - -static bfd_boolean -elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h, - void * data) -{ - asection *splt = (asection *) data; - struct alpha_elf_got_entry *gotent; - bfd_boolean saw_one = FALSE; - - /* If we didn't need an entry before, we still don't. */ - if (!h->root.needs_plt) - return TRUE; - - /* For each LITERAL got entry still in use, allocate a plt entry. */ - for (gotent = h->got_entries; gotent ; gotent = gotent->next) - if (gotent->reloc_type == R_ALPHA_LITERAL - && gotent->use_count > 0) - { - if (splt->size == 0) - splt->size = PLT_HEADER_SIZE; - gotent->plt_offset = splt->size; - splt->size += PLT_ENTRY_SIZE; - saw_one = TRUE; - } - - /* If there weren't any, there's no longer a need for the PLT entry. */ - if (!saw_one) - h->root.needs_plt = FALSE; - - return TRUE; -} - -/* Called from relax_section to rebuild the PLT in light of potential changes - in the function's status. */ - -static void -elf64_alpha_size_plt_section (struct bfd_link_info *info) -{ - asection *splt, *spltrel, *sgotplt; - unsigned long entries; - struct alpha_elf_link_hash_table * htab; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return; - - splt = elf_hash_table(info)->splt; - if (splt == NULL) - return; - - splt->size = 0; - - alpha_elf_link_hash_traverse (htab, - elf64_alpha_size_plt_section_1, splt); - - /* Every plt entry requires a JMP_SLOT relocation. */ - spltrel = elf_hash_table(info)->srelplt; - entries = 0; - if (splt->size) - { - if (elf64_alpha_use_secureplt) - entries = (splt->size - NEW_PLT_HEADER_SIZE) / NEW_PLT_ENTRY_SIZE; - else - entries = (splt->size - OLD_PLT_HEADER_SIZE) / OLD_PLT_ENTRY_SIZE; - } - spltrel->size = entries * sizeof (Elf64_External_Rela); - - /* When using the secureplt, we need two words somewhere in the data - segment for the dynamic linker to tell us where to go. This is the - entire contents of the .got.plt section. */ - if (elf64_alpha_use_secureplt) - { - sgotplt = elf_hash_table(info)->sgotplt; - sgotplt->size = entries ? 16 : 0; - } -} - -static bfd_boolean -elf64_alpha_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *i; - struct alpha_elf_link_hash_table * htab; - - if (bfd_link_relocatable (info)) - return TRUE; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - if (!elf64_alpha_size_got_sections (info, TRUE)) - return FALSE; - - /* Allocate space for all of the .got subsections. */ - i = htab->got_list; - for ( ; i ; i = alpha_elf_tdata(i)->got_link_next) - { - asection *s = alpha_elf_tdata(i)->got; - if (s->size > 0) - { - s->contents = (bfd_byte *) bfd_zalloc (i, s->size); - if (s->contents == NULL) - return FALSE; - } - } - - return TRUE; -} - -/* The number of dynamic relocations required by a static relocation. */ - -static int -alpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared, int pie) -{ - switch (r_type) - { - /* May appear in GOT entries. */ - case R_ALPHA_TLSGD: - return (dynamic ? 2 : shared ? 1 : 0); - case R_ALPHA_TLSLDM: - return shared; - case R_ALPHA_LITERAL: - return dynamic || shared; - case R_ALPHA_GOTTPREL: - return dynamic || (shared && !pie); - case R_ALPHA_GOTDTPREL: - return dynamic; - - /* May appear in data sections. */ - case R_ALPHA_REFLONG: - case R_ALPHA_REFQUAD: - return dynamic || shared; - case R_ALPHA_TPREL64: - return dynamic || (shared && !pie); - - /* Everything else is illegal. We'll issue an error during - relocate_section. */ - default: - return 0; - } -} - -/* Work out the sizes of the dynamic relocation entries. */ - -static bfd_boolean -elf64_alpha_calc_dynrel_sizes (struct alpha_elf_link_hash_entry *h, - struct bfd_link_info *info) -{ - bfd_boolean dynamic; - struct alpha_elf_reloc_entry *relent; - unsigned long entries; - - /* If the symbol was defined as a common symbol in a regular object - file, and there was no definition in any dynamic object, then the - linker will have allocated space for the symbol in a common - section but the ELF_LINK_HASH_DEF_REGULAR flag will not have been - set. This is done for dynamic symbols in - elf_adjust_dynamic_symbol but this is not done for non-dynamic - symbols, somehow. */ - if (!h->root.def_regular - && h->root.ref_regular - && !h->root.def_dynamic - && (h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - && !(h->root.root.u.def.section->owner->flags & DYNAMIC)) - h->root.def_regular = 1; - - /* If the symbol is dynamic, we'll need all the relocations in their - natural form. If this is a shared object, and it has been forced - local, we'll need the same number of RELATIVE relocations. */ - dynamic = alpha_elf_dynamic_symbol_p (&h->root, info); - - /* If the symbol is a hidden undefined weak, then we never have any - relocations. Avoid the loop which may want to add RELATIVE relocs - based on bfd_link_pic (info). */ - if (h->root.root.type == bfd_link_hash_undefweak && !dynamic) - return TRUE; - - for (relent = h->reloc_entries; relent; relent = relent->next) - { - entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic, - bfd_link_pic (info), - bfd_link_pie (info)); - if (entries) - { - relent->srel->size += - entries * sizeof (Elf64_External_Rela) * relent->count; - if (relent->reltext) - info->flags |= DT_TEXTREL; - } - } - - return TRUE; -} - -/* Subroutine of elf64_alpha_size_rela_got_section for doing the - global symbols. */ - -static bfd_boolean -elf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h, - struct bfd_link_info *info) -{ - bfd_boolean dynamic; - struct alpha_elf_got_entry *gotent; - unsigned long entries; - - /* If we're using a plt for this symbol, then all of its relocations - for its got entries go into .rela.plt. */ - if (h->root.needs_plt) - return TRUE; - - /* If the symbol is dynamic, we'll need all the relocations in their - natural form. If this is a shared object, and it has been forced - local, we'll need the same number of RELATIVE relocations. */ - dynamic = alpha_elf_dynamic_symbol_p (&h->root, info); - - /* If the symbol is a hidden undefined weak, then we never have any - relocations. Avoid the loop which may want to add RELATIVE relocs - based on bfd_link_pic (info). */ - if (h->root.root.type == bfd_link_hash_undefweak && !dynamic) - return TRUE; - - entries = 0; - for (gotent = h->got_entries; gotent ; gotent = gotent->next) - if (gotent->use_count > 0) - entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type, dynamic, - bfd_link_pic (info), - bfd_link_pie (info)); - - if (entries > 0) - { - asection *srel = elf_hash_table(info)->srelgot; - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf64_External_Rela) * entries; - } - - return TRUE; -} - -/* Set the sizes of the dynamic relocation sections. */ - -static void -elf64_alpha_size_rela_got_section (struct bfd_link_info *info) -{ - unsigned long entries; - bfd *i; - asection *srel; - struct alpha_elf_link_hash_table * htab; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return; - - /* Shared libraries often require RELATIVE relocs, and some relocs - require attention for the main application as well. */ - - entries = 0; - for (i = htab->got_list; - i ; i = alpha_elf_tdata(i)->got_link_next) - { - bfd *j; - - for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next) - { - struct alpha_elf_got_entry **local_got_entries, *gotent; - int k, n; - - local_got_entries = alpha_elf_tdata(j)->local_got_entries; - if (!local_got_entries) - continue; - - for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k) - for (gotent = local_got_entries[k]; - gotent ; gotent = gotent->next) - if (gotent->use_count > 0) - entries += (alpha_dynamic_entries_for_reloc - (gotent->reloc_type, 0, bfd_link_pic (info), - bfd_link_pie (info))); - } - } - - srel = elf_hash_table(info)->srelgot; - if (!srel) - { - BFD_ASSERT (entries == 0); - return; - } - srel->size = sizeof (Elf64_External_Rela) * entries; - - /* Now do the non-local symbols. */ - alpha_elf_link_hash_traverse (htab, - elf64_alpha_size_rela_got_1, info); -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean relplt, relocs; - struct alpha_elf_link_hash_table * htab; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = elf_hash_table(info)->dynobj; - BFD_ASSERT(dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - - /* Now that we've seen all of the input files, we can decide which - symbols need dynamic relocation entries and which don't. We've - collected information in check_relocs that we can now apply to - size the dynamic relocation sections. */ - alpha_elf_link_hash_traverse (htab, - elf64_alpha_calc_dynrel_sizes, info); - - elf64_alpha_size_rela_got_section (info); - elf64_alpha_size_plt_section (info); - } - /* else we're not dynamic and by definition we don't need such things. */ - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - relplt = FALSE; - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if (!(s->flags & SEC_LINKER_CREATED)) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - if (strcmp (name, ".rela.plt") == 0) - relplt = TRUE; - else - 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 if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".plt") != 0 - && strcmp (name, ".dynbss") != 0) - { - /* It's not one of our dynamic 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 to handle .rela.bss and .rela.plt. We must create it - in create_dynamic_sections, because it 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 (!CONST_STRNEQ (name, ".got")) - s->flags |= SEC_EXCLUDE; - } - else if ((s->flags & SEC_HAS_CONTENTS) != 0) - { - /* Allocate memory for the section contents. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in elf64_alpha_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (relplt) - { - 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 (elf64_alpha_use_secureplt - && !add_dynamic_entry (DT_ALPHA_PLTRO, 1)) - 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 (info->flags & DF_TEXTREL) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* These functions do relaxation for Alpha ELF. - - Currently I'm only handling what I can do with existing compiler - and assembler support, which means no instructions are removed, - though some may be nopped. At this time GCC does not emit enough - information to do all of the relaxing that is possible. It will - take some not small amount of work for that to happen. - - There are a couple of interesting papers that I once read on this - subject, that I cannot find references to at the moment, that - related to Alpha in particular. They are by David Wall, then of - DEC WRL. */ - -struct alpha_relax_info -{ - bfd *abfd; - asection *sec; - bfd_byte *contents; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *relocs, *relend; - struct bfd_link_info *link_info; - bfd_vma gp; - bfd *gotobj; - asection *tsec; - struct alpha_elf_link_hash_entry *h; - struct alpha_elf_got_entry **first_gotent; - struct alpha_elf_got_entry *gotent; - bfd_boolean changed_contents; - bfd_boolean changed_relocs; - unsigned char other; -}; - -static Elf_Internal_Rela * -elf64_alpha_find_reloc_at_ofs (Elf_Internal_Rela *rel, - Elf_Internal_Rela *relend, - bfd_vma offset, int type) -{ - while (rel < relend) - { - if (rel->r_offset == offset - && ELF64_R_TYPE (rel->r_info) == (unsigned int) type) - return rel; - ++rel; - } - return NULL; -} - -static bfd_boolean -elf64_alpha_relax_got_load (struct alpha_relax_info *info, bfd_vma symval, - Elf_Internal_Rela *irel, unsigned long r_type) -{ - unsigned int insn; - bfd_signed_vma disp; - - /* Get the instruction. */ - insn = bfd_get_32 (info->abfd, info->contents + irel->r_offset); - - if (insn >> 26 != OP_LDQ) - { - reloc_howto_type *howto = elf64_alpha_howto_table + r_type; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %A+%#Lx: warning: %s relocation against unexpected insn"), - info->abfd, info->sec, irel->r_offset, howto->name); - return TRUE; - } - - /* Can't relax dynamic symbols. */ - if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info)) - return TRUE; - - /* Can't use local-exec relocations in shared libraries. */ - if (r_type == R_ALPHA_GOTTPREL - && bfd_link_dll (info->link_info)) - return TRUE; - - if (r_type == R_ALPHA_LITERAL) - { - /* Look for nice constant addresses. This includes the not-uncommon - special case of 0 for undefweak symbols. */ - if ((info->h && info->h->root.root.type == bfd_link_hash_undefweak) - || (!bfd_link_pic (info->link_info) - && (symval >= (bfd_vma)-0x8000 || symval < 0x8000))) - { - disp = 0; - insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16); - insn |= (symval & 0xffff); - r_type = R_ALPHA_NONE; - } - else - { - /* We may only create GPREL relocs during the second pass. */ - if (info->link_info->relax_pass == 0) - return TRUE; - - disp = symval - info->gp; - insn = (OP_LDA << 26) | (insn & 0x03ff0000); - r_type = R_ALPHA_GPREL16; - } - } - else - { - bfd_vma dtp_base, tp_base; - - BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL); - dtp_base = alpha_get_dtprel_base (info->link_info); - tp_base = alpha_get_tprel_base (info->link_info); - disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base); - - insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16); - - switch (r_type) - { - case R_ALPHA_GOTDTPREL: - r_type = R_ALPHA_DTPREL16; - break; - case R_ALPHA_GOTTPREL: - r_type = R_ALPHA_TPREL16; - break; - default: - BFD_ASSERT (0); - return FALSE; - } - } - - if (disp < -0x8000 || disp >= 0x8000) - return TRUE; - - bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset); - info->changed_contents = TRUE; - - /* Reduce the use count on this got entry by one, possibly - eliminating it. */ - if (--info->gotent->use_count == 0) - { - int sz = alpha_got_entry_size (r_type); - alpha_elf_tdata (info->gotobj)->total_got_size -= sz; - if (!info->h) - alpha_elf_tdata (info->gotobj)->local_got_size -= sz; - } - - /* Smash the existing GOT relocation for its 16-bit immediate pair. */ - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type); - info->changed_relocs = TRUE; - - /* ??? Search forward through this basic block looking for insns - that use the target register. Stop after an insn modifying the - register is seen, or after a branch or call. - - Any such memory load insn may be substituted by a load directly - off the GP. This allows the memory load insn to be issued before - the calculated GP register would otherwise be ready. - - Any such jsr insn can be replaced by a bsr if it is in range. - - This would mean that we'd have to _add_ relocations, the pain of - which gives one pause. */ - - return TRUE; -} - -static bfd_vma -elf64_alpha_relax_opt_call (struct alpha_relax_info *info, bfd_vma symval) -{ - /* If the function has the same gp, and we can identify that the - function does not use its function pointer, we can eliminate the - address load. */ - - /* If the symbol is marked NOPV, we are being told the function never - needs its procedure value. */ - if ((info->other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_NOPV) - return symval; - - /* If the symbol is marked STD_GP, we are being told the function does - a normal ldgp in the first two words. */ - else if ((info->other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_STD_GPLOAD) - ; - - /* Otherwise, we may be able to identify a GP load in the first two - words, which we can then skip. */ - else - { - Elf_Internal_Rela *tsec_relocs, *tsec_relend, *tsec_free, *gpdisp; - bfd_vma ofs; - - /* Load the relocations from the section that the target symbol is in. */ - if (info->sec == info->tsec) - { - tsec_relocs = info->relocs; - tsec_relend = info->relend; - tsec_free = NULL; - } - else - { - tsec_relocs = (_bfd_elf_link_read_relocs - (info->abfd, info->tsec, NULL, - (Elf_Internal_Rela *) NULL, - info->link_info->keep_memory)); - if (tsec_relocs == NULL) - return 0; - tsec_relend = tsec_relocs + info->tsec->reloc_count; - tsec_free = (elf_section_data (info->tsec)->relocs == tsec_relocs - ? NULL - : tsec_relocs); - } - - /* Recover the symbol's offset within the section. */ - ofs = (symval - info->tsec->output_section->vma - - info->tsec->output_offset); - - /* Look for a GPDISP reloc. */ - gpdisp = (elf64_alpha_find_reloc_at_ofs - (tsec_relocs, tsec_relend, ofs, R_ALPHA_GPDISP)); - - if (!gpdisp || gpdisp->r_addend != 4) - { - if (tsec_free) - free (tsec_free); - return 0; - } - if (tsec_free) - free (tsec_free); - } - - /* We've now determined that we can skip an initial gp load. Verify - that the call and the target use the same gp. */ - if (info->link_info->output_bfd->xvec != info->tsec->owner->xvec - || info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj) - return 0; - - return symval + 8; -} - -static bfd_boolean -elf64_alpha_relax_with_lituse (struct alpha_relax_info *info, - bfd_vma symval, Elf_Internal_Rela *irel) -{ - Elf_Internal_Rela *urel, *erel, *irelend = info->relend; - int flags; - bfd_signed_vma disp; - bfd_boolean fits16; - bfd_boolean fits32; - bfd_boolean lit_reused = FALSE; - bfd_boolean all_optimized = TRUE; - bfd_boolean changed_contents; - bfd_boolean changed_relocs; - bfd_byte *contents = info->contents; - bfd *abfd = info->abfd; - bfd_vma sec_output_vma; - unsigned int lit_insn; - int relax_pass; - - lit_insn = bfd_get_32 (abfd, contents + irel->r_offset); - if (lit_insn >> 26 != OP_LDQ) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: %A+%#Lx: warning: LITERAL relocation against unexpected insn"), - abfd, info->sec, irel->r_offset); - return TRUE; - } - - /* Can't relax dynamic symbols. */ - if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info)) - return TRUE; - - changed_contents = info->changed_contents; - changed_relocs = info->changed_relocs; - sec_output_vma = info->sec->output_section->vma + info->sec->output_offset; - relax_pass = info->link_info->relax_pass; - - /* Summarize how this particular LITERAL is used. */ - for (erel = irel+1, flags = 0; erel < irelend; ++erel) - { - if (ELF64_R_TYPE (erel->r_info) != R_ALPHA_LITUSE) - break; - if (erel->r_addend <= 6) - flags |= 1 << erel->r_addend; - } - - /* A little preparation for the loop... */ - disp = symval - info->gp; - - for (urel = irel+1; urel < erel; ++urel) - { - bfd_vma urel_r_offset = urel->r_offset; - unsigned int insn; - int insn_disp; - bfd_signed_vma xdisp; - Elf_Internal_Rela nrel; - - insn = bfd_get_32 (abfd, contents + urel_r_offset); - - switch (urel->r_addend) - { - case LITUSE_ALPHA_ADDR: - default: - /* This type is really just a placeholder to note that all - uses cannot be optimized, but to still allow some. */ - all_optimized = FALSE; - break; - - case LITUSE_ALPHA_BASE: - /* We may only create GPREL relocs during the second pass. */ - if (relax_pass == 0) - { - all_optimized = FALSE; - break; - } - - /* We can always optimize 16-bit displacements. */ - - /* Extract the displacement from the instruction, sign-extending - it if necessary, then test whether it is within 16 or 32 bits - displacement from GP. */ - insn_disp = ((insn & 0xffff) ^ 0x8000) - 0x8000; - - xdisp = disp + insn_disp; - fits16 = (xdisp >= - (bfd_signed_vma) 0x8000 && xdisp < 0x8000); - fits32 = (xdisp >= - (bfd_signed_vma) 0x80000000 - && xdisp < 0x7fff8000); - - if (fits16) - { - /* Take the op code and dest from this insn, take the base - register from the literal insn. Leave the offset alone. */ - insn = (insn & 0xffe0ffff) | (lit_insn & 0x001f0000); - bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset); - changed_contents = TRUE; - - nrel = *urel; - nrel.r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_ALPHA_GPREL16); - nrel.r_addend = irel->r_addend; - - /* As we adjust, move the reloc to the end so that we don't - break the LITERAL+LITUSE chain. */ - if (urel < --erel) - *urel-- = *erel; - *erel = nrel; - changed_relocs = TRUE; - } - - /* If all mem+byte, we can optimize 32-bit mem displacements. */ - else if (fits32 && !(flags & ~6)) - { - /* FIXME: sanity check that lit insn Ra is mem insn Rb. */ - - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_ALPHA_GPRELHIGH); - lit_insn = (OP_LDAH << 26) | (lit_insn & 0x03ff0000); - bfd_put_32 (abfd, (bfd_vma) lit_insn, contents + irel->r_offset); - lit_reused = TRUE; - changed_contents = TRUE; - - /* Since all relocs must be optimized, don't bother swapping - this relocation to the end. */ - urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_ALPHA_GPRELLOW); - urel->r_addend = irel->r_addend; - changed_relocs = TRUE; - } - else - all_optimized = FALSE; - break; - - case LITUSE_ALPHA_BYTOFF: - /* We can always optimize byte instructions. */ - - /* FIXME: sanity check the insn for byte op. Check that the - literal dest reg is indeed Rb in the byte insn. */ - - insn &= ~ (unsigned) 0x001ff000; - insn |= ((symval & 7) << 13) | 0x1000; - bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset); - changed_contents = TRUE; - - nrel = *urel; - nrel.r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - nrel.r_addend = 0; - - /* As we adjust, move the reloc to the end so that we don't - break the LITERAL+LITUSE chain. */ - if (urel < --erel) - *urel-- = *erel; - *erel = nrel; - changed_relocs = TRUE; - break; - - case LITUSE_ALPHA_JSR: - case LITUSE_ALPHA_TLSGD: - case LITUSE_ALPHA_TLSLDM: - case LITUSE_ALPHA_JSRDIRECT: - { - bfd_vma optdest, org; - bfd_signed_vma odisp; - - /* For undefined weak symbols, we're mostly interested in getting - rid of the got entry whenever possible, so optimize this to a - use of the zero register. */ - if (info->h && info->h->root.root.type == bfd_link_hash_undefweak) - { - insn |= 31 << 16; - bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset); - - changed_contents = TRUE; - break; - } - - /* If not zero, place to jump without needing pv. */ - optdest = elf64_alpha_relax_opt_call (info, symval); - org = sec_output_vma + urel_r_offset + 4; - odisp = (optdest ? optdest : symval) - org; - - if (odisp >= -0x400000 && odisp < 0x400000) - { - Elf_Internal_Rela *xrel; - - /* Preserve branch prediction call stack when possible. */ - if ((insn & INSN_JSR_MASK) == INSN_JSR) - insn = (OP_BSR << 26) | (insn & 0x03e00000); - else - insn = (OP_BR << 26) | (insn & 0x03e00000); - bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset); - changed_contents = TRUE; - - nrel = *urel; - nrel.r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_ALPHA_BRADDR); - nrel.r_addend = irel->r_addend; - - if (optdest) - nrel.r_addend += optdest - symval; - else - all_optimized = FALSE; - - /* Kill any HINT reloc that might exist for this insn. */ - xrel = (elf64_alpha_find_reloc_at_ofs - (info->relocs, info->relend, urel_r_offset, - R_ALPHA_HINT)); - if (xrel) - xrel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - - /* As we adjust, move the reloc to the end so that we don't - break the LITERAL+LITUSE chain. */ - if (urel < --erel) - *urel-- = *erel; - *erel = nrel; - - info->changed_relocs = TRUE; - } - else - all_optimized = FALSE; - - /* Even if the target is not in range for a direct branch, - if we share a GP, we can eliminate the gp reload. */ - if (optdest) - { - Elf_Internal_Rela *gpdisp - = (elf64_alpha_find_reloc_at_ofs - (info->relocs, irelend, urel_r_offset + 4, - R_ALPHA_GPDISP)); - if (gpdisp) - { - bfd_byte *p_ldah = contents + gpdisp->r_offset; - bfd_byte *p_lda = p_ldah + gpdisp->r_addend; - unsigned int ldah = bfd_get_32 (abfd, p_ldah); - unsigned int lda = bfd_get_32 (abfd, p_lda); - - /* Verify that the instruction is "ldah $29,0($26)". - Consider a function that ends in a noreturn call, - and that the next function begins with an ldgp, - and that by accident there is no padding between. - In that case the insn would use $27 as the base. */ - if (ldah == 0x27ba0000 && lda == 0x23bd0000) - { - bfd_put_32 (abfd, (bfd_vma) INSN_UNOP, p_ldah); - bfd_put_32 (abfd, (bfd_vma) INSN_UNOP, p_lda); - - gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - changed_contents = TRUE; - changed_relocs = TRUE; - } - } - } - } - break; - } - } - - /* If we reused the literal instruction, we must have optimized all. */ - BFD_ASSERT(!lit_reused || all_optimized); - - /* If all cases were optimized, we can reduce the use count on this - got entry by one, possibly eliminating it. */ - if (all_optimized) - { - if (--info->gotent->use_count == 0) - { - int sz = alpha_got_entry_size (R_ALPHA_LITERAL); - alpha_elf_tdata (info->gotobj)->total_got_size -= sz; - if (!info->h) - alpha_elf_tdata (info->gotobj)->local_got_size -= sz; - } - - /* If the literal instruction is no longer needed (it may have been - reused. We can eliminate it. */ - /* ??? For now, I don't want to deal with compacting the section, - so just nop it out. */ - if (!lit_reused) - { - irel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - changed_relocs = TRUE; - - bfd_put_32 (abfd, (bfd_vma) INSN_UNOP, contents + irel->r_offset); - changed_contents = TRUE; - } - } - - info->changed_contents = changed_contents; - info->changed_relocs = changed_relocs; - - if (all_optimized || relax_pass == 0) - return TRUE; - return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL); -} - -static bfd_boolean -elf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval, - Elf_Internal_Rela *irel, bfd_boolean is_gd) -{ - bfd_byte *pos[5]; - unsigned int insn, tlsgd_reg; - Elf_Internal_Rela *gpdisp, *hint; - bfd_boolean dynamic, use_gottprel; - unsigned long new_symndx; - - dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info); - - /* If a TLS symbol is accessed using IE at least once, there is no point - to use dynamic model for it. */ - if (is_gd && info->h && (info->h->flags & ALPHA_ELF_LINK_HASH_TLS_IE)) - ; - - /* If the symbol is local, and we've already committed to DF_STATIC_TLS, - then we might as well relax to IE. */ - else if (bfd_link_pic (info->link_info) && !dynamic - && (info->link_info->flags & DF_STATIC_TLS)) - ; - - /* Otherwise we must be building an executable to do anything. */ - else if (bfd_link_pic (info->link_info)) - return TRUE; - - /* The TLSGD/TLSLDM relocation must be followed by a LITERAL and - the matching LITUSE_TLS relocations. */ - if (irel + 2 >= info->relend) - return TRUE; - if (ELF64_R_TYPE (irel[1].r_info) != R_ALPHA_LITERAL - || ELF64_R_TYPE (irel[2].r_info) != R_ALPHA_LITUSE - || irel[2].r_addend != (is_gd ? LITUSE_ALPHA_TLSGD : LITUSE_ALPHA_TLSLDM)) - return TRUE; - - /* There must be a GPDISP relocation positioned immediately after the - LITUSE relocation. */ - gpdisp = elf64_alpha_find_reloc_at_ofs (info->relocs, info->relend, - irel[2].r_offset + 4, R_ALPHA_GPDISP); - if (!gpdisp) - return TRUE; - - pos[0] = info->contents + irel[0].r_offset; - pos[1] = info->contents + irel[1].r_offset; - pos[2] = info->contents + irel[2].r_offset; - pos[3] = info->contents + gpdisp->r_offset; - pos[4] = pos[3] + gpdisp->r_addend; - - /* Beware of the compiler hoisting part of the sequence out a loop - and adjusting the destination register for the TLSGD insn. If this - happens, there will be a move into $16 before the JSR insn, so only - transformations of the first insn pair should use this register. */ - tlsgd_reg = bfd_get_32 (info->abfd, pos[0]); - tlsgd_reg = (tlsgd_reg >> 21) & 31; - - /* Generally, the positions are not allowed to be out of order, lest the - modified insn sequence have different register lifetimes. We can make - an exception when pos 1 is adjacent to pos 0. */ - if (pos[1] + 4 == pos[0]) - { - bfd_byte *tmp = pos[0]; - pos[0] = pos[1]; - pos[1] = tmp; - } - if (pos[1] >= pos[2] || pos[2] >= pos[3]) - return TRUE; - - /* Reduce the use count on the LITERAL relocation. Do this before we - smash the symndx when we adjust the relocations below. */ - { - struct alpha_elf_got_entry *lit_gotent; - struct alpha_elf_link_hash_entry *lit_h; - unsigned long indx; - - BFD_ASSERT (ELF64_R_SYM (irel[1].r_info) >= info->symtab_hdr->sh_info); - indx = ELF64_R_SYM (irel[1].r_info) - info->symtab_hdr->sh_info; - lit_h = alpha_elf_sym_hashes (info->abfd)[indx]; - - while (lit_h->root.root.type == bfd_link_hash_indirect - || lit_h->root.root.type == bfd_link_hash_warning) - lit_h = (struct alpha_elf_link_hash_entry *) lit_h->root.root.u.i.link; - - for (lit_gotent = lit_h->got_entries; lit_gotent ; - lit_gotent = lit_gotent->next) - if (lit_gotent->gotobj == info->gotobj - && lit_gotent->reloc_type == R_ALPHA_LITERAL - && lit_gotent->addend == irel[1].r_addend) - break; - BFD_ASSERT (lit_gotent); - - if (--lit_gotent->use_count == 0) - { - int sz = alpha_got_entry_size (R_ALPHA_LITERAL); - alpha_elf_tdata (info->gotobj)->total_got_size -= sz; - } - } - - /* Change - - lda $16,x($gp) !tlsgd!1 - ldq $27,__tls_get_addr($gp) !literal!1 - jsr $26,($27),__tls_get_addr !lituse_tlsgd!1 - ldah $29,0($26) !gpdisp!2 - lda $29,0($29) !gpdisp!2 - to - ldq $16,x($gp) !gottprel - unop - call_pal rduniq - addq $16,$0,$0 - unop - or the first pair to - lda $16,x($gp) !tprel - unop - or - ldah $16,x($gp) !tprelhi - lda $16,x($16) !tprello - - as appropriate. */ - - use_gottprel = FALSE; - new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF; - - /* Some compilers warn about a Boolean-looking expression being - used in a switch. The explicit cast silences them. */ - switch ((int) (!dynamic && !bfd_link_pic (info->link_info))) - { - case 1: - { - bfd_vma tp_base; - bfd_signed_vma disp; - - BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL); - tp_base = alpha_get_tprel_base (info->link_info); - disp = symval - tp_base; - - if (disp >= -0x8000 && disp < 0x8000) - { - insn = (OP_LDA << 26) | (tlsgd_reg << 21) | (31 << 16); - bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]); - bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]); - - irel[0].r_offset = pos[0] - info->contents; - irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPREL16); - irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - break; - } - else if (disp >= -(bfd_signed_vma) 0x80000000 - && disp < (bfd_signed_vma) 0x7fff8000 - && pos[0] + 4 == pos[1]) - { - insn = (OP_LDAH << 26) | (tlsgd_reg << 21) | (31 << 16); - bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]); - insn = (OP_LDA << 26) | (tlsgd_reg << 21) | (tlsgd_reg << 16); - bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]); - - irel[0].r_offset = pos[0] - info->contents; - irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELHI); - irel[1].r_offset = pos[1] - info->contents; - irel[1].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELLO); - break; - } - } - /* FALLTHRU */ - - default: - use_gottprel = TRUE; - - insn = (OP_LDQ << 26) | (tlsgd_reg << 21) | (29 << 16); - bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]); - bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]); - - irel[0].r_offset = pos[0] - info->contents; - irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_GOTTPREL); - irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - break; - } - - bfd_put_32 (info->abfd, (bfd_vma) INSN_RDUNIQ, pos[2]); - - insn = INSN_ADDQ | (16 << 21) | (0 << 16) | (0 << 0); - bfd_put_32 (info->abfd, (bfd_vma) insn, pos[3]); - - bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[4]); - - irel[2].r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - - hint = elf64_alpha_find_reloc_at_ofs (info->relocs, info->relend, - irel[2].r_offset, R_ALPHA_HINT); - if (hint) - hint->r_info = ELF64_R_INFO (0, R_ALPHA_NONE); - - info->changed_contents = TRUE; - info->changed_relocs = TRUE; - - /* Reduce the use count on the TLSGD/TLSLDM relocation. */ - if (--info->gotent->use_count == 0) - { - int sz = alpha_got_entry_size (info->gotent->reloc_type); - alpha_elf_tdata (info->gotobj)->total_got_size -= sz; - if (!info->h) - alpha_elf_tdata (info->gotobj)->local_got_size -= sz; - } - - /* If we've switched to a GOTTPREL relocation, increment the reference - count on that got entry. */ - if (use_gottprel) - { - struct alpha_elf_got_entry *tprel_gotent; - - for (tprel_gotent = *info->first_gotent; tprel_gotent ; - tprel_gotent = tprel_gotent->next) - if (tprel_gotent->gotobj == info->gotobj - && tprel_gotent->reloc_type == R_ALPHA_GOTTPREL - && tprel_gotent->addend == irel->r_addend) - break; - if (tprel_gotent) - tprel_gotent->use_count++; - else - { - if (info->gotent->use_count == 0) - tprel_gotent = info->gotent; - else - { - tprel_gotent = (struct alpha_elf_got_entry *) - bfd_alloc (info->abfd, sizeof (struct alpha_elf_got_entry)); - if (!tprel_gotent) - return FALSE; - - tprel_gotent->next = *info->first_gotent; - *info->first_gotent = tprel_gotent; - - tprel_gotent->gotobj = info->gotobj; - tprel_gotent->addend = irel->r_addend; - tprel_gotent->got_offset = -1; - tprel_gotent->reloc_done = 0; - tprel_gotent->reloc_xlated = 0; - } - - tprel_gotent->use_count = 1; - tprel_gotent->reloc_type = R_ALPHA_GOTTPREL; - } - } - - return TRUE; -} - -static bfd_boolean -elf64_alpha_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - Elf_Internal_Sym *isymbuf = NULL; - struct alpha_elf_got_entry **local_got_entries; - struct alpha_relax_info info; - struct alpha_elf_link_hash_table * htab; - int relax_pass; - - htab = alpha_elf_hash_table (link_info); - if (htab == NULL) - return FALSE; - - /* There's nothing to change, yet. */ - *again = FALSE; - - if (bfd_link_relocatable (link_info) - || ((sec->flags & (SEC_CODE | SEC_RELOC | SEC_ALLOC)) - != (SEC_CODE | SEC_RELOC | SEC_ALLOC)) - || sec->reloc_count == 0) - return TRUE; - - BFD_ASSERT (is_alpha_elf (abfd)); - relax_pass = link_info->relax_pass; - - /* Make sure our GOT and PLT tables are up-to-date. */ - if (htab->relax_trip != link_info->relax_trip) - { - htab->relax_trip = link_info->relax_trip; - - /* This should never fail after the initial round, since the only error - is GOT overflow, and relaxation only shrinks the table. However, we - may only merge got sections during the first pass. If we merge - sections after we've created GPREL relocs, the GP for the merged - section backs up which may put the relocs out of range. */ - if (!elf64_alpha_size_got_sections (link_info, relax_pass == 0)) - abort (); - if (elf_hash_table (link_info)->dynamic_sections_created) - { - elf64_alpha_size_plt_section (link_info); - elf64_alpha_size_rela_got_section (link_info); - } - } - - symtab_hdr = &elf_symtab_hdr (abfd); - local_got_entries = alpha_elf_tdata(abfd)->local_got_entries; - - /* Load the relocations for this section. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - return FALSE; - - memset(&info, 0, sizeof (info)); - info.abfd = abfd; - info.sec = sec; - info.link_info = link_info; - info.symtab_hdr = symtab_hdr; - info.relocs = internal_relocs; - info.relend = irelend = internal_relocs + sec->reloc_count; - - /* Find the GP for this object. Do not store the result back via - _bfd_set_gp_value, since this could change again before final. */ - info.gotobj = alpha_elf_tdata (abfd)->gotobj; - if (info.gotobj) - { - asection *sgot = alpha_elf_tdata (info.gotobj)->got; - info.gp = (sgot->output_section->vma - + sgot->output_offset - + 0x8000); - } - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - info.contents = elf_section_data (sec)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, &info.contents)) - goto error_return; - } - - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - struct alpha_elf_got_entry *gotent; - unsigned long r_type = ELF64_R_TYPE (irel->r_info); - unsigned long r_symndx = ELF64_R_SYM (irel->r_info); - - /* Early exit for unhandled or unrelaxable relocations. */ - if (r_type != R_ALPHA_LITERAL) - { - /* We complete everything except LITERAL in the first pass. */ - if (relax_pass != 0) - continue; - if (r_type == R_ALPHA_TLSLDM) - { - /* The symbol for a TLSLDM reloc is ignored. Collapse the - reloc to the STN_UNDEF (0) symbol so that they all match. */ - r_symndx = STN_UNDEF; - } - else if (r_type != R_ALPHA_GOTDTPREL - && r_type != R_ALPHA_GOTTPREL - && r_type != R_ALPHA_TLSGD) - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - isym = isymbuf + r_symndx; - - /* Given the symbol for a TLSLDM reloc is ignored, this also - means forcing the symbol value to the tp base. */ - if (r_type == R_ALPHA_TLSLDM) - { - info.tsec = bfd_abs_section_ptr; - symval = alpha_get_tprel_base (info.link_info); - } - else - { - symval = isym->st_value; - if (isym->st_shndx == SHN_UNDEF) - continue; - else if (isym->st_shndx == SHN_ABS) - info.tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - info.tsec = bfd_com_section_ptr; - else - info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - } - - info.h = NULL; - info.other = isym->st_other; - if (local_got_entries) - info.first_gotent = &local_got_entries[r_symndx]; - else - { - info.first_gotent = &info.gotent; - info.gotent = NULL; - } - } - else - { - unsigned long indx; - struct alpha_elf_link_hash_entry *h; - - indx = r_symndx - symtab_hdr->sh_info; - h = alpha_elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - while (h->root.root.type == bfd_link_hash_indirect - || h->root.root.type == bfd_link_hash_warning) - h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link; - - /* If the symbol is undefined, we can't do anything with it. */ - if (h->root.root.type == bfd_link_hash_undefined) - continue; - - /* If the symbol isn't defined in the current module, - again we can't do anything. */ - if (h->root.root.type == bfd_link_hash_undefweak) - { - info.tsec = bfd_abs_section_ptr; - symval = 0; - } - else if (!h->root.def_regular) - { - /* Except for TLSGD relocs, which can sometimes be - relaxed to GOTTPREL relocs. */ - if (r_type != R_ALPHA_TLSGD) - continue; - info.tsec = bfd_abs_section_ptr; - symval = 0; - } - else - { - info.tsec = h->root.root.u.def.section; - symval = h->root.root.u.def.value; - } - - info.h = h; - info.other = h->root.other; - info.first_gotent = &h->got_entries; - } - - /* Search for the got entry to be used by this relocation. */ - for (gotent = *info.first_gotent; gotent ; gotent = gotent->next) - if (gotent->gotobj == info.gotobj - && gotent->reloc_type == r_type - && gotent->addend == irel->r_addend) - break; - info.gotent = gotent; - - symval += info.tsec->output_section->vma + info.tsec->output_offset; - symval += irel->r_addend; - - switch (r_type) - { - case R_ALPHA_LITERAL: - BFD_ASSERT(info.gotent != NULL); - - /* If there exist LITUSE relocations immediately following, this - opens up all sorts of interesting optimizations, because we - now know every location that this address load is used. */ - if (irel+1 < irelend - && ELF64_R_TYPE (irel[1].r_info) == R_ALPHA_LITUSE) - { - if (!elf64_alpha_relax_with_lituse (&info, symval, irel)) - goto error_return; - } - else - { - if (!elf64_alpha_relax_got_load (&info, symval, irel, r_type)) - goto error_return; - } - break; - - case R_ALPHA_GOTDTPREL: - case R_ALPHA_GOTTPREL: - BFD_ASSERT(info.gotent != NULL); - if (!elf64_alpha_relax_got_load (&info, symval, irel, r_type)) - goto error_return; - break; - - case R_ALPHA_TLSGD: - case R_ALPHA_TLSLDM: - BFD_ASSERT(info.gotent != NULL); - if (!elf64_alpha_relax_tls_get_addr (&info, symval, irel, - r_type == R_ALPHA_TLSGD)) - goto error_return; - break; - } - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (!link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (info.contents != NULL - && elf_section_data (sec)->this_hdr.contents != info.contents) - { - if (!info.changed_contents && !link_info->keep_memory) - free (info.contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = info.contents; - } - } - - if (elf_section_data (sec)->relocs != internal_relocs) - { - if (!info.changed_relocs) - free (internal_relocs); - else - elf_section_data (sec)->relocs = internal_relocs; - } - - *again = info.changed_contents || info.changed_relocs; - - return TRUE; - - error_return: - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (info.contents != NULL - && elf_section_data (sec)->this_hdr.contents != info.contents) - free (info.contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -/* Emit a dynamic relocation for (DYNINDX, RTYPE, ADDEND) at (SEC, OFFSET) - into the next available slot in SREL. */ - -static void -elf64_alpha_emit_dynrel (bfd *abfd, struct bfd_link_info *info, - asection *sec, asection *srel, bfd_vma offset, - long dynindx, long rtype, bfd_vma addend) -{ - Elf_Internal_Rela outrel; - bfd_byte *loc; - - BFD_ASSERT (srel != NULL); - - outrel.r_info = ELF64_R_INFO (dynindx, rtype); - outrel.r_addend = addend; - - offset = _bfd_elf_section_offset (abfd, info, sec, offset); - if ((offset | 1) != (bfd_vma) -1) - outrel.r_offset = sec->output_section->vma + sec->output_offset + offset; - else - memset (&outrel, 0, sizeof (outrel)); - - loc = srel->contents; - loc += srel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (abfd, &outrel, loc); - BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count <= srel->size); -} - -/* Relocate an Alpha ELF section for 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. */ - -static bfd_boolean -elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *input_bfd, asection *input_section, - bfd_byte *contents ATTRIBUTE_UNUSED, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - unsigned long symtab_hdr_sh_info; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - struct elf_link_hash_entry **sym_hashes; - bfd_boolean ret_val = TRUE; - - symtab_hdr_sh_info = elf_symtab_hdr (input_bfd).sh_info; - sym_hashes = elf_sym_hashes (input_bfd); - - relend = relocs + input_section->reloc_count; - for (rel = relocs; rel < relend; rel++) - { - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - unsigned long r_type; - - r_type = ELF64_R_TYPE (rel->r_info); - if (r_type >= R_ALPHA_max) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - ret_val = FALSE; - continue; - } - - /* The symbol associated with GPDISP and LITUSE is - immaterial. Only the addend is significant. */ - if (r_type == R_ALPHA_GPDISP || r_type == R_ALPHA_LITUSE) - continue; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr_sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - } - else - { - struct elf_link_hash_entry *h; - - h = sym_hashes[r_symndx - symtab_hdr_sh_info]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - continue; - - sym = NULL; - sec = h->root.u.def.section; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, - elf64_alpha_howto_table + r_type, 0, - contents); - - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - } - - return ret_val; -} - -/* Relocate an Alpha ELF section. */ - -static bfd_boolean -elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - asection *sgot, *srel, *srelgot; - bfd *dynobj, *gotobj; - bfd_vma gp, tp_base, dtp_base; - struct alpha_elf_got_entry **local_got_entries; - bfd_boolean ret_val; - - BFD_ASSERT (is_alpha_elf (input_bfd)); - - /* Handle relocatable links with a smaller loop. */ - if (bfd_link_relocatable (info)) - return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd, - input_section, contents, relocs, - local_syms, local_sections); - - /* This is a final link. */ - - ret_val = TRUE; - - symtab_hdr = &elf_symtab_hdr (input_bfd); - - dynobj = elf_hash_table (info)->dynobj; - srelgot = elf_hash_table (info)->srelgot; - - if (input_section->flags & SEC_ALLOC) - { - const char *section_name; - section_name = (bfd_elf_string_from_elf_section - (input_bfd, elf_elfheader(input_bfd)->e_shstrndx, - _bfd_elf_single_rel_hdr (input_section)->sh_name)); - BFD_ASSERT(section_name != NULL); - srel = bfd_get_linker_section (dynobj, section_name); - } - else - srel = NULL; - - /* Find the gp value for this input bfd. */ - gotobj = alpha_elf_tdata (input_bfd)->gotobj; - if (gotobj) - { - sgot = alpha_elf_tdata (gotobj)->got; - gp = _bfd_get_gp_value (gotobj); - if (gp == 0) - { - gp = (sgot->output_section->vma - + sgot->output_offset - + 0x8000); - _bfd_set_gp_value (gotobj, gp); - } - } - else - { - sgot = NULL; - gp = 0; - } - - local_got_entries = alpha_elf_tdata(input_bfd)->local_got_entries; - - if (elf_hash_table (info)->tls_sec != NULL) - { - dtp_base = alpha_get_dtprel_base (info); - tp_base = alpha_get_tprel_base (info); - } - else - dtp_base = tp_base = 0; - - relend = relocs + input_section->reloc_count; - for (rel = relocs; rel < relend; rel++) - { - struct alpha_elf_link_hash_entry *h = NULL; - struct alpha_elf_got_entry *gotent; - bfd_reloc_status_type r; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym = NULL; - asection *sec = NULL; - bfd_vma value; - bfd_vma addend; - bfd_boolean dynamic_symbol_p; - bfd_boolean unresolved_reloc = FALSE; - bfd_boolean undef_weak_ref = FALSE; - unsigned long r_type; - - r_type = ELF64_R_TYPE(rel->r_info); - if (r_type >= R_ALPHA_max) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - ret_val = FALSE; - continue; - } - - howto = elf64_alpha_howto_table + r_type; - r_symndx = ELF64_R_SYM(rel->r_info); - - /* The symbol for a TLSLDM reloc is ignored. Collapse the - reloc to the STN_UNDEF (0) symbol so that they all match. */ - if (r_type == R_ALPHA_TLSLDM) - r_symndx = STN_UNDEF; - - if (r_symndx < symtab_hdr->sh_info) - { - asection *msec; - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - msec = sec; - value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); - - /* If this is a tp-relative relocation against sym STN_UNDEF (0), - this is hackery from relax_section. Force the value to - be the tls module base. */ - if (r_symndx == STN_UNDEF - && (r_type == R_ALPHA_TLSLDM - || r_type == R_ALPHA_GOTTPREL - || r_type == R_ALPHA_TPREL64 - || r_type == R_ALPHA_TPRELHI - || r_type == R_ALPHA_TPRELLO - || r_type == R_ALPHA_TPREL16)) - value = dtp_base; - - if (local_got_entries) - gotent = local_got_entries[r_symndx]; - else - gotent = NULL; - - /* Need to adjust local GOT entries' addends for SEC_MERGE - unless it has been done already. */ - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION - && sec->sec_info_type == SEC_INFO_TYPE_MERGE - && gotent - && !gotent->reloc_xlated) - { - struct alpha_elf_got_entry *ent; - - for (ent = gotent; ent; ent = ent->next) - { - ent->reloc_xlated = 1; - if (ent->use_count == 0) - continue; - msec = sec; - ent->addend = - _bfd_merged_section_offset (output_bfd, &msec, - elf_section_data (sec)-> - sec_info, - sym->st_value + ent->addend); - ent->addend -= sym->st_value; - ent->addend += msec->output_section->vma - + msec->output_offset - - sec->output_section->vma - - sec->output_offset; - } - } - - dynamic_symbol_p = FALSE; - } - else - { - bfd_boolean warned, ignored; - struct elf_link_hash_entry *hh; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - hh, sec, value, - unresolved_reloc, warned, ignored); - - if (warned) - continue; - - if (value == 0 - && ! unresolved_reloc - && hh->root.type == bfd_link_hash_undefweak) - undef_weak_ref = TRUE; - - h = (struct alpha_elf_link_hash_entry *) hh; - dynamic_symbol_p = alpha_elf_dynamic_symbol_p (&h->root, info); - gotent = h->got_entries; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - addend = rel->r_addend; - value += addend; - - /* Search for the proper got entry. */ - for (; gotent ; gotent = gotent->next) - if (gotent->gotobj == gotobj - && gotent->reloc_type == r_type - && gotent->addend == addend) - break; - - switch (r_type) - { - case R_ALPHA_GPDISP: - { - bfd_byte *p_ldah, *p_lda; - - BFD_ASSERT(gp != 0); - - value = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); - - p_ldah = contents + rel->r_offset; - p_lda = p_ldah + rel->r_addend; - - r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - value, - p_ldah, p_lda); - } - break; - - case R_ALPHA_LITERAL: - BFD_ASSERT(sgot != NULL); - BFD_ASSERT(gp != 0); - BFD_ASSERT(gotent != NULL); - BFD_ASSERT(gotent->use_count >= 1); - - if (!gotent->reloc_done) - { - gotent->reloc_done = 1; - - bfd_put_64 (output_bfd, value, - sgot->contents + gotent->got_offset); - - /* If the symbol has been forced local, output a - RELATIVE reloc, otherwise it will be handled in - finish_dynamic_symbol. */ - if (bfd_link_pic (info) - && !dynamic_symbol_p - && !undef_weak_ref) - elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot, - gotent->got_offset, 0, - R_ALPHA_RELATIVE, value); - } - - value = (sgot->output_section->vma - + sgot->output_offset - + gotent->got_offset); - value -= gp; - goto default_reloc; - - case R_ALPHA_GPREL32: - case R_ALPHA_GPREL16: - case R_ALPHA_GPRELLOW: - if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: gp-relative relocation against dynamic symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - BFD_ASSERT(gp != 0); - value -= gp; - goto default_reloc; - - case R_ALPHA_GPRELHIGH: - if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: gp-relative relocation against dynamic symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - BFD_ASSERT(gp != 0); - value -= gp; - value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1); - goto default_reloc; - - case R_ALPHA_HINT: - /* A call to a dynamic symbol is definitely out of range of - the 16-bit displacement. Don't bother writing anything. */ - if (dynamic_symbol_p) - { - r = bfd_reloc_ok; - break; - } - /* The regular PC-relative stuff measures from the start of - the instruction rather than the end. */ - value -= 4; - goto default_reloc; - - case R_ALPHA_BRADDR: - if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: pc-relative relocation against dynamic symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - /* The regular PC-relative stuff measures from the start of - the instruction rather than the end. */ - value -= 4; - goto default_reloc; - - case R_ALPHA_BRSGP: - { - int other; - const char *name; - - /* The regular PC-relative stuff measures from the start of - the instruction rather than the end. */ - value -= 4; - - /* The source and destination gp must be the same. Note that - the source will always have an assigned gp, since we forced - one in check_relocs, but that the destination may not, as - it might not have had any relocations at all. Also take - care not to crash if H is an undefined symbol. */ - if (h != NULL && sec != NULL - && alpha_elf_tdata (sec->owner)->gotobj - && gotobj != alpha_elf_tdata (sec->owner)->gotobj) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: change in gp: BRSGP %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - - /* The symbol should be marked either NOPV or STD_GPLOAD. */ - if (h != NULL) - other = h->root.other; - else - other = sym->st_other; - switch (other & STO_ALPHA_STD_GPLOAD) - { - case STO_ALPHA_NOPV: - break; - case STO_ALPHA_STD_GPLOAD: - value += 8; - break; - default: - if (h != NULL) - name = h->root.root.root.string; - else - { - name = (bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name)); - if (name == NULL) - name = _(""); - else if (name[0] == 0) - name = bfd_section_name (input_bfd, sec); - } - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: !samegp reloc against symbol without .prologue: %s"), - input_bfd, name); - ret_val = FALSE; - break; - } - - goto default_reloc; - } - - case R_ALPHA_REFLONG: - case R_ALPHA_REFQUAD: - case R_ALPHA_DTPREL64: - case R_ALPHA_TPREL64: - { - long dynindx, dyntype = r_type; - bfd_vma dynaddend; - - /* Careful here to remember RELATIVE relocations for global - variables for symbolic shared objects. */ - - if (dynamic_symbol_p) - { - BFD_ASSERT(h->root.dynindx != -1); - dynindx = h->root.dynindx; - dynaddend = addend; - addend = 0, value = 0; - } - else if (r_type == R_ALPHA_DTPREL64) - { - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); - value -= dtp_base; - goto default_reloc; - } - else if (r_type == R_ALPHA_TPREL64) - { - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); - if (!bfd_link_dll (info)) - { - value -= tp_base; - goto default_reloc; - } - dynindx = 0; - dynaddend = value - dtp_base; - } - else if (bfd_link_pic (info) - && r_symndx != STN_UNDEF - && (input_section->flags & SEC_ALLOC) - && !undef_weak_ref - && !(unresolved_reloc - && (_bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset) - == (bfd_vma) -1))) - { - if (r_type == R_ALPHA_REFLONG) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unhandled dynamic relocation against %s"), - input_bfd, - h->root.root.root.string); - ret_val = FALSE; - } - dynindx = 0; - dyntype = R_ALPHA_RELATIVE; - dynaddend = value; - } - else - goto default_reloc; - - if (input_section->flags & SEC_ALLOC) - elf64_alpha_emit_dynrel (output_bfd, info, input_section, - srel, rel->r_offset, dynindx, - dyntype, dynaddend); - } - goto default_reloc; - - case R_ALPHA_SREL16: - case R_ALPHA_SREL32: - case R_ALPHA_SREL64: - if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: pc-relative relocation against dynamic symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - else if (bfd_link_pic (info) - && undef_weak_ref) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: pc-relative relocation against undefined weak symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - - - /* ??? .eh_frame references to discarded sections will be smashed - to relocations against SHN_UNDEF. The .eh_frame format allows - NULL to be encoded as 0 in any format, so this works here. */ - if (r_symndx == STN_UNDEF - || (unresolved_reloc - && _bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset) == (bfd_vma) -1)) - howto = (elf64_alpha_howto_table - + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG)); - goto default_reloc; - - case R_ALPHA_TLSLDM: - /* Ignore the symbol for the relocation. The result is always - the current module. */ - dynamic_symbol_p = 0; - /* FALLTHRU */ - - case R_ALPHA_TLSGD: - if (!gotent->reloc_done) - { - gotent->reloc_done = 1; - - /* Note that the module index for the main program is 1. */ - bfd_put_64 (output_bfd, - !bfd_link_pic (info) && !dynamic_symbol_p, - sgot->contents + gotent->got_offset); - - /* If the symbol has been forced local, output a - DTPMOD64 reloc, otherwise it will be handled in - finish_dynamic_symbol. */ - if (bfd_link_pic (info) && !dynamic_symbol_p) - elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot, - gotent->got_offset, 0, - R_ALPHA_DTPMOD64, 0); - - if (dynamic_symbol_p || r_type == R_ALPHA_TLSLDM) - value = 0; - else - { - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); - value -= dtp_base; - } - bfd_put_64 (output_bfd, value, - sgot->contents + gotent->got_offset + 8); - } - - value = (sgot->output_section->vma - + sgot->output_offset - + gotent->got_offset); - value -= gp; - goto default_reloc; - - case R_ALPHA_DTPRELHI: - case R_ALPHA_DTPRELLO: - case R_ALPHA_DTPREL16: - if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: dtp-relative relocation against dynamic symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); - value -= dtp_base; - if (r_type == R_ALPHA_DTPRELHI) - value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1); - goto default_reloc; - - case R_ALPHA_TPRELHI: - case R_ALPHA_TPRELLO: - case R_ALPHA_TPREL16: - if (bfd_link_dll (info)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: TLS local exec code cannot be linked into shared objects"), - input_bfd); - ret_val = FALSE; - } - else if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: tp-relative relocation against dynamic symbol %s"), - input_bfd, h->root.root.root.string); - ret_val = FALSE; - } - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); - value -= tp_base; - if (r_type == R_ALPHA_TPRELHI) - value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1); - goto default_reloc; - - case R_ALPHA_GOTDTPREL: - case R_ALPHA_GOTTPREL: - BFD_ASSERT(sgot != NULL); - BFD_ASSERT(gp != 0); - BFD_ASSERT(gotent != NULL); - BFD_ASSERT(gotent->use_count >= 1); - - if (!gotent->reloc_done) - { - gotent->reloc_done = 1; - - if (dynamic_symbol_p) - value = 0; - else - { - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); - if (r_type == R_ALPHA_GOTDTPREL) - value -= dtp_base; - else if (!bfd_link_pic (info)) - value -= tp_base; - else - { - elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot, - gotent->got_offset, 0, - R_ALPHA_TPREL64, - value - dtp_base); - value = 0; - } - } - bfd_put_64 (output_bfd, value, - sgot->contents + gotent->got_offset); - } - - value = (sgot->output_section->vma - + sgot->output_offset - + gotent->got_offset); - value -= gp; - goto default_reloc; - - default: - default_reloc: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, value, 0); - break; - } - - switch (r) - { - case bfd_reloc_ok: - break; - - case bfd_reloc_overflow: - { - const char *name; - - /* Don't warn if the overflow is due to pc relative reloc - against discarded section. Section optimization code should - handle it. */ - - if (r_symndx < symtab_hdr->sh_info - && sec != NULL && howto->pc_relative - && discarded_section (sec)) - break; - - if (h != NULL) - name = NULL; - 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); - } - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root.root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - } - break; - - default: - case bfd_reloc_outofrange: - abort (); - } - } - - return ret_val; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct alpha_elf_link_hash_entry *ah = (struct alpha_elf_link_hash_entry *)h; - - if (h->needs_plt) - { - /* Fill in the .plt entry for this symbol. */ - asection *splt, *sgot, *srel; - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_vma got_addr, plt_addr; - bfd_vma plt_index; - struct alpha_elf_got_entry *gotent; - - BFD_ASSERT (h->dynindx != -1); - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - srel = elf_hash_table (info)->srelplt; - BFD_ASSERT (srel != NULL); - - for (gotent = ah->got_entries; gotent ; gotent = gotent->next) - if (gotent->reloc_type == R_ALPHA_LITERAL - && gotent->use_count > 0) - { - unsigned int insn; - int disp; - - sgot = alpha_elf_tdata (gotent->gotobj)->got; - BFD_ASSERT (sgot != NULL); - - BFD_ASSERT (gotent->got_offset != -1); - BFD_ASSERT (gotent->plt_offset != -1); - - got_addr = (sgot->output_section->vma - + sgot->output_offset - + gotent->got_offset); - plt_addr = (splt->output_section->vma - + splt->output_offset - + gotent->plt_offset); - - plt_index = (gotent->plt_offset-PLT_HEADER_SIZE) / PLT_ENTRY_SIZE; - - /* Fill in the entry in the procedure linkage table. */ - if (elf64_alpha_use_secureplt) - { - disp = (PLT_HEADER_SIZE - 4) - (gotent->plt_offset + 4); - insn = INSN_AD (INSN_BR, 31, disp); - bfd_put_32 (output_bfd, insn, - splt->contents + gotent->plt_offset); - - plt_index = ((gotent->plt_offset - NEW_PLT_HEADER_SIZE) - / NEW_PLT_ENTRY_SIZE); - } - else - { - disp = -(gotent->plt_offset + 4); - insn = INSN_AD (INSN_BR, 28, disp); - bfd_put_32 (output_bfd, insn, - splt->contents + gotent->plt_offset); - bfd_put_32 (output_bfd, INSN_UNOP, - splt->contents + gotent->plt_offset + 4); - bfd_put_32 (output_bfd, INSN_UNOP, - splt->contents + gotent->plt_offset + 8); - - plt_index = ((gotent->plt_offset - OLD_PLT_HEADER_SIZE) - / OLD_PLT_ENTRY_SIZE); - } - - /* Fill in the entry in the .rela.plt section. */ - outrel.r_offset = got_addr; - outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_JMP_SLOT); - outrel.r_addend = 0; - - loc = srel->contents + plt_index * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - - /* Fill in the entry in the .got. */ - bfd_put_64 (output_bfd, plt_addr, - sgot->contents + gotent->got_offset); - } - } - else if (alpha_elf_dynamic_symbol_p (h, info)) - { - /* Fill in the dynamic relocations for this symbol's .got entries. */ - asection *srel; - struct alpha_elf_got_entry *gotent; - - srel = elf_hash_table (info)->srelgot; - BFD_ASSERT (srel != NULL); - - for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries; - gotent != NULL; - gotent = gotent->next) - { - asection *sgot; - long r_type; - - if (gotent->use_count == 0) - continue; - - sgot = alpha_elf_tdata (gotent->gotobj)->got; - - r_type = gotent->reloc_type; - switch (r_type) - { - case R_ALPHA_LITERAL: - r_type = R_ALPHA_GLOB_DAT; - break; - case R_ALPHA_TLSGD: - r_type = R_ALPHA_DTPMOD64; - break; - case R_ALPHA_GOTDTPREL: - r_type = R_ALPHA_DTPREL64; - break; - case R_ALPHA_GOTTPREL: - r_type = R_ALPHA_TPREL64; - break; - case R_ALPHA_TLSLDM: - default: - abort (); - } - - elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel, - gotent->got_offset, h->dynindx, - r_type, gotent->addend); - - if (gotent->reloc_type == R_ALPHA_TLSGD) - elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel, - gotent->got_offset + 8, h->dynindx, - R_ALPHA_DTPREL64, gotent->addend); - } - } - - /* Mark some specially defined symbols as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot - || h == elf_hash_table (info)->hplt) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf64_alpha_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt, *sgotplt, *srelaplt; - Elf64_External_Dyn *dyncon, *dynconend; - bfd_vma plt_vma, gotplt_vma; - - splt = elf_hash_table (info)->splt; - srelaplt = elf_hash_table (info)->srelplt; - BFD_ASSERT (splt != NULL && sdyn != NULL); - - plt_vma = splt->output_section->vma + splt->output_offset; - - gotplt_vma = 0; - if (elf64_alpha_use_secureplt) - { - sgotplt = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgotplt != NULL); - if (sgotplt->size > 0) - gotplt_vma = sgotplt->output_section->vma + sgotplt->output_offset; - } - - dyncon = (Elf64_External_Dyn *) sdyn->contents; - dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - - bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_PLTGOT: - dyn.d_un.d_ptr - = elf64_alpha_use_secureplt ? gotplt_vma : plt_vma; - break; - case DT_PLTRELSZ: - dyn.d_un.d_val = srelaplt ? srelaplt->size : 0; - break; - case DT_JMPREL: - dyn.d_un.d_ptr = srelaplt ? (srelaplt->output_section->vma - + srelaplt->output_offset) : 0; - break; - } - - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - /* Initialize the plt header. */ - if (splt->size > 0) - { - unsigned int insn; - int ofs; - - if (elf64_alpha_use_secureplt) - { - ofs = gotplt_vma - (plt_vma + PLT_HEADER_SIZE); - - insn = INSN_ABC (INSN_SUBQ, 27, 28, 25); - bfd_put_32 (output_bfd, insn, splt->contents); - - insn = INSN_ABO (INSN_LDAH, 28, 28, (ofs + 0x8000) >> 16); - bfd_put_32 (output_bfd, insn, splt->contents + 4); - - insn = INSN_ABC (INSN_S4SUBQ, 25, 25, 25); - bfd_put_32 (output_bfd, insn, splt->contents + 8); - - insn = INSN_ABO (INSN_LDA, 28, 28, ofs); - bfd_put_32 (output_bfd, insn, splt->contents + 12); - - insn = INSN_ABO (INSN_LDQ, 27, 28, 0); - bfd_put_32 (output_bfd, insn, splt->contents + 16); - - insn = INSN_ABC (INSN_ADDQ, 25, 25, 25); - bfd_put_32 (output_bfd, insn, splt->contents + 20); - - insn = INSN_ABO (INSN_LDQ, 28, 28, 8); - bfd_put_32 (output_bfd, insn, splt->contents + 24); - - insn = INSN_AB (INSN_JMP, 31, 27); - bfd_put_32 (output_bfd, insn, splt->contents + 28); - - insn = INSN_AD (INSN_BR, 28, -PLT_HEADER_SIZE); - bfd_put_32 (output_bfd, insn, splt->contents + 32); - } - else - { - insn = INSN_AD (INSN_BR, 27, 0); /* br $27, .+4 */ - bfd_put_32 (output_bfd, insn, splt->contents); - - insn = INSN_ABO (INSN_LDQ, 27, 27, 12); - bfd_put_32 (output_bfd, insn, splt->contents + 4); - - insn = INSN_UNOP; - bfd_put_32 (output_bfd, insn, splt->contents + 8); - - insn = INSN_AB (INSN_JMP, 27, 27); - bfd_put_32 (output_bfd, insn, splt->contents + 12); - - /* The next two words will be filled in by ld.so. */ - bfd_put_64 (output_bfd, 0, splt->contents + 16); - bfd_put_64 (output_bfd, 0, splt->contents + 24); - } - - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 0; - } - } - - return TRUE; -} - -/* We need to use a special link routine to handle the .mdebug section. - We need to merge all instances of these sections together, not write - them all out sequentially. */ - -static bfd_boolean -elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info) -{ - asection *o; - struct bfd_link_order *p; - asection *mdebug_sec; - struct ecoff_debug_info debug; - const struct ecoff_debug_swap *swap - = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; - HDRR *symhdr = &debug.symbolic_header; - void * mdebug_handle = NULL; - struct alpha_elf_link_hash_table * htab; - - htab = alpha_elf_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Go through the sections and collect the mdebug information. */ - mdebug_sec = NULL; - for (o = abfd->sections; o != (asection *) NULL; o = o->next) - { - if (strcmp (o->name, ".mdebug") == 0) - { - struct extsym_info einfo; - - /* We have found the .mdebug section in the output file. - Look through all the link_orders comprising it and merge - the information together. */ - symhdr->magic = swap->sym_magic; - /* FIXME: What should the version stamp be? */ - symhdr->vstamp = 0; - symhdr->ilineMax = 0; - symhdr->cbLine = 0; - symhdr->idnMax = 0; - symhdr->ipdMax = 0; - symhdr->isymMax = 0; - symhdr->ioptMax = 0; - symhdr->iauxMax = 0; - symhdr->issMax = 0; - symhdr->issExtMax = 0; - symhdr->ifdMax = 0; - symhdr->crfd = 0; - symhdr->iextMax = 0; - - /* We accumulate the debugging information itself in the - debug_info structure. */ - debug.line = NULL; - debug.external_dnr = NULL; - debug.external_pdr = NULL; - debug.external_sym = NULL; - debug.external_opt = NULL; - debug.external_aux = NULL; - debug.ss = NULL; - debug.ssext = debug.ssext_end = NULL; - debug.external_fdr = NULL; - debug.external_rfd = NULL; - debug.external_ext = debug.external_ext_end = NULL; - - mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info); - if (mdebug_handle == NULL) - return FALSE; - - if (1) - { - asection *s; - EXTR esym; - bfd_vma last = 0; - unsigned int i; - static const char * const name[] = - { - ".text", ".init", ".fini", ".data", - ".rodata", ".sdata", ".sbss", ".bss" - }; - static const int sc[] = { scText, scInit, scFini, scData, - scRData, scSData, scSBss, scBss }; - - esym.jmptbl = 0; - esym.cobol_main = 0; - esym.weakext = 0; - esym.reserved = 0; - esym.ifd = ifdNil; - esym.asym.iss = issNil; - esym.asym.st = stLocal; - esym.asym.reserved = 0; - esym.asym.index = indexNil; - for (i = 0; i < 8; i++) - { - esym.asym.sc = sc[i]; - s = bfd_get_section_by_name (abfd, name[i]); - if (s != NULL) - { - esym.asym.value = s->vma; - last = s->vma + s->size; - } - else - esym.asym.value = last; - - if (! bfd_ecoff_debug_one_external (abfd, &debug, swap, - name[i], &esym)) - return FALSE; - } - } - - for (p = o->map_head.link_order; - p != (struct bfd_link_order *) NULL; - p = p->next) - { - asection *input_section; - bfd *input_bfd; - const struct ecoff_debug_swap *input_swap; - struct ecoff_debug_info input_debug; - char *eraw_src; - char *eraw_end; - - if (p->type != bfd_indirect_link_order) - { - if (p->type == bfd_data_link_order) - continue; - abort (); - } - - input_section = p->u.indirect.section; - input_bfd = input_section->owner; - - if (! is_alpha_elf (input_bfd)) - /* I don't know what a non ALPHA ELF bfd would be - doing with a .mdebug section, but I don't really - want to deal with it. */ - continue; - - input_swap = (get_elf_backend_data (input_bfd) - ->elf_backend_ecoff_debug_swap); - - BFD_ASSERT (p->size == input_section->size); - - /* The ECOFF linking code expects that we have already - read in the debugging information and set up an - ecoff_debug_info structure, so we do that now. */ - if (!elf64_alpha_read_ecoff_info (input_bfd, input_section, - &input_debug)) - return FALSE; - - if (! (bfd_ecoff_debug_accumulate - (mdebug_handle, abfd, &debug, swap, input_bfd, - &input_debug, input_swap, info))) - return FALSE; - - /* Loop through the external symbols. For each one with - interesting information, try to find the symbol in - the linker global hash table and save the information - for the output external symbols. */ - eraw_src = (char *) input_debug.external_ext; - eraw_end = (eraw_src - + (input_debug.symbolic_header.iextMax - * input_swap->external_ext_size)); - for (; - eraw_src < eraw_end; - eraw_src += input_swap->external_ext_size) - { - EXTR ext; - const char *name; - struct alpha_elf_link_hash_entry *h; - - (*input_swap->swap_ext_in) (input_bfd, eraw_src, &ext); - if (ext.asym.sc == scNil - || ext.asym.sc == scUndefined - || ext.asym.sc == scSUndefined) - continue; - - name = input_debug.ssext + ext.asym.iss; - h = alpha_elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); - if (h == NULL || h->esym.ifd != -2) - continue; - - if (ext.ifd != -1) - { - BFD_ASSERT (ext.ifd - < input_debug.symbolic_header.ifdMax); - ext.ifd = input_debug.ifdmap[ext.ifd]; - } - - h->esym = ext; - } - - /* Free up the information we just read. */ - free (input_debug.line); - free (input_debug.external_dnr); - free (input_debug.external_pdr); - free (input_debug.external_sym); - free (input_debug.external_opt); - free (input_debug.external_aux); - free (input_debug.ss); - free (input_debug.ssext); - free (input_debug.external_fdr); - free (input_debug.external_rfd); - free (input_debug.external_ext); - - /* Hack: reset the SEC_HAS_CONTENTS flag so that - elf_link_input_bfd ignores this section. */ - input_section->flags &=~ SEC_HAS_CONTENTS; - } - - /* Build the external symbol information. */ - einfo.abfd = abfd; - einfo.info = info; - einfo.debug = &debug; - einfo.swap = swap; - einfo.failed = FALSE; - elf_link_hash_traverse (elf_hash_table (info), - elf64_alpha_output_extsym, - &einfo); - if (einfo.failed) - return FALSE; - - /* Set the size of the .mdebug section. */ - o->size = bfd_ecoff_debug_size (abfd, &debug, swap); - - /* Skip this section later on (I don't think this currently - matters, but someday it might). */ - o->map_head.link_order = (struct bfd_link_order *) NULL; - - mdebug_sec = o; - } - } - - /* Invoke the regular ELF backend linker to do all the work. */ - if (! bfd_elf_final_link (abfd, info)) - return FALSE; - - /* Now write out the computed sections. */ - - /* The .got subsections... */ - { - bfd *i, *dynobj = elf_hash_table(info)->dynobj; - for (i = htab->got_list; - i != NULL; - i = alpha_elf_tdata(i)->got_link_next) - { - asection *sgot; - - /* elf_bfd_final_link already did everything in dynobj. */ - if (i == dynobj) - continue; - - sgot = alpha_elf_tdata(i)->got; - if (! bfd_set_section_contents (abfd, sgot->output_section, - sgot->contents, - (file_ptr) sgot->output_offset, - sgot->size)) - return FALSE; - } - } - - if (mdebug_sec != (asection *) NULL) - { - BFD_ASSERT (abfd->output_has_begun); - if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug, - swap, info, - mdebug_sec->filepos)) - return FALSE; - - bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info); - } - - return TRUE; -} - -static enum elf_reloc_type_class -elf64_alpha_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF64_R_TYPE (rela->r_info)) - { - case R_ALPHA_RELATIVE: - return reloc_class_relative; - case R_ALPHA_JMP_SLOT: - return reloc_class_plt; - case R_ALPHA_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -static const struct bfd_elf_special_section elf64_alpha_special_sections[] = -{ - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL }, - { NULL, 0, 0, 0, 0 } -}; - -/* ECOFF swapping routines. These are used when dealing with the - .mdebug section, which is in the ECOFF debugging format. Copied - from elf32-mips.c. */ -static const struct ecoff_debug_swap -elf64_alpha_ecoff_debug_swap = -{ - /* Symbol table magic number. */ - magicSym2, - /* Alignment of debugging information. E.g., 4. */ - 8, - /* Sizes of external symbolic information. */ - sizeof (struct hdr_ext), - sizeof (struct dnr_ext), - sizeof (struct pdr_ext), - sizeof (struct sym_ext), - sizeof (struct opt_ext), - sizeof (struct fdr_ext), - sizeof (struct rfd_ext), - sizeof (struct ext_ext), - /* Functions to swap in external symbolic data. */ - ecoff_swap_hdr_in, - ecoff_swap_dnr_in, - ecoff_swap_pdr_in, - ecoff_swap_sym_in, - ecoff_swap_opt_in, - ecoff_swap_fdr_in, - ecoff_swap_rfd_in, - ecoff_swap_ext_in, - _bfd_ecoff_swap_tir_in, - _bfd_ecoff_swap_rndx_in, - /* Functions to swap out external symbolic data. */ - ecoff_swap_hdr_out, - ecoff_swap_dnr_out, - ecoff_swap_pdr_out, - ecoff_swap_sym_out, - ecoff_swap_opt_out, - ecoff_swap_fdr_out, - ecoff_swap_rfd_out, - ecoff_swap_ext_out, - _bfd_ecoff_swap_tir_out, - _bfd_ecoff_swap_rndx_out, - /* Function to read in symbolic data. */ - elf64_alpha_read_ecoff_info -}; - -/* Use a non-standard hash bucket size of 8. */ - -static const struct elf_size_info alpha_elf_size_info = -{ - sizeof (Elf64_External_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_External_Rel), - sizeof (Elf64_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 8, - 1, - 64, 3, - ELFCLASS64, EV_CURRENT, - bfd_elf64_write_out_phdrs, - bfd_elf64_write_shdrs_and_ehdr, - bfd_elf64_checksum_contents, - bfd_elf64_write_relocs, - bfd_elf64_swap_symbol_in, - bfd_elf64_swap_symbol_out, - bfd_elf64_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - bfd_elf64_swap_reloc_in, - bfd_elf64_swap_reloc_out, - bfd_elf64_swap_reloca_in, - bfd_elf64_swap_reloca_out -}; - -#define TARGET_LITTLE_SYM alpha_elf64_vec -#define TARGET_LITTLE_NAME "elf64-alpha" -#define ELF_ARCH bfd_arch_alpha -#define ELF_TARGET_ID ALPHA_ELF_DATA -#define ELF_MACHINE_CODE EM_ALPHA -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x2000 - -#define bfd_elf64_bfd_link_hash_table_create \ - elf64_alpha_bfd_link_hash_table_create - -#define bfd_elf64_bfd_reloc_type_lookup \ - elf64_alpha_bfd_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup \ - elf64_alpha_bfd_reloc_name_lookup -#define elf_info_to_howto \ - elf64_alpha_info_to_howto - -#define bfd_elf64_mkobject \ - elf64_alpha_mkobject -#define elf_backend_object_p \ - elf64_alpha_object_p - -#define elf_backend_section_from_shdr \ - elf64_alpha_section_from_shdr -#define elf_backend_section_flags \ - elf64_alpha_section_flags -#define elf_backend_fake_sections \ - elf64_alpha_fake_sections - -#define bfd_elf64_bfd_is_local_label_name \ - elf64_alpha_is_local_label_name -#define bfd_elf64_find_nearest_line \ - elf64_alpha_find_nearest_line -#define bfd_elf64_bfd_relax_section \ - elf64_alpha_relax_section - -#define elf_backend_add_symbol_hook \ - elf64_alpha_add_symbol_hook -#define elf_backend_relocs_compatible \ - _bfd_elf_relocs_compatible -#define elf_backend_sort_relocs_p \ - elf64_alpha_sort_relocs_p -#define elf_backend_check_relocs \ - elf64_alpha_check_relocs -#define elf_backend_create_dynamic_sections \ - elf64_alpha_create_dynamic_sections -#define elf_backend_adjust_dynamic_symbol \ - elf64_alpha_adjust_dynamic_symbol -#define elf_backend_merge_symbol_attribute \ - elf64_alpha_merge_symbol_attribute -#define elf_backend_copy_indirect_symbol \ - elf64_alpha_copy_indirect_symbol -#define elf_backend_always_size_sections \ - elf64_alpha_always_size_sections -#define elf_backend_size_dynamic_sections \ - elf64_alpha_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_relocate_section \ - elf64_alpha_relocate_section -#define elf_backend_finish_dynamic_symbol \ - elf64_alpha_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf64_alpha_finish_dynamic_sections -#define bfd_elf64_bfd_final_link \ - elf64_alpha_final_link -#define elf_backend_reloc_type_class \ - elf64_alpha_reloc_type_class - -#define elf_backend_can_gc_sections 1 -#define elf_backend_gc_mark_hook elf64_alpha_gc_mark_hook - -#define elf_backend_ecoff_debug_swap \ - &elf64_alpha_ecoff_debug_swap - -#define elf_backend_size_info \ - alpha_elf_size_info - -#define elf_backend_special_sections \ - elf64_alpha_special_sections - -/* A few constants that determine how the .plt section is set up. */ -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 0 -#define elf_backend_want_plt_sym 1 -#define elf_backend_got_header_size 0 -#define elf_backend_dtrel_excludes_plt 1 - -#include "elf64-target.h" - -/* FreeBSD support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM alpha_elf64_fbsd_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-alpha-freebsd" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_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 -elf64_alpha_fbsd_post_process_headers (bfd * abfd, - struct bfd_link_info * link_info ATTRIBUTE_UNUSED) -{ - Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ - - i_ehdrp = elf_elfheader (abfd); - - /* Put an ABI label supported by FreeBSD >= 4.1. */ - i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; -#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 \ - elf64_alpha_fbsd_post_process_headers - -#undef elf64_bed -#define elf64_bed elf64_alpha_fbsd_bed - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-gen.c b/sdcc/support/sdbinutils/bfd/elf64-gen.c deleted file mode 100644 index 46bb32bf0..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-gen.c +++ /dev/null @@ -1,103 +0,0 @@ -/* Generic support for 64-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" - -/* 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); - /* xgettext:c-format */ - _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 elf64_le_vec -#define TARGET_LITTLE_NAME "elf64-little" -#define TARGET_BIG_SYM elf64_be_vec -#define TARGET_BIG_NAME "elf64-big" -#define ELF_ARCH bfd_arch_unknown -#define ELF_MACHINE_CODE EM_NONE -#define ELF_MAXPAGESIZE 0x1 -#define bfd_elf64_bfd_reloc_type_lookup bfd_default_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_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/sdcc/support/sdbinutils/bfd/elf64-hppa.c b/sdcc/support/sdbinutils/bfd/elf64-hppa.c deleted file mode 100644 index ff96a8cfb..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-hppa.c +++ /dev/null @@ -1,4117 +0,0 @@ -/* Support for HPPA 64-bit ELF - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "alloca-conf.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/hppa.h" -#include "libhppa.h" -#include "elf64-hppa.h" -#include "libiberty.h" - -#define ARCH_SIZE 64 - -#define PLT_ENTRY_SIZE 0x10 -#define DLT_ENTRY_SIZE 0x8 -#define OPD_ENTRY_SIZE 0x20 - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/pa20_64/dld.sl" - -/* The stub is supposed to load the target address and target's DP - value out of the PLT, then do an external branch to the target - address. - - LDD PLTOFF(%r27),%r1 - BVE (%r1) - LDD PLTOFF+8(%r27),%r27 - - Note that we must use the LDD with a 14 bit displacement, not the one - with a 5 bit displacement. */ -static char plt_stub[] = {0x53, 0x61, 0x00, 0x00, 0xe8, 0x20, 0xd0, 0x00, - 0x53, 0x7b, 0x00, 0x00 }; - -struct elf64_hppa_link_hash_entry -{ - struct elf_link_hash_entry eh; - - /* Offsets for this symbol in various linker sections. */ - bfd_vma dlt_offset; - bfd_vma plt_offset; - bfd_vma opd_offset; - bfd_vma stub_offset; - - /* The index of the (possibly local) symbol in the input bfd and its - associated BFD. Needed so that we can have relocs against local - symbols in shared libraries. */ - long sym_indx; - bfd *owner; - - /* Dynamic symbols may need to have two different values. One for - the dynamic symbol table, one for the normal symbol table. - - In such cases we store the symbol's real value and section - index here so we can restore the real value before we write - the normal symbol table. */ - bfd_vma st_value; - int st_shndx; - - /* Used to count non-got, non-plt relocations for delayed sizing - of relocation sections. */ - struct elf64_hppa_dyn_reloc_entry - { - /* Next relocation in the chain. */ - struct elf64_hppa_dyn_reloc_entry *next; - - /* The type of the relocation. */ - int type; - - /* The input section of the relocation. */ - asection *sec; - - /* Number of relocs copied in this section. */ - bfd_size_type count; - - /* The index of the section symbol for the input section of - the relocation. Only needed when building shared libraries. */ - int sec_symndx; - - /* The offset within the input section of the relocation. */ - bfd_vma offset; - - /* The addend for the relocation. */ - bfd_vma addend; - - } *reloc_entries; - - /* Nonzero if this symbol needs an entry in one of the linker - sections. */ - unsigned want_dlt; - unsigned want_plt; - unsigned want_opd; - unsigned want_stub; -}; - -struct elf64_hppa_link_hash_table -{ - struct elf_link_hash_table root; - - /* Shortcuts to get to the various linker defined sections. */ - asection *dlt_sec; - asection *dlt_rel_sec; - asection *plt_sec; - asection *plt_rel_sec; - asection *opd_sec; - asection *opd_rel_sec; - asection *other_rel_sec; - - /* Offset of __gp within .plt section. When the PLT gets large we want - to slide __gp into the PLT section so that we can continue to use - single DP relative instructions to load values out of the PLT. */ - bfd_vma gp_offset; - - /* Note this is not strictly correct. We should create a stub section for - each input section with calls. The stub section should be placed before - the section with the call. */ - asection *stub_sec; - - bfd_vma text_segment_base; - bfd_vma data_segment_base; - - /* We build tables to map from an input section back to its - symbol index. This is the BFD for which we currently have - a map. */ - bfd *section_syms_bfd; - - /* Array of symbol numbers for each input section attached to the - current BFD. */ - int *section_syms; -}; - -#define hppa_link_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == HPPA64_ELF_DATA ? ((struct elf64_hppa_link_hash_table *) ((p)->hash)) : NULL) - -#define hppa_elf_hash_entry(ent) \ - ((struct elf64_hppa_link_hash_entry *)(ent)) - -#define eh_name(eh) \ - (eh ? eh->root.root.string : "") - -typedef struct bfd_hash_entry *(*new_hash_entry_func) - (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); - -static struct bfd_link_hash_table *elf64_hppa_hash_table_create - (bfd *abfd); - -/* This must follow the definitions of the various derived linker - hash tables and shared functions. */ -#include "elf-hppa.h" - -static bfd_boolean elf64_hppa_object_p - (bfd *); - -static void elf64_hppa_post_process_headers - (bfd *, struct bfd_link_info *); - -static bfd_boolean elf64_hppa_create_dynamic_sections - (bfd *, struct bfd_link_info *); - -static bfd_boolean elf64_hppa_adjust_dynamic_symbol - (struct bfd_link_info *, struct elf_link_hash_entry *); - -static bfd_boolean elf64_hppa_mark_milli_and_exported_functions - (struct elf_link_hash_entry *, void *); - -static bfd_boolean elf64_hppa_size_dynamic_sections - (bfd *, struct bfd_link_info *); - -static int elf64_hppa_link_output_symbol_hook - (struct bfd_link_info *, const char *, Elf_Internal_Sym *, - asection *, struct elf_link_hash_entry *); - -static bfd_boolean elf64_hppa_finish_dynamic_symbol - (bfd *, struct bfd_link_info *, - struct elf_link_hash_entry *, Elf_Internal_Sym *); - -static bfd_boolean elf64_hppa_finish_dynamic_sections - (bfd *, struct bfd_link_info *); - -static bfd_boolean elf64_hppa_check_relocs - (bfd *, struct bfd_link_info *, - asection *, const Elf_Internal_Rela *); - -static bfd_boolean elf64_hppa_dynamic_symbol_p - (struct elf_link_hash_entry *, struct bfd_link_info *); - -static bfd_boolean elf64_hppa_mark_exported_functions - (struct elf_link_hash_entry *, void *); - -static bfd_boolean elf64_hppa_finalize_opd - (struct elf_link_hash_entry *, void *); - -static bfd_boolean elf64_hppa_finalize_dlt - (struct elf_link_hash_entry *, void *); - -static bfd_boolean allocate_global_data_dlt - (struct elf_link_hash_entry *, void *); - -static bfd_boolean allocate_global_data_plt - (struct elf_link_hash_entry *, void *); - -static bfd_boolean allocate_global_data_stub - (struct elf_link_hash_entry *, void *); - -static bfd_boolean allocate_global_data_opd - (struct elf_link_hash_entry *, void *); - -static bfd_boolean get_reloc_section - (bfd *, struct elf64_hppa_link_hash_table *, asection *); - -static bfd_boolean count_dyn_reloc - (bfd *, struct elf64_hppa_link_hash_entry *, - int, asection *, int, bfd_vma, bfd_vma); - -static bfd_boolean allocate_dynrel_entries - (struct elf_link_hash_entry *, void *); - -static bfd_boolean elf64_hppa_finalize_dynreloc - (struct elf_link_hash_entry *, void *); - -static bfd_boolean get_opd - (bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *); - -static bfd_boolean get_plt - (bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *); - -static bfd_boolean get_dlt - (bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *); - -static bfd_boolean get_stub - (bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *); - -static int elf64_hppa_elf_get_symbol_type - (Elf_Internal_Sym *, int); - -/* Initialize an entry in the link hash table. */ - -static struct bfd_hash_entry * -hppa64_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_hppa_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_hppa_link_hash_entry *hh; - - /* Initialize our local data. All zeros. */ - hh = hppa_elf_hash_entry (entry); - memset (&hh->dlt_offset, 0, - (sizeof (struct elf64_hppa_link_hash_entry) - - offsetof (struct elf64_hppa_link_hash_entry, dlt_offset))); - } - - return entry; -} - -/* Create the derived linker hash table. The PA64 ELF port uses this - derived hash table to keep information specific to the PA ElF - linker (without using static variables). */ - -static struct bfd_link_hash_table* -elf64_hppa_hash_table_create (bfd *abfd) -{ - struct elf64_hppa_link_hash_table *htab; - bfd_size_type amt = sizeof (*htab); - - htab = bfd_zmalloc (amt); - if (htab == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&htab->root, abfd, - hppa64_link_hash_newfunc, - sizeof (struct elf64_hppa_link_hash_entry), - HPPA64_ELF_DATA)) - { - free (htab); - return NULL; - } - - htab->text_segment_base = (bfd_vma) -1; - htab->data_segment_base = (bfd_vma) -1; - - return &htab->root.root; -} - -/* Return nonzero if ABFD represents a PA2.0 ELF64 file. - - Additionally we set the default architecture and machine. */ -static bfd_boolean -elf64_hppa_object_p (bfd *abfd) -{ - Elf_Internal_Ehdr * i_ehdrp; - unsigned int flags; - - i_ehdrp = elf_elfheader (abfd); - if (strcmp (bfd_get_target (abfd), "elf64-hppa-linux") == 0) - { - /* GCC on hppa-linux produces binaries with OSABI=GNU, - but the kernel produces corefiles with OSABI=SysV. */ - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_GNU - && i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_NONE) /* aka SYSV */ - return FALSE; - } - else - { - /* HPUX produces binaries with OSABI=HPUX, - but the kernel produces corefiles with OSABI=SysV. */ - if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_HPUX - && i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_NONE) /* aka SYSV */ - return FALSE; - } - - flags = i_ehdrp->e_flags; - switch (flags & (EF_PARISC_ARCH | EF_PARISC_WIDE)) - { - case EFA_PARISC_1_0: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 10); - case EFA_PARISC_1_1: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 11); - case EFA_PARISC_2_0: - if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64) - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 25); - else - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 20); - case EFA_PARISC_2_0 | EF_PARISC_WIDE: - return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 25); - } - /* Don't be fussy. */ - return TRUE; -} - -/* Given section type (hdr->sh_type), return a boolean indicating - whether or not the section is an elf64-hppa specific section. */ -static bfd_boolean -elf64_hppa_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) -{ - switch (hdr->sh_type) - { - case SHT_PARISC_EXT: - if (strcmp (name, ".PARISC.archext") != 0) - return FALSE; - break; - case SHT_PARISC_UNWIND: - if (strcmp (name, ".PARISC.unwind") != 0) - return FALSE; - break; - case SHT_PARISC_DOC: - case SHT_PARISC_ANNOT: - default: - return FALSE; - } - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - return TRUE; -} - -/* SEC is a section containing relocs for an input BFD when linking; return - a suitable section for holding relocs in the output BFD for a link. */ - -static bfd_boolean -get_reloc_section (bfd *abfd, - struct elf64_hppa_link_hash_table *hppa_info, - asection *sec) -{ - const char *srel_name; - asection *srel; - bfd *dynobj; - - srel_name = (bfd_elf_string_from_elf_section - (abfd, elf_elfheader(abfd)->e_shstrndx, - _bfd_elf_single_rel_hdr(sec)->sh_name)); - if (srel_name == NULL) - return FALSE; - - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - srel = bfd_get_linker_section (dynobj, srel_name); - if (srel == NULL) - { - srel = bfd_make_section_anyway_with_flags (dynobj, srel_name, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (srel == NULL - || !bfd_set_section_alignment (dynobj, srel, 3)) - return FALSE; - } - - hppa_info->other_rel_sec = srel; - return TRUE; -} - -/* Add a new entry to the list of dynamic relocations against DYN_H. - - We use this to keep a record of all the FPTR relocations against a - particular symbol so that we can create FPTR relocations in the - output file. */ - -static bfd_boolean -count_dyn_reloc (bfd *abfd, - struct elf64_hppa_link_hash_entry *hh, - int type, - asection *sec, - int sec_symndx, - bfd_vma offset, - bfd_vma addend) -{ - struct elf64_hppa_dyn_reloc_entry *rent; - - rent = (struct elf64_hppa_dyn_reloc_entry *) - bfd_alloc (abfd, (bfd_size_type) sizeof (*rent)); - if (!rent) - return FALSE; - - rent->next = hh->reloc_entries; - rent->type = type; - rent->sec = sec; - rent->sec_symndx = sec_symndx; - rent->offset = offset; - rent->addend = addend; - hh->reloc_entries = rent; - - return TRUE; -} - -/* Return a pointer to the local DLT, PLT and OPD reference counts - for ABFD. Returns NULL if the storage allocation fails. */ - -static bfd_signed_vma * -hppa64_elf_local_refcounts (bfd *abfd) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - bfd_signed_vma *local_refcounts; - - local_refcounts = elf_local_got_refcounts (abfd); - if (local_refcounts == NULL) - { - bfd_size_type size; - - /* Allocate space for local DLT, PLT and OPD reference - counts. Done this way to save polluting elf_obj_tdata - with another target specific pointer. */ - size = symtab_hdr->sh_info; - size *= 3 * sizeof (bfd_signed_vma); - local_refcounts = bfd_zalloc (abfd, size); - elf_local_got_refcounts (abfd) = local_refcounts; - } - return local_refcounts; -} - -/* Scan the RELOCS and record the type of dynamic entries that each - referenced symbol needs. */ - -static bfd_boolean -elf64_hppa_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf64_hppa_link_hash_table *hppa_info; - const Elf_Internal_Rela *relend; - Elf_Internal_Shdr *symtab_hdr; - const Elf_Internal_Rela *rel; - unsigned int sec_symndx; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* If this is the first dynamic object found in the link, create - the special sections required for dynamic linking. */ - if (! elf_hash_table (info)->dynamic_sections_created) - { - if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) - return FALSE; - } - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* If necessary, build a new table holding section symbols indices - for this BFD. */ - - if (bfd_link_pic (info) && hppa_info->section_syms_bfd != abfd) - { - unsigned long i; - unsigned int highest_shndx; - Elf_Internal_Sym *local_syms = NULL; - Elf_Internal_Sym *isym, *isymend; - bfd_size_type amt; - - /* We're done with the old cache of section index to section symbol - index information. Free it. - - ?!? Note we leak the last section_syms array. Presumably we - could free it in one of the later routines in this file. */ - if (hppa_info->section_syms) - free (hppa_info->section_syms); - - /* Read this BFD's local symbols. */ - if (symtab_hdr->sh_info != 0) - { - local_syms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (local_syms == NULL) - local_syms = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (local_syms == NULL) - return FALSE; - } - - /* Record the highest section index referenced by the local symbols. */ - highest_shndx = 0; - isymend = local_syms + symtab_hdr->sh_info; - for (isym = local_syms; isym < isymend; isym++) - { - if (isym->st_shndx > highest_shndx - && isym->st_shndx < SHN_LORESERVE) - highest_shndx = isym->st_shndx; - } - - /* Allocate an array to hold the section index to section symbol index - mapping. Bump by one since we start counting at zero. */ - highest_shndx++; - amt = highest_shndx; - amt *= sizeof (int); - hppa_info->section_syms = (int *) bfd_malloc (amt); - - /* Now walk the local symbols again. If we find a section symbol, - record the index of the symbol into the section_syms array. */ - for (i = 0, isym = local_syms; isym < isymend; i++, isym++) - { - if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) - hppa_info->section_syms[isym->st_shndx] = i; - } - - /* We are finished with the local symbols. */ - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - { - if (! info->keep_memory) - free (local_syms); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) local_syms; - } - } - - /* Record which BFD we built the section_syms mapping for. */ - hppa_info->section_syms_bfd = abfd; - } - - /* Record the symbol index for this input section. We may need it for - relocations when building shared libraries. When not building shared - libraries this value is never really used, but assign it to zero to - prevent out of bounds memory accesses in other routines. */ - if (bfd_link_pic (info)) - { - sec_symndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* If we did not find a section symbol for this section, then - something went terribly wrong above. */ - if (sec_symndx == SHN_BAD) - return FALSE; - - if (sec_symndx < SHN_LORESERVE) - sec_symndx = hppa_info->section_syms[sec_symndx]; - else - sec_symndx = 0; - } - else - sec_symndx = 0; - - relend = relocs + sec->reloc_count; - for (rel = relocs; rel < relend; ++rel) - { - enum - { - NEED_DLT = 1, - NEED_PLT = 2, - NEED_STUB = 4, - NEED_OPD = 8, - NEED_DYNREL = 16, - }; - - unsigned long r_symndx = ELF64_R_SYM (rel->r_info); - struct elf64_hppa_link_hash_entry *hh; - int need_entry; - bfd_boolean maybe_dynamic; - int dynrel_type = R_PARISC_NONE; - static reloc_howto_type *howto; - - if (r_symndx >= symtab_hdr->sh_info) - { - /* We're dealing with a global symbol -- find its hash entry - and mark it as being referenced. */ - long indx = r_symndx - symtab_hdr->sh_info; - hh = hppa_elf_hash_entry (elf_sym_hashes (abfd)[indx]); - while (hh->eh.root.type == bfd_link_hash_indirect - || hh->eh.root.type == bfd_link_hash_warning) - hh = hppa_elf_hash_entry (hh->eh.root.u.i.link); - - /* PR15323, ref flags aren't set for references in the same - object. */ - hh->eh.ref_regular = 1; - } - else - hh = NULL; - - /* We can only get preliminary data on whether a symbol is - locally or externally defined, as not all of the input files - have yet been processed. Do something with what we know, as - this may help reduce memory usage and processing time later. */ - maybe_dynamic = FALSE; - if (hh && ((bfd_link_pic (info) - && (!info->symbolic - || info->unresolved_syms_in_shared_libs == RM_IGNORE)) - || !hh->eh.def_regular - || hh->eh.root.type == bfd_link_hash_defweak)) - maybe_dynamic = TRUE; - - howto = elf_hppa_howto_table + ELF64_R_TYPE (rel->r_info); - need_entry = 0; - switch (howto->type) - { - /* These are simple indirect references to symbols through the - DLT. We need to create a DLT entry for any symbols which - appears in a DLTIND relocation. */ - case R_PARISC_DLTIND21L: - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND14F: - case R_PARISC_DLTIND14WR: - case R_PARISC_DLTIND14DR: - need_entry = NEED_DLT; - break; - - /* ?!? These need a DLT entry. But I have no idea what to do with - the "link time TP value. */ - case R_PARISC_LTOFF_TP21L: - case R_PARISC_LTOFF_TP14R: - case R_PARISC_LTOFF_TP14F: - case R_PARISC_LTOFF_TP64: - case R_PARISC_LTOFF_TP14WR: - case R_PARISC_LTOFF_TP14DR: - case R_PARISC_LTOFF_TP16F: - case R_PARISC_LTOFF_TP16WF: - case R_PARISC_LTOFF_TP16DF: - need_entry = NEED_DLT; - break; - - /* These are function calls. Depending on their precise target we - may need to make a stub for them. The stub uses the PLT, so we - need to create PLT entries for these symbols too. */ - case R_PARISC_PCREL12F: - case R_PARISC_PCREL17F: - case R_PARISC_PCREL22F: - case R_PARISC_PCREL32: - case R_PARISC_PCREL64: - case R_PARISC_PCREL21L: - case R_PARISC_PCREL17R: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL14R: - case R_PARISC_PCREL14F: - case R_PARISC_PCREL22C: - case R_PARISC_PCREL14WR: - case R_PARISC_PCREL14DR: - case R_PARISC_PCREL16F: - case R_PARISC_PCREL16WF: - case R_PARISC_PCREL16DF: - /* Function calls might need to go through the .plt, and - might need a long branch stub. */ - if (hh != NULL && hh->eh.type != STT_PARISC_MILLI) - need_entry = (NEED_PLT | NEED_STUB); - else - need_entry = 0; - break; - - case R_PARISC_PLTOFF21L: - case R_PARISC_PLTOFF14R: - case R_PARISC_PLTOFF14F: - case R_PARISC_PLTOFF14WR: - case R_PARISC_PLTOFF14DR: - case R_PARISC_PLTOFF16F: - case R_PARISC_PLTOFF16WF: - case R_PARISC_PLTOFF16DF: - need_entry = (NEED_PLT); - break; - - case R_PARISC_DIR64: - if (bfd_link_pic (info) || maybe_dynamic) - need_entry = (NEED_DYNREL); - dynrel_type = R_PARISC_DIR64; - break; - - /* This is an indirect reference through the DLT to get the address - of a OPD descriptor. Thus we need to make a DLT entry that points - to an OPD entry. */ - case R_PARISC_LTOFF_FPTR21L: - case R_PARISC_LTOFF_FPTR14R: - case R_PARISC_LTOFF_FPTR14WR: - case R_PARISC_LTOFF_FPTR14DR: - case R_PARISC_LTOFF_FPTR32: - case R_PARISC_LTOFF_FPTR64: - case R_PARISC_LTOFF_FPTR16F: - case R_PARISC_LTOFF_FPTR16WF: - case R_PARISC_LTOFF_FPTR16DF: - if (bfd_link_pic (info) || maybe_dynamic) - need_entry = (NEED_DLT | NEED_OPD | NEED_PLT); - else - need_entry = (NEED_DLT | NEED_OPD | NEED_PLT); - dynrel_type = R_PARISC_FPTR64; - break; - - /* This is a simple OPD entry. */ - case R_PARISC_FPTR64: - if (bfd_link_pic (info) || maybe_dynamic) - need_entry = (NEED_OPD | NEED_PLT | NEED_DYNREL); - else - need_entry = (NEED_OPD | NEED_PLT); - dynrel_type = R_PARISC_FPTR64; - break; - - /* Add more cases as needed. */ - } - - if (!need_entry) - continue; - - if (hh) - { - /* Stash away enough information to be able to find this symbol - regardless of whether or not it is local or global. */ - hh->owner = abfd; - hh->sym_indx = r_symndx; - } - - /* Create what's needed. */ - if (need_entry & NEED_DLT) - { - /* Allocate space for a DLT entry, as well as a dynamic - relocation for this entry. */ - if (! hppa_info->dlt_sec - && ! get_dlt (abfd, info, hppa_info)) - goto err_out; - - if (hh != NULL) - { - hh->want_dlt = 1; - hh->eh.got.refcount += 1; - } - else - { - bfd_signed_vma *local_dlt_refcounts; - - /* This is a DLT entry for a local symbol. */ - local_dlt_refcounts = hppa64_elf_local_refcounts (abfd); - if (local_dlt_refcounts == NULL) - return FALSE; - local_dlt_refcounts[r_symndx] += 1; - } - } - - if (need_entry & NEED_PLT) - { - if (! hppa_info->plt_sec - && ! get_plt (abfd, info, hppa_info)) - goto err_out; - - if (hh != NULL) - { - hh->want_plt = 1; - hh->eh.needs_plt = 1; - hh->eh.plt.refcount += 1; - } - else - { - bfd_signed_vma *local_dlt_refcounts; - bfd_signed_vma *local_plt_refcounts; - - /* This is a PLT entry for a local symbol. */ - local_dlt_refcounts = hppa64_elf_local_refcounts (abfd); - if (local_dlt_refcounts == NULL) - return FALSE; - local_plt_refcounts = local_dlt_refcounts + symtab_hdr->sh_info; - local_plt_refcounts[r_symndx] += 1; - } - } - - if (need_entry & NEED_STUB) - { - if (! hppa_info->stub_sec - && ! get_stub (abfd, info, hppa_info)) - goto err_out; - if (hh) - hh->want_stub = 1; - } - - if (need_entry & NEED_OPD) - { - if (! hppa_info->opd_sec - && ! get_opd (abfd, info, hppa_info)) - goto err_out; - - /* FPTRs are not allocated by the dynamic linker for PA64, - though it is possible that will change in the future. */ - - if (hh != NULL) - hh->want_opd = 1; - else - { - bfd_signed_vma *local_dlt_refcounts; - bfd_signed_vma *local_opd_refcounts; - - /* This is a OPD for a local symbol. */ - local_dlt_refcounts = hppa64_elf_local_refcounts (abfd); - if (local_dlt_refcounts == NULL) - return FALSE; - local_opd_refcounts = (local_dlt_refcounts - + 2 * symtab_hdr->sh_info); - local_opd_refcounts[r_symndx] += 1; - } - } - - /* Add a new dynamic relocation to the chain of dynamic - relocations for this symbol. */ - if ((need_entry & NEED_DYNREL) && (sec->flags & SEC_ALLOC)) - { - if (! hppa_info->other_rel_sec - && ! get_reloc_section (abfd, hppa_info, sec)) - goto err_out; - - /* Count dynamic relocations against global symbols. */ - if (hh != NULL - && !count_dyn_reloc (abfd, hh, dynrel_type, sec, - sec_symndx, rel->r_offset, rel->r_addend)) - goto err_out; - - /* If we are building a shared library and we just recorded - a dynamic R_PARISC_FPTR64 relocation, then make sure the - section symbol for this section ends up in the dynamic - symbol table. */ - if (bfd_link_pic (info) && dynrel_type == R_PARISC_FPTR64 - && ! (bfd_elf_link_record_local_dynamic_symbol - (info, abfd, sec_symndx))) - return FALSE; - } - } - - return TRUE; - - err_out: - return FALSE; -} - -struct elf64_hppa_allocate_data -{ - struct bfd_link_info *info; - bfd_size_type ofs; -}; - -/* Should we do dynamic things to this symbol? */ - -static bfd_boolean -elf64_hppa_dynamic_symbol_p (struct elf_link_hash_entry *eh, - struct bfd_link_info *info) -{ - /* ??? What, if anything, needs to happen wrt STV_PROTECTED symbols - and relocations that retrieve a function descriptor? Assume the - worst for now. */ - if (_bfd_elf_dynamic_symbol_p (eh, info, 1)) - { - /* ??? Why is this here and not elsewhere is_local_label_name. */ - if (eh->root.root.string[0] == '$' && eh->root.root.string[1] == '$') - return FALSE; - - return TRUE; - } - else - return FALSE; -} - -/* Mark all functions exported by this file so that we can later allocate - entries in .opd for them. */ - -static bfd_boolean -elf64_hppa_mark_exported_functions (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - if (eh - && (eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak) - && eh->root.u.def.section->output_section != NULL - && eh->type == STT_FUNC) - { - if (! hppa_info->opd_sec - && ! get_opd (hppa_info->root.dynobj, info, hppa_info)) - return FALSE; - - hh->want_opd = 1; - - /* Put a flag here for output_symbol_hook. */ - hh->st_shndx = -1; - eh->needs_plt = 1; - } - - return TRUE; -} - -/* Allocate space for a DLT entry. */ - -static bfd_boolean -allocate_global_data_dlt (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (hh->want_dlt) - { - if (bfd_link_pic (x->info)) - { - /* Possibly add the symbol to the local dynamic symbol - table since we might need to create a dynamic relocation - against it. */ - if (eh->dynindx == -1 && eh->type != STT_PARISC_MILLI) - { - bfd *owner = eh->root.u.def.section->owner; - - if (! (bfd_elf_link_record_local_dynamic_symbol - (x->info, owner, hh->sym_indx))) - return FALSE; - } - } - - hh->dlt_offset = x->ofs; - x->ofs += DLT_ENTRY_SIZE; - } - return TRUE; -} - -/* Allocate space for a DLT.PLT entry. */ - -static bfd_boolean -allocate_global_data_plt (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *) data; - - if (hh->want_plt - && elf64_hppa_dynamic_symbol_p (eh, x->info) - && !((eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak) - && eh->root.u.def.section->output_section != NULL)) - { - hh->plt_offset = x->ofs; - x->ofs += PLT_ENTRY_SIZE; - if (hh->plt_offset < 0x2000) - { - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = hppa_link_hash_table (x->info); - if (hppa_info == NULL) - return FALSE; - - hppa_info->gp_offset = hh->plt_offset; - } - } - else - hh->want_plt = 0; - - return TRUE; -} - -/* Allocate space for a STUB entry. */ - -static bfd_boolean -allocate_global_data_stub (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (hh->want_stub - && elf64_hppa_dynamic_symbol_p (eh, x->info) - && !((eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak) - && eh->root.u.def.section->output_section != NULL)) - { - hh->stub_offset = x->ofs; - x->ofs += sizeof (plt_stub); - } - else - hh->want_stub = 0; - return TRUE; -} - -/* Allocate space for a FPTR entry. */ - -static bfd_boolean -allocate_global_data_opd (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - - if (hh && hh->want_opd) - { - /* We never need an opd entry for a symbol which is not - defined by this output file. */ - if (hh && (hh->eh.root.type == bfd_link_hash_undefined - || hh->eh.root.type == bfd_link_hash_undefweak - || hh->eh.root.u.def.section->output_section == NULL)) - hh->want_opd = 0; - - /* If we are creating a shared library, took the address of a local - function or might export this function from this object file, then - we have to create an opd descriptor. */ - else if (bfd_link_pic (x->info) - || hh == NULL - || (hh->eh.dynindx == -1 && hh->eh.type != STT_PARISC_MILLI) - || (hh->eh.root.type == bfd_link_hash_defined - || hh->eh.root.type == bfd_link_hash_defweak)) - { - /* If we are creating a shared library, then we will have to - create a runtime relocation for the symbol to properly - initialize the .opd entry. Make sure the symbol gets - added to the dynamic symbol table. */ - if (bfd_link_pic (x->info) - && (hh == NULL || (hh->eh.dynindx == -1))) - { - bfd *owner; - /* PR 6511: Default to using the dynamic symbol table. */ - owner = (hh->owner ? hh->owner: eh->root.u.def.section->owner); - - if (!bfd_elf_link_record_local_dynamic_symbol - (x->info, owner, hh->sym_indx)) - return FALSE; - } - - /* This may not be necessary or desirable anymore now that - we have some support for dealing with section symbols - in dynamic relocs. But name munging does make the result - much easier to debug. ie, the EPLT reloc will reference - a symbol like .foobar, instead of .text + offset. */ - if (bfd_link_pic (x->info) && eh) - { - char *new_name; - struct elf_link_hash_entry *nh; - - new_name = concat (".", eh->root.root.string, NULL); - - nh = elf_link_hash_lookup (elf_hash_table (x->info), - new_name, TRUE, TRUE, TRUE); - - free (new_name); - nh->root.type = eh->root.type; - nh->root.u.def.value = eh->root.u.def.value; - nh->root.u.def.section = eh->root.u.def.section; - - if (! bfd_elf_link_record_dynamic_symbol (x->info, nh)) - return FALSE; - } - hh->opd_offset = x->ofs; - x->ofs += OPD_ENTRY_SIZE; - } - - /* Otherwise we do not need an opd entry. */ - else - hh->want_opd = 0; - } - return TRUE; -} - -/* HP requires the EI_OSABI field to be filled in. The assignment to - EI_ABIVERSION may not be strictly necessary. */ - -static void -elf64_hppa_post_process_headers (bfd *abfd, - struct bfd_link_info *link_info ATTRIBUTE_UNUSED) -{ - Elf_Internal_Ehdr * i_ehdrp; - - i_ehdrp = elf_elfheader (abfd); - - i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; - i_ehdrp->e_ident[EI_ABIVERSION] = 1; -} - -/* Create function descriptor section (.opd). This section is called .opd - because it contains "official procedure descriptors". The "official" - refers to the fact that these descriptors are used when taking the address - of a procedure, thus ensuring a unique address for each procedure. */ - -static bfd_boolean -get_opd (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf64_hppa_link_hash_table *hppa_info) -{ - asection *opd; - bfd *dynobj; - - opd = hppa_info->opd_sec; - if (!opd) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - opd = bfd_make_section_anyway_with_flags (dynobj, ".opd", - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (!opd - || !bfd_set_section_alignment (abfd, opd, 3)) - { - BFD_ASSERT (0); - return FALSE; - } - - hppa_info->opd_sec = opd; - } - - return TRUE; -} - -/* Create the PLT section. */ - -static bfd_boolean -get_plt (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf64_hppa_link_hash_table *hppa_info) -{ - asection *plt; - bfd *dynobj; - - plt = hppa_info->plt_sec; - if (!plt) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - plt = bfd_make_section_anyway_with_flags (dynobj, ".plt", - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (!plt - || !bfd_set_section_alignment (abfd, plt, 3)) - { - BFD_ASSERT (0); - return FALSE; - } - - hppa_info->plt_sec = plt; - } - - return TRUE; -} - -/* Create the DLT section. */ - -static bfd_boolean -get_dlt (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf64_hppa_link_hash_table *hppa_info) -{ - asection *dlt; - bfd *dynobj; - - dlt = hppa_info->dlt_sec; - if (!dlt) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - dlt = bfd_make_section_anyway_with_flags (dynobj, ".dlt", - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (!dlt - || !bfd_set_section_alignment (abfd, dlt, 3)) - { - BFD_ASSERT (0); - return FALSE; - } - - hppa_info->dlt_sec = dlt; - } - - return TRUE; -} - -/* Create the stubs section. */ - -static bfd_boolean -get_stub (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf64_hppa_link_hash_table *hppa_info) -{ - asection *stub; - bfd *dynobj; - - stub = hppa_info->stub_sec; - if (!stub) - { - dynobj = hppa_info->root.dynobj; - if (!dynobj) - hppa_info->root.dynobj = dynobj = abfd; - - stub = bfd_make_section_anyway_with_flags (dynobj, ".stub", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)); - if (!stub - || !bfd_set_section_alignment (abfd, stub, 3)) - { - BFD_ASSERT (0); - return FALSE; - } - - hppa_info->stub_sec = stub; - } - - return TRUE; -} - -/* Create sections necessary for dynamic linking. This is only a rough - cut and will likely change as we learn more about the somewhat - unusual dynamic linking scheme HP uses. - - .stub: - Contains code to implement cross-space calls. The first time one - of the stubs is used it will call into the dynamic linker, later - calls will go straight to the target. - - The only stub we support right now looks like - - ldd OFFSET(%dp),%r1 - bve %r0(%r1) - ldd OFFSET+8(%dp),%dp - - Other stubs may be needed in the future. We may want the remove - the break/nop instruction. It is only used right now to keep the - offset of a .plt entry and a .stub entry in sync. - - .dlt: - This is what most people call the .got. HP used a different name. - Losers. - - .rela.dlt: - Relocations for the DLT. - - .plt: - Function pointers as address,gp pairs. - - .rela.plt: - Should contain dynamic IPLT (and EPLT?) relocations. - - .opd: - FPTRS - - .rela.opd: - EPLT relocations for symbols exported from shared libraries. */ - -static bfd_boolean -elf64_hppa_create_dynamic_sections (bfd *abfd, - struct bfd_link_info *info) -{ - asection *s; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - if (! get_stub (abfd, info, hppa_info)) - return FALSE; - - if (! get_dlt (abfd, info, hppa_info)) - return FALSE; - - if (! get_plt (abfd, info, hppa_info)) - return FALSE; - - if (! get_opd (abfd, info, hppa_info)) - return FALSE; - - s = bfd_make_section_anyway_with_flags (abfd, ".rela.dlt", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - hppa_info->dlt_rel_sec = s; - - s = bfd_make_section_anyway_with_flags (abfd, ".rela.plt", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - hppa_info->plt_rel_sec = s; - - s = bfd_make_section_anyway_with_flags (abfd, ".rela.data", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - hppa_info->other_rel_sec = s; - - s = bfd_make_section_anyway_with_flags (abfd, ".rela.opd", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - hppa_info->opd_rel_sec = s; - - return TRUE; -} - -/* Allocate dynamic relocations for those symbols that turned out - to be dynamic. */ - -static bfd_boolean -allocate_dynrel_entries (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct elf64_hppa_allocate_data *x = (struct elf64_hppa_allocate_data *)data; - struct elf64_hppa_link_hash_table *hppa_info; - struct elf64_hppa_dyn_reloc_entry *rent; - bfd_boolean dynamic_symbol, shared; - - hppa_info = hppa_link_hash_table (x->info); - if (hppa_info == NULL) - return FALSE; - - dynamic_symbol = elf64_hppa_dynamic_symbol_p (eh, x->info); - shared = bfd_link_pic (x->info); - - /* We may need to allocate relocations for a non-dynamic symbol - when creating a shared library. */ - if (!dynamic_symbol && !shared) - return TRUE; - - /* Take care of the normal data relocations. */ - - for (rent = hh->reloc_entries; rent; rent = rent->next) - { - /* Allocate one iff we are building a shared library, the relocation - isn't a R_PARISC_FPTR64, or we don't want an opd entry. */ - if (!shared && rent->type == R_PARISC_FPTR64 && hh->want_opd) - continue; - - hppa_info->other_rel_sec->size += sizeof (Elf64_External_Rela); - - /* Make sure this symbol gets into the dynamic symbol table if it is - not already recorded. ?!? This should not be in the loop since - the symbol need only be added once. */ - if (eh->dynindx == -1 && eh->type != STT_PARISC_MILLI) - if (!bfd_elf_link_record_local_dynamic_symbol - (x->info, rent->sec->owner, hh->sym_indx)) - return FALSE; - } - - /* Take care of the GOT and PLT relocations. */ - - if ((dynamic_symbol || shared) && hh->want_dlt) - hppa_info->dlt_rel_sec->size += sizeof (Elf64_External_Rela); - - /* If we are building a shared library, then every symbol that has an - opd entry will need an EPLT relocation to relocate the symbol's address - and __gp value based on the runtime load address. */ - if (shared && hh->want_opd) - hppa_info->opd_rel_sec->size += sizeof (Elf64_External_Rela); - - if (hh->want_plt && dynamic_symbol) - { - bfd_size_type t = 0; - - /* Dynamic symbols get one IPLT relocation. Local symbols in - shared libraries get two REL relocations. Local symbols in - main applications get nothing. */ - if (dynamic_symbol) - t = sizeof (Elf64_External_Rela); - else if (shared) - t = 2 * sizeof (Elf64_External_Rela); - - hppa_info->plt_rel_sec->size += t; - } - - return TRUE; -} - -/* Adjust a symbol defined by a dynamic object and referenced by a - regular object. */ - -static bfd_boolean -elf64_hppa_adjust_dynamic_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *eh) -{ - /* ??? Undefined symbols with PLT entries should be re-defined - to be the PLT entry. */ - - /* 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 (eh->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (eh); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - eh->root.u.def.section = def->root.u.def.section; - eh->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* If this is a reference to a symbol defined by a dynamic object which - is not a function, we might allocate the symbol in our .dynbss section - and allocate a COPY dynamic relocation. - - But PA64 code is canonically PIC, so as a rule we can avoid this sort - of hackery. */ - - return TRUE; -} - -/* This function is called via elf_link_hash_traverse to mark millicode - symbols with a dynindx of -1 and to remove the string table reference - from the dynamic symbol table. If the symbol is not a millicode symbol, - elf64_hppa_mark_exported_functions is called. */ - -static bfd_boolean -elf64_hppa_mark_milli_and_exported_functions (struct elf_link_hash_entry *eh, - void *data) -{ - struct bfd_link_info *info = (struct bfd_link_info *) data; - - if (eh->type == STT_PARISC_MILLI) - { - if (eh->dynindx != -1) - { - eh->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - eh->dynstr_index); - } - return TRUE; - } - - return elf64_hppa_mark_exported_functions (eh, data); -} - -/* Set the final sizes of the dynamic sections and allocate memory for - the contents of our special sections. */ - -static bfd_boolean -elf64_hppa_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - struct elf64_hppa_link_hash_table *hppa_info; - struct elf64_hppa_allocate_data data; - bfd *dynobj; - bfd *ibfd; - asection *sec; - bfd_boolean plt; - bfd_boolean relocs; - bfd_boolean reltext; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - dynobj = hppa_info->root.dynobj; - BFD_ASSERT (dynobj != NULL); - - /* Mark each function this program exports so that we will allocate - space in the .opd section for each function's FPTR. If we are - creating dynamic sections, change the dynamic index of millicode - symbols to -1 and remove them from the string table for .dynstr. - - We have to traverse the main linker hash table since we have to - find functions which may not have been mentioned in any relocs. */ - elf_link_hash_traverse (&hppa_info->root, - (hppa_info->root.dynamic_sections_created - ? elf64_hppa_mark_milli_and_exported_functions - : elf64_hppa_mark_exported_functions), - info); - - if (hppa_info->root.dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - sec = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (sec != NULL); - sec->size = sizeof ELF_DYNAMIC_INTERPRETER; - sec->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.dlt, - which will cause it to get stripped from the output file - below. */ - sec = hppa_info->dlt_rel_sec; - if (sec != NULL) - sec->size = 0; - } - - /* Set up DLT, PLT and OPD 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_dlt; - bfd_signed_vma *end_local_dlt; - bfd_signed_vma *local_plt; - bfd_signed_vma *end_local_plt; - bfd_signed_vma *local_opd; - bfd_signed_vma *end_local_opd; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srel; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - struct elf64_hppa_dyn_reloc_entry *hdh_p; - - for (hdh_p = ((struct elf64_hppa_dyn_reloc_entry *) - elf_section_data (sec)->local_dynrel); - hdh_p != NULL; - hdh_p = hdh_p->next) - { - if (!bfd_is_abs_section (hdh_p->sec) - && bfd_is_abs_section (hdh_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 (hdh_p->count != 0) - { - srel = elf_section_data (hdh_p->sec)->sreloc; - srel->size += hdh_p->count * sizeof (Elf64_External_Rela); - if ((hdh_p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - local_dlt = elf_local_got_refcounts (ibfd); - if (!local_dlt) - continue; - - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; - locsymcount = symtab_hdr->sh_info; - end_local_dlt = local_dlt + locsymcount; - sec = hppa_info->dlt_sec; - srel = hppa_info->dlt_rel_sec; - for (; local_dlt < end_local_dlt; ++local_dlt) - { - if (*local_dlt > 0) - { - *local_dlt = sec->size; - sec->size += DLT_ENTRY_SIZE; - if (bfd_link_pic (info)) - { - srel->size += sizeof (Elf64_External_Rela); - } - } - else - *local_dlt = (bfd_vma) -1; - } - - local_plt = end_local_dlt; - end_local_plt = local_plt + locsymcount; - if (! hppa_info->root.dynamic_sections_created) - { - /* Won't be used, but be safe. */ - for (; local_plt < end_local_plt; ++local_plt) - *local_plt = (bfd_vma) -1; - } - else - { - sec = hppa_info->plt_sec; - srel = hppa_info->plt_rel_sec; - for (; local_plt < end_local_plt; ++local_plt) - { - if (*local_plt > 0) - { - *local_plt = sec->size; - sec->size += PLT_ENTRY_SIZE; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf64_External_Rela); - } - else - *local_plt = (bfd_vma) -1; - } - } - - local_opd = end_local_plt; - end_local_opd = local_opd + locsymcount; - if (! hppa_info->root.dynamic_sections_created) - { - /* Won't be used, but be safe. */ - for (; local_opd < end_local_opd; ++local_opd) - *local_opd = (bfd_vma) -1; - } - else - { - sec = hppa_info->opd_sec; - srel = hppa_info->opd_rel_sec; - for (; local_opd < end_local_opd; ++local_opd) - { - if (*local_opd > 0) - { - *local_opd = sec->size; - sec->size += OPD_ENTRY_SIZE; - if (bfd_link_pic (info)) - srel->size += sizeof (Elf64_External_Rela); - } - else - *local_opd = (bfd_vma) -1; - } - } - } - - /* Allocate the GOT entries. */ - - data.info = info; - if (hppa_info->dlt_sec) - { - data.ofs = hppa_info->dlt_sec->size; - elf_link_hash_traverse (&hppa_info->root, - allocate_global_data_dlt, &data); - hppa_info->dlt_sec->size = data.ofs; - } - - if (hppa_info->plt_sec) - { - data.ofs = hppa_info->plt_sec->size; - elf_link_hash_traverse (&hppa_info->root, - allocate_global_data_plt, &data); - hppa_info->plt_sec->size = data.ofs; - } - - if (hppa_info->stub_sec) - { - data.ofs = 0x0; - elf_link_hash_traverse (&hppa_info->root, - allocate_global_data_stub, &data); - hppa_info->stub_sec->size = data.ofs; - } - - /* Allocate space for entries in the .opd section. */ - if (hppa_info->opd_sec) - { - data.ofs = hppa_info->opd_sec->size; - elf_link_hash_traverse (&hppa_info->root, - allocate_global_data_opd, &data); - hppa_info->opd_sec->size = data.ofs; - } - - /* Now allocate space for dynamic relocations, if necessary. */ - if (hppa_info->root.dynamic_sections_created) - elf_link_hash_traverse (&hppa_info->root, - allocate_dynrel_entries, &data); - - /* The sizes of all the sections are set. Allocate memory for them. */ - plt = FALSE; - relocs = FALSE; - reltext = FALSE; - for (sec = dynobj->sections; sec != NULL; sec = sec->next) - { - const char *name; - - if ((sec->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, sec); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = sec->size != 0; - } - else if (strcmp (name, ".opd") == 0 - || CONST_STRNEQ (name, ".dlt") - || strcmp (name, ".stub") == 0 - || strcmp (name, ".got") == 0) - { - /* Strip this section if we don't need it; see the comment below. */ - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (sec->size != 0) - { - asection *target; - - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (strcmp (name, ".rela.plt") != 0) - { - const char *outname; - - relocs = TRUE; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL - entry. The entries in the .rela.plt section - really apply to the .got section, which we - created ourselves and so know is not readonly. */ - outname = bfd_get_section_name (output_bfd, - sec->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 4); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = TRUE; - } - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - sec->reloc_count = 0; - } - } - else - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (sec->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. */ - sec->flags |= SEC_EXCLUDE; - continue; - } - - if ((sec->flags & SEC_HAS_CONTENTS) == 0) - continue; - - /* Allocate memory for the section contents if it has not - been allocated already. 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_PARISC_NONE reloc instead of - garbage. */ - if (sec->contents == NULL) - { - sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->size); - if (sec->contents == NULL) - return FALSE; - } - } - - if (hppa_info->root.dynamic_sections_created) - { - /* Always create a DT_PLTGOT. It actually has nothing to do with - the PLT, it is how we communicate the __gp value of a load - module to the dynamic linker. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (!add_dynamic_entry (DT_HP_DLD_FLAGS, 0) - || !add_dynamic_entry (DT_PLTGOT, 0)) - return FALSE; - - /* Add some entries to the .dynamic section. We fill in the - values later, in elf64_hppa_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. */ - if (! bfd_link_pic (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0) - || !add_dynamic_entry (DT_HP_DLD_HOOK, 0) - || !add_dynamic_entry (DT_HP_LOAD_MAP, 0)) - return FALSE; - } - - /* Force DT_FLAGS to always be set. - Required by HPUX 11.00 patch PHSS_26559. */ - if (!add_dynamic_entry (DT_FLAGS, (info)->flags)) - return FALSE; - - if (plt) - { - if (!add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!add_dynamic_entry (DT_RELA, 0) - || !add_dynamic_entry (DT_RELASZ, 0) - || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela))) - return FALSE; - } - - if (reltext) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - info->flags |= DF_TEXTREL; - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Called after we have output the symbol into the dynamic symbol - table, but before we output the symbol into the normal symbol - table. - - For some symbols we had to change their address when outputting - the dynamic symbol table. We undo that change here so that - the symbols have their expected value in the normal symbol - table. Ick. */ - -static int -elf64_hppa_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 *eh) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - - /* We may be called with the file symbol or section symbols. - They never need munging, so it is safe to ignore them. */ - if (!name || !eh) - return 1; - - /* Function symbols for which we created .opd entries *may* have been - munged by finish_dynamic_symbol and have to be un-munged here. - - Note that finish_dynamic_symbol sometimes turns dynamic symbols - into non-dynamic ones, so we initialize st_shndx to -1 in - mark_exported_functions and check to see if it was overwritten - here instead of just checking eh->dynindx. */ - if (hh->want_opd && hh->st_shndx != -1) - { - /* Restore the saved value and section index. */ - sym->st_value = hh->st_value; - sym->st_shndx = hh->st_shndx; - } - - return 1; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf64_hppa_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *eh, - Elf_Internal_Sym *sym) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - asection *stub, *splt, *sopd, *spltrel; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - stub = hppa_info->stub_sec; - splt = hppa_info->plt_sec; - sopd = hppa_info->opd_sec; - spltrel = hppa_info->plt_rel_sec; - - /* Incredible. It is actually necessary to NOT use the symbol's real - value when building the dynamic symbol table for a shared library. - At least for symbols that refer to functions. - - We will store a new value and section index into the symbol long - enough to output it into the dynamic symbol table, then we restore - the original values (in elf64_hppa_link_output_symbol_hook). */ - if (hh->want_opd) - { - BFD_ASSERT (sopd != NULL); - - /* Save away the original value and section index so that we - can restore them later. */ - hh->st_value = sym->st_value; - hh->st_shndx = sym->st_shndx; - - /* For the dynamic symbol table entry, we want the value to be - address of this symbol's entry within the .opd section. */ - sym->st_value = (hh->opd_offset - + sopd->output_offset - + sopd->output_section->vma); - sym->st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, - sopd->output_section); - } - - /* Initialize a .plt entry if requested. */ - if (hh->want_plt - && elf64_hppa_dynamic_symbol_p (eh, info)) - { - bfd_vma value; - Elf_Internal_Rela rel; - bfd_byte *loc; - - BFD_ASSERT (splt != NULL && spltrel != NULL); - - /* We do not actually care about the value in the PLT entry - if we are creating a shared library and the symbol is - still undefined, we create a dynamic relocation to fill - in the correct value. */ - if (bfd_link_pic (info) && eh->root.type == bfd_link_hash_undefined) - value = 0; - else - value = (eh->root.u.def.value + eh->root.u.def.section->vma); - - /* Fill in the entry in the procedure linkage table. - - The format of a plt entry is - <__gp>. - - plt_offset is the offset within the PLT section at which to - install the PLT entry. - - We are modifying the in-memory PLT contents here, so we do not add - in the output_offset of the PLT section. */ - - bfd_put_64 (splt->owner, value, splt->contents + hh->plt_offset); - value = _bfd_get_gp_value (splt->output_section->owner); - bfd_put_64 (splt->owner, value, splt->contents + hh->plt_offset + 0x8); - - /* Create a dynamic IPLT relocation for this entry. - - We are creating a relocation in the output file's PLT section, - which is included within the DLT secton. So we do need to include - the PLT's output_offset in the computation of the relocation's - address. */ - rel.r_offset = (hh->plt_offset + splt->output_offset - + splt->output_section->vma); - rel.r_info = ELF64_R_INFO (hh->eh.dynindx, R_PARISC_IPLT); - rel.r_addend = 0; - - loc = spltrel->contents; - loc += spltrel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (splt->output_section->owner, &rel, loc); - } - - /* Initialize an external call stub entry if requested. */ - if (hh->want_stub - && elf64_hppa_dynamic_symbol_p (eh, info)) - { - bfd_vma value; - int insn; - unsigned int max_offset; - - BFD_ASSERT (stub != NULL); - - /* Install the generic stub template. - - We are modifying the contents of the stub section, so we do not - need to include the stub section's output_offset here. */ - memcpy (stub->contents + hh->stub_offset, plt_stub, sizeof (plt_stub)); - - /* Fix up the first ldd instruction. - - We are modifying the contents of the STUB section in memory, - so we do not need to include its output offset in this computation. - - Note the plt_offset value is the value of the PLT entry relative to - the start of the PLT section. These instructions will reference - data relative to the value of __gp, which may not necessarily have - the same address as the start of the PLT section. - - gp_offset contains the offset of __gp within the PLT section. */ - value = hh->plt_offset - hppa_info->gp_offset; - - insn = bfd_get_32 (stub->owner, stub->contents + hh->stub_offset); - if (output_bfd->arch_info->mach >= 25) - { - /* Wide mode allows 16 bit offsets. */ - max_offset = 32768; - insn &= ~ 0xfff1; - insn |= re_assemble_16 ((int) value); - } - else - { - max_offset = 8192; - insn &= ~ 0x3ff1; - insn |= re_assemble_14 ((int) value); - } - - if ((value & 7) || value + max_offset >= 2*max_offset - 8) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("stub entry for %s cannot load .plt, dp offset = %Ld"), - hh->eh.root.root.string, value); - return FALSE; - } - - bfd_put_32 (stub->owner, (bfd_vma) insn, - stub->contents + hh->stub_offset); - - /* Fix up the second ldd instruction. */ - value += 8; - insn = bfd_get_32 (stub->owner, stub->contents + hh->stub_offset + 8); - if (output_bfd->arch_info->mach >= 25) - { - insn &= ~ 0xfff1; - insn |= re_assemble_16 ((int) value); - } - else - { - insn &= ~ 0x3ff1; - insn |= re_assemble_14 ((int) value); - } - bfd_put_32 (stub->owner, (bfd_vma) insn, - stub->contents + hh->stub_offset + 8); - } - - return TRUE; -} - -/* The .opd section contains FPTRs for each function this file - exports. Initialize the FPTR entries. */ - -static bfd_boolean -elf64_hppa_finalize_opd (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - asection *sopd; - asection *sopdrel; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - sopd = hppa_info->opd_sec; - sopdrel = hppa_info->opd_rel_sec; - - if (hh->want_opd) - { - bfd_vma value; - - /* The first two words of an .opd entry are zero. - - We are modifying the contents of the OPD section in memory, so we - do not need to include its output offset in this computation. */ - memset (sopd->contents + hh->opd_offset, 0, 16); - - value = (eh->root.u.def.value - + eh->root.u.def.section->output_section->vma - + eh->root.u.def.section->output_offset); - - /* The next word is the address of the function. */ - bfd_put_64 (sopd->owner, value, sopd->contents + hh->opd_offset + 16); - - /* The last word is our local __gp value. */ - value = _bfd_get_gp_value (sopd->output_section->owner); - bfd_put_64 (sopd->owner, value, sopd->contents + hh->opd_offset + 24); - } - - /* If we are generating a shared library, we must generate EPLT relocations - for each entry in the .opd, even for static functions (they may have - had their address taken). */ - if (bfd_link_pic (info) && hh->want_opd) - { - Elf_Internal_Rela rel; - bfd_byte *loc; - int dynindx; - - /* We may need to do a relocation against a local symbol, in - which case we have to look up it's dynamic symbol index off - the local symbol hash table. */ - if (eh->dynindx != -1) - dynindx = eh->dynindx; - else - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, hh->owner, - hh->sym_indx); - - /* The offset of this relocation is the absolute address of the - .opd entry for this symbol. */ - rel.r_offset = (hh->opd_offset + sopd->output_offset - + sopd->output_section->vma); - - /* If H is non-null, then we have an external symbol. - - It is imperative that we use a different dynamic symbol for the - EPLT relocation if the symbol has global scope. - - In the dynamic symbol table, the function symbol will have a value - which is address of the function's .opd entry. - - Thus, we can not use that dynamic symbol for the EPLT relocation - (if we did, the data in the .opd would reference itself rather - than the actual address of the function). Instead we have to use - a new dynamic symbol which has the same value as the original global - function symbol. - - We prefix the original symbol with a "." and use the new symbol in - the EPLT relocation. This new symbol has already been recorded in - the symbol table, we just have to look it up and use it. - - We do not have such problems with static functions because we do - not make their addresses in the dynamic symbol table point to - the .opd entry. Ultimately this should be safe since a static - function can not be directly referenced outside of its shared - library. - - We do have to play similar games for FPTR relocations in shared - libraries, including those for static symbols. See the FPTR - handling in elf64_hppa_finalize_dynreloc. */ - if (eh) - { - char *new_name; - struct elf_link_hash_entry *nh; - - new_name = concat (".", eh->root.root.string, NULL); - - nh = elf_link_hash_lookup (elf_hash_table (info), - new_name, TRUE, TRUE, FALSE); - - /* All we really want from the new symbol is its dynamic - symbol index. */ - if (nh) - dynindx = nh->dynindx; - free (new_name); - } - - rel.r_addend = 0; - rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_EPLT); - - loc = sopdrel->contents; - loc += sopdrel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (sopd->output_section->owner, &rel, loc); - } - return TRUE; -} - -/* The .dlt section contains addresses for items referenced through the - dlt. Note that we can have a DLTIND relocation for a local symbol, thus - we can not depend on finish_dynamic_symbol to initialize the .dlt. */ - -static bfd_boolean -elf64_hppa_finalize_dlt (struct elf_link_hash_entry *eh, void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - asection *sdlt, *sdltrel; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - sdlt = hppa_info->dlt_sec; - sdltrel = hppa_info->dlt_rel_sec; - - /* H/DYN_H may refer to a local variable and we know it's - address, so there is no need to create a relocation. Just install - the proper value into the DLT, note this shortcut can not be - skipped when building a shared library. */ - if (! bfd_link_pic (info) && hh && hh->want_dlt) - { - bfd_vma value; - - /* If we had an LTOFF_FPTR style relocation we want the DLT entry - to point to the FPTR entry in the .opd section. - - We include the OPD's output offset in this computation as - we are referring to an absolute address in the resulting - object file. */ - if (hh->want_opd) - { - value = (hh->opd_offset - + hppa_info->opd_sec->output_offset - + hppa_info->opd_sec->output_section->vma); - } - else if ((eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak) - && eh->root.u.def.section) - { - value = eh->root.u.def.value + eh->root.u.def.section->output_offset; - if (eh->root.u.def.section->output_section) - value += eh->root.u.def.section->output_section->vma; - else - value += eh->root.u.def.section->vma; - } - else - /* We have an undefined function reference. */ - value = 0; - - /* We do not need to include the output offset of the DLT section - here because we are modifying the in-memory contents. */ - bfd_put_64 (sdlt->owner, value, sdlt->contents + hh->dlt_offset); - } - - /* Create a relocation for the DLT entry associated with this symbol. - When building a shared library the symbol does not have to be dynamic. */ - if (hh->want_dlt - && (elf64_hppa_dynamic_symbol_p (eh, info) || bfd_link_pic (info))) - { - Elf_Internal_Rela rel; - bfd_byte *loc; - int dynindx; - - /* We may need to do a relocation against a local symbol, in - which case we have to look up it's dynamic symbol index off - the local symbol hash table. */ - if (eh && eh->dynindx != -1) - dynindx = eh->dynindx; - else - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, hh->owner, - hh->sym_indx); - - /* Create a dynamic relocation for this entry. Do include the output - offset of the DLT entry since we need an absolute address in the - resulting object file. */ - rel.r_offset = (hh->dlt_offset + sdlt->output_offset - + sdlt->output_section->vma); - if (eh && eh->type == STT_FUNC) - rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_FPTR64); - else - rel.r_info = ELF64_R_INFO (dynindx, R_PARISC_DIR64); - rel.r_addend = 0; - - loc = sdltrel->contents; - loc += sdltrel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (sdlt->output_section->owner, &rel, loc); - } - return TRUE; -} - -/* Finalize the dynamic relocations. Specifically the FPTR relocations - for dynamic functions used to initialize static data. */ - -static bfd_boolean -elf64_hppa_finalize_dynreloc (struct elf_link_hash_entry *eh, - void *data) -{ - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - struct bfd_link_info *info = (struct bfd_link_info *)data; - struct elf64_hppa_link_hash_table *hppa_info; - int dynamic_symbol; - - dynamic_symbol = elf64_hppa_dynamic_symbol_p (eh, info); - - if (!dynamic_symbol && !bfd_link_pic (info)) - return TRUE; - - if (hh->reloc_entries) - { - struct elf64_hppa_dyn_reloc_entry *rent; - int dynindx; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - /* We may need to do a relocation against a local symbol, in - which case we have to look up it's dynamic symbol index off - the local symbol hash table. */ - if (eh->dynindx != -1) - dynindx = eh->dynindx; - else - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, hh->owner, - hh->sym_indx); - - for (rent = hh->reloc_entries; rent; rent = rent->next) - { - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* Allocate one iff we are building a shared library, the relocation - isn't a R_PARISC_FPTR64, or we don't want an opd entry. */ - if (!bfd_link_pic (info) - && rent->type == R_PARISC_FPTR64 && hh->want_opd) - continue; - - /* Create a dynamic relocation for this entry. - - We need the output offset for the reloc's section because - we are creating an absolute address in the resulting object - file. */ - rel.r_offset = (rent->offset + rent->sec->output_offset - + rent->sec->output_section->vma); - - /* An FPTR64 relocation implies that we took the address of - a function and that the function has an entry in the .opd - section. We want the FPTR64 relocation to reference the - entry in .opd. - - We could munge the symbol value in the dynamic symbol table - (in fact we already do for functions with global scope) to point - to the .opd entry. Then we could use that dynamic symbol in - this relocation. - - Or we could do something sensible, not munge the symbol's - address and instead just use a different symbol to reference - the .opd entry. At least that seems sensible until you - realize there's no local dynamic symbols we can use for that - purpose. Thus the hair in the check_relocs routine. - - We use a section symbol recorded by check_relocs as the - base symbol for the relocation. The addend is the difference - between the section symbol and the address of the .opd entry. */ - if (bfd_link_pic (info) - && rent->type == R_PARISC_FPTR64 && hh->want_opd) - { - bfd_vma value, value2; - - /* First compute the address of the opd entry for this symbol. */ - value = (hh->opd_offset - + hppa_info->opd_sec->output_section->vma - + hppa_info->opd_sec->output_offset); - - /* Compute the value of the start of the section with - the relocation. */ - value2 = (rent->sec->output_section->vma - + rent->sec->output_offset); - - /* Compute the difference between the start of the section - with the relocation and the opd entry. */ - value -= value2; - - /* The result becomes the addend of the relocation. */ - rel.r_addend = value; - - /* The section symbol becomes the symbol for the dynamic - relocation. */ - dynindx - = _bfd_elf_link_lookup_local_dynindx (info, - rent->sec->owner, - rent->sec_symndx); - } - else - rel.r_addend = rent->addend; - - rel.r_info = ELF64_R_INFO (dynindx, rent->type); - - loc = hppa_info->other_rel_sec->contents; - loc += (hppa_info->other_rel_sec->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (hppa_info->other_rel_sec->output_section->owner, - &rel, loc); - } - } - - 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_hppa_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - if (ELF64_R_SYM (rela->r_info) == STN_UNDEF) - return reloc_class_relative; - - switch ((int) ELF64_R_TYPE (rela->r_info)) - { - case R_PARISC_IPLT: - return reloc_class_plt; - case R_PARISC_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf64_hppa_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sdyn; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - /* Finalize the contents of the .opd section. */ - elf_link_hash_traverse (elf_hash_table (info), - elf64_hppa_finalize_opd, - info); - - elf_link_hash_traverse (elf_hash_table (info), - elf64_hppa_finalize_dynreloc, - info); - - /* Finalize the contents of the .dlt section. */ - dynobj = elf_hash_table (info)->dynobj; - /* Finalize the contents of the .dlt section. */ - elf_link_hash_traverse (elf_hash_table (info), - elf64_hppa_finalize_dlt, - info); - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf64_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sdyn != NULL); - - 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: - break; - - case DT_HP_LOAD_MAP: - /* Compute the absolute address of 16byte scratchpad area - for the dynamic linker. - - By convention the linker script will allocate the scratchpad - area at the start of the .data section. So all we have to - to is find the start of the .data section. */ - s = bfd_get_section_by_name (output_bfd, ".data"); - if (!s) - return FALSE; - dyn.d_un.d_ptr = s->vma; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTGOT: - /* HP's use PLTGOT to set the GOT register. */ - dyn.d_un.d_ptr = _bfd_get_gp_value (output_bfd); - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_JMPREL: - s = hppa_info->plt_rel_sec; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = hppa_info->plt_rel_sec; - dyn.d_un.d_val = s->size; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_RELA: - s = hppa_info->other_rel_sec; - if (! s || ! s->size) - s = hppa_info->dlt_rel_sec; - if (! s || ! s->size) - s = hppa_info->opd_rel_sec; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_RELASZ: - s = hppa_info->other_rel_sec; - dyn.d_un.d_val = s->size; - s = hppa_info->dlt_rel_sec; - dyn.d_un.d_val += s->size; - s = hppa_info->opd_rel_sec; - dyn.d_un.d_val += s->size; - /* There is some question about whether or not the size of - the PLT relocs should be included here. HP's tools do - it, so we'll emulate them. */ - s = hppa_info->plt_rel_sec; - dyn.d_un.d_val += s->size; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - } - } - } - - return TRUE; -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf64_hppa_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 760: /* Linux/hppa */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32); - - /* pr_reg */ - offset = 112; - size = 640; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf64_hppa_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - char * command; - int n; - - switch (note->descsz) - { - default: - return FALSE; - - case 136: /* Linux/hppa elf_prpsinfo. */ - 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. */ - command = elf_tdata (abfd)->core->command; - n = strlen (command); - - if (0 < n && command[n - 1] == ' ') - command[n - 1] = '\0'; - - return TRUE; -} - -/* Return the number of additional phdrs we will need. - - The generic ELF code only creates PT_PHDRs for executables. The HP - dynamic linker requires PT_PHDRs for dynamic libraries too. - - This routine indicates that the backend needs one additional program - header for that case. - - Note we do not have access to the link info structure here, so we have - to guess whether or not we are building a shared library based on the - existence of a .interp section. */ - -static int -elf64_hppa_additional_program_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - asection *s; - - /* If we are creating a shared library, then we have to create a - PT_PHDR segment. HP's dynamic linker chokes without it. */ - s = bfd_get_section_by_name (abfd, ".interp"); - if (! s) - return 1; - return 0; -} - -static bfd_boolean -elf64_hppa_allow_non_load_phdr (bfd *abfd ATTRIBUTE_UNUSED, - const Elf_Internal_Phdr *phdr ATTRIBUTE_UNUSED, - unsigned int count ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Allocate and initialize any program headers required by this - specific backend. - - The generic ELF code only creates PT_PHDRs for executables. The HP - dynamic linker requires PT_PHDRs for dynamic libraries too. - - This allocates the PT_PHDR and initializes it in a manner suitable - for the HP linker. - - Note we do not have access to the link info structure here, so we have - to guess whether or not we are building a shared library based on the - existence of a .interp section. */ - -static bfd_boolean -elf64_hppa_modify_segment_map (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_segment_map *m; - - m = elf_seg_map (abfd); - if (info != NULL && !info->user_phdrs && m != NULL && m->p_type != PT_PHDR) - { - m = ((struct elf_segment_map *) - bfd_zalloc (abfd, (bfd_size_type) sizeof *m)); - if (m == NULL) - return FALSE; - - m->p_type = PT_PHDR; - m->p_flags = PF_R | PF_X; - m->p_flags_valid = 1; - m->p_paddr_valid = 1; - m->includes_phdrs = 1; - - m->next = elf_seg_map (abfd); - elf_seg_map (abfd) = m; - } - - for (m = elf_seg_map (abfd) ; m != NULL; m = m->next) - if (m->p_type == PT_LOAD) - { - unsigned int i; - - for (i = 0; i < m->count; i++) - { - /* The code "hint" is not really a hint. It is a requirement - for certain versions of the HP dynamic linker. Worse yet, - it must be set even if the shared library does not have - any code in its "text" segment (thus the check for .hash - to catch this situation). */ - if (m->sections[i]->flags & SEC_CODE - || (strcmp (m->sections[i]->name, ".hash") == 0)) - m->p_flags |= (PF_X | PF_HP_CODE); - } - } - - return TRUE; -} - -/* Called when writing out an object file to decide the type of a - symbol. */ -static int -elf64_hppa_elf_get_symbol_type (Elf_Internal_Sym *elf_sym, - int type) -{ - if (ELF_ST_TYPE (elf_sym->st_info) == STT_PARISC_MILLI) - return STT_PARISC_MILLI; - else - return type; -} - -/* Support HP specific sections for core files. */ - -static bfd_boolean -elf64_hppa_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int sec_index, - const char *typename) -{ - if (hdr->p_type == PT_HP_CORE_KERNEL) - { - asection *sect; - - if (!_bfd_elf_make_section_from_phdr (abfd, hdr, sec_index, typename)) - return FALSE; - - sect = bfd_make_section_anyway (abfd, ".kernel"); - if (sect == NULL) - return FALSE; - sect->size = hdr->p_filesz; - sect->filepos = hdr->p_offset; - sect->flags = SEC_HAS_CONTENTS | SEC_READONLY; - return TRUE; - } - - if (hdr->p_type == PT_HP_CORE_PROC) - { - int sig; - - if (bfd_seek (abfd, hdr->p_offset, SEEK_SET) != 0) - return FALSE; - if (bfd_bread (&sig, 4, abfd) != 4) - return FALSE; - - elf_tdata (abfd)->core->signal = sig; - - if (!_bfd_elf_make_section_from_phdr (abfd, hdr, sec_index, typename)) - return FALSE; - - /* GDB uses the ".reg" section to read register contents. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", hdr->p_filesz, - hdr->p_offset); - } - - if (hdr->p_type == PT_HP_CORE_LOADABLE - || hdr->p_type == PT_HP_CORE_STACK - || hdr->p_type == PT_HP_CORE_MMF) - hdr->p_type = PT_LOAD; - - return _bfd_elf_make_section_from_phdr (abfd, hdr, sec_index, typename); -} - -/* Hook called by the linker routine which adds symbols from an object - file. HP's libraries define symbols with HP specific section - indices, which we have to handle. */ - -static bfd_boolean -elf_hppa_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) -{ - unsigned int sec_index = sym->st_shndx; - - switch (sec_index) - { - case SHN_PARISC_ANSI_COMMON: - *secp = bfd_make_section_old_way (abfd, ".PARISC.ansi.common"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - - case SHN_PARISC_HUGE_COMMON: - *secp = bfd_make_section_old_way (abfd, ".PARISC.huge.common"); - (*secp)->flags |= SEC_IS_COMMON; - *valp = sym->st_size; - break; - } - - return TRUE; -} - -static bfd_boolean -elf_hppa_unmark_useless_dynamic_symbols (struct elf_link_hash_entry *h, - void *data) -{ - struct bfd_link_info *info = data; - - /* If we are not creating a shared library, and this symbol is - referenced by a shared library but is not defined anywhere, then - the generic code will warn that it is undefined. - - This behavior is undesirable on HPs since the standard shared - libraries contain references to undefined symbols. - - So we twiddle the flags associated with such symbols so that they - will not trigger the warning. ?!? FIXME. This is horribly fragile. - - Ultimately we should have better controls over the generic ELF BFD - linker code. */ - if (! bfd_link_relocatable (info) - && info->unresolved_syms_in_shared_libs != RM_IGNORE - && h->root.type == bfd_link_hash_undefined - && h->ref_dynamic - && !h->ref_regular) - { - h->ref_dynamic = 0; - h->pointer_equality_needed = 1; - } - - return TRUE; -} - -static bfd_boolean -elf_hppa_remark_useless_dynamic_symbols (struct elf_link_hash_entry *h, - void *data) -{ - struct bfd_link_info *info = data; - - /* If we are not creating a shared library, and this symbol is - referenced by a shared library but is not defined anywhere, then - the generic code will warn that it is undefined. - - This behavior is undesirable on HPs since the standard shared - libraries contain references to undefined symbols. - - So we twiddle the flags associated with such symbols so that they - will not trigger the warning. ?!? FIXME. This is horribly fragile. - - Ultimately we should have better controls over the generic ELF BFD - linker code. */ - if (! bfd_link_relocatable (info) - && info->unresolved_syms_in_shared_libs != RM_IGNORE - && h->root.type == bfd_link_hash_undefined - && !h->ref_dynamic - && !h->ref_regular - && h->pointer_equality_needed) - { - h->ref_dynamic = 1; - h->pointer_equality_needed = 0; - } - - return TRUE; -} - -static bfd_boolean -elf_hppa_is_dynamic_loader_symbol (const char *name) -{ - return (! strcmp (name, "__CPU_REVISION") - || ! strcmp (name, "__CPU_KEYBITS_1") - || ! strcmp (name, "__SYSTEM_ID_D") - || ! strcmp (name, "__FPU_MODEL") - || ! strcmp (name, "__FPU_REVISION") - || ! strcmp (name, "__ARGC") - || ! strcmp (name, "__ARGV") - || ! strcmp (name, "__ENVP") - || ! strcmp (name, "__TLS_SIZE_D") - || ! strcmp (name, "__LOAD_INFO") - || ! strcmp (name, "__systab")); -} - -/* Record the lowest address for the data and text segments. */ -static void -elf_hppa_record_segment_addrs (bfd *abfd, - asection *section, - void *data) -{ - struct elf64_hppa_link_hash_table *hppa_info = data; - - if ((section->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) - { - bfd_vma value; - Elf_Internal_Phdr *p; - - p = _bfd_elf_find_segment_containing_section (abfd, section->output_section); - BFD_ASSERT (p != NULL); - value = p->p_vaddr; - - if (section->flags & SEC_READONLY) - { - if (value < hppa_info->text_segment_base) - hppa_info->text_segment_base = value; - } - else - { - if (value < hppa_info->data_segment_base) - hppa_info->data_segment_base = value; - } - } -} - -/* Called after we have seen all the input files/sections, but before - final symbol resolution and section placement has been determined. - - We use this hook to (possibly) provide a value for __gp, then we - fall back to the generic ELF final link routine. */ - -static bfd_boolean -elf_hppa_final_link (bfd *abfd, struct bfd_link_info *info) -{ - struct stat buf; - struct elf64_hppa_link_hash_table *hppa_info = hppa_link_hash_table (info); - - if (hppa_info == NULL) - return FALSE; - - if (! bfd_link_relocatable (info)) - { - struct elf_link_hash_entry *gp; - bfd_vma gp_val; - - /* The linker script defines a value for __gp iff it was referenced - by one of the objects being linked. First try to find the symbol - in the hash table. If that fails, just compute the value __gp - should have had. */ - gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, - FALSE, FALSE); - - if (gp) - { - - /* Adjust the value of __gp as we may want to slide it into the - .plt section so that the stubs can access PLT entries without - using an addil sequence. */ - gp->root.u.def.value += hppa_info->gp_offset; - - gp_val = (gp->root.u.def.section->output_section->vma - + gp->root.u.def.section->output_offset - + gp->root.u.def.value); - } - else - { - asection *sec; - - /* First look for a .plt section. If found, then __gp is the - address of the .plt + gp_offset. - - If no .plt is found, then look for .dlt, .opd and .data (in - that order) and set __gp to the base address of whichever - section is found first. */ - - sec = hppa_info->plt_sec; - if (sec && ! (sec->flags & SEC_EXCLUDE)) - gp_val = (sec->output_offset - + sec->output_section->vma - + hppa_info->gp_offset); - else - { - sec = hppa_info->dlt_sec; - if (!sec || (sec->flags & SEC_EXCLUDE)) - sec = hppa_info->opd_sec; - if (!sec || (sec->flags & SEC_EXCLUDE)) - sec = bfd_get_section_by_name (abfd, ".data"); - if (!sec || (sec->flags & SEC_EXCLUDE)) - gp_val = 0; - else - gp_val = sec->output_offset + sec->output_section->vma; - } - } - - /* Install whatever value we found/computed for __gp. */ - _bfd_set_gp_value (abfd, gp_val); - } - - /* We need to know the base of the text and data segments so that we - can perform SEGREL relocations. We will record the base addresses - when we encounter the first SEGREL relocation. */ - hppa_info->text_segment_base = (bfd_vma)-1; - hppa_info->data_segment_base = (bfd_vma)-1; - - /* HP's shared libraries have references to symbols that are not - defined anywhere. The generic ELF BFD linker code will complain - about such symbols. - - So we detect the losing case and arrange for the flags on the symbol - to indicate that it was never referenced. This keeps the generic - ELF BFD link code happy and appears to not create any secondary - problems. Ultimately we need a way to control the behavior of the - generic ELF BFD link code better. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_hppa_unmark_useless_dynamic_symbols, - info); - - /* Invoke the regular ELF backend linker to do all the work. */ - if (!bfd_elf_final_link (abfd, info)) - return FALSE; - - elf_link_hash_traverse (elf_hash_table (info), - elf_hppa_remark_useless_dynamic_symbols, - info); - - /* If we're producing a final executable, sort the contents of the - unwind section. */ - if (bfd_link_relocatable (info)) - return TRUE; - - /* Do not attempt to sort non-regular files. This is here - especially for configure scripts and kernel builds which run - tests with "ld [...] -o /dev/null". */ - if (stat (abfd->filename, &buf) != 0 - || !S_ISREG(buf.st_mode)) - return TRUE; - - return elf_hppa_sort_unwind (abfd); -} - -/* Relocate the given INSN. VALUE should be the actual value we want - to insert into the instruction, ie by this point we should not be - concerned with computing an offset relative to the DLT, PC, etc. - Instead this routine is meant to handle the bit manipulations needed - to insert the relocation into the given instruction. */ - -static int -elf_hppa_relocate_insn (int insn, int sym_value, unsigned int r_type) -{ - switch (r_type) - { - /* This is any 22 bit branch. In PA2.0 syntax it corresponds to - the "B" instruction. */ - case R_PARISC_PCREL22F: - case R_PARISC_PCREL22C: - return (insn & ~0x3ff1ffd) | re_assemble_22 (sym_value); - - /* This is any 12 bit branch. */ - case R_PARISC_PCREL12F: - return (insn & ~0x1ffd) | re_assemble_12 (sym_value); - - /* This is any 17 bit branch. In PA2.0 syntax it also corresponds - to the "B" instruction as well as BE. */ - case R_PARISC_PCREL17F: - case R_PARISC_DIR17F: - case R_PARISC_DIR17R: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL17R: - return (insn & ~0x1f1ffd) | re_assemble_17 (sym_value); - - /* ADDIL or LDIL instructions. */ - case R_PARISC_DLTREL21L: - case R_PARISC_DLTIND21L: - case R_PARISC_LTOFF_FPTR21L: - case R_PARISC_PCREL21L: - case R_PARISC_LTOFF_TP21L: - case R_PARISC_DPREL21L: - case R_PARISC_PLTOFF21L: - case R_PARISC_DIR21L: - return (insn & ~0x1fffff) | re_assemble_21 (sym_value); - - /* LDO and integer loads/stores with 14 bit displacements. */ - case R_PARISC_DLTREL14R: - case R_PARISC_DLTREL14F: - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND14F: - case R_PARISC_LTOFF_FPTR14R: - case R_PARISC_PCREL14R: - case R_PARISC_PCREL14F: - case R_PARISC_LTOFF_TP14R: - case R_PARISC_LTOFF_TP14F: - case R_PARISC_DPREL14R: - case R_PARISC_DPREL14F: - case R_PARISC_PLTOFF14R: - case R_PARISC_PLTOFF14F: - case R_PARISC_DIR14R: - case R_PARISC_DIR14F: - return (insn & ~0x3fff) | low_sign_unext (sym_value, 14); - - /* PA2.0W LDO and integer loads/stores with 16 bit displacements. */ - case R_PARISC_LTOFF_FPTR16F: - case R_PARISC_PCREL16F: - case R_PARISC_LTOFF_TP16F: - case R_PARISC_GPREL16F: - case R_PARISC_PLTOFF16F: - case R_PARISC_DIR16F: - case R_PARISC_LTOFF16F: - return (insn & ~0xffff) | re_assemble_16 (sym_value); - - /* Doubleword loads and stores with a 14 bit displacement. */ - case R_PARISC_DLTREL14DR: - case R_PARISC_DLTIND14DR: - case R_PARISC_LTOFF_FPTR14DR: - case R_PARISC_LTOFF_FPTR16DF: - case R_PARISC_PCREL14DR: - case R_PARISC_PCREL16DF: - case R_PARISC_LTOFF_TP14DR: - case R_PARISC_LTOFF_TP16DF: - case R_PARISC_DPREL14DR: - case R_PARISC_GPREL16DF: - case R_PARISC_PLTOFF14DR: - case R_PARISC_PLTOFF16DF: - case R_PARISC_DIR14DR: - case R_PARISC_DIR16DF: - case R_PARISC_LTOFF16DF: - return (insn & ~0x3ff1) | (((sym_value & 0x2000) >> 13) - | ((sym_value & 0x1ff8) << 1)); - - /* Floating point single word load/store instructions. */ - case R_PARISC_DLTREL14WR: - case R_PARISC_DLTIND14WR: - case R_PARISC_LTOFF_FPTR14WR: - case R_PARISC_LTOFF_FPTR16WF: - case R_PARISC_PCREL14WR: - case R_PARISC_PCREL16WF: - case R_PARISC_LTOFF_TP14WR: - case R_PARISC_LTOFF_TP16WF: - case R_PARISC_DPREL14WR: - case R_PARISC_GPREL16WF: - case R_PARISC_PLTOFF14WR: - case R_PARISC_PLTOFF16WF: - case R_PARISC_DIR16WF: - case R_PARISC_DIR14WR: - case R_PARISC_LTOFF16WF: - return (insn & ~0x3ff9) | (((sym_value & 0x2000) >> 13) - | ((sym_value & 0x1ffc) << 1)); - - default: - return insn; - } -} - -/* Compute the value for a relocation (REL) during a final link stage, - then insert the value into the proper location in CONTENTS. - - VALUE is a tentative value for the relocation and may be overridden - and modified here based on the specific relocation to be performed. - - For example we do conversions for PC-relative branches in this routine - or redirection of calls to external routines to stubs. - - The work of actually applying the relocation is left to a helper - routine in an attempt to reduce the complexity and size of this - function. */ - -static bfd_reloc_status_type -elf_hppa_final_link_relocate (Elf_Internal_Rela *rel, - bfd *input_bfd, - bfd *output_bfd, - asection *input_section, - bfd_byte *contents, - bfd_vma value, - struct bfd_link_info *info, - asection *sym_sec, - struct elf_link_hash_entry *eh) -{ - struct elf64_hppa_link_hash_table *hppa_info = hppa_link_hash_table (info); - struct elf64_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh); - bfd_vma *local_offsets; - Elf_Internal_Shdr *symtab_hdr; - int insn; - bfd_vma max_branch_offset = 0; - bfd_vma offset = rel->r_offset; - bfd_signed_vma addend = rel->r_addend; - reloc_howto_type *howto = elf_hppa_howto_table + ELF_R_TYPE (rel->r_info); - unsigned int r_symndx = ELF_R_SYM (rel->r_info); - unsigned int r_type = howto->type; - bfd_byte *hit_data = contents + offset; - - if (hppa_info == NULL) - return bfd_reloc_notsupported; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - local_offsets = elf_local_got_offsets (input_bfd); - insn = bfd_get_32 (input_bfd, hit_data); - - switch (r_type) - { - case R_PARISC_NONE: - break; - - /* Basic function call support. - - Note for a call to a function defined in another dynamic library - we want to redirect the call to a stub. */ - - /* PC relative relocs without an implicit offset. */ - case R_PARISC_PCREL21L: - case R_PARISC_PCREL14R: - case R_PARISC_PCREL14F: - case R_PARISC_PCREL14WR: - case R_PARISC_PCREL14DR: - case R_PARISC_PCREL16F: - case R_PARISC_PCREL16WF: - case R_PARISC_PCREL16DF: - { - /* If this is a call to a function defined in another dynamic - library, then redirect the call to the local stub for this - function. */ - if (sym_sec == NULL || sym_sec->output_section == NULL) - value = (hh->stub_offset + hppa_info->stub_sec->output_offset - + hppa_info->stub_sec->output_section->vma); - - /* Turn VALUE into a proper PC relative address. */ - value -= (offset + input_section->output_offset - + input_section->output_section->vma); - - /* Adjust for any field selectors. */ - if (r_type == R_PARISC_PCREL21L) - value = hppa_field_adjust (value, -8 + addend, e_lsel); - else if (r_type == R_PARISC_PCREL14F - || r_type == R_PARISC_PCREL16F - || r_type == R_PARISC_PCREL16WF - || r_type == R_PARISC_PCREL16DF) - value = hppa_field_adjust (value, -8 + addend, e_fsel); - else - value = hppa_field_adjust (value, -8 + addend, e_rsel); - - /* Apply the relocation to the given instruction. */ - insn = elf_hppa_relocate_insn (insn, (int) value, r_type); - break; - } - - case R_PARISC_PCREL12F: - case R_PARISC_PCREL22F: - case R_PARISC_PCREL17F: - case R_PARISC_PCREL22C: - case R_PARISC_PCREL17C: - case R_PARISC_PCREL17R: - { - /* If this is a call to a function defined in another dynamic - library, then redirect the call to the local stub for this - function. */ - if (sym_sec == NULL || sym_sec->output_section == NULL) - value = (hh->stub_offset + hppa_info->stub_sec->output_offset - + hppa_info->stub_sec->output_section->vma); - - /* Turn VALUE into a proper PC relative address. */ - value -= (offset + input_section->output_offset - + input_section->output_section->vma); - addend -= 8; - - if (r_type == (unsigned int) R_PARISC_PCREL22F) - max_branch_offset = (1 << (22-1)) << 2; - else if (r_type == (unsigned int) R_PARISC_PCREL17F) - max_branch_offset = (1 << (17-1)) << 2; - else if (r_type == (unsigned int) R_PARISC_PCREL12F) - max_branch_offset = (1 << (12-1)) << 2; - - /* Make sure we can reach the branch target. */ - if (max_branch_offset != 0 - && value + addend + max_branch_offset >= 2*max_branch_offset) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): cannot reach %s"), - input_bfd, - input_section, - offset, - eh ? eh->root.root.string : "unknown"); - bfd_set_error (bfd_error_bad_value); - return bfd_reloc_overflow; - } - - /* Adjust for any field selectors. */ - if (r_type == R_PARISC_PCREL17R) - value = hppa_field_adjust (value, addend, e_rsel); - else - value = hppa_field_adjust (value, addend, e_fsel); - - /* All branches are implicitly shifted by 2 places. */ - value >>= 2; - - /* Apply the relocation to the given instruction. */ - insn = elf_hppa_relocate_insn (insn, (int) value, r_type); - break; - } - - /* Indirect references to data through the DLT. */ - case R_PARISC_DLTIND14R: - case R_PARISC_DLTIND14F: - case R_PARISC_DLTIND14DR: - case R_PARISC_DLTIND14WR: - case R_PARISC_DLTIND21L: - case R_PARISC_LTOFF_FPTR14R: - case R_PARISC_LTOFF_FPTR14DR: - case R_PARISC_LTOFF_FPTR14WR: - case R_PARISC_LTOFF_FPTR21L: - case R_PARISC_LTOFF_FPTR16F: - case R_PARISC_LTOFF_FPTR16WF: - case R_PARISC_LTOFF_FPTR16DF: - case R_PARISC_LTOFF_TP21L: - case R_PARISC_LTOFF_TP14R: - case R_PARISC_LTOFF_TP14F: - case R_PARISC_LTOFF_TP14WR: - case R_PARISC_LTOFF_TP14DR: - case R_PARISC_LTOFF_TP16F: - case R_PARISC_LTOFF_TP16WF: - case R_PARISC_LTOFF_TP16DF: - case R_PARISC_LTOFF16F: - case R_PARISC_LTOFF16WF: - case R_PARISC_LTOFF16DF: - { - bfd_vma off; - - /* If this relocation was against a local symbol, then we still - have not set up the DLT entry (it's not convenient to do so - in the "finalize_dlt" routine because it is difficult to get - to the local symbol's value). - - So, if this is a local symbol (h == NULL), then we need to - fill in its DLT entry. - - Similarly we may still need to set up an entry in .opd for - a local function which had its address taken. */ - if (hh == NULL) - { - bfd_vma *local_opd_offsets, *local_dlt_offsets; - - if (local_offsets == NULL) - abort (); - - /* Now do .opd creation if needed. */ - if (r_type == R_PARISC_LTOFF_FPTR14R - || r_type == R_PARISC_LTOFF_FPTR14DR - || r_type == R_PARISC_LTOFF_FPTR14WR - || r_type == R_PARISC_LTOFF_FPTR21L - || r_type == R_PARISC_LTOFF_FPTR16F - || r_type == R_PARISC_LTOFF_FPTR16WF - || r_type == R_PARISC_LTOFF_FPTR16DF) - { - local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info; - off = local_opd_offsets[r_symndx]; - - /* The last bit records whether we've already initialised - this local .opd entry. */ - if ((off & 1) != 0) - { - BFD_ASSERT (off != (bfd_vma) -1); - off &= ~1; - } - else - { - local_opd_offsets[r_symndx] |= 1; - - /* The first two words of an .opd entry are zero. */ - memset (hppa_info->opd_sec->contents + off, 0, 16); - - /* The next word is the address of the function. */ - bfd_put_64 (hppa_info->opd_sec->owner, value + addend, - (hppa_info->opd_sec->contents + off + 16)); - - /* The last word is our local __gp value. */ - value = _bfd_get_gp_value - (hppa_info->opd_sec->output_section->owner); - bfd_put_64 (hppa_info->opd_sec->owner, value, - (hppa_info->opd_sec->contents + off + 24)); - } - - /* The DLT value is the address of the .opd entry. */ - value = (off - + hppa_info->opd_sec->output_offset - + hppa_info->opd_sec->output_section->vma); - addend = 0; - } - - local_dlt_offsets = local_offsets; - off = local_dlt_offsets[r_symndx]; - - if ((off & 1) != 0) - { - BFD_ASSERT (off != (bfd_vma) -1); - off &= ~1; - } - else - { - local_dlt_offsets[r_symndx] |= 1; - bfd_put_64 (hppa_info->dlt_sec->owner, - value + addend, - hppa_info->dlt_sec->contents + off); - } - } - else - off = hh->dlt_offset; - - /* We want the value of the DLT offset for this symbol, not - the symbol's actual address. Note that __gp may not point - to the start of the DLT, so we have to compute the absolute - address, then subtract out the value of __gp. */ - value = (off - + hppa_info->dlt_sec->output_offset - + hppa_info->dlt_sec->output_section->vma); - value -= _bfd_get_gp_value (output_bfd); - - /* All DLTIND relocations are basically the same at this point, - except that we need different field selectors for the 21bit - version vs the 14bit versions. */ - if (r_type == R_PARISC_DLTIND21L - || r_type == R_PARISC_LTOFF_FPTR21L - || r_type == R_PARISC_LTOFF_TP21L) - value = hppa_field_adjust (value, 0, e_lsel); - else if (r_type == R_PARISC_DLTIND14F - || r_type == R_PARISC_LTOFF_FPTR16F - || r_type == R_PARISC_LTOFF_FPTR16WF - || r_type == R_PARISC_LTOFF_FPTR16DF - || r_type == R_PARISC_LTOFF16F - || r_type == R_PARISC_LTOFF16DF - || r_type == R_PARISC_LTOFF16WF - || r_type == R_PARISC_LTOFF_TP16F - || r_type == R_PARISC_LTOFF_TP16WF - || r_type == R_PARISC_LTOFF_TP16DF) - value = hppa_field_adjust (value, 0, e_fsel); - else - value = hppa_field_adjust (value, 0, e_rsel); - - insn = elf_hppa_relocate_insn (insn, (int) value, r_type); - break; - } - - case R_PARISC_DLTREL14R: - case R_PARISC_DLTREL14F: - case R_PARISC_DLTREL14DR: - case R_PARISC_DLTREL14WR: - case R_PARISC_DLTREL21L: - case R_PARISC_DPREL21L: - case R_PARISC_DPREL14WR: - case R_PARISC_DPREL14DR: - case R_PARISC_DPREL14R: - case R_PARISC_DPREL14F: - case R_PARISC_GPREL16F: - case R_PARISC_GPREL16WF: - case R_PARISC_GPREL16DF: - { - /* Subtract out the global pointer value to make value a DLT - relative address. */ - value -= _bfd_get_gp_value (output_bfd); - - /* All DLTREL relocations are basically the same at this point, - except that we need different field selectors for the 21bit - version vs the 14bit versions. */ - if (r_type == R_PARISC_DLTREL21L - || r_type == R_PARISC_DPREL21L) - value = hppa_field_adjust (value, addend, e_lrsel); - else if (r_type == R_PARISC_DLTREL14F - || r_type == R_PARISC_DPREL14F - || r_type == R_PARISC_GPREL16F - || r_type == R_PARISC_GPREL16WF - || r_type == R_PARISC_GPREL16DF) - value = hppa_field_adjust (value, addend, e_fsel); - else - value = hppa_field_adjust (value, addend, e_rrsel); - - insn = elf_hppa_relocate_insn (insn, (int) value, r_type); - break; - } - - case R_PARISC_DIR21L: - case R_PARISC_DIR17R: - case R_PARISC_DIR17F: - case R_PARISC_DIR14R: - case R_PARISC_DIR14F: - case R_PARISC_DIR14WR: - case R_PARISC_DIR14DR: - case R_PARISC_DIR16F: - case R_PARISC_DIR16WF: - case R_PARISC_DIR16DF: - { - /* All DIR relocations are basically the same at this point, - except that branch offsets need to be divided by four, and - we need different field selectors. Note that we don't - redirect absolute calls to local stubs. */ - - if (r_type == R_PARISC_DIR21L) - value = hppa_field_adjust (value, addend, e_lrsel); - else if (r_type == R_PARISC_DIR17F - || r_type == R_PARISC_DIR16F - || r_type == R_PARISC_DIR16WF - || r_type == R_PARISC_DIR16DF - || r_type == R_PARISC_DIR14F) - value = hppa_field_adjust (value, addend, e_fsel); - else - value = hppa_field_adjust (value, addend, e_rrsel); - - if (r_type == R_PARISC_DIR17R || r_type == R_PARISC_DIR17F) - /* All branches are implicitly shifted by 2 places. */ - value >>= 2; - - insn = elf_hppa_relocate_insn (insn, (int) value, r_type); - break; - } - - case R_PARISC_PLTOFF21L: - case R_PARISC_PLTOFF14R: - case R_PARISC_PLTOFF14F: - case R_PARISC_PLTOFF14WR: - case R_PARISC_PLTOFF14DR: - case R_PARISC_PLTOFF16F: - case R_PARISC_PLTOFF16WF: - case R_PARISC_PLTOFF16DF: - { - /* We want the value of the PLT offset for this symbol, not - the symbol's actual address. Note that __gp may not point - to the start of the DLT, so we have to compute the absolute - address, then subtract out the value of __gp. */ - value = (hh->plt_offset - + hppa_info->plt_sec->output_offset - + hppa_info->plt_sec->output_section->vma); - value -= _bfd_get_gp_value (output_bfd); - - /* All PLTOFF relocations are basically the same at this point, - except that we need different field selectors for the 21bit - version vs the 14bit versions. */ - if (r_type == R_PARISC_PLTOFF21L) - value = hppa_field_adjust (value, addend, e_lrsel); - else if (r_type == R_PARISC_PLTOFF14F - || r_type == R_PARISC_PLTOFF16F - || r_type == R_PARISC_PLTOFF16WF - || r_type == R_PARISC_PLTOFF16DF) - value = hppa_field_adjust (value, addend, e_fsel); - else - value = hppa_field_adjust (value, addend, e_rrsel); - - insn = elf_hppa_relocate_insn (insn, (int) value, r_type); - break; - } - - case R_PARISC_LTOFF_FPTR32: - { - /* We may still need to create the FPTR itself if it was for - a local symbol. */ - if (hh == NULL) - { - /* The first two words of an .opd entry are zero. */ - memset (hppa_info->opd_sec->contents + hh->opd_offset, 0, 16); - - /* The next word is the address of the function. */ - bfd_put_64 (hppa_info->opd_sec->owner, value + addend, - (hppa_info->opd_sec->contents - + hh->opd_offset + 16)); - - /* The last word is our local __gp value. */ - value = _bfd_get_gp_value - (hppa_info->opd_sec->output_section->owner); - bfd_put_64 (hppa_info->opd_sec->owner, value, - hppa_info->opd_sec->contents + hh->opd_offset + 24); - - /* The DLT value is the address of the .opd entry. */ - value = (hh->opd_offset - + hppa_info->opd_sec->output_offset - + hppa_info->opd_sec->output_section->vma); - - bfd_put_64 (hppa_info->dlt_sec->owner, - value, - hppa_info->dlt_sec->contents + hh->dlt_offset); - } - - /* We want the value of the DLT offset for this symbol, not - the symbol's actual address. Note that __gp may not point - to the start of the DLT, so we have to compute the absolute - address, then subtract out the value of __gp. */ - value = (hh->dlt_offset - + hppa_info->dlt_sec->output_offset - + hppa_info->dlt_sec->output_section->vma); - value -= _bfd_get_gp_value (output_bfd); - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - - case R_PARISC_LTOFF_FPTR64: - case R_PARISC_LTOFF_TP64: - { - /* We may still need to create the FPTR itself if it was for - a local symbol. */ - if (eh == NULL && r_type == R_PARISC_LTOFF_FPTR64) - { - /* The first two words of an .opd entry are zero. */ - memset (hppa_info->opd_sec->contents + hh->opd_offset, 0, 16); - - /* The next word is the address of the function. */ - bfd_put_64 (hppa_info->opd_sec->owner, value + addend, - (hppa_info->opd_sec->contents - + hh->opd_offset + 16)); - - /* The last word is our local __gp value. */ - value = _bfd_get_gp_value - (hppa_info->opd_sec->output_section->owner); - bfd_put_64 (hppa_info->opd_sec->owner, value, - hppa_info->opd_sec->contents + hh->opd_offset + 24); - - /* The DLT value is the address of the .opd entry. */ - value = (hh->opd_offset - + hppa_info->opd_sec->output_offset - + hppa_info->opd_sec->output_section->vma); - - bfd_put_64 (hppa_info->dlt_sec->owner, - value, - hppa_info->dlt_sec->contents + hh->dlt_offset); - } - - /* We want the value of the DLT offset for this symbol, not - the symbol's actual address. Note that __gp may not point - to the start of the DLT, so we have to compute the absolute - address, then subtract out the value of __gp. */ - value = (hh->dlt_offset - + hppa_info->dlt_sec->output_offset - + hppa_info->dlt_sec->output_section->vma); - value -= _bfd_get_gp_value (output_bfd); - bfd_put_64 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - - case R_PARISC_DIR32: - bfd_put_32 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_PARISC_DIR64: - bfd_put_64 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_PARISC_GPREL64: - /* Subtract out the global pointer value to make value a DLT - relative address. */ - value -= _bfd_get_gp_value (output_bfd); - - bfd_put_64 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_PARISC_LTOFF64: - /* We want the value of the DLT offset for this symbol, not - the symbol's actual address. Note that __gp may not point - to the start of the DLT, so we have to compute the absolute - address, then subtract out the value of __gp. */ - value = (hh->dlt_offset - + hppa_info->dlt_sec->output_offset - + hppa_info->dlt_sec->output_section->vma); - value -= _bfd_get_gp_value (output_bfd); - - bfd_put_64 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_PARISC_PCREL32: - { - /* If this is a call to a function defined in another dynamic - library, then redirect the call to the local stub for this - function. */ - if (sym_sec == NULL || sym_sec->output_section == NULL) - value = (hh->stub_offset + hppa_info->stub_sec->output_offset - + hppa_info->stub_sec->output_section->vma); - - /* Turn VALUE into a proper PC relative address. */ - value -= (offset + input_section->output_offset - + input_section->output_section->vma); - - value += addend; - value -= 8; - bfd_put_32 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - - case R_PARISC_PCREL64: - { - /* If this is a call to a function defined in another dynamic - library, then redirect the call to the local stub for this - function. */ - if (sym_sec == NULL || sym_sec->output_section == NULL) - value = (hh->stub_offset + hppa_info->stub_sec->output_offset - + hppa_info->stub_sec->output_section->vma); - - /* Turn VALUE into a proper PC relative address. */ - value -= (offset + input_section->output_offset - + input_section->output_section->vma); - - value += addend; - value -= 8; - bfd_put_64 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - - case R_PARISC_FPTR64: - { - bfd_vma off; - - /* We may still need to create the FPTR itself if it was for - a local symbol. */ - if (hh == NULL) - { - bfd_vma *local_opd_offsets; - - if (local_offsets == NULL) - abort (); - - local_opd_offsets = local_offsets + 2 * symtab_hdr->sh_info; - off = local_opd_offsets[r_symndx]; - - /* The last bit records whether we've already initialised - this local .opd entry. */ - if ((off & 1) != 0) - { - BFD_ASSERT (off != (bfd_vma) -1); - off &= ~1; - } - else - { - /* The first two words of an .opd entry are zero. */ - memset (hppa_info->opd_sec->contents + off, 0, 16); - - /* The next word is the address of the function. */ - bfd_put_64 (hppa_info->opd_sec->owner, value + addend, - (hppa_info->opd_sec->contents + off + 16)); - - /* The last word is our local __gp value. */ - value = _bfd_get_gp_value - (hppa_info->opd_sec->output_section->owner); - bfd_put_64 (hppa_info->opd_sec->owner, value, - hppa_info->opd_sec->contents + off + 24); - } - } - else - off = hh->opd_offset; - - if (hh == NULL || hh->want_opd) - /* We want the value of the OPD offset for this symbol. */ - value = (off - + hppa_info->opd_sec->output_offset - + hppa_info->opd_sec->output_section->vma); - else - /* We want the address of the symbol. */ - value += addend; - - bfd_put_64 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - - case R_PARISC_SECREL32: - if (sym_sec) - value -= sym_sec->output_section->vma; - bfd_put_32 (input_bfd, value + addend, hit_data); - return bfd_reloc_ok; - - case R_PARISC_SEGREL32: - case R_PARISC_SEGREL64: - { - /* If this is the first SEGREL relocation, then initialize - the segment base values. */ - if (hppa_info->text_segment_base == (bfd_vma) -1) - bfd_map_over_sections (output_bfd, elf_hppa_record_segment_addrs, - hppa_info); - - /* VALUE holds the absolute address. We want to include the - addend, then turn it into a segment relative address. - - The segment is derived from SYM_SEC. We assume that there are - only two segments of note in the resulting executable/shlib. - A readonly segment (.text) and a readwrite segment (.data). */ - value += addend; - - if (sym_sec->flags & SEC_CODE) - value -= hppa_info->text_segment_base; - else - value -= hppa_info->data_segment_base; - - if (r_type == R_PARISC_SEGREL32) - bfd_put_32 (input_bfd, value, hit_data); - else - bfd_put_64 (input_bfd, value, hit_data); - return bfd_reloc_ok; - } - - /* Something we don't know how to handle. */ - default: - return bfd_reloc_notsupported; - } - - /* Update the instruction word. */ - bfd_put_32 (input_bfd, (bfd_vma) insn, hit_data); - return bfd_reloc_ok; -} - -/* Relocate an HPPA ELF section. */ - -static bfd_boolean -elf64_hppa_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - struct elf64_hppa_link_hash_table *hppa_info; - - hppa_info = hppa_link_hash_table (info); - if (hppa_info == NULL) - return FALSE; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto = elf_hppa_howto_table + ELF_R_TYPE (rel->r_info); - unsigned long r_symndx; - struct elf_link_hash_entry *eh; - Elf_Internal_Sym *sym; - asection *sym_sec; - bfd_vma relocation; - bfd_reloc_status_type r; - - r_type = ELF_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= (int) R_PARISC_UNIMPLEMENTED) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - if (r_type == (unsigned int) R_PARISC_GNU_VTENTRY - || r_type == (unsigned int) R_PARISC_GNU_VTINHERIT) - continue; - - /* This is a final link. */ - r_symndx = ELF_R_SYM (rel->r_info); - eh = NULL; - sym = NULL; - sym_sec = NULL; - if (r_symndx < symtab_hdr->sh_info) - { - /* This is a local symbol, hh defaults to NULL. */ - sym = local_syms + r_symndx; - sym_sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sym_sec, rel); - } - else - { - /* This is not a local symbol. */ - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - - /* 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; - - eh = sym_hashes[r_symndx - symtab_hdr->sh_info]; - - if (info->wrap_hash != NULL - && (input_section->flags & SEC_DEBUGGING) != 0) - eh = ((struct elf_link_hash_entry *) - unwrap_hash_lookup (info, input_bfd, &eh->root)); - - while (eh->root.type == bfd_link_hash_indirect - || eh->root.type == bfd_link_hash_warning) - eh = (struct elf_link_hash_entry *) eh->root.u.i.link; - - relocation = 0; - if (eh->root.type == bfd_link_hash_defined - || eh->root.type == bfd_link_hash_defweak) - { - sym_sec = eh->root.u.def.section; - if (sym_sec != NULL - && sym_sec->output_section != NULL) - relocation = (eh->root.u.def.value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else if (eh->root.type == bfd_link_hash_undefweak) - ; - else if (info->unresolved_syms_in_objects == RM_IGNORE - && ELF_ST_VISIBILITY (eh->other) == STV_DEFAULT) - ; - else if (!bfd_link_relocatable (info) - && elf_hppa_is_dynamic_loader_symbol (eh->root.root.string)) - continue; - else if (!bfd_link_relocatable (info)) - { - bfd_boolean err; - err = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR - || ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT); - (*info->callbacks->undefined_symbol) (info, - eh->root.root.string, - input_bfd, - input_section, - rel->r_offset, err); - } - - if (!bfd_link_relocatable (info) - && relocation == 0 - && eh->root.type != bfd_link_hash_defined - && eh->root.type != bfd_link_hash_defweak - && eh->root.type != bfd_link_hash_undefweak) - { - if (info->unresolved_syms_in_objects == RM_IGNORE - && ELF_ST_VISIBILITY (eh->other) == STV_DEFAULT - && eh->type == STT_PARISC_MILLI) - (*info->callbacks->undefined_symbol) - (info, eh_name (eh), input_bfd, - input_section, rel->r_offset, FALSE); - } - } - - if (sym_sec != NULL && discarded_section (sym_sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - r = elf_hppa_final_link_relocate (rel, input_bfd, output_bfd, - input_section, contents, - relocation, info, sym_sec, - eh); - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - abort (); - case bfd_reloc_overflow: - { - const char *sym_name; - - if (eh != NULL) - sym_name = NULL; - else - { - sym_name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (sym_name == NULL) - return FALSE; - if (*sym_name == '\0') - sym_name = bfd_section_name (input_bfd, sym_sec); - } - - (*info->callbacks->reloc_overflow) - (info, (eh ? &eh->root : NULL), sym_name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - } - break; - } - } - } - return TRUE; -} - -static const struct bfd_elf_special_section elf64_hppa_special_sections[] = -{ - { STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_PARISC_SHORT }, - { STRING_COMMA_LEN (".dlt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_PARISC_SHORT }, - { STRING_COMMA_LEN (".sdata"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_PARISC_SHORT }, - { STRING_COMMA_LEN (".sbss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_PARISC_SHORT }, - { STRING_COMMA_LEN (".tbss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_HP_TLS }, - { NULL, 0, 0, 0, 0 } -}; - -/* The hash bucket size is the standard one, namely 4. */ - -const struct elf_size_info hppa64_elf_size_info = -{ - sizeof (Elf64_External_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_External_Rel), - sizeof (Elf64_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 4, - 1, - 64, 3, - ELFCLASS64, EV_CURRENT, - bfd_elf64_write_out_phdrs, - bfd_elf64_write_shdrs_and_ehdr, - bfd_elf64_checksum_contents, - bfd_elf64_write_relocs, - bfd_elf64_swap_symbol_in, - bfd_elf64_swap_symbol_out, - bfd_elf64_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - bfd_elf64_swap_reloc_in, - bfd_elf64_swap_reloc_out, - bfd_elf64_swap_reloca_in, - bfd_elf64_swap_reloca_out -}; - -#define TARGET_BIG_SYM hppa_elf64_vec -#define TARGET_BIG_NAME "elf64-hppa" -#define ELF_ARCH bfd_arch_hppa -#define ELF_TARGET_ID HPPA64_ELF_DATA -#define ELF_MACHINE_CODE EM_PARISC -/* This is not strictly correct. The maximum page size for PA2.0 is - 64M. But everything still uses 4k. */ -#define ELF_MAXPAGESIZE 0x1000 -#define ELF_OSABI ELFOSABI_HPUX - -#define bfd_elf64_bfd_reloc_type_lookup elf_hppa_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup elf_hppa_reloc_name_lookup -#define bfd_elf64_bfd_is_local_label_name elf_hppa_is_local_label_name -#define elf_info_to_howto elf_hppa_info_to_howto -#define elf_info_to_howto_rel elf_hppa_info_to_howto_rel - -#define elf_backend_section_from_shdr elf64_hppa_section_from_shdr -#define elf_backend_object_p elf64_hppa_object_p -#define elf_backend_final_write_processing \ - elf_hppa_final_write_processing -#define elf_backend_fake_sections elf_hppa_fake_sections -#define elf_backend_add_symbol_hook elf_hppa_add_symbol_hook - -#define elf_backend_relocate_section elf_hppa_relocate_section - -#define bfd_elf64_bfd_final_link elf_hppa_final_link - -#define elf_backend_create_dynamic_sections \ - elf64_hppa_create_dynamic_sections -#define elf_backend_post_process_headers elf64_hppa_post_process_headers - -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_adjust_dynamic_symbol \ - elf64_hppa_adjust_dynamic_symbol - -#define elf_backend_size_dynamic_sections \ - elf64_hppa_size_dynamic_sections - -#define elf_backend_finish_dynamic_symbol \ - elf64_hppa_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf64_hppa_finish_dynamic_sections -#define elf_backend_grok_prstatus elf64_hppa_grok_prstatus -#define elf_backend_grok_psinfo elf64_hppa_grok_psinfo - -/* Stuff for the BFD linker: */ -#define bfd_elf64_bfd_link_hash_table_create \ - elf64_hppa_hash_table_create - -#define elf_backend_check_relocs \ - elf64_hppa_check_relocs - -#define elf_backend_size_info \ - hppa64_elf_size_info - -#define elf_backend_additional_program_headers \ - elf64_hppa_additional_program_headers - -#define elf_backend_modify_segment_map \ - elf64_hppa_modify_segment_map - -#define elf_backend_allow_non_load_phdr \ - elf64_hppa_allow_non_load_phdr - -#define elf_backend_link_output_symbol_hook \ - elf64_hppa_link_output_symbol_hook - -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 0 -#define elf_backend_want_plt_sym 0 -#define elf_backend_got_header_size 0 -#define elf_backend_type_change_ok TRUE -#define elf_backend_get_symbol_type elf64_hppa_elf_get_symbol_type -#define elf_backend_reloc_type_class elf64_hppa_reloc_type_class -#define elf_backend_rela_normal 1 -#define elf_backend_special_sections elf64_hppa_special_sections -#define elf_backend_action_discarded elf_hppa_action_discarded -#define elf_backend_section_from_phdr elf64_hppa_section_from_phdr - -#define elf64_bed elf64_hppa_hpux_bed - -#include "elf64-target.h" - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM hppa_elf64_linux_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-hppa-linux" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_GNU -#undef elf64_bed -#define elf64_bed elf64_hppa_linux_bed - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-hppa.h b/sdcc/support/sdbinutils/bfd/elf64-hppa.h deleted file mode 100644 index 26dda0ebb..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-hppa.h +++ /dev/null @@ -1,51 +0,0 @@ -/* ELF64/HPPA support - - Copyright (C) 1999-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF64_HPPA_H -#define _ELF64_HPPA_H - -#include "elf-bfd.h" -#include "libhppa.h" -#include "elf/hppa.h" - -extern elf_hppa_reloc_type elf64_hppa_reloc_final_type - (bfd *, elf_hppa_reloc_type, int, unsigned int); - -extern elf_hppa_reloc_type ** _bfd_elf64_hppa_gen_reloc_type - (bfd *, elf_hppa_reloc_type, int, unsigned int, int, asymbol *); - -/* Define groups of basic relocations. FIXME: These should - be the only basic relocations created by GAS. The rest - should be internal to the BFD backend. - - The idea is both SOM and ELF define these basic relocation - types so they map into a SOM or ELF specific relocation - as appropriate. This allows GAS to share much more code - between the two target object formats. */ - -#define R_HPPA_NONE R_PARISC_NONE -#define R_HPPA R_PARISC_DIR64 -#define R_HPPA_GOTOFF R_PARISC_DLTREL21L -#define R_HPPA_PCREL_CALL R_PARISC_PCREL21L -#define R_HPPA_ABS_CALL R_PARISC_DIR17F -#define R_HPPA_COMPLEX R_PARISC_UNIMPLEMENTED - -#endif /* _ELF64_HPPA_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf64-ia64-vms.c b/sdcc/support/sdbinutils/bfd/elf64-ia64-vms.c deleted file mode 100644 index 0fab317bf..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-ia64-vms.c +++ /dev/null @@ -1,5621 +0,0 @@ -/* IA-64 support for OpenVMS - Copyright (C) 1998-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "opcode/ia64.h" -#include "elf/ia64.h" -#include "objalloc.h" -#include "hashtab.h" -#include "elfxx-ia64.h" -#include "vms.h" -#include "bfdver.h" - -/* THE RULES for all the stuff the linker creates -- - - GOT Entries created in response to LTOFF or LTOFF_FPTR - relocations. Dynamic relocs created for dynamic - symbols in an application; REL relocs for locals - in a shared library. - - FPTR The canonical function descriptor. Created for local - symbols in applications. Descriptors for dynamic symbols - and local symbols in shared libraries are created by - ld.so. Thus there are no dynamic relocs against these - objects. The FPTR relocs for such _are_ passed through - to the dynamic relocation tables. - - FULL_PLT Created for a PCREL21B relocation against a dynamic symbol. - Requires the creation of a PLTOFF entry. This does not - require any dynamic relocations. - - PLTOFF Created by PLTOFF relocations. For local symbols, this - is an alternate function descriptor, and in shared libraries - requires two REL relocations. Note that this cannot be - transformed into an FPTR relocation, since it must be in - range of the GP. For dynamic symbols, this is a function - descriptor. */ - -typedef struct bfd_hash_entry *(*new_hash_entry_func) - (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); - -/* In dynamically (linker-) created sections, we generally need to keep track - of the place a symbol or expression got allocated to. This is done via hash - tables that store entries of the following type. */ - -struct elf64_ia64_dyn_sym_info -{ - /* The addend for which this entry is relevant. */ - bfd_vma addend; - - bfd_vma got_offset; - bfd_vma fptr_offset; - bfd_vma pltoff_offset; - bfd_vma plt_offset; - bfd_vma plt2_offset; - - /* The symbol table entry, if any, that this was derived from. */ - struct elf_link_hash_entry *h; - - /* Used to count non-got, non-plt relocations for delayed sizing - of relocation sections. */ - struct elf64_ia64_dyn_reloc_entry - { - struct elf64_ia64_dyn_reloc_entry *next; - asection *srel; - int type; - int count; - } *reloc_entries; - - /* TRUE when the section contents have been updated. */ - unsigned got_done : 1; - unsigned fptr_done : 1; - unsigned pltoff_done : 1; - - /* TRUE for the different kinds of linker data we want created. */ - unsigned want_got : 1; - unsigned want_gotx : 1; - unsigned want_fptr : 1; - unsigned want_ltoff_fptr : 1; - unsigned want_plt : 1; /* A MIN_PLT entry. */ - unsigned want_plt2 : 1; /* A FULL_PLT. */ - unsigned want_pltoff : 1; -}; - -struct elf64_ia64_local_hash_entry -{ - int id; - unsigned int r_sym; - /* The number of elements in elf64_ia64_dyn_sym_info array. */ - unsigned int count; - /* The number of sorted elements in elf64_ia64_dyn_sym_info array. */ - unsigned int sorted_count; - /* The size of elf64_ia64_dyn_sym_info array. */ - unsigned int size; - /* The array of elf64_ia64_dyn_sym_info. */ - struct elf64_ia64_dyn_sym_info *info; - - /* TRUE if this hash entry's addends was translated for - SHF_MERGE optimization. */ - unsigned sec_merge_done : 1; -}; - -struct elf64_ia64_link_hash_entry -{ - struct elf_link_hash_entry root; - - /* Set if this symbol is defined in a shared library. - We can't use root.u.def.section->owner as the symbol is an absolute - symbol. */ - bfd *shl; - - /* The number of elements in elf64_ia64_dyn_sym_info array. */ - unsigned int count; - /* The number of sorted elements in elf64_ia64_dyn_sym_info array. */ - unsigned int sorted_count; - /* The size of elf64_ia64_dyn_sym_info array. */ - unsigned int size; - /* The array of elf64_ia64_dyn_sym_info. */ - struct elf64_ia64_dyn_sym_info *info; -}; - -struct elf64_ia64_link_hash_table -{ - /* The main hash table. */ - struct elf_link_hash_table root; - - asection *fptr_sec; /* Function descriptor table (or NULL). */ - asection *rel_fptr_sec; /* Dynamic relocation section for same. */ - asection *pltoff_sec; /* Private descriptors for plt (or NULL). */ - asection *fixups_sec; /* Fixups section. */ - asection *transfer_sec; /* Transfer vector section. */ - asection *note_sec; /* .note section. */ - - /* There are maybe R_IA64_GPREL22 relocations, including those - optimized from R_IA64_LTOFF22X, against non-SHF_IA_64_SHORT - sections. We need to record those sections so that we can choose - a proper GP to cover all R_IA64_GPREL22 relocations. */ - asection *max_short_sec; /* Maximum short output section. */ - bfd_vma max_short_offset; /* Maximum short offset. */ - asection *min_short_sec; /* Minimum short output section. */ - bfd_vma min_short_offset; /* Minimum short offset. */ - - htab_t loc_hash_table; - void *loc_hash_memory; -}; - -struct elf64_ia64_allocate_data -{ - struct bfd_link_info *info; - bfd_size_type ofs; -}; - -#define elf64_ia64_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == IA64_ELF_DATA ? ((struct elf64_ia64_link_hash_table *) ((p)->hash)) : NULL) - -struct elf64_ia64_vms_obj_tdata -{ - struct elf_obj_tdata root; - - /* Ident for shared library. */ - bfd_uint64_t ident; - - /* Used only during link: offset in the .fixups section for this bfd. */ - bfd_vma fixups_off; - - /* Max number of shared libraries. */ - unsigned int needed_count; -}; - -#define elf_ia64_vms_tdata(abfd) \ - ((struct elf64_ia64_vms_obj_tdata *)((abfd)->tdata.any)) -#define elf_ia64_vms_ident(abfd) (elf_ia64_vms_tdata(abfd)->ident) - -struct elf64_vms_transfer -{ - unsigned char size[4]; - unsigned char spare[4]; - unsigned char tfradr1[8]; - unsigned char tfradr2[8]; - unsigned char tfradr3[8]; - unsigned char tfradr4[8]; - unsigned char tfradr5[8]; - - /* Local function descriptor for tfr3. */ - unsigned char tfr3_func[8]; - unsigned char tfr3_gp[8]; -}; - -typedef struct -{ - Elf64_External_Ehdr ehdr; - unsigned char vms_needed_count[8]; -} Elf64_External_VMS_Ehdr; - -static struct elf64_ia64_dyn_sym_info * get_dyn_sym_info - (struct elf64_ia64_link_hash_table *, - struct elf_link_hash_entry *, - bfd *, const Elf_Internal_Rela *, bfd_boolean); -static bfd_boolean elf64_ia64_dynamic_symbol_p - (struct elf_link_hash_entry *); -static bfd_boolean elf64_ia64_choose_gp - (bfd *, struct bfd_link_info *, bfd_boolean); -static void elf64_ia64_dyn_sym_traverse - (struct elf64_ia64_link_hash_table *, - bfd_boolean (*) (struct elf64_ia64_dyn_sym_info *, void *), - void *); -static bfd_boolean allocate_global_data_got - (struct elf64_ia64_dyn_sym_info *, void *); -static bfd_boolean allocate_global_fptr_got - (struct elf64_ia64_dyn_sym_info *, void *); -static bfd_boolean allocate_local_got - (struct elf64_ia64_dyn_sym_info *, void *); -static bfd_boolean allocate_dynrel_entries - (struct elf64_ia64_dyn_sym_info *, void *); -static asection *get_pltoff - (bfd *, struct elf64_ia64_link_hash_table *); -static asection *get_got - (bfd *, struct elf64_ia64_link_hash_table *); - - -/* Given a ELF reloc, return the matching HOWTO structure. */ - -static void -elf64_ia64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - bfd_reloc->howto - = ia64_elf_lookup_howto ((unsigned int) ELF64_R_TYPE (elf_reloc->r_info)); -} - - -#define PLT_FULL_ENTRY_SIZE (2 * 16) - -static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] = -{ - 0x0b, 0x78, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r15=0,r1;; */ - 0x00, 0x41, 0x3c, 0x70, 0x29, 0xc0, /* ld8.acq r16=[r15],8*/ - 0x01, 0x08, 0x00, 0x84, /* mov r14=r1;; */ - 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, /* [MIB] ld8 r1=[r15] */ - 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ - 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */ -}; - -static const bfd_byte oor_brl[16] = -{ - 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* brl.sptk.few tgt;;*/ - 0x00, 0x00, 0x00, 0xc0 -}; - - -/* These functions do relaxation for IA-64 ELF. */ - -/* Rename some of the generic section flags to better document how they - are used here. */ -#define skip_relax_pass_0 sec_flg0 -#define skip_relax_pass_1 sec_flg1 - -static void -elf64_ia64_update_short_info (asection *sec, bfd_vma offset, - struct elf64_ia64_link_hash_table *ia64_info) -{ - /* Skip ABS and SHF_IA_64_SHORT sections. */ - if (sec == bfd_abs_section_ptr - || (sec->flags & SEC_SMALL_DATA) != 0) - return; - - if (!ia64_info->min_short_sec) - { - ia64_info->max_short_sec = sec; - ia64_info->max_short_offset = offset; - ia64_info->min_short_sec = sec; - ia64_info->min_short_offset = offset; - } - else if (sec == ia64_info->max_short_sec - && offset > ia64_info->max_short_offset) - ia64_info->max_short_offset = offset; - else if (sec == ia64_info->min_short_sec - && offset < ia64_info->min_short_offset) - ia64_info->min_short_offset = offset; - else if (sec->output_section->vma - > ia64_info->max_short_sec->vma) - { - ia64_info->max_short_sec = sec; - ia64_info->max_short_offset = offset; - } - else if (sec->output_section->vma - < ia64_info->min_short_sec->vma) - { - ia64_info->min_short_sec = sec; - ia64_info->min_short_offset = offset; - } -} - -/* Use a two passes algorithm. In the first pass, branches are relaxed - (which may increase the size of the section). In the second pass, - the other relaxations are done. -*/ - -static bfd_boolean -elf64_ia64_relax_section (bfd *abfd, asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - struct one_fixup - { - struct one_fixup *next; - asection *tsec; - bfd_vma toff; - bfd_vma trampoff; - }; - - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - bfd_byte *contents; - Elf_Internal_Sym *isymbuf = NULL; - struct elf64_ia64_link_hash_table *ia64_info; - struct one_fixup *fixups = NULL; - bfd_boolean changed_contents = FALSE; - bfd_boolean changed_relocs = FALSE; - bfd_boolean skip_relax_pass_0 = TRUE; - bfd_boolean skip_relax_pass_1 = TRUE; - bfd_vma gp = 0; - - /* Assume we're not going to change any sizes, and we'll only need - one pass. */ - *again = FALSE; - - if (bfd_link_relocatable (link_info)) - (*link_info->callbacks->einfo) - (_("%P%F: --relax and -r may not be used together\n")); - - /* Don't even try to relax for non-ELF outputs. */ - if (!is_elf_hash_table (link_info->hash)) - return FALSE; - - /* Nothing to do if there are no relocations or there is no need for - the current pass. */ - if ((sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (link_info->relax_pass == 0 && sec->skip_relax_pass_0) - || (link_info->relax_pass == 1 && sec->skip_relax_pass_1)) - return TRUE; - - ia64_info = elf64_ia64_hash_table (link_info); - if (ia64_info == NULL) - return FALSE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - /* Load the relocations for this section. */ - internal_relocs = (_bfd_elf_link_read_relocs - (abfd, sec, NULL, (Elf_Internal_Rela *) NULL, - link_info->keep_memory)); - if (internal_relocs == NULL) - return FALSE; - - irelend = internal_relocs + sec->reloc_count; - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else - { - if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } - - for (irel = internal_relocs; irel < irelend; irel++) - { - unsigned long r_type = ELF64_R_TYPE (irel->r_info); - bfd_vma symaddr, reladdr, trampoff, toff, roff; - asection *tsec; - struct one_fixup *f; - bfd_size_type amt; - bfd_boolean is_branch; - struct elf64_ia64_dyn_sym_info *dyn_i; - - switch (r_type) - { - case R_IA64_PCREL21B: - case R_IA64_PCREL21BI: - case R_IA64_PCREL21M: - case R_IA64_PCREL21F: - /* In pass 1, all br relaxations are done. We can skip it. */ - if (link_info->relax_pass == 1) - continue; - skip_relax_pass_0 = FALSE; - is_branch = TRUE; - break; - - case R_IA64_PCREL60B: - /* We can't optimize brl to br in pass 0 since br relaxations - will increase the code size. Defer it to pass 1. */ - if (link_info->relax_pass == 0) - { - skip_relax_pass_1 = FALSE; - continue; - } - is_branch = TRUE; - break; - - case R_IA64_GPREL22: - /* Update max_short_sec/min_short_sec. */ - - case R_IA64_LTOFF22X: - case R_IA64_LDXMOV: - /* We can't relax ldx/mov in pass 0 since br relaxations will - increase the code size. Defer it to pass 1. */ - if (link_info->relax_pass == 0) - { - skip_relax_pass_1 = FALSE; - continue; - } - is_branch = FALSE; - break; - - default: - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - - /* Read this BFD's local symbols. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == 0) - goto error_return; - } - - isym = isymbuf + ELF64_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - continue; /* We can't do anything with undefined symbols. */ - else if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else if (isym->st_shndx == SHN_IA_64_ANSI_COMMON) - tsec = bfd_com_section_ptr; - else - tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - - toff = isym->st_value; - dyn_i = get_dyn_sym_info (ia64_info, NULL, abfd, irel, FALSE); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - dyn_i = get_dyn_sym_info (ia64_info, h, abfd, irel, FALSE); - - /* For branches to dynamic symbols, we're interested instead - in a branch to the PLT entry. */ - if (is_branch && dyn_i && dyn_i->want_plt2) - { - /* Internal branches shouldn't be sent to the PLT. - Leave this for now and we'll give an error later. */ - if (r_type != R_IA64_PCREL21B) - continue; - - tsec = ia64_info->root.splt; - toff = dyn_i->plt2_offset; - BFD_ASSERT (irel->r_addend == 0); - } - - /* Can't do anything else with dynamic symbols. */ - else if (elf64_ia64_dynamic_symbol_p (h)) - continue; - - else - { - /* We can't do anything with undefined symbols. */ - if (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - continue; - - tsec = h->root.u.def.section; - toff = h->root.u.def.value; - } - } - - toff += irel->r_addend; - - symaddr = tsec->output_section->vma + tsec->output_offset + toff; - - roff = irel->r_offset; - - if (is_branch) - { - bfd_signed_vma offset; - - reladdr = (sec->output_section->vma - + sec->output_offset - + roff) & (bfd_vma) -4; - - /* The .plt section is aligned at 32byte and the .text section - is aligned at 64byte. The .text section is right after the - .plt section. After the first relaxation pass, linker may - increase the gap between the .plt and .text sections up - to 32byte. We assume linker will always insert 32byte - between the .plt and .text sections after the first - relaxation pass. */ - if (tsec == ia64_info->root.splt) - offset = -0x1000000 + 32; - else - offset = -0x1000000; - - /* If the branch is in range, no need to do anything. */ - if ((bfd_signed_vma) (symaddr - reladdr) >= offset - && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0) - { - /* If the 60-bit branch is in 21-bit range, optimize it. */ - if (r_type == R_IA64_PCREL60B) - { - ia64_elf_relax_brl (contents, roff); - - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_IA64_PCREL21B); - - /* If the original relocation offset points to slot - 1, change it to slot 2. */ - if ((irel->r_offset & 3) == 1) - irel->r_offset += 1; - } - - continue; - } - else if (r_type == R_IA64_PCREL60B) - continue; - else if (ia64_elf_relax_br (contents, roff)) - { - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_IA64_PCREL60B); - - /* Make the relocation offset point to slot 1. */ - irel->r_offset = (irel->r_offset & ~((bfd_vma) 0x3)) + 1; - continue; - } - - /* We can't put a trampoline in a .init/.fini section. Issue - an error. */ - if (strcmp (sec->output_section->name, ".init") == 0 - || strcmp (sec->output_section->name, ".fini") == 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Can't relax br at %#Lx in section `%A'." - " Please use brl or indirect branch."), - sec->owner, roff, sec); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - - /* If the branch and target are in the same section, you've - got one honking big section and we can't help you unless - you are branching backwards. You'll get an error message - later. */ - if (tsec == sec && toff > roff) - continue; - - /* Look for an existing fixup to this address. */ - for (f = fixups; f ; f = f->next) - if (f->tsec == tsec && f->toff == toff) - break; - - if (f == NULL) - { - /* Two alternatives: If it's a branch to a PLT entry, we can - make a copy of the FULL_PLT entry. Otherwise, we'll have - to use a `brl' insn to get where we're going. */ - - size_t size; - - if (tsec == ia64_info->root.splt) - size = sizeof (plt_full_entry); - else - size = sizeof (oor_brl); - - /* Resize the current section to make room for the new branch. */ - trampoff = (sec->size + 15) & (bfd_vma) -16; - - /* If trampoline is out of range, there is nothing we - can do. */ - offset = trampoff - (roff & (bfd_vma) -4); - if (offset < -0x1000000 || offset > 0x0FFFFF0) - continue; - - amt = trampoff + size; - contents = (bfd_byte *) bfd_realloc (contents, amt); - if (contents == NULL) - goto error_return; - sec->size = amt; - - if (tsec == ia64_info->root.splt) - { - memcpy (contents + trampoff, plt_full_entry, size); - - /* Hijack the old relocation for use as the PLTOFF reloc. */ - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_IA64_PLTOFF22); - irel->r_offset = trampoff; - } - else - { - memcpy (contents + trampoff, oor_brl, size); - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_IA64_PCREL60B); - irel->r_offset = trampoff + 2; - } - - /* Record the fixup so we don't do it again this section. */ - f = (struct one_fixup *) - bfd_malloc ((bfd_size_type) sizeof (*f)); - f->next = fixups; - f->tsec = tsec; - f->toff = toff; - f->trampoff = trampoff; - fixups = f; - } - else - { - /* If trampoline is out of range, there is nothing we - can do. */ - offset = f->trampoff - (roff & (bfd_vma) -4); - if (offset < -0x1000000 || offset > 0x0FFFFF0) - continue; - - /* Nop out the reloc, since we're finalizing things here. */ - irel->r_info = ELF64_R_INFO (0, R_IA64_NONE); - } - - /* Fix up the existing branch to hit the trampoline. */ - if (ia64_elf_install_value (contents + roff, offset, r_type) - != bfd_reloc_ok) - goto error_return; - - changed_contents = TRUE; - changed_relocs = TRUE; - } - else - { - /* Fetch the gp. */ - if (gp == 0) - { - bfd *obfd = sec->output_section->owner; - gp = _bfd_get_gp_value (obfd); - if (gp == 0) - { - if (!elf64_ia64_choose_gp (obfd, link_info, FALSE)) - goto error_return; - gp = _bfd_get_gp_value (obfd); - } - } - - /* If the data is out of range, do nothing. */ - if ((bfd_signed_vma) (symaddr - gp) >= 0x200000 - ||(bfd_signed_vma) (symaddr - gp) < -0x200000) - continue; - - if (r_type == R_IA64_GPREL22) - elf64_ia64_update_short_info (tsec->output_section, - tsec->output_offset + toff, - ia64_info); - else if (r_type == R_IA64_LTOFF22X) - { - /* Can't deal yet correctly with ABS symbols. */ - if (bfd_is_abs_section (tsec)) - continue; - - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_IA64_GPREL22); - changed_relocs = TRUE; - - elf64_ia64_update_short_info (tsec->output_section, - tsec->output_offset + toff, - ia64_info); - } - else - { - ia64_elf_relax_ldxmov (contents, roff); - irel->r_info = ELF64_R_INFO (0, R_IA64_NONE); - changed_contents = TRUE; - changed_relocs = TRUE; - } - } - } - - /* ??? If we created fixups, this may push the code segment large - enough that the data segment moves, which will change the GP. - Reset the GP so that we re-calculate next round. We need to - do this at the _beginning_ of the next round; now will not do. */ - - /* Clean up and go home. */ - while (fixups) - { - struct one_fixup *f = fixups; - fixups = fixups->next; - free (f); - } - - if (isymbuf != NULL - && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - { - if (!changed_contents && !link_info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - if (elf_section_data (sec)->relocs != internal_relocs) - { - if (!changed_relocs) - free (internal_relocs); - else - elf_section_data (sec)->relocs = internal_relocs; - } - - if (link_info->relax_pass == 0) - { - /* Pass 0 is only needed to relax br. */ - sec->skip_relax_pass_0 = skip_relax_pass_0; - sec->skip_relax_pass_1 = skip_relax_pass_1; - } - - *again = changed_contents || changed_relocs; - return TRUE; - - error_return: - if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} -#undef skip_relax_pass_0 -#undef skip_relax_pass_1 - -/* Return TRUE if NAME is an unwind table section name. */ - -static inline bfd_boolean -is_unwind_section_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name) -{ - return ((CONST_STRNEQ (name, ELF_STRING_ia64_unwind) - && ! CONST_STRNEQ (name, ELF_STRING_ia64_unwind_info)) - || CONST_STRNEQ (name, ELF_STRING_ia64_unwind_once)); -} - - -/* Convert IA-64 specific section flags to bfd internal section flags. */ - -/* ??? There is no bfd internal flag equivalent to the SHF_IA_64_NORECOV - flag. */ - -static bfd_boolean -elf64_ia64_section_flags (flagword *flags, - const Elf_Internal_Shdr *hdr) -{ - if (hdr->sh_flags & SHF_IA_64_SHORT) - *flags |= SEC_SMALL_DATA; - - return TRUE; -} - -/* Set the correct type for an IA-64 ELF section. We do this by the - section name, which is a hack, but ought to work. */ - -static bfd_boolean -elf64_ia64_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, - asection *sec) -{ - const char *name; - - name = bfd_get_section_name (abfd, sec); - - if (is_unwind_section_name (abfd, name)) - { - /* We don't have the sections numbered at this point, so sh_info - is set later, in elf64_ia64_final_write_processing. */ - hdr->sh_type = SHT_IA_64_UNWIND; - hdr->sh_flags |= SHF_LINK_ORDER; - } - else if (strcmp (name, ELF_STRING_ia64_archext) == 0) - hdr->sh_type = SHT_IA_64_EXT; - - if (sec->flags & SEC_SMALL_DATA) - hdr->sh_flags |= SHF_IA_64_SHORT; - - return TRUE; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it to put .comm items in .sbss, and not .bss. */ - -static bfd_boolean -elf64_ia64_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp) -{ - if (sym->st_shndx == SHN_COMMON - && !bfd_link_relocatable (info) - && sym->st_size <= elf_gp_size (abfd)) - { - /* Common symbols less than or equal to -G nn bytes are - automatically put into .sbss. */ - - asection *scomm = bfd_get_section_by_name (abfd, ".scommon"); - - if (scomm == NULL) - { - scomm = bfd_make_section_with_flags (abfd, ".scommon", - (SEC_ALLOC - | SEC_IS_COMMON - | SEC_LINKER_CREATED)); - if (scomm == NULL) - return FALSE; - } - - *secp = scomm; - *valp = sym->st_size; - } - - return TRUE; -} - -/* According to the Tahoe assembler spec, all labels starting with a - '.' are local. */ - -static bfd_boolean -elf64_ia64_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, - const char *name) -{ - return name[0] == '.'; -} - -/* Should we do dynamic things to this symbol? */ - -static bfd_boolean -elf64_ia64_dynamic_symbol_p (struct elf_link_hash_entry *h) -{ - return h != NULL && h->def_dynamic; -} - -static struct bfd_hash_entry* -elf64_ia64_new_elf_hash_entry (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf64_ia64_link_hash_entry *ret; - ret = (struct elf64_ia64_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (!ret) - ret = bfd_hash_allocate (table, sizeof (*ret)); - - if (!ret) - return 0; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf64_ia64_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - - ret->info = NULL; - ret->count = 0; - ret->sorted_count = 0; - ret->size = 0; - return (struct bfd_hash_entry *) ret; -} - -static void -elf64_ia64_hash_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *xh, - bfd_boolean force_local) -{ - struct elf64_ia64_link_hash_entry *h; - struct elf64_ia64_dyn_sym_info *dyn_i; - unsigned int count; - - h = (struct elf64_ia64_link_hash_entry *)xh; - - _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); - - for (count = h->count, dyn_i = h->info; - count != 0; - count--, dyn_i++) - { - dyn_i->want_plt2 = 0; - dyn_i->want_plt = 0; - } -} - -/* Compute a hash of a local hash entry. */ - -static hashval_t -elf64_ia64_local_htab_hash (const void *ptr) -{ - struct elf64_ia64_local_hash_entry *entry - = (struct elf64_ia64_local_hash_entry *) ptr; - - return ELF_LOCAL_SYMBOL_HASH (entry->id, entry->r_sym); -} - -/* Compare local hash entries. */ - -static int -elf64_ia64_local_htab_eq (const void *ptr1, const void *ptr2) -{ - struct elf64_ia64_local_hash_entry *entry1 - = (struct elf64_ia64_local_hash_entry *) ptr1; - struct elf64_ia64_local_hash_entry *entry2 - = (struct elf64_ia64_local_hash_entry *) ptr2; - - return entry1->id == entry2->id && entry1->r_sym == entry2->r_sym; -} - -/* Free the global elf64_ia64_dyn_sym_info array. */ - -static bfd_boolean -elf64_ia64_global_dyn_info_free (void **xentry, - void * unused ATTRIBUTE_UNUSED) -{ - struct elf64_ia64_link_hash_entry *entry - = (struct elf64_ia64_link_hash_entry *) xentry; - - if (entry->root.root.type == bfd_link_hash_warning) - entry = (struct elf64_ia64_link_hash_entry *) entry->root.root.u.i.link; - - if (entry->info) - { - free (entry->info); - entry->info = NULL; - entry->count = 0; - entry->sorted_count = 0; - entry->size = 0; - } - - return TRUE; -} - -/* Free the local elf64_ia64_dyn_sym_info array. */ - -static bfd_boolean -elf64_ia64_local_dyn_info_free (void **slot, - void * unused ATTRIBUTE_UNUSED) -{ - struct elf64_ia64_local_hash_entry *entry - = (struct elf64_ia64_local_hash_entry *) *slot; - - if (entry->info) - { - free (entry->info); - entry->info = NULL; - entry->count = 0; - entry->sorted_count = 0; - entry->size = 0; - } - - return TRUE; -} - -/* Destroy IA-64 linker hash table. */ - -static void -elf64_ia64_link_hash_table_free (bfd *obfd) -{ - struct elf64_ia64_link_hash_table *ia64_info - = (struct elf64_ia64_link_hash_table *) obfd->link.hash; - if (ia64_info->loc_hash_table) - { - htab_traverse (ia64_info->loc_hash_table, - elf64_ia64_local_dyn_info_free, NULL); - htab_delete (ia64_info->loc_hash_table); - } - if (ia64_info->loc_hash_memory) - objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory); - elf_link_hash_traverse (&ia64_info->root, - elf64_ia64_global_dyn_info_free, NULL); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create the derived linker hash table. The IA-64 ELF port uses this - derived hash table to keep information specific to the IA-64 ElF - linker (without using static variables). */ - -static struct bfd_link_hash_table * -elf64_ia64_hash_table_create (bfd *abfd) -{ - struct elf64_ia64_link_hash_table *ret; - - ret = bfd_zmalloc ((bfd_size_type) sizeof (*ret)); - if (!ret) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, - elf64_ia64_new_elf_hash_entry, - sizeof (struct elf64_ia64_link_hash_entry), - IA64_ELF_DATA)) - { - free (ret); - return NULL; - } - - ret->loc_hash_table = htab_try_create (1024, elf64_ia64_local_htab_hash, - elf64_ia64_local_htab_eq, NULL); - ret->loc_hash_memory = objalloc_create (); - if (!ret->loc_hash_table || !ret->loc_hash_memory) - { - elf64_ia64_link_hash_table_free (abfd); - return NULL; - } - ret->root.root.hash_table_free = elf64_ia64_link_hash_table_free; - - return &ret->root.root; -} - -/* Traverse both local and global hash tables. */ - -struct elf64_ia64_dyn_sym_traverse_data -{ - bfd_boolean (*func) (struct elf64_ia64_dyn_sym_info *, void *); - void * data; -}; - -static bfd_boolean -elf64_ia64_global_dyn_sym_thunk (struct bfd_hash_entry *xentry, - void * xdata) -{ - struct elf64_ia64_link_hash_entry *entry - = (struct elf64_ia64_link_hash_entry *) xentry; - struct elf64_ia64_dyn_sym_traverse_data *data - = (struct elf64_ia64_dyn_sym_traverse_data *) xdata; - struct elf64_ia64_dyn_sym_info *dyn_i; - unsigned int count; - - if (entry->root.root.type == bfd_link_hash_warning) - entry = (struct elf64_ia64_link_hash_entry *) entry->root.root.u.i.link; - - for (count = entry->count, dyn_i = entry->info; - count != 0; - count--, dyn_i++) - if (! (*data->func) (dyn_i, data->data)) - return FALSE; - return TRUE; -} - -static bfd_boolean -elf64_ia64_local_dyn_sym_thunk (void **slot, void * xdata) -{ - struct elf64_ia64_local_hash_entry *entry - = (struct elf64_ia64_local_hash_entry *) *slot; - struct elf64_ia64_dyn_sym_traverse_data *data - = (struct elf64_ia64_dyn_sym_traverse_data *) xdata; - struct elf64_ia64_dyn_sym_info *dyn_i; - unsigned int count; - - for (count = entry->count, dyn_i = entry->info; - count != 0; - count--, dyn_i++) - if (! (*data->func) (dyn_i, data->data)) - return FALSE; - return TRUE; -} - -static void -elf64_ia64_dyn_sym_traverse (struct elf64_ia64_link_hash_table *ia64_info, - bfd_boolean (*func) (struct elf64_ia64_dyn_sym_info *, void *), - void * data) -{ - struct elf64_ia64_dyn_sym_traverse_data xdata; - - xdata.func = func; - xdata.data = data; - - elf_link_hash_traverse (&ia64_info->root, - elf64_ia64_global_dyn_sym_thunk, &xdata); - htab_traverse (ia64_info->loc_hash_table, - elf64_ia64_local_dyn_sym_thunk, &xdata); -} - -#define NOTE_NAME "IPF/VMS" - -static bfd_boolean -create_ia64_vms_notes (bfd *abfd, struct bfd_link_info *info, - unsigned int time_hi, unsigned int time_lo) -{ -#define NBR_NOTES 7 - Elf_Internal_Note notes[NBR_NOTES]; - char *module_name; - int module_name_len; - unsigned char cur_time[8]; - Elf64_External_VMS_ORIG_DYN_Note *orig_dyn; - unsigned int orig_dyn_size; - unsigned int note_size; - int i; - unsigned char *noteptr; - unsigned char *note_contents; - struct elf64_ia64_link_hash_table *ia64_info; - - ia64_info = elf64_ia64_hash_table (info); - - module_name = vms_get_module_name (bfd_get_filename (abfd), TRUE); - module_name_len = strlen (module_name) + 1; - - bfd_putl32 (time_lo, cur_time + 0); - bfd_putl32 (time_hi, cur_time + 4); - - /* Note 0: IMGNAM. */ - notes[0].type = NT_VMS_IMGNAM; - notes[0].descdata = module_name; - notes[0].descsz = module_name_len; - - /* Note 1: GSTNAM. */ - notes[1].type = NT_VMS_GSTNAM; - notes[1].descdata = module_name; - notes[1].descsz = module_name_len; - - /* Note 2: IMGID. */ -#define IMG_ID "V1.0" - notes[2].type = NT_VMS_IMGID; - notes[2].descdata = IMG_ID; - notes[2].descsz = sizeof (IMG_ID); - - /* Note 3: Linktime. */ - notes[3].type = NT_VMS_LINKTIME; - notes[3].descdata = (char *)cur_time; - notes[3].descsz = sizeof (cur_time); - - /* Note 4: Linker id. */ - notes[4].type = NT_VMS_LINKID; - notes[4].descdata = "GNU ld " BFD_VERSION_STRING; - notes[4].descsz = strlen (notes[4].descdata) + 1; - - /* Note 5: Original dyn. */ - orig_dyn_size = (sizeof (*orig_dyn) + sizeof (IMG_ID) - 1 + 7) & ~7; - orig_dyn = bfd_zalloc (abfd, orig_dyn_size); - if (orig_dyn == NULL) - return FALSE; - bfd_putl32 (1, orig_dyn->major_id); - bfd_putl32 (3, orig_dyn->minor_id); - memcpy (orig_dyn->manipulation_date, cur_time, sizeof (cur_time)); - bfd_putl64 (VMS_LF_IMGSTA | VMS_LF_MAIN, orig_dyn->link_flags); - bfd_putl32 (EF_IA_64_ABI64, orig_dyn->elf_flags); - memcpy (orig_dyn->imgid, IMG_ID, sizeof (IMG_ID)); - notes[5].type = NT_VMS_ORIG_DYN; - notes[5].descdata = (char *)orig_dyn; - notes[5].descsz = orig_dyn_size; - - /* Note 3: Patchtime. */ - notes[6].type = NT_VMS_PATCHTIME; - notes[6].descdata = (char *)cur_time; - notes[6].descsz = sizeof (cur_time); - - /* Compute notes size. */ - note_size = 0; - for (i = 0; i < NBR_NOTES; i++) - note_size += sizeof (Elf64_External_VMS_Note) - 1 - + ((sizeof (NOTE_NAME) - 1 + 7) & ~7) - + ((notes[i].descsz + 7) & ~7); - - /* Malloc a temporary buffer large enough for most notes */ - note_contents = (unsigned char *) bfd_zalloc (abfd, note_size); - if (note_contents == NULL) - return FALSE; - noteptr = note_contents; - - /* Fill notes. */ - for (i = 0; i < NBR_NOTES; i++) - { - Elf64_External_VMS_Note *enote = (Elf64_External_VMS_Note *) noteptr; - - bfd_putl64 (sizeof (NOTE_NAME) - 1, enote->namesz); - bfd_putl64 (notes[i].descsz, enote->descsz); - bfd_putl64 (notes[i].type, enote->type); - - noteptr = (unsigned char *)enote->name; - memcpy (noteptr, NOTE_NAME, sizeof (NOTE_NAME) - 1); - noteptr += (sizeof (NOTE_NAME) - 1 + 7) & ~7; - memcpy (noteptr, notes[i].descdata, notes[i].descsz); - noteptr += (notes[i].descsz + 7) & ~7; - } - - ia64_info->note_sec->contents = note_contents; - ia64_info->note_sec->size = note_size; - - free (module_name); - - return TRUE; -} - -static bfd_boolean -elf64_ia64_create_dynamic_sections (bfd *abfd, - struct bfd_link_info *info) -{ - struct elf64_ia64_link_hash_table *ia64_info; - asection *s; - flagword flags; - const struct elf_backend_data *bed; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - if (elf_hash_table (info)->dynamic_sections_created) - return TRUE; - - abfd = elf_hash_table (info)->dynobj; - bed = get_elf_backend_data (abfd); - - flags = bed->dynamic_sec_flags; - - s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - ia64_info->root.splt = s; - - if (!get_got (abfd, ia64_info)) - return FALSE; - - if (!get_pltoff (abfd, ia64_info)) - return FALSE; - - s = bfd_make_section_anyway_with_flags (abfd, ".vmsdynstr", - (SEC_ALLOC - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 0)) - return FALSE; - - /* Create a fixup section. */ - s = bfd_make_section_anyway_with_flags (abfd, ".fixups", - (SEC_ALLOC - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - ia64_info->fixups_sec = s; - - /* Create the transfer fixup section. */ - s = bfd_make_section_anyway_with_flags (abfd, ".transfer", - (SEC_ALLOC - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - s->size = sizeof (struct elf64_vms_transfer); - ia64_info->transfer_sec = s; - - /* Create note section. */ - s = bfd_make_section_anyway_with_flags (abfd, ".vms.note", - (SEC_LINKER_CREATED - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY)); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, 3)) - return FALSE; - ia64_info->note_sec = s; - - elf_hash_table (info)->dynamic_sections_created = TRUE; - return TRUE; -} - -/* Find and/or create a hash entry for local symbol. */ -static struct elf64_ia64_local_hash_entry * -get_local_sym_hash (struct elf64_ia64_link_hash_table *ia64_info, - bfd *abfd, const Elf_Internal_Rela *rel, - bfd_boolean create) -{ - struct elf64_ia64_local_hash_entry e, *ret; - asection *sec = abfd->sections; - hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, - ELF64_R_SYM (rel->r_info)); - void **slot; - - e.id = sec->id; - e.r_sym = ELF64_R_SYM (rel->r_info); - slot = htab_find_slot_with_hash (ia64_info->loc_hash_table, &e, h, - create ? INSERT : NO_INSERT); - - if (!slot) - return NULL; - - if (*slot) - return (struct elf64_ia64_local_hash_entry *) *slot; - - ret = (struct elf64_ia64_local_hash_entry *) - objalloc_alloc ((struct objalloc *) ia64_info->loc_hash_memory, - sizeof (struct elf64_ia64_local_hash_entry)); - if (ret) - { - memset (ret, 0, sizeof (*ret)); - ret->id = sec->id; - ret->r_sym = ELF64_R_SYM (rel->r_info); - *slot = ret; - } - return ret; -} - -/* Used to sort elf64_ia64_dyn_sym_info array. */ - -static int -addend_compare (const void *xp, const void *yp) -{ - const struct elf64_ia64_dyn_sym_info *x - = (const struct elf64_ia64_dyn_sym_info *) xp; - const struct elf64_ia64_dyn_sym_info *y - = (const struct elf64_ia64_dyn_sym_info *) yp; - - return x->addend < y->addend ? -1 : x->addend > y->addend ? 1 : 0; -} - -/* Sort elf64_ia64_dyn_sym_info array and remove duplicates. */ - -static unsigned int -sort_dyn_sym_info (struct elf64_ia64_dyn_sym_info *info, - unsigned int count) -{ - bfd_vma curr, prev, got_offset; - unsigned int i, kept, dupes, diff, dest, src, len; - - qsort (info, count, sizeof (*info), addend_compare); - - /* Find the first duplicate. */ - prev = info [0].addend; - got_offset = info [0].got_offset; - for (i = 1; i < count; i++) - { - curr = info [i].addend; - if (curr == prev) - { - /* For duplicates, make sure that GOT_OFFSET is valid. */ - if (got_offset == (bfd_vma) -1) - got_offset = info [i].got_offset; - break; - } - got_offset = info [i].got_offset; - prev = curr; - } - - /* We may move a block of elements to here. */ - dest = i++; - - /* Remove duplicates. */ - if (i < count) - { - while (i < count) - { - /* For duplicates, make sure that the kept one has a valid - got_offset. */ - kept = dest - 1; - if (got_offset != (bfd_vma) -1) - info [kept].got_offset = got_offset; - - curr = info [i].addend; - got_offset = info [i].got_offset; - - /* Move a block of elements whose first one is different from - the previous. */ - if (curr == prev) - { - for (src = i + 1; src < count; src++) - { - if (info [src].addend != curr) - break; - /* For duplicates, make sure that GOT_OFFSET is - valid. */ - if (got_offset == (bfd_vma) -1) - got_offset = info [src].got_offset; - } - - /* Make sure that the kept one has a valid got_offset. */ - if (got_offset != (bfd_vma) -1) - info [kept].got_offset = got_offset; - } - else - src = i; - - if (src >= count) - break; - - /* Find the next duplicate. SRC will be kept. */ - prev = info [src].addend; - got_offset = info [src].got_offset; - for (dupes = src + 1; dupes < count; dupes ++) - { - curr = info [dupes].addend; - if (curr == prev) - { - /* Make sure that got_offset is valid. */ - if (got_offset == (bfd_vma) -1) - got_offset = info [dupes].got_offset; - - /* For duplicates, make sure that the kept one has - a valid got_offset. */ - if (got_offset != (bfd_vma) -1) - info [dupes - 1].got_offset = got_offset; - break; - } - got_offset = info [dupes].got_offset; - prev = curr; - } - - /* How much to move. */ - len = dupes - src; - i = dupes + 1; - - if (len == 1 && dupes < count) - { - /* If we only move 1 element, we combine it with the next - one. There must be at least a duplicate. Find the - next different one. */ - for (diff = dupes + 1, src++; diff < count; diff++, src++) - { - if (info [diff].addend != curr) - break; - /* Make sure that got_offset is valid. */ - if (got_offset == (bfd_vma) -1) - got_offset = info [diff].got_offset; - } - - /* Makre sure that the last duplicated one has an valid - offset. */ - BFD_ASSERT (curr == prev); - if (got_offset != (bfd_vma) -1) - info [diff - 1].got_offset = got_offset; - - if (diff < count) - { - /* Find the next duplicate. Track the current valid - offset. */ - prev = info [diff].addend; - got_offset = info [diff].got_offset; - for (dupes = diff + 1; dupes < count; dupes ++) - { - curr = info [dupes].addend; - if (curr == prev) - { - /* For duplicates, make sure that GOT_OFFSET - is valid. */ - if (got_offset == (bfd_vma) -1) - got_offset = info [dupes].got_offset; - break; - } - got_offset = info [dupes].got_offset; - prev = curr; - diff++; - } - - len = diff - src + 1; - i = diff + 1; - } - } - - memmove (&info [dest], &info [src], len * sizeof (*info)); - - dest += len; - } - - count = dest; - } - else - { - /* When we get here, either there is no duplicate at all or - the only duplicate is the last element. */ - if (dest < count) - { - /* If the last element is a duplicate, make sure that the - kept one has a valid got_offset. We also update count. */ - if (got_offset != (bfd_vma) -1) - info [dest - 1].got_offset = got_offset; - count = dest; - } - } - - return count; -} - -/* Find and/or create a descriptor for dynamic symbol info. This will - vary based on global or local symbol, and the addend to the reloc. - - We don't sort when inserting. Also, we sort and eliminate - duplicates if there is an unsorted section. Typically, this will - only happen once, because we do all insertions before lookups. We - then use bsearch to do a lookup. This also allows lookups to be - fast. So we have fast insertion (O(log N) due to duplicate check), - fast lookup (O(log N)) and one sort (O(N log N) expected time). - Previously, all lookups were O(N) because of the use of the linked - list and also all insertions were O(N) because of the check for - duplicates. There are some complications here because the array - size grows occasionally, which may add an O(N) factor, but this - should be rare. Also, we free the excess array allocation, which - requires a copy which is O(N), but this only happens once. */ - -static struct elf64_ia64_dyn_sym_info * -get_dyn_sym_info (struct elf64_ia64_link_hash_table *ia64_info, - struct elf_link_hash_entry *h, bfd *abfd, - const Elf_Internal_Rela *rel, bfd_boolean create) -{ - struct elf64_ia64_dyn_sym_info **info_p, *info, *dyn_i, key; - unsigned int *count_p, *sorted_count_p, *size_p; - unsigned int count, sorted_count, size; - bfd_vma addend = rel ? rel->r_addend : 0; - bfd_size_type amt; - - if (h) - { - struct elf64_ia64_link_hash_entry *global_h; - - global_h = (struct elf64_ia64_link_hash_entry *) h; - info_p = &global_h->info; - count_p = &global_h->count; - sorted_count_p = &global_h->sorted_count; - size_p = &global_h->size; - } - else - { - struct elf64_ia64_local_hash_entry *loc_h; - - loc_h = get_local_sym_hash (ia64_info, abfd, rel, create); - if (!loc_h) - { - BFD_ASSERT (!create); - return NULL; - } - - info_p = &loc_h->info; - count_p = &loc_h->count; - sorted_count_p = &loc_h->sorted_count; - size_p = &loc_h->size; - } - - count = *count_p; - sorted_count = *sorted_count_p; - size = *size_p; - info = *info_p; - if (create) - { - /* When we create the array, we don't check for duplicates, - except in the previously sorted section if one exists, and - against the last inserted entry. This allows insertions to - be fast. */ - if (info) - { - if (sorted_count) - { - /* Try bsearch first on the sorted section. */ - key.addend = addend; - dyn_i = bsearch (&key, info, sorted_count, - sizeof (*info), addend_compare); - - if (dyn_i) - { - return dyn_i; - } - } - - /* Do a quick check for the last inserted entry. */ - dyn_i = info + count - 1; - if (dyn_i->addend == addend) - { - return dyn_i; - } - } - - if (size == 0) - { - /* It is the very first element. We create the array of size - 1. */ - size = 1; - amt = size * sizeof (*info); - info = bfd_malloc (amt); - } - else if (size <= count) - { - /* We double the array size every time when we reach the - size limit. */ - size += size; - amt = size * sizeof (*info); - info = bfd_realloc (info, amt); - } - else - goto has_space; - - if (info == NULL) - return NULL; - *size_p = size; - *info_p = info; - -has_space: - /* Append the new one to the array. */ - dyn_i = info + count; - memset (dyn_i, 0, sizeof (*dyn_i)); - dyn_i->got_offset = (bfd_vma) -1; - dyn_i->addend = addend; - - /* We increment count only since the new ones are unsorted and - may have duplicate. */ - (*count_p)++; - } - else - { - /* It is a lookup without insertion. Sort array if part of the - array isn't sorted. */ - if (count != sorted_count) - { - count = sort_dyn_sym_info (info, count); - *count_p = count; - *sorted_count_p = count; - } - - /* Free unused memory. */ - if (size != count) - { - amt = count * sizeof (*info); - info = bfd_malloc (amt); - if (info != NULL) - { - memcpy (info, *info_p, amt); - free (*info_p); - *size_p = count; - *info_p = info; - } - } - - key.addend = addend; - dyn_i = bsearch (&key, info, count, - sizeof (*info), addend_compare); - } - - return dyn_i; -} - -static asection * -get_got (bfd *abfd, struct elf64_ia64_link_hash_table *ia64_info) -{ - asection *got; - bfd *dynobj; - - got = ia64_info->root.sgot; - if (!got) - { - flagword flags; - - dynobj = ia64_info->root.dynobj; - if (!dynobj) - ia64_info->root.dynobj = dynobj = abfd; - - /* The .got section is always aligned at 8 bytes. */ - flags = get_elf_backend_data (dynobj)->dynamic_sec_flags; - got = bfd_make_section_anyway_with_flags (dynobj, ".got", - flags | SEC_SMALL_DATA); - if (got == NULL - || !bfd_set_section_alignment (dynobj, got, 3)) - return NULL; - ia64_info->root.sgot = got; - } - - return got; -} - -/* Create function descriptor section (.opd). This section is called .opd - because it contains "official procedure descriptors". The "official" - refers to the fact that these descriptors are used when taking the address - of a procedure, thus ensuring a unique address for each procedure. */ - -static asection * -get_fptr (bfd *abfd, struct bfd_link_info *info, - struct elf64_ia64_link_hash_table *ia64_info) -{ - asection *fptr; - bfd *dynobj; - - fptr = ia64_info->fptr_sec; - if (!fptr) - { - dynobj = ia64_info->root.dynobj; - if (!dynobj) - ia64_info->root.dynobj = dynobj = abfd; - - fptr = bfd_make_section_anyway_with_flags (dynobj, ".opd", - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | (bfd_link_pie (info) ? 0 - : SEC_READONLY) - | SEC_LINKER_CREATED)); - if (!fptr - || !bfd_set_section_alignment (dynobj, fptr, 4)) - { - BFD_ASSERT (0); - return NULL; - } - - ia64_info->fptr_sec = fptr; - - if (bfd_link_pie (info)) - { - asection *fptr_rel; - fptr_rel = bfd_make_section_anyway_with_flags (dynobj, ".rela.opd", - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (fptr_rel == NULL - || !bfd_set_section_alignment (dynobj, fptr_rel, 3)) - { - BFD_ASSERT (0); - return NULL; - } - - ia64_info->rel_fptr_sec = fptr_rel; - } - } - - return fptr; -} - -static asection * -get_pltoff (bfd *abfd, struct elf64_ia64_link_hash_table *ia64_info) -{ - asection *pltoff; - bfd *dynobj; - - pltoff = ia64_info->pltoff_sec; - if (!pltoff) - { - dynobj = ia64_info->root.dynobj; - if (!dynobj) - ia64_info->root.dynobj = dynobj = abfd; - - pltoff = bfd_make_section_anyway_with_flags (dynobj, - ELF_STRING_ia64_pltoff, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_SMALL_DATA - | SEC_LINKER_CREATED)); - if (!pltoff - || !bfd_set_section_alignment (dynobj, pltoff, 4)) - { - BFD_ASSERT (0); - return NULL; - } - - ia64_info->pltoff_sec = pltoff; - } - - return pltoff; -} - -static asection * -get_reloc_section (bfd *abfd, - struct elf64_ia64_link_hash_table *ia64_info, - asection *sec, bfd_boolean create) -{ - const char *srel_name; - asection *srel; - bfd *dynobj; - - srel_name = (bfd_elf_string_from_elf_section - (abfd, elf_elfheader(abfd)->e_shstrndx, - _bfd_elf_single_rel_hdr (sec)->sh_name)); - if (srel_name == NULL) - return NULL; - - BFD_ASSERT ((CONST_STRNEQ (srel_name, ".rela") - && strcmp (bfd_get_section_name (abfd, sec), - srel_name+5) == 0) - || (CONST_STRNEQ (srel_name, ".rel") - && strcmp (bfd_get_section_name (abfd, sec), - srel_name+4) == 0)); - - dynobj = ia64_info->root.dynobj; - if (!dynobj) - ia64_info->root.dynobj = dynobj = abfd; - - srel = bfd_get_linker_section (dynobj, srel_name); - if (srel == NULL && create) - { - srel = bfd_make_section_anyway_with_flags (dynobj, srel_name, - (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (srel == NULL - || !bfd_set_section_alignment (dynobj, srel, 3)) - return NULL; - } - - return srel; -} - -static bfd_boolean -count_dyn_reloc (bfd *abfd, struct elf64_ia64_dyn_sym_info *dyn_i, - asection *srel, int type) -{ - struct elf64_ia64_dyn_reloc_entry *rent; - - for (rent = dyn_i->reloc_entries; rent; rent = rent->next) - if (rent->srel == srel && rent->type == type) - break; - - if (!rent) - { - rent = ((struct elf64_ia64_dyn_reloc_entry *) - bfd_alloc (abfd, (bfd_size_type) sizeof (*rent))); - if (!rent) - return FALSE; - - rent->next = dyn_i->reloc_entries; - rent->srel = srel; - rent->type = type; - rent->count = 0; - dyn_i->reloc_entries = rent; - } - rent->count++; - - return TRUE; -} - -static bfd_boolean -elf64_ia64_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf64_ia64_link_hash_table *ia64_info; - const Elf_Internal_Rela *relend; - Elf_Internal_Shdr *symtab_hdr; - const Elf_Internal_Rela *rel; - asection *got, *fptr, *srel, *pltoff; - enum { - NEED_GOT = 1, - NEED_GOTX = 2, - NEED_FPTR = 4, - NEED_PLTOFF = 8, - NEED_MIN_PLT = 16, - NEED_FULL_PLT = 32, - NEED_DYNREL = 64, - NEED_LTOFF_FPTR = 128 - }; - int need_entry; - struct elf_link_hash_entry *h; - unsigned long r_symndx; - bfd_boolean maybe_dynamic; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - got = fptr = srel = pltoff = NULL; - - relend = relocs + sec->reloc_count; - - /* We scan relocations first to create dynamic relocation arrays. We - modified get_dyn_sym_info to allow fast insertion and support fast - lookup in the next loop. */ - for (rel = relocs; rel < relend; ++rel) - { - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - long indx = r_symndx - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - 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; - } - else - h = NULL; - - /* We can only get preliminary data on whether a symbol is - locally or externally defined, as not all of the input files - have yet been processed. Do something with what we know, as - this may help reduce memory usage and processing time later. */ - maybe_dynamic = (h && ((!bfd_link_executable (info) - && (!SYMBOLIC_BIND (info, h) - || info->unresolved_syms_in_shared_libs == RM_IGNORE)) - || !h->def_regular - || h->root.type == bfd_link_hash_defweak)); - - need_entry = 0; - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_IA64_TPREL64MSB: - case R_IA64_TPREL64LSB: - case R_IA64_LTOFF_TPREL22: - case R_IA64_DTPREL32MSB: - case R_IA64_DTPREL32LSB: - case R_IA64_DTPREL64MSB: - case R_IA64_DTPREL64LSB: - case R_IA64_LTOFF_DTPREL22: - case R_IA64_DTPMOD64MSB: - case R_IA64_DTPMOD64LSB: - case R_IA64_LTOFF_DTPMOD22: - abort (); - break; - - case R_IA64_IPLTMSB: - case R_IA64_IPLTLSB: - break; - - case R_IA64_LTOFF_FPTR22: - case R_IA64_LTOFF_FPTR64I: - case R_IA64_LTOFF_FPTR32MSB: - case R_IA64_LTOFF_FPTR32LSB: - case R_IA64_LTOFF_FPTR64MSB: - case R_IA64_LTOFF_FPTR64LSB: - need_entry = NEED_FPTR | NEED_GOT | NEED_LTOFF_FPTR; - break; - - case R_IA64_FPTR64I: - case R_IA64_FPTR32MSB: - case R_IA64_FPTR32LSB: - case R_IA64_FPTR64MSB: - case R_IA64_FPTR64LSB: - if (bfd_link_pic (info) || h) - need_entry = NEED_FPTR | NEED_DYNREL; - else - need_entry = NEED_FPTR; - break; - - case R_IA64_LTOFF22: - case R_IA64_LTOFF64I: - need_entry = NEED_GOT; - break; - - case R_IA64_LTOFF22X: - need_entry = NEED_GOTX; - break; - - case R_IA64_PLTOFF22: - case R_IA64_PLTOFF64I: - case R_IA64_PLTOFF64MSB: - case R_IA64_PLTOFF64LSB: - need_entry = NEED_PLTOFF; - if (h) - { - if (maybe_dynamic) - need_entry |= NEED_MIN_PLT; - } - else - { - (*info->callbacks->warning) - (info, _("@pltoff reloc against local symbol"), 0, - abfd, 0, (bfd_vma) 0); - } - break; - - case R_IA64_PCREL21B: - case R_IA64_PCREL60B: - /* Depending on where this symbol is defined, we may or may not - need a full plt entry. Only skip if we know we'll not need - the entry -- static or symbolic, and the symbol definition - has already been seen. */ - if (maybe_dynamic && rel->r_addend == 0) - need_entry = NEED_FULL_PLT; - break; - - case R_IA64_IMM14: - case R_IA64_IMM22: - case R_IA64_IMM64: - case R_IA64_DIR32MSB: - case R_IA64_DIR32LSB: - case R_IA64_DIR64MSB: - case R_IA64_DIR64LSB: - /* Shared objects will always need at least a REL relocation. */ - if (bfd_link_pic (info) || maybe_dynamic) - need_entry = NEED_DYNREL; - break; - - case R_IA64_PCREL22: - case R_IA64_PCREL64I: - case R_IA64_PCREL32MSB: - case R_IA64_PCREL32LSB: - case R_IA64_PCREL64MSB: - case R_IA64_PCREL64LSB: - if (maybe_dynamic) - need_entry = NEED_DYNREL; - break; - } - - if (!need_entry) - continue; - - if ((need_entry & NEED_FPTR) != 0 - && rel->r_addend) - { - (*info->callbacks->warning) - (info, _("non-zero addend in @fptr reloc"), 0, - abfd, 0, (bfd_vma) 0); - } - - if (get_dyn_sym_info (ia64_info, h, abfd, rel, TRUE) == NULL) - return FALSE; - } - - /* Now, we only do lookup without insertion, which is very fast - with the modified get_dyn_sym_info. */ - for (rel = relocs; rel < relend; ++rel) - { - struct elf64_ia64_dyn_sym_info *dyn_i; - int dynrel_type = R_IA64_NONE; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - /* We're dealing with a global symbol -- find its hash entry - and mark it as being referenced. */ - long indx = r_symndx - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - /* PR15323, ref flags aren't set for references in the same - object. */ - h->ref_regular = 1; - } - else - h = NULL; - - /* We can only get preliminary data on whether a symbol is - locally or externally defined, as not all of the input files - have yet been processed. Do something with what we know, as - this may help reduce memory usage and processing time later. */ - maybe_dynamic = (h && ((!bfd_link_executable (info) - && (!SYMBOLIC_BIND (info, h) - || info->unresolved_syms_in_shared_libs == RM_IGNORE)) - || !h->def_regular - || h->root.type == bfd_link_hash_defweak)); - - need_entry = 0; - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_IA64_TPREL64MSB: - case R_IA64_TPREL64LSB: - case R_IA64_LTOFF_TPREL22: - case R_IA64_DTPREL32MSB: - case R_IA64_DTPREL32LSB: - case R_IA64_DTPREL64MSB: - case R_IA64_DTPREL64LSB: - case R_IA64_LTOFF_DTPREL22: - case R_IA64_DTPMOD64MSB: - case R_IA64_DTPMOD64LSB: - case R_IA64_LTOFF_DTPMOD22: - abort (); - break; - - case R_IA64_LTOFF_FPTR22: - case R_IA64_LTOFF_FPTR64I: - case R_IA64_LTOFF_FPTR32MSB: - case R_IA64_LTOFF_FPTR32LSB: - case R_IA64_LTOFF_FPTR64MSB: - case R_IA64_LTOFF_FPTR64LSB: - need_entry = NEED_FPTR | NEED_GOT | NEED_LTOFF_FPTR; - break; - - case R_IA64_FPTR64I: - case R_IA64_FPTR32MSB: - case R_IA64_FPTR32LSB: - case R_IA64_FPTR64MSB: - case R_IA64_FPTR64LSB: - if (bfd_link_pic (info) || h) - need_entry = NEED_FPTR | NEED_DYNREL; - else - need_entry = NEED_FPTR; - dynrel_type = R_IA64_FPTR64LSB; - break; - - case R_IA64_LTOFF22: - case R_IA64_LTOFF64I: - need_entry = NEED_GOT; - break; - - case R_IA64_LTOFF22X: - need_entry = NEED_GOTX; - break; - - case R_IA64_PLTOFF22: - case R_IA64_PLTOFF64I: - case R_IA64_PLTOFF64MSB: - case R_IA64_PLTOFF64LSB: - need_entry = NEED_PLTOFF; - if (h) - { - if (maybe_dynamic) - need_entry |= NEED_MIN_PLT; - } - break; - - case R_IA64_PCREL21B: - case R_IA64_PCREL60B: - /* Depending on where this symbol is defined, we may or may not - need a full plt entry. Only skip if we know we'll not need - the entry -- static or symbolic, and the symbol definition - has already been seen. */ - if (maybe_dynamic && rel->r_addend == 0) - need_entry = NEED_FULL_PLT; - break; - - case R_IA64_IMM14: - case R_IA64_IMM22: - case R_IA64_IMM64: - case R_IA64_DIR32MSB: - case R_IA64_DIR32LSB: - case R_IA64_DIR64MSB: - case R_IA64_DIR64LSB: - /* Shared objects will always need at least a REL relocation. */ - if (bfd_link_pic (info) || maybe_dynamic) - need_entry = NEED_DYNREL; - dynrel_type = R_IA64_DIR64LSB; - break; - - case R_IA64_IPLTMSB: - case R_IA64_IPLTLSB: - break; - - case R_IA64_PCREL22: - case R_IA64_PCREL64I: - case R_IA64_PCREL32MSB: - case R_IA64_PCREL32LSB: - case R_IA64_PCREL64MSB: - case R_IA64_PCREL64LSB: - if (maybe_dynamic) - need_entry = NEED_DYNREL; - dynrel_type = R_IA64_PCREL64LSB; - break; - } - - if (!need_entry) - continue; - - dyn_i = get_dyn_sym_info (ia64_info, h, abfd, rel, FALSE); - - /* Record whether or not this is a local symbol. */ - dyn_i->h = h; - - /* Create what's needed. */ - if (need_entry & (NEED_GOT | NEED_GOTX)) - { - if (!got) - { - got = get_got (abfd, ia64_info); - if (!got) - return FALSE; - } - if (need_entry & NEED_GOT) - dyn_i->want_got = 1; - if (need_entry & NEED_GOTX) - dyn_i->want_gotx = 1; - } - if (need_entry & NEED_FPTR) - { - /* Create the .opd section. */ - if (!fptr) - { - fptr = get_fptr (abfd, info, ia64_info); - if (!fptr) - return FALSE; - } - dyn_i->want_fptr = 1; - } - if (need_entry & NEED_LTOFF_FPTR) - dyn_i->want_ltoff_fptr = 1; - if (need_entry & (NEED_MIN_PLT | NEED_FULL_PLT)) - { - if (!ia64_info->root.dynobj) - ia64_info->root.dynobj = abfd; - h->needs_plt = 1; - dyn_i->want_plt = 1; - } - if (need_entry & NEED_FULL_PLT) - dyn_i->want_plt2 = 1; - if (need_entry & NEED_PLTOFF) - { - /* This is needed here, in case @pltoff is used in a non-shared - link. */ - if (!pltoff) - { - pltoff = get_pltoff (abfd, ia64_info); - if (!pltoff) - return FALSE; - } - - dyn_i->want_pltoff = 1; - } - if ((need_entry & NEED_DYNREL) && (sec->flags & SEC_ALLOC)) - { - if (!srel) - { - srel = get_reloc_section (abfd, ia64_info, sec, TRUE); - if (!srel) - return FALSE; - } - if (!count_dyn_reloc (abfd, dyn_i, srel, dynrel_type)) - return FALSE; - } - } - - return TRUE; -} - -/* For cleanliness, and potentially faster dynamic loading, allocate - external GOT entries first. */ - -static bfd_boolean -allocate_global_data_got (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *)data; - - if ((dyn_i->want_got || dyn_i->want_gotx) - && ! dyn_i->want_fptr - && elf64_ia64_dynamic_symbol_p (dyn_i->h)) - { - /* GOT entry with FPTR is done by allocate_global_fptr_got. */ - dyn_i->got_offset = x->ofs; - x->ofs += 8; - } - return TRUE; -} - -/* Next, allocate all the GOT entries used by LTOFF_FPTR relocs. */ - -static bfd_boolean -allocate_global_fptr_got (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *)data; - - if (dyn_i->want_got - && dyn_i->want_fptr - && elf64_ia64_dynamic_symbol_p (dyn_i->h)) - { - dyn_i->got_offset = x->ofs; - x->ofs += 8; - } - return TRUE; -} - -/* Lastly, allocate all the GOT entries for local data. */ - -static bfd_boolean -allocate_local_got (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *) data; - - if ((dyn_i->want_got || dyn_i->want_gotx) - && !elf64_ia64_dynamic_symbol_p (dyn_i->h)) - { - dyn_i->got_offset = x->ofs; - x->ofs += 8; - } - return TRUE; -} - -/* Allocate function descriptors. We can do these for every function - in a main executable that is not exported. */ - -static bfd_boolean -allocate_fptr (struct elf64_ia64_dyn_sym_info *dyn_i, void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *) data; - - if (dyn_i->want_fptr) - { - struct elf_link_hash_entry *h = dyn_i->h; - - if (h) - 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 == NULL || !h->def_dynamic) - { - /* A non dynamic symbol. */ - dyn_i->fptr_offset = x->ofs; - x->ofs += 16; - } - else - dyn_i->want_fptr = 0; - } - return TRUE; -} - -/* Allocate all the minimal PLT entries. */ - -static bfd_boolean -allocate_plt_entries (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data ATTRIBUTE_UNUSED) -{ - if (dyn_i->want_plt) - { - struct elf_link_hash_entry *h = dyn_i->h; - - if (h) - 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; - - /* ??? Versioned symbols seem to lose NEEDS_PLT. */ - if (elf64_ia64_dynamic_symbol_p (h)) - { - dyn_i->want_pltoff = 1; - } - else - { - dyn_i->want_plt = 0; - dyn_i->want_plt2 = 0; - } - } - return TRUE; -} - -/* Allocate all the full PLT entries. */ - -static bfd_boolean -allocate_plt2_entries (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *)data; - - if (dyn_i->want_plt2) - { - struct elf_link_hash_entry *h = dyn_i->h; - bfd_size_type ofs = x->ofs; - - dyn_i->plt2_offset = ofs; - x->ofs = ofs + PLT_FULL_ENTRY_SIZE; - - 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; - dyn_i->h->plt.offset = ofs; - } - return TRUE; -} - -/* Allocate all the PLTOFF entries requested by relocations and - plt entries. We can't share space with allocated FPTR entries, - because the latter are not necessarily addressable by the GP. - ??? Relaxation might be able to determine that they are. */ - -static bfd_boolean -allocate_pltoff_entries (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *)data; - - if (dyn_i->want_pltoff) - { - dyn_i->pltoff_offset = x->ofs; - x->ofs += 16; - } - return TRUE; -} - -/* Allocate dynamic relocations for those symbols that turned out - to be dynamic. */ - -static bfd_boolean -allocate_dynrel_entries (struct elf64_ia64_dyn_sym_info *dyn_i, - void * data) -{ - struct elf64_ia64_allocate_data *x = (struct elf64_ia64_allocate_data *)data; - struct elf64_ia64_link_hash_table *ia64_info; - struct elf64_ia64_dyn_reloc_entry *rent; - bfd_boolean dynamic_symbol, shared, resolved_zero; - struct elf64_ia64_link_hash_entry *h_ia64; - - ia64_info = elf64_ia64_hash_table (x->info); - if (ia64_info == NULL) - return FALSE; - - /* Note that this can't be used in relation to FPTR relocs below. */ - dynamic_symbol = elf64_ia64_dynamic_symbol_p (dyn_i->h); - - shared = bfd_link_pic (x->info); - resolved_zero = (dyn_i->h - && ELF_ST_VISIBILITY (dyn_i->h->other) - && dyn_i->h->root.type == bfd_link_hash_undefweak); - - /* Take care of the GOT and PLT relocations. */ - - if ((!resolved_zero - && (dynamic_symbol || shared) - && (dyn_i->want_got || dyn_i->want_gotx)) - || (dyn_i->want_ltoff_fptr - && dyn_i->h - && dyn_i->h->def_dynamic)) - { - /* VMS: FIX64. */ - if (dyn_i->h != NULL && dyn_i->h->def_dynamic) - { - h_ia64 = (struct elf64_ia64_link_hash_entry *) dyn_i->h; - elf_ia64_vms_tdata (h_ia64->shl)->fixups_off += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - ia64_info->fixups_sec->size += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - } - } - - if (ia64_info->rel_fptr_sec && dyn_i->want_fptr) - { - /* VMS: only image reloc. */ - if (dyn_i->h == NULL || dyn_i->h->root.type != bfd_link_hash_undefweak) - ia64_info->rel_fptr_sec->size += sizeof (Elf64_External_Rela); - } - - if (!resolved_zero && dyn_i->want_pltoff) - { - /* VMS: FIXFD. */ - if (dyn_i->h != NULL && dyn_i->h->def_dynamic) - { - h_ia64 = (struct elf64_ia64_link_hash_entry *) dyn_i->h; - elf_ia64_vms_tdata (h_ia64->shl)->fixups_off += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - ia64_info->fixups_sec->size += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - } - } - - /* Take care of the normal data relocations. */ - - for (rent = dyn_i->reloc_entries; rent; rent = rent->next) - { - int count = rent->count; - - switch (rent->type) - { - case R_IA64_FPTR32LSB: - case R_IA64_FPTR64LSB: - /* Allocate one iff !want_fptr and not PIE, which by this point - will be true only if we're actually allocating one statically - in the main executable. Position independent executables - need a relative reloc. */ - if (dyn_i->want_fptr && !bfd_link_pie (x->info)) - continue; - break; - case R_IA64_PCREL32LSB: - case R_IA64_PCREL64LSB: - if (!dynamic_symbol) - continue; - break; - case R_IA64_DIR32LSB: - case R_IA64_DIR64LSB: - if (!dynamic_symbol && !shared) - continue; - break; - case R_IA64_IPLTLSB: - if (!dynamic_symbol && !shared) - continue; - /* Use two REL relocations for IPLT relocations - against local symbols. */ - if (!dynamic_symbol) - count *= 2; - break; - case R_IA64_DTPREL32LSB: - case R_IA64_TPREL64LSB: - case R_IA64_DTPREL64LSB: - case R_IA64_DTPMOD64LSB: - break; - default: - abort (); - } - - /* Add a fixup. */ - if (!dynamic_symbol) - abort (); - - h_ia64 = (struct elf64_ia64_link_hash_entry *) dyn_i->h; - elf_ia64_vms_tdata (h_ia64->shl)->fixups_off += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - ia64_info->fixups_sec->size += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - } - - return TRUE; -} - -static bfd_boolean -elf64_ia64_adjust_dynamic_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h) -{ - /* ??? Undefined symbols with PLT entries should be re-defined - to be the PLT entry. */ - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* If this is a reference to a symbol defined by a dynamic object which - is not a function, we might allocate the symbol in our .dynbss section - and allocate a COPY dynamic relocation. - - But IA-64 code is canonically PIC, so as a rule we can avoid this sort - of hackery. */ - - return TRUE; -} - -static bfd_boolean -elf64_ia64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf64_ia64_allocate_data data; - struct elf64_ia64_link_hash_table *ia64_info; - asection *sec; - bfd *dynobj; - struct elf_link_hash_table *hash_table; - - hash_table = elf_hash_table (info); - dynobj = hash_table->dynobj; - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - BFD_ASSERT(dynobj != NULL); - data.info = info; - - /* Allocate the GOT entries. */ - - if (ia64_info->root.sgot) - { - data.ofs = 0; - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data); - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data); - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data); - ia64_info->root.sgot->size = data.ofs; - } - - /* Allocate the FPTR entries. */ - - if (ia64_info->fptr_sec) - { - data.ofs = 0; - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_fptr, &data); - ia64_info->fptr_sec->size = data.ofs; - } - - /* Now that we've seen all of the input files, we can decide which - symbols need plt entries. Allocate the minimal PLT entries first. - We do this even though dynamic_sections_created may be FALSE, because - this has the side-effect of clearing want_plt and want_plt2. */ - - data.ofs = 0; - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_plt_entries, &data); - - /* Align the pointer for the plt2 entries. */ - data.ofs = (data.ofs + 31) & (bfd_vma) -32; - - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_plt2_entries, &data); - if (data.ofs != 0 || ia64_info->root.dynamic_sections_created) - { - /* FIXME: we always reserve the memory for dynamic linker even if - there are no PLT entries since dynamic linker may assume the - reserved memory always exists. */ - - BFD_ASSERT (ia64_info->root.dynamic_sections_created); - - ia64_info->root.splt->size = data.ofs; - } - - /* Allocate the PLTOFF entries. */ - - if (ia64_info->pltoff_sec) - { - data.ofs = 0; - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_pltoff_entries, &data); - ia64_info->pltoff_sec->size = data.ofs; - } - - if (ia64_info->root.dynamic_sections_created) - { - /* Allocate space for the dynamic relocations that turned out to be - required. */ - elf64_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, &data); - } - - /* We have now determined the sizes of the various dynamic sections. - Allocate memory for them. */ - for (sec = dynobj->sections; sec != NULL; sec = sec->next) - { - bfd_boolean strip; - - if (!(sec->flags & SEC_LINKER_CREATED)) - continue; - - /* If we don't need this section, strip it from the output file. - There were several sections primarily related to dynamic - linking that must be create before the linker maps input - sections to output sections. The linker does that before - bfd_elf_size_dynamic_sections is called, and it is that - function which decides whether anything needs to go into - these sections. */ - - strip = (sec->size == 0); - - if (sec == ia64_info->root.sgot) - strip = FALSE; - else if (sec == ia64_info->root.srelgot) - { - if (strip) - ia64_info->root.srelgot = NULL; - else - /* We use the reloc_count field as a counter if we need to - copy relocs into the output file. */ - sec->reloc_count = 0; - } - else if (sec == ia64_info->fptr_sec) - { - if (strip) - ia64_info->fptr_sec = NULL; - } - else if (sec == ia64_info->rel_fptr_sec) - { - if (strip) - ia64_info->rel_fptr_sec = NULL; - else - /* We use the reloc_count field as a counter if we need to - copy relocs into the output file. */ - sec->reloc_count = 0; - } - else if (sec == ia64_info->root.splt) - { - if (strip) - ia64_info->root.splt = NULL; - } - else if (sec == ia64_info->pltoff_sec) - { - if (strip) - ia64_info->pltoff_sec = NULL; - } - else if (sec == ia64_info->fixups_sec) - { - if (strip) - ia64_info->fixups_sec = NULL; - } - else if (sec == ia64_info->transfer_sec) - { - ; - } - else - { - const char *name; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, sec); - - if (strcmp (name, ".got.plt") == 0) - strip = FALSE; - else if (CONST_STRNEQ (name, ".rel")) - { - if (!strip) - { - /* We use the reloc_count field as a counter if we need to - copy relocs into the output file. */ - sec->reloc_count = 0; - } - } - else - continue; - } - - if (strip) - sec->flags |= SEC_EXCLUDE; - else - { - /* Allocate memory for the section contents. */ - sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->size); - if (sec->contents == NULL && sec->size != 0) - return FALSE; - } - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - bfd *abfd; - asection *dynsec; - asection *dynstrsec; - Elf_Internal_Dyn dyn; - const struct elf_backend_data *bed; - unsigned int shl_num = 0; - bfd_vma fixups_off = 0; - bfd_vma strdyn_off; - unsigned int time_hi, time_lo; - - /* The .dynamic section must exist and be empty. */ - dynsec = bfd_get_linker_section (hash_table->dynobj, ".dynamic"); - BFD_ASSERT (dynsec != NULL); - BFD_ASSERT (dynsec->size == 0); - - dynstrsec = bfd_get_linker_section (hash_table->dynobj, ".vmsdynstr"); - BFD_ASSERT (dynstrsec != NULL); - BFD_ASSERT (dynstrsec->size == 0); - dynstrsec->size = 1; /* Initial blank. */ - - /* Ident + link time. */ - vms_get_time (&time_hi, &time_lo); - - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_IDENT, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_LINKTIME, - (((bfd_uint64_t)time_hi) << 32) - + time_lo)) - return FALSE; - - /* Strtab. */ - strdyn_off = dynsec->size; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_STRTAB_OFFSET, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_STRSZ, 0)) - return FALSE; - - /* PLTGOT */ - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_PLTGOT_SEG, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_PLTGOT_OFFSET, 0)) - return FALSE; - - /* Misc. */ - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_FPMODE, 0x9800000)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_LNKFLAGS, - VMS_LF_IMGSTA | VMS_LF_MAIN)) - return FALSE; - - /* Add entries for shared libraries. */ - for (abfd = info->input_bfds; abfd; abfd = abfd->link.next) - { - char *soname; - size_t soname_len; - bfd_size_type strindex; - bfd_byte *newcontents; - bfd_vma fixups_shl_off; - - if (!(abfd->flags & DYNAMIC)) - continue; - BFD_ASSERT (abfd->xvec == output_bfd->xvec); - - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_NEEDED_IDENT, - elf_ia64_vms_ident (abfd))) - return FALSE; - - soname = vms_get_module_name (abfd->filename, TRUE); - if (soname == NULL) - return FALSE; - strindex = dynstrsec->size; - soname_len = strlen (soname) + 1; - newcontents = (bfd_byte *) bfd_realloc (dynstrsec->contents, - strindex + soname_len); - if (newcontents == NULL) - return FALSE; - memcpy (newcontents + strindex, soname, soname_len); - dynstrsec->size += soname_len; - dynstrsec->contents = newcontents; - - if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex)) - return FALSE; - - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_FIXUP_NEEDED, - shl_num)) - return FALSE; - shl_num++; - - /* The fixups_off was in fact containing the size of the fixup - section. Remap into the offset. */ - fixups_shl_off = elf_ia64_vms_tdata (abfd)->fixups_off; - elf_ia64_vms_tdata (abfd)->fixups_off = fixups_off; - - if (!_bfd_elf_add_dynamic_entry - (info, DT_IA_64_VMS_FIXUP_RELA_CNT, - fixups_shl_off / sizeof (Elf64_External_VMS_IMAGE_FIXUP))) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_FIXUP_RELA_OFF, - fixups_off)) - return FALSE; - fixups_off += fixups_shl_off; - } - - /* Unwind. */ - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_UNWINDSZ, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_UNWIND_CODSEG, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_UNWIND_INFOSEG, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_UNWIND_OFFSET, 0)) - return FALSE; - if (!_bfd_elf_add_dynamic_entry (info, DT_IA_64_VMS_UNWIND_SEG, 0)) - return FALSE; - - if (!_bfd_elf_add_dynamic_entry (info, DT_NULL, 0xdead)) - return FALSE; - - /* Fix the strtab entries. */ - bed = get_elf_backend_data (hash_table->dynobj); - - if (dynstrsec->size > 1) - dynstrsec->contents[0] = 0; - else - dynstrsec->size = 0; - - /* Note: one 'spare' (ie DT_NULL) entry is added by - bfd_elf_size_dynsym_hash_dynstr. */ - dyn.d_tag = DT_IA_64_VMS_STRTAB_OFFSET; - dyn.d_un.d_val = dynsec->size /* + sizeof (Elf64_External_Dyn) */; - bed->s->swap_dyn_out (hash_table->dynobj, &dyn, - dynsec->contents + strdyn_off); - - dyn.d_tag = DT_STRSZ; - dyn.d_un.d_val = dynstrsec->size; - bed->s->swap_dyn_out (hash_table->dynobj, &dyn, - dynsec->contents + strdyn_off + bed->s->sizeof_dyn); - - elf_ia64_vms_tdata (output_bfd)->needed_count = shl_num; - - /* Note section. */ - if (!create_ia64_vms_notes (output_bfd, info, time_hi, time_lo)) - return FALSE; - } - - /* ??? Perhaps force __gp local. */ - - return TRUE; -} - -static void -elf64_ia64_install_fixup (bfd *output_bfd, - struct elf64_ia64_link_hash_table *ia64_info, - struct elf_link_hash_entry *h, - unsigned int type, asection *sec, bfd_vma offset, - bfd_vma addend) -{ - asection *relsec; - Elf64_External_VMS_IMAGE_FIXUP *fixup; - struct elf64_ia64_link_hash_entry *h_ia64; - bfd_vma fixoff; - Elf_Internal_Phdr *phdr; - - if (h == NULL || !h->def_dynamic) - abort (); - - h_ia64 = (struct elf64_ia64_link_hash_entry *) h; - fixoff = elf_ia64_vms_tdata (h_ia64->shl)->fixups_off; - elf_ia64_vms_tdata (h_ia64->shl)->fixups_off += - sizeof (Elf64_External_VMS_IMAGE_FIXUP); - relsec = ia64_info->fixups_sec; - - fixup = (Elf64_External_VMS_IMAGE_FIXUP *)(relsec->contents + fixoff); - offset += sec->output_section->vma + sec->output_offset; - - /* FIXME: this is slow. We should cache the last one used, or create a - map. */ - phdr = _bfd_elf_find_segment_containing_section - (output_bfd, sec->output_section); - BFD_ASSERT (phdr != NULL); - - bfd_putl64 (offset - phdr->p_vaddr, fixup->fixup_offset); - bfd_putl32 (type, fixup->type); - bfd_putl32 (phdr - elf_tdata (output_bfd)->phdr, fixup->fixup_seg); - bfd_putl64 (addend, fixup->addend); - bfd_putl32 (h->root.u.def.value, fixup->symvec_index); - bfd_putl32 (2, fixup->data_type); -} - -/* Store an entry for target address TARGET_ADDR in the linkage table - and return the gp-relative address of the linkage table entry. */ - -static bfd_vma -set_got_entry (bfd *abfd, struct bfd_link_info *info, - struct elf64_ia64_dyn_sym_info *dyn_i, - bfd_vma addend, bfd_vma value, unsigned int dyn_r_type) -{ - struct elf64_ia64_link_hash_table *ia64_info; - asection *got_sec; - bfd_boolean done; - bfd_vma got_offset; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return 0; - - got_sec = ia64_info->root.sgot; - - switch (dyn_r_type) - { - case R_IA64_TPREL64LSB: - case R_IA64_DTPMOD64LSB: - case R_IA64_DTPREL32LSB: - case R_IA64_DTPREL64LSB: - abort (); - break; - default: - done = dyn_i->got_done; - dyn_i->got_done = TRUE; - got_offset = dyn_i->got_offset; - break; - } - - BFD_ASSERT ((got_offset & 7) == 0); - - if (! done) - { - /* Store the target address in the linkage table entry. */ - bfd_put_64 (abfd, value, got_sec->contents + got_offset); - - /* Install a dynamic relocation if needed. */ - if (((bfd_link_pic (info) - && (!dyn_i->h - || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT - || dyn_i->h->root.type != bfd_link_hash_undefweak)) - || elf64_ia64_dynamic_symbol_p (dyn_i->h)) - && (!dyn_i->want_ltoff_fptr - || !bfd_link_pie (info) - || !dyn_i->h - || dyn_i->h->root.type != bfd_link_hash_undefweak)) - { - if (!dyn_i->h || !dyn_i->h->def_dynamic) - { - dyn_r_type = R_IA64_REL64LSB; - addend = value; - } - - /* VMS: install a FIX32 or FIX64. */ - switch (dyn_r_type) - { - case R_IA64_DIR32LSB: - case R_IA64_FPTR32LSB: - dyn_r_type = R_IA64_VMS_FIX32; - break; - case R_IA64_DIR64LSB: - case R_IA64_FPTR64LSB: - dyn_r_type = R_IA64_VMS_FIX64; - break; - default: - BFD_ASSERT (FALSE); - break; - } - elf64_ia64_install_fixup - (info->output_bfd, ia64_info, dyn_i->h, - dyn_r_type, got_sec, got_offset, addend); - } - } - - /* Return the address of the linkage table entry. */ - value = (got_sec->output_section->vma - + got_sec->output_offset - + got_offset); - - return value; -} - -/* Fill in a function descriptor consisting of the function's code - address and its global pointer. Return the descriptor's address. */ - -static bfd_vma -set_fptr_entry (bfd *abfd, struct bfd_link_info *info, - struct elf64_ia64_dyn_sym_info *dyn_i, - bfd_vma value) -{ - struct elf64_ia64_link_hash_table *ia64_info; - asection *fptr_sec; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return 0; - - fptr_sec = ia64_info->fptr_sec; - - if (!dyn_i->fptr_done) - { - dyn_i->fptr_done = 1; - - /* Fill in the function descriptor. */ - bfd_put_64 (abfd, value, fptr_sec->contents + dyn_i->fptr_offset); - bfd_put_64 (abfd, _bfd_get_gp_value (abfd), - fptr_sec->contents + dyn_i->fptr_offset + 8); - } - - /* Return the descriptor's address. */ - value = (fptr_sec->output_section->vma - + fptr_sec->output_offset - + dyn_i->fptr_offset); - - return value; -} - -/* Fill in a PLTOFF entry consisting of the function's code address - and its global pointer. Return the descriptor's address. */ - -static bfd_vma -set_pltoff_entry (bfd *abfd, struct bfd_link_info *info, - struct elf64_ia64_dyn_sym_info *dyn_i, - bfd_vma value, bfd_boolean is_plt) -{ - struct elf64_ia64_link_hash_table *ia64_info; - asection *pltoff_sec; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return 0; - - pltoff_sec = ia64_info->pltoff_sec; - - /* Don't do anything if this symbol uses a real PLT entry. In - that case, we'll fill this in during finish_dynamic_symbol. */ - if ((! dyn_i->want_plt || is_plt) - && !dyn_i->pltoff_done) - { - bfd_vma gp = _bfd_get_gp_value (abfd); - - /* Fill in the function descriptor. */ - bfd_put_64 (abfd, value, pltoff_sec->contents + dyn_i->pltoff_offset); - bfd_put_64 (abfd, gp, pltoff_sec->contents + dyn_i->pltoff_offset + 8); - - /* Install dynamic relocations if needed. */ - if (!is_plt - && bfd_link_pic (info) - && (!dyn_i->h - || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT - || dyn_i->h->root.type != bfd_link_hash_undefweak)) - { - /* VMS: */ - abort (); - } - - dyn_i->pltoff_done = 1; - } - - /* Return the descriptor's address. */ - value = (pltoff_sec->output_section->vma - + pltoff_sec->output_offset - + dyn_i->pltoff_offset); - - return value; -} - -/* Called through qsort to sort the .IA_64.unwind section during a - non-relocatable link. Set elf64_ia64_unwind_entry_compare_bfd - to the output bfd so we can do proper endianness frobbing. */ - -static bfd *elf64_ia64_unwind_entry_compare_bfd; - -static int -elf64_ia64_unwind_entry_compare (const void * a, const void * b) -{ - bfd_vma av, bv; - - av = bfd_get_64 (elf64_ia64_unwind_entry_compare_bfd, a); - bv = bfd_get_64 (elf64_ia64_unwind_entry_compare_bfd, b); - - return (av < bv ? -1 : av > bv ? 1 : 0); -} - -/* Make sure we've got ourselves a nice fat __gp value. */ -static bfd_boolean -elf64_ia64_choose_gp (bfd *abfd, struct bfd_link_info *info, bfd_boolean final) -{ - bfd_vma min_vma = (bfd_vma) -1, max_vma = 0; - bfd_vma min_short_vma = min_vma, max_short_vma = 0; - struct elf_link_hash_entry *gp; - bfd_vma gp_val; - asection *os; - struct elf64_ia64_link_hash_table *ia64_info; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - /* Find the min and max vma of all sections marked short. Also collect - min and max vma of any type, for use in selecting a nice gp. */ - for (os = abfd->sections; os ; os = os->next) - { - bfd_vma lo, hi; - - if ((os->flags & SEC_ALLOC) == 0) - continue; - - lo = os->vma; - /* When this function is called from elfNN_ia64_final_link - the correct value to use is os->size. When called from - elfNN_ia64_relax_section we are in the middle of section - sizing; some sections will already have os->size set, others - will have os->size zero and os->rawsize the previous size. */ - hi = os->vma + (!final && os->rawsize ? os->rawsize : os->size); - if (hi < lo) - hi = (bfd_vma) -1; - - if (min_vma > lo) - min_vma = lo; - if (max_vma < hi) - max_vma = hi; - if (os->flags & SEC_SMALL_DATA) - { - if (min_short_vma > lo) - min_short_vma = lo; - if (max_short_vma < hi) - max_short_vma = hi; - } - } - - if (ia64_info->min_short_sec) - { - if (min_short_vma - > (ia64_info->min_short_sec->vma - + ia64_info->min_short_offset)) - min_short_vma = (ia64_info->min_short_sec->vma - + ia64_info->min_short_offset); - if (max_short_vma - < (ia64_info->max_short_sec->vma - + ia64_info->max_short_offset)) - max_short_vma = (ia64_info->max_short_sec->vma - + ia64_info->max_short_offset); - } - - /* See if the user wants to force a value. */ - gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, - FALSE, FALSE); - - if (gp - && (gp->root.type == bfd_link_hash_defined - || gp->root.type == bfd_link_hash_defweak)) - { - asection *gp_sec = gp->root.u.def.section; - gp_val = (gp->root.u.def.value - + gp_sec->output_section->vma - + gp_sec->output_offset); - } - else - { - /* Pick a sensible value. */ - - if (ia64_info->min_short_sec) - { - bfd_vma short_range = max_short_vma - min_short_vma; - - /* If min_short_sec is set, pick one in the middle bewteen - min_short_vma and max_short_vma. */ - if (short_range >= 0x400000) - goto overflow; - gp_val = min_short_vma + short_range / 2; - } - else - { - asection *got_sec = ia64_info->root.sgot; - - /* Start with just the address of the .got. */ - if (got_sec) - gp_val = got_sec->output_section->vma; - else if (max_short_vma != 0) - gp_val = min_short_vma; - else if (max_vma - min_vma < 0x200000) - gp_val = min_vma; - else - gp_val = max_vma - 0x200000 + 8; - } - - /* If it is possible to address the entire image, but we - don't with the choice above, adjust. */ - if (max_vma - min_vma < 0x400000 - && (max_vma - gp_val >= 0x200000 - || gp_val - min_vma > 0x200000)) - gp_val = min_vma + 0x200000; - else if (max_short_vma != 0) - { - /* If we don't cover all the short data, adjust. */ - if (max_short_vma - gp_val >= 0x200000) - gp_val = min_short_vma + 0x200000; - - /* If we're addressing stuff past the end, adjust back. */ - if (gp_val > max_vma) - gp_val = max_vma - 0x200000 + 8; - } - } - - /* Validate whether all SHF_IA_64_SHORT sections are within - range of the chosen GP. */ - - if (max_short_vma != 0) - { - if (max_short_vma - min_short_vma >= 0x400000) - { -overflow: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: short data segment overflowed (%#Lx >= 0x400000)"), - abfd, max_short_vma - min_short_vma); - return FALSE; - } - else if ((gp_val > min_short_vma - && gp_val - min_short_vma > 0x200000) - || (gp_val < max_short_vma - && max_short_vma - gp_val >= 0x200000)) - { - _bfd_error_handler - (_("%B: __gp does not cover short data segment"), abfd); - return FALSE; - } - } - - _bfd_set_gp_value (abfd, gp_val); - - return TRUE; -} - -static bfd_boolean -elf64_ia64_final_link (bfd *abfd, struct bfd_link_info *info) -{ - struct elf64_ia64_link_hash_table *ia64_info; - asection *unwind_output_sec; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - /* Make sure we've got ourselves a nice fat __gp value. */ - if (!bfd_link_relocatable (info)) - { - bfd_vma gp_val; - struct elf_link_hash_entry *gp; - - /* We assume after gp is set, section size will only decrease. We - need to adjust gp for it. */ - _bfd_set_gp_value (abfd, 0); - if (! elf64_ia64_choose_gp (abfd, info, TRUE)) - return FALSE; - gp_val = _bfd_get_gp_value (abfd); - - gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, - FALSE, FALSE); - if (gp) - { - gp->root.type = bfd_link_hash_defined; - gp->root.u.def.value = gp_val; - gp->root.u.def.section = bfd_abs_section_ptr; - } - } - - /* If we're producing a final executable, we need to sort the contents - of the .IA_64.unwind section. Force this section to be relocated - into memory rather than written immediately to the output file. */ - unwind_output_sec = NULL; - if (!bfd_link_relocatable (info)) - { - asection *s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind); - if (s) - { - unwind_output_sec = s->output_section; - unwind_output_sec->contents - = bfd_malloc (unwind_output_sec->size); - if (unwind_output_sec->contents == NULL) - return FALSE; - } - } - - /* Invoke the regular ELF backend linker to do all the work. */ - if (!bfd_elf_final_link (abfd, info)) - return FALSE; - - if (unwind_output_sec) - { - elf64_ia64_unwind_entry_compare_bfd = abfd; - qsort (unwind_output_sec->contents, - (size_t) (unwind_output_sec->size / 24), - 24, - elf64_ia64_unwind_entry_compare); - - if (! bfd_set_section_contents (abfd, unwind_output_sec, - unwind_output_sec->contents, (bfd_vma) 0, - unwind_output_sec->size)) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -elf64_ia64_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_ia64_link_hash_table *ia64_info; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - bfd_boolean ret_val = TRUE; /* for non-fatal errors */ - bfd_vma gp_val; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - /* Infect various flags from the input section to the output section. */ - if (bfd_link_relocatable (info)) - { - bfd_vma flags; - - flags = elf_section_data(input_section)->this_hdr.sh_flags; - flags &= SHF_IA_64_NORECOV; - - elf_section_data(input_section->output_section) - ->this_hdr.sh_flags |= flags; - } - - gp_val = _bfd_get_gp_value (output_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; ++rel) - { - struct elf_link_hash_entry *h; - struct elf64_ia64_dyn_sym_info *dyn_i; - bfd_reloc_status_type r; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - unsigned int r_type; - bfd_vma value; - asection *sym_sec; - bfd_byte *hit_addr; - bfd_boolean dynamic_symbol_p; - bfd_boolean undef_weak_ref; - - r_type = ELF64_R_TYPE (rel->r_info); - if (r_type > R_IA64_MAX_RELOC_CODE) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unknown relocation type %d"), - input_bfd, (int) r_type); - bfd_set_error (bfd_error_bad_value); - ret_val = FALSE; - continue; - } - - howto = ia64_elf_lookup_howto (r_type); - r_symndx = ELF64_R_SYM (rel->r_info); - h = NULL; - sym = NULL; - sym_sec = NULL; - undef_weak_ref = FALSE; - - if (r_symndx < symtab_hdr->sh_info) - { - /* Reloc against local symbol. */ - asection *msec; - sym = local_syms + r_symndx; - sym_sec = local_sections[r_symndx]; - msec = sym_sec; - value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); - if (!bfd_link_relocatable (info) - && (sym_sec->flags & SEC_MERGE) != 0 - && ELF_ST_TYPE (sym->st_info) == STT_SECTION - && sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE) - { - struct elf64_ia64_local_hash_entry *loc_h; - - loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, FALSE); - if (loc_h && ! loc_h->sec_merge_done) - { - struct elf64_ia64_dyn_sym_info *dynent; - unsigned int count; - - for (count = loc_h->count, dynent = loc_h->info; - count != 0; - count--, dynent++) - { - msec = sym_sec; - dynent->addend = - _bfd_merged_section_offset (output_bfd, &msec, - elf_section_data (msec)-> - sec_info, - sym->st_value - + dynent->addend); - dynent->addend -= sym->st_value; - dynent->addend += msec->output_section->vma - + msec->output_offset - - sym_sec->output_section->vma - - sym_sec->output_offset; - } - - /* We may have introduced duplicated entries. We need - to remove them properly. */ - count = sort_dyn_sym_info (loc_h->info, loc_h->count); - if (count != loc_h->count) - { - loc_h->count = count; - loc_h->sorted_count = count; - } - - loc_h->sec_merge_done = 1; - } - } - } - else - { - bfd_boolean unresolved_reloc; - bfd_boolean warned, ignored; - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sym_sec, value, - unresolved_reloc, warned, ignored); - - if (h->root.type == bfd_link_hash_undefweak) - undef_weak_ref = TRUE; - else if (warned) - continue; - } - - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - if (sym_sec != NULL && discarded_section (sym_sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - hit_addr = contents + rel->r_offset; - value += rel->r_addend; - dynamic_symbol_p = elf64_ia64_dynamic_symbol_p (h); - - switch (r_type) - { - case R_IA64_NONE: - case R_IA64_LDXMOV: - continue; - - case R_IA64_IMM14: - case R_IA64_IMM22: - case R_IA64_IMM64: - case R_IA64_DIR32MSB: - case R_IA64_DIR32LSB: - case R_IA64_DIR64MSB: - case R_IA64_DIR64LSB: - /* Install a dynamic relocation for this reloc. */ - if ((dynamic_symbol_p || bfd_link_pic (info)) - && r_symndx != 0 - && (input_section->flags & SEC_ALLOC) != 0) - { - unsigned int dyn_r_type; - bfd_vma addend; - - switch (r_type) - { - case R_IA64_IMM14: - case R_IA64_IMM22: - case R_IA64_IMM64: - /* ??? People shouldn't be doing non-pic code in - shared libraries nor dynamic executables. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: non-pic code with imm relocation against" - " dynamic symbol `%s'"), - input_bfd, - h ? h->root.root.string - : bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - sym_sec)); - ret_val = FALSE; - continue; - - default: - break; - } - - /* If we don't need dynamic symbol lookup, find a - matching RELATIVE relocation. */ - dyn_r_type = r_type; - if (dynamic_symbol_p) - { - addend = rel->r_addend; - value = 0; - } - else - { - addend = value; - } - - /* VMS: install a FIX64. */ - switch (dyn_r_type) - { - case R_IA64_DIR32LSB: - dyn_r_type = R_IA64_VMS_FIX32; - break; - case R_IA64_DIR64LSB: - dyn_r_type = R_IA64_VMS_FIX64; - break; - default: - BFD_ASSERT (FALSE); - break; - } - elf64_ia64_install_fixup - (output_bfd, ia64_info, h, - dyn_r_type, input_section, rel->r_offset, addend); - r = bfd_reloc_ok; - break; - } - /* Fall through. */ - - case R_IA64_LTV32MSB: - case R_IA64_LTV32LSB: - case R_IA64_LTV64MSB: - case R_IA64_LTV64LSB: - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_GPREL22: - case R_IA64_GPREL64I: - case R_IA64_GPREL32MSB: - case R_IA64_GPREL32LSB: - case R_IA64_GPREL64MSB: - case R_IA64_GPREL64LSB: - if (dynamic_symbol_p) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: @gprel relocation against dynamic symbol %s"), - input_bfd, - h ? h->root.root.string - : bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - sym_sec)); - ret_val = FALSE; - continue; - } - value -= gp_val; - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_LTOFF22: - case R_IA64_LTOFF22X: - case R_IA64_LTOFF64I: - dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); - value = set_got_entry (input_bfd, info, dyn_i, - rel->r_addend, value, R_IA64_DIR64LSB); - value -= gp_val; - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_PLTOFF22: - case R_IA64_PLTOFF64I: - case R_IA64_PLTOFF64MSB: - case R_IA64_PLTOFF64LSB: - dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); - value = set_pltoff_entry (output_bfd, info, dyn_i, value, FALSE); - value -= gp_val; - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_FPTR64I: - case R_IA64_FPTR32MSB: - case R_IA64_FPTR32LSB: - case R_IA64_FPTR64MSB: - case R_IA64_FPTR64LSB: - dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); - if (dyn_i->want_fptr) - { - if (!undef_weak_ref) - value = set_fptr_entry (output_bfd, info, dyn_i, value); - } - if (!dyn_i->want_fptr || bfd_link_pie (info)) - { - /* Otherwise, we expect the dynamic linker to create - the entry. */ - - if (dyn_i->want_fptr) - { - if (r_type == R_IA64_FPTR64I) - { - /* We can't represent this without a dynamic symbol. - Adjust the relocation to be against an output - section symbol, which are always present in the - dynamic symbol table. */ - /* ??? People shouldn't be doing non-pic code in - shared libraries. Hork. */ - _bfd_error_handler - (_("%B: linking non-pic code in a position independent executable"), - input_bfd); - ret_val = FALSE; - continue; - } - } - else - { - value = 0; - } - - /* VMS: FIXFD. */ - elf64_ia64_install_fixup - (output_bfd, ia64_info, h, R_IA64_VMS_FIXFD, - input_section, rel->r_offset, 0); - r = bfd_reloc_ok; - break; - } - - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_LTOFF_FPTR22: - case R_IA64_LTOFF_FPTR64I: - case R_IA64_LTOFF_FPTR32MSB: - case R_IA64_LTOFF_FPTR32LSB: - case R_IA64_LTOFF_FPTR64MSB: - case R_IA64_LTOFF_FPTR64LSB: - dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); - if (dyn_i->want_fptr) - { - BFD_ASSERT (h == NULL || !h->def_dynamic); - if (!undef_weak_ref) - value = set_fptr_entry (output_bfd, info, dyn_i, value); - } - else - value = 0; - - value = set_got_entry (output_bfd, info, dyn_i, - rel->r_addend, value, R_IA64_FPTR64LSB); - value -= gp_val; - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_PCREL32MSB: - case R_IA64_PCREL32LSB: - case R_IA64_PCREL64MSB: - case R_IA64_PCREL64LSB: - /* Install a dynamic relocation for this reloc. */ - if (dynamic_symbol_p && r_symndx != 0) - { - /* VMS: doesn't exist ??? */ - abort (); - } - goto finish_pcrel; - - case R_IA64_PCREL21B: - case R_IA64_PCREL60B: - /* We should have created a PLT entry for any dynamic symbol. */ - dyn_i = NULL; - if (h) - dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, FALSE); - - if (dyn_i && dyn_i->want_plt2) - { - /* Should have caught this earlier. */ - BFD_ASSERT (rel->r_addend == 0); - - value = (ia64_info->root.splt->output_section->vma - + ia64_info->root.splt->output_offset - + dyn_i->plt2_offset); - } - else - { - /* Since there's no PLT entry, Validate that this is - locally defined. */ - BFD_ASSERT (undef_weak_ref || sym_sec->output_section != NULL); - - /* If the symbol is undef_weak, we shouldn't be trying - to call it. There's every chance that we'd wind up - with an out-of-range fixup here. Don't bother setting - any value at all. */ - if (undef_weak_ref) - continue; - } - goto finish_pcrel; - - case R_IA64_PCREL21BI: - case R_IA64_PCREL21F: - case R_IA64_PCREL21M: - case R_IA64_PCREL22: - case R_IA64_PCREL64I: - /* The PCREL21BI reloc is specifically not intended for use with - dynamic relocs. PCREL21F and PCREL21M are used for speculation - fixup code, and thus probably ought not be dynamic. The - PCREL22 and PCREL64I relocs aren't emitted as dynamic relocs. */ - if (dynamic_symbol_p) - { - const char *msg; - - if (r_type == R_IA64_PCREL21BI) - /* xgettext:c-format */ - msg = _("%B: @internal branch to dynamic symbol %s"); - else if (r_type == R_IA64_PCREL21F || r_type == R_IA64_PCREL21M) - /* xgettext:c-format */ - msg = _("%B: speculation fixup to dynamic symbol %s"); - else - /* xgettext:c-format */ - msg = _("%B: @pcrel relocation against dynamic symbol %s"); - _bfd_error_handler (msg, input_bfd, - h ? h->root.root.string - : bfd_elf_sym_name (input_bfd, - symtab_hdr, - sym, - sym_sec)); - ret_val = FALSE; - continue; - } - goto finish_pcrel; - - finish_pcrel: - /* Make pc-relative. */ - value -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset) & ~ (bfd_vma) 0x3; - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_SEGREL32MSB: - case R_IA64_SEGREL32LSB: - case R_IA64_SEGREL64MSB: - case R_IA64_SEGREL64LSB: - { - /* Find the segment that contains the output_section. */ - Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section - (output_bfd, sym_sec->output_section); - - if (p == NULL) - { - r = bfd_reloc_notsupported; - } - else - { - /* The VMA of the segment is the vaddr of the associated - program header. */ - if (value > p->p_vaddr) - value -= p->p_vaddr; - else - value = 0; - r = ia64_elf_install_value (hit_addr, value, r_type); - } - break; - } - - case R_IA64_SECREL32MSB: - case R_IA64_SECREL32LSB: - case R_IA64_SECREL64MSB: - case R_IA64_SECREL64LSB: - /* Make output-section relative to section where the symbol - is defined. PR 475 */ - if (sym_sec) - value -= sym_sec->output_section->vma; - r = ia64_elf_install_value (hit_addr, value, r_type); - break; - - case R_IA64_IPLTMSB: - case R_IA64_IPLTLSB: - /* Install a dynamic relocation for this reloc. */ - if ((dynamic_symbol_p || bfd_link_pic (info)) - && (input_section->flags & SEC_ALLOC) != 0) - { - /* VMS: FIXFD ?? */ - abort (); - } - - if (r_type == R_IA64_IPLTMSB) - r_type = R_IA64_DIR64MSB; - else - r_type = R_IA64_DIR64LSB; - ia64_elf_install_value (hit_addr, value, r_type); - r = ia64_elf_install_value (hit_addr + 8, gp_val, r_type); - break; - - case R_IA64_TPREL14: - case R_IA64_TPREL22: - case R_IA64_TPREL64I: - r = bfd_reloc_notsupported; - break; - - case R_IA64_DTPREL14: - case R_IA64_DTPREL22: - case R_IA64_DTPREL64I: - case R_IA64_DTPREL32LSB: - case R_IA64_DTPREL32MSB: - case R_IA64_DTPREL64LSB: - case R_IA64_DTPREL64MSB: - r = bfd_reloc_notsupported; - break; - - case R_IA64_LTOFF_TPREL22: - case R_IA64_LTOFF_DTPMOD22: - case R_IA64_LTOFF_DTPREL22: - r = bfd_reloc_notsupported; - break; - - default: - r = bfd_reloc_notsupported; - break; - } - - switch (r) - { - case bfd_reloc_ok: - break; - - case bfd_reloc_undefined: - /* This can happen for global table relative relocs if - __gp is undefined. This is a panic situation so we - don't try to continue. */ - (*info->callbacks->undefined_symbol) - (info, "__gp", input_bfd, input_section, rel->r_offset, 1); - return FALSE; - - case bfd_reloc_notsupported: - { - const char *name; - - if (h) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - sym_sec); - (*info->callbacks->warning) (info, _("unsupported reloc"), - name, input_bfd, - input_section, rel->r_offset); - ret_val = FALSE; - } - break; - - case bfd_reloc_dangerous: - case bfd_reloc_outofrange: - case bfd_reloc_overflow: - default: - { - const char *name; - - if (h) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - sym_sec); - - switch (r_type) - { - case R_IA64_TPREL14: - case R_IA64_TPREL22: - case R_IA64_TPREL64I: - case R_IA64_DTPREL14: - case R_IA64_DTPREL22: - case R_IA64_DTPREL64I: - case R_IA64_DTPREL32LSB: - case R_IA64_DTPREL32MSB: - case R_IA64_DTPREL64LSB: - case R_IA64_DTPREL64MSB: - case R_IA64_LTOFF_TPREL22: - case R_IA64_LTOFF_DTPMOD22: - case R_IA64_LTOFF_DTPREL22: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: missing TLS section for relocation %s against `%s'" - " at %#Lx in section `%A'."), - input_bfd, howto->name, name, - rel->r_offset, input_section); - break; - - case R_IA64_PCREL21B: - case R_IA64_PCREL21BI: - case R_IA64_PCREL21M: - case R_IA64_PCREL21F: - if (is_elf_hash_table (info->hash)) - { - /* Relaxtion is always performed for ELF output. - Overflow failures for those relocations mean - that the section is too big to relax. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Can't relax br (%s) to `%s' at %#Lx in section" - " `%A' with size %#Lx (> 0x1000000)."), - input_bfd, howto->name, name, rel->r_offset, - input_section, input_section->size); - break; - } - /* Fall through. */ - default: - (*info->callbacks->reloc_overflow) (info, - &h->root, - name, - howto->name, - (bfd_vma) 0, - input_bfd, - input_section, - rel->r_offset); - break; - } - - ret_val = FALSE; - } - break; - } - } - - return ret_val; -} - -static bfd_boolean -elf64_ia64_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf64_ia64_link_hash_table *ia64_info; - struct elf64_ia64_dyn_sym_info *dyn_i; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, FALSE); - - /* Fill in the PLT data, if required. */ - if (dyn_i && dyn_i->want_plt) - { - bfd_byte *loc; - asection *plt_sec; - bfd_vma plt_addr, pltoff_addr, gp_val; - - gp_val = _bfd_get_gp_value (output_bfd); - - plt_sec = ia64_info->root.splt; - plt_addr = 0; /* Not used as overriden by FIXUPs. */ - pltoff_addr = set_pltoff_entry (output_bfd, info, dyn_i, plt_addr, TRUE); - - /* Initialize the FULL PLT entry, if needed. */ - if (dyn_i->want_plt2) - { - loc = plt_sec->contents + dyn_i->plt2_offset; - - memcpy (loc, plt_full_entry, PLT_FULL_ENTRY_SIZE); - ia64_elf_install_value (loc, pltoff_addr - gp_val, R_IA64_IMM22); - - /* Mark the symbol as undefined, rather than as defined in the - plt section. Leave the value alone. */ - /* ??? We didn't redefine it in adjust_dynamic_symbol in the - first place. But perhaps elflink.c did some for us. */ - if (!h->def_regular) - sym->st_shndx = SHN_UNDEF; - } - - /* VMS: FIXFD. */ - elf64_ia64_install_fixup - (output_bfd, ia64_info, h, R_IA64_VMS_FIXFD, ia64_info->pltoff_sec, - pltoff_addr - (ia64_info->pltoff_sec->output_section->vma - + ia64_info->pltoff_sec->output_offset), 0); - } - - /* Mark some specially defined symbols as absolute. */ - if (h == ia64_info->root.hdynamic - || h == ia64_info->root.hgot - || h == ia64_info->root.hplt) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -static bfd_boolean -elf64_ia64_finish_dynamic_sections (bfd *abfd, - struct bfd_link_info *info) -{ - struct elf64_ia64_link_hash_table *ia64_info; - bfd *dynobj; - - ia64_info = elf64_ia64_hash_table (info); - if (ia64_info == NULL) - return FALSE; - - dynobj = ia64_info->root.dynobj; - - if (elf_hash_table (info)->dynamic_sections_created) - { - Elf64_External_Dyn *dyncon, *dynconend; - asection *sdyn; - asection *unwind_sec; - bfd_vma gp_val; - unsigned int gp_seg; - bfd_vma gp_off; - Elf_Internal_Phdr *phdr; - Elf_Internal_Phdr *base_phdr; - unsigned int unwind_seg = 0; - unsigned int code_seg = 0; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - BFD_ASSERT (sdyn != NULL); - dyncon = (Elf64_External_Dyn *) sdyn->contents; - dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); - - gp_val = _bfd_get_gp_value (abfd); - phdr = _bfd_elf_find_segment_containing_section - (info->output_bfd, ia64_info->pltoff_sec->output_section); - BFD_ASSERT (phdr != NULL); - base_phdr = elf_tdata (info->output_bfd)->phdr; - gp_seg = phdr - base_phdr; - gp_off = gp_val - phdr->p_vaddr; - - unwind_sec = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind); - if (unwind_sec != NULL) - { - asection *code_sec; - - phdr = _bfd_elf_find_segment_containing_section (abfd, unwind_sec); - BFD_ASSERT (phdr != NULL); - unwind_seg = phdr - base_phdr; - - code_sec = bfd_get_section_by_name (abfd, "$CODE$"); - phdr = _bfd_elf_find_segment_containing_section (abfd, code_sec); - BFD_ASSERT (phdr != NULL); - code_seg = phdr - base_phdr; - } - - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - - bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_IA_64_VMS_FIXUP_RELA_OFF: - dyn.d_un.d_val += - (ia64_info->fixups_sec->output_section->vma - + ia64_info->fixups_sec->output_offset) - - (sdyn->output_section->vma + sdyn->output_offset); - break; - - case DT_IA_64_VMS_PLTGOT_OFFSET: - dyn.d_un.d_val = gp_off; - break; - - case DT_IA_64_VMS_PLTGOT_SEG: - dyn.d_un.d_val = gp_seg; - break; - - case DT_IA_64_VMS_UNWINDSZ: - if (unwind_sec == NULL) - { - dyn.d_tag = DT_NULL; - dyn.d_un.d_val = 0xdead; - } - else - dyn.d_un.d_val = unwind_sec->size; - break; - - case DT_IA_64_VMS_UNWIND_CODSEG: - dyn.d_un.d_val = code_seg; - break; - - case DT_IA_64_VMS_UNWIND_INFOSEG: - case DT_IA_64_VMS_UNWIND_SEG: - dyn.d_un.d_val = unwind_seg; - break; - - case DT_IA_64_VMS_UNWIND_OFFSET: - break; - - default: - /* No need to rewrite the entry. */ - continue; - } - - bfd_elf64_swap_dyn_out (abfd, &dyn, dyncon); - } - } - - /* Handle transfer addresses. */ - { - asection *tfr_sec = ia64_info->transfer_sec; - struct elf64_vms_transfer *tfr; - struct elf_link_hash_entry *tfr3; - - tfr = (struct elf64_vms_transfer *)tfr_sec->contents; - bfd_putl32 (6 * 8, tfr->size); - bfd_putl64 (tfr_sec->output_section->vma - + tfr_sec->output_offset - + 6 * 8, tfr->tfradr3); - - tfr3 = elf_link_hash_lookup (elf_hash_table (info), "ELF$TFRADR", FALSE, - FALSE, FALSE); - - if (tfr3 - && (tfr3->root.type == bfd_link_hash_defined - || tfr3->root.type == bfd_link_hash_defweak)) - { - asection *tfr3_sec = tfr3->root.u.def.section; - bfd_vma tfr3_val; - - tfr3_val = (tfr3->root.u.def.value - + tfr3_sec->output_section->vma - + tfr3_sec->output_offset); - - bfd_putl64 (tfr3_val, tfr->tfr3_func); - bfd_putl64 (_bfd_get_gp_value (info->output_bfd), tfr->tfr3_gp); - } - - /* FIXME: set linker flags, - handle lib$initialize. */ - } - - return TRUE; -} - -/* ELF file flag handling: */ - -/* Function to keep IA-64 specific file flags. */ -static bfd_boolean -elf64_ia64_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (!elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ -static bfd_boolean -elf64_ia64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword out_flags; - flagword in_flags; - bfd_boolean ok = TRUE; - - /* Don't even pretend to support mixed-format linking. */ - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return FALSE; - - in_flags = elf_elfheader (ibfd)->e_flags; - out_flags = elf_elfheader (obfd)->e_flags; - - if (! elf_flags_init (obfd)) - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = in_flags; - - if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) - && bfd_get_arch_info (obfd)->the_default) - { - return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), - bfd_get_mach (ibfd)); - } - - return TRUE; - } - - /* Check flag compatibility. */ - if (in_flags == out_flags) - return TRUE; - - /* Output has EF_IA_64_REDUCEDFP set only if all inputs have it set. */ - if (!(in_flags & EF_IA_64_REDUCEDFP) && (out_flags & EF_IA_64_REDUCEDFP)) - elf_elfheader (obfd)->e_flags &= ~EF_IA_64_REDUCEDFP; - - if ((in_flags & EF_IA_64_TRAPNIL) != (out_flags & EF_IA_64_TRAPNIL)) - { - _bfd_error_handler - (_("%B: linking trap-on-NULL-dereference with non-trapping files"), - ibfd); - - bfd_set_error (bfd_error_bad_value); - ok = FALSE; - } - if ((in_flags & EF_IA_64_BE) != (out_flags & EF_IA_64_BE)) - { - _bfd_error_handler - (_("%B: linking big-endian files with little-endian files"), - ibfd); - - bfd_set_error (bfd_error_bad_value); - ok = FALSE; - } - if ((in_flags & EF_IA_64_ABI64) != (out_flags & EF_IA_64_ABI64)) - { - _bfd_error_handler - (_("%B: linking 64-bit files with 32-bit files"), - ibfd); - - bfd_set_error (bfd_error_bad_value); - ok = FALSE; - } - if ((in_flags & EF_IA_64_CONS_GP) != (out_flags & EF_IA_64_CONS_GP)) - { - _bfd_error_handler - (_("%B: linking constant-gp files with non-constant-gp files"), - ibfd); - - bfd_set_error (bfd_error_bad_value); - ok = FALSE; - } - if ((in_flags & EF_IA_64_NOFUNCDESC_CONS_GP) - != (out_flags & EF_IA_64_NOFUNCDESC_CONS_GP)) - { - _bfd_error_handler - (_("%B: linking auto-pic files with non-auto-pic files"), - ibfd); - - bfd_set_error (bfd_error_bad_value); - ok = FALSE; - } - - return ok; -} - -static bfd_boolean -elf64_ia64_print_private_bfd_data (bfd *abfd, void * ptr) -{ - FILE *file = (FILE *) ptr; - flagword flags = elf_elfheader (abfd)->e_flags; - - BFD_ASSERT (abfd != NULL && ptr != NULL); - - fprintf (file, "private flags = %s%s%s%s%s%s%s%s\n", - (flags & EF_IA_64_TRAPNIL) ? "TRAPNIL, " : "", - (flags & EF_IA_64_EXT) ? "EXT, " : "", - (flags & EF_IA_64_BE) ? "BE, " : "LE, ", - (flags & EF_IA_64_REDUCEDFP) ? "REDUCEDFP, " : "", - (flags & EF_IA_64_CONS_GP) ? "CONS_GP, " : "", - (flags & EF_IA_64_NOFUNCDESC_CONS_GP) ? "NOFUNCDESC_CONS_GP, " : "", - (flags & EF_IA_64_ABSOLUTE) ? "ABSOLUTE, " : "", - (flags & EF_IA_64_ABI64) ? "ABI64" : "ABI32"); - - _bfd_elf_print_private_bfd_data (abfd, ptr); - return TRUE; -} - -static enum elf_reloc_type_class -elf64_ia64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF64_R_TYPE (rela->r_info)) - { - case R_IA64_REL32MSB: - case R_IA64_REL32LSB: - case R_IA64_REL64MSB: - case R_IA64_REL64LSB: - return reloc_class_relative; - case R_IA64_IPLTMSB: - case R_IA64_IPLTLSB: - return reloc_class_plt; - case R_IA64_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -static const struct bfd_elf_special_section elf64_ia64_special_sections[] = -{ - { STRING_COMMA_LEN (".sbss"), -1, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, - { STRING_COMMA_LEN (".sdata"), -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, - { NULL, 0, 0, 0, 0 } -}; - -static bfd_boolean -elf64_ia64_object_p (bfd *abfd) -{ - asection *sec; - asection *group, *unwi, *unw; - flagword flags; - const char *name; - char *unwi_name, *unw_name; - bfd_size_type amt; - - if (abfd->flags & DYNAMIC) - return TRUE; - - /* Flags for fake group section. */ - flags = (SEC_LINKER_CREATED | SEC_GROUP | SEC_LINK_ONCE - | SEC_EXCLUDE); - - /* We add a fake section group for each .gnu.linkonce.t.* section, - which isn't in a section group, and its unwind sections. */ - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - if (elf_sec_group (sec) == NULL - && ((sec->flags & (SEC_LINK_ONCE | SEC_CODE | SEC_GROUP)) - == (SEC_LINK_ONCE | SEC_CODE)) - && CONST_STRNEQ (sec->name, ".gnu.linkonce.t.")) - { - name = sec->name + 16; - - amt = strlen (name) + sizeof (".gnu.linkonce.ia64unwi."); - unwi_name = bfd_alloc (abfd, amt); - if (!unwi_name) - return FALSE; - - strcpy (stpcpy (unwi_name, ".gnu.linkonce.ia64unwi."), name); - unwi = bfd_get_section_by_name (abfd, unwi_name); - - amt = strlen (name) + sizeof (".gnu.linkonce.ia64unw."); - unw_name = bfd_alloc (abfd, amt); - if (!unw_name) - return FALSE; - - strcpy (stpcpy (unw_name, ".gnu.linkonce.ia64unw."), name); - unw = bfd_get_section_by_name (abfd, unw_name); - - /* We need to create a fake group section for it and its - unwind sections. */ - group = bfd_make_section_anyway_with_flags (abfd, name, - flags); - if (group == NULL) - return FALSE; - - /* Move the fake group section to the beginning. */ - bfd_section_list_remove (abfd, group); - bfd_section_list_prepend (abfd, group); - - elf_next_in_group (group) = sec; - - elf_group_name (sec) = name; - elf_next_in_group (sec) = sec; - elf_sec_group (sec) = group; - - if (unwi) - { - elf_group_name (unwi) = name; - elf_next_in_group (unwi) = sec; - elf_next_in_group (sec) = unwi; - elf_sec_group (unwi) = group; - } - - if (unw) - { - elf_group_name (unw) = name; - if (unwi) - { - elf_next_in_group (unw) = elf_next_in_group (unwi); - elf_next_in_group (unwi) = unw; - } - else - { - elf_next_in_group (unw) = sec; - elf_next_in_group (sec) = unw; - } - elf_sec_group (unw) = group; - } - - /* Fake SHT_GROUP section header. */ - elf_section_data (group)->this_hdr.bfd_section = group; - elf_section_data (group)->this_hdr.sh_type = SHT_GROUP; - } - } - return TRUE; -} - -/* Handle an IA-64 specific section when reading an object file. This - is called when bfd_section_from_shdr finds a section with an unknown - type. */ - -static bfd_boolean -elf64_vms_section_from_shdr (bfd *abfd, - Elf_Internal_Shdr *hdr, - const char *name, - int shindex) -{ - flagword secflags = 0; - - switch (hdr->sh_type) - { - case SHT_IA_64_VMS_TRACE: - case SHT_IA_64_VMS_DEBUG: - case SHT_IA_64_VMS_DEBUG_STR: - secflags = SEC_DEBUGGING; - break; - - case SHT_IA_64_UNWIND: - case SHT_IA_64_HP_OPT_ANOT: - break; - - case SHT_IA_64_EXT: - if (strcmp (name, ELF_STRING_ia64_archext) != 0) - return FALSE; - break; - - default: - return FALSE; - } - - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) - return FALSE; - - if (secflags != 0) - { - asection *newsect = hdr->bfd_section; - - if (! bfd_set_section_flags - (abfd, newsect, bfd_get_section_flags (abfd, newsect) | secflags)) - return FALSE; - } - - return TRUE; -} - -static bfd_boolean -elf64_vms_object_p (bfd *abfd) -{ - Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - Elf_Internal_Phdr *i_phdr = elf_tdata (abfd)->phdr; - unsigned int i; - unsigned int num_text = 0; - unsigned int num_data = 0; - unsigned int num_rodata = 0; - char name[16]; - - if (!elf64_ia64_object_p (abfd)) - return FALSE; - - /* Many VMS compilers do not generate sections for the corresponding - segment. This is boring as binutils tools won't be able to disassemble - the code. So we simply create all the missing sections. */ - for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++) - { - /* Is there a section for this segment? */ - bfd_vma base_vma = i_phdr->p_vaddr; - bfd_vma limit_vma = base_vma + i_phdr->p_filesz; - - if (i_phdr->p_type != PT_LOAD) - continue; - - /* We need to cover from base_vms to limit_vma. */ - again: - while (base_vma < limit_vma) - { - bfd_vma next_vma = limit_vma; - asection *nsec; - asection *sec; - flagword flags; - char *nname = NULL; - - /* Find a section covering [base_vma;limit_vma) */ - for (sec = abfd->sections; sec != NULL; sec = sec->next) - { - /* Skip uninteresting sections (either not in memory or - below base_vma. */ - if ((sec->flags & (SEC_ALLOC | SEC_LOAD)) == 0 - || sec->vma + sec->size <= base_vma) - continue; - if (sec->vma <= base_vma) - { - /* This section covers (maybe partially) the beginning - of the range. */ - base_vma = sec->vma + sec->size; - goto again; - } - if (sec->vma < next_vma) - { - /* This section partially covers the end of the range. - Used to compute the size of the hole. */ - next_vma = sec->vma; - } - } - - /* No section covering [base_vma; next_vma). Create a fake one. */ - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; - if (i_phdr->p_flags & PF_X) - { - flags |= SEC_CODE; - if (num_text++ == 0) - nname = ".text"; - else - sprintf (name, ".text$%u", num_text); - } - else if ((i_phdr->p_flags & (PF_R | PF_W)) == PF_R) - { - flags |= SEC_READONLY; - sprintf (name, ".rodata$%u", num_rodata++); - } - else - { - flags |= SEC_DATA; - sprintf (name, ".data$%u", num_data++); - } - - /* Allocate name. */ - if (nname == NULL) - { - size_t name_len = strlen (name) + 1; - nname = bfd_alloc (abfd, name_len); - if (nname == NULL) - return FALSE; - memcpy (nname, name, name_len); - } - - /* Create and fill new section. */ - nsec = bfd_make_section_anyway_with_flags (abfd, nname, flags); - if (nsec == NULL) - return FALSE; - nsec->vma = base_vma; - nsec->size = next_vma - base_vma; - nsec->filepos = i_phdr->p_offset + (base_vma - i_phdr->p_vaddr); - - base_vma = next_vma; - } - } - return TRUE; -} - -static void -elf64_vms_post_process_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_OPENVMS; - i_ehdrp->e_ident[EI_ABIVERSION] = 2; -} - -static bfd_boolean -elf64_vms_section_processing (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr) -{ - if (hdr->bfd_section != NULL) - { - const char *name = bfd_get_section_name (abfd, hdr->bfd_section); - - if (strcmp (name, ".text") == 0) - hdr->sh_flags |= SHF_IA_64_VMS_SHARED; - else if ((strcmp (name, ".debug") == 0) - || (strcmp (name, ".debug_abbrev") == 0) - || (strcmp (name, ".debug_aranges") == 0) - || (strcmp (name, ".debug_frame") == 0) - || (strcmp (name, ".debug_info") == 0) - || (strcmp (name, ".debug_loc") == 0) - || (strcmp (name, ".debug_macinfo") == 0) - || (strcmp (name, ".debug_pubnames") == 0) - || (strcmp (name, ".debug_pubtypes") == 0)) - hdr->sh_type = SHT_IA_64_VMS_DEBUG; - else if ((strcmp (name, ".debug_line") == 0) - || (strcmp (name, ".debug_ranges") == 0) - || (strcmp (name, ".trace_info") == 0) - || (strcmp (name, ".trace_abbrev") == 0) - || (strcmp (name, ".trace_aranges") == 0)) - hdr->sh_type = SHT_IA_64_VMS_TRACE; - else if (strcmp (name, ".debug_str") == 0) - hdr->sh_type = SHT_IA_64_VMS_DEBUG_STR; - } - - return TRUE; -} - -/* The final processing done just before writing out a VMS IA-64 ELF - object file. */ - -static void -elf64_vms_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - Elf_Internal_Shdr *hdr; - asection *s; - int unwind_info_sect_idx = 0; - - for (s = abfd->sections; s; s = s->next) - { - hdr = &elf_section_data (s)->this_hdr; - - if (strcmp (bfd_get_section_name (abfd, hdr->bfd_section), - ".IA_64.unwind_info") == 0) - unwind_info_sect_idx = elf_section_data (s)->this_idx; - - switch (hdr->sh_type) - { - case SHT_IA_64_UNWIND: - /* VMS requires sh_info to point to the unwind info section. */ - hdr->sh_info = unwind_info_sect_idx; - break; - } - } - - if (! elf_flags_init (abfd)) - { - unsigned long flags = 0; - - if (abfd->xvec->byteorder == BFD_ENDIAN_BIG) - flags |= EF_IA_64_BE; - if (bfd_get_mach (abfd) == bfd_mach_ia64_elf64) - flags |= EF_IA_64_ABI64; - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - } -} - -static bfd_boolean -elf64_vms_write_shdrs_and_ehdr (bfd *abfd) -{ - unsigned char needed_count[8]; - - if (!bfd_elf64_write_shdrs_and_ehdr (abfd)) - return FALSE; - - bfd_putl64 (elf_ia64_vms_tdata (abfd)->needed_count, needed_count); - - if (bfd_seek (abfd, sizeof (Elf64_External_Ehdr), SEEK_SET) != 0 - || bfd_bwrite (needed_count, 8, abfd) != 8) - return FALSE; - - return TRUE; -} - -static bfd_boolean -elf64_vms_close_and_cleanup (bfd *abfd) -{ - if (bfd_get_format (abfd) == bfd_object) - { - long isize; - - /* Pad to 8 byte boundary for IPF/VMS. */ - isize = bfd_get_size (abfd); - if ((isize & 7) != 0) - { - int ishort = 8 - (isize & 7); - bfd_uint64_t pad = 0; - - bfd_seek (abfd, isize, SEEK_SET); - bfd_bwrite (&pad, ishort, abfd); - } - } - - return _bfd_elf_close_and_cleanup (abfd); -} - -/* Add symbols from an ELF object file to the linker hash table. */ - -static bfd_boolean -elf64_vms_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_Internal_Sym *isymbuf = NULL; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - const struct elf_backend_data *bed; - struct elf_link_hash_table *htab; - bfd_size_type amt; - - 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 (bfd_link_relocatable (info) - || !is_elf_hash_table (htab) - || info->output_bfd->xvec != abfd->xvec) - { - if (bfd_link_relocatable (info)) - bfd_set_error (bfd_error_invalid_operation); - else - bfd_set_error (bfd_error_wrong_format); - goto error_return; - } - } - - 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 (bfd_link_pic (info) - && is_elf_hash_table (htab) - && info->output_bfd->xvec == abfd->xvec - && !htab->dynamic_sections_created) - { - if (! elf64_ia64_create_dynamic_sections (abfd, info)) - goto error_return; - } - } - else if (!is_elf_hash_table (htab)) - goto error_return; - else - { - asection *s; - bfd_byte *dynbuf; - bfd_byte *extdyn; - - /* ld --just-symbols and dynamic objects don't mix very well. - ld shouldn't allow it. */ - if ((s = abfd->sections) != NULL - && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - abort (); - - /* Be sure there are dynamic sections. */ - if (! elf64_ia64_create_dynamic_sections (htab->dynobj, info)) - goto error_return; - - s = bfd_get_section_by_name (abfd, ".dynamic"); - if (s == NULL) - { - /* VMS libraries do not have dynamic sections. Create one from - the segment. */ - Elf_Internal_Phdr *phdr; - unsigned int i, phnum; - - phdr = elf_tdata (abfd)->phdr; - if (phdr == NULL) - goto error_return; - phnum = elf_elfheader (abfd)->e_phnum; - for (i = 0; i < phnum; phdr++) - if (phdr->p_type == PT_DYNAMIC) - { - s = bfd_make_section (abfd, ".dynamic"); - if (s == NULL) - goto error_return; - s->vma = phdr->p_vaddr; - s->lma = phdr->p_paddr; - s->size = phdr->p_filesz; - s->filepos = phdr->p_offset; - s->flags |= SEC_HAS_CONTENTS; - s->alignment_power = bfd_log2 (phdr->p_align); - break; - } - if (s == NULL) - goto error_return; - } - - /* Extract IDENT. */ - if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) - { -error_free_dyn: - free (dynbuf); - goto error_return; - } - - 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_IA_64_VMS_IDENT) - { - bfd_uint64_t tagv = dyn.d_un.d_val; - elf_ia64_vms_ident (abfd) = tagv; - break; - } - } - if (extdyn >= dynbuf + s->size) - { - /* Ident not found. */ - goto error_free_dyn; - } - free (dynbuf); - - /* 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); - - /* FIXME: should we detect if this library is already included ? - This should be harmless and shouldn't happen in practice. */ - } - - hdr = &elf_tdata (abfd)->symtab_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. */ - extsymcount = symcount - hdr->sh_info; - extsymoff = hdr->sh_info; - - sym_hash = NULL; - if (extsymcount != 0) - { - isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - - /* We store a pointer to the hash table entry for each external - symbol. */ - amt = extsymcount * sizeof (struct elf_link_hash_entry *); - sym_hash = (struct elf_link_hash_entry **) bfd_alloc (abfd, amt); - if (sym_hash == NULL) - goto error_free_sym; - elf_sym_hashes (abfd) = sym_hash; - } - - for (isym = isymbuf, isymend = isymbuf + extsymcount; - isym < isymend; - isym++, sym_hash++) - { - 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 common; - unsigned int old_alignment; - bfd *old_bfd; - - 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); - switch (bind) - { - case 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; - - case STB_GLOBAL: - if (isym->st_shndx != SHN_UNDEF && !common) - flags = BSF_GLOBAL; - break; - - case STB_WEAK: - flags = BSF_WEAK; - break; - - case STB_GNU_UNIQUE: - flags = BSF_GNU_UNIQUE; - break; - - default: - /* Leave it up to the processor backend. */ - break; - } - - if (isym->st_shndx == SHN_UNDEF) - sec = bfd_und_section_ptr; - 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 - { - 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. We keep - its visibility. */ - sec = bfd_und_section_ptr; - isym->st_shndx = SHN_UNDEF; - } - else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) - value -= sec->vma; - } - - name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, - isym->st_name); - if (name == NULL) - goto error_free_vers; - - 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 (! bfd_is_und_section (sec)) - h = elf_link_hash_lookup (htab, 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) - goto error_free_sym; - - *sym_hash = h; - - if (is_elf_hash_table (htab)) - { - 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: - if (abfd->selective_search) - continue; - /* Fall-through. */ - 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 (! (_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; - if (definition) - h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; - - /* 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)) - { - /* 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) - { - /* PR binutils/2735 */ - if (normal_bfd == NULL) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: alignment %u of common symbol `%s' in %B" - " is greater than the alignment (%u) of its section %A"), - 1 << common_align, name, common_bfd, - 1 << normal_align, h->root.u.def.section); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: alignment %u of symbol `%s' in %B" - " is smaller than %u in %B"), - 1 << normal_align, name, normal_bfd, - 1 << common_align, common_bfd); - } - } - - /* Remember the symbol size if it isn't undefined. */ - if ((isym->st_size != 0 && isym->st_shndx != SHN_UNDEF) - && (definition || h->size == 0)) - { - if (h->size != 0 - && h->size != isym->st_size - && ! size_change_ok) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: size of symbol `%s' changed" - " from %Lu in %B to %Lu in %B"), - name, h->size, old_bfd, isym->st_size, abfd); - - h->size = isym->st_size; - } - - /* If this is a common symbol, then we always want H->SIZE - to be the size of the common symbol. The code just above - won't fix the size if a common symbol becomes larger. We - don't warn about a size change here, because that is - covered by --warn-common. Allow changed between different - function types. */ - 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)) - { - unsigned int type = ELF_ST_TYPE (isym->st_info); - - if (h->type != type) - { - if (h->type != STT_NOTYPE && ! type_change_ok) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: type of symbol `%s' changed" - " from %d to %d in %B"), - name, h->type, type, abfd); - - h->type = type; - } - } - - /* 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. */ - if (! dynamic) - { - if (! definition) - { - h->ref_regular = 1; - if (bind != STB_WEAK) - h->ref_regular_nonweak = 1; - } - else - { - BFD_ASSERT (!h->def_dynamic); - h->def_regular = 1; - } - } - else - { - BFD_ASSERT (definition); - h->def_dynamic = 1; - h->dynindx = -2; - ((struct elf64_ia64_link_hash_entry *)h)->shl = abfd; - } - } - } - - if (isymbuf != NULL) - { - free (isymbuf); - isymbuf = NULL; - } - - /* 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) - && bed->check_relocs != NULL - && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) - { - 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; - } - } - - return TRUE; - - error_free_vers: - error_free_sym: - if (isymbuf != NULL) - free (isymbuf); - error_return: - return FALSE; -} - -static bfd_boolean -elf64_vms_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) -{ - int pass; - struct bfd_link_hash_entry **pundef; - struct bfd_link_hash_entry **next_pundef; - - /* We only accept VMS libraries. */ - if (info->output_bfd->xvec != abfd->xvec) - { - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - /* The archive_pass field in the archive itself is used to - initialize PASS, since we may search the same archive multiple - times. */ - pass = ++abfd->archive_pass; - - /* Look through the list of undefined symbols. */ - for (pundef = &info->hash->undefs; *pundef != NULL; pundef = next_pundef) - { - struct bfd_link_hash_entry *h; - symindex symidx; - bfd *element; - bfd *orig_element; - - h = *pundef; - next_pundef = &(*pundef)->u.undef.next; - - /* 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. */ - if (*pundef != info->hash->undefs_tail) - { - *pundef = *next_pundef; - next_pundef = pundef; - } - continue; - } - - /* Look for this symbol in the archive hash table. */ - symidx = _bfd_vms_lib_find_symbol (abfd, h->root.string); - if (symidx == BFD_NO_MORE_SYMBOLS) - { - /* Nothing in this slot. */ - continue; - } - - element = bfd_get_elt_at_index (abfd, symidx); - if (element == NULL) - return FALSE; - - if (element->archive_pass == -1 || element->archive_pass == pass) - { - /* Next symbol if this archive is wrong or already handled. */ - continue; - } - - orig_element = element; - if (bfd_is_thin_archive (abfd)) - { - element = _bfd_vms_lib_get_imagelib_file (element); - if (element == NULL || !bfd_check_format (element, bfd_object)) - { - orig_element->archive_pass = -1; - return FALSE; - } - } - else if (! bfd_check_format (element, bfd_object)) - { - element->archive_pass = -1; - return FALSE; - } - - /* Unlike the generic linker, we know that this element provides - a definition for an undefined symbol and we know that we want - to include it. We don't need to check anything. */ - if (! (*info->callbacks->add_archive_element) (info, element, - h->root.string, &element)) - continue; - if (! elf64_vms_link_add_object_symbols (element, info)) - return FALSE; - - orig_element->archive_pass = pass; - } - - return TRUE; -} - -static bfd_boolean -elf64_vms_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) -{ - switch (bfd_get_format (abfd)) - { - case bfd_object: - return elf64_vms_link_add_object_symbols (abfd, info); - break; - case bfd_archive: - return elf64_vms_link_add_archive_symbols (abfd, info); - break; - default: - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } -} - -static bfd_boolean -elf64_ia64_vms_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object - (abfd, sizeof (struct elf64_ia64_vms_obj_tdata), IA64_ELF_DATA); -} - - -/* Size-dependent data and functions. */ -static const struct elf_size_info elf64_ia64_vms_size_info = { - sizeof (Elf64_External_VMS_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_External_Rel), - sizeof (Elf64_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 4, - 1, - 64, 3, /* ARCH_SIZE, LOG_FILE_ALIGN */ - ELFCLASS64, EV_CURRENT, - bfd_elf64_write_out_phdrs, - elf64_vms_write_shdrs_and_ehdr, - bfd_elf64_checksum_contents, - bfd_elf64_write_relocs, - bfd_elf64_swap_symbol_in, - bfd_elf64_swap_symbol_out, - bfd_elf64_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - bfd_elf64_swap_reloc_in, - bfd_elf64_swap_reloc_out, - bfd_elf64_swap_reloca_in, - bfd_elf64_swap_reloca_out -}; - -#define ELF_ARCH bfd_arch_ia64 -#define ELF_MACHINE_CODE EM_IA_64 -#define ELF_MAXPAGESIZE 0x10000 /* 64KB */ -#define ELF_COMMONPAGESIZE 0x200 /* 16KB */ - -#define elf_backend_section_from_shdr \ - elf64_ia64_section_from_shdr -#define elf_backend_section_flags \ - elf64_ia64_section_flags -#define elf_backend_fake_sections \ - elf64_ia64_fake_sections -#define elf_backend_final_write_processing \ - elf64_ia64_final_write_processing -#define elf_backend_add_symbol_hook \ - elf64_ia64_add_symbol_hook -#define elf_info_to_howto \ - elf64_ia64_info_to_howto - -#define bfd_elf64_bfd_reloc_type_lookup \ - ia64_elf_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup \ - ia64_elf_reloc_name_lookup -#define bfd_elf64_bfd_is_local_label_name \ - elf64_ia64_is_local_label_name -#define bfd_elf64_bfd_relax_section \ - elf64_ia64_relax_section - -#define elf_backend_object_p \ - elf64_ia64_object_p - -/* Stuff for the BFD linker: */ -#define bfd_elf64_bfd_link_hash_table_create \ - elf64_ia64_hash_table_create -#define elf_backend_create_dynamic_sections \ - elf64_ia64_create_dynamic_sections -#define elf_backend_check_relocs \ - elf64_ia64_check_relocs -#define elf_backend_adjust_dynamic_symbol \ - elf64_ia64_adjust_dynamic_symbol -#define elf_backend_size_dynamic_sections \ - elf64_ia64_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_relocate_section \ - elf64_ia64_relocate_section -#define elf_backend_finish_dynamic_symbol \ - elf64_ia64_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf64_ia64_finish_dynamic_sections -#define bfd_elf64_bfd_final_link \ - elf64_ia64_final_link - -#define bfd_elf64_bfd_merge_private_bfd_data \ - elf64_ia64_merge_private_bfd_data -#define bfd_elf64_bfd_set_private_flags \ - elf64_ia64_set_private_flags -#define bfd_elf64_bfd_print_private_bfd_data \ - elf64_ia64_print_private_bfd_data - -#define elf_backend_plt_readonly 1 -#define elf_backend_want_plt_sym 0 -#define elf_backend_plt_alignment 5 -#define elf_backend_got_header_size 0 -#define elf_backend_want_got_plt 1 -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_default_use_rela_p 1 -#define elf_backend_want_dynbss 0 -#define elf_backend_hide_symbol elf64_ia64_hash_hide_symbol -#define elf_backend_fixup_symbol _bfd_elf_link_hash_fixup_symbol -#define elf_backend_reloc_type_class elf64_ia64_reloc_type_class -#define elf_backend_rela_normal 1 -#define elf_backend_special_sections elf64_ia64_special_sections -#define elf_backend_default_execstack 0 - -/* FIXME: 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. - We don't want to flood users with so many error messages. We turn - off the warning for now. It will be turned on later when the Intel - compiler is fixed. */ -#define elf_backend_link_order_error_handler NULL - -/* VMS-specific vectors. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM ia64_elf64_vms_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-ia64-vms" -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -/* These are VMS specific functions. */ - -#undef elf_backend_object_p -#define elf_backend_object_p elf64_vms_object_p - -#undef elf_backend_section_from_shdr -#define elf_backend_section_from_shdr elf64_vms_section_from_shdr - -#undef elf_backend_post_process_headers -#define elf_backend_post_process_headers elf64_vms_post_process_headers - -#undef elf_backend_section_processing -#define elf_backend_section_processing elf64_vms_section_processing - -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing elf64_vms_final_write_processing - -#undef bfd_elf64_close_and_cleanup -#define bfd_elf64_close_and_cleanup elf64_vms_close_and_cleanup - -#undef elf_backend_section_from_bfd_section - -#undef elf_backend_symbol_processing - -#undef elf_backend_want_p_paddr_set_to_zero - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_OPENVMS - -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x10000 /* 64KB */ - -#undef elf64_bed -#define elf64_bed elf64_ia64_vms_bed - -#define elf_backend_size_info elf64_ia64_vms_size_info - -/* Use VMS-style archives (in particular, don't use the standard coff - archive format). */ -#define bfd_elf64_archive_functions - -#undef bfd_elf64_archive_p -#define bfd_elf64_archive_p _bfd_vms_lib_ia64_archive_p -#undef bfd_elf64_write_archive_contents -#define bfd_elf64_write_archive_contents _bfd_vms_lib_write_archive_contents -#undef bfd_elf64_mkarchive -#define bfd_elf64_mkarchive _bfd_vms_lib_ia64_mkarchive - -#define bfd_elf64_archive_slurp_armap \ - _bfd_vms_lib_slurp_armap -#define bfd_elf64_archive_slurp_extended_name_table \ - _bfd_vms_lib_slurp_extended_name_table -#define bfd_elf64_archive_construct_extended_name_table \ - _bfd_vms_lib_construct_extended_name_table -#define bfd_elf64_archive_truncate_arname \ - _bfd_vms_lib_truncate_arname -#define bfd_elf64_archive_write_armap \ - _bfd_vms_lib_write_armap -#define bfd_elf64_archive_read_ar_hdr \ - _bfd_vms_lib_read_ar_hdr -#define bfd_elf64_archive_write_ar_hdr \ - _bfd_vms_lib_write_ar_hdr -#define bfd_elf64_archive_openr_next_archived_file \ - _bfd_vms_lib_openr_next_archived_file -#define bfd_elf64_archive_get_elt_at_index \ - _bfd_vms_lib_get_elt_at_index -#define bfd_elf64_archive_generic_stat_arch_elt \ - _bfd_vms_lib_generic_stat_arch_elt -#define bfd_elf64_archive_update_armap_timestamp \ - _bfd_vms_lib_update_armap_timestamp - -/* VMS link methods. */ -#undef bfd_elf64_bfd_link_add_symbols -#define bfd_elf64_bfd_link_add_symbols elf64_vms_bfd_link_add_symbols - -#undef elf_backend_want_got_sym -#define elf_backend_want_got_sym 0 - -#undef bfd_elf64_mkobject -#define bfd_elf64_mkobject elf64_ia64_vms_mkobject - -/* Redefine to align segments on block size. */ -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x200 /* 512B */ - -#undef elf_backend_want_got_plt -#define elf_backend_want_got_plt 0 - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-mips.c b/sdcc/support/sdbinutils/bfd/elf64-mips.c deleted file mode 100644 index 82186252f..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-mips.c +++ /dev/null @@ -1,4525 +0,0 @@ -/* MIPS-specific support for 64-bit ELF - Copyright (C) 1996-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 ABI. - - The MIPS 64-bit ELF ABI uses an unusual reloc format. This file - overrides the usual ELF reloc handling, and handles reading and - writing the relocations here. */ - -/* TODO: Many things are unsupported, even if there is some code for it - . (which was mostly stolen from elf32-mips.c and slightly adapted). - . - . - Relocation handling for REL relocs is wrong in many cases and - . generally untested. - . - Relocation handling for RELA relocs related to GOT support are - . also likely to be wrong. - . - Support for MIPS16 is untested. - . - Combined relocs with RSS_* entries are unsupported. - . - The whole GOT handling for NewABI is missing, some parts of - . the OldABI version is still lying around and should be removed. - */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "aout/ar.h" -#include "bfdlink.h" -#include "genlink.h" -#include "elf-bfd.h" -#include "elfxx-mips.h" -#include "elf/mips.h" - -/* Get the ECOFF swapping routines. The 64-bit ABI is not supposed to - use ECOFF. However, we support it anyhow for an easier changeover. */ -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/internal.h" -#include "coff/ecoff.h" -/* The 64 bit versions of the mdebug data structures are in alpha.h. */ -#include "coff/alpha.h" -#define ECOFF_SIGNED_64 -#include "ecoffswap.h" - -static void mips_elf64_swap_reloc_in - (bfd *, const Elf64_Mips_External_Rel *, Elf64_Mips_Internal_Rela *); -static void mips_elf64_swap_reloca_in - (bfd *, const Elf64_Mips_External_Rela *, Elf64_Mips_Internal_Rela *); -static void mips_elf64_swap_reloc_out - (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rel *); -static void mips_elf64_swap_reloca_out - (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rela *); -static void mips_elf64_be_swap_reloc_in - (bfd *, const bfd_byte *, Elf_Internal_Rela *); -static void mips_elf64_be_swap_reloc_out - (bfd *, const Elf_Internal_Rela *, bfd_byte *); -static void mips_elf64_be_swap_reloca_in - (bfd *, const bfd_byte *, Elf_Internal_Rela *); -static void mips_elf64_be_swap_reloca_out - (bfd *, const Elf_Internal_Rela *, bfd_byte *); -static reloc_howto_type *bfd_elf64_bfd_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static reloc_howto_type *mips_elf64_rtype_to_howto - (unsigned int, bfd_boolean); -static void mips_elf64_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); -static void mips_elf64_info_to_howto_rela - (bfd *, arelent *, Elf_Internal_Rela *); -static long mips_elf64_get_dynamic_reloc_upper_bound - (bfd *); -static bfd_boolean mips_elf64_slurp_one_reloc_table - (bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type, arelent *, - asymbol **, bfd_boolean); -static bfd_boolean mips_elf64_slurp_reloc_table - (bfd *, asection *, asymbol **, bfd_boolean); -static void mips_elf64_write_relocs - (bfd *, asection *, void *); -static void mips_elf64_write_rel - (bfd *, asection *, Elf_Internal_Shdr *, int *, void *); -static void mips_elf64_write_rela - (bfd *, asection *, Elf_Internal_Shdr *, int *, void *); -static bfd_reloc_status_type mips_elf64_gprel16_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips_elf64_literal_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips_elf64_gprel32_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips_elf64_shift6_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips16_gprel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_boolean mips_elf64_assign_gp - (bfd *, bfd_vma *); -static bfd_reloc_status_type mips_elf64_final_gp - (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *); -static bfd_boolean mips_elf64_object_p - (bfd *); -static irix_compat_t elf64_mips_irix_compat - (bfd *); -static bfd_boolean elf64_mips_grok_prstatus - (bfd *, Elf_Internal_Note *); -static bfd_boolean elf64_mips_grok_psinfo - (bfd *, Elf_Internal_Note *); - -extern const bfd_target mips_elf64_be_vec; -extern const bfd_target mips_elf64_le_vec; - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -/* The number of local .got entries we reserve. */ -#define MIPS_RESERVED_GOTNO (2) - -/* The relocation table used for SHT_REL sections. */ - -static reloc_howto_type mips_elf64_howto_table_rel[] = -{ - /* No relocation. */ - HOWTO (R_MIPS_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit relocation. */ - HOWTO (R_MIPS_16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation. */ - HOWTO (R_MIPS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_MIPS_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 26 bit jump address. */ - HOWTO (R_MIPS_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper 36 - bits must match the PC + 4. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_26", /* name */ - TRUE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_MIPS_HI16 and R_MIPS_LO16 are unsupported for NewABI REL. - However, the native IRIX6 tools use them, so we try our best. */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf64_gprel16_reloc, /* special_function */ - "R_MIPS_GPREL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf64_literal_reloc, /* special_function */ - "R_MIPS_LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative reference. Note that the ABI document has a typo - and claims R_MIPS_PC16 to be not rightshifted, rendering it useless. - We do the right thing here. */ - HOWTO (R_MIPS_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_MIPS_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips_elf64_gprel32_reloc, /* special_function */ - "R_MIPS_GPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - - /* A 5 bit shift field. */ - HOWTO (R_MIPS_SHIFT5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SHIFT5", /* name */ - TRUE, /* partial_inplace */ - 0x000007c0, /* src_mask */ - 0x000007c0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 6 bit shift field. */ - HOWTO (R_MIPS_SHIFT6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf64_shift6_reloc, /* special_function */ - "R_MIPS_SHIFT6", /* name */ - TRUE, /* partial_inplace */ - 0x000007c4, /* src_mask */ - 0x000007c4, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit relocation. */ - HOWTO (R_MIPS_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement in the global offset table. */ - HOWTO (R_MIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_DISP", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_PAGE", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_OFST", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. */ - HOWTO (R_MIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SUB", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_A, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_A", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction, and change all relocations - to refer to the old instruction at the address. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_B", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Delete a 32 bit instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_DELETE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_DELETE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The MIPS ELF64 ABI Draft wants us to support these for REL relocations. - We don't, because - a) It means building the addend from a R_MIPS_HIGHEST/R_MIPS_HIGHER/ - R_MIPS_HI16/R_MIPS_LO16 sequence with varying ordering, using - fallable heuristics. - b) No other NewABI toolchain actually emits such relocations. */ - EMPTY_HOWTO (R_MIPS_HIGHER), - EMPTY_HOWTO (R_MIPS_HIGHEST), - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement, used by an associated event location section. */ - HOWTO (R_MIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SCN_DISP", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* These two are obsolete. */ - EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE), - EMPTY_HOWTO (R_MIPS_PJUMP), - - /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section. - It must be used for multigot GOT's (and only there). */ - HOWTO (R_MIPS_RELGOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_RELGOT", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS relocations. */ - EMPTY_HOWTO (R_MIPS_TLS_DTPMOD32), - EMPTY_HOWTO (R_MIPS_TLS_DTPREL32), - - HOWTO (R_MIPS_TLS_DTPMOD64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPMOD64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_TLS_DTPREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS general dynamic variable reference. */ - HOWTO (R_MIPS_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_MIPS_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS IE dynamic relocations. */ - EMPTY_HOWTO (R_MIPS_TLS_TPREL32), - - HOWTO (R_MIPS_TLS_TPREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation with no addend. */ - HOWTO (R_MIPS_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - - HOWTO (R_MIPS_PC21_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC21_S2", /* name */ - TRUE, /* partial_inplace */ - 0x001fffff, /* src_mask */ - 0x001fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC26_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC26_S2", /* name */ - TRUE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC18_S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC18_S3", /* name */ - TRUE, /* partial_inplace */ - 0x0003ffff, /* src_mask */ - 0x0003ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC19_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC19_S2", /* name */ - TRUE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCHI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCHI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCLO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCLO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - -}; - -/* The relocation table used for SHT_RELA sections. */ - -static reloc_howto_type mips_elf64_howto_table_rela[] = -{ - /* No relocation. */ - HOWTO (R_MIPS_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit relocation. */ - HOWTO (R_MIPS_16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation. */ - HOWTO (R_MIPS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_MIPS_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 26 bit jump address. */ - HOWTO (R_MIPS_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper 36 - bits must match the PC + 4. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_26", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MIPS_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf64_gprel16_reloc, /* special_function */ - "R_MIPS_GPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf64_literal_reloc, /* special_function */ - "R_MIPS_LITERAL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative reference. Note that the ABI document has a typo - and claims R_MIPS_PC16 to be not rightshifted, rendering it useless. - We do the right thing here. */ - HOWTO (R_MIPS_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_MIPS_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips_elf64_gprel32_reloc, /* special_function */ - "R_MIPS_GPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - - /* A 5 bit shift field. */ - HOWTO (R_MIPS_SHIFT5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SHIFT5", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000007c0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 6 bit shift field. */ - HOWTO (R_MIPS_SHIFT6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf64_shift6_reloc, /* special_function */ - "R_MIPS_SHIFT6", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000007c4, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit relocation. */ - HOWTO (R_MIPS_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement in the global offset table. */ - HOWTO (R_MIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_DISP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_PAGE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_OFST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. */ - HOWTO (R_MIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SUB", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_A, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction, and change all relocations - to refer to the old instruction at the address. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_B", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Delete a 32 bit instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_DELETE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_DELETE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the higher value of a 64 bit addend. */ - HOWTO (R_MIPS_HIGHER, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the highest value of a 64 bit addend. */ - HOWTO (R_MIPS_HIGHEST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement, used by an associated event location section. */ - HOWTO (R_MIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SCN_DISP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* These two are obsolete. */ - EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE), - EMPTY_HOWTO (R_MIPS_PJUMP), - - /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section. - It must be used for multigot GOT's (and only there). */ - HOWTO (R_MIPS_RELGOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_RELGOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS relocations. */ - EMPTY_HOWTO (R_MIPS_TLS_DTPMOD32), - EMPTY_HOWTO (R_MIPS_TLS_DTPREL32), - - HOWTO (R_MIPS_TLS_DTPMOD64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPMOD64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_TLS_DTPREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS general dynamic variable reference. */ - HOWTO (R_MIPS_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_MIPS_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_LDM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GOTTPREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS IE dynamic relocations. */ - EMPTY_HOWTO (R_MIPS_TLS_TPREL32), - - HOWTO (R_MIPS_TLS_TPREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation with no addend. */ - HOWTO (R_MIPS_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - - HOWTO (R_MIPS_PC21_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC21_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x001fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC26_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC26_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC18_S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC18_S3", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0003ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC19_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC19_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCHI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCLO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCLO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - -}; - -static reloc_howto_type mips16_elf64_howto_table_rel[] = -{ - /* The reloc used for the mips16 jump instruction. */ - HOWTO (R_MIPS16_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_26", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The reloc used for the mips16 gprel instruction. */ - HOWTO (R_MIPS16_GPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips16_gprel_reloc, /* special_function */ - "R_MIPS16_GPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 reference to the global offset table. */ - HOWTO (R_MIPS16_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS16_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 call through the global offset table. */ - HOWTO (R_MIPS16_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 high 16 bits of symbol value. */ - HOWTO (R_MIPS16_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS16_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 low 16 bits of symbol value. */ - HOWTO (R_MIPS16_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS16_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS general dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 16-bit PC-relative branch offset. */ - HOWTO (R_MIPS16_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_PC16_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -static reloc_howto_type mips16_elf64_howto_table_rela[] = -{ - /* The reloc used for the mips16 jump instruction. */ - HOWTO (R_MIPS16_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_26", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The reloc used for the mips16 gprel instruction. */ - HOWTO (R_MIPS16_GPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips16_gprel_reloc, /* special_function */ - "R_MIPS16_GPREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 reference to the global offset table. */ - HOWTO (R_MIPS16_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS16_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 call through the global offset table. */ - HOWTO (R_MIPS16_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_CALL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 high 16 bits of symbol value. */ - HOWTO (R_MIPS16_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS16_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 low 16 bits of symbol value. */ - HOWTO (R_MIPS16_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS16_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS general dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_LDM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GOTTPREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 16-bit PC-relative branch offset. */ - HOWTO (R_MIPS16_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_PC16_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -static reloc_howto_type micromips_elf64_howto_table_rel[] = -{ - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - - /* 26 bit jump address. */ - HOWTO (R_MICROMIPS_26_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_26_S1", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MICROMIPS_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MICROMIPS_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MICROMIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_GPREL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MICROMIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MICROMIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MICROMIPS_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is for microMIPS branches. */ - HOWTO (R_MICROMIPS_PC7_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC7_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000007f, /* src_mask */ - 0x0000007f, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC10_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC10_S1", /* name */ - TRUE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC16_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MICROMIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - - /* Displacement in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_DISP",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_PAGE",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_OFST",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_HI16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. Used in the N32 ABI. */ - HOWTO (R_MICROMIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SUB", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* We don't support these for REL relocations, because it means building - the addend from a R_MICROMIPS_HIGHEST/R_MICROMIPS_HIGHER/ - R_MICROMIPS_HI16/R_MICROMIPS_LO16 sequence with varying ordering, - using fallable heuristics. */ - EMPTY_HOWTO (R_MICROMIPS_HIGHER), - EMPTY_HOWTO (R_MICROMIPS_HIGHEST), - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_HI16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MICROMIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SCN_DISP", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MICROMIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static reloc_howto_type micromips_elf64_howto_table_rela[] = -{ - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - - /* 26 bit jump address. */ - HOWTO (R_MICROMIPS_26_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_26_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MICROMIPS_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MICROMIPS_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MICROMIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_GPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MICROMIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_LITERAL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MICROMIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MICROMIPS_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is for microMIPS branches. */ - HOWTO (R_MICROMIPS_PC7_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC7_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000007f, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC10_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC10_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000003ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC16_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MICROMIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - - /* Displacement in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_DISP",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_PAGE",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_OFST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_HI16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_LO16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. Used in the N32 ABI. */ - HOWTO (R_MICROMIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SUB", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the higher value of a 64 bit addend. */ - HOWTO (R_MICROMIPS_HIGHER, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the highest value of a 64 bit addend. */ - HOWTO (R_MICROMIPS_HIGHEST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_HI16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_LO16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MICROMIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SCN_DISP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MICROMIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* GNU extension to record C++ vtable hierarchy */ -static reloc_howto_type elf_mips_gnu_vtinherit_howto = - HOWTO (R_MIPS_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_MIPS_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* GNU extension to record C++ vtable member usage */ -static reloc_howto_type elf_mips_gnu_vtentry_howto = - HOWTO (R_MIPS_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_MIPS_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* 16 bit offset for pc-relative branches. */ -static reloc_howto_type elf_mips_gnu_rel16_s2 = - HOWTO (R_MIPS_GNU_REL16_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GNU_REL16_S2", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - -/* 16 bit offset for pc-relative branches. */ -static reloc_howto_type elf_mips_gnu_rela16_s2 = - HOWTO (R_MIPS_GNU_REL16_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GNU_REL16_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - -/* 32 bit pc-relative. Used for compact EH tables. */ -static reloc_howto_type elf_mips_gnu_pcrel32 = - HOWTO (R_MIPS_PC32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - - -/* Originally a VxWorks extension, but now used for other systems too. */ -static reloc_howto_type elf_mips_copy_howto = - HOWTO (R_MIPS_COPY, /* type */ - 0, /* rightshift */ - 0, /* this one is variable size */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_COPY", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Originally a VxWorks extension, but now used for other systems too. */ -static reloc_howto_type elf_mips_jump_slot_howto = - HOWTO (R_MIPS_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JUMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Used in EH tables. */ -static reloc_howto_type elf_mips_eh_howto = - HOWTO (R_MIPS_EH, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_EH", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - - -/* Swap in a MIPS 64-bit Rel reloc. */ - -static void -mips_elf64_swap_reloc_in (bfd *abfd, const Elf64_Mips_External_Rel *src, - Elf64_Mips_Internal_Rela *dst) -{ - dst->r_offset = H_GET_64 (abfd, src->r_offset); - dst->r_sym = H_GET_32 (abfd, src->r_sym); - dst->r_ssym = H_GET_8 (abfd, src->r_ssym); - dst->r_type3 = H_GET_8 (abfd, src->r_type3); - dst->r_type2 = H_GET_8 (abfd, src->r_type2); - dst->r_type = H_GET_8 (abfd, src->r_type); - dst->r_addend = 0; -} - -/* Swap in a MIPS 64-bit Rela reloc. */ - -static void -mips_elf64_swap_reloca_in (bfd *abfd, const Elf64_Mips_External_Rela *src, - Elf64_Mips_Internal_Rela *dst) -{ - dst->r_offset = H_GET_64 (abfd, src->r_offset); - dst->r_sym = H_GET_32 (abfd, src->r_sym); - dst->r_ssym = H_GET_8 (abfd, src->r_ssym); - dst->r_type3 = H_GET_8 (abfd, src->r_type3); - dst->r_type2 = H_GET_8 (abfd, src->r_type2); - dst->r_type = H_GET_8 (abfd, src->r_type); - dst->r_addend = H_GET_S64 (abfd, src->r_addend); -} - -/* Swap out a MIPS 64-bit Rel reloc. */ - -static void -mips_elf64_swap_reloc_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src, - Elf64_Mips_External_Rel *dst) -{ - H_PUT_64 (abfd, src->r_offset, dst->r_offset); - H_PUT_32 (abfd, src->r_sym, dst->r_sym); - H_PUT_8 (abfd, src->r_ssym, dst->r_ssym); - H_PUT_8 (abfd, src->r_type3, dst->r_type3); - H_PUT_8 (abfd, src->r_type2, dst->r_type2); - H_PUT_8 (abfd, src->r_type, dst->r_type); -} - -/* Swap out a MIPS 64-bit Rela reloc. */ - -static void -mips_elf64_swap_reloca_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src, - Elf64_Mips_External_Rela *dst) -{ - H_PUT_64 (abfd, src->r_offset, dst->r_offset); - H_PUT_32 (abfd, src->r_sym, dst->r_sym); - H_PUT_8 (abfd, src->r_ssym, dst->r_ssym); - H_PUT_8 (abfd, src->r_type3, dst->r_type3); - H_PUT_8 (abfd, src->r_type2, dst->r_type2); - H_PUT_8 (abfd, src->r_type, dst->r_type); - H_PUT_S64 (abfd, src->r_addend, dst->r_addend); -} - -/* Swap in a MIPS 64-bit Rel reloc. */ - -static void -mips_elf64_be_swap_reloc_in (bfd *abfd, const bfd_byte *src, - Elf_Internal_Rela *dst) -{ - Elf64_Mips_Internal_Rela mirel; - - mips_elf64_swap_reloc_in (abfd, - (const Elf64_Mips_External_Rel *) src, - &mirel); - - dst[0].r_offset = mirel.r_offset; - dst[0].r_info = ELF64_R_INFO (mirel.r_sym, mirel.r_type); - dst[0].r_addend = 0; - dst[1].r_offset = mirel.r_offset; - dst[1].r_info = ELF64_R_INFO (mirel.r_ssym, mirel.r_type2); - dst[1].r_addend = 0; - dst[2].r_offset = mirel.r_offset; - dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirel.r_type3); - dst[2].r_addend = 0; -} - -/* Swap in a MIPS 64-bit Rela reloc. */ - -static void -mips_elf64_be_swap_reloca_in (bfd *abfd, const bfd_byte *src, - Elf_Internal_Rela *dst) -{ - Elf64_Mips_Internal_Rela mirela; - - mips_elf64_swap_reloca_in (abfd, - (const Elf64_Mips_External_Rela *) src, - &mirela); - - dst[0].r_offset = mirela.r_offset; - dst[0].r_info = ELF64_R_INFO (mirela.r_sym, mirela.r_type); - dst[0].r_addend = mirela.r_addend; - dst[1].r_offset = mirela.r_offset; - dst[1].r_info = ELF64_R_INFO (mirela.r_ssym, mirela.r_type2); - dst[1].r_addend = 0; - dst[2].r_offset = mirela.r_offset; - dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirela.r_type3); - dst[2].r_addend = 0; -} - -/* Swap out a MIPS 64-bit Rel reloc. */ - -static void -mips_elf64_be_swap_reloc_out (bfd *abfd, const Elf_Internal_Rela *src, - bfd_byte *dst) -{ - Elf64_Mips_Internal_Rela mirel; - - mirel.r_offset = src[0].r_offset; - BFD_ASSERT(src[0].r_offset == src[1].r_offset); - BFD_ASSERT(src[0].r_offset == src[2].r_offset); - - mirel.r_type = ELF64_MIPS_R_TYPE (src[0].r_info); - mirel.r_sym = ELF64_R_SYM (src[0].r_info); - mirel.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info); - mirel.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info); - mirel.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info); - - mips_elf64_swap_reloc_out (abfd, &mirel, - (Elf64_Mips_External_Rel *) dst); -} - -/* Swap out a MIPS 64-bit Rela reloc. */ - -static void -mips_elf64_be_swap_reloca_out (bfd *abfd, const Elf_Internal_Rela *src, - bfd_byte *dst) -{ - Elf64_Mips_Internal_Rela mirela; - - mirela.r_offset = src[0].r_offset; - BFD_ASSERT(src[0].r_offset == src[1].r_offset); - BFD_ASSERT(src[0].r_offset == src[2].r_offset); - - mirela.r_type = ELF64_MIPS_R_TYPE (src[0].r_info); - mirela.r_sym = ELF64_R_SYM (src[0].r_info); - mirela.r_addend = src[0].r_addend; - BFD_ASSERT(src[1].r_addend == 0); - BFD_ASSERT(src[2].r_addend == 0); - - mirela.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info); - mirela.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info); - mirela.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info); - - mips_elf64_swap_reloca_out (abfd, &mirela, - (Elf64_Mips_External_Rela *) dst); -} - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ - -static bfd_boolean -mips_elf64_assign_gp (bfd *output_bfd, bfd_vma *pgp) -{ - unsigned int count; - asymbol **sym; - unsigned int i; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - /* The linker script will have created a symbol named `_gp' with the - appropriate value. */ - if (sym == NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - register const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - *pgp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, *pgp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - return TRUE; -} - -/* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static bfd_reloc_status_type -mips_elf64_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, - char **error_message, bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) - && ! relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 - && (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma /*+ 0x4000*/; - _bfd_set_gp_value (output_bfd, *pgp); - } - else if (!mips_elf64_assign_gp (output_bfd, pgp)) - { - *error_message = - (char *) _("GP relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -mips_elf64_gprel16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* If we're relocating, and this is an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); -} - -/* Do a R_MIPS_LITERAL relocation. */ - -static bfd_reloc_status_type -mips_elf64_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* R_MIPS_LITERAL relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("literal relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - /* FIXME: The entries in the .lit8 and .lit4 sections should be merged. */ - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); -} - -/* Do a R_MIPS_GPREL32 relocation. This is a 32 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -mips_elf64_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - bfd_vma relocation; - bfd_vma val; - - /* R_MIPS_GPREL32 relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("32bits gp relative relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, - error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - /* Set val to the offset into the section or symbol. */ - val = reloc_entry->addend; - - if (reloc_entry->howto->partial_inplace) - val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - - /* Adjust val for the final section location and GP value. If we - are producing relocatable output, we don't want to do this for - an external symbol. */ - if (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0) - val += relocation - gp; - - if (reloc_entry->howto->partial_inplace) - bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); - else - reloc_entry->addend = val; - - if (relocatable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -/* Do a R_MIPS_SHIFT6 relocation. The MSB of the shift is stored at bit 2, - the rest is at bits 6-10. The bitpos already got right by the howto. */ - -static bfd_reloc_status_type -mips_elf64_shift6_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - if (reloc_entry->howto->partial_inplace) - { - reloc_entry->addend = ((reloc_entry->addend & 0x00007c0) - | (reloc_entry->addend & 0x00000800) >> 9); - } - - return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, - error_message); -} - -/* Handle a mips16 GP relative reloc. */ - -static bfd_reloc_status_type -mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_byte *location; - bfd_vma gp; - - /* If we're relocating, and this is an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - location = (bfd_byte *) data + reloc_entry->address; - _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE, - location); - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); - _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, !relocatable, - location); - - return ret; -} - -/* A mapping from BFD reloc types to MIPS ELF reloc types. */ - -struct elf_reloc_map { - bfd_reloc_code_real_type bfd_val; - enum elf_mips_reloc_type elf_val; -}; - -static const struct elf_reloc_map mips_reloc_map[] = -{ - { BFD_RELOC_NONE, R_MIPS_NONE }, - { BFD_RELOC_16, R_MIPS_16 }, - { BFD_RELOC_32, R_MIPS_32 }, - /* There is no BFD reloc for R_MIPS_REL32. */ - { BFD_RELOC_64, R_MIPS_64 }, - { BFD_RELOC_CTOR, R_MIPS_64 }, - { BFD_RELOC_16_PCREL_S2, R_MIPS_PC16 }, - { BFD_RELOC_HI16_S, R_MIPS_HI16 }, - { BFD_RELOC_LO16, R_MIPS_LO16 }, - { BFD_RELOC_GPREL16, R_MIPS_GPREL16 }, - { BFD_RELOC_GPREL32, R_MIPS_GPREL32 }, - { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, - { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, - { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, - { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, - { BFD_RELOC_MIPS_SHIFT5, R_MIPS_SHIFT5 }, - { BFD_RELOC_MIPS_SHIFT6, R_MIPS_SHIFT6 }, - { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP }, - { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE }, - { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST }, - { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 }, - { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 }, - { BFD_RELOC_MIPS_SUB, R_MIPS_SUB }, - { BFD_RELOC_MIPS_INSERT_A, R_MIPS_INSERT_A }, - { BFD_RELOC_MIPS_INSERT_B, R_MIPS_INSERT_B }, - { BFD_RELOC_MIPS_DELETE, R_MIPS_DELETE }, - { BFD_RELOC_MIPS_HIGHEST, R_MIPS_HIGHEST }, - { BFD_RELOC_MIPS_HIGHER, R_MIPS_HIGHER }, - { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 }, - { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 }, - { BFD_RELOC_MIPS_SCN_DISP, R_MIPS_SCN_DISP }, - { BFD_RELOC_MIPS_REL16, R_MIPS_REL16 }, - /* Use of R_MIPS_ADD_IMMEDIATE and R_MIPS_PJUMP is deprecated. */ - { BFD_RELOC_MIPS_RELGOT, R_MIPS_RELGOT }, - { BFD_RELOC_MIPS_JALR, R_MIPS_JALR }, - { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 }, - { BFD_RELOC_MIPS_TLS_DTPREL32, R_MIPS_TLS_DTPREL32 }, - { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 }, - { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 }, - { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD }, - { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM }, - { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 }, - { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL }, - { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, - { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, - { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }, - { BFD_RELOC_MIPS_21_PCREL_S2, R_MIPS_PC21_S2 }, - { BFD_RELOC_MIPS_26_PCREL_S2, R_MIPS_PC26_S2 }, - { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 }, - { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 }, - { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 }, - { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 } -}; - -static const struct elf_reloc_map mips16_reloc_map[] = -{ - { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min }, - { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_GD, R_MIPS16_TLS_GD - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_LDM, R_MIPS16_TLS_LDM - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_DTPREL_HI16, - R_MIPS16_TLS_DTPREL_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_DTPREL_LO16, - R_MIPS16_TLS_DTPREL_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_GOTTPREL, R_MIPS16_TLS_GOTTPREL - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_TPREL_HI16, R_MIPS16_TLS_TPREL_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_TPREL_LO16, R_MIPS16_TLS_TPREL_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_16_PCREL_S1, R_MIPS16_PC16_S1 - R_MIPS16_min } -}; - -static const struct elf_reloc_map micromips_reloc_map[] = -{ - { BFD_RELOC_MICROMIPS_JMP, R_MICROMIPS_26_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HI16_S, R_MICROMIPS_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_LO16, R_MICROMIPS_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GPREL16, R_MICROMIPS_GPREL16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_LITERAL, R_MICROMIPS_LITERAL - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT16, R_MICROMIPS_GOT16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_7_PCREL_S1, R_MICROMIPS_PC7_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_10_PCREL_S1, R_MICROMIPS_PC10_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_16_PCREL_S1, R_MICROMIPS_PC16_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL16, R_MICROMIPS_CALL16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_DISP, R_MICROMIPS_GOT_DISP - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_PAGE - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_OFST, R_MICROMIPS_GOT_OFST - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_LO16, R_MICROMIPS_GOT_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_SUB, R_MICROMIPS_SUB - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HIGHER, R_MICROMIPS_HIGHER - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HIGHEST, R_MICROMIPS_HIGHEST - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL_HI16, R_MICROMIPS_CALL_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL_LO16, R_MICROMIPS_CALL_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_SCN_DISP, R_MICROMIPS_SCN_DISP - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_JALR, R_MICROMIPS_JALR - R_MICROMIPS_min }, -}; -/* Given a BFD reloc type, return a howto structure. */ - -static reloc_howto_type * -bfd_elf64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - /* FIXME: We default to RELA here instead of choosing the right - relocation variant. */ - reloc_howto_type *howto_table = mips_elf64_howto_table_rela; - reloc_howto_type *howto16_table = mips16_elf64_howto_table_rela; - reloc_howto_type *howto_micromips_table = micromips_elf64_howto_table_rela; - - for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (mips_reloc_map[i].bfd_val == code) - return &howto_table[(int) mips_reloc_map[i].elf_val]; - } - - for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (mips16_reloc_map[i].bfd_val == code) - return &howto16_table[(int) mips16_reloc_map[i].elf_val]; - } - - for (i = 0; i < sizeof (micromips_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (micromips_reloc_map[i].bfd_val == code) - return &howto_micromips_table[(int) micromips_reloc_map[i].elf_val]; - } - - switch (code) - { - case BFD_RELOC_VTABLE_INHERIT: - return &elf_mips_gnu_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &elf_mips_gnu_vtentry_howto; - case BFD_RELOC_32_PCREL: - return &elf_mips_gnu_pcrel32; - case BFD_RELOC_MIPS_EH: - return &elf_mips_eh_howto; - case BFD_RELOC_MIPS_COPY: - return &elf_mips_copy_howto; - case BFD_RELOC_MIPS_JUMP_SLOT: - return &elf_mips_jump_slot_howto; - default: - bfd_set_error (bfd_error_bad_value); - return NULL; - } -} - -static reloc_howto_type * -bfd_elf64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (mips_elf64_howto_table_rela) - / sizeof (mips_elf64_howto_table_rela[0])); i++) - if (mips_elf64_howto_table_rela[i].name != NULL - && strcasecmp (mips_elf64_howto_table_rela[i].name, r_name) == 0) - return &mips_elf64_howto_table_rela[i]; - - for (i = 0; - i < (sizeof (mips16_elf64_howto_table_rela) - / sizeof (mips16_elf64_howto_table_rela[0])); - i++) - if (mips16_elf64_howto_table_rela[i].name != NULL - && strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0) - return &mips16_elf64_howto_table_rela[i]; - - for (i = 0; - i < (sizeof (micromips_elf64_howto_table_rela) - / sizeof (micromips_elf64_howto_table_rela[0])); - i++) - if (micromips_elf64_howto_table_rela[i].name != NULL - && strcasecmp (micromips_elf64_howto_table_rela[i].name, r_name) == 0) - return µmips_elf64_howto_table_rela[i]; - - if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0) - return &elf_mips_gnu_vtinherit_howto; - if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0) - return &elf_mips_gnu_vtentry_howto; - if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0) - return &elf_mips_gnu_rel16_s2; - if (strcasecmp (elf_mips_gnu_rela16_s2.name, r_name) == 0) - return &elf_mips_gnu_rela16_s2; - if (strcasecmp (elf_mips_gnu_pcrel32.name, r_name) == 0) - return &elf_mips_gnu_pcrel32; - if (strcasecmp (elf_mips_eh_howto.name, r_name) == 0) - return &elf_mips_eh_howto; - if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0) - return &elf_mips_copy_howto; - if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0) - return &elf_mips_jump_slot_howto; - - return NULL; -} - -/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure. */ - -static reloc_howto_type * -mips_elf64_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p) -{ - switch (r_type) - { - case R_MIPS_GNU_VTINHERIT: - return &elf_mips_gnu_vtinherit_howto; - case R_MIPS_GNU_VTENTRY: - return &elf_mips_gnu_vtentry_howto; - case R_MIPS_GNU_REL16_S2: - if (rela_p) - return &elf_mips_gnu_rela16_s2; - else - return &elf_mips_gnu_rel16_s2; - case R_MIPS_PC32: - return &elf_mips_gnu_pcrel32; - case R_MIPS_EH: - return &elf_mips_eh_howto; - case R_MIPS_COPY: - return &elf_mips_copy_howto; - case R_MIPS_JUMP_SLOT: - return &elf_mips_jump_slot_howto; - default: - if (r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max) - { - if (rela_p) - return µmips_elf64_howto_table_rela[r_type - R_MICROMIPS_min]; - else - return µmips_elf64_howto_table_rel[r_type - R_MICROMIPS_min]; - } - if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max) - { - if (rela_p) - return &mips16_elf64_howto_table_rela[r_type - R_MIPS16_min]; - else - return &mips16_elf64_howto_table_rel[r_type - R_MIPS16_min]; - } - if (r_type >= R_MIPS_max) - { - _bfd_error_handler (_("unrecognised MIPS reloc number: %d"), r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_MIPS_NONE; - } - if (rela_p) - return &mips_elf64_howto_table_rela[r_type]; - else - return &mips_elf64_howto_table_rel[r_type]; - break; - } -} - -/* Prevent relocation handling by bfd for MIPS ELF64. */ - -static void -mips_elf64_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr ATTRIBUTE_UNUSED, - Elf_Internal_Rela *dst ATTRIBUTE_UNUSED) -{ - BFD_ASSERT (0); -} - -static void -mips_elf64_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr ATTRIBUTE_UNUSED, - Elf_Internal_Rela *dst ATTRIBUTE_UNUSED) -{ - BFD_ASSERT (0); -} - -/* Since each entry in an SHT_REL or SHT_RELA section can represent up - to three relocs, we must tell the user to allocate more space. */ - -static long -mips_elf64_get_dynamic_reloc_upper_bound (bfd *abfd) -{ - return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3; -} - -/* Read the relocations from one reloc section. This is mostly copied - from elfcode.h, except for the changes to expand one external - relocation to 3 internal ones. To reduce processing effort we - could discard those R_MIPS_NONE relocations that occupy the second - and the third entry of a triplet, as `mips_elf64_write_rel' and - `mips_elf64_write_rela' recreate them in output automagically, - however that would also remove them from `objdump -r' output, - breaking a long-established tradition and likely confusing people. */ - -static bfd_boolean -mips_elf64_slurp_one_reloc_table (bfd *abfd, asection *asect, - Elf_Internal_Shdr *rel_hdr, - bfd_size_type reloc_count, - arelent *relents, asymbol **symbols, - bfd_boolean dynamic) -{ - void *allocated; - bfd_byte *native_relocs; - arelent *relent; - bfd_vma i; - int entsize; - bfd_boolean rela_p; - - allocated = bfd_malloc (rel_hdr->sh_size); - if (allocated == NULL) - return FALSE; - - 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 (Elf64_Mips_External_Rel) - || entsize == sizeof (Elf64_Mips_External_Rela)); - - if (entsize == sizeof (Elf64_Mips_External_Rel)) - rela_p = FALSE; - else - rela_p = TRUE; - - for (i = 0, relent = relents; - i < reloc_count; - i++, native_relocs += entsize) - { - Elf64_Mips_Internal_Rela rela; - bfd_boolean used_sym, used_ssym; - int ir; - - if (entsize == sizeof (Elf64_Mips_External_Rela)) - mips_elf64_swap_reloca_in (abfd, - (Elf64_Mips_External_Rela *) native_relocs, - &rela); - else - mips_elf64_swap_reloc_in (abfd, - (Elf64_Mips_External_Rel *) native_relocs, - &rela); - - /* Each entry represents exactly three actual relocations. */ - - used_sym = FALSE; - used_ssym = FALSE; - for (ir = 0; ir < 3; ir++) - { - enum elf_mips_reloc_type type; - - switch (ir) - { - default: - abort (); - case 0: - type = (enum elf_mips_reloc_type) rela.r_type; - break; - case 1: - type = (enum elf_mips_reloc_type) rela.r_type2; - break; - case 2: - type = (enum elf_mips_reloc_type) rela.r_type3; - break; - } - - /* Some types require symbols, whereas some do not. */ - switch (type) - { - case R_MIPS_NONE: - case R_MIPS_LITERAL: - case R_MIPS_INSERT_A: - case R_MIPS_INSERT_B: - case R_MIPS_DELETE: - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - break; - - default: - if (! used_sym) - { - if (rela.r_sym == STN_UNDEF) - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - else - { - asymbol **ps, *s; - - ps = symbols + rela.r_sym - 1; - s = *ps; - if ((s->flags & BSF_SECTION_SYM) == 0) - relent->sym_ptr_ptr = ps; - else - relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; - } - - used_sym = TRUE; - } - else if (! used_ssym) - { - switch (rela.r_ssym) - { - case RSS_UNDEF: - relent->sym_ptr_ptr = - bfd_abs_section_ptr->symbol_ptr_ptr; - break; - - case RSS_GP: - case RSS_GP0: - case RSS_LOC: - /* FIXME: I think these need to be handled using - special howto structures. */ - BFD_ASSERT (0); - break; - - default: - BFD_ASSERT (0); - break; - } - - used_ssym = TRUE; - } - else - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - - break; - } - - /* 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. */ - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic) - relent->address = rela.r_offset; - else - relent->address = rela.r_offset - asect->vma; - - relent->addend = rela.r_addend; - - relent->howto = mips_elf64_rtype_to_howto (type, rela_p); - - ++relent; - } - } - - if (allocated != NULL) - free (allocated); - - return TRUE; - - error_return: - if (allocated != NULL) - free (allocated); - return FALSE; -} - -/* Read the relocations. On Irix 6, there can be two reloc sections - associated with a single data section. This is copied from - elfcode.h as well, with changes as small as accounting for 3 - internal relocs per external reloc. */ - -static bfd_boolean -mips_elf64_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 = rel_hdr ? NUM_SHDR_ENTRIES (rel_hdr) : 0; - rel_hdr2 = d->rela.hdr; - reloc_count2 = (rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0); - - BFD_ASSERT (asect->reloc_count == 3 * (reloc_count + reloc_count2)); - BFD_ASSERT ((rel_hdr && 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; - } - - /* Allocate space for 3 arelent structures for each Rel structure. */ - amt = (reloc_count + reloc_count2) * 3 * sizeof (arelent); - relents = bfd_alloc (abfd, amt); - if (relents == NULL) - return FALSE; - - if (rel_hdr != NULL - && ! mips_elf64_slurp_one_reloc_table (abfd, asect, - rel_hdr, reloc_count, - relents, - symbols, dynamic)) - return FALSE; - if (rel_hdr2 != NULL - && ! mips_elf64_slurp_one_reloc_table (abfd, asect, - rel_hdr2, reloc_count2, - relents + reloc_count * 3, - symbols, dynamic)) - return FALSE; - - asect->relocation = relents; - return TRUE; -} - -/* Write out the relocations. */ - -static void -mips_elf64_write_relocs (bfd *abfd, asection *sec, void *data) -{ - bfd_boolean *failedp = data; - int count; - Elf_Internal_Shdr *rel_hdr; - unsigned int 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; - - /* We can combine up to three relocs that refer to the same address - if the latter relocs have no associated symbol. */ - count = 0; - for (idx = 0; idx < sec->reloc_count; idx++) - { - bfd_vma addr; - unsigned int i; - - ++count; - - addr = sec->orelocation[idx]->address; - for (i = 0; i < 2; i++) - { - arelent *r; - - if (idx + 1 >= sec->reloc_count) - break; - r = sec->orelocation[idx + 1]; - if (r->address != addr - || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) - || (*r->sym_ptr_ptr)->value != 0) - break; - - /* We can merge the reloc at IDX + 1 with the reloc at IDX. */ - - ++idx; - } - } - - rel_hdr = _bfd_elf_single_rel_hdr (sec); - - /* Do the actual relocation. */ - - if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rel)) - mips_elf64_write_rel (abfd, sec, rel_hdr, &count, data); - else if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rela)) - mips_elf64_write_rela (abfd, sec, rel_hdr, &count, data); - else - BFD_ASSERT (0); -} - -static void -mips_elf64_write_rel (bfd *abfd, asection *sec, - Elf_Internal_Shdr *rel_hdr, - int *count, void *data) -{ - bfd_boolean *failedp = data; - Elf64_Mips_External_Rel *ext_rel; - unsigned int idx; - asymbol *last_sym = 0; - int last_sym_idx = 0; - - rel_hdr->sh_size = rel_hdr->sh_entsize * *count; - rel_hdr->contents = bfd_alloc (abfd, rel_hdr->sh_size); - if (rel_hdr->contents == NULL) - { - *failedp = TRUE; - return; - } - - ext_rel = (Elf64_Mips_External_Rel *) rel_hdr->contents; - for (idx = 0; idx < sec->reloc_count; idx++, ext_rel++) - { - arelent *ptr; - Elf64_Mips_Internal_Rela int_rel; - asymbol *sym; - int n; - unsigned int i; - - ptr = sec->orelocation[idx]; - - /* 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. */ - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) - int_rel.r_offset = ptr->address; - else - int_rel.r_offset = ptr->address + sec->vma; - - 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; - } - - int_rel.r_sym = n; - int_rel.r_ssym = RSS_UNDEF; - - if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec - && ! _bfd_elf_validate_reloc (abfd, ptr)) - { - *failedp = TRUE; - return; - } - - int_rel.r_type = ptr->howto->type; - int_rel.r_type2 = (int) R_MIPS_NONE; - int_rel.r_type3 = (int) R_MIPS_NONE; - - for (i = 0; i < 2; i++) - { - arelent *r; - - if (idx + 1 >= sec->reloc_count) - break; - r = sec->orelocation[idx + 1]; - if (r->address != ptr->address - || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) - || (*r->sym_ptr_ptr)->value != 0) - break; - - /* We can merge the reloc at IDX + 1 with the reloc at IDX. */ - - if (i == 0) - int_rel.r_type2 = r->howto->type; - else - int_rel.r_type3 = r->howto->type; - - ++idx; - } - - mips_elf64_swap_reloc_out (abfd, &int_rel, ext_rel); - } - - BFD_ASSERT (ext_rel - (Elf64_Mips_External_Rel *) rel_hdr->contents - == *count); -} - -static void -mips_elf64_write_rela (bfd *abfd, asection *sec, - Elf_Internal_Shdr *rela_hdr, - int *count, void *data) -{ - bfd_boolean *failedp = data; - Elf64_Mips_External_Rela *ext_rela; - unsigned int idx; - asymbol *last_sym = 0; - int last_sym_idx = 0; - - rela_hdr->sh_size = rela_hdr->sh_entsize * *count; - rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size); - if (rela_hdr->contents == NULL) - { - *failedp = TRUE; - return; - } - - ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents; - for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++) - { - arelent *ptr; - Elf64_Mips_Internal_Rela int_rela; - asymbol *sym; - int n; - unsigned int i; - - ptr = sec->orelocation[idx]; - - /* 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. */ - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) - int_rela.r_offset = ptr->address; - else - int_rela.r_offset = ptr->address + sec->vma; - - 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; - } - - int_rela.r_sym = n; - int_rela.r_addend = ptr->addend; - int_rela.r_ssym = RSS_UNDEF; - - if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec - && ! _bfd_elf_validate_reloc (abfd, ptr)) - { - *failedp = TRUE; - return; - } - - int_rela.r_type = ptr->howto->type; - int_rela.r_type2 = (int) R_MIPS_NONE; - int_rela.r_type3 = (int) R_MIPS_NONE; - - for (i = 0; i < 2; i++) - { - arelent *r; - - if (idx + 1 >= sec->reloc_count) - break; - r = sec->orelocation[idx + 1]; - if (r->address != ptr->address - || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) - || (*r->sym_ptr_ptr)->value != 0) - break; - - /* We can merge the reloc at IDX + 1 with the reloc at IDX. */ - - if (i == 0) - int_rela.r_type2 = r->howto->type; - else - int_rela.r_type3 = r->howto->type; - - ++idx; - } - - mips_elf64_swap_reloca_out (abfd, &int_rela, ext_rela); - } - - BFD_ASSERT (ext_rela - (Elf64_Mips_External_Rela *) rela_hdr->contents - == *count); -} - -/* Set the right machine number for a MIPS ELF file. */ - -static bfd_boolean -mips_elf64_object_p (bfd *abfd) -{ - unsigned long mach; - - /* Irix 6 is broken. Object file symbol tables are not always - sorted correctly such that local symbols precede global symbols, - and the sh_info field in the symbol table is not always right. */ - if (elf64_mips_irix_compat (abfd) != ict_none) - elf_bad_symtab (abfd) = TRUE; - - mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags); - bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach); - return TRUE; -} - -/* Depending on the target vector we generate some version of Irix - executables or "normal" MIPS ELF ABI executables. */ -static irix_compat_t -elf64_mips_irix_compat (bfd *abfd) -{ - if ((abfd->xvec == &mips_elf64_be_vec) - || (abfd->xvec == &mips_elf64_le_vec)) - return ict_irix6; - else - return ict_none; -} - -/* Support for core dump NOTE sections. */ -static bfd_boolean -elf64_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 480: /* Linux/MIPS - N64 kernel */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32); - - /* pr_reg */ - offset = 112; - size = 360; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -elf64_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 136: /* Linux/MIPS - N64 kernel elf_prpsinfo */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 24); - 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; -} - -/* Write Linux core PRSTATUS note into core file. */ - -static char * -elf64_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, - ...) -{ - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - BFD_FAIL (); - return NULL; - - case NT_PRSTATUS: - { - char data[480]; - va_list ap; - long pid; - int cursig; - const void *greg; - - va_start (ap, note_type); - memset (data, 0, 112); - pid = va_arg (ap, long); - bfd_put_32 (abfd, pid, data + 32); - cursig = va_arg (ap, int); - bfd_put_16 (abfd, cursig, data + 12); - greg = va_arg (ap, const void *); - memcpy (data + 112, greg, 360); - memset (data + 472, 0, 8); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - } -} - -/* ECOFF swapping routines. These are used when dealing with the - .mdebug section, which is in the ECOFF debugging format. */ -static const struct ecoff_debug_swap mips_elf64_ecoff_debug_swap = -{ - /* Symbol table magic number. */ - magicSym2, - /* Alignment of debugging information. E.g., 4. */ - 8, - /* Sizes of external symbolic information. */ - sizeof (struct hdr_ext), - sizeof (struct dnr_ext), - sizeof (struct pdr_ext), - sizeof (struct sym_ext), - sizeof (struct opt_ext), - sizeof (struct fdr_ext), - sizeof (struct rfd_ext), - sizeof (struct ext_ext), - /* Functions to swap in external symbolic data. */ - ecoff_swap_hdr_in, - ecoff_swap_dnr_in, - ecoff_swap_pdr_in, - ecoff_swap_sym_in, - ecoff_swap_opt_in, - ecoff_swap_fdr_in, - ecoff_swap_rfd_in, - ecoff_swap_ext_in, - _bfd_ecoff_swap_tir_in, - _bfd_ecoff_swap_rndx_in, - /* Functions to swap out external symbolic data. */ - ecoff_swap_hdr_out, - ecoff_swap_dnr_out, - ecoff_swap_pdr_out, - ecoff_swap_sym_out, - ecoff_swap_opt_out, - ecoff_swap_fdr_out, - ecoff_swap_rfd_out, - ecoff_swap_ext_out, - _bfd_ecoff_swap_tir_out, - _bfd_ecoff_swap_rndx_out, - /* Function to read in symbolic data. */ - _bfd_mips_elf_read_ecoff_info -}; - -/* Relocations in the 64 bit MIPS ELF ABI are more complex than in - standard ELF. This structure is used to redirect the relocation - handling routines. */ - -const struct elf_size_info mips_elf64_size_info = -{ - sizeof (Elf64_External_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_Mips_External_Rel), - sizeof (Elf64_Mips_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 4, /* hash-table entry size */ - 3, /* internal relocations per external relocations */ - 64, /* arch_size */ - 3, /* log_file_align */ - ELFCLASS64, - EV_CURRENT, - bfd_elf64_write_out_phdrs, - bfd_elf64_write_shdrs_and_ehdr, - bfd_elf64_checksum_contents, - mips_elf64_write_relocs, - bfd_elf64_swap_symbol_in, - bfd_elf64_swap_symbol_out, - mips_elf64_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - mips_elf64_be_swap_reloc_in, - mips_elf64_be_swap_reloc_out, - mips_elf64_be_swap_reloca_in, - mips_elf64_be_swap_reloca_out -}; - -#define ELF_ARCH bfd_arch_mips -#define ELF_TARGET_ID MIPS_ELF_DATA -#define ELF_MACHINE_CODE EM_MIPS - -#define elf_backend_collect TRUE -#define elf_backend_type_change_ok TRUE -#define elf_backend_can_gc_sections TRUE -#define elf_backend_gc_mark_extra_sections \ - _bfd_mips_elf_gc_mark_extra_sections -#define elf_info_to_howto mips_elf64_info_to_howto_rela -#define elf_info_to_howto_rel mips_elf64_info_to_howto_rel -#define elf_backend_object_p mips_elf64_object_p -#define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing -#define elf_backend_section_processing _bfd_mips_elf_section_processing -#define elf_backend_section_from_shdr _bfd_mips_elf_section_from_shdr -#define elf_backend_fake_sections _bfd_mips_elf_fake_sections -#define elf_backend_section_from_bfd_section \ - _bfd_mips_elf_section_from_bfd_section -#define elf_backend_add_symbol_hook _bfd_mips_elf_add_symbol_hook -#define elf_backend_link_output_symbol_hook \ - _bfd_mips_elf_link_output_symbol_hook -#define elf_backend_create_dynamic_sections \ - _bfd_mips_elf_create_dynamic_sections -#define elf_backend_check_relocs _bfd_mips_elf_check_relocs -#define elf_backend_merge_symbol_attribute \ - _bfd_mips_elf_merge_symbol_attribute -#define elf_backend_get_target_dtag _bfd_mips_elf_get_target_dtag -#define elf_backend_adjust_dynamic_symbol \ - _bfd_mips_elf_adjust_dynamic_symbol -#define elf_backend_always_size_sections \ - _bfd_mips_elf_always_size_sections -#define elf_backend_size_dynamic_sections \ - _bfd_mips_elf_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_relocate_section _bfd_mips_elf_relocate_section -#define elf_backend_finish_dynamic_symbol \ - _bfd_mips_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_mips_elf_finish_dynamic_sections -#define elf_backend_final_write_processing \ - _bfd_mips_elf_final_write_processing -#define elf_backend_additional_program_headers \ - _bfd_mips_elf_additional_program_headers -#define elf_backend_modify_segment_map _bfd_mips_elf_modify_segment_map -#define elf_backend_gc_mark_hook _bfd_mips_elf_gc_mark_hook -#define elf_backend_copy_indirect_symbol \ - _bfd_mips_elf_copy_indirect_symbol -#define elf_backend_ignore_discarded_relocs \ - _bfd_mips_elf_ignore_discarded_relocs -#define elf_backend_mips_irix_compat elf64_mips_irix_compat -#define elf_backend_mips_rtype_to_howto mips_elf64_rtype_to_howto -#define elf_backend_ecoff_debug_swap &mips_elf64_ecoff_debug_swap -#define elf_backend_size_info mips_elf64_size_info - -#define elf_backend_grok_prstatus elf64_mips_grok_prstatus -#define elf_backend_grok_psinfo elf64_mips_grok_psinfo - -#define elf_backend_got_header_size (8 * MIPS_RESERVED_GOTNO) -#define elf_backend_want_dynrelro 1 - -/* MIPS ELF64 can use a mixture of REL and RELA, but some Relocations - work better/work only in RELA, so we default to this. */ -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_default_use_rela_p 1 -#define elf_backend_rela_plts_and_copies_p 0 -#define elf_backend_plt_readonly 1 -#define elf_backend_plt_sym_val _bfd_mips_elf_plt_sym_val - -#define elf_backend_sign_extend_vma TRUE - -#define elf_backend_write_section _bfd_mips_elf_write_section -#define elf_backend_sort_relocs_p _bfd_mips_elf_sort_relocs_p - -/* We don't set bfd_elf64_bfd_is_local_label_name because the 32-bit - MIPS-specific function only applies to IRIX5, which had no 64-bit - ABI. */ -#define bfd_elf64_bfd_is_target_special_symbol \ - _bfd_mips_elf_is_target_special_symbol -#define bfd_elf64_find_nearest_line _bfd_mips_elf_find_nearest_line -#define bfd_elf64_find_inliner_info _bfd_mips_elf_find_inliner_info -#define bfd_elf64_new_section_hook _bfd_mips_elf_new_section_hook -#define bfd_elf64_set_section_contents _bfd_mips_elf_set_section_contents -#define bfd_elf64_bfd_get_relocated_section_contents \ - _bfd_elf_mips_get_relocated_section_contents -#define bfd_elf64_bfd_link_hash_table_create \ - _bfd_mips_elf_link_hash_table_create -#define bfd_elf64_bfd_final_link _bfd_mips_elf_final_link -#define bfd_elf64_bfd_merge_private_bfd_data \ - _bfd_mips_elf_merge_private_bfd_data -#define bfd_elf64_bfd_set_private_flags _bfd_mips_elf_set_private_flags -#define bfd_elf64_bfd_print_private_bfd_data \ - _bfd_mips_elf_print_private_bfd_data - -#define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound -#define bfd_elf64_mkobject _bfd_mips_elf_mkobject - -/* The SGI style (n)64 NewABI. */ -#define TARGET_LITTLE_SYM mips_elf64_le_vec -#define TARGET_LITTLE_NAME "elf64-littlemips" -#define TARGET_BIG_SYM mips_elf64_be_vec -#define TARGET_BIG_NAME "elf64-bigmips" - -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x1000 - -#include "elf64-target.h" - -/* The SYSV-style 'traditional' (n)64 NewABI. */ -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#undef ELF_MAXPAGESIZE -#undef ELF_COMMONPAGESIZE - -#define TARGET_LITTLE_SYM mips_elf64_trad_le_vec -#define TARGET_LITTLE_NAME "elf64-tradlittlemips" -#define TARGET_BIG_SYM mips_elf64_trad_be_vec -#define TARGET_BIG_NAME "elf64-tradbigmips" - -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x1000 -#define elf64_bed elf64_tradbed - -#undef elf_backend_write_core_note -#define elf_backend_write_core_note elf64_mips_write_core_note - -/* Include the target file again for this target. */ -#include "elf64-target.h" - - -/* FreeBSD support. */ - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#define TARGET_LITTLE_SYM mips_elf64_tradfbsd_le_vec -#define TARGET_LITTLE_NAME "elf64-tradlittlemips-freebsd" -#define TARGET_BIG_SYM mips_elf64_tradfbsd_be_vec -#define TARGET_BIG_NAME "elf64-tradbigmips-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf64_bed -#define elf64_bed elf64_fbsd_tradbed - -#undef elf64_mips_write_core_note - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-mmix.c b/sdcc/support/sdbinutils/bfd/elf64-mmix.c deleted file mode 100644 index 16930c1f5..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-mmix.c +++ /dev/null @@ -1,2925 +0,0 @@ -/* MMIX-specific support for 64-bit ELF. - Copyright (C) 2001-2018 Free Software Foundation, Inc. - Contributed by Hans-Peter Nilsson - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* No specific ABI or "processor-specific supplement" defined. */ - -/* TODO: - - "Traditional" linker relaxation (shrinking whole sections). - - Merge reloc stubs jumping to same location. - - GETA stub relaxation (call a stub for out of range new - R_MMIX_GETA_STUBBABLE). */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/mmix.h" -#include "opcode/mmix.h" - -#define MINUS_ONE (((bfd_vma) 0) - 1) - -#define MAX_PUSHJ_STUB_SIZE (5 * 4) - -/* Put these everywhere in new code. */ -#define FATAL_DEBUG \ - _bfd_abort (__FILE__, __LINE__, \ - "Internal: Non-debugged code (test-case missing)") - -#define BAD_CASE(x) \ - _bfd_abort (__FILE__, __LINE__, \ - "bad case for " #x) - -struct _mmix_elf_section_data -{ - struct bfd_elf_section_data elf; - union - { - struct bpo_reloc_section_info *reloc; - struct bpo_greg_section_info *greg; - } bpo; - - struct pushj_stub_info - { - /* Maximum number of stubs needed for this section. */ - bfd_size_type n_pushj_relocs; - - /* Size of stubs after a mmix_elf_relax_section round. */ - bfd_size_type stubs_size_sum; - - /* Per-reloc stubs_size_sum information. The stubs_size_sum member is the sum - of these. Allocated in mmix_elf_check_common_relocs. */ - bfd_size_type *stub_size; - - /* Offset of next stub during relocation. Somewhat redundant with the - above: error coverage is easier and we don't have to reset the - stubs_size_sum for relocation. */ - bfd_size_type stub_offset; - } pjs; - - /* Whether there has been a warning that this section could not be - linked due to a specific cause. FIXME: a way to access the - linker info or output section, then stuff the limiter guard - there. */ - bfd_boolean has_warned_bpo; - bfd_boolean has_warned_pushj; -}; - -#define mmix_elf_section_data(sec) \ - ((struct _mmix_elf_section_data *) elf_section_data (sec)) - -/* For each section containing a base-plus-offset (BPO) reloc, we attach - this struct as mmix_elf_section_data (section)->bpo, which is otherwise - NULL. */ -struct bpo_reloc_section_info - { - /* The base is 1; this is the first number in this section. */ - size_t first_base_plus_offset_reloc; - - /* Number of BPO-relocs in this section. */ - size_t n_bpo_relocs_this_section; - - /* Running index, used at relocation time. */ - size_t bpo_index; - - /* We don't have access to the bfd_link_info struct in - mmix_final_link_relocate. What we really want to get at is the - global single struct greg_relocation, so we stash it here. */ - asection *bpo_greg_section; - }; - -/* Helper struct (in global context) for the one below. - There's one of these created for every BPO reloc. */ -struct bpo_reloc_request - { - bfd_vma value; - - /* Valid after relaxation. The base is 0; the first register number - must be added. The offset is in range 0..255. */ - size_t regindex; - size_t offset; - - /* The order number for this BPO reloc, corresponding to the order in - which BPO relocs were found. Used to create an index after reloc - requests are sorted. */ - size_t bpo_reloc_no; - - /* Set when the value is computed. Better than coding "guard values" - into the other members. Is FALSE only for BPO relocs in a GC:ed - section. */ - bfd_boolean valid; - }; - -/* We attach this as mmix_elf_section_data (sec)->bpo in the linker-allocated - greg contents section (MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME), - which is linked into the register contents section - (MMIX_REG_CONTENTS_SECTION_NAME). This section is created by the - linker; using the same hook as for usual with BPO relocs does not - collide. */ -struct bpo_greg_section_info - { - /* After GC, this reflects the number of remaining, non-excluded - BPO-relocs. */ - size_t n_bpo_relocs; - - /* This is the number of allocated bpo_reloc_requests; the size of - sorted_indexes. Valid after the check.*relocs functions are called - for all incoming sections. It includes the number of BPO relocs in - sections that were GC:ed. */ - size_t n_max_bpo_relocs; - - /* A counter used to find out when to fold the BPO gregs, since we - don't have a single "after-relaxation" hook. */ - size_t n_remaining_bpo_relocs_this_relaxation_round; - - /* The number of linker-allocated GREGs resulting from BPO relocs. - This is an approximation after _bfd_mmix_before_linker_allocation - and supposedly accurate after mmix_elf_relax_section is called for - all incoming non-collected sections. */ - size_t n_allocated_bpo_gregs; - - /* Index into reloc_request[], sorted on increasing "value", secondary - by increasing index for strict sorting order. */ - size_t *bpo_reloc_indexes; - - /* An array of all relocations, with the "value" member filled in by - the relaxation function. */ - struct bpo_reloc_request *reloc_request; - }; - - -extern bfd_boolean mmix_elf_final_link (bfd *, struct bfd_link_info *); - -extern void mmix_elf_symbol_processing (bfd *, asymbol *); - -/* Only intended to be called from a debugger. */ -extern void mmix_dump_bpo_gregs - (struct bfd_link_info *, void (*) (const char *, ...)); - -static void -mmix_set_relaxable_size (bfd *, asection *, void *); -static bfd_reloc_status_type -mmix_elf_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_reloc_status_type -mmix_final_link_relocate (reloc_howto_type *, asection *, bfd_byte *, bfd_vma, - bfd_signed_vma, bfd_vma, const char *, asection *, - char **); - - -/* Watch out: this currently needs to have elements with the same index as - their R_MMIX_ number. */ -static reloc_howto_type elf_mmix_howto_table[] = - { - /* This reloc does nothing. */ - HOWTO (R_MMIX_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit absolute relocation. */ - HOWTO (R_MMIX_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 16 bit absolute relocation. */ - HOWTO (R_MMIX_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 24 bit absolute relocation. */ - HOWTO (R_MMIX_24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_24", /* name */ - FALSE, /* partial_inplace */ - ~0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 32 bit absolute relocation. */ - HOWTO (R_MMIX_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit relocation. */ - HOWTO (R_MMIX_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An 8 bit PC-relative relocation. */ - HOWTO (R_MMIX_PC_8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_PC_8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* An 16 bit PC-relative relocation. */ - HOWTO (R_MMIX_PC_16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_PC_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* An 24 bit PC-relative relocation. */ - HOWTO (R_MMIX_PC_24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 24, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_PC_24", /* name */ - FALSE, /* partial_inplace */ - ~0xffffff, /* src_mask */ - 0xffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit absolute PC-relative relocation. */ - HOWTO (R_MMIX_PC_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_PC_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 64 bit PC-relative relocation. */ - HOWTO (R_MMIX_PC_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_MMIX_PC_64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_MMIX_GNU_VTINHERIT, /* 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 */ - "R_MMIX_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable member usage. */ - HOWTO (R_MMIX_GNU_VTENTRY, /* type */ - 0, /* rightshift */ - 0, /* 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_MMIX_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The GETA relocation is supposed to get any address that could - possibly be reached by the GETA instruction. It can silently expand - to get a 64-bit operand, but will complain if any of the two least - significant bits are set. The howto members reflect a simple GETA. */ - HOWTO (R_MMIX_GETA, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_GETA", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_GETA_1, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_GETA_1", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_GETA_2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_GETA_2", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_GETA_3, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_GETA_3", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The conditional branches are supposed to reach any (code) address. - It can silently expand to a 64-bit operand, but will emit an error if - any of the two least significant bits are set. The howto members - reflect a simple branch. */ - HOWTO (R_MMIX_CBRANCH, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_CBRANCH", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_CBRANCH_J, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_CBRANCH_J", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_CBRANCH_1, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_CBRANCH_1", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_CBRANCH_2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_CBRANCH_2", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_CBRANCH_3, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_CBRANCH_3", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The PUSHJ instruction can reach any (code) address, as long as it's - the beginning of a function (no usable restriction). It can silently - expand to a 64-bit operand, but will emit an error if any of the two - least significant bits are set. It can also expand into a call to a - stub; see R_MMIX_PUSHJ_STUBBABLE. The howto members reflect a simple - PUSHJ. */ - HOWTO (R_MMIX_PUSHJ, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_PUSHJ", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_PUSHJ_1, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_PUSHJ_1", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_PUSHJ_2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_PUSHJ_2", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_PUSHJ_3, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_PUSHJ_3", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A JMP is supposed to reach any (code) address. By itself, it can - reach +-64M; the expansion can reach all 64 bits. Note that the 64M - limit is soon reached if you link the program in wildly different - memory segments. The howto members reflect a trivial JMP. */ - HOWTO (R_MMIX_JMP, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 27, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_JMP", /* name */ - FALSE, /* partial_inplace */ - ~0x1ffffff, /* src_mask */ - 0x1ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_JMP_1, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 27, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_JMP_1", /* name */ - FALSE, /* partial_inplace */ - ~0x1ffffff, /* src_mask */ - 0x1ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_JMP_2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 27, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_JMP_2", /* name */ - FALSE, /* partial_inplace */ - ~0x1ffffff, /* src_mask */ - 0x1ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MMIX_JMP_3, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 27, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_JMP_3", /* name */ - FALSE, /* partial_inplace */ - ~0x1ffffff, /* src_mask */ - 0x1ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* When we don't emit link-time-relaxable code from the assembler, or - when relaxation has done all it can do, these relocs are used. For - GETA/PUSHJ/branches. */ - HOWTO (R_MMIX_ADDR19, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_ADDR19", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* For JMP. */ - HOWTO (R_MMIX_ADDR27, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 27, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_ADDR27", /* name */ - FALSE, /* partial_inplace */ - ~0x1ffffff, /* src_mask */ - 0x1ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A general register or the value 0..255. If a value, then the - instruction (offset -3) needs adjusting. */ - HOWTO (R_MMIX_REG_OR_BYTE, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_REG_OR_BYTE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A general register. */ - HOWTO (R_MMIX_REG, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_REG", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A register plus an index, corresponding to the relocation expression. - The sizes must correspond to the valid range of the expression, while - the bitmasks correspond to what we store in the image. */ - HOWTO (R_MMIX_BASE_PLUS_OFFSET, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_BASE_PLUS_OFFSET", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A "magic" relocation for a LOCAL expression, asserting that the - expression is less than the number of global registers. No actual - modification of the contents is done. Implementing this as a - relocation was less intrusive than e.g. putting such expressions in a - section to discard *after* relocation. */ - HOWTO (R_MMIX_LOCAL, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_LOCAL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MMIX_PUSHJ_STUBBABLE, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mmix_elf_reloc, /* special_function */ - "R_MMIX_PUSHJ_STUBBABLE", /* name */ - FALSE, /* partial_inplace */ - ~0x0100ffff, /* src_mask */ - 0x0100ffff, /* dst_mask */ - TRUE) /* pcrel_offset */ - }; - - -/* Map BFD reloc types to MMIX ELF reloc types. */ - -struct mmix_reloc_map - { - bfd_reloc_code_real_type bfd_reloc_val; - enum elf_mmix_reloc_type elf_reloc_val; - }; - - -static const struct mmix_reloc_map mmix_reloc_map[] = - { - {BFD_RELOC_NONE, R_MMIX_NONE}, - {BFD_RELOC_8, R_MMIX_8}, - {BFD_RELOC_16, R_MMIX_16}, - {BFD_RELOC_24, R_MMIX_24}, - {BFD_RELOC_32, R_MMIX_32}, - {BFD_RELOC_64, R_MMIX_64}, - {BFD_RELOC_8_PCREL, R_MMIX_PC_8}, - {BFD_RELOC_16_PCREL, R_MMIX_PC_16}, - {BFD_RELOC_24_PCREL, R_MMIX_PC_24}, - {BFD_RELOC_32_PCREL, R_MMIX_PC_32}, - {BFD_RELOC_64_PCREL, R_MMIX_PC_64}, - {BFD_RELOC_VTABLE_INHERIT, R_MMIX_GNU_VTINHERIT}, - {BFD_RELOC_VTABLE_ENTRY, R_MMIX_GNU_VTENTRY}, - {BFD_RELOC_MMIX_GETA, R_MMIX_GETA}, - {BFD_RELOC_MMIX_CBRANCH, R_MMIX_CBRANCH}, - {BFD_RELOC_MMIX_PUSHJ, R_MMIX_PUSHJ}, - {BFD_RELOC_MMIX_JMP, R_MMIX_JMP}, - {BFD_RELOC_MMIX_ADDR19, R_MMIX_ADDR19}, - {BFD_RELOC_MMIX_ADDR27, R_MMIX_ADDR27}, - {BFD_RELOC_MMIX_REG_OR_BYTE, R_MMIX_REG_OR_BYTE}, - {BFD_RELOC_MMIX_REG, R_MMIX_REG}, - {BFD_RELOC_MMIX_BASE_PLUS_OFFSET, R_MMIX_BASE_PLUS_OFFSET}, - {BFD_RELOC_MMIX_LOCAL, R_MMIX_LOCAL}, - {BFD_RELOC_MMIX_PUSHJ_STUBBABLE, R_MMIX_PUSHJ_STUBBABLE} - }; - -static reloc_howto_type * -bfd_elf64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; - i < sizeof (mmix_reloc_map) / sizeof (mmix_reloc_map[0]); - i++) - { - if (mmix_reloc_map[i].bfd_reloc_val == code) - return &elf_mmix_howto_table[mmix_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -bfd_elf64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf_mmix_howto_table) / sizeof (elf_mmix_howto_table[0]); - i++) - if (elf_mmix_howto_table[i].name != NULL - && strcasecmp (elf_mmix_howto_table[i].name, r_name) == 0) - return &elf_mmix_howto_table[i]; - - return NULL; -} - -static bfd_boolean -mmix_elf_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - struct _mmix_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - - -/* This function performs the actual bitfiddling and sanity check for a - final relocation. Each relocation gets its *worst*-case expansion - in size when it arrives here; any reduction in size should have been - caught in linker relaxation earlier. When we get here, the relocation - looks like the smallest instruction with SWYM:s (nop:s) appended to the - max size. We fill in those nop:s. - - R_MMIX_GETA: (FIXME: Relaxation should break this up in 1, 2, 3 tetra) - GETA $N,foo - -> - SETL $N,foo & 0xffff - INCML $N,(foo >> 16) & 0xffff - INCMH $N,(foo >> 32) & 0xffff - INCH $N,(foo >> 48) & 0xffff - - R_MMIX_CBRANCH: (FIXME: Relaxation should break this up, but - condbranches needing relaxation might be rare enough to not be - worthwhile.) - [P]Bcc $N,foo - -> - [~P]B~cc $N,.+20 - SETL $255,foo & ... - INCML ... - INCMH ... - INCH ... - GO $255,$255,0 - - R_MMIX_PUSHJ: (FIXME: Relaxation...) - PUSHJ $N,foo - -> - SETL $255,foo & ... - INCML ... - INCMH ... - INCH ... - PUSHGO $N,$255,0 - - R_MMIX_JMP: (FIXME: Relaxation...) - JMP foo - -> - SETL $255,foo & ... - INCML ... - INCMH ... - INCH ... - GO $255,$255,0 - - R_MMIX_ADDR19 and R_MMIX_ADDR27 are just filled in. */ - -static bfd_reloc_status_type -mmix_elf_perform_relocation (asection *isec, reloc_howto_type *howto, - void *datap, bfd_vma addr, bfd_vma value, - char **error_message) -{ - bfd *abfd = isec->owner; - bfd_reloc_status_type flag = bfd_reloc_ok; - bfd_reloc_status_type r; - int offs = 0; - int reg = 255; - - /* The worst case bits are all similar SETL/INCML/INCMH/INCH sequences. - We handle the differences here and the common sequence later. */ - switch (howto->type) - { - case R_MMIX_GETA: - offs = 0; - reg = bfd_get_8 (abfd, (bfd_byte *) datap + 1); - - /* We change to an absolute value. */ - value += addr; - break; - - case R_MMIX_CBRANCH: - { - int in1 = bfd_get_16 (abfd, (bfd_byte *) datap) << 16; - - /* Invert the condition and prediction bit, and set the offset - to five instructions ahead. - - We *can* do better if we want to. If the branch is found to be - within limits, we could leave the branch as is; there'll just - be a bunch of NOP:s after it. But we shouldn't see this - sequence often enough that it's worth doing it. */ - - bfd_put_32 (abfd, - (((in1 ^ ((PRED_INV_BIT | COND_INV_BIT) << 24)) & ~0xffff) - | (24/4)), - (bfd_byte *) datap); - - /* Put a "GO $255,$255,0" after the common sequence. */ - bfd_put_32 (abfd, - ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24) | 0xffff00, - (bfd_byte *) datap + 20); - - /* Common sequence starts at offset 4. */ - offs = 4; - - /* We change to an absolute value. */ - value += addr; - } - break; - - case R_MMIX_PUSHJ_STUBBABLE: - /* If the address fits, we're fine. */ - if ((value & 3) == 0 - /* Note rightshift 0; see R_MMIX_JMP case below. */ - && (r = bfd_check_overflow (complain_overflow_signed, - howto->bitsize, - 0, - bfd_arch_bits_per_address (abfd), - value)) == bfd_reloc_ok) - goto pcrel_mmix_reloc_fits; - else - { - bfd_size_type size = isec->rawsize ? isec->rawsize : isec->size; - - /* We have the bytes at the PUSHJ insn and need to get the - position for the stub. There's supposed to be room allocated - for the stub. */ - bfd_byte *stubcontents - = ((bfd_byte *) datap - - (addr - (isec->output_section->vma + isec->output_offset)) - + size - + mmix_elf_section_data (isec)->pjs.stub_offset); - bfd_vma stubaddr; - - if (mmix_elf_section_data (isec)->pjs.n_pushj_relocs == 0) - { - /* This shouldn't happen when linking to ELF or mmo, so - this is an attempt to link to "binary", right? We - can't access the output bfd, so we can't verify that - assumption. We only know that the critical - mmix_elf_check_common_relocs has not been called, - which happens when the output format is different - from the input format (and is not mmo). */ - if (! mmix_elf_section_data (isec)->has_warned_pushj) - { - /* For the first such error per input section, produce - a verbose message. */ - *error_message - = _("invalid input relocation when producing" - " non-ELF, non-mmo format output." - "\n Please use the objcopy program to convert from" - " ELF or mmo," - "\n or assemble using" - " \"-no-expand\" (for gcc, \"-Wa,-no-expand\""); - mmix_elf_section_data (isec)->has_warned_pushj = TRUE; - return bfd_reloc_dangerous; - } - - /* For subsequent errors, return this one, which is - rate-limited but looks a little bit different, - hopefully without affecting user-friendliness. */ - return bfd_reloc_overflow; - } - - /* The address doesn't fit, so redirect the PUSHJ to the - location of the stub. */ - r = mmix_elf_perform_relocation (isec, - &elf_mmix_howto_table - [R_MMIX_ADDR19], - datap, - addr, - isec->output_section->vma - + isec->output_offset - + size - + (mmix_elf_section_data (isec) - ->pjs.stub_offset) - - addr, - error_message); - if (r != bfd_reloc_ok) - return r; - - stubaddr - = (isec->output_section->vma - + isec->output_offset - + size - + mmix_elf_section_data (isec)->pjs.stub_offset); - - /* We generate a simple JMP if that suffices, else the whole 5 - insn stub. */ - if (bfd_check_overflow (complain_overflow_signed, - elf_mmix_howto_table[R_MMIX_ADDR27].bitsize, - 0, - bfd_arch_bits_per_address (abfd), - addr + value - stubaddr) == bfd_reloc_ok) - { - bfd_put_32 (abfd, JMP_INSN_BYTE << 24, stubcontents); - r = mmix_elf_perform_relocation (isec, - &elf_mmix_howto_table - [R_MMIX_ADDR27], - stubcontents, - stubaddr, - value + addr - stubaddr, - error_message); - mmix_elf_section_data (isec)->pjs.stub_offset += 4; - - if (size + mmix_elf_section_data (isec)->pjs.stub_offset - > isec->size) - abort (); - - return r; - } - else - { - /* Put a "GO $255,0" after the common sequence. */ - bfd_put_32 (abfd, - ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24) - | 0xff00, (bfd_byte *) stubcontents + 16); - - /* Prepare for the general code to set the first part of the - linker stub, and */ - value += addr; - datap = stubcontents; - mmix_elf_section_data (isec)->pjs.stub_offset - += MAX_PUSHJ_STUB_SIZE; - } - } - break; - - case R_MMIX_PUSHJ: - { - int inreg = bfd_get_8 (abfd, (bfd_byte *) datap + 1); - - /* Put a "PUSHGO $N,$255,0" after the common sequence. */ - bfd_put_32 (abfd, - ((PUSHGO_INSN_BYTE | IMM_OFFSET_BIT) << 24) - | (inreg << 16) - | 0xff00, - (bfd_byte *) datap + 16); - - /* We change to an absolute value. */ - value += addr; - } - break; - - case R_MMIX_JMP: - /* This one is a little special. If we get here on a non-relaxing - link, and the destination is actually in range, we don't need to - execute the nops. - If so, we fall through to the bit-fiddling relocs. - - FIXME: bfd_check_overflow seems broken; the relocation is - rightshifted before testing, so supply a zero rightshift. */ - - if (! ((value & 3) == 0 - && (r = bfd_check_overflow (complain_overflow_signed, - howto->bitsize, - 0, - bfd_arch_bits_per_address (abfd), - value)) == bfd_reloc_ok)) - { - /* If the relocation doesn't fit in a JMP, we let the NOP:s be - modified below, and put a "GO $255,$255,0" after the - address-loading sequence. */ - bfd_put_32 (abfd, - ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24) - | 0xffff00, - (bfd_byte *) datap + 16); - - /* We change to an absolute value. */ - value += addr; - break; - } - /* FALLTHROUGH. */ - case R_MMIX_ADDR19: - case R_MMIX_ADDR27: - pcrel_mmix_reloc_fits: - /* These must be in range, or else we emit an error. */ - if ((value & 3) == 0 - /* Note rightshift 0; see above. */ - && (r = bfd_check_overflow (complain_overflow_signed, - howto->bitsize, - 0, - bfd_arch_bits_per_address (abfd), - value)) == bfd_reloc_ok) - { - bfd_vma in1 - = bfd_get_32 (abfd, (bfd_byte *) datap); - bfd_vma highbit; - - if ((bfd_signed_vma) value < 0) - { - highbit = 1 << 24; - value += (1 << (howto->bitsize - 1)); - } - else - highbit = 0; - - value >>= 2; - - bfd_put_32 (abfd, - (in1 & howto->src_mask) - | highbit - | (value & howto->dst_mask), - (bfd_byte *) datap); - - return bfd_reloc_ok; - } - else - return bfd_reloc_overflow; - - case R_MMIX_BASE_PLUS_OFFSET: - { - struct bpo_reloc_section_info *bpodata - = mmix_elf_section_data (isec)->bpo.reloc; - asection *bpo_greg_section; - struct bpo_greg_section_info *gregdata; - size_t bpo_index; - - if (bpodata == NULL) - { - /* This shouldn't happen when linking to ELF or mmo, so - this is an attempt to link to "binary", right? We - can't access the output bfd, so we can't verify that - assumption. We only know that the critical - mmix_elf_check_common_relocs has not been called, which - happens when the output format is different from the - input format (and is not mmo). */ - if (! mmix_elf_section_data (isec)->has_warned_bpo) - { - /* For the first such error per input section, produce - a verbose message. */ - *error_message - = _("invalid input relocation when producing" - " non-ELF, non-mmo format output." - "\n Please use the objcopy program to convert from" - " ELF or mmo," - "\n or compile using the gcc-option" - " \"-mno-base-addresses\"."); - mmix_elf_section_data (isec)->has_warned_bpo = TRUE; - return bfd_reloc_dangerous; - } - - /* For subsequent errors, return this one, which is - rate-limited but looks a little bit different, - hopefully without affecting user-friendliness. */ - return bfd_reloc_overflow; - } - - bpo_greg_section = bpodata->bpo_greg_section; - gregdata = mmix_elf_section_data (bpo_greg_section)->bpo.greg; - bpo_index = gregdata->bpo_reloc_indexes[bpodata->bpo_index++]; - - /* A consistency check: The value we now have in "relocation" must - be the same as the value we stored for that relocation. It - doesn't cost much, so can be left in at all times. */ - if (value != gregdata->reloc_request[bpo_index].value) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Internal inconsistency error for value for\n\ - linker-allocated global register: linked: %#Lx != relaxed: %#Lx"), - isec->owner, - value, - gregdata->reloc_request[bpo_index].value); - bfd_set_error (bfd_error_bad_value); - return bfd_reloc_overflow; - } - - /* Then store the register number and offset for that register - into datap and datap + 1 respectively. */ - bfd_put_8 (abfd, - gregdata->reloc_request[bpo_index].regindex - + bpo_greg_section->output_section->vma / 8, - datap); - bfd_put_8 (abfd, - gregdata->reloc_request[bpo_index].offset, - ((unsigned char *) datap) + 1); - return bfd_reloc_ok; - } - - case R_MMIX_REG_OR_BYTE: - case R_MMIX_REG: - if (value > 255) - return bfd_reloc_overflow; - bfd_put_8 (abfd, value, datap); - return bfd_reloc_ok; - - default: - BAD_CASE (howto->type); - } - - /* This code adds the common SETL/INCML/INCMH/INCH worst-case - sequence. */ - - /* Lowest two bits must be 0. We return bfd_reloc_overflow for - everything that looks strange. */ - if (value & 3) - flag = bfd_reloc_overflow; - - bfd_put_32 (abfd, - (SETL_INSN_BYTE << 24) | (value & 0xffff) | (reg << 16), - (bfd_byte *) datap + offs); - bfd_put_32 (abfd, - (INCML_INSN_BYTE << 24) | ((value >> 16) & 0xffff) | (reg << 16), - (bfd_byte *) datap + offs + 4); - bfd_put_32 (abfd, - (INCMH_INSN_BYTE << 24) | ((value >> 32) & 0xffff) | (reg << 16), - (bfd_byte *) datap + offs + 8); - bfd_put_32 (abfd, - (INCH_INSN_BYTE << 24) | ((value >> 48) & 0xffff) | (reg << 16), - (bfd_byte *) datap + offs + 12); - - return flag; -} - -/* Set the howto pointer for an MMIX ELF reloc (type RELA). */ - -static void -mmix_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF64_R_TYPE (dst->r_info); - if (r_type >= (unsigned int) R_MMIX_max) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid MMIX reloc number: %d"), abfd, r_type); - r_type = 0; - } - cache_ptr->howto = &elf_mmix_howto_table[r_type]; -} - -/* Any MMIX-specific relocation gets here at assembly time or when linking - to other formats (such as mmo); this is the relocation function from - the reloc_table. We don't get here for final pure ELF linking. */ - -static bfd_reloc_status_type -mmix_elf_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message) -{ - bfd_vma relocation; - bfd_reloc_status_type r; - asection *reloc_target_output_section; - bfd_reloc_status_type flag = bfd_reloc_ok; - bfd_vma output_base = 0; - - r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* If that was all that was needed (i.e. this isn't a final link, only - some segment adjustments), we're done. */ - if (r != bfd_reloc_continue) - return r; - - if (bfd_is_und_section (symbol->section) - && (symbol->flags & BSF_WEAK) == 0 - && output_bfd == (bfd *) NULL) - return bfd_reloc_undefined; - - /* 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 = bfd_get_output_section (symbol); - - /* Here the variable relocation holds the final address of the symbol we - are relocating against, plus any addend. */ - if (output_bfd) - output_base = 0; - else - output_base = reloc_target_output_section->vma; - - relocation += output_base + symbol->section->output_offset; - - if (output_bfd != (bfd *) NULL) - { - /* Add in supplied addend. */ - relocation += reloc_entry->addend; - - /* 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; - } - - return mmix_final_link_relocate (reloc_entry->howto, input_section, - data, reloc_entry->address, - reloc_entry->addend, relocation, - bfd_asymbol_name (symbol), - reloc_target_output_section, - error_message); -} - -/* Relocate an MMIX ELF section. Modified from elf32-fr30.c; look to it - for guidance if you're thinking of copying this. */ - -static bfd_boolean -mmix_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - bfd_size_type size; - size_t pjsno = 0; - - size = input_section->rawsize ? input_section->rawsize : input_section->size; - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - relend = relocs + input_section->reloc_count; - - /* Zero the stub area before we start. */ - if (input_section->rawsize != 0 - && input_section->size > input_section->rawsize) - memset (contents + input_section->rawsize, 0, - input_section->size - input_section->rawsize); - - for (rel = relocs; rel < relend; rel ++) - { - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_reloc_status_type r; - const char *name = NULL; - int r_type; - bfd_boolean undefined_signalled = FALSE; - - r_type = ELF64_R_TYPE (rel->r_info); - - if (r_type == R_MMIX_GNU_VTINHERIT - || r_type == R_MMIX_GNU_VTENTRY) - continue; - - r_symndx = ELF64_R_SYM (rel->r_info); - - howto = elf_mmix_howto_table + ELF64_R_TYPE (rel->r_info); - h = NULL; - sym = NULL; - sec = NULL; - - if (r_symndx < symtab_hdr->sh_info) - { - sym = local_syms + r_symndx; - sec = local_sections [r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL) - name = bfd_section_name (input_bfd, sec); - } - else - { - bfd_boolean unresolved_reloc, ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, undefined_signalled, - ignored); - name = h->root.root.string; - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - { - /* This is a relocatable link. For most relocs we don't have to - change anything, unless the reloc is against a section - symbol, in which case we have to adjust according to where - the section symbol winds up in the output section. */ - if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += sec->output_offset; - - /* For PUSHJ stub relocs however, we may need to change the - reloc and the section contents, if the reloc doesn't reach - beyond the end of the output section and previous stubs. - Then we change the section contents to be a PUSHJ to the end - of the input section plus stubs (we can do that without using - a reloc), and then we change the reloc to be a R_MMIX_PUSHJ - at the stub location. */ - if (r_type == R_MMIX_PUSHJ_STUBBABLE) - { - /* We've already checked whether we need a stub; use that - knowledge. */ - if (mmix_elf_section_data (input_section)->pjs.stub_size[pjsno] - != 0) - { - Elf_Internal_Rela relcpy; - - if (mmix_elf_section_data (input_section) - ->pjs.stub_size[pjsno] != MAX_PUSHJ_STUB_SIZE) - abort (); - - /* There's already a PUSHJ insn there, so just fill in - the offset bits to the stub. */ - if (mmix_final_link_relocate (elf_mmix_howto_table - + R_MMIX_ADDR19, - input_section, - contents, - rel->r_offset, - 0, - input_section - ->output_section->vma - + input_section->output_offset - + size - + mmix_elf_section_data (input_section) - ->pjs.stub_offset, - NULL, NULL, NULL) != bfd_reloc_ok) - return FALSE; - - /* Put a JMP insn at the stub; it goes with the - R_MMIX_JMP reloc. */ - bfd_put_32 (output_bfd, JMP_INSN_BYTE << 24, - contents - + size - + mmix_elf_section_data (input_section) - ->pjs.stub_offset); - - /* Change the reloc to be at the stub, and to a full - R_MMIX_JMP reloc. */ - rel->r_info = ELF64_R_INFO (r_symndx, R_MMIX_JMP); - rel->r_offset - = (size - + mmix_elf_section_data (input_section) - ->pjs.stub_offset); - - mmix_elf_section_data (input_section)->pjs.stub_offset - += MAX_PUSHJ_STUB_SIZE; - - /* Shift this reloc to the end of the relocs to maintain - the r_offset sorted reloc order. */ - relcpy = *rel; - memmove (rel, rel + 1, (char *) relend - (char *) rel); - relend[-1] = relcpy; - - /* Back up one reloc, or else we'd skip the next reloc - in turn. */ - rel--; - } - - pjsno++; - } - continue; - } - - r = mmix_final_link_relocate (howto, input_section, - contents, rel->r_offset, - rel->r_addend, relocation, name, sec, NULL); - - if (r != bfd_reloc_ok) - { - const char * msg = (const char *) NULL; - - switch (r) - { - case bfd_reloc_overflow: - info->callbacks->reloc_overflow - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - break; - - case bfd_reloc_undefined: - /* We may have sent this message above. */ - if (! undefined_signalled) - info->callbacks->undefined_symbol - (info, name, input_bfd, input_section, rel->r_offset, TRUE); - undefined_signalled = TRUE; - break; - - case bfd_reloc_outofrange: - msg = _("internal error: out of range error"); - break; - - case bfd_reloc_notsupported: - msg = _("internal error: unsupported relocation error"); - break; - - case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); - break; - - default: - msg = _("internal error: unknown error"); - break; - } - - if (msg) - (*info->callbacks->warning) (info, msg, name, input_bfd, - input_section, rel->r_offset); - } - } - - return TRUE; -} - -/* Perform a single relocation. By default we use the standard BFD - routines. A few relocs we have to do ourselves. */ - -static bfd_reloc_status_type -mmix_final_link_relocate (reloc_howto_type *howto, asection *input_section, - bfd_byte *contents, bfd_vma r_offset, - bfd_signed_vma r_addend, bfd_vma relocation, - const char *symname, asection *symsec, - char **error_message) -{ - bfd_reloc_status_type r = bfd_reloc_ok; - bfd_vma addr - = (input_section->output_section->vma - + input_section->output_offset - + r_offset); - bfd_signed_vma srel - = (bfd_signed_vma) relocation + r_addend; - - switch (howto->type) - { - /* All these are PC-relative. */ - case R_MMIX_PUSHJ_STUBBABLE: - case R_MMIX_PUSHJ: - case R_MMIX_CBRANCH: - case R_MMIX_ADDR19: - case R_MMIX_GETA: - case R_MMIX_ADDR27: - case R_MMIX_JMP: - contents += r_offset; - - srel -= (input_section->output_section->vma - + input_section->output_offset - + r_offset); - - r = mmix_elf_perform_relocation (input_section, howto, contents, - addr, srel, error_message); - break; - - case R_MMIX_BASE_PLUS_OFFSET: - if (symsec == NULL) - return bfd_reloc_undefined; - - /* Check that we're not relocating against a register symbol. */ - if (strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_CONTENTS_SECTION_NAME) == 0 - || strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_SECTION_NAME) == 0) - { - /* Note: This is separated out into two messages in order - to ease the translation into other languages. */ - if (symname == NULL || *symname == 0) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: base-plus-offset relocation against register symbol:" - " (unknown) in %A"), - input_section->owner, symsec); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: base-plus-offset relocation against register symbol:" - " %s in %A"), - input_section->owner, symname, symsec); - return bfd_reloc_overflow; - } - goto do_mmix_reloc; - - case R_MMIX_REG_OR_BYTE: - case R_MMIX_REG: - /* For now, we handle these alike. They must refer to an register - symbol, which is either relative to the register section and in - the range 0..255, or is in the register contents section with vma - regno * 8. */ - - /* FIXME: A better way to check for reg contents section? - FIXME: Postpone section->scaling to mmix_elf_perform_relocation? */ - if (symsec == NULL) - return bfd_reloc_undefined; - - if (strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_CONTENTS_SECTION_NAME) == 0) - { - if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8) - { - /* The bfd_reloc_outofrange return value, though intuitively - a better value, will not get us an error. */ - return bfd_reloc_overflow; - } - srel /= 8; - } - else if (strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_SECTION_NAME) == 0) - { - if (srel < 0 || srel > 255) - /* The bfd_reloc_outofrange return value, though intuitively a - better value, will not get us an error. */ - return bfd_reloc_overflow; - } - else - { - /* Note: This is separated out into two messages in order - to ease the translation into other languages. */ - if (symname == NULL || *symname == 0) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: register relocation against non-register symbol:" - " (unknown) in %A"), - input_section->owner, symsec); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: register relocation against non-register symbol:" - " %s in %A"), - input_section->owner, symname, symsec); - - /* The bfd_reloc_outofrange return value, though intuitively a - better value, will not get us an error. */ - return bfd_reloc_overflow; - } - do_mmix_reloc: - contents += r_offset; - r = mmix_elf_perform_relocation (input_section, howto, contents, - addr, srel, error_message); - break; - - case R_MMIX_LOCAL: - /* This isn't a real relocation, it's just an assertion that the - final relocation value corresponds to a local register. We - ignore the actual relocation; nothing is changed. */ - { - asection *regsec - = bfd_get_section_by_name (input_section->output_section->owner, - MMIX_REG_CONTENTS_SECTION_NAME); - bfd_vma first_global; - - /* Check that this is an absolute value, or a reference to the - register contents section or the register (symbol) section. - Absolute numbers can get here as undefined section. Undefined - symbols are signalled elsewhere, so there's no conflict in us - accidentally handling it. */ - if (!bfd_is_abs_section (symsec) - && !bfd_is_und_section (symsec) - && strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_CONTENTS_SECTION_NAME) != 0 - && strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_SECTION_NAME) != 0) - { - _bfd_error_handler - (_("%B: directive LOCAL valid only with a register or absolute value"), - input_section->owner); - - return bfd_reloc_overflow; - } - - /* If we don't have a register contents section, then $255 is the - first global register. */ - if (regsec == NULL) - first_global = 255; - else - { - first_global - = bfd_get_section_vma (input_section->output_section->owner, - regsec) / 8; - if (strcmp (bfd_get_section_name (symsec->owner, symsec), - MMIX_REG_CONTENTS_SECTION_NAME) == 0) - { - if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8) - /* The bfd_reloc_outofrange return value, though - intuitively a better value, will not get us an error. */ - return bfd_reloc_overflow; - srel /= 8; - } - } - - if ((bfd_vma) srel >= first_global) - { - /* FIXME: Better error message. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: LOCAL directive: Register $%Ld is not a local register." - " First global register is $%Ld."), - input_section->owner, srel, first_global); - - return bfd_reloc_overflow; - } - } - r = bfd_reloc_ok; - break; - - default: - r = _bfd_final_link_relocate (howto, input_section->owner, input_section, - contents, r_offset, - relocation, r_addend); - } - - return r; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -mmix_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_MMIX_GNU_VTINHERIT: - case R_MMIX_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Sort register relocs to come before expanding relocs. */ - -static int -mmix_elf_sort_relocs (const void * p1, const void * p2) -{ - const Elf_Internal_Rela *r1 = (const Elf_Internal_Rela *) p1; - const Elf_Internal_Rela *r2 = (const Elf_Internal_Rela *) p2; - int r1_is_reg, r2_is_reg; - - /* Sort primarily on r_offset & ~3, so relocs are done to consecutive - insns. */ - if ((r1->r_offset & ~(bfd_vma) 3) > (r2->r_offset & ~(bfd_vma) 3)) - return 1; - else if ((r1->r_offset & ~(bfd_vma) 3) < (r2->r_offset & ~(bfd_vma) 3)) - return -1; - - r1_is_reg - = (ELF64_R_TYPE (r1->r_info) == R_MMIX_REG_OR_BYTE - || ELF64_R_TYPE (r1->r_info) == R_MMIX_REG); - r2_is_reg - = (ELF64_R_TYPE (r2->r_info) == R_MMIX_REG_OR_BYTE - || ELF64_R_TYPE (r2->r_info) == R_MMIX_REG); - if (r1_is_reg != r2_is_reg) - return r2_is_reg - r1_is_reg; - - /* Neither or both are register relocs. Then sort on full offset. */ - if (r1->r_offset > r2->r_offset) - return 1; - else if (r1->r_offset < r2->r_offset) - return -1; - return 0; -} - -/* Subset of mmix_elf_check_relocs, common to ELF and mmo linking. */ - -static bfd_boolean -mmix_elf_check_common_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - bfd *bpo_greg_owner = NULL; - asection *allocated_gregs_section = NULL; - struct bpo_greg_section_info *gregdata = NULL; - struct bpo_reloc_section_info *bpodata = NULL; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - /* We currently have to abuse this COFF-specific member, since there's - no target-machine-dedicated member. There's no alternative outside - the bfd_link_info struct; we can't specialize a hash-table since - they're different between ELF and mmo. */ - bpo_greg_owner = (bfd *) info->base_file; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - switch (ELF64_R_TYPE (rel->r_info)) - { - /* This relocation causes a GREG allocation. We need to count - them, and we need to create a section for them, so we need an - object to fake as the owner of that section. We can't use - the ELF dynobj for this, since the ELF bits assume lots of - DSO-related stuff if that member is non-NULL. */ - case R_MMIX_BASE_PLUS_OFFSET: - /* We don't do anything with this reloc for a relocatable link. */ - if (bfd_link_relocatable (info)) - break; - - if (bpo_greg_owner == NULL) - { - bpo_greg_owner = abfd; - info->base_file = bpo_greg_owner; - } - - if (allocated_gregs_section == NULL) - allocated_gregs_section - = bfd_get_section_by_name (bpo_greg_owner, - MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); - - if (allocated_gregs_section == NULL) - { - allocated_gregs_section - = bfd_make_section_with_flags (bpo_greg_owner, - MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME, - (SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED)); - /* Setting both SEC_ALLOC and SEC_LOAD means the section is - treated like any other section, and we'd get errors for - address overlap with the text section. Let's set none of - those flags, as that is what currently happens for usual - GREG allocations, and that works. */ - if (allocated_gregs_section == NULL - || !bfd_set_section_alignment (bpo_greg_owner, - allocated_gregs_section, - 3)) - return FALSE; - - gregdata = (struct bpo_greg_section_info *) - bfd_zalloc (bpo_greg_owner, sizeof (struct bpo_greg_section_info)); - if (gregdata == NULL) - return FALSE; - mmix_elf_section_data (allocated_gregs_section)->bpo.greg - = gregdata; - } - else if (gregdata == NULL) - gregdata - = mmix_elf_section_data (allocated_gregs_section)->bpo.greg; - - /* Get ourselves some auxiliary info for the BPO-relocs. */ - if (bpodata == NULL) - { - /* No use doing a separate iteration pass to find the upper - limit - just use the number of relocs. */ - bpodata = (struct bpo_reloc_section_info *) - bfd_alloc (bpo_greg_owner, - sizeof (struct bpo_reloc_section_info) - * (sec->reloc_count + 1)); - if (bpodata == NULL) - return FALSE; - mmix_elf_section_data (sec)->bpo.reloc = bpodata; - bpodata->first_base_plus_offset_reloc - = bpodata->bpo_index - = gregdata->n_max_bpo_relocs; - bpodata->bpo_greg_section - = allocated_gregs_section; - bpodata->n_bpo_relocs_this_section = 0; - } - - bpodata->n_bpo_relocs_this_section++; - gregdata->n_max_bpo_relocs++; - - /* We don't get another chance to set this before GC; we've not - set up any hook that runs before GC. */ - gregdata->n_bpo_relocs - = gregdata->n_max_bpo_relocs; - break; - - case R_MMIX_PUSHJ_STUBBABLE: - mmix_elf_section_data (sec)->pjs.n_pushj_relocs++; - break; - } - } - - /* Allocate per-reloc stub storage and initialize it to the max stub - size. */ - if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs != 0) - { - size_t i; - - mmix_elf_section_data (sec)->pjs.stub_size - = bfd_alloc (abfd, mmix_elf_section_data (sec)->pjs.n_pushj_relocs - * sizeof (mmix_elf_section_data (sec) - ->pjs.stub_size[0])); - if (mmix_elf_section_data (sec)->pjs.stub_size == NULL) - return FALSE; - - for (i = 0; i < mmix_elf_section_data (sec)->pjs.n_pushj_relocs; i++) - mmix_elf_section_data (sec)->pjs.stub_size[i] = MAX_PUSHJ_STUB_SIZE; - } - - return TRUE; -} - -/* Look through the relocs for a section during the first phase. */ - -static bfd_boolean -mmix_elf_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - /* First we sort the relocs so that any register relocs come before - expansion-relocs to the same insn. FIXME: Not done for mmo. */ - qsort ((void *) relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), - mmix_elf_sort_relocs); - - /* Do the common part. */ - if (!mmix_elf_check_common_relocs (abfd, info, sec, relocs)) - return FALSE; - - if (bfd_link_relocatable (info)) - return TRUE; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - switch (ELF64_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_MMIX_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_MMIX_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - } - } - - return TRUE; -} - -/* Wrapper for mmix_elf_check_common_relocs, called when linking to mmo. - Copied from elf_link_add_object_symbols. */ - -bfd_boolean -_bfd_mmix_check_all_relocs (bfd *abfd, struct bfd_link_info *info) -{ - 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, - (Elf_Internal_Rela *) NULL, - info->keep_memory); - if (internal_relocs == NULL) - return FALSE; - - ok = mmix_elf_check_common_relocs (abfd, info, o, internal_relocs); - - if (! info->keep_memory) - free (internal_relocs); - - if (! ok) - return FALSE; - } - - return TRUE; -} - -/* Change symbols relative to the reg contents section to instead be to - the register section, and scale them down to correspond to the register - number. */ - -static int -mmix_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - asection *input_sec, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - if (input_sec != NULL - && input_sec->name != NULL - && ELF_ST_TYPE (sym->st_info) != STT_SECTION - && strcmp (input_sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0) - { - sym->st_value /= 8; - sym->st_shndx = SHN_REGISTER; - } - - return 1; -} - -/* We fake a register section that holds values that are register numbers. - Having a SHN_REGISTER and register section translates better to other - formats (e.g. mmo) than for example a STT_REGISTER attribute. - This section faking is based on a construct in elf32-mips.c. */ -static asection mmix_elf_reg_section; -static asymbol mmix_elf_reg_section_symbol; -static asymbol *mmix_elf_reg_section_symbol_ptr; - -/* Handle the special section numbers that a symbol may use. */ - -void -mmix_elf_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym) -{ - elf_symbol_type *elfsym; - - elfsym = (elf_symbol_type *) asym; - switch (elfsym->internal_elf_sym.st_shndx) - { - case SHN_REGISTER: - if (mmix_elf_reg_section.name == NULL) - { - /* Initialize the register section. */ - mmix_elf_reg_section.name = MMIX_REG_SECTION_NAME; - mmix_elf_reg_section.flags = SEC_NO_FLAGS; - mmix_elf_reg_section.output_section = &mmix_elf_reg_section; - mmix_elf_reg_section.symbol = &mmix_elf_reg_section_symbol; - mmix_elf_reg_section.symbol_ptr_ptr = &mmix_elf_reg_section_symbol_ptr; - mmix_elf_reg_section_symbol.name = MMIX_REG_SECTION_NAME; - mmix_elf_reg_section_symbol.flags = BSF_SECTION_SYM; - mmix_elf_reg_section_symbol.section = &mmix_elf_reg_section; - mmix_elf_reg_section_symbol_ptr = &mmix_elf_reg_section_symbol; - } - asym->section = &mmix_elf_reg_section; - break; - - default: - break; - } -} - -/* Given a BFD section, try to locate the corresponding ELF section - index. */ - -static bfd_boolean -mmix_elf_section_from_bfd_section (bfd * abfd ATTRIBUTE_UNUSED, - asection * sec, - int * retval) -{ - if (strcmp (bfd_get_section_name (abfd, sec), MMIX_REG_SECTION_NAME) == 0) - *retval = SHN_REGISTER; - else - return FALSE; - - return TRUE; -} - -/* Hook called by the linker routine which adds symbols from an object - file. We must handle the special SHN_REGISTER section number here. - - We also check that we only have *one* each of the section-start - symbols, since otherwise having two with the same value would cause - them to be "merged", but with the contents serialized. */ - -static bfd_boolean -mmix_elf_add_symbol_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Sym *sym, - const char **namep ATTRIBUTE_UNUSED, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, - bfd_vma *valp ATTRIBUTE_UNUSED) -{ - if (sym->st_shndx == SHN_REGISTER) - { - *secp = bfd_make_section_old_way (abfd, MMIX_REG_SECTION_NAME); - (*secp)->flags |= SEC_LINKER_CREATED; - } - else if ((*namep)[0] == '_' && (*namep)[1] == '_' && (*namep)[2] == '.' - && CONST_STRNEQ (*namep, MMIX_LOC_SECTION_START_SYMBOL_PREFIX)) - { - /* See if we have another one. */ - struct bfd_link_hash_entry *h = bfd_link_hash_lookup (info->hash, - *namep, - FALSE, - FALSE, - FALSE); - - if (h != NULL && h->type != bfd_link_hash_undefined) - { - /* How do we get the asymbol (or really: the filename) from h? - h->u.def.section->owner is NULL. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Error: multiple definition of `%s'; start of %s " - "is set in a earlier linked file\n"), - abfd, *namep, - *namep + strlen (MMIX_LOC_SECTION_START_SYMBOL_PREFIX)); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - return TRUE; -} - -/* We consider symbols matching "L.*:[0-9]+" to be local symbols. */ - -static bfd_boolean -mmix_elf_is_local_label_name (bfd *abfd, const char *name) -{ - const char *colpos; - int digits; - - /* Also include the default local-label definition. */ - if (_bfd_elf_is_local_label_name (abfd, name)) - return TRUE; - - if (*name != 'L') - return FALSE; - - /* If there's no ":", or more than one, it's not a local symbol. */ - colpos = strchr (name, ':'); - if (colpos == NULL || strchr (colpos + 1, ':') != NULL) - return FALSE; - - /* Check that there are remaining characters and that they are digits. */ - if (colpos[1] == 0) - return FALSE; - - digits = strspn (colpos + 1, "0123456789"); - return digits != 0 && colpos[1 + digits] == 0; -} - -/* We get rid of the register section here. */ - -bfd_boolean -mmix_elf_final_link (bfd *abfd, struct bfd_link_info *info) -{ - /* We never output a register section, though we create one for - temporary measures. Check that nobody entered contents into it. */ - asection *reg_section; - - reg_section = bfd_get_section_by_name (abfd, MMIX_REG_SECTION_NAME); - - if (reg_section != NULL) - { - /* FIXME: Pass error state gracefully. */ - if (bfd_get_section_flags (abfd, reg_section) & SEC_HAS_CONTENTS) - _bfd_abort (__FILE__, __LINE__, _("Register section has contents\n")); - - /* Really remove the section, if it hasn't already been done. */ - if (!bfd_section_removed_from_list (abfd, reg_section)) - { - bfd_section_list_remove (abfd, reg_section); - --abfd->section_count; - } - } - - if (! bfd_elf_final_link (abfd, info)) - return FALSE; - - /* Since this section is marked SEC_LINKER_CREATED, it isn't output by - the regular linker machinery. We do it here, like other targets with - special sections. */ - if (info->base_file != NULL) - { - asection *greg_section - = bfd_get_section_by_name ((bfd *) info->base_file, - MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); - if (!bfd_set_section_contents (abfd, - greg_section->output_section, - greg_section->contents, - (file_ptr) greg_section->output_offset, - greg_section->size)) - return FALSE; - } - return TRUE; -} - -/* We need to include the maximum size of PUSHJ-stubs in the initial - section size. This is expected to shrink during linker relaxation. */ - -static void -mmix_set_relaxable_size (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - void *ptr) -{ - struct bfd_link_info *info = ptr; - - /* Make sure we only do this for section where we know we want this, - otherwise we might end up resetting the size of COMMONs. */ - if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0) - return; - - sec->rawsize = sec->size; - sec->size += (mmix_elf_section_data (sec)->pjs.n_pushj_relocs - * MAX_PUSHJ_STUB_SIZE); - - /* For use in relocatable link, we start with a max stubs size. See - mmix_elf_relax_section. */ - if (bfd_link_relocatable (info) && sec->output_section) - mmix_elf_section_data (sec->output_section)->pjs.stubs_size_sum - += (mmix_elf_section_data (sec)->pjs.n_pushj_relocs - * MAX_PUSHJ_STUB_SIZE); -} - -/* Initialize stuff for the linker-generated GREGs to match - R_MMIX_BASE_PLUS_OFFSET relocs seen by the linker. */ - -bfd_boolean -_bfd_mmix_before_linker_allocation (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - asection *bpo_gregs_section; - bfd *bpo_greg_owner; - struct bpo_greg_section_info *gregdata; - size_t n_gregs; - bfd_vma gregs_size; - size_t i; - size_t *bpo_reloc_indexes; - bfd *ibfd; - - /* Set the initial size of sections. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - bfd_map_over_sections (ibfd, mmix_set_relaxable_size, info); - - /* The bpo_greg_owner bfd is supposed to have been set by - mmix_elf_check_relocs when the first R_MMIX_BASE_PLUS_OFFSET is seen. - If there is no such object, there was no R_MMIX_BASE_PLUS_OFFSET. */ - bpo_greg_owner = (bfd *) info->base_file; - if (bpo_greg_owner == NULL) - return TRUE; - - bpo_gregs_section - = bfd_get_section_by_name (bpo_greg_owner, - MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); - - if (bpo_gregs_section == NULL) - return TRUE; - - /* We use the target-data handle in the ELF section data. */ - gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg; - if (gregdata == NULL) - return FALSE; - - n_gregs = gregdata->n_bpo_relocs; - gregdata->n_allocated_bpo_gregs = n_gregs; - - /* When this reaches zero during relaxation, all entries have been - filled in and the size of the linker gregs can be calculated. */ - gregdata->n_remaining_bpo_relocs_this_relaxation_round = n_gregs; - - /* Set the zeroth-order estimate for the GREGs size. */ - gregs_size = n_gregs * 8; - - if (!bfd_set_section_size (bpo_greg_owner, bpo_gregs_section, gregs_size)) - return FALSE; - - /* Allocate and set up the GREG arrays. They're filled in at relaxation - time. Note that we must use the max number ever noted for the array, - since the index numbers were created before GC. */ - gregdata->reloc_request - = bfd_zalloc (bpo_greg_owner, - sizeof (struct bpo_reloc_request) - * gregdata->n_max_bpo_relocs); - - gregdata->bpo_reloc_indexes - = bpo_reloc_indexes - = bfd_alloc (bpo_greg_owner, - gregdata->n_max_bpo_relocs - * sizeof (size_t)); - if (bpo_reloc_indexes == NULL) - return FALSE; - - /* The default order is an identity mapping. */ - for (i = 0; i < gregdata->n_max_bpo_relocs; i++) - { - bpo_reloc_indexes[i] = i; - gregdata->reloc_request[i].bpo_reloc_no = i; - } - - return TRUE; -} - -/* Fill in contents in the linker allocated gregs. Everything is - calculated at this point; we just move the contents into place here. */ - -bfd_boolean -_bfd_mmix_after_linker_allocation (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *link_info) -{ - asection *bpo_gregs_section; - bfd *bpo_greg_owner; - struct bpo_greg_section_info *gregdata; - size_t n_gregs; - size_t i, j; - size_t lastreg; - bfd_byte *contents; - - /* The bpo_greg_owner bfd is supposed to have been set by mmix_elf_check_relocs - when the first R_MMIX_BASE_PLUS_OFFSET is seen. If there is no such - object, there was no R_MMIX_BASE_PLUS_OFFSET. */ - bpo_greg_owner = (bfd *) link_info->base_file; - if (bpo_greg_owner == NULL) - return TRUE; - - bpo_gregs_section - = bfd_get_section_by_name (bpo_greg_owner, - MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); - - /* This can't happen without DSO handling. When DSOs are handled - without any R_MMIX_BASE_PLUS_OFFSET seen, there will be no such - section. */ - if (bpo_gregs_section == NULL) - return TRUE; - - /* We use the target-data handle in the ELF section data. */ - - gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg; - if (gregdata == NULL) - return FALSE; - - n_gregs = gregdata->n_allocated_bpo_gregs; - - bpo_gregs_section->contents - = contents = bfd_alloc (bpo_greg_owner, bpo_gregs_section->size); - if (contents == NULL) - return FALSE; - - /* Sanity check: If these numbers mismatch, some relocation has not been - accounted for and the rest of gregdata is probably inconsistent. - It's a bug, but it's more helpful to identify it than segfaulting - below. */ - if (gregdata->n_remaining_bpo_relocs_this_relaxation_round - != gregdata->n_bpo_relocs) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("Internal inconsistency: remaining %lu != max %lu.\n\ - Please report this bug."), - (unsigned long) gregdata->n_remaining_bpo_relocs_this_relaxation_round, - (unsigned long) gregdata->n_bpo_relocs); - return FALSE; - } - - for (lastreg = 255, i = 0, j = 0; j < n_gregs; i++) - if (gregdata->reloc_request[i].regindex != lastreg) - { - bfd_put_64 (bpo_greg_owner, gregdata->reloc_request[i].value, - contents + j * 8); - lastreg = gregdata->reloc_request[i].regindex; - j++; - } - - return TRUE; -} - -/* Sort valid relocs to come before non-valid relocs, then on increasing - value. */ - -static int -bpo_reloc_request_sort_fn (const void * p1, const void * p2) -{ - const struct bpo_reloc_request *r1 = (const struct bpo_reloc_request *) p1; - const struct bpo_reloc_request *r2 = (const struct bpo_reloc_request *) p2; - - /* Primary function is validity; non-valid relocs sorted after valid - ones. */ - if (r1->valid != r2->valid) - return r2->valid - r1->valid; - - /* Then sort on value. Don't simplify and return just the difference of - the values: the upper bits of the 64-bit value would be truncated on - a host with 32-bit ints. */ - if (r1->value != r2->value) - return r1->value > r2->value ? 1 : -1; - - /* As a last re-sort, use the relocation number, so we get a stable - sort. The *addresses* aren't stable since items are swapped during - sorting. It depends on the qsort implementation if this actually - happens. */ - return r1->bpo_reloc_no > r2->bpo_reloc_no - ? 1 : (r1->bpo_reloc_no < r2->bpo_reloc_no ? -1 : 0); -} - -/* For debug use only. Dumps the global register allocations resulting - from base-plus-offset relocs. */ - -void -mmix_dump_bpo_gregs (struct bfd_link_info *link_info, - void (*pf) (const char *fmt, ...)) -{ - bfd *bpo_greg_owner; - asection *bpo_gregs_section; - struct bpo_greg_section_info *gregdata; - unsigned int i; - - if (link_info == NULL || link_info->base_file == NULL) - return; - - bpo_greg_owner = (bfd *) link_info->base_file; - - bpo_gregs_section - = bfd_get_section_by_name (bpo_greg_owner, - MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME); - - if (bpo_gregs_section == NULL) - return; - - gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg; - if (gregdata == NULL) - return; - - if (pf == NULL) - pf = _bfd_error_handler; - - /* These format strings are not translated. They are for debug purposes - only and never displayed to an end user. Should they escape, we - surely want them in original. */ - (*pf) (" n_bpo_relocs: %u\n n_max_bpo_relocs: %u\n n_remain...round: %u\n\ - n_allocated_bpo_gregs: %u\n", gregdata->n_bpo_relocs, - gregdata->n_max_bpo_relocs, - gregdata->n_remaining_bpo_relocs_this_relaxation_round, - gregdata->n_allocated_bpo_gregs); - - if (gregdata->reloc_request) - for (i = 0; i < gregdata->n_max_bpo_relocs; i++) - (*pf) ("%4u (%4u)/%4u#%u: 0x%08lx%08lx r: %3u o: %3u\n", - i, - (gregdata->bpo_reloc_indexes != NULL - ? gregdata->bpo_reloc_indexes[i] : (size_t) -1), - gregdata->reloc_request[i].bpo_reloc_no, - gregdata->reloc_request[i].valid, - - (unsigned long) (gregdata->reloc_request[i].value >> 32), - (unsigned long) gregdata->reloc_request[i].value, - gregdata->reloc_request[i].regindex, - gregdata->reloc_request[i].offset); -} - -/* This links all R_MMIX_BASE_PLUS_OFFSET relocs into a special array, and - when the last such reloc is done, an index-array is sorted according to - the values and iterated over to produce register numbers (indexed by 0 - from the first allocated register number) and offsets for use in real - relocation. (N.B.: Relocatable runs are handled, not just punted.) - - PUSHJ stub accounting is also done here. - - Symbol- and reloc-reading infrastructure copied from elf-m10200.c. */ - -static bfd_boolean -mmix_elf_relax_section (bfd *abfd, - asection *sec, - struct bfd_link_info *link_info, - bfd_boolean *again) -{ - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *irel, *irelend; - asection *bpo_gregs_section = NULL; - struct bpo_greg_section_info *gregdata; - struct bpo_reloc_section_info *bpodata - = mmix_elf_section_data (sec)->bpo.reloc; - /* The initialization is to quiet compiler warnings. The value is to - spot a missing actual initialization. */ - size_t bpono = (size_t) -1; - size_t pjsno = 0; - Elf_Internal_Sym *isymbuf = NULL; - bfd_size_type size = sec->rawsize ? sec->rawsize : sec->size; - - mmix_elf_section_data (sec)->pjs.stubs_size_sum = 0; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything if this section does not have relocs, or - if this is not a code section. */ - if ((sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 - || (sec->flags & SEC_CODE) == 0 - || (sec->flags & SEC_LINKER_CREATED) != 0 - /* If no R_MMIX_BASE_PLUS_OFFSET relocs and no PUSHJ-stub relocs, - then nothing to do. */ - || (bpodata == NULL - && mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - - if (bpodata != NULL) - { - bpo_gregs_section = bpodata->bpo_greg_section; - gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg; - bpono = bpodata->first_base_plus_offset_reloc; - } - else - gregdata = NULL; - - /* Get a copy of the native relocations. */ - internal_relocs - = _bfd_elf_link_read_relocs (abfd, sec, NULL, - (Elf_Internal_Rela *) NULL, - link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - struct elf_link_hash_entry *h = NULL; - - /* We only process two relocs. */ - if (ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_BASE_PLUS_OFFSET - && ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_PUSHJ_STUBBABLE) - continue; - - /* We process relocs in a distinctly different way when this is a - relocatable link (for one, we don't look at symbols), so we avoid - mixing its code with that for the "normal" relaxation. */ - if (bfd_link_relocatable (link_info)) - { - /* The only transformation in a relocatable link is to generate - a full stub at the location of the stub calculated for the - input section, if the relocated stub location, the end of the - output section plus earlier stubs, cannot be reached. Thus - relocatable linking can only lead to worse code, but it still - works. */ - if (ELF64_R_TYPE (irel->r_info) == R_MMIX_PUSHJ_STUBBABLE) - { - /* If we can reach the end of the output-section and beyond - any current stubs, then we don't need a stub for this - reloc. The relaxed order of output stub allocation may - not exactly match the straightforward order, so we always - assume presence of output stubs, which will allow - relaxation only on relocations indifferent to the - presence of output stub allocations for other relocations - and thus the order of output stub allocation. */ - if (bfd_check_overflow (complain_overflow_signed, - 19, - 0, - bfd_arch_bits_per_address (abfd), - /* Output-stub location. */ - sec->output_section->rawsize - + (mmix_elf_section_data (sec - ->output_section) - ->pjs.stubs_size_sum) - /* Location of this PUSHJ reloc. */ - - (sec->output_offset + irel->r_offset) - /* Don't count *this* stub twice. */ - - (mmix_elf_section_data (sec) - ->pjs.stub_size[pjsno] - + MAX_PUSHJ_STUB_SIZE)) - == bfd_reloc_ok) - mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0; - - mmix_elf_section_data (sec)->pjs.stubs_size_sum - += mmix_elf_section_data (sec)->pjs.stub_size[pjsno]; - - pjsno++; - } - - continue; - } - - /* Get the value of the symbol referred to by the reloc. */ - if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - /* Read this BFD's local symbols if we haven't already. */ - if (isymbuf == NULL) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == 0) - goto error_return; - } - - isym = isymbuf + ELF64_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - else - { - unsigned long indx; - - /* An external symbol. */ - indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - if (h->root.type == bfd_link_hash_undefweak) - /* FIXME: for R_MMIX_PUSHJ_STUBBABLE, there are alternatives to - the canonical value 0 for an unresolved weak symbol to - consider: as the debug-friendly approach, resolve to "abort" - (or a port-specific function), or as the space-friendly - approach resolve to the next instruction (like some other - ports, notably ARM and AArch64). These alternatives require - matching code in mmix_elf_perform_relocation or its caller. */ - symval = 0; - else if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - else - { - /* This appears to be a reference to an undefined symbol. Just - ignore it--it will be caught by the regular reloc processing. - We need to keep BPO reloc accounting consistent, though - else we'll abort instead of emitting an error message. */ - if (ELF64_R_TYPE (irel->r_info) == R_MMIX_BASE_PLUS_OFFSET - && gregdata != NULL) - { - gregdata->n_remaining_bpo_relocs_this_relaxation_round--; - bpono++; - } - continue; - } - } - - if (ELF64_R_TYPE (irel->r_info) == (int) R_MMIX_PUSHJ_STUBBABLE) - { - bfd_vma value = symval + irel->r_addend; - bfd_vma dot - = (sec->output_section->vma - + sec->output_offset - + irel->r_offset); - bfd_vma stubaddr - = (sec->output_section->vma - + sec->output_offset - + size - + mmix_elf_section_data (sec)->pjs.stubs_size_sum); - - if ((value & 3) == 0 - && bfd_check_overflow (complain_overflow_signed, - 19, - 0, - bfd_arch_bits_per_address (abfd), - value - dot - - (value > dot - ? mmix_elf_section_data (sec) - ->pjs.stub_size[pjsno] - : 0)) - == bfd_reloc_ok) - /* If the reloc fits, no stub is needed. */ - mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0; - else - /* Maybe we can get away with just a JMP insn? */ - if ((value & 3) == 0 - && bfd_check_overflow (complain_overflow_signed, - 27, - 0, - bfd_arch_bits_per_address (abfd), - value - stubaddr - - (value > dot - ? mmix_elf_section_data (sec) - ->pjs.stub_size[pjsno] - 4 - : 0)) - == bfd_reloc_ok) - /* Yep, account for a stub consisting of a single JMP insn. */ - mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 4; - else - /* Nope, go for the full insn stub. It doesn't seem useful to - emit the intermediate sizes; those will only be useful for - a >64M program assuming contiguous code. */ - mmix_elf_section_data (sec)->pjs.stub_size[pjsno] - = MAX_PUSHJ_STUB_SIZE; - - mmix_elf_section_data (sec)->pjs.stubs_size_sum - += mmix_elf_section_data (sec)->pjs.stub_size[pjsno]; - pjsno++; - continue; - } - - /* We're looking at a R_MMIX_BASE_PLUS_OFFSET reloc. */ - - gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono]].value - = symval + irel->r_addend; - gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono++]].valid = TRUE; - gregdata->n_remaining_bpo_relocs_this_relaxation_round--; - } - - /* Check if that was the last BPO-reloc. If so, sort the values and - calculate how many registers we need to cover them. Set the size of - the linker gregs, and if the number of registers changed, indicate - that we need to relax some more because we have more work to do. */ - if (gregdata != NULL - && gregdata->n_remaining_bpo_relocs_this_relaxation_round == 0) - { - size_t i; - bfd_vma prev_base; - size_t regindex; - - /* First, reset the remaining relocs for the next round. */ - gregdata->n_remaining_bpo_relocs_this_relaxation_round - = gregdata->n_bpo_relocs; - - qsort (gregdata->reloc_request, - gregdata->n_max_bpo_relocs, - sizeof (struct bpo_reloc_request), - bpo_reloc_request_sort_fn); - - /* Recalculate indexes. When we find a change (however unlikely - after the initial iteration), we know we need to relax again, - since items in the GREG-array are sorted by increasing value and - stored in the relaxation phase. */ - for (i = 0; i < gregdata->n_max_bpo_relocs; i++) - if (gregdata->bpo_reloc_indexes[gregdata->reloc_request[i].bpo_reloc_no] - != i) - { - gregdata->bpo_reloc_indexes[gregdata->reloc_request[i].bpo_reloc_no] - = i; - *again = TRUE; - } - - /* Allocate register numbers (indexing from 0). Stop at the first - non-valid reloc. */ - for (i = 0, regindex = 0, prev_base = gregdata->reloc_request[0].value; - i < gregdata->n_bpo_relocs; - i++) - { - if (gregdata->reloc_request[i].value > prev_base + 255) - { - regindex++; - prev_base = gregdata->reloc_request[i].value; - } - gregdata->reloc_request[i].regindex = regindex; - gregdata->reloc_request[i].offset - = gregdata->reloc_request[i].value - prev_base; - } - - /* If it's not the same as the last time, we need to relax again, - because the size of the section has changed. I'm not sure we - actually need to do any adjustments since the shrinking happens - at the start of this section, but better safe than sorry. */ - if (gregdata->n_allocated_bpo_gregs != regindex + 1) - { - gregdata->n_allocated_bpo_gregs = regindex + 1; - *again = TRUE; - } - - bpo_gregs_section->size = (regindex + 1) * 8; - } - - if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) - { - if (! link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } - - BFD_ASSERT(pjsno == mmix_elf_section_data (sec)->pjs.n_pushj_relocs); - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - if (sec->size < size + mmix_elf_section_data (sec)->pjs.stubs_size_sum) - abort (); - - if (sec->size > size + mmix_elf_section_data (sec)->pjs.stubs_size_sum) - { - sec->size = size + mmix_elf_section_data (sec)->pjs.stubs_size_sum; - *again = TRUE; - } - - return TRUE; - - error_return: - if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) - free (isymbuf); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - return FALSE; -} - -#define ELF_ARCH bfd_arch_mmix -#define ELF_MACHINE_CODE EM_MMIX - -/* According to mmix-doc page 36 (paragraph 45), this should be (1LL << 48LL). - However, that's too much for something somewhere in the linker part of - BFD; perhaps the start-address has to be a non-zero multiple of this - number, or larger than this number. The symptom is that the linker - complains: "warning: allocated section `.text' not in segment". We - settle for 64k; the page-size used in examples is 8k. - #define ELF_MAXPAGESIZE 0x10000 - - Unfortunately, this causes excessive padding in the supposedly small - for-education programs that are the expected usage (where people would - inspect output). We stick to 256 bytes just to have *some* default - alignment. */ -#define ELF_MAXPAGESIZE 0x100 - -#define TARGET_BIG_SYM mmix_elf64_vec -#define TARGET_BIG_NAME "elf64-mmix" - -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto mmix_info_to_howto_rela -#define elf_backend_relocate_section mmix_elf_relocate_section -#define elf_backend_gc_mark_hook mmix_elf_gc_mark_hook - -#define elf_backend_link_output_symbol_hook \ - mmix_elf_link_output_symbol_hook -#define elf_backend_add_symbol_hook mmix_elf_add_symbol_hook - -#define elf_backend_check_relocs mmix_elf_check_relocs -#define elf_backend_symbol_processing mmix_elf_symbol_processing -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) - -#define bfd_elf64_bfd_copy_link_hash_symbol_type \ - _bfd_generic_copy_link_hash_symbol_type - -#define bfd_elf64_bfd_is_local_label_name \ - mmix_elf_is_local_label_name - -#define elf_backend_may_use_rel_p 0 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_default_use_rela_p 1 - -#define elf_backend_can_gc_sections 1 -#define elf_backend_section_from_bfd_section \ - mmix_elf_section_from_bfd_section - -#define bfd_elf64_new_section_hook mmix_elf_new_section_hook -#define bfd_elf64_bfd_final_link mmix_elf_final_link -#define bfd_elf64_bfd_relax_section mmix_elf_relax_section - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-ppc.c b/sdcc/support/sdbinutils/bfd/elf64-ppc.c deleted file mode 100644 index 5cbb03553..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-ppc.c +++ /dev/null @@ -1,15833 +0,0 @@ -/* PowerPC64-specific support for 64-bit ELF. - Copyright (C) 1999-2018 Free Software Foundation, Inc. - Written by Linus Nordberg, Swox AB , - based on elf32-ppc.c by Ian Lance Taylor. - Largely rewritten by Alan Modra. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - - -/* The 64-bit PowerPC ELF ABI may be found at - http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and - http://www.linuxbase.org/spec/ELF/ppc64/spec/book1.html */ - -#include "sysdep.h" -#include -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/ppc64.h" -#include "elf64-ppc.h" -#include "dwarf2.h" - -static bfd_reloc_status_type ppc64_elf_ha_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_branch_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_brtaken_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_sectoff_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_sectoff_ha_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_toc_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_toc_ha_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_toc64_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type ppc64_elf_unhandled_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_vma opd_entry_value - (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean); - -#define TARGET_LITTLE_SYM powerpc_elf64_le_vec -#define TARGET_LITTLE_NAME "elf64-powerpcle" -#define TARGET_BIG_SYM powerpc_elf64_vec -#define TARGET_BIG_NAME "elf64-powerpc" -#define ELF_ARCH bfd_arch_powerpc -#define ELF_TARGET_ID PPC64_ELF_DATA -#define ELF_MACHINE_CODE EM_PPC64 -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x10000 -#define elf_info_to_howto ppc64_elf_info_to_howto - -#define elf_backend_want_got_sym 0 -#define elf_backend_want_plt_sym 0 -#define elf_backend_plt_alignment 3 -#define elf_backend_plt_not_loaded 1 -#define elf_backend_got_header_size 8 -#define elf_backend_want_dynrelro 1 -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_rela_normal 1 -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_default_execstack 0 - -#define bfd_elf64_mkobject ppc64_elf_mkobject -#define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup -#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data -#define bfd_elf64_bfd_print_private_bfd_data ppc64_elf_print_private_bfd_data -#define bfd_elf64_new_section_hook ppc64_elf_new_section_hook -#define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create -#define bfd_elf64_get_synthetic_symtab ppc64_elf_get_synthetic_symtab -#define bfd_elf64_bfd_link_just_syms ppc64_elf_link_just_syms -#define bfd_elf64_bfd_gc_sections ppc64_elf_gc_sections - -#define elf_backend_object_p ppc64_elf_object_p -#define elf_backend_grok_prstatus ppc64_elf_grok_prstatus -#define elf_backend_grok_psinfo ppc64_elf_grok_psinfo -#define elf_backend_write_core_note ppc64_elf_write_core_note -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections -#define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol -#define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook -#define elf_backend_check_directives ppc64_elf_before_check_relocs -#define elf_backend_notice_as_needed ppc64_elf_notice_as_needed -#define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup -#define elf_backend_check_relocs ppc64_elf_check_relocs -#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible -#define elf_backend_gc_keep ppc64_elf_gc_keep -#define elf_backend_gc_mark_dynamic_ref ppc64_elf_gc_mark_dynamic_ref -#define elf_backend_gc_mark_hook ppc64_elf_gc_mark_hook -#define elf_backend_adjust_dynamic_symbol ppc64_elf_adjust_dynamic_symbol -#define elf_backend_hide_symbol ppc64_elf_hide_symbol -#define elf_backend_maybe_function_sym ppc64_elf_maybe_function_sym -#define elf_backend_always_size_sections ppc64_elf_func_desc_adjust -#define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections -#define elf_backend_hash_symbol ppc64_elf_hash_symbol -#define elf_backend_init_index_section _bfd_elf_init_2_index_sections -#define elf_backend_action_discarded ppc64_elf_action_discarded -#define elf_backend_relocate_section ppc64_elf_relocate_section -#define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol -#define elf_backend_reloc_type_class ppc64_elf_reloc_type_class -#define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections -#define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook -#define elf_backend_special_sections ppc64_elf_special_sections -#define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute -#define elf_backend_merge_symbol ppc64_elf_merge_symbol -#define elf_backend_get_reloc_section bfd_get_section_by_name - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" - -/* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8) - -/* The initial size of the plt reserved for the dynamic linker. */ -#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16) - -/* Offsets to some stack save slots. */ -#define STK_LR 16 -#define STK_TOC(htab) (htab->opd_abi ? 40 : 24) -/* This one is dodgy. ELFv2 does not have a linker word, so use the - CR save slot. Used only by optimised __tls_get_addr call stub, - relying on __tls_get_addr_opt not saving CR.. */ -#define STK_LINKER(htab) (htab->opd_abi ? 32 : 8) - -/* TOC base pointers offset from start of TOC. */ -#define TOC_BASE_OFF 0x8000 -/* TOC base alignment. */ -#define TOC_BASE_ALIGN 256 - -/* Offset of tp and dtp pointers from start of TLS block. */ -#define TP_OFFSET 0x7000 -#define DTP_OFFSET 0x8000 - -/* .plt call stub instructions. The normal stub is like this, but - sometimes the .plt entry crosses a 64k boundary and we need to - insert an addi to adjust r11. */ -#define STD_R2_0R1 0xf8410000 /* std %r2,0+40(%r1) */ -#define ADDIS_R11_R2 0x3d620000 /* addis %r11,%r2,xxx@ha */ -#define LD_R12_0R11 0xe98b0000 /* ld %r12,xxx+0@l(%r11) */ -#define MTCTR_R12 0x7d8903a6 /* mtctr %r12 */ -#define LD_R2_0R11 0xe84b0000 /* ld %r2,xxx+8@l(%r11) */ -#define LD_R11_0R11 0xe96b0000 /* ld %r11,xxx+16@l(%r11) */ -#define BCTR 0x4e800420 /* bctr */ - -#define CRSETEQ 0x4c421242 /* crset 4*%cr0+%eq */ -#define BEQCTRM 0x4dc20420 /* beqctr- */ -#define BEQCTRLM 0x4dc20421 /* beqctrl- */ - -#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */ -#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ -#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ - -#define XOR_R2_R12_R12 0x7d826278 /* xor %r2,%r12,%r12 */ -#define ADD_R11_R11_R2 0x7d6b1214 /* add %r11,%r11,%r2 */ -#define XOR_R11_R12_R12 0x7d8b6278 /* xor %r11,%r12,%r12 */ -#define ADD_R2_R2_R11 0x7c425a14 /* add %r2,%r2,%r11 */ -#define CMPLDI_R2_0 0x28220000 /* cmpldi %r2,0 */ -#define BNECTR 0x4ca20420 /* bnectr+ */ -#define BNECTR_P4 0x4ce20420 /* bnectr+ */ - -#define LD_R12_0R2 0xe9820000 /* ld %r12,xxx+0(%r2) */ -#define LD_R11_0R2 0xe9620000 /* ld %r11,xxx+0(%r2) */ -#define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ - -#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ -#define LD_R2_0R12 0xe84c0000 /* ld %r2,0(%r12) */ -#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */ - -#define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */ -#define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */ -#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ -#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ -#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ - -/* __glink_PLTresolve stub instructions. We enter with the index in R0. */ -#define GLINK_PLTRESOLVE_SIZE(htab) \ - (8u + (htab->opd_abi ? 11 * 4 : 14 * 4) \ - + (!htab->params->speculate_indirect_jumps ? 2 * 4 : 0)) - /* 0: */ - /* .quad plt0-1f */ - /* __glink: */ -#define MFLR_R12 0x7d8802a6 /* mflr %12 */ -#define BCL_20_31 0x429f0005 /* bcl 20,31,1f */ - /* 1: */ -#define MFLR_R11 0x7d6802a6 /* mflr %11 */ - /* ld %2,(0b-1b)(%11) */ -#define MTLR_R12 0x7d8803a6 /* mtlr %12 */ -#define ADD_R11_R2_R11 0x7d625a14 /* add %11,%2,%11 */ - /* ld %12,0(%11) */ - /* ld %2,8(%11) */ - /* mtctr %12 */ - /* ld %11,16(%11) */ - /* bctr */ -#define MFLR_R0 0x7c0802a6 /* mflr %r0 */ -#define MTLR_R0 0x7c0803a6 /* mtlr %r0 */ -#define SUB_R12_R12_R11 0x7d8b6050 /* subf %r12,%r11,%r12 */ -#define ADDI_R0_R12 0x380c0000 /* addi %r0,%r12,0 */ -#define SRDI_R0_R0_2 0x7800f082 /* rldicl %r0,%r0,62,2 */ - -/* Pad with this. */ -#define NOP 0x60000000 - -/* Some other nops. */ -#define CROR_151515 0x4def7b82 -#define CROR_313131 0x4ffffb82 - -/* .glink entries for the first 32k functions are two instructions. */ -#define LI_R0_0 0x38000000 /* li %r0,0 */ -#define B_DOT 0x48000000 /* b . */ - -/* After that, we need two instructions to load the index, followed by - a branch. */ -#define LIS_R0_0 0x3c000000 /* lis %r0,0 */ -#define ORI_R0_R0_0 0x60000000 /* ori %r0,%r0,0 */ - -/* Instructions used by the save and restore reg functions. */ -#define STD_R0_0R1 0xf8010000 /* std %r0,0(%r1) */ -#define STD_R0_0R12 0xf80c0000 /* std %r0,0(%r12) */ -#define LD_R0_0R1 0xe8010000 /* ld %r0,0(%r1) */ -#define LD_R0_0R12 0xe80c0000 /* ld %r0,0(%r12) */ -#define STFD_FR0_0R1 0xd8010000 /* stfd %fr0,0(%r1) */ -#define LFD_FR0_0R1 0xc8010000 /* lfd %fr0,0(%r1) */ -#define LI_R12_0 0x39800000 /* li %r12,0 */ -#define STVX_VR0_R12_R0 0x7c0c01ce /* stvx %v0,%r12,%r0 */ -#define LVX_VR0_R12_R0 0x7c0c00ce /* lvx %v0,%r12,%r0 */ -#define MTLR_R0 0x7c0803a6 /* mtlr %r0 */ -#define BLR 0x4e800020 /* blr */ - -/* Since .opd is an array of descriptors and each entry will end up - with identical R_PPC64_RELATIVE relocs, there is really no need to - propagate .opd relocs; The dynamic linker should be taught to - relocate .opd without reloc entries. */ -#ifndef NO_OPD_RELOCS -#define NO_OPD_RELOCS 0 -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) -#endif - -static inline int -abiversion (bfd *abfd) -{ - return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI; -} - -static inline void -set_abiversion (bfd *abfd, int ver) -{ - elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI; - elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI; -} - -#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1) - -/* Relocation HOWTO's. */ -static reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC64_max]; - -static reloc_howto_type ppc64_elf_howto_raw[] = { - /* This reloc does nothing. */ - HOWTO (R_PPC64_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 32 bit relocation. */ - HOWTO (R_PPC64_ADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 26 bit branch; the lower two bits must be zero. - FIXME: we don't check that, we just clear them. */ - HOWTO (R_PPC64_ADDR24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03fffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A standard 16 bit relocation. */ - HOWTO (R_PPC64_ADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit relocation without overflow. */ - HOWTO (R_PPC64_ADDR16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 of an address. */ - HOWTO (R_PPC64_ADDR16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Bits 16-31 of an address, plus 1 if the contents of the low 16 - bits, treated as a signed number, is negative. */ - HOWTO (R_PPC64_ADDR16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_ADDR16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 16 bit branch; the lower two bits must be zero. - FIXME: we don't check that, we just clear them. */ - HOWTO (R_PPC64_ADDR14, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_branch_reloc, /* special_function */ - "R_PPC64_ADDR14", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000fffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 16 bit branch, for which bit 10 should be set to - indicate that the branch is expected to be taken. The lower two - bits must be zero. */ - HOWTO (R_PPC64_ADDR14_BRTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_brtaken_reloc, /* special_function */ - "R_PPC64_ADDR14_BRTAKEN",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000fffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* An absolute 16 bit branch, for which bit 10 should be set to - indicate that the branch is not expected to be taken. The lower - two bits must be zero. */ - HOWTO (R_PPC64_ADDR14_BRNTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_brtaken_reloc, /* special_function */ - "R_PPC64_ADDR14_BRNTAKEN",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000fffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A relative 26 bit branch; the lower two bits must be zero. */ - HOWTO (R_PPC64_REL24, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_branch_reloc, /* special_function */ - "R_PPC64_REL24", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03fffffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 16 bit branch; the lower two bits must be zero. */ - HOWTO (R_PPC64_REL14, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_branch_reloc, /* special_function */ - "R_PPC64_REL14", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000fffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 16 bit branch. Bit 10 should be set to indicate that - the branch is expected to be taken. The lower two bits must be - zero. */ - HOWTO (R_PPC64_REL14_BRTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_brtaken_reloc, /* special_function */ - "R_PPC64_REL14_BRTAKEN", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000fffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A relative 16 bit branch. Bit 10 should be set to indicate that - the branch is not expected to be taken. The lower two bits must - be zero. */ - HOWTO (R_PPC64_REL14_BRNTAKEN, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_brtaken_reloc, /* special_function */ - "R_PPC64_REL14_BRNTAKEN",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000fffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16, but referring to the GOT table entry for the - symbol. */ - HOWTO (R_PPC64_GOT16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_LO, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_PPC64_GOT16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_HI, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_PPC64_GOT16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_HA, but referring to the GOT table entry for - the symbol. */ - HOWTO (R_PPC64_GOT16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed,/* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is used only by the dynamic linker. The symbol should exist - both in the object being run and in some shared library. The - dynamic linker copies the data addressed by the symbol from the - shared library into the object, because the object being - run has to have the data at some particular address. */ - HOWTO (R_PPC64_COPY, /* type */ - 0, /* rightshift */ - 0, /* this one is variable size */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_COPY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR64, but used when setting global offset table - entries. */ - HOWTO (R_PPC64_GLOB_DAT, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Created by the link editor. Marks a procedure linkage table - entry for a symbol. */ - HOWTO (R_PPC64_JMP_SLOT, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_JMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used only by the dynamic linker. When the object is run, this - doubleword64 is set to the load address of the object, plus the - addend. */ - HOWTO (R_PPC64_RELATIVE, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_RELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR32, but may be unaligned. */ - HOWTO (R_PPC64_UADDR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_UADDR32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16, but may be unaligned. */ - HOWTO (R_PPC64_UADDR16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_UADDR16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32-bit PC relative. */ - HOWTO (R_PPC64_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 32-bit relocation to the symbol's procedure linkage table. */ - HOWTO (R_PPC64_PLT32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLT32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32-bit PC relative relocation to the symbol's procedure linkage table. - FIXME: R_PPC64_PLTREL32 not supported. */ - HOWTO (R_PPC64_PLTREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_LO, but referring to the PLT table entry for - the symbol. */ - HOWTO (R_PPC64_PLT16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLT16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_HI, but referring to the PLT table entry for - the symbol. */ - HOWTO (R_PPC64_PLT16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLT16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_HA, but referring to the PLT table entry for - the symbol. */ - HOWTO (R_PPC64_PLT16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLT16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit section relative relocation. */ - HOWTO (R_PPC64_SECTOFF, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_sectoff_reloc, /* special_function */ - "R_PPC64_SECTOFF", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_SECTOFF, but no overflow warning. */ - HOWTO (R_PPC64_SECTOFF_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_sectoff_reloc, /* special_function */ - "R_PPC64_SECTOFF_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit upper half section relative relocation. */ - HOWTO (R_PPC64_SECTOFF_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_sectoff_reloc, /* special_function */ - "R_PPC64_SECTOFF_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16-bit upper half adjusted section relative relocation. */ - HOWTO (R_PPC64_SECTOFF_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_sectoff_ha_reloc, /* special_function */ - "R_PPC64_SECTOFF_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_REL24 without touching the two least significant bits. */ - HOWTO (R_PPC64_REL30, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 30, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_REL30", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffffffc, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Relocs in the 64-bit PowerPC ELF ABI, not in the 32-bit ABI. */ - - /* A standard 64-bit relocation. */ - HOWTO (R_PPC64_ADDR64, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The bits 32-47 of an address. */ - HOWTO (R_PPC64_ADDR16_HIGHER, /* type */ - 32, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The bits 32-47 of an address, plus 1 if the contents of the low - 16 bits, treated as a signed number, is negative. */ - HOWTO (R_PPC64_ADDR16_HIGHERA, /* type */ - 32, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_ADDR16_HIGHERA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The bits 48-63 of an address. */ - HOWTO (R_PPC64_ADDR16_HIGHEST,/* type */ - 48, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The bits 48-63 of an address, plus 1 if the contents of the low - 16 bits, treated as a signed number, is negative. */ - HOWTO (R_PPC64_ADDR16_HIGHESTA,/* type */ - 48, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_ADDR16_HIGHESTA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like ADDR64, but may be unaligned. */ - HOWTO (R_PPC64_UADDR64, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_UADDR64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64-bit relative relocation. */ - HOWTO (R_PPC64_REL64, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_REL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 64-bit relocation to the symbol's procedure linkage table. */ - HOWTO (R_PPC64_PLT64, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLT64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64-bit PC relative relocation to the symbol's procedure linkage - table. */ - /* FIXME: R_PPC64_PLTREL64 not supported. */ - HOWTO (R_PPC64_PLTREL64, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTREL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit TOC-relative relocation. */ - - /* R_PPC64_TOC16 47 half16* S + A - .TOC. */ - HOWTO (R_PPC64_TOC16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_toc_reloc, /* special_function */ - "R_PPC64_TOC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit TOC-relative relocation without overflow. */ - - /* R_PPC64_TOC16_LO 48 half16 #lo (S + A - .TOC.) */ - HOWTO (R_PPC64_TOC16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_toc_reloc, /* special_function */ - "R_PPC64_TOC16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit TOC-relative relocation, high 16 bits. */ - - /* R_PPC64_TOC16_HI 49 half16 #hi (S + A - .TOC.) */ - HOWTO (R_PPC64_TOC16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_toc_reloc, /* special_function */ - "R_PPC64_TOC16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit TOC-relative relocation, high 16 bits, plus 1 if the - contents of the low 16 bits, treated as a signed number, is - negative. */ - - /* R_PPC64_TOC16_HA 50 half16 #ha (S + A - .TOC.) */ - HOWTO (R_PPC64_TOC16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_toc_ha_reloc, /* special_function */ - "R_PPC64_TOC16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64-bit relocation; insert value of TOC base (.TOC.). */ - - /* R_PPC64_TOC 51 doubleword64 .TOC. */ - HOWTO (R_PPC64_TOC, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_toc64_reloc, /* special_function */ - "R_PPC64_TOC", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_GOT16, but also informs the link editor that the - value to relocate may (!) refer to a PLT entry which the link - editor (a) may replace with the symbol value. If the link editor - is unable to fully resolve the symbol, it may (b) create a PLT - entry and store the address to the new PLT entry in the GOT. - This permits lazy resolution of function symbols at run time. - The link editor may also skip all of this and just (c) emit a - R_PPC64_GLOB_DAT to tie the symbol to the GOT entry. */ - /* FIXME: R_PPC64_PLTGOT16 not implemented. */ - HOWTO (R_PPC64_PLTGOT16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTGOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_PLTGOT16, but without overflow. */ - /* FIXME: R_PPC64_PLTGOT16_LO not implemented. */ - HOWTO (R_PPC64_PLTGOT16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTGOT16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address. */ - /* FIXME: R_PPC64_PLTGOT16_HI not implemented. */ - HOWTO (R_PPC64_PLTGOT16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTGOT16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address, plus - 1 if the contents of the low 16 bits, treated as a signed number, - is negative. */ - /* FIXME: R_PPC64_PLTGOT16_HA not implemented. */ - HOWTO (R_PPC64_PLTGOT16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTGOT16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16, but for instructions with a DS field. */ - HOWTO (R_PPC64_ADDR16_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_LO, but for instructions with a DS field. */ - HOWTO (R_PPC64_ADDR16_LO_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_LO_DS",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_GOT16, but for instructions with a DS field. */ - HOWTO (R_PPC64_GOT16_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_GOT16_LO, but for instructions with a DS field. */ - HOWTO (R_PPC64_GOT16_LO_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_PLT16_LO, but for instructions with a DS field. */ - HOWTO (R_PPC64_PLT16_LO_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLT16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_SECTOFF, but for instructions with a DS field. */ - HOWTO (R_PPC64_SECTOFF_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_sectoff_reloc, /* special_function */ - "R_PPC64_SECTOFF_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field. */ - HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_sectoff_reloc, /* special_function */ - "R_PPC64_SECTOFF_LO_DS",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_TOC16, but for instructions with a DS field. */ - HOWTO (R_PPC64_TOC16_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_toc_reloc, /* special_function */ - "R_PPC64_TOC16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_TOC16_LO, but for instructions with a DS field. */ - HOWTO (R_PPC64_TOC16_LO_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_toc_reloc, /* special_function */ - "R_PPC64_TOC16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_PLTGOT16, but for instructions with a DS field. */ - /* FIXME: R_PPC64_PLTGOT16_DS not implemented. */ - HOWTO (R_PPC64_PLTGOT16_DS, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTGOT16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_PLTGOT16_LO, but for instructions with a DS field. */ - /* FIXME: R_PPC64_PLTGOT16_LO not implemented. */ - HOWTO (R_PPC64_PLTGOT16_LO_DS,/* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_PLTGOT16_LO_DS",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marker relocs for TLS. */ - HOWTO (R_PPC64_TLS, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_TLS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC64_TLSGD, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_TLSGD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC64_TLSLD, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_TLSLD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC64_TOCSAVE, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_TOCSAVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes the load module index of the load module that contains the - definition of its TLS sym. */ - HOWTO (R_PPC64_DTPMOD64, - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPMOD64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a dtv-relative displacement, the difference between the value - of sym+add and the base address of the thread-local storage block that - contains the definition of sym, minus 0x8000. */ - HOWTO (R_PPC64_DTPREL64, - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit dtprel reloc. */ - HOWTO (R_PPC64_DTPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16, but no overflow. */ - HOWTO (R_PPC64_DTPREL16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC64_DTPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC64_DTPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_HI, but next higher group of 16 bits. */ - HOWTO (R_PPC64_DTPREL16_HIGHER, - 32, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_HIGHER, but adjust for low 16 bits. */ - HOWTO (R_PPC64_DTPREL16_HIGHERA, - 32, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HIGHERA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_HIGHER, but next higher group of 16 bits. */ - HOWTO (R_PPC64_DTPREL16_HIGHEST, - 48, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_HIGHEST, but adjust for low 16 bits. */ - HOWTO (R_PPC64_DTPREL16_HIGHESTA, - 48, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HIGHESTA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16, but for insns with a DS field. */ - HOWTO (R_PPC64_DTPREL16_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like DTPREL16_DS, but no overflow. */ - HOWTO (R_PPC64_DTPREL16_LO_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Computes a tp-relative displacement, the difference between the value of - sym+add and the value of the thread pointer (r13). */ - HOWTO (R_PPC64_TPREL64, - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit tprel reloc. */ - HOWTO (R_PPC64_TPREL16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16, but no overflow. */ - HOWTO (R_PPC64_TPREL16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC64_TPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC64_TPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_HI, but next higher group of 16 bits. */ - HOWTO (R_PPC64_TPREL16_HIGHER, - 32, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_HIGHER, but adjust for low 16 bits. */ - HOWTO (R_PPC64_TPREL16_HIGHERA, - 32, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HIGHERA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_HIGHER, but next higher group of 16 bits. */ - HOWTO (R_PPC64_TPREL16_HIGHEST, - 48, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_HIGHEST, but adjust for low 16 bits. */ - HOWTO (R_PPC64_TPREL16_HIGHESTA, - 48, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HIGHESTA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16, but for insns with a DS field. */ - HOWTO (R_PPC64_TPREL16_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like TPREL16_DS, but no overflow. */ - HOWTO (R_PPC64_TPREL16_LO_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates two contiguous entries in the GOT to hold a tls_index structure, - with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset - to the first entry relative to the TOC base (r2). */ - HOWTO (R_PPC64_GOT_TLSGD16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSGD16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSGD16, but no overflow. */ - HOWTO (R_PPC64_GOT_TLSGD16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSGD16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC64_GOT_TLSGD16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSGD16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC64_GOT_TLSGD16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSGD16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates two contiguous entries in the GOT to hold a tls_index structure, - with values (sym+add)@dtpmod and zero, and computes the offset to the - first entry relative to the TOC base (r2). */ - HOWTO (R_PPC64_GOT_TLSLD16, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSLD16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSLD16, but no overflow. */ - HOWTO (R_PPC64_GOT_TLSLD16_LO, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSLD16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */ - HOWTO (R_PPC64_GOT_TLSLD16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSLD16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC64_GOT_TLSLD16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TLSLD16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes - the offset to the entry relative to the TOC base (r2). */ - HOWTO (R_PPC64_GOT_DTPREL16_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_DTPREL16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_DTPREL16_DS, but no overflow. */ - HOWTO (R_PPC64_GOT_DTPREL16_LO_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_DTPREL16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_DTPREL16_LO_DS, but next higher group of 16 bits. */ - HOWTO (R_PPC64_GOT_DTPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_DTPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC64_GOT_DTPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_DTPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the - offset to the entry relative to the TOC base (r2). */ - HOWTO (R_PPC64_GOT_TPREL16_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TPREL16_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TPREL16_DS, but no overflow. */ - HOWTO (R_PPC64_GOT_TPREL16_LO_DS, - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TPREL16_LO_DS", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TPREL16_LO_DS, but next higher group of 16 bits. */ - HOWTO (R_PPC64_GOT_TPREL16_HI, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TPREL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like GOT_TPREL16_HI, but adjust for low 16 bits. */ - HOWTO (R_PPC64_GOT_TPREL16_HA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_GOT_TPREL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC64_JMP_IREL, /* type */ - 0, /* rightshift */ - 0, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_JMP_IREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_PPC64_IRELATIVE, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_IRELATIVE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 16 bit relative relocation. */ - HOWTO (R_PPC64_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_REL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 16 bit relative relocation without overflow. */ - HOWTO (R_PPC64_REL16_LO, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_REL16_LO", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The high order 16 bits of a relative address. */ - HOWTO (R_PPC64_REL16_HI, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_REL16_HI", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* The high order 16 bits of a relative address, plus 1 if the contents of - the low 16 bits, treated as a signed number, is negative. */ - HOWTO (R_PPC64_REL16_HA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_REL16_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Like R_PPC64_REL16_HA but for split field in addpcis. */ - HOWTO (R_PPC64_REL16DX_HA, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_REL16DX_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1fffc1, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A split-field reloc for addpcis, non-relative (gas internal use only). */ - HOWTO (R_PPC64_16DX_HA, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_16DX_HA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x1fffc1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_HI, but no overflow. */ - HOWTO (R_PPC64_ADDR16_HIGH, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR16_HIGH", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_ADDR16_HA, but no overflow. */ - HOWTO (R_PPC64_ADDR16_HIGHA, /* type */ - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_ha_reloc, /* special_function */ - "R_PPC64_ADDR16_HIGHA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_DTPREL16_HI, but no overflow. */ - HOWTO (R_PPC64_DTPREL16_HIGH, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HIGH", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_DTPREL16_HA, but no overflow. */ - HOWTO (R_PPC64_DTPREL16_HIGHA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_DTPREL16_HIGHA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_TPREL16_HI, but no overflow. */ - HOWTO (R_PPC64_TPREL16_HIGH, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HIGH", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like R_PPC64_TPREL16_HA, but no overflow. */ - HOWTO (R_PPC64_TPREL16_HIGHA, - 16, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - ppc64_elf_unhandled_reloc, /* special_function */ - "R_PPC64_TPREL16_HIGHA", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Marker reloc on ELFv2 large-model function entry. */ - HOWTO (R_PPC64_ENTRY, - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Like ADDR64, but use local entry point of function. */ - HOWTO (R_PPC64_ADDR64_LOCAL, /* type */ - 0, /* rightshift */ - 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_PPC64_ADDR64_LOCAL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ONES (64), /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy. */ - HOWTO (R_PPC64_GNU_VTINHERIT, /* 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 */ - "R_PPC64_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_PPC64_GNU_VTENTRY, /* 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 */ - "R_PPC64_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - - -/* Initialize the ppc64_elf_howto_table, so that linear accesses can - be done. */ - -static void -ppc_howto_init (void) -{ - unsigned int i, type; - - for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++) - { - type = ppc64_elf_howto_raw[i].type; - BFD_ASSERT (type < ARRAY_SIZE (ppc64_elf_howto_table)); - ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i]; - } -} - -static reloc_howto_type * -ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - enum elf_ppc64_reloc_type r = R_PPC64_NONE; - - if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) - /* Initialize howto table if needed. */ - ppc_howto_init (); - - switch (code) - { - default: - return NULL; - - case BFD_RELOC_NONE: r = R_PPC64_NONE; - break; - case BFD_RELOC_32: r = R_PPC64_ADDR32; - break; - case BFD_RELOC_PPC_BA26: r = R_PPC64_ADDR24; - break; - case BFD_RELOC_16: r = R_PPC64_ADDR16; - break; - case BFD_RELOC_LO16: r = R_PPC64_ADDR16_LO; - break; - case BFD_RELOC_HI16: r = R_PPC64_ADDR16_HI; - break; - case BFD_RELOC_PPC64_ADDR16_HIGH: r = R_PPC64_ADDR16_HIGH; - break; - case BFD_RELOC_HI16_S: r = R_PPC64_ADDR16_HA; - break; - case BFD_RELOC_PPC64_ADDR16_HIGHA: r = R_PPC64_ADDR16_HIGHA; - break; - case BFD_RELOC_PPC_BA16: r = R_PPC64_ADDR14; - break; - case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC64_ADDR14_BRTAKEN; - break; - case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC64_ADDR14_BRNTAKEN; - break; - case BFD_RELOC_PPC_B26: r = R_PPC64_REL24; - break; - case BFD_RELOC_PPC_B16: r = R_PPC64_REL14; - break; - case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC64_REL14_BRTAKEN; - break; - case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC64_REL14_BRNTAKEN; - break; - case BFD_RELOC_16_GOTOFF: r = R_PPC64_GOT16; - break; - case BFD_RELOC_LO16_GOTOFF: r = R_PPC64_GOT16_LO; - break; - case BFD_RELOC_HI16_GOTOFF: r = R_PPC64_GOT16_HI; - break; - case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC64_GOT16_HA; - break; - case BFD_RELOC_PPC_COPY: r = R_PPC64_COPY; - break; - case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC64_GLOB_DAT; - break; - case BFD_RELOC_32_PCREL: r = R_PPC64_REL32; - break; - case BFD_RELOC_32_PLTOFF: r = R_PPC64_PLT32; - break; - case BFD_RELOC_32_PLT_PCREL: r = R_PPC64_PLTREL32; - break; - case BFD_RELOC_LO16_PLTOFF: r = R_PPC64_PLT16_LO; - break; - case BFD_RELOC_HI16_PLTOFF: r = R_PPC64_PLT16_HI; - break; - case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC64_PLT16_HA; - break; - case BFD_RELOC_16_BASEREL: r = R_PPC64_SECTOFF; - break; - case BFD_RELOC_LO16_BASEREL: r = R_PPC64_SECTOFF_LO; - break; - case BFD_RELOC_HI16_BASEREL: r = R_PPC64_SECTOFF_HI; - break; - case BFD_RELOC_HI16_S_BASEREL: r = R_PPC64_SECTOFF_HA; - break; - case BFD_RELOC_CTOR: r = R_PPC64_ADDR64; - break; - case BFD_RELOC_64: r = R_PPC64_ADDR64; - break; - case BFD_RELOC_PPC64_HIGHER: r = R_PPC64_ADDR16_HIGHER; - break; - case BFD_RELOC_PPC64_HIGHER_S: r = R_PPC64_ADDR16_HIGHERA; - break; - case BFD_RELOC_PPC64_HIGHEST: r = R_PPC64_ADDR16_HIGHEST; - break; - case BFD_RELOC_PPC64_HIGHEST_S: r = R_PPC64_ADDR16_HIGHESTA; - break; - case BFD_RELOC_64_PCREL: r = R_PPC64_REL64; - break; - case BFD_RELOC_64_PLTOFF: r = R_PPC64_PLT64; - break; - case BFD_RELOC_64_PLT_PCREL: r = R_PPC64_PLTREL64; - break; - case BFD_RELOC_PPC_TOC16: r = R_PPC64_TOC16; - break; - case BFD_RELOC_PPC64_TOC16_LO: r = R_PPC64_TOC16_LO; - break; - case BFD_RELOC_PPC64_TOC16_HI: r = R_PPC64_TOC16_HI; - break; - case BFD_RELOC_PPC64_TOC16_HA: r = R_PPC64_TOC16_HA; - break; - case BFD_RELOC_PPC64_TOC: r = R_PPC64_TOC; - break; - case BFD_RELOC_PPC64_PLTGOT16: r = R_PPC64_PLTGOT16; - break; - case BFD_RELOC_PPC64_PLTGOT16_LO: r = R_PPC64_PLTGOT16_LO; - break; - case BFD_RELOC_PPC64_PLTGOT16_HI: r = R_PPC64_PLTGOT16_HI; - break; - case BFD_RELOC_PPC64_PLTGOT16_HA: r = R_PPC64_PLTGOT16_HA; - break; - case BFD_RELOC_PPC64_ADDR16_DS: r = R_PPC64_ADDR16_DS; - break; - case BFD_RELOC_PPC64_ADDR16_LO_DS: r = R_PPC64_ADDR16_LO_DS; - break; - case BFD_RELOC_PPC64_GOT16_DS: r = R_PPC64_GOT16_DS; - break; - case BFD_RELOC_PPC64_GOT16_LO_DS: r = R_PPC64_GOT16_LO_DS; - break; - case BFD_RELOC_PPC64_PLT16_LO_DS: r = R_PPC64_PLT16_LO_DS; - break; - case BFD_RELOC_PPC64_SECTOFF_DS: r = R_PPC64_SECTOFF_DS; - break; - case BFD_RELOC_PPC64_SECTOFF_LO_DS: r = R_PPC64_SECTOFF_LO_DS; - break; - case BFD_RELOC_PPC64_TOC16_DS: r = R_PPC64_TOC16_DS; - break; - case BFD_RELOC_PPC64_TOC16_LO_DS: r = R_PPC64_TOC16_LO_DS; - break; - case BFD_RELOC_PPC64_PLTGOT16_DS: r = R_PPC64_PLTGOT16_DS; - break; - case BFD_RELOC_PPC64_PLTGOT16_LO_DS: r = R_PPC64_PLTGOT16_LO_DS; - break; - case BFD_RELOC_PPC_TLS: r = R_PPC64_TLS; - break; - case BFD_RELOC_PPC_TLSGD: r = R_PPC64_TLSGD; - break; - case BFD_RELOC_PPC_TLSLD: r = R_PPC64_TLSLD; - break; - case BFD_RELOC_PPC_DTPMOD: r = R_PPC64_DTPMOD64; - break; - case BFD_RELOC_PPC_TPREL16: r = R_PPC64_TPREL16; - break; - case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC64_TPREL16_LO; - break; - case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC64_TPREL16_HI; - break; - case BFD_RELOC_PPC64_TPREL16_HIGH: r = R_PPC64_TPREL16_HIGH; - break; - case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC64_TPREL16_HA; - break; - case BFD_RELOC_PPC64_TPREL16_HIGHA: r = R_PPC64_TPREL16_HIGHA; - break; - case BFD_RELOC_PPC_TPREL: r = R_PPC64_TPREL64; - break; - case BFD_RELOC_PPC_DTPREL16: r = R_PPC64_DTPREL16; - break; - case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC64_DTPREL16_LO; - break; - case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC64_DTPREL16_HI; - break; - case BFD_RELOC_PPC64_DTPREL16_HIGH: r = R_PPC64_DTPREL16_HIGH; - break; - case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC64_DTPREL16_HA; - break; - case BFD_RELOC_PPC64_DTPREL16_HIGHA: r = R_PPC64_DTPREL16_HIGHA; - break; - case BFD_RELOC_PPC_DTPREL: r = R_PPC64_DTPREL64; - break; - case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC64_GOT_TLSGD16; - break; - case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC64_GOT_TLSGD16_LO; - break; - case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC64_GOT_TLSGD16_HI; - break; - case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC64_GOT_TLSGD16_HA; - break; - case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC64_GOT_TLSLD16; - break; - case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC64_GOT_TLSLD16_LO; - break; - case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC64_GOT_TLSLD16_HI; - break; - case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC64_GOT_TLSLD16_HA; - break; - case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC64_GOT_TPREL16_DS; - break; - case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC64_GOT_TPREL16_LO_DS; - break; - case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC64_GOT_TPREL16_HI; - break; - case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC64_GOT_TPREL16_HA; - break; - case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC64_GOT_DTPREL16_DS; - break; - case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC64_GOT_DTPREL16_LO_DS; - break; - case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC64_GOT_DTPREL16_HI; - break; - case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC64_GOT_DTPREL16_HA; - break; - case BFD_RELOC_PPC64_TPREL16_DS: r = R_PPC64_TPREL16_DS; - break; - case BFD_RELOC_PPC64_TPREL16_LO_DS: r = R_PPC64_TPREL16_LO_DS; - break; - case BFD_RELOC_PPC64_TPREL16_HIGHER: r = R_PPC64_TPREL16_HIGHER; - break; - case BFD_RELOC_PPC64_TPREL16_HIGHERA: r = R_PPC64_TPREL16_HIGHERA; - break; - case BFD_RELOC_PPC64_TPREL16_HIGHEST: r = R_PPC64_TPREL16_HIGHEST; - break; - case BFD_RELOC_PPC64_TPREL16_HIGHESTA: r = R_PPC64_TPREL16_HIGHESTA; - break; - case BFD_RELOC_PPC64_DTPREL16_DS: r = R_PPC64_DTPREL16_DS; - break; - case BFD_RELOC_PPC64_DTPREL16_LO_DS: r = R_PPC64_DTPREL16_LO_DS; - break; - case BFD_RELOC_PPC64_DTPREL16_HIGHER: r = R_PPC64_DTPREL16_HIGHER; - break; - case BFD_RELOC_PPC64_DTPREL16_HIGHERA: r = R_PPC64_DTPREL16_HIGHERA; - break; - case BFD_RELOC_PPC64_DTPREL16_HIGHEST: r = R_PPC64_DTPREL16_HIGHEST; - break; - case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: r = R_PPC64_DTPREL16_HIGHESTA; - break; - case BFD_RELOC_16_PCREL: r = R_PPC64_REL16; - break; - case BFD_RELOC_LO16_PCREL: r = R_PPC64_REL16_LO; - break; - case BFD_RELOC_HI16_PCREL: r = R_PPC64_REL16_HI; - break; - case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA; - break; - case BFD_RELOC_PPC_16DX_HA: r = R_PPC64_16DX_HA; - break; - case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA; - break; - case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY; - break; - case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL; - break; - case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT; - break; - case BFD_RELOC_VTABLE_ENTRY: r = R_PPC64_GNU_VTENTRY; - break; - } - - return ppc64_elf_howto_table[r]; -}; - -static reloc_howto_type * -ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++) - if (ppc64_elf_howto_raw[i].name != NULL - && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0) - return &ppc64_elf_howto_raw[i]; - - return NULL; -} - -/* Set the howto pointer for a PowerPC ELF reloc. */ - -static void -ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int type; - - /* Initialize howto table if needed. */ - if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) - ppc_howto_init (); - - type = ELF64_R_TYPE (dst->r_info); - if (type >= ARRAY_SIZE (ppc64_elf_howto_table)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) type); - type = R_PPC64_NONE; - } - cache_ptr->howto = ppc64_elf_howto_table[type]; -} - -/* Handle the R_PPC64_ADDR16_HA and similar relocs. */ - -static bfd_reloc_status_type -ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - enum elf_ppc64_reloc_type r_type; - long insn; - bfd_size_type octets; - bfd_vma value; - - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* Adjust the addend for sign extension of the low 16 bits. - We won't actually be using the low 16 bits, so trashing them - doesn't matter. */ - reloc_entry->addend += 0x8000; - r_type = reloc_entry->howto->type; - if (r_type != R_PPC64_REL16DX_HA) - return bfd_reloc_continue; - - value = 0; - if (!bfd_is_com_section (symbol->section)) - value = symbol->value; - value += (reloc_entry->addend - + symbol->section->output_offset - + symbol->section->output_section->vma); - value -= (reloc_entry->address - + input_section->output_offset - + input_section->output_section->vma); - value = (bfd_signed_vma) value >> 16; - - octets = reloc_entry->address * bfd_octets_per_byte (abfd); - insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); - insn &= ~0x1fffc1; - insn |= (value & 0xffc1) | ((value & 0x3e) << 15); - bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); - if (value + 0x8000 > 0xffff) - return bfd_reloc_overflow; - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - if (strcmp (symbol->section->name, ".opd") == 0 - && (symbol->section->owner->flags & DYNAMIC) == 0) - { - bfd_vma dest = opd_entry_value (symbol->section, - symbol->value + reloc_entry->addend, - NULL, NULL, FALSE); - if (dest != (bfd_vma) -1) - reloc_entry->addend = dest - (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset); - } - else - { - elf_symbol_type *elfsym = (elf_symbol_type *) symbol; - - if (symbol->section->owner != abfd - && symbol->section->owner != NULL - && abiversion (symbol->section->owner) >= 2) - { - unsigned int i; - - for (i = 0; i < symbol->section->owner->symcount; ++i) - { - asymbol *symdef = symbol->section->owner->outsymbols[i]; - - if (strcmp (symdef->name, symbol->name) == 0) - { - elfsym = (elf_symbol_type *) symdef; - break; - } - } - } - reloc_entry->addend - += PPC64_LOCAL_ENTRY_OFFSET (elfsym->internal_elf_sym.st_other); - } - return bfd_reloc_continue; -} - -static bfd_reloc_status_type -ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - long insn; - enum elf_ppc64_reloc_type r_type; - bfd_size_type octets; - /* Assume 'at' branch hints. */ - bfd_boolean is_isa_v2 = TRUE; - - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - octets = reloc_entry->address * bfd_octets_per_byte (abfd); - insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); - insn &= ~(0x01 << 21); - r_type = reloc_entry->howto->type; - if (r_type == R_PPC64_ADDR14_BRTAKEN - || r_type == R_PPC64_REL14_BRTAKEN) - insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */ - - if (is_isa_v2) - { - /* Set 'a' bit. This is 0b00010 in BO field for branch - on CR(BI) insns (BO == 001at or 011at), and 0b01000 - for branch on CTR insns (BO == 1a00t or 1a01t). */ - if ((insn & (0x14 << 21)) == (0x04 << 21)) - insn |= 0x02 << 21; - else if ((insn & (0x14 << 21)) == (0x10 << 21)) - insn |= 0x08 << 21; - else - goto out; - } - else - { - bfd_vma target = 0; - bfd_vma from; - - if (!bfd_is_com_section (symbol->section)) - target = symbol->value; - target += symbol->section->output_section->vma; - target += symbol->section->output_offset; - target += reloc_entry->addend; - - from = (reloc_entry->address - + input_section->output_offset - + input_section->output_section->vma); - - /* Invert 'y' bit if not the default. */ - if ((bfd_signed_vma) (target - from) < 0) - insn ^= 0x01 << 21; - } - bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); - out: - return ppc64_elf_branch_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); -} - -static bfd_reloc_status_type -ppc64_elf_sectoff_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* Subtract the symbol section base address. */ - reloc_entry->addend -= symbol->section->output_section->vma; - return bfd_reloc_continue; -} - -static bfd_reloc_status_type -ppc64_elf_sectoff_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - /* Subtract the symbol section base address. */ - reloc_entry->addend -= symbol->section->output_section->vma; - - /* Adjust the addend for sign extension of the low 16 bits. */ - reloc_entry->addend += 0x8000; - return bfd_reloc_continue; -} - -static bfd_reloc_status_type -ppc64_elf_toc_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - bfd_vma TOCstart; - - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - TOCstart = _bfd_get_gp_value (input_section->output_section->owner); - if (TOCstart == 0) - TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner); - - /* Subtract the TOC base address. */ - reloc_entry->addend -= TOCstart + TOC_BASE_OFF; - return bfd_reloc_continue; -} - -static bfd_reloc_status_type -ppc64_elf_toc_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - bfd_vma TOCstart; - - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - TOCstart = _bfd_get_gp_value (input_section->output_section->owner); - if (TOCstart == 0) - TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner); - - /* Subtract the TOC base address. */ - reloc_entry->addend -= TOCstart + TOC_BASE_OFF; - - /* Adjust the addend for sign extension of the low 16 bits. */ - reloc_entry->addend += 0x8000; - return bfd_reloc_continue; -} - -static bfd_reloc_status_type -ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - bfd_vma TOCstart; - bfd_size_type octets; - - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - TOCstart = _bfd_get_gp_value (input_section->output_section->owner); - if (TOCstart == 0) - TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner); - - octets = reloc_entry->address * bfd_octets_per_byte (abfd); - bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets); - return bfd_reloc_ok; -} - -static bfd_reloc_status_type -ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, - bfd *output_bfd, char **error_message) -{ - /* If this is a relocatable link (output_bfd test tells us), just - call the generic function. Any adjustment will be done at final - link time. */ - if (output_bfd != NULL) - return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, error_message); - - if (error_message != NULL) - { - static char buf[60]; - sprintf (buf, "generic linker can't handle %s", - reloc_entry->howto->name); - *error_message = buf; - } - return bfd_reloc_dangerous; -} - -/* Track GOT entries needed for a given symbol. We might need more - than one got entry per symbol. */ -struct got_entry -{ - struct got_entry *next; - - /* The symbol addend that we'll be placing in the GOT. */ - bfd_vma addend; - - /* Unlike other ELF targets, we use separate GOT entries for the same - symbol referenced from different input files. This is to support - automatic multiple TOC/GOT sections, where the TOC base can vary - from one input file to another. After partitioning into TOC groups - we merge entries within the group. - - Point to the BFD owning this GOT entry. */ - bfd *owner; - - /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD, - TLS_TPREL or TLS_DTPREL for tls entries. */ - unsigned char tls_type; - - /* Non-zero if got.ent points to real entry. */ - unsigned char is_indirect; - - /* Reference count until size_dynamic_sections, GOT offset thereafter. */ - union - { - bfd_signed_vma refcount; - bfd_vma offset; - struct got_entry *ent; - } got; -}; - -/* The same for PLT. */ -struct plt_entry -{ - struct plt_entry *next; - - bfd_vma addend; - - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } plt; -}; - -struct ppc64_elf_obj_tdata -{ - struct elf_obj_tdata elf; - - /* Shortcuts to dynamic linker sections. */ - asection *got; - asection *relgot; - - /* Used during garbage collection. We attach global symbols defined - on removed .opd entries to this section so that the sym is removed. */ - asection *deleted_section; - - /* TLS local dynamic got entry handling. Support for multiple GOT - sections means we potentially need one of these for each input bfd. */ - struct got_entry tlsld_got; - - union { - /* A copy of relocs before they are modified for --emit-relocs. */ - Elf_Internal_Rela *relocs; - - /* Section contents. */ - bfd_byte *contents; - } opd; - - /* Nonzero if this bfd has small toc/got relocs, ie. that expect - the reloc to be in the range -32768 to 32767. */ - unsigned int has_small_toc_reloc : 1; - - /* Set if toc/got ha relocs detected not using r2, or lo reloc - instruction not one we handle. */ - unsigned int unexpected_toc_insn : 1; -}; - -#define ppc64_elf_tdata(bfd) \ - ((struct ppc64_elf_obj_tdata *) (bfd)->tdata.any) - -#define ppc64_tlsld_got(bfd) \ - (&ppc64_elf_tdata (bfd)->tlsld_got) - -#define is_ppc64_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_object_id (bfd) == PPC64_ELF_DATA) - -/* Override the generic function because we store some extras. */ - -static bfd_boolean -ppc64_elf_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct ppc64_elf_obj_tdata), - PPC64_ELF_DATA); -} - -/* Fix bad default arch selected for a 64 bit input bfd when the - default is 32 bit. Also select arch based on apuinfo. */ - -static bfd_boolean -ppc64_elf_object_p (bfd *abfd) -{ - if (!abfd->arch_info->the_default) - return TRUE; - - if (abfd->arch_info->bits_per_word == 32) - { - Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); - - if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS64) - { - /* Relies on arch after 32 bit default being 64 bit default. */ - abfd->arch_info = abfd->arch_info->next; - BFD_ASSERT (abfd->arch_info->bits_per_word == 64); - } - } - return _bfd_elf_ppc_set_arch (abfd); -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - size_t offset, size; - - if (note->descsz != 504) - return FALSE; - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32); - - /* pr_reg */ - offset = 112; - size = 384; - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - if (note->descsz != 136) - return FALSE; - - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 24); - 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); - - return TRUE; -} - -static char * -ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, - ...) -{ - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - { - char data[136]; - va_list ap; - - va_start (ap, note_type); - memset (data, 0, sizeof (data)); - strncpy (data + 40, va_arg (ap, const char *), 16); - strncpy (data + 56, va_arg (ap, const char *), 80); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - - case NT_PRSTATUS: - { - char data[504]; - va_list ap; - long pid; - int cursig; - const void *greg; - - va_start (ap, note_type); - memset (data, 0, 112); - pid = va_arg (ap, long); - bfd_put_32 (abfd, pid, data + 32); - cursig = va_arg (ap, int); - bfd_put_16 (abfd, cursig, data + 12); - greg = va_arg (ap, const void *); - memcpy (data + 112, greg, 384); - memset (data + 496, 0, 8); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - } -} - -/* Add extra PPC sections. */ - -static const struct bfd_elf_special_section ppc64_elf_special_sections[]= -{ - { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, 0 }, - { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".toc"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".toc1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { STRING_COMMA_LEN (".tocbss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } -}; - -enum _ppc64_sec_type { - sec_normal = 0, - sec_opd = 1, - sec_toc = 2 -}; - -struct _ppc64_elf_section_data -{ - struct bfd_elf_section_data elf; - - union - { - /* An array with one entry for each opd function descriptor, - and some spares since opd entries may be either 16 or 24 bytes. */ -#define OPD_NDX(OFF) ((OFF) >> 4) - struct _opd_sec_data - { - /* Points to the function code section for local opd entries. */ - asection **func_sec; - - /* After editing .opd, adjust references to opd local syms. */ - long *adjust; - } opd; - - /* An array for toc sections, indexed by offset/8. */ - struct _toc_sec_data - { - /* Specifies the relocation symbol index used at a given toc offset. */ - unsigned *symndx; - - /* And the relocation addend. */ - bfd_vma *add; - } toc; - } u; - - enum _ppc64_sec_type sec_type:2; - - /* Flag set when small branches are detected. Used to - select suitable defaults for the stub group size. */ - unsigned int has_14bit_branch:1; -}; - -#define ppc64_elf_section_data(sec) \ - ((struct _ppc64_elf_section_data *) elf_section_data (sec)) - -static bfd_boolean -ppc64_elf_new_section_hook (bfd *abfd, asection *sec) -{ - if (!sec->used_by_bfd) - { - struct _ppc64_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); - - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; - } - - return _bfd_elf_new_section_hook (abfd, sec); -} - -static struct _opd_sec_data * -get_opd_info (asection * sec) -{ - if (sec != NULL - && ppc64_elf_section_data (sec) != NULL - && ppc64_elf_section_data (sec)->sec_type == sec_opd) - return &ppc64_elf_section_data (sec)->u.opd; - return NULL; -} - -/* Parameters for the qsort hook. */ -static bfd_boolean synthetic_relocatable; -static asection *synthetic_opd; - -/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */ - -static int -compare_symbols (const void *ap, const void *bp) -{ - const asymbol *a = * (const asymbol **) ap; - const asymbol *b = * (const asymbol **) bp; - - /* Section symbols first. */ - if ((a->flags & BSF_SECTION_SYM) && !(b->flags & BSF_SECTION_SYM)) - return -1; - if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM)) - return 1; - - /* then .opd symbols. */ - if (synthetic_opd != NULL) - { - if (strcmp (a->section->name, ".opd") == 0 - && strcmp (b->section->name, ".opd") != 0) - return -1; - if (strcmp (a->section->name, ".opd") != 0 - && strcmp (b->section->name, ".opd") == 0) - return 1; - } - - /* then other code symbols. */ - if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) - == (SEC_CODE | SEC_ALLOC) - && (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) - != (SEC_CODE | SEC_ALLOC)) - return -1; - - if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) - != (SEC_CODE | SEC_ALLOC) - && (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) - == (SEC_CODE | SEC_ALLOC)) - return 1; - - if (synthetic_relocatable) - { - if (a->section->id < b->section->id) - return -1; - - if (a->section->id > b->section->id) - return 1; - } - - if (a->value + a->section->vma < b->value + b->section->vma) - return -1; - - if (a->value + a->section->vma > b->value + b->section->vma) - return 1; - - /* For syms with the same value, prefer strong dynamic global function - syms over other syms. */ - if ((a->flags & BSF_GLOBAL) != 0 && (b->flags & BSF_GLOBAL) == 0) - return -1; - - if ((a->flags & BSF_GLOBAL) == 0 && (b->flags & BSF_GLOBAL) != 0) - return 1; - - if ((a->flags & BSF_FUNCTION) != 0 && (b->flags & BSF_FUNCTION) == 0) - return -1; - - if ((a->flags & BSF_FUNCTION) == 0 && (b->flags & BSF_FUNCTION) != 0) - return 1; - - if ((a->flags & BSF_WEAK) == 0 && (b->flags & BSF_WEAK) != 0) - return -1; - - if ((a->flags & BSF_WEAK) != 0 && (b->flags & BSF_WEAK) == 0) - return 1; - - if ((a->flags & BSF_DYNAMIC) != 0 && (b->flags & BSF_DYNAMIC) == 0) - return -1; - - if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0) - return 1; - - return a > b; -} - -/* Search SYMS for a symbol of the given VALUE. */ - -static asymbol * -sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value) -{ - long mid; - - if (id == (unsigned) -1) - { - while (lo < hi) - { - mid = (lo + hi) >> 1; - if (syms[mid]->value + syms[mid]->section->vma < value) - lo = mid + 1; - else if (syms[mid]->value + syms[mid]->section->vma > value) - hi = mid; - else - return syms[mid]; - } - } - else - { - while (lo < hi) - { - mid = (lo + hi) >> 1; - if (syms[mid]->section->id < id) - lo = mid + 1; - else if (syms[mid]->section->id > id) - hi = mid; - else if (syms[mid]->value < value) - lo = mid + 1; - else if (syms[mid]->value > value) - hi = mid; - else - return syms[mid]; - } - } - return NULL; -} - -static bfd_boolean -section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr) -{ - bfd_vma vma = *(bfd_vma *) ptr; - return ((section->flags & SEC_ALLOC) != 0 - && section->vma <= vma - && vma < section->vma + section->size); -} - -/* Create synthetic symbols, effectively restoring "dot-symbol" function - entry syms. Also generate @plt symbols for the glink branch table. - Returns count of synthetic symbols in RET or -1 on error. */ - -static long -ppc64_elf_get_synthetic_symtab (bfd *abfd, - long static_count, asymbol **static_syms, - long dyn_count, asymbol **dyn_syms, - asymbol **ret) -{ - asymbol *s; - long i; - long count; - char *names; - long symcount, codesecsym, codesecsymend, secsymend, opdsymend; - asection *opd = NULL; - bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; - asymbol **syms; - int abi = abiversion (abfd); - - *ret = NULL; - - if (abi < 2) - { - opd = bfd_get_section_by_name (abfd, ".opd"); - if (opd == NULL && abi == 1) - return 0; - } - - syms = NULL; - codesecsym = 0; - codesecsymend = 0; - secsymend = 0; - opdsymend = 0; - symcount = 0; - if (opd != NULL) - { - symcount = static_count; - if (!relocatable) - symcount += dyn_count; - if (symcount == 0) - return 0; - - syms = bfd_malloc ((symcount + 1) * sizeof (*syms)); - if (syms == NULL) - return -1; - - if (!relocatable && static_count != 0 && dyn_count != 0) - { - /* Use both symbol tables. */ - memcpy (syms, static_syms, static_count * sizeof (*syms)); - memcpy (syms + static_count, dyn_syms, - (dyn_count + 1) * sizeof (*syms)); - } - else if (!relocatable && static_count == 0) - memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms)); - else - memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms)); - - synthetic_relocatable = relocatable; - synthetic_opd = opd; - qsort (syms, symcount, sizeof (*syms), compare_symbols); - - if (!relocatable && symcount > 1) - { - long j; - /* Trim duplicate syms, since we may have merged the normal and - dynamic symbols. Actually, we only care about syms that have - different values, so trim any with the same value. */ - for (i = 1, j = 1; i < symcount; ++i) - if (syms[i - 1]->value + syms[i - 1]->section->vma - != syms[i]->value + syms[i]->section->vma) - syms[j++] = syms[i]; - symcount = j; - } - - i = 0; - /* Note that here and in compare_symbols we can't compare opd and - sym->section directly. With separate debug info files, the - symbols will be extracted from the debug file while abfd passed - to this function is the real binary. */ - if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0) - ++i; - codesecsym = i; - - for (; i < symcount; ++i) - if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC - | SEC_THREAD_LOCAL)) - != (SEC_CODE | SEC_ALLOC)) - || (syms[i]->flags & BSF_SECTION_SYM) == 0) - break; - codesecsymend = i; - - for (; i < symcount; ++i) - if ((syms[i]->flags & BSF_SECTION_SYM) == 0) - break; - secsymend = i; - - for (; i < symcount; ++i) - if (strcmp (syms[i]->section->name, ".opd") != 0) - break; - opdsymend = i; - - for (; i < symcount; ++i) - if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) - != (SEC_CODE | SEC_ALLOC)) - break; - symcount = i; - } - count = 0; - - if (relocatable) - { - bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - arelent *r; - size_t size; - long relcount; - - if (opdsymend == secsymend) - goto done; - - slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; - relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0; - if (relcount == 0) - goto done; - - if (!(*slurp_relocs) (abfd, opd, static_syms, FALSE)) - { - count = -1; - goto done; - } - - size = 0; - for (i = secsymend, r = opd->relocation; i < opdsymend; ++i) - { - asymbol *sym; - - while (r < opd->relocation + relcount - && r->address < syms[i]->value + opd->vma) - ++r; - - if (r == opd->relocation + relcount) - break; - - if (r->address != syms[i]->value + opd->vma) - continue; - - if (r->howto->type != R_PPC64_ADDR64) - continue; - - sym = *r->sym_ptr_ptr; - if (!sym_exists_at (syms, opdsymend, symcount, - sym->section->id, sym->value + r->addend)) - { - ++count; - size += sizeof (asymbol); - size += strlen (syms[i]->name) + 2; - } - } - - if (size == 0) - goto done; - s = *ret = bfd_malloc (size); - if (s == NULL) - { - count = -1; - goto done; - } - - names = (char *) (s + count); - - for (i = secsymend, r = opd->relocation; i < opdsymend; ++i) - { - asymbol *sym; - - while (r < opd->relocation + relcount - && r->address < syms[i]->value + opd->vma) - ++r; - - if (r == opd->relocation + relcount) - break; - - if (r->address != syms[i]->value + opd->vma) - continue; - - if (r->howto->type != R_PPC64_ADDR64) - continue; - - sym = *r->sym_ptr_ptr; - if (!sym_exists_at (syms, opdsymend, symcount, - sym->section->id, sym->value + r->addend)) - { - size_t len; - - *s = *syms[i]; - s->flags |= BSF_SYNTHETIC; - s->section = sym->section; - s->value = sym->value + r->addend; - s->name = names; - *names++ = '.'; - len = strlen (syms[i]->name); - memcpy (names, syms[i]->name, len + 1); - names += len + 1; - /* Have udata.p point back to the original symbol this - synthetic symbol was derived from. */ - s->udata.p = syms[i]; - s++; - } - } - } - else - { - bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - bfd_byte *contents = NULL; - size_t size; - long plt_count = 0; - bfd_vma glink_vma = 0, resolv_vma = 0; - asection *dynamic, *glink = NULL, *relplt = NULL; - arelent *p; - - if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents)) - { - free_contents_and_exit_err: - count = -1; - free_contents_and_exit: - if (contents) - free (contents); - goto done; - } - - size = 0; - for (i = secsymend; i < opdsymend; ++i) - { - bfd_vma ent; - - /* Ignore bogus symbols. */ - if (syms[i]->value > opd->size - 8) - continue; - - ent = bfd_get_64 (abfd, contents + syms[i]->value); - if (!sym_exists_at (syms, opdsymend, symcount, -1, ent)) - { - ++count; - size += sizeof (asymbol); - size += strlen (syms[i]->name) + 2; - } - } - - /* Get start of .glink stubs from DT_PPC64_GLINK. */ - if (dyn_count != 0 - && (dynamic = bfd_get_section_by_name (abfd, ".dynamic")) != NULL) - { - bfd_byte *dynbuf, *extdyn, *extdynend; - size_t extdynsize; - void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); - - if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf)) - goto free_contents_and_exit_err; - - 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 + dynamic->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_PPC64_GLINK) - { - /* The first glink stub starts at DT_PPC64_GLINK plus 32. - See comment in ppc64_elf_finish_dynamic_sections. */ - glink_vma = dyn.d_un.d_val + 8 * 4; - /* The .glink section usually does not survive the final - link; search for the section (usually .text) where the - glink stubs now reside. */ - glink = bfd_sections_find_if (abfd, section_covers_vma, - &glink_vma); - break; - } - } - - free (dynbuf); - } - - if (glink != NULL) - { - /* Determine __glink trampoline by reading the relative branch - from the first glink stub. */ - bfd_byte buf[4]; - unsigned int off = 0; - - while (bfd_get_section_contents (abfd, glink, buf, - glink_vma + off - glink->vma, 4)) - { - unsigned int insn = bfd_get_32 (abfd, buf); - insn ^= B_DOT; - if ((insn & ~0x3fffffc) == 0) - { - resolv_vma = glink_vma + off + (insn ^ 0x2000000) - 0x2000000; - break; - } - off += 4; - if (off > 4) - break; - } - - if (resolv_vma) - size += sizeof (asymbol) + sizeof ("__glink_PLTresolve"); - - relplt = bfd_get_section_by_name (abfd, ".rela.plt"); - if (relplt != NULL) - { - slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; - if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE)) - goto free_contents_and_exit_err; - - plt_count = relplt->size / sizeof (Elf64_External_Rela); - size += plt_count * sizeof (asymbol); - - p = relplt->relocation; - for (i = 0; i < plt_count; i++, p++) - { - size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); - if (p->addend != 0) - size += sizeof ("+0x") - 1 + 16; - } - } - } - - if (size == 0) - goto free_contents_and_exit; - s = *ret = bfd_malloc (size); - if (s == NULL) - goto free_contents_and_exit_err; - - names = (char *) (s + count + plt_count + (resolv_vma != 0)); - - for (i = secsymend; i < opdsymend; ++i) - { - bfd_vma ent; - - if (syms[i]->value > opd->size - 8) - continue; - - ent = bfd_get_64 (abfd, contents + syms[i]->value); - if (!sym_exists_at (syms, opdsymend, symcount, -1, ent)) - { - long lo, hi; - size_t len; - asection *sec = abfd->sections; - - *s = *syms[i]; - lo = codesecsym; - hi = codesecsymend; - while (lo < hi) - { - long mid = (lo + hi) >> 1; - if (syms[mid]->section->vma < ent) - lo = mid + 1; - else if (syms[mid]->section->vma > ent) - hi = mid; - else - { - sec = syms[mid]->section; - break; - } - } - - if (lo >= hi && lo > codesecsym) - sec = syms[lo - 1]->section; - - for (; sec != NULL; sec = sec->next) - { - if (sec->vma > ent) - break; - /* SEC_LOAD may not be set if SEC is from a separate debug - info file. */ - if ((sec->flags & SEC_ALLOC) == 0) - break; - if ((sec->flags & SEC_CODE) != 0) - s->section = sec; - } - s->flags |= BSF_SYNTHETIC; - s->value = ent - s->section->vma; - s->name = names; - *names++ = '.'; - len = strlen (syms[i]->name); - memcpy (names, syms[i]->name, len + 1); - names += len + 1; - /* Have udata.p point back to the original symbol this - synthetic symbol was derived from. */ - s->udata.p = syms[i]; - s++; - } - } - free (contents); - - if (glink != NULL && relplt != NULL) - { - if (resolv_vma) - { - /* Add a symbol for the main glink trampoline. */ - memset (s, 0, sizeof *s); - s->the_bfd = abfd; - s->flags = BSF_GLOBAL | BSF_SYNTHETIC; - s->section = glink; - s->value = resolv_vma - glink->vma; - s->name = names; - memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve")); - names += sizeof ("__glink_PLTresolve"); - s++; - count++; - } - - /* FIXME: It would be very much nicer to put sym@plt on the - stub rather than on the glink branch table entry. The - objdump disassembler would then use a sensible symbol - name on plt calls. The difficulty in doing so is - a) finding the stubs, and, - b) matching stubs against plt entries, and, - c) there can be multiple stubs for a given plt entry. - - Solving (a) could be done by code scanning, but older - ppc64 binaries used different stubs to current code. - (b) is the tricky one since you need to known the toc - pointer for at least one function that uses a pic stub to - be able to calculate the plt address referenced. - (c) means gdb would need to set multiple breakpoints (or - find the glink branch itself) when setting breakpoints - for pending shared library loads. */ - p = relplt->relocation; - for (i = 0; i < plt_count; i++, p++) - { - size_t len; - - *s = **p->sym_ptr_ptr; - /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since - we are defining a symbol, ensure one of them is set. */ - if ((s->flags & BSF_LOCAL) == 0) - s->flags |= BSF_GLOBAL; - s->flags |= BSF_SYNTHETIC; - s->section = glink; - s->value = glink_vma - glink->vma; - s->name = names; - s->udata.p = NULL; - len = strlen ((*p->sym_ptr_ptr)->name); - memcpy (names, (*p->sym_ptr_ptr)->name, len); - names += len; - if (p->addend != 0) - { - memcpy (names, "+0x", sizeof ("+0x") - 1); - names += sizeof ("+0x") - 1; - bfd_sprintf_vma (abfd, names, p->addend); - names += strlen (names); - } - memcpy (names, "@plt", sizeof ("@plt")); - names += sizeof ("@plt"); - s++; - if (abi < 2) - { - glink_vma += 8; - if (i >= 0x8000) - glink_vma += 4; - } - else - glink_vma += 4; - } - count += plt_count; - } - } - - done: - free (syms); - return count; -} - -/* The following functions are specific to the ELF linker, while - functions above are used generally. Those named ppc64_elf_* are - called by the main ELF linker code. They appear in this file more - or less in the order in which they are called. eg. - ppc64_elf_check_relocs is called early in the link process, - ppc64_elf_finish_dynamic_sections is one of the last functions - called. - - PowerPC64-ELF uses a similar scheme to PowerPC64-XCOFF in that - functions have both a function code symbol and a function descriptor - symbol. A call to foo in a relocatable object file looks like: - - . .text - . x: - . bl .foo - . nop - - The function definition in another object file might be: - - . .section .opd - . foo: .quad .foo - . .quad .TOC.@tocbase - . .quad 0 - . - . .text - . .foo: blr - - When the linker resolves the call during a static link, the branch - unsurprisingly just goes to .foo and the .opd information is unused. - If the function definition is in a shared library, things are a little - different: The call goes via a plt call stub, the opd information gets - copied to the plt, and the linker patches the nop. - - . x: - . bl .foo_stub - . ld 2,40(1) - . - . - . .foo_stub: - . std 2,40(1) # in practice, the call stub - . addis 11,2,Lfoo@toc@ha # is slightly optimized, but - . addi 11,11,Lfoo@toc@l # this is the general idea - . ld 12,0(11) - . ld 2,8(11) - . mtctr 12 - . ld 11,16(11) - . bctr - . - . .section .plt - . Lfoo: reloc (R_PPC64_JMP_SLOT, foo) - - The "reloc ()" notation is supposed to indicate that the linker emits - an R_PPC64_JMP_SLOT reloc against foo. The dynamic linker does the opd - copying. - - What are the difficulties here? Well, firstly, the relocations - examined by the linker in check_relocs are against the function code - sym .foo, while the dynamic relocation in the plt is emitted against - the function descriptor symbol, foo. Somewhere along the line, we need - to carefully copy dynamic link information from one symbol to the other. - Secondly, the generic part of the elf linker will make .foo a dynamic - symbol as is normal for most other backends. We need foo dynamic - instead, at least for an application final link. However, when - creating a shared library containing foo, we need to have both symbols - dynamic so that references to .foo are satisfied during the early - stages of linking. Otherwise the linker might decide to pull in a - definition from some other object, eg. a static library. - - Update: As of August 2004, we support a new convention. Function - calls may use the function descriptor symbol, ie. "bl foo". This - behaves exactly as "bl .foo". */ - -/* Of those relocs that might be copied as dynamic relocs, this - function selects those that must be copied when linking a shared - library or PIE, even when the symbol is local. */ - -static int -must_be_dyn_reloc (struct bfd_link_info *info, - enum elf_ppc64_reloc_type r_type) -{ - switch (r_type) - { - default: - /* Only relative relocs can be resolved when the object load - address isn't fixed. DTPREL64 is excluded because the - dynamic linker needs to differentiate global dynamic from - local dynamic __tls_index pairs when PPC64_OPT_TLS is set. */ - return 1; - - case R_PPC64_REL32: - case R_PPC64_REL64: - case R_PPC64_REL30: - return 0; - - case R_PPC64_TPREL16: - case R_PPC64_TPREL16_LO: - case R_PPC64_TPREL16_HI: - case R_PPC64_TPREL16_HA: - case R_PPC64_TPREL16_DS: - case R_PPC64_TPREL16_LO_DS: - case R_PPC64_TPREL16_HIGH: - case R_PPC64_TPREL16_HIGHA: - case R_PPC64_TPREL16_HIGHER: - case R_PPC64_TPREL16_HIGHERA: - case R_PPC64_TPREL16_HIGHEST: - case R_PPC64_TPREL16_HIGHESTA: - case R_PPC64_TPREL64: - /* These relocations are relative but in a shared library the - linker doesn't know the thread pointer base. */ - return bfd_link_dll (info); - } -} - -/* 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. With code that gcc generates, it's vital that this be - enabled; In the PowerPC64 ABI, the address of a function is actually - the address of a function descriptor, which resides in the .opd - section. gcc uses the descriptor directly rather than going via the - GOT as some other ABI's do, which means that initialized function - pointers must reference the descriptor. Thus, a function pointer - initialized to the address of a function in a shared library will - either require a copy reloc, or a dynamic reloc. Using a copy reloc - redefines the function descriptor symbol to point to the copy. This - presents a problem as a plt entry for that function is also - initialized from the function descriptor symbol and the copy reloc - may not be initialized first. */ -#define ELIMINATE_COPY_RELOCS 1 - -/* Section name for stubs is the associated section name plus this - string. */ -#define STUB_SUFFIX ".stub" - -/* Linker stubs. - ppc_stub_long_branch: - Used when a 14 bit branch (or even a 24 bit branch) can't reach its - destination, but a 24 bit branch in a stub section will reach. - . b dest - - ppc_stub_plt_branch: - Similar to the above, but a 24 bit branch in the stub section won't - reach its destination. - . addis %r11,%r2,xxx@toc@ha - . ld %r12,xxx@toc@l(%r11) - . mtctr %r12 - . bctr - - ppc_stub_plt_call: - Used to call a function in a shared library. If it so happens that - the plt entry referenced crosses a 64k boundary, then an extra - "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr". - . std %r2,40(%r1) - . addis %r11,%r2,xxx@toc@ha - . ld %r12,xxx+0@toc@l(%r11) - . mtctr %r12 - . ld %r2,xxx+8@toc@l(%r11) - . ld %r11,xxx+16@toc@l(%r11) - . bctr - - ppc_stub_long_branch and ppc_stub_plt_branch may also have additional - code to adjust the value and save r2 to support multiple toc sections. - A ppc_stub_long_branch with an r2 offset looks like: - . std %r2,40(%r1) - . addis %r2,%r2,off@ha - . addi %r2,%r2,off@l - . b dest - - A ppc_stub_plt_branch with an r2 offset looks like: - . std %r2,40(%r1) - . addis %r11,%r2,xxx@toc@ha - . ld %r12,xxx@toc@l(%r11) - . addis %r2,%r2,off@ha - . addi %r2,%r2,off@l - . mtctr %r12 - . bctr - - In cases where the "addis" instruction would add zero, the "addis" is - omitted and following instructions modified slightly in some cases. -*/ - -enum ppc_stub_type { - ppc_stub_none, - ppc_stub_long_branch, - ppc_stub_long_branch_r2off, - ppc_stub_plt_branch, - ppc_stub_plt_branch_r2off, - ppc_stub_plt_call, - ppc_stub_plt_call_r2save, - ppc_stub_global_entry, - ppc_stub_save_res -}; - -/* Information on stub grouping. */ -struct map_stub -{ - /* The stub section. */ - asection *stub_sec; - /* This is the section to which stubs in the group will be attached. */ - asection *link_sec; - /* Next group. */ - struct map_stub *next; - /* Whether to emit a copy of register save/restore functions in this - group. */ - int needs_save_res; - /* The offset of the __tls_get_addr_opt plt stub bctrl in this group, - or -1u if no such stub with bctrl exists. */ - unsigned int tls_get_addr_opt_bctrl; -}; - -struct ppc_stub_hash_entry { - - /* Base hash table entry structure. */ - struct bfd_hash_entry root; - - enum ppc_stub_type stub_type; - - /* Group information. */ - struct map_stub *group; - - /* Offset within stub_sec of the beginning of this stub. */ - bfd_vma stub_offset; - - /* Given the symbol's value and its section we can determine its final - value when building the stubs (so the stub knows where to jump. */ - bfd_vma target_value; - asection *target_section; - - /* The symbol table entry, if any, that this was derived from. */ - struct ppc_link_hash_entry *h; - struct plt_entry *plt_ent; - - /* Symbol st_other. */ - unsigned char other; -}; - -struct ppc_branch_hash_entry { - - /* Base hash table entry structure. */ - struct bfd_hash_entry root; - - /* Offset within branch lookup table. */ - unsigned int offset; - - /* Generation marker. */ - unsigned int iter; -}; - -/* Used to track dynamic relocations for local symbols. */ -struct ppc_dyn_relocs -{ - struct ppc_dyn_relocs *next; - - /* The input section of the reloc. */ - asection *sec; - - /* Total number of relocs copied for the input section. */ - unsigned int count : 31; - - /* Whether this entry is for STT_GNU_IFUNC symbols. */ - unsigned int ifunc : 1; -}; - -struct ppc_link_hash_entry -{ - struct elf_link_hash_entry elf; - - union { - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct ppc_stub_hash_entry *stub_cache; - - /* A pointer to the next symbol starting with a '.' */ - struct ppc_link_hash_entry *next_dot_sym; - } u; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* Link between function code and descriptor symbols. */ - struct ppc_link_hash_entry *oh; - - /* Flag function code and descriptor symbols. */ - unsigned int is_func:1; - unsigned int is_func_descriptor:1; - unsigned int fake:1; - - /* Whether global opd/toc sym has been adjusted or not. - After ppc64_elf_edit_opd/ppc64_elf_edit_toc has run, this flag - should be set for all globals defined in any opd/toc section. */ - unsigned int adjust_done:1; - - /* Set if this is an out-of-line register save/restore function, - with non-standard calling convention. */ - unsigned int save_res:1; - - /* Set if a duplicate symbol with non-zero localentry is detected, - even when the duplicate symbol does not provide a definition. */ - unsigned int non_zero_localentry:1; - - /* Contexts in which symbol is used in the GOT (or TOC). - TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the - corresponding relocs are encountered during check_relocs. - tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to - indicate the corresponding GOT entry type is not needed. - tls_optimize may also set TLS_TPRELGD when a GD reloc turns into - a TPREL one. We use a separate flag rather than setting TPREL - just for convenience in distinguishing the two cases. */ -#define TLS_GD 1 /* GD reloc. */ -#define TLS_LD 2 /* LD reloc. */ -#define TLS_TPREL 4 /* TPREL reloc, => IE. */ -#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ -#define TLS_TLS 16 /* Any TLS reloc. */ -#define TLS_EXPLICIT 32 /* Marks TOC section TLS relocs. */ -#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */ -#define PLT_IFUNC 128 /* STT_GNU_IFUNC. */ - unsigned char tls_mask; -}; - -/* ppc64 ELF linker hash table. */ - -struct ppc_link_hash_table -{ - struct elf_link_hash_table elf; - - /* The stub hash table. */ - struct bfd_hash_table stub_hash_table; - - /* Another hash table for plt_branch stubs. */ - struct bfd_hash_table branch_hash_table; - - /* Hash table for function prologue tocsave. */ - htab_t tocsave_htab; - - /* Various options and other info passed from the linker. */ - struct ppc64_elf_params *params; - - /* The size of sec_info below. */ - unsigned int sec_info_arr_size; - - /* Per-section array of extra section info. Done this way rather - than as part of ppc64_elf_section_data so we have the info for - non-ppc64 sections. */ - struct - { - /* Along with elf_gp, specifies the TOC pointer used by this section. */ - bfd_vma toc_off; - - union - { - /* The section group that this section belongs to. */ - struct map_stub *group; - /* A temp section list pointer. */ - asection *list; - } u; - } *sec_info; - - /* Linked list of groups. */ - struct map_stub *group; - - /* Temp used when calculating TOC pointers. */ - bfd_vma toc_curr; - bfd *toc_bfd; - asection *toc_first_sec; - - /* Used when adding symbols. */ - struct ppc_link_hash_entry *dot_syms; - - /* Shortcuts to get to dynamic linker sections. */ - asection *glink; - asection *global_entry; - asection *sfpr; - asection *brlt; - asection *relbrlt; - asection *glink_eh_frame; - - /* Shortcut to .__tls_get_addr and __tls_get_addr. */ - struct ppc_link_hash_entry *tls_get_addr; - struct ppc_link_hash_entry *tls_get_addr_fd; - - /* The size of reliplt used by got entry relocs. */ - bfd_size_type got_reli_size; - - /* Statistics. */ - unsigned long stub_count[ppc_stub_global_entry]; - - /* Number of stubs against global syms. */ - unsigned long stub_globals; - - /* Set if we're linking code with function descriptors. */ - unsigned int opd_abi:1; - - /* Support for multiple toc sections. */ - unsigned int do_multi_toc:1; - unsigned int multi_toc_needed:1; - unsigned int second_toc_pass:1; - unsigned int do_toc_opt:1; - - /* Set if tls optimization is enabled. */ - unsigned int do_tls_opt:1; - - /* Set on error. */ - unsigned int stub_error:1; - - /* Whether func_desc_adjust needs to be run over symbols. */ - unsigned int need_func_desc_adj:1; - - /* Whether there exist local gnu indirect function resolvers, - referenced by dynamic relocations. */ - unsigned int local_ifunc_resolver:1; - unsigned int maybe_local_ifunc_resolver:1; - - /* Whether plt calls for ELFv2 localentry:0 funcs have been optimized. */ - unsigned int has_plt_localentry0:1; - - /* Incremented every time we size stubs. */ - unsigned int stub_iteration; - - /* Small local sym cache. */ - struct sym_cache sym_cache; -}; - -/* Rename some of the generic section flags to better document how they - are used here. */ - -/* Nonzero if this section has TLS related relocations. */ -#define has_tls_reloc sec_flg0 - -/* Nonzero if this section has a call to __tls_get_addr. */ -#define has_tls_get_addr_call sec_flg1 - -/* Nonzero if this section has any toc or got relocs. */ -#define has_toc_reloc sec_flg2 - -/* Nonzero if this section has a call to another section that uses - the toc or got. */ -#define makes_toc_func_call sec_flg3 - -/* Recursion protection when determining above flag. */ -#define call_check_in_progress sec_flg4 -#define call_check_done sec_flg5 - -/* Get the ppc64 ELF linker hash table from a link_info structure. */ - -#define ppc_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == PPC64_ELF_DATA ? ((struct ppc_link_hash_table *) ((p)->hash)) : NULL) - -#define ppc_stub_hash_lookup(table, string, create, copy) \ - ((struct ppc_stub_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -#define ppc_branch_hash_lookup(table, string, create, copy) \ - ((struct ppc_branch_hash_entry *) \ - bfd_hash_lookup ((table), (string), (create), (copy))) - -/* Create an entry in the stub hash table. */ - -static struct bfd_hash_entry * -stub_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 ppc_stub_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct ppc_stub_hash_entry *eh; - - /* Initialize the local fields. */ - eh = (struct ppc_stub_hash_entry *) entry; - eh->stub_type = ppc_stub_none; - eh->group = NULL; - eh->stub_offset = 0; - eh->target_value = 0; - eh->target_section = NULL; - eh->h = NULL; - eh->plt_ent = NULL; - eh->other = 0; - } - - return entry; -} - -/* Create an entry in the branch hash table. */ - -static struct bfd_hash_entry * -branch_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 ppc_branch_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = bfd_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct ppc_branch_hash_entry *eh; - - /* Initialize the local fields. */ - eh = (struct ppc_branch_hash_entry *) entry; - eh->offset = 0; - eh->iter = 0; - } - - return entry; -} - -/* Create an entry in a ppc64 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 ppc_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 ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) entry; - - memset (&eh->u.stub_cache, 0, - (sizeof (struct ppc_link_hash_entry) - - offsetof (struct ppc_link_hash_entry, u.stub_cache))); - - /* When making function calls, old ABI code references function entry - points (dot symbols), while new ABI code references the function - descriptor symbol. We need to make any combination of reference and - definition work together, without breaking archive linking. - - For a defined function "foo" and an undefined call to "bar": - An old object defines "foo" and ".foo", references ".bar" (possibly - "bar" too). - A new object defines "foo" and references "bar". - - A new object thus has no problem with its undefined symbols being - satisfied by definitions in an old object. On the other hand, the - old object won't have ".bar" satisfied by a new object. - - Keep a list of newly added dot-symbols. */ - - if (string[0] == '.') - { - struct ppc_link_hash_table *htab; - - htab = (struct ppc_link_hash_table *) table; - eh->u.next_dot_sym = htab->dot_syms; - htab->dot_syms = eh; - } - } - - return entry; -} - -struct tocsave_entry { - asection *sec; - bfd_vma offset; -}; - -static hashval_t -tocsave_htab_hash (const void *p) -{ - const struct tocsave_entry *e = (const struct tocsave_entry *) p; - return ((bfd_vma) (intptr_t) e->sec ^ e->offset) >> 3; -} - -static int -tocsave_htab_eq (const void *p1, const void *p2) -{ - const struct tocsave_entry *e1 = (const struct tocsave_entry *) p1; - const struct tocsave_entry *e2 = (const struct tocsave_entry *) p2; - return e1->sec == e2->sec && e1->offset == e2->offset; -} - -/* Destroy a ppc64 ELF linker hash table. */ - -static void -ppc64_elf_link_hash_table_free (bfd *obfd) -{ - struct ppc_link_hash_table *htab; - - htab = (struct ppc_link_hash_table *) obfd->link.hash; - if (htab->tocsave_htab) - htab_delete (htab->tocsave_htab); - bfd_hash_table_free (&htab->branch_hash_table); - bfd_hash_table_free (&htab->stub_hash_table); - _bfd_elf_link_hash_table_free (obfd); -} - -/* Create a ppc64 ELF linker hash table. */ - -static struct bfd_link_hash_table * -ppc64_elf_link_hash_table_create (bfd *abfd) -{ - struct ppc_link_hash_table *htab; - bfd_size_type amt = sizeof (struct ppc_link_hash_table); - - htab = bfd_zmalloc (amt); - if (htab == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, link_hash_newfunc, - sizeof (struct ppc_link_hash_entry), - PPC64_ELF_DATA)) - { - free (htab); - return NULL; - } - - /* Init the stub hash table too. */ - if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc, - sizeof (struct ppc_stub_hash_entry))) - { - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - - /* And the branch hash table. */ - if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc, - sizeof (struct ppc_branch_hash_entry))) - { - bfd_hash_table_free (&htab->stub_hash_table); - _bfd_elf_link_hash_table_free (abfd); - return NULL; - } - - htab->tocsave_htab = htab_try_create (1024, - tocsave_htab_hash, - tocsave_htab_eq, - NULL); - if (htab->tocsave_htab == NULL) - { - ppc64_elf_link_hash_table_free (abfd); - return NULL; - } - htab->elf.root.hash_table_free = ppc64_elf_link_hash_table_free; - - /* Initializing two fields of the union is just cosmetic. We really - only care about glist, but when compiled on a 32-bit host the - bfd_vma fields are larger. Setting the bfd_vma to zero makes - debugger inspection of these fields look nicer. */ - htab->elf.init_got_refcount.refcount = 0; - htab->elf.init_got_refcount.glist = NULL; - htab->elf.init_plt_refcount.refcount = 0; - htab->elf.init_plt_refcount.glist = NULL; - htab->elf.init_got_offset.offset = 0; - htab->elf.init_got_offset.glist = NULL; - htab->elf.init_plt_offset.offset = 0; - htab->elf.init_plt_offset.glist = NULL; - - return &htab->elf.root; -} - -/* Create sections for linker generated code. */ - -static bfd_boolean -create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - flagword flags; - - htab = ppc_hash_table (info); - - flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if (htab->params->save_restore_funcs) - { - /* Create .sfpr for code to save and restore fp regs. */ - htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", - flags); - if (htab->sfpr == NULL - || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2)) - return FALSE; - } - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Create .glink for lazy dynamic linking support. */ - htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink", - flags); - if (htab->glink == NULL - || ! bfd_set_section_alignment (dynobj, htab->glink, 3)) - return FALSE; - - /* The part of .glink used by global entry stubs, separate so that - it can be aligned appropriately without affecting htab->glink. */ - htab->global_entry = bfd_make_section_anyway_with_flags (dynobj, ".glink", - flags); - if (htab->global_entry == NULL - || ! bfd_set_section_alignment (dynobj, htab->global_entry, 2)) - return FALSE; - - if (!info->no_ld_generated_unwind_info) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj, - ".eh_frame", - flags); - if (htab->glink_eh_frame == NULL - || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2)) - return FALSE; - } - - flags = SEC_ALLOC | SEC_LINKER_CREATED; - htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags); - if (htab->elf.iplt == NULL - || ! bfd_set_section_alignment (dynobj, htab->elf.iplt, 3)) - return FALSE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->elf.irelplt - = bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags); - if (htab->elf.irelplt == NULL - || ! bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3)) - return FALSE; - - /* Create branch lookup table for plt_branch stubs. */ - flags = (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt", - flags); - if (htab->brlt == NULL - || ! bfd_set_section_alignment (dynobj, htab->brlt, 3)) - return FALSE; - - if (!bfd_link_pic (info)) - return TRUE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj, - ".rela.branch_lt", - flags); - if (htab->relbrlt == NULL - || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3)) - return FALSE; - - return TRUE; -} - -/* Satisfy the ELF linker by filling in some fields in our fake bfd. */ - -bfd_boolean -ppc64_elf_init_stub_bfd (struct bfd_link_info *info, - struct ppc64_elf_params *params) -{ - struct ppc_link_hash_table *htab; - - elf_elfheader (params->stub_bfd)->e_ident[EI_CLASS] = ELFCLASS64; - -/* Always hook our dynamic sections into the first bfd, which is the - linker created stub bfd. This ensures that the GOT header is at - the start of the output TOC section. */ - htab = ppc_hash_table (info); - htab->elf.dynobj = params->stub_bfd; - htab->params = params; - - return create_linkage_sections (htab->elf.dynobj, info); -} - -/* Build a name for an entry in the stub hash table. */ - -static char * -ppc_stub_name (const asection *input_section, - const asection *sym_sec, - const struct ppc_link_hash_entry *h, - const Elf_Internal_Rela *rel) -{ - char *stub_name; - ssize_t len; - - /* rel->r_addend is actually 64 bit, but who uses more than +/- 2^31 - offsets from a sym as a branch target? In fact, we could - probably assume the addend is always zero. */ - BFD_ASSERT (((int) rel->r_addend & 0xffffffff) == rel->r_addend); - - if (h) - { - len = 8 + 1 + strlen (h->elf.root.root.string) + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name == NULL) - return stub_name; - - len = sprintf (stub_name, "%08x.%s+%x", - input_section->id & 0xffffffff, - h->elf.root.root.string, - (int) rel->r_addend & 0xffffffff); - } - else - { - len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; - stub_name = bfd_malloc (len); - if (stub_name == NULL) - return stub_name; - - len = sprintf (stub_name, "%08x.%x:%x+%x", - input_section->id & 0xffffffff, - sym_sec->id & 0xffffffff, - (int) ELF64_R_SYM (rel->r_info) & 0xffffffff, - (int) rel->r_addend & 0xffffffff); - } - if (len > 2 && stub_name[len - 2] == '+' && stub_name[len - 1] == '0') - stub_name[len - 2] = 0; - return stub_name; -} - -/* Look up an entry in the stub hash. Stub entries are cached because - creating the stub name takes a bit of time. */ - -static struct ppc_stub_hash_entry * -ppc_get_stub_entry (const asection *input_section, - const asection *sym_sec, - struct ppc_link_hash_entry *h, - const Elf_Internal_Rela *rel, - struct ppc_link_hash_table *htab) -{ - struct ppc_stub_hash_entry *stub_entry; - struct map_stub *group; - - /* If this input section is part of a group of sections sharing one - stub section, then use the id of the first section in the group. - Stub names need to include a section id, as there may well be - more than one stub used to reach say, printf, and we need to - distinguish between them. */ - group = htab->sec_info[input_section->id].u.group; - if (group == NULL) - return NULL; - - if (h != NULL && h->u.stub_cache != NULL - && h->u.stub_cache->h == h - && h->u.stub_cache->group == group) - { - stub_entry = h->u.stub_cache; - } - else - { - char *stub_name; - - stub_name = ppc_stub_name (group->link_sec, sym_sec, h, rel); - if (stub_name == NULL) - return NULL; - - stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, - stub_name, FALSE, FALSE); - if (h != NULL) - h->u.stub_cache = stub_entry; - - free (stub_name); - } - - return stub_entry; -} - -/* Add a new stub entry to the stub hash. Not all fields of the new - stub entry are initialised. */ - -static struct ppc_stub_hash_entry * -ppc_add_stub (const char *stub_name, - asection *section, - struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - struct map_stub *group; - asection *link_sec; - asection *stub_sec; - struct ppc_stub_hash_entry *stub_entry; - - group = htab->sec_info[section->id].u.group; - link_sec = group->link_sec; - stub_sec = group->stub_sec; - if (stub_sec == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; - - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->params->stub_bfd, len); - if (s_name == NULL) - return NULL; - - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - stub_sec = (*htab->params->add_stub_section) (s_name, link_sec); - if (stub_sec == NULL) - return NULL; - group->stub_sec = stub_sec; - } - - /* Enter this entry into the linker stub hash table. */ - stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, stub_name, - TRUE, FALSE); - if (stub_entry == NULL) - { - /* xgettext:c-format */ - info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"), - section->owner, stub_name); - return NULL; - } - - stub_entry->group = group; - stub_entry->stub_offset = 0; - return stub_entry; -} - -/* Create .got and .rela.got sections in ABFD, and .got in dynobj if - not already done. */ - -static bfd_boolean -create_got_section (bfd *abfd, struct bfd_link_info *info) -{ - asection *got, *relgot; - flagword flags; - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (!is_ppc64_elf (abfd)) - return FALSE; - if (htab == NULL) - return FALSE; - - if (!htab->elf.sgot - && !_bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - if (!got - || !bfd_set_section_alignment (abfd, got, 3)) - return FALSE; - - relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got", - flags | SEC_READONLY); - if (!relgot - || ! bfd_set_section_alignment (abfd, relgot, 3)) - return FALSE; - - ppc64_elf_tdata (abfd)->got = got; - ppc64_elf_tdata (abfd)->relgot = relgot; - return TRUE; -} - -/* Follow indirect and warning symbol links. */ - -static inline struct bfd_link_hash_entry * -follow_link (struct bfd_link_hash_entry *h) -{ - while (h->type == bfd_link_hash_indirect - || h->type == bfd_link_hash_warning) - h = h->u.i.link; - return h; -} - -static inline struct elf_link_hash_entry * -elf_follow_link (struct elf_link_hash_entry *h) -{ - return (struct elf_link_hash_entry *) follow_link (&h->root); -} - -static inline struct ppc_link_hash_entry * -ppc_follow_link (struct ppc_link_hash_entry *h) -{ - return (struct ppc_link_hash_entry *) follow_link (&h->elf.root); -} - -/* Merge PLT info on FROM with that on TO. */ - -static void -move_plt_plist (struct ppc_link_hash_entry *from, - struct ppc_link_hash_entry *to) -{ - if (from->elf.plt.plist != NULL) - { - if (to->elf.plt.plist != NULL) - { - struct plt_entry **entp; - struct plt_entry *ent; - - for (entp = &from->elf.plt.plist; (ent = *entp) != NULL; ) - { - struct plt_entry *dent; - - for (dent = to->elf.plt.plist; dent != NULL; dent = dent->next) - if (dent->addend == ent->addend) - { - dent->plt.refcount += ent->plt.refcount; - *entp = ent->next; - break; - } - if (dent == NULL) - entp = &ent->next; - } - *entp = to->elf.plt.plist; - } - - to->elf.plt.plist = from->elf.plt.plist; - from->elf.plt.plist = NULL; - } -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct ppc_link_hash_entry *edir, *eind; - - edir = (struct ppc_link_hash_entry *) dir; - eind = (struct ppc_link_hash_entry *) ind; - - edir->is_func |= eind->is_func; - edir->is_func_descriptor |= eind->is_func_descriptor; - edir->tls_mask |= eind->tls_mask; - if (eind->oh != NULL) - edir->oh = ppc_follow_link (eind->oh); - - if (edir->elf.versioned != versioned_hidden) - edir->elf.ref_dynamic |= eind->elf.ref_dynamic; - edir->elf.ref_regular |= eind->elf.ref_regular; - edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; - edir->elf.non_got_ref |= eind->elf.non_got_ref; - edir->elf.needs_plt |= eind->elf.needs_plt; - edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; - - /* If we were called to copy over info for a weak sym, don't copy - dyn_relocs, plt/got info, or dynindx. We used to copy dyn_relocs - in order to simplify readonly_dynrelocs and save a field in the - symbol hash entry, but that means dyn_relocs can't be used in any - tests about a specific symbol, or affect other symbol flags which - are then tested. */ - if (eind->elf.root.type != bfd_link_hash_indirect) - return; - - /* Copy over any dynamic relocs we may have on the indirect sym. */ - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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; - } - - /* Copy over got entries that we may have already seen to the - symbol which just became indirect. */ - if (eind->elf.got.glist != NULL) - { - if (edir->elf.got.glist != NULL) - { - struct got_entry **entp; - struct got_entry *ent; - - for (entp = &eind->elf.got.glist; (ent = *entp) != NULL; ) - { - struct got_entry *dent; - - for (dent = edir->elf.got.glist; dent != NULL; dent = dent->next) - if (dent->addend == ent->addend - && dent->owner == ent->owner - && dent->tls_type == ent->tls_type) - { - dent->got.refcount += ent->got.refcount; - *entp = ent->next; - break; - } - if (dent == NULL) - entp = &ent->next; - } - *entp = edir->elf.got.glist; - } - - edir->elf.got.glist = eind->elf.got.glist; - eind->elf.got.glist = NULL; - } - - /* And plt entries. */ - move_plt_plist (eind, edir); - - if (eind->elf.dynindx != -1) - { - if (edir->elf.dynindx != -1) - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - edir->elf.dynstr_index); - edir->elf.dynindx = eind->elf.dynindx; - edir->elf.dynstr_index = eind->elf.dynstr_index; - eind->elf.dynindx = -1; - eind->elf.dynstr_index = 0; - } -} - -/* Find the function descriptor hash entry from the given function code - hash entry FH. Link the entries via their OH fields. */ - -static struct ppc_link_hash_entry * -lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab) -{ - struct ppc_link_hash_entry *fdh = fh->oh; - - if (fdh == NULL) - { - const char *fd_name = fh->elf.root.root.string + 1; - - fdh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE); - if (fdh == NULL) - return fdh; - - fdh->is_func_descriptor = 1; - fdh->oh = fh; - fh->is_func = 1; - fh->oh = fdh; - } - - fdh = ppc_follow_link (fdh); - fdh->is_func_descriptor = 1; - fdh->oh = fh; - return fdh; -} - -/* Make a fake function descriptor sym for the undefined code sym FH. */ - -static struct ppc_link_hash_entry * -make_fdh (struct bfd_link_info *info, - struct ppc_link_hash_entry *fh) -{ - bfd *abfd = fh->elf.root.u.undef.abfd; - struct bfd_link_hash_entry *bh = NULL; - struct ppc_link_hash_entry *fdh; - flagword flags = (fh->elf.root.type == bfd_link_hash_undefweak - ? BSF_WEAK - : BSF_GLOBAL); - - if (!_bfd_generic_link_add_one_symbol (info, abfd, - fh->elf.root.root.string + 1, - flags, bfd_und_section_ptr, 0, - NULL, FALSE, FALSE, &bh)) - return NULL; - - fdh = (struct ppc_link_hash_entry *) bh; - fdh->elf.non_elf = 0; - fdh->fake = 1; - fdh->is_func_descriptor = 1; - fdh->oh = fh; - fh->is_func = 1; - fh->oh = fdh; - return fdh; -} - -/* Fix function descriptor symbols defined in .opd sections to be - function type. */ - -static bfd_boolean -ppc64_elf_add_symbol_hook (bfd *ibfd, - struct bfd_link_info *info, - Elf_Internal_Sym *isym, - const char **name, - flagword *flags ATTRIBUTE_UNUSED, - asection **sec, - bfd_vma *value) -{ - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - && (ibfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - if (*sec != NULL - && strcmp ((*sec)->name, ".opd") == 0) - { - asection *code_sec; - - if (!(ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - || ELF_ST_TYPE (isym->st_info) == STT_FUNC)) - isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); - - /* If the symbol is a function defined in .opd, and the function - code is in a discarded group, let it appear to be undefined. */ - if (!bfd_link_relocatable (info) - && (*sec)->reloc_count != 0 - && opd_entry_value (*sec, *value, &code_sec, NULL, - FALSE) != (bfd_vma) -1 - && discarded_section (code_sec)) - { - *sec = bfd_und_section_ptr; - isym->st_shndx = SHN_UNDEF; - } - } - else if (*sec != NULL - && strcmp ((*sec)->name, ".toc") == 0 - && ELF_ST_TYPE (isym->st_info) == STT_OBJECT) - { - struct ppc_link_hash_table *htab = ppc_hash_table (info); - if (htab != NULL) - htab->params->object_in_toc = 1; - } - - if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0) - { - if (abiversion (ibfd) == 0) - set_abiversion (ibfd, 2); - else if (abiversion (ibfd) == 1) - { - info->callbacks->einfo (_("%P: symbol '%s' has invalid st_other" - " for ABI version 1\n"), name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - return TRUE; -} - -/* Merge non-visibility st_other attributes: local entry point. */ - -static void -ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic) -{ - if (definition && (!dynamic || !h->def_regular)) - h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) - | ELF_ST_VISIBILITY (h->other)); -} - -/* Hook called on merging a symbol. We use this to clear "fake" since - we now have a real symbol. */ - -static bfd_boolean -ppc64_elf_merge_symbol (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - asection **psec ATTRIBUTE_UNUSED, - bfd_boolean newdef ATTRIBUTE_UNUSED, - bfd_boolean olddef ATTRIBUTE_UNUSED, - bfd *oldbfd ATTRIBUTE_UNUSED, - const asection *oldsec ATTRIBUTE_UNUSED) -{ - ((struct ppc_link_hash_entry *) h)->fake = 0; - if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0) - ((struct ppc_link_hash_entry *) h)->non_zero_localentry = 1; - return TRUE; -} - -/* This function makes an old ABI object reference to ".bar" cause the - inclusion of a new ABI object archive that defines "bar". - NAME is a symbol defined in an archive. Return a symbol in the hash - table that might be satisfied by the archive symbols. */ - -static struct elf_link_hash_entry * -ppc64_elf_archive_symbol_lookup (bfd *abfd, - struct bfd_link_info *info, - const char *name) -{ - struct elf_link_hash_entry *h; - char *dot_name; - size_t len; - - h = _bfd_elf_archive_symbol_lookup (abfd, info, name); - if (h != NULL - /* Don't return this sym if it is a fake function descriptor - created by add_symbol_adjust. */ - && !((struct ppc_link_hash_entry *) h)->fake) - return h; - - if (name[0] == '.') - return h; - - len = strlen (name); - dot_name = bfd_alloc (abfd, len + 2); - if (dot_name == NULL) - return (struct elf_link_hash_entry *) 0 - 1; - dot_name[0] = '.'; - memcpy (dot_name + 1, name, len + 1); - h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name); - bfd_release (abfd, dot_name); - return h; -} - -/* This function satisfies all old ABI object references to ".bar" if a - new ABI object defines "bar". Well, at least, undefined dot symbols - are made weak. This stops later archive searches from including an - object if we already have a function descriptor definition. It also - prevents the linker complaining about undefined symbols. - We also check and correct mismatched symbol visibility here. The - most restrictive visibility of the function descriptor and the - function entry symbol is used. */ - -static bfd_boolean -add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - struct ppc_link_hash_entry *fdh; - - if (eh->elf.root.type == bfd_link_hash_warning) - eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link; - - if (eh->elf.root.type == bfd_link_hash_indirect) - return TRUE; - - if (eh->elf.root.root.string[0] != '.') - abort (); - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - fdh = lookup_fdh (eh, htab); - if (fdh == NULL - && !bfd_link_relocatable (info) - && (eh->elf.root.type == bfd_link_hash_undefined - || eh->elf.root.type == bfd_link_hash_undefweak) - && eh->elf.ref_regular) - { - /* Make an undefined function descriptor sym, in order to - pull in an --as-needed shared lib. Archives are handled - elsewhere. */ - fdh = make_fdh (info, eh); - if (fdh == NULL) - return FALSE; - } - - if (fdh != NULL) - { - unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1; - unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1; - - /* Make both descriptor and entry symbol have the most - constraining visibility of either symbol. */ - if (entry_vis < descr_vis) - fdh->elf.other += entry_vis - descr_vis; - else if (entry_vis > descr_vis) - eh->elf.other += descr_vis - entry_vis; - - /* Propagate reference flags from entry symbol to function - descriptor symbol. */ - fdh->elf.root.non_ir_ref_regular |= eh->elf.root.non_ir_ref_regular; - fdh->elf.root.non_ir_ref_dynamic |= eh->elf.root.non_ir_ref_dynamic; - fdh->elf.ref_regular |= eh->elf.ref_regular; - fdh->elf.ref_regular_nonweak |= eh->elf.ref_regular_nonweak; - - if (!fdh->elf.forced_local - && fdh->elf.dynindx == -1 - && fdh->elf.versioned != versioned_hidden - && (bfd_link_dll (info) - || fdh->elf.def_dynamic - || fdh->elf.ref_dynamic) - && (eh->elf.ref_regular - || eh->elf.def_regular)) - { - if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf)) - return FALSE; - } - } - - return TRUE; -} - -/* Set up opd section info and abiversion for IBFD, and process list - of dot-symbols we made in link_hash_newfunc. */ - -static bfd_boolean -ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - struct ppc_link_hash_entry **p, *eh; - asection *opd = bfd_get_section_by_name (ibfd, ".opd"); - - if (opd != NULL && opd->size != 0) - { - BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal); - ppc64_elf_section_data (opd)->sec_type = sec_opd; - - if (abiversion (ibfd) == 0) - set_abiversion (ibfd, 1); - else if (abiversion (ibfd) >= 2) - { - /* xgettext:c-format */ - info->callbacks->einfo (_("%P: %B .opd not allowed in ABI" - " version %d\n"), - ibfd, abiversion (ibfd)); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - if (is_ppc64_elf (info->output_bfd)) - { - /* For input files without an explicit abiversion in e_flags - we should have flagged any with symbol st_other bits set - as ELFv1 and above flagged those with .opd as ELFv2. - Set the output abiversion if not yet set, and for any input - still ambiguous, take its abiversion from the output. - Differences in ABI are reported later. */ - if (abiversion (info->output_bfd) == 0) - set_abiversion (info->output_bfd, abiversion (ibfd)); - else if (abiversion (ibfd) == 0) - set_abiversion (ibfd, abiversion (info->output_bfd)); - } - - htab = ppc_hash_table (info); - if (htab == NULL) - return TRUE; - - if (opd != NULL && opd->size != 0 - && (ibfd->flags & DYNAMIC) == 0 - && (opd->flags & SEC_RELOC) != 0 - && opd->reloc_count != 0 - && !bfd_is_abs_section (opd->output_section) - && info->gc_sections) - { - /* Garbage collection needs some extra help with .opd sections. - We don't want to necessarily keep everything referenced by - relocs in .opd, as that would keep all functions. Instead, - if we reference an .opd symbol (a function descriptor), we - want to keep the function code symbol's section. This is - easy for global symbols, but for local syms we need to keep - information about the associated function section. */ - bfd_size_type amt; - asection **opd_sym_map; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *relocs, *rel_end, *rel; - - amt = OPD_NDX (opd->size) * sizeof (*opd_sym_map); - opd_sym_map = bfd_zalloc (ibfd, amt); - if (opd_sym_map == NULL) - return FALSE; - ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map; - relocs = _bfd_elf_link_read_relocs (ibfd, opd, NULL, NULL, - info->keep_memory); - if (relocs == NULL) - return FALSE; - symtab_hdr = &elf_symtab_hdr (ibfd); - rel_end = relocs + opd->reloc_count - 1; - for (rel = relocs; rel < rel_end; rel++) - { - enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info); - unsigned long r_symndx = ELF64_R_SYM (rel->r_info); - - if (r_type == R_PPC64_ADDR64 - && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC - && r_symndx < symtab_hdr->sh_info) - { - Elf_Internal_Sym *isym; - asection *s; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, r_symndx); - if (isym == NULL) - { - if (elf_section_data (opd)->relocs != relocs) - free (relocs); - return FALSE; - } - - s = bfd_section_from_elf_index (ibfd, isym->st_shndx); - if (s != NULL && s != opd) - opd_sym_map[OPD_NDX (rel->r_offset)] = s; - } - } - if (elf_section_data (opd)->relocs != relocs) - free (relocs); - } - - p = &htab->dot_syms; - while ((eh = *p) != NULL) - { - *p = NULL; - if (&eh->elf == htab->elf.hgot) - ; - else if (htab->elf.hgot == NULL - && strcmp (eh->elf.root.root.string, ".TOC.") == 0) - htab->elf.hgot = &eh->elf; - else if (abiversion (ibfd) <= 1) - { - htab->need_func_desc_adj = 1; - if (!add_symbol_adjust (eh, info)) - return FALSE; - } - p = &eh->u.next_dot_sym; - } - return TRUE; -} - -/* Undo hash table changes when an --as-needed input file is determined - not to be needed. */ - -static bfd_boolean -ppc64_elf_notice_as_needed (bfd *ibfd, - struct bfd_link_info *info, - enum notice_asneeded_action act) -{ - if (act == notice_not_needed) - { - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab == NULL) - return FALSE; - - htab->dot_syms = NULL; - } - return _bfd_elf_notice_as_needed (ibfd, info, act); -} - -/* If --just-symbols against a final linked binary, then assume we need - toc adjusting stubs when calling functions defined there. */ - -static void -ppc64_elf_link_just_syms (asection *sec, struct bfd_link_info *info) -{ - if ((sec->flags & SEC_CODE) != 0 - && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0 - && is_ppc64_elf (sec->owner)) - { - if (abiversion (sec->owner) >= 2 - || bfd_get_section_by_name (sec->owner, ".opd") != NULL) - sec->has_toc_reloc = 1; - } - _bfd_elf_link_just_syms (sec, info); -} - -static struct plt_entry ** -update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, - unsigned long r_symndx, bfd_vma r_addend, int tls_type) -{ - struct got_entry **local_got_ents = elf_local_got_ents (abfd); - struct plt_entry **local_plt; - unsigned char *local_got_tls_masks; - - if (local_got_ents == NULL) - { - bfd_size_type size = symtab_hdr->sh_info; - - size *= (sizeof (*local_got_ents) - + sizeof (*local_plt) - + sizeof (*local_got_tls_masks)); - local_got_ents = bfd_zalloc (abfd, size); - if (local_got_ents == NULL) - return NULL; - elf_local_got_ents (abfd) = local_got_ents; - } - - if ((tls_type & (PLT_IFUNC | TLS_EXPLICIT)) == 0) - { - struct got_entry *ent; - - for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next) - if (ent->addend == r_addend - && ent->owner == abfd - && ent->tls_type == tls_type) - break; - if (ent == NULL) - { - bfd_size_type amt = sizeof (*ent); - ent = bfd_alloc (abfd, amt); - if (ent == NULL) - return FALSE; - ent->next = local_got_ents[r_symndx]; - ent->addend = r_addend; - ent->owner = abfd; - ent->tls_type = tls_type; - ent->is_indirect = FALSE; - ent->got.refcount = 0; - local_got_ents[r_symndx] = ent; - } - ent->got.refcount += 1; - } - - local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info); - local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info); - local_got_tls_masks[r_symndx] |= tls_type; - - return local_plt + r_symndx; -} - -static bfd_boolean -update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend) -{ - struct plt_entry *ent; - - for (ent = *plist; ent != NULL; ent = ent->next) - if (ent->addend == addend) - break; - if (ent == NULL) - { - bfd_size_type amt = sizeof (*ent); - ent = bfd_alloc (abfd, amt); - if (ent == NULL) - return FALSE; - ent->next = *plist; - ent->addend = addend; - ent->plt.refcount = 0; - *plist = ent; - } - ent->plt.refcount += 1; - return TRUE; -} - -static bfd_boolean -is_branch_reloc (enum elf_ppc64_reloc_type r_type) -{ - return (r_type == R_PPC64_REL24 - || r_type == R_PPC64_REL14 - || r_type == R_PPC64_REL14_BRTAKEN - || r_type == R_PPC64_REL14_BRNTAKEN - || r_type == R_PPC64_ADDR24 - || r_type == R_PPC64_ADDR14 - || r_type == R_PPC64_ADDR14_BRTAKEN - || r_type == R_PPC64_ADDR14_BRNTAKEN); -} - -/* 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 -ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - struct ppc_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; - struct elf_link_hash_entry *tga, *dottga; - bfd_boolean is_opd; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - BFD_ASSERT (is_ppc64_elf (abfd)); - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", - FALSE, FALSE, TRUE); - dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", - FALSE, FALSE, TRUE); - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - sreloc = NULL; - is_opd = ppc64_elf_section_data (sec)->sec_type == sec_opd; - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned long r_symndx; - struct elf_link_hash_entry *h; - enum elf_ppc64_reloc_type r_type; - int tls_type; - struct _ppc64_elf_section_data *ppc64_sec; - struct plt_entry **ifunc, **plt_list; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - h = elf_follow_link (h); - - if (h == htab->elf.hgot) - sec->has_toc_reloc = 1; - } - - tls_type = 0; - ifunc = NULL; - if (h != NULL) - { - if (h->type == STT_GNU_IFUNC) - { - h->needs_plt = 1; - ifunc = &h->plt.plist; - } - } - else - { - Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, - rel->r_addend, PLT_IFUNC); - if (ifunc == NULL) - return FALSE; - } - } - - r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - case R_PPC64_TLSGD: - case R_PPC64_TLSLD: - /* These special tls relocs tie a call to __tls_get_addr with - its parameter symbol. */ - break; - - case R_PPC64_GOT_TLSLD16: - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSLD16_HI: - case R_PPC64_GOT_TLSLD16_HA: - tls_type = TLS_TLS | TLS_LD; - goto dogottls; - - case R_PPC64_GOT_TLSGD16: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TLSGD16_HI: - case R_PPC64_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD; - goto dogottls; - - case R_PPC64_GOT_TPREL16_DS: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_TPREL16_HI: - case R_PPC64_GOT_TPREL16_HA: - if (bfd_link_dll (info)) - info->flags |= DF_STATIC_TLS; - tls_type = TLS_TLS | TLS_TPREL; - goto dogottls; - - case R_PPC64_GOT_DTPREL16_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_HI: - case R_PPC64_GOT_DTPREL16_HA: - tls_type = TLS_TLS | TLS_DTPREL; - dogottls: - sec->has_tls_reloc = 1; - /* Fall through */ - - case R_PPC64_GOT16: - case R_PPC64_GOT16_DS: - case R_PPC64_GOT16_HA: - case R_PPC64_GOT16_HI: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_LO_DS: - /* This symbol requires a global offset table entry. */ - sec->has_toc_reloc = 1; - if (r_type == R_PPC64_GOT_TLSLD16 - || r_type == R_PPC64_GOT_TLSGD16 - || r_type == R_PPC64_GOT_TPREL16_DS - || r_type == R_PPC64_GOT_DTPREL16_DS - || r_type == R_PPC64_GOT16 - || r_type == R_PPC64_GOT16_DS) - { - htab->do_multi_toc = 1; - ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1; - } - - if (ppc64_elf_tdata (abfd)->got == NULL - && !create_got_section (abfd, info)) - return FALSE; - - if (h != NULL) - { - struct ppc_link_hash_entry *eh; - struct got_entry *ent; - - eh = (struct ppc_link_hash_entry *) h; - for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend - && ent->owner == abfd - && ent->tls_type == tls_type) - break; - if (ent == NULL) - { - bfd_size_type amt = sizeof (*ent); - ent = bfd_alloc (abfd, amt); - if (ent == NULL) - return FALSE; - ent->next = eh->elf.got.glist; - ent->addend = rel->r_addend; - ent->owner = abfd; - ent->tls_type = tls_type; - ent->is_indirect = FALSE; - ent->got.refcount = 0; - eh->elf.got.glist = ent; - } - ent->got.refcount += 1; - eh->tls_mask |= tls_type; - } - else - /* This is a global offset table entry for a local symbol. */ - if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, - rel->r_addend, tls_type)) - return FALSE; - - /* We may also need a plt entry if the symbol turns out to be - an ifunc. */ - if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1) - { - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; - } - break; - - case R_PPC64_PLT16_HA: - case R_PPC64_PLT16_HI: - case R_PPC64_PLT16_LO: - case R_PPC64_PLT32: - case R_PPC64_PLT64: - /* This symbol requires a procedure linkage table entry. */ - plt_list = ifunc; - if (h != NULL) - { - h->needs_plt = 1; - if (h->root.root.string[0] == '.' - && h->root.root.string[1] != '\0') - ((struct ppc_link_hash_entry *) h)->is_func = 1; - plt_list = &h->plt.plist; - } - if (plt_list == NULL) - { - /* It does not make sense to have a procedure linkage - table entry for a non-ifunc local symbol. */ - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s reloc against local symbol\n"), - abfd, sec, rel->r_offset, - ppc64_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - if (!update_plt_info (abfd, plt_list, rel->r_addend)) - return FALSE; - break; - - /* The following relocations don't need to propagate the - relocation if linking a shared object since they are - section relative. */ - case R_PPC64_SECTOFF: - case R_PPC64_SECTOFF_LO: - case R_PPC64_SECTOFF_HI: - case R_PPC64_SECTOFF_HA: - case R_PPC64_SECTOFF_DS: - case R_PPC64_SECTOFF_LO_DS: - case R_PPC64_DTPREL16: - case R_PPC64_DTPREL16_LO: - case R_PPC64_DTPREL16_HI: - case R_PPC64_DTPREL16_HA: - case R_PPC64_DTPREL16_DS: - case R_PPC64_DTPREL16_LO_DS: - case R_PPC64_DTPREL16_HIGH: - case R_PPC64_DTPREL16_HIGHA: - case R_PPC64_DTPREL16_HIGHER: - case R_PPC64_DTPREL16_HIGHERA: - case R_PPC64_DTPREL16_HIGHEST: - case R_PPC64_DTPREL16_HIGHESTA: - break; - - /* Nor do these. */ - case R_PPC64_REL16: - case R_PPC64_REL16_LO: - case R_PPC64_REL16_HI: - case R_PPC64_REL16_HA: - case R_PPC64_REL16DX_HA: - break; - - /* Not supported as a dynamic relocation. */ - case R_PPC64_ADDR64_LOCAL: - if (bfd_link_pic (info)) - { - if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) - ppc_howto_init (); - /* xgettext:c-format */ - info->callbacks->einfo (_("%H: %s reloc unsupported " - "in shared libraries and PIEs.\n"), - abfd, sec, rel->r_offset, - ppc64_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - break; - - case R_PPC64_TOC16: - case R_PPC64_TOC16_DS: - htab->do_multi_toc = 1; - ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1; - /* Fall through. */ - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_HA: - case R_PPC64_TOC16_LO_DS: - sec->has_toc_reloc = 1; - break; - - /* Marker reloc. */ - case R_PPC64_ENTRY: - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_PPC64_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_PPC64_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - case R_PPC64_REL14: - case R_PPC64_REL14_BRTAKEN: - case R_PPC64_REL14_BRNTAKEN: - { - asection *dest = NULL; - - /* Heuristic: If jumping outside our section, chances are - we are going to need a stub. */ - if (h != NULL) - { - /* If the sym is weak it may be overridden later, so - don't assume we know where a weak sym lives. */ - if (h->root.type == bfd_link_hash_defined) - dest = h->root.u.def.section; - } - else - { - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - dest = bfd_section_from_elf_index (abfd, isym->st_shndx); - } - - if (dest != sec) - ppc64_elf_section_data (sec)->has_14bit_branch = 1; - } - /* Fall through. */ - - case R_PPC64_REL24: - plt_list = ifunc; - if (h != NULL) - { - h->needs_plt = 1; - if (h->root.root.string[0] == '.' - && h->root.root.string[1] != '\0') - ((struct ppc_link_hash_entry *) h)->is_func = 1; - - if (h == tga || h == dottga) - { - sec->has_tls_reloc = 1; - if (rel != relocs - && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD - || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD)) - /* We have a new-style __tls_get_addr call with - a marker reloc. */ - ; - else - /* Mark this section as having an old-style call. */ - sec->has_tls_get_addr_call = 1; - } - plt_list = &h->plt.plist; - } - - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - if (plt_list - && !update_plt_info (abfd, plt_list, rel->r_addend)) - return FALSE; - break; - - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_ADDR24: - goto dodyn; - - case R_PPC64_TPREL64: - tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL; - if (bfd_link_dll (info)) - info->flags |= DF_STATIC_TLS; - goto dotlstoc; - - case R_PPC64_DTPMOD64: - if (rel + 1 < rel_end - && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64) - && rel[1].r_offset == rel->r_offset + 8) - tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD; - else - tls_type = TLS_EXPLICIT | TLS_TLS | TLS_LD; - goto dotlstoc; - - case R_PPC64_DTPREL64: - tls_type = TLS_EXPLICIT | TLS_TLS | TLS_DTPREL; - if (rel != relocs - && rel[-1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPMOD64) - && rel[-1].r_offset == rel->r_offset - 8) - /* This is the second reloc of a dtpmod, dtprel pair. - Don't mark with TLS_DTPREL. */ - goto dodyn; - - dotlstoc: - sec->has_tls_reloc = 1; - if (h != NULL) - { - struct ppc_link_hash_entry *eh; - eh = (struct ppc_link_hash_entry *) h; - eh->tls_mask |= tls_type; - } - else - if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, - rel->r_addend, tls_type)) - return FALSE; - - ppc64_sec = ppc64_elf_section_data (sec); - if (ppc64_sec->sec_type != sec_toc) - { - bfd_size_type amt; - - /* One extra to simplify get_tls_mask. */ - amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned); - ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt); - if (ppc64_sec->u.toc.symndx == NULL) - return FALSE; - amt = sec->size * sizeof (bfd_vma) / 8; - ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt); - if (ppc64_sec->u.toc.add == NULL) - return FALSE; - BFD_ASSERT (ppc64_sec->sec_type == sec_normal); - ppc64_sec->sec_type = sec_toc; - } - BFD_ASSERT (rel->r_offset % 8 == 0); - ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx; - ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend; - - /* Mark the second slot of a GD or LD entry. - -1 to indicate GD and -2 to indicate LD. */ - if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD)) - ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1; - else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD)) - ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2; - goto dodyn; - - case R_PPC64_TPREL16: - case R_PPC64_TPREL16_LO: - case R_PPC64_TPREL16_HI: - case R_PPC64_TPREL16_HA: - case R_PPC64_TPREL16_DS: - case R_PPC64_TPREL16_LO_DS: - case R_PPC64_TPREL16_HIGH: - case R_PPC64_TPREL16_HIGHA: - case R_PPC64_TPREL16_HIGHER: - case R_PPC64_TPREL16_HIGHERA: - case R_PPC64_TPREL16_HIGHEST: - case R_PPC64_TPREL16_HIGHESTA: - if (bfd_link_dll (info)) - info->flags |= DF_STATIC_TLS; - goto dodyn; - - case R_PPC64_ADDR64: - if (is_opd - && rel + 1 < rel_end - && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC) - { - if (h != NULL) - ((struct ppc_link_hash_entry *) h)->is_func = 1; - } - /* Fall through. */ - - case R_PPC64_ADDR16: - case R_PPC64_ADDR16_DS: - case R_PPC64_ADDR16_HA: - case R_PPC64_ADDR16_HI: - case R_PPC64_ADDR16_HIGH: - case R_PPC64_ADDR16_HIGHA: - case R_PPC64_ADDR16_HIGHER: - case R_PPC64_ADDR16_HIGHERA: - case R_PPC64_ADDR16_HIGHEST: - case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_ADDR16_LO: - case R_PPC64_ADDR16_LO_DS: - if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1 - && rel->r_addend == 0) - { - /* We may need a .plt entry if this reloc refers to a - function in a shared lib. */ - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; - h->pointer_equality_needed = 1; - } - /* Fall through. */ - - case R_PPC64_REL30: - case R_PPC64_REL32: - case R_PPC64_REL64: - case R_PPC64_ADDR32: - case R_PPC64_UADDR16: - case R_PPC64_UADDR32: - case R_PPC64_UADDR64: - case R_PPC64_TOC: - if (h != NULL && !bfd_link_pic (info)) - /* We may need a copy reloc. */ - h->non_got_ref = 1; - - /* Don't propagate .opd relocs. */ - if (NO_OPD_RELOCS && is_opd) - break; - - /* 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 dyn_relocs field of the hash - table entry. A similar situation occurs when creating - shared libraries and symbol visibility changes render the - symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - dodyn: - if ((bfd_link_pic (info) - && (must_be_dyn_reloc (info, r_type) - || (h != NULL - && (!SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular)) - || (!bfd_link_pic (info) - && ifunc != NULL)) - { - /* 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) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **head; - - head = &((struct ppc_link_hash_entry *) h)->dyn_relocs; - p = *head; - if (p == NULL || p->sec != sec) - { - p = bfd_alloc (htab->elf.dynobj, sizeof *p); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - p->count += 1; - if (!must_be_dyn_reloc (info, r_type)) - p->pc_count += 1; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - struct ppc_dyn_relocs *p; - struct ppc_dyn_relocs **head; - bfd_boolean is_ifunc; - asection *s; - void *vpp; - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct ppc_dyn_relocs **) vpp; - is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC; - p = *head; - if (p != NULL && p->sec == sec && p->ifunc != is_ifunc) - p = p->next; - if (p == NULL || p->sec != sec || p->ifunc != is_ifunc) - { - p = bfd_alloc (htab->elf.dynobj, sizeof *p); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->ifunc = is_ifunc; - p->count = 0; - } - p->count += 1; - } - } - break; - - default: - break; - } - } - - return TRUE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - unsigned long iflags, oflags; - - if ((ibfd->flags & BFD_LINKER_CREATED) != 0) - return TRUE; - - if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd)) - return TRUE; - - if (!_bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - iflags = elf_elfheader (ibfd)->e_flags; - oflags = elf_elfheader (obfd)->e_flags; - - if (iflags & ~EF_PPC64_ABI) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else if (iflags != oflags && iflags != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: ABI version %ld is not compatible with ABI version %ld output"), - ibfd, iflags, oflags); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - _bfd_elf_ppc_merge_fp_attributes (ibfd, info); - - /* Merge Tag_compatibility attributes and any common GNU ones. */ - _bfd_elf_merge_object_attributes (ibfd, info); - - return TRUE; -} - -static bfd_boolean -ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr) -{ - /* Print normal ELF private data. */ - _bfd_elf_print_private_bfd_data (abfd, ptr); - - if (elf_elfheader (abfd)->e_flags != 0) - { - FILE *file = ptr; - - fprintf (file, _("private flags = 0x%lx:"), - elf_elfheader (abfd)->e_flags); - - if ((elf_elfheader (abfd)->e_flags & EF_PPC64_ABI) != 0) - fprintf (file, _(" [abiv%ld]"), - elf_elfheader (abfd)->e_flags & EF_PPC64_ABI); - fputc ('\n', file); - } - - return TRUE; -} - -/* OFFSET in OPD_SEC specifies a function descriptor. Return the address - of the code entry point, and its section, which must be in the same - object as OPD_SEC. Returns (bfd_vma) -1 on error. */ - -static bfd_vma -opd_entry_value (asection *opd_sec, - bfd_vma offset, - asection **code_sec, - bfd_vma *code_off, - bfd_boolean in_code_sec) -{ - bfd *opd_bfd = opd_sec->owner; - Elf_Internal_Rela *relocs; - Elf_Internal_Rela *lo, *hi, *look; - bfd_vma val; - - /* No relocs implies we are linking a --just-symbols object, or looking - at a final linked executable with addr2line or somesuch. */ - if (opd_sec->reloc_count == 0) - { - bfd_byte *contents = ppc64_elf_tdata (opd_bfd)->opd.contents; - - if (contents == NULL) - { - if (!bfd_malloc_and_get_section (opd_bfd, opd_sec, &contents)) - return (bfd_vma) -1; - ppc64_elf_tdata (opd_bfd)->opd.contents = contents; - } - - /* PR 17512: file: 64b9dfbb. */ - if (offset + 7 >= opd_sec->size || offset + 7 < offset) - return (bfd_vma) -1; - - val = bfd_get_64 (opd_bfd, contents + offset); - if (code_sec != NULL) - { - asection *sec, *likely = NULL; - - if (in_code_sec) - { - sec = *code_sec; - if (sec->vma <= val - && val < sec->vma + sec->size) - likely = sec; - else - val = -1; - } - else - for (sec = opd_bfd->sections; sec != NULL; sec = sec->next) - if (sec->vma <= val - && (sec->flags & SEC_LOAD) != 0 - && (sec->flags & SEC_ALLOC) != 0) - likely = sec; - if (likely != NULL) - { - *code_sec = likely; - if (code_off != NULL) - *code_off = val - likely->vma; - } - } - return val; - } - - BFD_ASSERT (is_ppc64_elf (opd_bfd)); - - relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs; - if (relocs == NULL) - relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE); - /* PR 17512: file: df8e1fd6. */ - if (relocs == NULL) - return (bfd_vma) -1; - - /* Go find the opd reloc at the sym address. */ - lo = relocs; - hi = lo + opd_sec->reloc_count - 1; /* ignore last reloc */ - val = (bfd_vma) -1; - while (lo < hi) - { - look = lo + (hi - lo) / 2; - if (look->r_offset < offset) - lo = look + 1; - else if (look->r_offset > offset) - hi = look; - else - { - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (opd_bfd); - - if (ELF64_R_TYPE (look->r_info) == R_PPC64_ADDR64 - && ELF64_R_TYPE ((look + 1)->r_info) == R_PPC64_TOC) - { - unsigned long symndx = ELF64_R_SYM (look->r_info); - asection *sec = NULL; - - if (symndx >= symtab_hdr->sh_info - && elf_sym_hashes (opd_bfd) != NULL) - { - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry *rh; - - sym_hashes = elf_sym_hashes (opd_bfd); - rh = sym_hashes[symndx - symtab_hdr->sh_info]; - if (rh != NULL) - { - rh = elf_follow_link (rh); - if (rh->root.type != bfd_link_hash_defined - && rh->root.type != bfd_link_hash_defweak) - break; - if (rh->root.u.def.section->owner == opd_bfd) - { - val = rh->root.u.def.value; - sec = rh->root.u.def.section; - } - } - } - - if (sec == NULL) - { - Elf_Internal_Sym *sym; - - if (symndx < symtab_hdr->sh_info) - { - sym = (Elf_Internal_Sym *) symtab_hdr->contents; - if (sym == NULL) - { - size_t symcnt = symtab_hdr->sh_info; - sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, - symcnt, 0, - NULL, NULL, NULL); - if (sym == NULL) - break; - symtab_hdr->contents = (bfd_byte *) sym; - } - sym += symndx; - } - else - { - sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, - 1, symndx, - NULL, NULL, NULL); - if (sym == NULL) - break; - } - sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); - if (sec == NULL) - break; - BFD_ASSERT ((sec->flags & SEC_MERGE) == 0); - val = sym->st_value; - } - - val += look->r_addend; - if (code_off != NULL) - *code_off = val; - if (code_sec != NULL) - { - if (in_code_sec && *code_sec != sec) - return -1; - else - *code_sec = sec; - } - if (sec->output_section != NULL) - val += sec->output_section->vma + sec->output_offset; - } - break; - } - } - - return val; -} - -/* If the ELF symbol SYM might be a function in SEC, return the - function size and set *CODE_OFF to the function's entry point, - otherwise return zero. */ - -static bfd_size_type -ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec, - bfd_vma *code_off) -{ - bfd_size_type size; - - if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT - | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0) - return 0; - - size = 0; - if (!(sym->flags & BSF_SYNTHETIC)) - size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; - - if (strcmp (sym->section->name, ".opd") == 0) - { - struct _opd_sec_data *opd = get_opd_info (sym->section); - bfd_vma symval = sym->value; - - if (opd != NULL - && opd->adjust != NULL - && elf_section_data (sym->section)->relocs != NULL) - { - /* opd_entry_value will use cached relocs that have been - adjusted, but with raw symbols. That means both local - and global symbols need adjusting. */ - long adjust = opd->adjust[OPD_NDX (symval)]; - if (adjust == -1) - return 0; - symval += adjust; - } - - if (opd_entry_value (sym->section, symval, - &sec, code_off, TRUE) == (bfd_vma) -1) - return 0; - /* An old ABI binary with dot-syms has a size of 24 on the .opd - symbol. This size has nothing to do with the code size of the - function, which is what we're supposed to return, but the - code size isn't available without looking up the dot-sym. - However, doing that would be a waste of time particularly - since elf_find_function will look at the dot-sym anyway. - Now, elf_find_function will keep the largest size of any - function sym found at the code address of interest, so return - 1 here to avoid it incorrectly caching a larger function size - for a small function. This does mean we return the wrong - size for a new-ABI function of size 24, but all that does is - disable caching for such functions. */ - if (size == 24) - size = 1; - } - else - { - if (sym->section != sec) - return 0; - *code_off = sym->value; - } - if (size == 0) - size = 1; - return size; -} - -/* Return true if symbol is a strong function defined in an ELFv2 - object with st_other localentry bits of zero, ie. its local entry - point coincides with its global entry point. */ - -static bfd_boolean -is_elfv2_localentry0 (struct elf_link_hash_entry *h) -{ - return (h != NULL - && h->type == STT_FUNC - && h->root.type == bfd_link_hash_defined - && (STO_PPC64_LOCAL_MASK & h->other) == 0 - && !((struct ppc_link_hash_entry *) h)->non_zero_localentry - && is_ppc64_elf (h->root.u.def.section->owner) - && abiversion (h->root.u.def.section->owner) >= 2); -} - -/* Return true if symbol is defined in a regular object file. */ - -static bfd_boolean -is_static_defined (struct elf_link_hash_entry *h) -{ - return ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section != NULL - && h->root.u.def.section->output_section != NULL); -} - -/* If FDH is a function descriptor symbol, return the associated code - entry symbol if it is defined. Return NULL otherwise. */ - -static struct ppc_link_hash_entry * -defined_code_entry (struct ppc_link_hash_entry *fdh) -{ - if (fdh->is_func_descriptor) - { - struct ppc_link_hash_entry *fh = ppc_follow_link (fdh->oh); - if (fh->elf.root.type == bfd_link_hash_defined - || fh->elf.root.type == bfd_link_hash_defweak) - return fh; - } - return NULL; -} - -/* If FH is a function code entry symbol, return the associated - function descriptor symbol if it is defined. Return NULL otherwise. */ - -static struct ppc_link_hash_entry * -defined_func_desc (struct ppc_link_hash_entry *fh) -{ - if (fh->oh != NULL - && fh->oh->is_func_descriptor) - { - struct ppc_link_hash_entry *fdh = ppc_follow_link (fh->oh); - if (fdh->elf.root.type == bfd_link_hash_defined - || fdh->elf.root.type == bfd_link_hash_defweak) - return fdh; - } - return NULL; -} - -static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *); - -/* Garbage collect sections, after first dealing with dot-symbols. */ - -static bfd_boolean -ppc64_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab != NULL && htab->need_func_desc_adj) - { - elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); - htab->need_func_desc_adj = 0; - } - return bfd_elf_gc_sections (abfd, info); -} - -/* Mark all our entry sym sections, both opd and code section. */ - -static void -ppc64_elf_gc_keep (struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - struct bfd_sym_chain *sym; - - if (htab == NULL) - return; - - for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) - { - struct ppc_link_hash_entry *eh, *fh; - asection *sec; - - eh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, TRUE); - if (eh == NULL) - continue; - if (eh->elf.root.type != bfd_link_hash_defined - && eh->elf.root.type != bfd_link_hash_defweak) - continue; - - fh = defined_code_entry (eh); - if (fh != NULL) - { - sec = fh->elf.root.u.def.section; - sec->flags |= SEC_KEEP; - } - else if (get_opd_info (eh->elf.root.u.def.section) != NULL - && opd_entry_value (eh->elf.root.u.def.section, - eh->elf.root.u.def.value, - &sec, NULL, FALSE) != (bfd_vma) -1) - sec->flags |= SEC_KEEP; - - sec = eh->elf.root.u.def.section; - sec->flags |= SEC_KEEP; - } -} - -/* Mark sections containing dynamically referenced symbols. When - building shared libraries, we must assume that any visible symbol is - referenced. */ - -static bfd_boolean -ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info = (struct bfd_link_info *) inf; - struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; - struct ppc_link_hash_entry *fdh; - struct bfd_elf_dynamic_list *d = info->dynamic_list; - - /* Dynamic linking info is on the func descriptor sym. */ - fdh = defined_func_desc (eh); - if (fdh != NULL) - eh = fdh; - - if ((eh->elf.root.type == bfd_link_hash_defined - || eh->elf.root.type == bfd_link_hash_defweak) - && ((eh->elf.ref_dynamic && !eh->elf.forced_local) - || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf)) - && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL - && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN - && (!bfd_link_executable (info) - || info->gc_keep_exported - || info->export_dynamic - || (eh->elf.dynamic - && d != NULL - && (*d->match) (&d->head, NULL, eh->elf.root.root.string))) - && (eh->elf.versioned >= versioned - || !bfd_hide_sym_by_version (info->version_info, - eh->elf.root.root.string))))) - { - asection *code_sec; - struct ppc_link_hash_entry *fh; - - eh->elf.root.u.def.section->flags |= SEC_KEEP; - - /* Function descriptor syms cause the associated - function code sym section to be marked. */ - fh = defined_code_entry (eh); - if (fh != NULL) - { - code_sec = fh->elf.root.u.def.section; - code_sec->flags |= SEC_KEEP; - } - else if (get_opd_info (eh->elf.root.u.def.section) != NULL - && opd_entry_value (eh->elf.root.u.def.section, - eh->elf.root.u.def.value, - &code_sec, NULL, FALSE) != (bfd_vma) -1) - code_sec->flags |= SEC_KEEP; - } - - return TRUE; -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -ppc64_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - asection *rsec; - - /* Syms return NULL if we're marking .opd, so we avoid marking all - function sections, as all functions are referenced in .opd. */ - rsec = NULL; - if (get_opd_info (sec) != NULL) - return rsec; - - if (h != NULL) - { - enum elf_ppc64_reloc_type r_type; - struct ppc_link_hash_entry *eh, *fh, *fdh; - - r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - case R_PPC64_GNU_VTINHERIT: - case R_PPC64_GNU_VTENTRY: - break; - - default: - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - eh = (struct ppc_link_hash_entry *) h; - fdh = defined_func_desc (eh); - if (fdh != NULL) - { - /* -mcall-aixdesc code references the dot-symbol on - a call reloc. Mark the function descriptor too - against garbage collection. */ - fdh->elf.mark = 1; - if (fdh->elf.is_weakalias) - weakdef (&fdh->elf)->mark = 1; - eh = fdh; - } - - /* Function descriptor syms cause the associated - function code sym section to be marked. */ - fh = defined_code_entry (eh); - if (fh != NULL) - { - /* They also mark their opd section. */ - eh->elf.root.u.def.section->gc_mark = 1; - - rsec = fh->elf.root.u.def.section; - } - else if (get_opd_info (eh->elf.root.u.def.section) != NULL - && opd_entry_value (eh->elf.root.u.def.section, - eh->elf.root.u.def.value, - &rsec, NULL, FALSE) != (bfd_vma) -1) - eh->elf.root.u.def.section->gc_mark = 1; - else - rsec = h->root.u.def.section; - break; - - case bfd_link_hash_common: - rsec = h->root.u.c.p->section; - break; - - default: - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); - } - } - } - else - { - struct _opd_sec_data *opd; - - rsec = bfd_section_from_elf_index (sec->owner, sym->st_shndx); - opd = get_opd_info (rsec); - if (opd != NULL && opd->func_sec != NULL) - { - rsec->gc_mark = 1; - - rsec = opd->func_sec[OPD_NDX (sym->st_value + rel->r_addend)]; - } - } - - return rsec; -} - -/* The maximum size of .sfpr. */ -#define SFPR_MAX (218*4) - -struct sfpr_def_parms -{ - const char name[12]; - unsigned char lo, hi; - bfd_byte * (*write_ent) (bfd *, bfd_byte *, int); - bfd_byte * (*write_tail) (bfd *, bfd_byte *, int); -}; - -/* Auto-generate _save*, _rest* functions in .sfpr. - If STUB_SEC is non-null, define alias symbols in STUB_SEC - instead. */ - -static bfd_boolean -sfpr_define (struct bfd_link_info *info, - const struct sfpr_def_parms *parm, - asection *stub_sec) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - unsigned int i; - size_t len = strlen (parm->name); - bfd_boolean writing = FALSE; - char sym[16]; - - if (htab == NULL) - return FALSE; - - memcpy (sym, parm->name, len); - sym[len + 2] = 0; - - for (i = parm->lo; i <= parm->hi; i++) - { - struct ppc_link_hash_entry *h; - - sym[len + 0] = i / 10 + '0'; - sym[len + 1] = i % 10 + '0'; - h = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, sym, writing, TRUE, TRUE); - if (stub_sec != NULL) - { - if (h != NULL - && h->elf.root.type == bfd_link_hash_defined - && h->elf.root.u.def.section == htab->sfpr) - { - struct elf_link_hash_entry *s; - char buf[32]; - sprintf (buf, "%08x.%s", stub_sec->id & 0xffffffff, sym); - s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE); - if (s == NULL) - return FALSE; - if (s->root.type == bfd_link_hash_new - || (s->root.type = bfd_link_hash_defined - && s->root.u.def.section == stub_sec)) - { - s->root.type = bfd_link_hash_defined; - s->root.u.def.section = stub_sec; - s->root.u.def.value = (stub_sec->size - + h->elf.root.u.def.value); - s->ref_regular = 1; - s->def_regular = 1; - s->ref_regular_nonweak = 1; - s->forced_local = 1; - s->non_elf = 0; - s->root.linker_def = 1; - } - } - continue; - } - if (h != NULL) - { - h->save_res = 1; - if (!h->elf.def_regular) - { - h->elf.root.type = bfd_link_hash_defined; - h->elf.root.u.def.section = htab->sfpr; - h->elf.root.u.def.value = htab->sfpr->size; - h->elf.type = STT_FUNC; - h->elf.def_regular = 1; - h->elf.non_elf = 0; - _bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE); - writing = TRUE; - if (htab->sfpr->contents == NULL) - { - htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX); - if (htab->sfpr->contents == NULL) - return FALSE; - } - } - } - if (writing) - { - bfd_byte *p = htab->sfpr->contents + htab->sfpr->size; - if (i != parm->hi) - p = (*parm->write_ent) (htab->elf.dynobj, p, i); - else - p = (*parm->write_tail) (htab->elf.dynobj, p, i); - htab->sfpr->size = p - htab->sfpr->contents; - } - } - - return TRUE; -} - -static bfd_byte * -savegpr0 (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, STD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); - return p + 4; -} - -static bfd_byte * -savegpr0_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = savegpr0 (abfd, p, r); - bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p); - p = p + 4; - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -restgpr0 (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); - return p + 4; -} - -static bfd_byte * -restgpr0_tail (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p); - p = p + 4; - p = restgpr0 (abfd, p, r); - bfd_put_32 (abfd, MTLR_R0, p); - p = p + 4; - if (r == 29) - { - p = restgpr0 (abfd, p, 30); - p = restgpr0 (abfd, p, 31); - } - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -savegpr1 (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, STD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p); - return p + 4; -} - -static bfd_byte * -savegpr1_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = savegpr1 (abfd, p, r); - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -restgpr1 (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p); - return p + 4; -} - -static bfd_byte * -restgpr1_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = restgpr1 (abfd, p, r); - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -savefpr (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, STFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); - return p + 4; -} - -static bfd_byte * -savefpr0_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = savefpr (abfd, p, r); - bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p); - p = p + 4; - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -restfpr (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); - return p + 4; -} - -static bfd_byte * -restfpr0_tail (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p); - p = p + 4; - p = restfpr (abfd, p, r); - bfd_put_32 (abfd, MTLR_R0, p); - p = p + 4; - if (r == 29) - { - p = restfpr (abfd, p, 30); - p = restfpr (abfd, p, 31); - } - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -savefpr1_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = savefpr (abfd, p, r); - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -restfpr1_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = restfpr (abfd, p, r); - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -savevr (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p); - p = p + 4; - bfd_put_32 (abfd, STVX_VR0_R12_R0 + (r << 21), p); - return p + 4; -} - -static bfd_byte * -savevr_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = savevr (abfd, p, r); - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -static bfd_byte * -restvr (bfd *abfd, bfd_byte *p, int r) -{ - bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p); - p = p + 4; - bfd_put_32 (abfd, LVX_VR0_R12_R0 + (r << 21), p); - return p + 4; -} - -static bfd_byte * -restvr_tail (bfd *abfd, bfd_byte *p, int r) -{ - p = restvr (abfd, p, r); - bfd_put_32 (abfd, BLR, p); - return p + 4; -} - -/* Called via elf_link_hash_traverse to transfer dynamic linking - information on function code symbol entries to their corresponding - function descriptor symbol entries. */ - -static bfd_boolean -func_desc_adjust (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct ppc_link_hash_table *htab; - struct ppc_link_hash_entry *fh; - struct ppc_link_hash_entry *fdh; - bfd_boolean force_local; - - fh = (struct ppc_link_hash_entry *) h; - if (fh->elf.root.type == bfd_link_hash_indirect) - return TRUE; - - if (!fh->is_func) - return TRUE; - - if (fh->elf.root.root.string[0] != '.' - || fh->elf.root.root.string[1] == '\0') - return TRUE; - - info = inf; - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Find the corresponding function descriptor symbol. */ - fdh = lookup_fdh (fh, htab); - - /* Resolve undefined references to dot-symbols as the value - in the function descriptor, if we have one in a regular object. - This is to satisfy cases like ".quad .foo". Calls to functions - in dynamic objects are handled elsewhere. */ - if ((fh->elf.root.type == bfd_link_hash_undefined - || fh->elf.root.type == bfd_link_hash_undefweak) - && (fdh->elf.root.type == bfd_link_hash_defined - || fdh->elf.root.type == bfd_link_hash_defweak) - && get_opd_info (fdh->elf.root.u.def.section) != NULL - && opd_entry_value (fdh->elf.root.u.def.section, - fdh->elf.root.u.def.value, - &fh->elf.root.u.def.section, - &fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1) - { - fh->elf.root.type = fdh->elf.root.type; - fh->elf.forced_local = 1; - fh->elf.def_regular = fdh->elf.def_regular; - fh->elf.def_dynamic = fdh->elf.def_dynamic; - } - - if (!fh->elf.dynamic) - { - struct plt_entry *ent; - - for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; - if (ent == NULL) - return TRUE; - } - - /* Create a descriptor as undefined if necessary. */ - if (fdh == NULL - && !bfd_link_executable (info) - && (fh->elf.root.type == bfd_link_hash_undefined - || fh->elf.root.type == bfd_link_hash_undefweak)) - { - fdh = make_fdh (info, fh); - if (fdh == NULL) - return FALSE; - } - - /* We can't support overriding of symbols on a fake descriptor. */ - if (fdh != NULL - && fdh->fake - && (fh->elf.root.type == bfd_link_hash_defined - || fh->elf.root.type == bfd_link_hash_defweak)) - _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE); - - /* Transfer dynamic linking information to the function descriptor. */ - if (fdh != NULL) - { - fdh->elf.ref_regular |= fh->elf.ref_regular; - fdh->elf.ref_dynamic |= fh->elf.ref_dynamic; - fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak; - fdh->elf.non_got_ref |= fh->elf.non_got_ref; - fdh->elf.dynamic |= fh->elf.dynamic; - fdh->elf.needs_plt |= (fh->elf.needs_plt - || fh->elf.type == STT_FUNC - || fh->elf.type == STT_GNU_IFUNC); - move_plt_plist (fh, fdh); - - if (!fdh->elf.forced_local - && fh->elf.dynindx != -1) - if (!bfd_elf_link_record_dynamic_symbol (info, &fdh->elf)) - return FALSE; - } - - /* Now that the info is on the function descriptor, clear the - function code sym info. Any function code syms for which we - don't have a definition in a regular file, we force local. - This prevents a shared library from exporting syms that have - been imported from another library. Function code syms that - are really in the library we must leave global to prevent the - linker dragging in a definition from a static library. */ - force_local = (!fh->elf.def_regular - || fdh == NULL - || !fdh->elf.def_regular - || fdh->elf.forced_local); - _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local); - - return TRUE; -} - -static const struct sfpr_def_parms save_res_funcs[] = - { - { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail }, - { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail }, - { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail }, - { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail }, - { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail }, - { "_savefpr_", 14, 31, savefpr, savefpr0_tail }, - { "_restfpr_", 14, 29, restfpr, restfpr0_tail }, - { "_restfpr_", 30, 31, restfpr, restfpr0_tail }, - { "._savef", 14, 31, savefpr, savefpr1_tail }, - { "._restf", 14, 31, restfpr, restfpr1_tail }, - { "_savevr_", 20, 31, savevr, savevr_tail }, - { "_restvr_", 20, 31, restvr, restvr_tail } - }; - -/* Called near the start of bfd_elf_size_dynamic_sections. We use - this hook to a) provide some gcc support functions, and b) transfer - dynamic linking information gathered so far on function code symbol - entries, to their corresponding function descriptor symbol entries. */ - -static bfd_boolean -ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Provide any missing _save* and _rest* functions. */ - if (htab->sfpr != NULL) - { - unsigned int i; - - htab->sfpr->size = 0; - for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++) - if (!sfpr_define (info, &save_res_funcs[i], NULL)) - return FALSE; - if (htab->sfpr->size == 0) - htab->sfpr->flags |= SEC_EXCLUDE; - } - - if (bfd_link_relocatable (info)) - return TRUE; - - if (htab->elf.hgot != NULL) - { - _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE); - /* Make .TOC. defined so as to prevent it being made dynamic. - The wrong value here is fixed later in ppc64_elf_set_toc. */ - if (!htab->elf.hgot->def_regular - || htab->elf.hgot->root.type != bfd_link_hash_defined) - { - htab->elf.hgot->root.type = bfd_link_hash_defined; - htab->elf.hgot->root.u.def.value = 0; - htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr; - htab->elf.hgot->def_regular = 1; - htab->elf.hgot->root.linker_def = 1; - } - htab->elf.hgot->type = STT_OBJECT; - htab->elf.hgot->other = ((htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1)) - | STV_HIDDEN); - } - - if (htab->need_func_desc_adj) - { - elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); - htab->need_func_desc_adj = 0; - } - - return TRUE; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct ppc_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - eh = (struct ppc_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) - return p->sec; - } - return NULL; -} - -/* Return true if we have dynamic relocs against H or any of its weak - aliases, that apply to read-only sections. Cannot be used after - size_dynamic_sections. */ - -static bfd_boolean -alias_readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct ppc_link_hash_entry *eh; - - eh = (struct ppc_link_hash_entry *) h; - do - { - if (readonly_dynrelocs (&eh->elf)) - return TRUE; - eh = (struct ppc_link_hash_entry *) eh->elf.u.alias; - } while (eh != NULL && &eh->elf != h); - - return FALSE; -} - -/* Return whether EH has pc-relative dynamic relocs. */ - -static bfd_boolean -pc_dynrelocs (struct ppc_link_hash_entry *eh) -{ - struct elf_dyn_relocs *p; - - for (p = eh->dyn_relocs; p != NULL; p = p->next) - if (p->pc_count != 0) - return TRUE; - return FALSE; -} - -/* Return true if a global entry stub will be created for H. Valid - for ELFv2 before plt entries have been allocated. */ - -static bfd_boolean -global_entry_stub (struct elf_link_hash_entry *h) -{ - struct plt_entry *pent; - - if (!h->pointer_equality_needed - || h->def_regular) - return FALSE; - - for (pent = h->plt.plist; pent != NULL; pent = pent->next) - if (pent->plt.refcount > 0 - && pent->addend == 0) - return TRUE; - - return FALSE; -} - -/* 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 -ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct ppc_link_hash_table *htab; - asection *s, *srel; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Deal with function syms. */ - if (h->type == STT_FUNC - || h->type == STT_GNU_IFUNC - || h->needs_plt) - { - bfd_boolean local = (((struct ppc_link_hash_entry *) h)->save_res - || SYMBOL_CALLS_LOCAL (info, h) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - /* Discard dyn_relocs when non-pic if we've decided that a - function symbol is local and not an ifunc. We keep dynamic - relocs for ifuncs when local rather than always emitting a - plt call stub for them and defining the symbol on the call - stub. We can't do that for ELFv1 anyway (a function symbol - is defined on a descriptor, not code) and it can be faster at - run-time due to not needing to bounce through a stub. The - dyn_relocs for ifuncs will be applied even in a static - executable. */ - if (!bfd_link_pic (info) - && h->type != STT_GNU_IFUNC - && local) - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; - - /* Clear procedure linkage table information for any symbol that - won't need a .plt entry. */ - struct plt_entry *ent; - for (ent = h->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; - if (ent == NULL - || (h->type != STT_GNU_IFUNC && local)) - { - h->plt.plist = NULL; - h->needs_plt = 0; - h->pointer_equality_needed = 0; - } - else if (abiversion (info->output_bfd) >= 2) - { - /* Taking a function's address in a read/write section - doesn't require us to define the function symbol in the - executable on a global entry stub. A dynamic reloc can - be used instead. The reason we prefer a few more dynamic - relocs is that calling via a global entry stub costs a - few more instructions, and pointer_equality_needed causes - extra work in ld.so when resolving these symbols. */ - if (global_entry_stub (h)) - { - if (!readonly_dynrelocs (h)) - { - h->pointer_equality_needed = 0; - /* If we haven't seen a branch reloc then we don't need - a plt entry. */ - if (!h->needs_plt) - h->plt.plist = NULL; - } - else if (!bfd_link_pic (info)) - /* We are going to be defining the function symbol on the - plt stub, so no dyn_relocs needed when non-pic. */ - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; - } - - /* ELFv2 function symbols can't have copy relocs. */ - return TRUE; - } - else if (!h->needs_plt - && !readonly_dynrelocs (h)) - { - /* If we haven't seen a branch reloc then we don't need a - plt entry. */ - h->plt.plist = NULL; - h->pointer_equality_needed = 0; - return TRUE; - } - } - else - h->plt.plist = NULL; - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - if (def->root.u.def.section == htab->elf.sdynbss - || def->root.u.def.section == htab->elf.sdynrelro) - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; - return TRUE; - } - - /* 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 (bfd_link_pic (info)) - 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; - - /* Don't generate a copy reloc for symbols defined in the executable. */ - if (!h->def_dynamic || !h->ref_regular || h->def_regular - - /* If -z nocopyreloc was given, don't generate them either. */ - || info->nocopyreloc - - /* If we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h)) - - /* Protected variables do not work with .dynbss. The copy in - .dynbss won't be used by the shared library with the protected - definition for the variable. Text relocations are preferable - to an incorrect program. */ - || h->protected_def) - return TRUE; - - if (h->plt.plist != NULL) - { - /* We should never get here, but unfortunately there are versions - of gcc out there that improperly (for this ABI) put initialized - function pointers, vtable refs and suchlike in read-only - sections. Allow them to proceed, but warn that this might - break at runtime. */ - info->callbacks->einfo - (_("%P: copy reloc against `%T' requires lazy plt linking; " - "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"), - h->root.root.string); - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* 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. */ - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) - { - s = htab->elf.sdynrelro; - srel = htab->elf.sreldynrelro; - } - else - { - s = htab->elf.sdynbss; - srel = htab->elf.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - /* We must generate a R_PPC64_COPY reloc to tell the dynamic - linker to copy the initial value out of the dynamic object - and into the runtime process image. */ - srel->size += sizeof (Elf64_External_Rela); - h->needs_copy = 1; - } - - /* We no longer want dyn_relocs. */ - ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL; - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* If given a function descriptor symbol, hide both the function code - sym and the descriptor. */ -static void -ppc64_elf_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - bfd_boolean force_local) -{ - struct ppc_link_hash_entry *eh; - _bfd_elf_link_hash_hide_symbol (info, h, force_local); - - eh = (struct ppc_link_hash_entry *) h; - if (eh->is_func_descriptor) - { - struct ppc_link_hash_entry *fh = eh->oh; - - if (fh == NULL) - { - const char *p, *q; - struct elf_link_hash_table *htab = elf_hash_table (info); - char save; - - /* We aren't supposed to use alloca in BFD because on - systems which do not have alloca the version in libiberty - calls xmalloc, which might cause the program to crash - when it runs out of memory. This function doesn't have a - return status, so there's no way to gracefully return an - error. So cheat. We know that string[-1] can be safely - accessed; It's either a string in an ELF string table, - or allocated in an objalloc structure. */ - - p = eh->elf.root.root.string - 1; - save = *p; - *(char *) p = '.'; - fh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE); - *(char *) p = save; - - /* Unfortunately, if it so happens that the string we were - looking for was allocated immediately before this string, - then we overwrote the string terminator. That's the only - reason the lookup should fail. */ - if (fh == NULL) - { - q = eh->elf.root.root.string + strlen (eh->elf.root.root.string); - while (q >= eh->elf.root.root.string && *q == *p) - --q, --p; - if (q < eh->elf.root.root.string && *p == '.') - fh = (struct ppc_link_hash_entry *) - elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE); - } - if (fh != NULL) - { - eh->oh = fh; - fh->oh = eh; - } - } - if (fh != NULL) - _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local); - } -} - -static bfd_boolean -get_sym_h (struct elf_link_hash_entry **hp, - Elf_Internal_Sym **symp, - asection **symsecp, - unsigned char **tls_maskp, - Elf_Internal_Sym **locsymsp, - unsigned long r_symndx, - bfd *ibfd) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); - - if (r_symndx >= symtab_hdr->sh_info) - { - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); - struct elf_link_hash_entry *h; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - h = elf_follow_link (h); - - if (hp != NULL) - *hp = h; - - if (symp != NULL) - *symp = NULL; - - if (symsecp != NULL) - { - asection *symsec = NULL; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - symsec = h->root.u.def.section; - *symsecp = symsec; - } - - if (tls_maskp != NULL) - { - struct ppc_link_hash_entry *eh; - - eh = (struct ppc_link_hash_entry *) h; - *tls_maskp = &eh->tls_mask; - } - } - else - { - Elf_Internal_Sym *sym; - Elf_Internal_Sym *locsyms = *locsymsp; - - if (locsyms == NULL) - { - locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; - if (locsyms == NULL) - locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, - symtab_hdr->sh_info, - 0, NULL, NULL, NULL); - if (locsyms == NULL) - return FALSE; - *locsymsp = locsyms; - } - sym = locsyms + r_symndx; - - if (hp != NULL) - *hp = NULL; - - if (symp != NULL) - *symp = sym; - - if (symsecp != NULL) - *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx); - - if (tls_maskp != NULL) - { - struct got_entry **lgot_ents; - unsigned char *tls_mask; - - tls_mask = NULL; - lgot_ents = elf_local_got_ents (ibfd); - if (lgot_ents != NULL) - { - struct plt_entry **local_plt = (struct plt_entry **) - (lgot_ents + symtab_hdr->sh_info); - unsigned char *lgot_masks = (unsigned char *) - (local_plt + symtab_hdr->sh_info); - tls_mask = &lgot_masks[r_symndx]; - } - *tls_maskp = tls_mask; - } - } - return TRUE; -} - -/* Returns TLS_MASKP for the given REL symbol. Function return is 0 on - error, 2 on a toc GD type suitable for optimization, 3 on a toc LD - type suitable for optimization, and 1 otherwise. */ - -static int -get_tls_mask (unsigned char **tls_maskp, - unsigned long *toc_symndx, - bfd_vma *toc_addend, - Elf_Internal_Sym **locsymsp, - const Elf_Internal_Rela *rel, - bfd *ibfd) -{ - unsigned long r_symndx; - int next_r; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - asection *sec; - bfd_vma off; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) - return 0; - - if ((*tls_maskp != NULL && **tls_maskp != 0) - || sec == NULL - || ppc64_elf_section_data (sec) == NULL - || ppc64_elf_section_data (sec)->sec_type != sec_toc) - return 1; - - /* Look inside a TOC section too. */ - if (h != NULL) - { - BFD_ASSERT (h->root.type == bfd_link_hash_defined); - off = h->root.u.def.value; - } - else - off = sym->st_value; - off += rel->r_addend; - BFD_ASSERT (off % 8 == 0); - r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8]; - next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1]; - if (toc_symndx != NULL) - *toc_symndx = r_symndx; - if (toc_addend != NULL) - *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8]; - if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) - return 0; - if ((h == NULL || is_static_defined (h)) - && (next_r == -1 || next_r == -2)) - return 1 - next_r; - return 1; -} - -/* Find (or create) an entry in the tocsave hash table. */ - -static struct tocsave_entry * -tocsave_find (struct ppc_link_hash_table *htab, - enum insert_option insert, - Elf_Internal_Sym **local_syms, - const Elf_Internal_Rela *irela, - bfd *ibfd) -{ - unsigned long r_indx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - struct tocsave_entry ent, *p; - hashval_t hash; - struct tocsave_entry **slot; - - r_indx = ELF64_R_SYM (irela->r_info); - if (!get_sym_h (&h, &sym, &ent.sec, NULL, local_syms, r_indx, ibfd)) - return NULL; - if (ent.sec == NULL || ent.sec->output_section == NULL) - { - _bfd_error_handler - (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"), ibfd); - return NULL; - } - - if (h != NULL) - ent.offset = h->root.u.def.value; - else - ent.offset = sym->st_value; - ent.offset += irela->r_addend; - - hash = tocsave_htab_hash (&ent); - slot = ((struct tocsave_entry **) - htab_find_slot_with_hash (htab->tocsave_htab, &ent, hash, insert)); - if (slot == NULL) - return NULL; - - if (*slot == NULL) - { - p = (struct tocsave_entry *) bfd_alloc (ibfd, sizeof (*p)); - if (p == NULL) - return NULL; - *p = ent; - *slot = p; - } - return *slot; -} - -/* Adjust all global syms defined in opd sections. In gcc generated - code for the old ABI, these will already have been done. */ - -static bfd_boolean -adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) -{ - struct ppc_link_hash_entry *eh; - asection *sym_sec; - struct _opd_sec_data *opd; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - return TRUE; - - eh = (struct ppc_link_hash_entry *) h; - if (eh->adjust_done) - return TRUE; - - sym_sec = eh->elf.root.u.def.section; - opd = get_opd_info (sym_sec); - if (opd != NULL && opd->adjust != NULL) - { - long adjust = opd->adjust[OPD_NDX (eh->elf.root.u.def.value)]; - if (adjust == -1) - { - /* This entry has been deleted. */ - asection *dsec = ppc64_elf_tdata (sym_sec->owner)->deleted_section; - if (dsec == NULL) - { - for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next) - if (discarded_section (dsec)) - { - ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec; - break; - } - } - eh->elf.root.u.def.value = 0; - eh->elf.root.u.def.section = dsec; - } - else - eh->elf.root.u.def.value += adjust; - eh->adjust_done = 1; - } - return TRUE; -} - -/* Handles decrementing dynamic reloc counts for the reloc specified by - R_INFO in section SEC. If LOCAL_SYMS is NULL, then H and SYM - have already been determined. */ - -static bfd_boolean -dec_dynrel_count (bfd_vma r_info, - asection *sec, - struct bfd_link_info *info, - Elf_Internal_Sym **local_syms, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - enum elf_ppc64_reloc_type r_type; - asection *sym_sec = NULL; - - /* Can this reloc be dynamic? This switch, and later tests here - should be kept in sync with the code in check_relocs. */ - r_type = ELF64_R_TYPE (r_info); - switch (r_type) - { - default: - return TRUE; - - case R_PPC64_TPREL16: - case R_PPC64_TPREL16_LO: - case R_PPC64_TPREL16_HI: - case R_PPC64_TPREL16_HA: - case R_PPC64_TPREL16_DS: - case R_PPC64_TPREL16_LO_DS: - case R_PPC64_TPREL16_HIGH: - case R_PPC64_TPREL16_HIGHA: - case R_PPC64_TPREL16_HIGHER: - case R_PPC64_TPREL16_HIGHERA: - case R_PPC64_TPREL16_HIGHEST: - case R_PPC64_TPREL16_HIGHESTA: - case R_PPC64_TPREL64: - case R_PPC64_DTPMOD64: - case R_PPC64_DTPREL64: - case R_PPC64_ADDR64: - case R_PPC64_REL30: - case R_PPC64_REL32: - case R_PPC64_REL64: - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_ADDR16: - case R_PPC64_ADDR16_DS: - case R_PPC64_ADDR16_HA: - case R_PPC64_ADDR16_HI: - case R_PPC64_ADDR16_HIGH: - case R_PPC64_ADDR16_HIGHA: - case R_PPC64_ADDR16_HIGHER: - case R_PPC64_ADDR16_HIGHERA: - case R_PPC64_ADDR16_HIGHEST: - case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_ADDR16_LO: - case R_PPC64_ADDR16_LO_DS: - case R_PPC64_ADDR24: - case R_PPC64_ADDR32: - case R_PPC64_UADDR16: - case R_PPC64_UADDR32: - case R_PPC64_UADDR64: - case R_PPC64_TOC: - break; - } - - if (local_syms != NULL) - { - unsigned long r_symndx; - bfd *ibfd = sec->owner; - - r_symndx = ELF64_R_SYM (r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd)) - return FALSE; - } - - if ((bfd_link_pic (info) - && (must_be_dyn_reloc (info, r_type) - || (h != NULL - && (!SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - ; - else - return TRUE; - - if (h != NULL) - { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **pp; - pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs; - - /* elf_gc_sweep may have already removed all dyn relocs associated - with local syms for a given section. Also, symbol flags are - changed by elf_gc_sweep_symbol, confusing the test above. Don't - report a dynreloc miscount. */ - if (*pp == NULL && info->gc_sections) - return TRUE; - - while ((p = *pp) != NULL) - { - if (p->sec == sec) - { - if (!must_be_dyn_reloc (info, r_type)) - p->pc_count -= 1; - p->count -= 1; - if (p->count == 0) - *pp = p->next; - return TRUE; - } - pp = &p->next; - } - } - else - { - struct ppc_dyn_relocs *p; - struct ppc_dyn_relocs **pp; - void *vpp; - bfd_boolean is_ifunc; - - if (local_syms == NULL) - sym_sec = bfd_section_from_elf_index (sec->owner, sym->st_shndx); - if (sym_sec == NULL) - sym_sec = sec; - - vpp = &elf_section_data (sym_sec)->local_dynrel; - pp = (struct ppc_dyn_relocs **) vpp; - - if (*pp == NULL && info->gc_sections) - return TRUE; - - is_ifunc = ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC; - while ((p = *pp) != NULL) - { - if (p->sec == sec && p->ifunc == is_ifunc) - { - p->count -= 1; - if (p->count == 0) - *pp = p->next; - return TRUE; - } - pp = &p->next; - } - } - - /* xgettext:c-format */ - info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"), - sec->owner, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; -} - -/* Remove unused Official Procedure Descriptor entries. Currently we - only remove those associated with functions in discarded link-once - sections, or weakly defined functions that have been overridden. It - would be possible to remove many more entries for statically linked - applications. */ - -bfd_boolean -ppc64_elf_edit_opd (struct bfd_link_info *info) -{ - bfd *ibfd; - bfd_boolean some_edited = FALSE; - asection *need_pad = NULL; - struct ppc_link_hash_table *htab; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *sec; - Elf_Internal_Rela *relstart, *rel, *relend; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *local_syms; - struct _opd_sec_data *opd; - bfd_boolean need_edit, add_aux_fields, broken; - bfd_size_type cnt_16b = 0; - - if (!is_ppc64_elf (ibfd)) - continue; - - sec = bfd_get_section_by_name (ibfd, ".opd"); - if (sec == NULL || sec->size == 0) - continue; - - if (sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - if (sec->output_section == bfd_abs_section_ptr) - continue; - - /* Look through the section relocs. */ - if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0) - continue; - - local_syms = NULL; - symtab_hdr = &elf_symtab_hdr (ibfd); - - /* Read the relocations. */ - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - return FALSE; - - /* First run through the relocs to check they are sane, and to - determine whether we need to edit this opd section. */ - need_edit = FALSE; - broken = FALSE; - need_pad = sec; - relend = relstart + sec->reloc_count; - for (rel = relstart; rel < relend; ) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - bfd_vma offset; - - /* .opd contains an array of 16 or 24 byte entries. We're - only interested in the reloc pointing to a function entry - point. */ - offset = rel->r_offset; - if (rel + 1 == relend - || rel[1].r_offset != offset + 8) - { - /* If someone messes with .opd alignment then after a - "ld -r" we might have padding in the middle of .opd. - Also, there's nothing to prevent someone putting - something silly in .opd with the assembler. No .opd - optimization for them! */ - broken_opd: - _bfd_error_handler - (_("%B: .opd is not a regular array of opd entries"), ibfd); - broken = TRUE; - break; - } - - if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64 - || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unexpected reloc type %u in .opd section"), - ibfd, r_type); - broken = TRUE; - break; - } - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - goto error_ret; - - if (sym_sec == NULL || sym_sec->owner == NULL) - { - const char *sym_name; - if (h != NULL) - sym_name = h->root.root.string; - else - sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym, - sym_sec); - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: undefined sym `%s' in .opd section"), - ibfd, sym_name); - broken = TRUE; - break; - } - - /* opd entries are always for functions defined in the - current input bfd. If the symbol isn't defined in the - input bfd, then we won't be using the function in this - bfd; It must be defined in a linkonce section in another - bfd, or is weak. It's also possible that we are - discarding the function due to a linker script /DISCARD/, - which we test for via the output_section. */ - if (sym_sec->owner != ibfd - || sym_sec->output_section == bfd_abs_section_ptr) - need_edit = TRUE; - - rel += 2; - if (rel + 1 == relend - || (rel + 2 < relend - && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC)) - ++rel; - - if (rel == relend) - { - if (sec->size == offset + 24) - { - need_pad = NULL; - break; - } - if (sec->size == offset + 16) - { - cnt_16b++; - break; - } - goto broken_opd; - } - else if (rel + 1 < relend - && ELF64_R_TYPE (rel[0].r_info) == R_PPC64_ADDR64 - && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOC) - { - if (rel[0].r_offset == offset + 16) - cnt_16b++; - else if (rel[0].r_offset != offset + 24) - goto broken_opd; - } - else - goto broken_opd; - } - - add_aux_fields = htab->params->non_overlapping_opd && cnt_16b > 0; - - if (!broken && (need_edit || add_aux_fields)) - { - Elf_Internal_Rela *write_rel; - Elf_Internal_Shdr *rel_hdr; - bfd_byte *rptr, *wptr; - bfd_byte *new_contents; - bfd_size_type amt; - - new_contents = NULL; - amt = OPD_NDX (sec->size) * sizeof (long); - opd = &ppc64_elf_section_data (sec)->u.opd; - opd->adjust = bfd_zalloc (sec->owner, amt); - if (opd->adjust == NULL) - return FALSE; - - /* This seems a waste of time as input .opd sections are all - zeros as generated by gcc, but I suppose there's no reason - this will always be so. We might start putting something in - the third word of .opd entries. */ - if ((sec->flags & SEC_IN_MEMORY) == 0) - { - bfd_byte *loc; - if (!bfd_malloc_and_get_section (ibfd, sec, &loc)) - { - if (loc != NULL) - free (loc); - error_ret: - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - free (local_syms); - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - return FALSE; - } - sec->contents = loc; - sec->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS); - } - - elf_section_data (sec)->relocs = relstart; - - new_contents = sec->contents; - if (add_aux_fields) - { - new_contents = bfd_malloc (sec->size + cnt_16b * 8); - if (new_contents == NULL) - return FALSE; - need_pad = NULL; - } - wptr = new_contents; - rptr = sec->contents; - write_rel = relstart; - for (rel = relstart; rel < relend; ) - { - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - struct ppc_link_hash_entry *fdh = NULL; - Elf_Internal_Sym *sym; - long opd_ent_size; - Elf_Internal_Rela *next_rel; - bfd_boolean skip; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - goto error_ret; - - next_rel = rel + 2; - if (next_rel + 1 == relend - || (next_rel + 2 < relend - && ELF64_R_TYPE (next_rel[2].r_info) == R_PPC64_TOC)) - ++next_rel; - - /* See if the .opd entry is full 24 byte or - 16 byte (with fd_aux entry overlapped with next - fd_func). */ - opd_ent_size = 24; - if (next_rel == relend) - { - if (sec->size == rel->r_offset + 16) - opd_ent_size = 16; - } - else if (next_rel->r_offset == rel->r_offset + 16) - opd_ent_size = 16; - - if (h != NULL - && h->root.root.string[0] == '.') - { - fdh = ((struct ppc_link_hash_entry *) h)->oh; - if (fdh != NULL) - { - fdh = ppc_follow_link (fdh); - if (fdh->elf.root.type != bfd_link_hash_defined - && fdh->elf.root.type != bfd_link_hash_defweak) - fdh = NULL; - } - } - - skip = (sym_sec->owner != ibfd - || sym_sec->output_section == bfd_abs_section_ptr); - if (skip) - { - if (fdh != NULL && sym_sec->owner == ibfd) - { - /* Arrange for the function descriptor sym - to be dropped. */ - fdh->elf.root.u.def.value = 0; - fdh->elf.root.u.def.section = sym_sec; - } - opd->adjust[OPD_NDX (rel->r_offset)] = -1; - - if (NO_OPD_RELOCS || bfd_link_relocatable (info)) - rel = next_rel; - else - while (1) - { - if (!dec_dynrel_count (rel->r_info, sec, info, - NULL, h, sym)) - goto error_ret; - - if (++rel == next_rel) - break; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - goto error_ret; - } - } - else - { - /* We'll be keeping this opd entry. */ - long adjust; - - if (fdh != NULL) - { - /* Redefine the function descriptor symbol to - this location in the opd section. It is - necessary to update the value here rather - than using an array of adjustments as we do - for local symbols, because various places - in the generic ELF code use the value - stored in u.def.value. */ - fdh->elf.root.u.def.value = wptr - new_contents; - fdh->adjust_done = 1; - } - - /* Local syms are a bit tricky. We could - tweak them as they can be cached, but - we'd need to look through the local syms - for the function descriptor sym which we - don't have at the moment. So keep an - array of adjustments. */ - adjust = (wptr - new_contents) - (rptr - sec->contents); - opd->adjust[OPD_NDX (rel->r_offset)] = adjust; - - if (wptr != rptr) - memcpy (wptr, rptr, opd_ent_size); - wptr += opd_ent_size; - if (add_aux_fields && opd_ent_size == 16) - { - memset (wptr, '\0', 8); - wptr += 8; - } - - /* We need to adjust any reloc offsets to point to the - new opd entries. */ - for ( ; rel != next_rel; ++rel) - { - rel->r_offset += adjust; - if (write_rel != rel) - memcpy (write_rel, rel, sizeof (*rel)); - ++write_rel; - } - } - - rptr += opd_ent_size; - } - - sec->size = wptr - new_contents; - sec->reloc_count = write_rel - relstart; - if (add_aux_fields) - { - free (sec->contents); - sec->contents = new_contents; - } - - /* Fudge the header size too, as this is used later in - elf_bfd_final_link if we are emitting relocs. */ - rel_hdr = _bfd_elf_single_rel_hdr (sec); - rel_hdr->sh_size = sec->reloc_count * rel_hdr->sh_entsize; - some_edited = TRUE; - } - else if (elf_section_data (sec)->relocs != relstart) - free (relstart); - - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - { - if (!info->keep_memory) - free (local_syms); - else - symtab_hdr->contents = (unsigned char *) local_syms; - } - } - - if (some_edited) - elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL); - - /* If we are doing a final link and the last .opd entry is just 16 byte - long, add a 8 byte padding after it. */ - if (need_pad != NULL && !bfd_link_relocatable (info)) - { - bfd_byte *p; - - if ((need_pad->flags & SEC_IN_MEMORY) == 0) - { - BFD_ASSERT (need_pad->size > 0); - - p = bfd_malloc (need_pad->size + 8); - if (p == NULL) - return FALSE; - - if (! bfd_get_section_contents (need_pad->owner, need_pad, - p, 0, need_pad->size)) - return FALSE; - - need_pad->contents = p; - need_pad->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS); - } - else - { - p = bfd_realloc (need_pad->contents, need_pad->size + 8); - if (p == NULL) - return FALSE; - - need_pad->contents = p; - } - - memset (need_pad->contents + need_pad->size, 0, 8); - need_pad->size += 8; - } - - return TRUE; -} - -/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ - -asection * -ppc64_elf_tls_setup (struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - - htab = ppc_hash_table (info); - if (htab == NULL) - return NULL; - - if (abiversion (info->output_bfd) == 1) - htab->opd_abi = 1; - - if (htab->params->no_multi_toc) - htab->do_multi_toc = 0; - else if (!htab->do_multi_toc) - htab->params->no_multi_toc = 1; - - /* Default to --no-plt-localentry, as this option can cause problems - with symbol interposition. For example, glibc libpthread.so and - libc.so duplicate many pthread symbols, with a fallback - implementation in libc.so. In some cases the fallback does more - work than the pthread implementation. __pthread_condattr_destroy - is one such symbol: the libpthread.so implementation is - localentry:0 while the libc.so implementation is localentry:8. - An app that "cleverly" uses dlopen to only load necessary - libraries at runtime may omit loading libpthread.so when not - running multi-threaded, which then results in the libc.so - fallback symbols being used and ld.so complaining. Now there - are workarounds in ld (see non_zero_localentry) to detect the - pthread situation, but that may not be the only case where - --plt-localentry can cause trouble. */ - if (htab->params->plt_localentry0 < 0) - htab->params->plt_localentry0 = 0; - if (htab->params->plt_localentry0 - && elf_link_hash_lookup (&htab->elf, "GLIBC_2.26", - FALSE, FALSE, FALSE) == NULL) - info->callbacks->einfo - (_("%P: warning: --plt-localentry is especially dangerous without " - "ld.so support to detect ABI violations.\n")); - - htab->tls_get_addr = ((struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", - FALSE, FALSE, TRUE)); - /* Move dynamic linking info to the function descriptor sym. */ - if (htab->tls_get_addr != NULL) - func_desc_adjust (&htab->tls_get_addr->elf, info); - htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *) - elf_link_hash_lookup (&htab->elf, "__tls_get_addr", - FALSE, FALSE, TRUE)); - if (htab->params->tls_get_addr_opt) - { - struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd; - - opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt", - FALSE, FALSE, TRUE); - if (opt != NULL) - func_desc_adjust (opt, info); - opt_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", - FALSE, FALSE, TRUE); - if (opt_fd != NULL - && (opt_fd->root.type == bfd_link_hash_defined - || opt_fd->root.type == bfd_link_hash_defweak)) - { - /* If glibc supports an optimized __tls_get_addr call stub, - signalled by the presence of __tls_get_addr_opt, and we'll - be calling __tls_get_addr via a plt call stub, then - make __tls_get_addr point to __tls_get_addr_opt. */ - tga_fd = &htab->tls_get_addr_fd->elf; - if (htab->elf.dynamic_sections_created - && tga_fd != NULL - && (tga_fd->type == STT_FUNC - || tga_fd->needs_plt) - && !(SYMBOL_CALLS_LOCAL (info, tga_fd) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd))) - { - struct plt_entry *ent; - - for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - break; - if (ent != NULL) - { - tga_fd->root.type = bfd_link_hash_indirect; - tga_fd->root.u.i.link = &opt_fd->root; - ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd); - opt_fd->mark = 1; - if (opt_fd->dynindx != -1) - { - /* Use __tls_get_addr_opt in dynamic relocations. */ - opt_fd->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - opt_fd->dynstr_index); - if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd)) - return NULL; - } - htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd; - tga = &htab->tls_get_addr->elf; - if (opt != NULL && tga != NULL) - { - tga->root.type = bfd_link_hash_indirect; - tga->root.u.i.link = &opt->root; - ppc64_elf_copy_indirect_symbol (info, opt, tga); - opt->mark = 1; - _bfd_elf_link_hash_hide_symbol (info, opt, - tga->forced_local); - htab->tls_get_addr = (struct ppc_link_hash_entry *) opt; - } - htab->tls_get_addr_fd->oh = htab->tls_get_addr; - htab->tls_get_addr_fd->is_func_descriptor = 1; - if (htab->tls_get_addr != NULL) - { - htab->tls_get_addr->oh = htab->tls_get_addr_fd; - htab->tls_get_addr->is_func = 1; - } - } - } - } - else if (htab->params->tls_get_addr_opt < 0) - htab->params->tls_get_addr_opt = 0; - } - return _bfd_elf_tls_setup (info->output_bfd, info); -} - -/* Return TRUE iff REL is a branch reloc with a global symbol matching - HASH1 or HASH2. */ - -static bfd_boolean -branch_reloc_hash_match (const bfd *ibfd, - const Elf_Internal_Rela *rel, - const struct ppc_link_hash_entry *hash1, - const struct ppc_link_hash_entry *hash2) -{ - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); - enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info); - unsigned int r_symndx = ELF64_R_SYM (rel->r_info); - - if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type)) - { - struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); - struct elf_link_hash_entry *h; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - h = elf_follow_link (h); - if (h == &hash1->elf || h == &hash2->elf) - return TRUE; - } - return FALSE; -} - -/* Run through all the TLS relocs looking for optimization - opportunities. The linker has been hacked (see ppc64elf.em) to do - a preliminary section layout so that we know the TLS segment - offsets. We can't optimize earlier because some optimizations need - to know the tp offset, and we need to optimize before allocating - dynamic relocations. */ - -bfd_boolean -ppc64_elf_tls_optimize (struct bfd_link_info *info) -{ - bfd *ibfd; - asection *sec; - struct ppc_link_hash_table *htab; - unsigned char *toc_ref; - int pass; - - if (!bfd_link_executable (info)) - return TRUE; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Make two passes over the relocs. On the first pass, mark toc - entries involved with tls relocs, and check that tls relocs - involved in setting up a tls_get_addr call are indeed followed by - such a call. If they are not, we can't do any tls optimization. - On the second pass twiddle tls_mask flags to notify - relocate_section that optimization can be done, and adjust got - and plt refcounts. */ - toc_ref = NULL; - for (pass = 0; pass < 2; ++pass) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - Elf_Internal_Sym *locsyms = NULL; - asection *toc = bfd_get_section_by_name (ibfd, ".toc"); - - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) - { - Elf_Internal_Rela *relstart, *rel, *relend; - bfd_boolean found_tls_get_addr_arg = 0; - - /* Read the relocations. */ - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - { - free (toc_ref); - return FALSE; - } - - relend = relstart + sec->reloc_count; - for (rel = relstart; rel < relend; rel++) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - asection *sym_sec; - unsigned char *tls_mask; - unsigned char tls_set, tls_clear, tls_type = 0; - bfd_vma value; - bfd_boolean ok_tprel, is_local; - long toc_ref_index = 0; - int expecting_tls_get_addr = 0; - bfd_boolean ret = FALSE; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms, - r_symndx, ibfd)) - { - err_free_rel: - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - if (toc_ref != NULL) - free (toc_ref); - if (locsyms != NULL - && (elf_symtab_hdr (ibfd).contents - != (unsigned char *) locsyms)) - free (locsyms); - return ret; - } - - if (h != NULL) - { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - value = h->root.u.def.value; - else if (h->root.type == bfd_link_hash_undefweak) - value = 0; - else - { - found_tls_get_addr_arg = 0; - continue; - } - } - else - /* Symbols referenced by TLS relocs must be of type - STT_TLS. So no need for .opd local sym adjust. */ - value = sym->st_value; - - ok_tprel = FALSE; - is_local = FALSE; - if (h == NULL - || !h->def_dynamic) - { - is_local = TRUE; - if (h != NULL - && h->root.type == bfd_link_hash_undefweak) - ok_tprel = TRUE; - else if (sym_sec != NULL - && sym_sec->output_section != NULL) - { - value += sym_sec->output_offset; - value += sym_sec->output_section->vma; - value -= htab->elf.tls_sec->vma; - ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) - < (bfd_vma) 1 << 32); - } - } - - r_type = ELF64_R_TYPE (rel->r_info); - /* If this section has old-style __tls_get_addr calls - without marker relocs, then check that each - __tls_get_addr call reloc is preceded by a reloc - that conceivably belongs to the __tls_get_addr arg - setup insn. If we don't find matching arg setup - relocs, don't do any tls optimization. */ - if (pass == 0 - && sec->has_tls_get_addr_call - && h != NULL - && (h == &htab->tls_get_addr->elf - || h == &htab->tls_get_addr_fd->elf) - && !found_tls_get_addr_arg - && is_branch_reloc (r_type)) - { - info->callbacks->minfo (_("%H __tls_get_addr lost arg, " - "TLS optimization disabled\n"), - ibfd, sec, rel->r_offset); - ret = TRUE; - goto err_free_rel; - } - - found_tls_get_addr_arg = 0; - switch (r_type) - { - case R_PPC64_GOT_TLSLD16: - case R_PPC64_GOT_TLSLD16_LO: - expecting_tls_get_addr = 1; - found_tls_get_addr_arg = 1; - /* Fall through. */ - - case R_PPC64_GOT_TLSLD16_HI: - case R_PPC64_GOT_TLSLD16_HA: - /* These relocs should never be against a symbol - defined in a shared lib. Leave them alone if - that turns out to be the case. */ - if (!is_local) - continue; - - /* LD -> LE */ - tls_set = 0; - tls_clear = TLS_LD; - tls_type = TLS_TLS | TLS_LD; - break; - - case R_PPC64_GOT_TLSGD16: - case R_PPC64_GOT_TLSGD16_LO: - expecting_tls_get_addr = 1; - found_tls_get_addr_arg = 1; - /* Fall through. */ - - case R_PPC64_GOT_TLSGD16_HI: - case R_PPC64_GOT_TLSGD16_HA: - if (ok_tprel) - /* GD -> LE */ - tls_set = 0; - else - /* GD -> IE */ - tls_set = TLS_TLS | TLS_TPRELGD; - tls_clear = TLS_GD; - tls_type = TLS_TLS | TLS_GD; - break; - - case R_PPC64_GOT_TPREL16_DS: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_TPREL16_HI: - case R_PPC64_GOT_TPREL16_HA: - if (ok_tprel) - { - /* IE -> LE */ - tls_set = 0; - tls_clear = TLS_TPREL; - tls_type = TLS_TLS | TLS_TPREL; - break; - } - continue; - - case R_PPC64_TLSGD: - case R_PPC64_TLSLD: - found_tls_get_addr_arg = 1; - /* Fall through. */ - - case R_PPC64_TLS: - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - if (sym_sec == NULL || sym_sec != toc) - continue; - - /* Mark this toc entry as referenced by a TLS - code sequence. We can do that now in the - case of R_PPC64_TLS, and after checking for - tls_get_addr for the TOC16 relocs. */ - if (toc_ref == NULL) - toc_ref = bfd_zmalloc (toc->output_section->rawsize / 8); - if (toc_ref == NULL) - goto err_free_rel; - - if (h != NULL) - value = h->root.u.def.value; - else - value = sym->st_value; - value += rel->r_addend; - if (value % 8 != 0) - continue; - BFD_ASSERT (value < toc->size - && toc->output_offset % 8 == 0); - toc_ref_index = (value + toc->output_offset) / 8; - if (r_type == R_PPC64_TLS - || r_type == R_PPC64_TLSGD - || r_type == R_PPC64_TLSLD) - { - toc_ref[toc_ref_index] = 1; - continue; - } - - if (pass != 0 && toc_ref[toc_ref_index] == 0) - continue; - - tls_set = 0; - tls_clear = 0; - expecting_tls_get_addr = 2; - break; - - case R_PPC64_TPREL64: - if (pass == 0 - || sec != toc - || toc_ref == NULL - || !toc_ref[(rel->r_offset + toc->output_offset) / 8]) - continue; - if (ok_tprel) - { - /* IE -> LE */ - tls_set = TLS_EXPLICIT; - tls_clear = TLS_TPREL; - break; - } - continue; - - case R_PPC64_DTPMOD64: - if (pass == 0 - || sec != toc - || toc_ref == NULL - || !toc_ref[(rel->r_offset + toc->output_offset) / 8]) - continue; - if (rel + 1 < relend - && (rel[1].r_info - == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) - && rel[1].r_offset == rel->r_offset + 8) - { - if (ok_tprel) - /* GD -> LE */ - tls_set = TLS_EXPLICIT | TLS_GD; - else - /* GD -> IE */ - tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD; - tls_clear = TLS_GD; - } - else - { - if (!is_local) - continue; - - /* LD -> LE */ - tls_set = TLS_EXPLICIT; - tls_clear = TLS_LD; - } - break; - - default: - continue; - } - - if (pass == 0) - { - if (!expecting_tls_get_addr - || !sec->has_tls_get_addr_call) - continue; - - if (rel + 1 < relend - && branch_reloc_hash_match (ibfd, rel + 1, - htab->tls_get_addr, - htab->tls_get_addr_fd)) - { - if (expecting_tls_get_addr == 2) - { - /* Check for toc tls entries. */ - unsigned char *toc_tls; - int retval; - - retval = get_tls_mask (&toc_tls, NULL, NULL, - &locsyms, - rel, ibfd); - if (retval == 0) - goto err_free_rel; - if (toc_tls != NULL) - { - if ((*toc_tls & (TLS_GD | TLS_LD)) != 0) - found_tls_get_addr_arg = 1; - if (retval > 1) - toc_ref[toc_ref_index] = 1; - } - } - continue; - } - - if (expecting_tls_get_addr != 1) - continue; - - /* Uh oh, we didn't find the expected call. We - could just mark this symbol to exclude it - from tls optimization but it's safer to skip - the entire optimization. */ - /* xgettext:c-format */ - info->callbacks->minfo (_("%H arg lost __tls_get_addr, " - "TLS optimization disabled\n"), - ibfd, sec, rel->r_offset); - ret = TRUE; - goto err_free_rel; - } - - if (expecting_tls_get_addr && htab->tls_get_addr != NULL) - { - struct plt_entry *ent; - for (ent = htab->tls_get_addr->elf.plt.plist; - ent != NULL; - ent = ent->next) - if (ent->addend == 0) - { - if (ent->plt.refcount > 0) - { - ent->plt.refcount -= 1; - expecting_tls_get_addr = 0; - } - break; - } - } - - if (expecting_tls_get_addr && htab->tls_get_addr_fd != NULL) - { - struct plt_entry *ent; - for (ent = htab->tls_get_addr_fd->elf.plt.plist; - ent != NULL; - ent = ent->next) - if (ent->addend == 0) - { - if (ent->plt.refcount > 0) - ent->plt.refcount -= 1; - break; - } - } - - if (tls_clear == 0) - continue; - - if ((tls_set & TLS_EXPLICIT) == 0) - { - struct got_entry *ent; - - /* Adjust got entry for this reloc. */ - if (h != NULL) - ent = h->got.glist; - else - ent = elf_local_got_ents (ibfd)[r_symndx]; - - for (; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend - && ent->owner == ibfd - && ent->tls_type == tls_type) - break; - if (ent == NULL) - abort (); - - if (tls_set == 0) - { - /* We managed to get rid of a got entry. */ - if (ent->got.refcount > 0) - ent->got.refcount -= 1; - } - } - else - { - /* If we got rid of a DTPMOD/DTPREL reloc pair then - we'll lose one or two dyn relocs. */ - if (!dec_dynrel_count (rel->r_info, sec, info, - NULL, h, sym)) - return FALSE; - - if (tls_set == (TLS_EXPLICIT | TLS_GD)) - { - if (!dec_dynrel_count ((rel + 1)->r_info, sec, info, - NULL, h, sym)) - return FALSE; - } - } - - *tls_mask |= tls_set; - *tls_mask &= ~tls_clear; - } - - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - } - - if (locsyms != NULL - && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms)) - { - if (!info->keep_memory) - free (locsyms); - else - elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms; - } - } - - if (toc_ref != NULL) - free (toc_ref); - htab->do_tls_opt = 1; - return TRUE; -} - -/* Called via elf_link_hash_traverse from ppc64_elf_edit_toc to adjust - the values of any global symbols in a toc section that has been - edited. Globals in toc sections should be a rarity, so this function - sets a flag if any are found in toc sections other than the one just - edited, so that further hash table traversals can be avoided. */ - -struct adjust_toc_info -{ - asection *toc; - unsigned long *skip; - bfd_boolean global_toc_syms; -}; - -enum toc_skip_enum { ref_from_discarded = 1, can_optimize = 2 }; - -static bfd_boolean -adjust_toc_syms (struct elf_link_hash_entry *h, void *inf) -{ - struct ppc_link_hash_entry *eh; - struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf; - unsigned long i; - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - return TRUE; - - eh = (struct ppc_link_hash_entry *) h; - if (eh->adjust_done) - return TRUE; - - if (eh->elf.root.u.def.section == toc_inf->toc) - { - if (eh->elf.root.u.def.value > toc_inf->toc->rawsize) - i = toc_inf->toc->rawsize >> 3; - else - i = eh->elf.root.u.def.value >> 3; - - if ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0) - { - _bfd_error_handler - (_("%s defined on removed toc entry"), eh->elf.root.root.string); - do - ++i; - while ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0); - eh->elf.root.u.def.value = (bfd_vma) i << 3; - } - - eh->elf.root.u.def.value -= toc_inf->skip[i]; - eh->adjust_done = 1; - } - else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0) - toc_inf->global_toc_syms = TRUE; - - return TRUE; -} - -/* Return TRUE iff INSN with a relocation of R_TYPE is one we expect - on a _LO variety toc/got reloc. */ - -static bfd_boolean -ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type) -{ - return ((insn & (0x3f << 26)) == 12u << 26 /* addic */ - || (insn & (0x3f << 26)) == 14u << 26 /* addi */ - || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ - || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ - || (insn & (0x3f << 26)) == 36u << 26 /* stw */ - || (insn & (0x3f << 26)) == 38u << 26 /* stb */ - || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ - || (insn & (0x3f << 26)) == 42u << 26 /* lha */ - || (insn & (0x3f << 26)) == 44u << 26 /* sth */ - || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ - || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ - || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ - || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ - || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ - || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ - || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */ - || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */ - /* Exclude lfqu by testing reloc. If relocs are ever - defined for the reduced D field in psq_lu then those - will need testing too. */ - && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) - || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */ - && (insn & 1) == 0) - || (insn & (0x3f << 26)) == 60u << 26 /* stfq */ - || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */ - /* Exclude stfqu. psq_stu as above for psq_lu. */ - && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO) - || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */ - && (insn & 1) == 0)); -} - -/* Examine all relocs referencing .toc sections in order to remove - unused .toc entries. */ - -bfd_boolean -ppc64_elf_edit_toc (struct bfd_link_info *info) -{ - bfd *ibfd; - struct adjust_toc_info toc_inf; - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - htab->do_toc_opt = 1; - toc_inf.global_toc_syms = TRUE; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *toc, *sec; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Sym *local_syms; - Elf_Internal_Rela *relstart, *rel, *toc_relocs; - unsigned long *skip, *drop; - unsigned char *used; - unsigned char *keep, last, some_unused; - - if (!is_ppc64_elf (ibfd)) - continue; - - toc = bfd_get_section_by_name (ibfd, ".toc"); - if (toc == NULL - || toc->size == 0 - || toc->sec_info_type == SEC_INFO_TYPE_JUST_SYMS - || discarded_section (toc)) - continue; - - toc_relocs = NULL; - local_syms = NULL; - symtab_hdr = &elf_symtab_hdr (ibfd); - - /* Look at sections dropped from the final link. */ - skip = NULL; - relstart = NULL; - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - if (sec->reloc_count == 0 - || !discarded_section (sec) - || get_opd_info (sec) - || (sec->flags & SEC_ALLOC) == 0 - || (sec->flags & SEC_DEBUGGING) != 0) - continue; - - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, FALSE); - if (relstart == NULL) - goto error_ret; - - /* Run through the relocs to see which toc entries might be - unused. */ - for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - bfd_vma val; - - r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - default: - continue; - - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_HA: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - break; - } - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - goto error_ret; - - if (sym_sec != toc) - continue; - - if (h != NULL) - val = h->root.u.def.value; - else - val = sym->st_value; - val += rel->r_addend; - - if (val >= toc->size) - continue; - - /* Anything in the toc ought to be aligned to 8 bytes. - If not, don't mark as unused. */ - if (val & 7) - continue; - - if (skip == NULL) - { - skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8); - if (skip == NULL) - goto error_ret; - } - - skip[val >> 3] = ref_from_discarded; - } - - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - } - - /* For largetoc loads of address constants, we can convert - . addis rx,2,addr@got@ha - . ld ry,addr@got@l(rx) - to - . addis rx,2,addr@toc@ha - . addi ry,rx,addr@toc@l - when addr is within 2G of the toc pointer. This then means - that the word storing "addr" in the toc is no longer needed. */ - - if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc - && toc->output_section->rawsize < (bfd_vma) 1 << 31 - && toc->reloc_count != 0) - { - /* Read toc relocs. */ - toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, - info->keep_memory); - if (toc_relocs == NULL) - goto error_ret; - - for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - bfd_vma val, addr; - - r_type = ELF64_R_TYPE (rel->r_info); - if (r_type != R_PPC64_ADDR64) - continue; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - goto error_ret; - - if (sym_sec == NULL - || sym_sec->output_section == NULL - || discarded_section (sym_sec)) - continue; - - if (!SYMBOL_REFERENCES_LOCAL (info, h)) - continue; - - if (h != NULL) - { - if (h->type == STT_GNU_IFUNC) - continue; - val = h->root.u.def.value; - } - else - { - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - continue; - val = sym->st_value; - } - val += rel->r_addend; - val += sym_sec->output_section->vma + sym_sec->output_offset; - - /* We don't yet know the exact toc pointer value, but we - know it will be somewhere in the toc section. Don't - optimize if the difference from any possible toc - pointer is outside [ff..f80008000, 7fff7fff]. */ - addr = toc->output_section->vma + TOC_BASE_OFF; - if (val - addr + (bfd_vma) 0x80008000 >= (bfd_vma) 1 << 32) - continue; - - addr = toc->output_section->vma + toc->output_section->rawsize; - if (val - addr + (bfd_vma) 0x80008000 >= (bfd_vma) 1 << 32) - continue; - - if (skip == NULL) - { - skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8); - if (skip == NULL) - goto error_ret; - } - - skip[rel->r_offset >> 3] - |= can_optimize | ((rel - toc_relocs) << 2); - } - } - - if (skip == NULL) - continue; - - used = bfd_zmalloc (sizeof (*used) * (toc->size + 7) / 8); - if (used == NULL) - { - error_ret: - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - free (local_syms); - if (sec != NULL - && relstart != NULL - && elf_section_data (sec)->relocs != relstart) - free (relstart); - if (toc_relocs != NULL - && elf_section_data (toc)->relocs != toc_relocs) - free (toc_relocs); - if (skip != NULL) - free (skip); - return FALSE; - } - - /* Now check all kept sections that might reference the toc. - Check the toc itself last. */ - for (sec = (ibfd->sections == toc && toc->next ? toc->next - : ibfd->sections); - sec != NULL; - sec = (sec == toc ? NULL - : sec->next == NULL ? toc - : sec->next == toc && toc->next ? toc->next - : sec->next)) - { - int repeat; - - if (sec->reloc_count == 0 - || discarded_section (sec) - || get_opd_info (sec) - || (sec->flags & SEC_ALLOC) == 0 - || (sec->flags & SEC_DEBUGGING) != 0) - continue; - - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - { - free (used); - goto error_ret; - } - - /* Mark toc entries referenced as used. */ - do - { - repeat = 0; - for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - bfd_vma val; - enum {no_check, check_lo, check_ha} insn_check; - - r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - default: - insn_check = no_check; - break; - - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT16_HA: - case R_PPC64_TOC16_HA: - insn_check = check_ha; - break; - - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_LO_DS: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_LO_DS: - insn_check = check_lo; - break; - } - - if (insn_check != no_check) - { - bfd_vma off = rel->r_offset & ~3; - unsigned char buf[4]; - unsigned int insn; - - if (!bfd_get_section_contents (ibfd, sec, buf, off, 4)) - { - free (used); - goto error_ret; - } - insn = bfd_get_32 (ibfd, buf); - if (insn_check == check_lo - ? !ok_lo_toc_insn (insn, r_type) - : ((insn & ((0x3f << 26) | 0x1f << 16)) - != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)) - { - char str[12]; - - ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1; - sprintf (str, "%#08x", insn); - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: toc optimization is not supported for" - " %s instruction.\n"), - ibfd, sec, rel->r_offset & ~3, str); - } - } - - switch (r_type) - { - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_HA: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - /* In case we're taking addresses of toc entries. */ - case R_PPC64_ADDR64: - break; - - default: - continue; - } - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - { - free (used); - goto error_ret; - } - - if (sym_sec != toc) - continue; - - if (h != NULL) - val = h->root.u.def.value; - else - val = sym->st_value; - val += rel->r_addend; - - if (val >= toc->size) - continue; - - if ((skip[val >> 3] & can_optimize) != 0) - { - bfd_vma off; - unsigned char opc; - - switch (r_type) - { - case R_PPC64_TOC16_HA: - break; - - case R_PPC64_TOC16_LO_DS: - off = rel->r_offset; - off += (bfd_big_endian (ibfd) ? -2 : 3); - if (!bfd_get_section_contents (ibfd, sec, &opc, - off, 1)) - { - free (used); - goto error_ret; - } - if ((opc & (0x3f << 2)) == (58u << 2)) - break; - /* Fall through. */ - - default: - /* Wrong sort of reloc, or not a ld. We may - as well clear ref_from_discarded too. */ - skip[val >> 3] = 0; - } - } - - if (sec != toc) - used[val >> 3] = 1; - /* For the toc section, we only mark as used if this - entry itself isn't unused. */ - else if ((used[rel->r_offset >> 3] - || !(skip[rel->r_offset >> 3] & ref_from_discarded)) - && !used[val >> 3]) - { - /* Do all the relocs again, to catch reference - chains. */ - repeat = 1; - used[val >> 3] = 1; - } - } - } - while (repeat); - - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - } - - /* Merge the used and skip arrays. Assume that TOC - doublewords not appearing as either used or unused belong - to an entry more than one doubleword in size. */ - for (drop = skip, keep = used, last = 0, some_unused = 0; - drop < skip + (toc->size + 7) / 8; - ++drop, ++keep) - { - if (*keep) - { - *drop &= ~ref_from_discarded; - if ((*drop & can_optimize) != 0) - some_unused = 1; - last = 0; - } - else if ((*drop & ref_from_discarded) != 0) - { - some_unused = 1; - last = ref_from_discarded; - } - else - *drop = last; - } - - free (used); - - if (some_unused) - { - bfd_byte *contents, *src; - unsigned long off; - Elf_Internal_Sym *sym; - bfd_boolean local_toc_syms = FALSE; - - /* Shuffle the toc contents, and at the same time convert the - skip array from booleans into offsets. */ - if (!bfd_malloc_and_get_section (ibfd, toc, &contents)) - goto error_ret; - - elf_section_data (toc)->this_hdr.contents = contents; - - for (src = contents, off = 0, drop = skip; - src < contents + toc->size; - src += 8, ++drop) - { - if ((*drop & (can_optimize | ref_from_discarded)) != 0) - off += 8; - else if (off != 0) - { - *drop = off; - memcpy (src - off, src, 8); - } - } - *drop = off; - toc->rawsize = toc->size; - toc->size = src - contents - off; - - /* Adjust addends for relocs against the toc section sym, - and optimize any accesses we can. */ - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - { - if (sec->reloc_count == 0 - || discarded_section (sec)) - continue; - - relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - goto error_ret; - - for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - asection *sym_sec; - struct elf_link_hash_entry *h; - bfd_vma val; - - r_type = ELF64_R_TYPE (rel->r_info); - switch (r_type) - { - default: - continue; - - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_HA: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - case R_PPC64_ADDR64: - break; - } - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_symndx, ibfd)) - goto error_ret; - - if (sym_sec != toc) - continue; - - if (h != NULL) - val = h->root.u.def.value; - else - { - val = sym->st_value; - if (val != 0) - local_toc_syms = TRUE; - } - - val += rel->r_addend; - - if (val > toc->rawsize) - val = toc->rawsize; - else if ((skip[val >> 3] & ref_from_discarded) != 0) - continue; - else if ((skip[val >> 3] & can_optimize) != 0) - { - Elf_Internal_Rela *tocrel - = toc_relocs + (skip[val >> 3] >> 2); - unsigned long tsym = ELF64_R_SYM (tocrel->r_info); - - switch (r_type) - { - case R_PPC64_TOC16_HA: - rel->r_info = ELF64_R_INFO (tsym, R_PPC64_TOC16_HA); - break; - - case R_PPC64_TOC16_LO_DS: - rel->r_info = ELF64_R_INFO (tsym, R_PPC64_LO_DS_OPT); - break; - - default: - if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) - ppc_howto_init (); - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s references " - "optimized away TOC entry\n"), - ibfd, sec, rel->r_offset, - ppc64_elf_howto_table[r_type]->name); - bfd_set_error (bfd_error_bad_value); - goto error_ret; - } - rel->r_addend = tocrel->r_addend; - elf_section_data (sec)->relocs = relstart; - continue; - } - - if (h != NULL || sym->st_value != 0) - continue; - - rel->r_addend -= skip[val >> 3]; - elf_section_data (sec)->relocs = relstart; - } - - if (elf_section_data (sec)->relocs != relstart) - free (relstart); - } - - /* We shouldn't have local or global symbols defined in the TOC, - but handle them anyway. */ - if (local_syms != NULL) - for (sym = local_syms; - sym < local_syms + symtab_hdr->sh_info; - ++sym) - if (sym->st_value != 0 - && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc) - { - unsigned long i; - - if (sym->st_value > toc->rawsize) - i = toc->rawsize >> 3; - else - i = sym->st_value >> 3; - - if ((skip[i] & (ref_from_discarded | can_optimize)) != 0) - { - if (local_toc_syms) - _bfd_error_handler - (_("%s defined on removed toc entry"), - bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL)); - do - ++i; - while ((skip[i] & (ref_from_discarded | can_optimize))); - sym->st_value = (bfd_vma) i << 3; - } - - sym->st_value -= skip[i]; - symtab_hdr->contents = (unsigned char *) local_syms; - } - - /* Adjust any global syms defined in this toc input section. */ - if (toc_inf.global_toc_syms) - { - toc_inf.toc = toc; - toc_inf.skip = skip; - toc_inf.global_toc_syms = FALSE; - elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms, - &toc_inf); - } - - if (toc->reloc_count != 0) - { - Elf_Internal_Shdr *rel_hdr; - Elf_Internal_Rela *wrel; - bfd_size_type sz; - - /* Remove unused toc relocs, and adjust those we keep. */ - if (toc_relocs == NULL) - toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, - info->keep_memory); - if (toc_relocs == NULL) - goto error_ret; - - wrel = toc_relocs; - for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel) - if ((skip[rel->r_offset >> 3] - & (ref_from_discarded | can_optimize)) == 0) - { - wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3]; - wrel->r_info = rel->r_info; - wrel->r_addend = rel->r_addend; - ++wrel; - } - else if (!dec_dynrel_count (rel->r_info, toc, info, - &local_syms, NULL, NULL)) - goto error_ret; - - elf_section_data (toc)->relocs = toc_relocs; - toc->reloc_count = wrel - toc_relocs; - rel_hdr = _bfd_elf_single_rel_hdr (toc); - sz = rel_hdr->sh_entsize; - rel_hdr->sh_size = toc->reloc_count * sz; - } - } - else if (toc_relocs != NULL - && elf_section_data (toc)->relocs != toc_relocs) - free (toc_relocs); - - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - { - if (!info->keep_memory) - free (local_syms); - else - symtab_hdr->contents = (unsigned char *) local_syms; - } - free (skip); - } - - return TRUE; -} - -/* Return true iff input section I references the TOC using - instructions limited to +/-32k offsets. */ - -bfd_boolean -ppc64_elf_has_small_toc_reloc (asection *i) -{ - return (is_ppc64_elf (i->owner) - && ppc64_elf_tdata (i->owner)->has_small_toc_reloc); -} - -/* Allocate space for one GOT entry. */ - -static void -allocate_got (struct elf_link_hash_entry *h, - struct bfd_link_info *info, - struct got_entry *gent) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; - int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD) - ? 16 : 8); - int rentsize = (gent->tls_type & eh->tls_mask & TLS_GD - ? 2 : 1) * sizeof (Elf64_External_Rela); - asection *got = ppc64_elf_tdata (gent->owner)->got; - - gent->got.offset = got->size; - got->size += entsize; - - if (h->type == STT_GNU_IFUNC) - { - htab->elf.irelplt->size += rentsize; - htab->got_reli_size += rentsize; - } - else if (((bfd_link_pic (info) - && !((gent->tls_type & TLS_TPREL) != 0 - && bfd_link_executable (info) - && SYMBOL_REFERENCES_LOCAL (info, h))) - || (htab->elf.dynamic_sections_created - && h->dynindx != -1 - && !SYMBOL_REFERENCES_LOCAL (info, h))) - && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - { - asection *relgot = ppc64_elf_tdata (gent->owner)->relgot; - relgot->size += rentsize; - } -} - -/* This function merges got entries in the same toc group. */ - -static void -merge_got_entries (struct got_entry **pent) -{ - struct got_entry *ent, *ent2; - - for (ent = *pent; ent != NULL; ent = ent->next) - if (!ent->is_indirect) - for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next) - if (!ent2->is_indirect - && ent2->addend == ent->addend - && ent2->tls_type == ent->tls_type - && elf_gp (ent2->owner) == elf_gp (ent->owner)) - { - ent2->is_indirect = TRUE; - ent2->got.ent = ent; - } -} - -/* If H is undefined, make it dynamic if that makes sense. */ - -static bfd_boolean -ensure_undef_dynamic (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (htab->dynamic_sections_created - && ((info->dynamic_undefined_weak != 0 - && h->root.type == bfd_link_hash_undefweak) - || h->root.type == bfd_link_hash_undefined) - && h->dynindx == -1 - && !h->forced_local - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - return bfd_elf_link_record_dynamic_symbol (info, h); - 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 ppc_link_hash_table *htab; - asection *s; - struct ppc_link_hash_entry *eh; - struct got_entry **pgent, *gent; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - eh = (struct ppc_link_hash_entry *) h; - /* Run through the TLS GD got entries first if we're changing them - to TPREL. */ - if ((eh->tls_mask & TLS_TPRELGD) != 0) - for (gent = h->got.glist; gent != NULL; gent = gent->next) - if (gent->got.refcount > 0 - && (gent->tls_type & TLS_GD) != 0) - { - /* This was a GD entry that has been converted to TPREL. If - there happens to be a TPREL entry we can use that one. */ - struct got_entry *ent; - for (ent = h->got.glist; ent != NULL; ent = ent->next) - if (ent->got.refcount > 0 - && (ent->tls_type & TLS_TPREL) != 0 - && ent->addend == gent->addend - && ent->owner == gent->owner) - { - gent->got.refcount = 0; - break; - } - - /* If not, then we'll be using our own TPREL entry. */ - if (gent->got.refcount != 0) - gent->tls_type = TLS_TLS | TLS_TPREL; - } - - /* Remove any list entry that won't generate a word in the GOT before - we call merge_got_entries. Otherwise we risk merging to empty - entries. */ - pgent = &h->got.glist; - while ((gent = *pgent) != NULL) - if (gent->got.refcount > 0) - { - if ((gent->tls_type & TLS_LD) != 0 - && !h->def_dynamic) - { - ppc64_tlsld_got (gent->owner)->got.refcount += 1; - *pgent = gent->next; - } - else - pgent = &gent->next; - } - else - *pgent = gent->next; - - if (!htab->do_multi_toc) - merge_got_entries (&h->got.glist); - - for (gent = h->got.glist; gent != NULL; gent = gent->next) - if (!gent->is_indirect) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (!ensure_undef_dynamic (info, h)) - return FALSE; - - if (!is_ppc64_elf (gent->owner)) - abort (); - - allocate_got (h, info, gent); - } - - /* If no dynamic sections we can't have dynamic relocs, except for - IFUNCs which are handled even in static executables. */ - if (!htab->elf.dynamic_sections_created - && h->type != STT_GNU_IFUNC) - eh->dyn_relocs = NULL; - - /* Discard relocs on undefined symbols that must be local. */ - else if (h->root.type == bfd_link_hash_undefined - && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - eh->dyn_relocs = NULL; - - /* Also discard relocs on undefined weak syms with non-default - visibility, or when dynamic_undefined_weak says so. */ - else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; - - if (eh->dyn_relocs != NULL) - { - struct elf_dyn_relocs *p, **pp; - - /* 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 relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - /* Relocs that use pc_count are those that appear on a call - insn, or certain REL relocs (see must_be_dyn_reloc) that - can be 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)) - { - 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; - } - } - - if (eh->dyn_relocs != NULL) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (!ensure_undef_dynamic (info, h)) - return FALSE; - } - } - else if (ELIMINATE_COPY_RELOCS && h->type != STT_GNU_IFUNC) - { - /* For the non-pic case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ - if (h->dynamic_adjusted - && !h->def_regular - && !ELF_COMMON_DEF_P (h)) - { - /* Make sure this symbol is output as a dynamic symbol. */ - if (!ensure_undef_dynamic (info, h)) - return FALSE; - - if (h->dynindx == -1) - eh->dyn_relocs = NULL; - } - else - eh->dyn_relocs = NULL; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc = elf_section_data (p->sec)->sreloc; - if (eh->elf.type == STT_GNU_IFUNC) - sreloc = htab->elf.irelplt; - sreloc->size += p->count * sizeof (Elf64_External_Rela); - } - } - - if ((htab->elf.dynamic_sections_created - && h->dynindx != -1) - || h->type == STT_GNU_IFUNC) - { - struct plt_entry *pent; - bfd_boolean doneone = FALSE; - for (pent = h->plt.plist; pent != NULL; pent = pent->next) - if (pent->plt.refcount > 0) - { - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - s = htab->elf.iplt; - pent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE (htab); - s = htab->elf.irelplt; - } - else - { - /* If this is the first .plt entry, make room for the special - first entry. */ - s = htab->elf.splt; - if (s->size == 0) - s->size += PLT_INITIAL_ENTRY_SIZE (htab); - - pent->plt.offset = s->size; - - /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE (htab); - - /* Make room for the .glink code. */ - s = htab->glink; - if (s->size == 0) - s->size += GLINK_PLTRESOLVE_SIZE (htab); - if (htab->opd_abi) - { - /* We need bigger stubs past index 32767. */ - if (s->size >= GLINK_PLTRESOLVE_SIZE (htab) + 32768*2*4) - s->size += 4; - s->size += 2*4; - } - else - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - s = htab->elf.srelplt; - } - s->size += sizeof (Elf64_External_Rela); - doneone = TRUE; - } - else - pent->plt.offset = (bfd_vma) -1; - if (!doneone) - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - } - else - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - - return TRUE; -} - -#define PPC_LO(v) ((v) & 0xffff) -#define PPC_HI(v) (((v) >> 16) & 0xffff) -#define PPC_HA(v) PPC_HI ((v) + 0x8000) - -/* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections - to set up space for global entry stubs. These are put in glink, - after the branch table. */ - -static bfd_boolean -size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct ppc_link_hash_table *htab; - struct plt_entry *pent; - asection *s, *plt; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - if (!h->pointer_equality_needed) - return TRUE; - - if (h->def_regular) - return TRUE; - - info = inf; - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - s = htab->global_entry; - plt = htab->elf.splt; - for (pent = h->plt.plist; pent != NULL; pent = pent->next) - if (pent->plt.offset != (bfd_vma) -1 - && pent->addend == 0) - { - /* For ELFv2, if this symbol is not defined in a regular file - and we are not generating a shared library or pie, then we - need to define the symbol in the executable on a call stub. - This is to avoid text relocations. */ - bfd_vma off, stub_align, stub_off, stub_size; - unsigned int align_power; - - stub_size = 16; - if (!htab->params->speculate_indirect_jumps) - stub_size += 8; - stub_off = s->size; - if (htab->params->plt_stub_align >= 0) - align_power = htab->params->plt_stub_align; - else - align_power = -htab->params->plt_stub_align; - /* Setting section alignment is delayed until we know it is - non-empty. Otherwise the .text output section will be - aligned at least to plt_stub_align even when no global - entry stubs are needed. */ - if (s->alignment_power < align_power) - s->alignment_power = align_power; - stub_align = (bfd_vma) 1 << align_power; - if (htab->params->plt_stub_align >= 0 - || ((((stub_off + stub_size - 1) & -stub_align) - - (stub_off & -stub_align)) - > ((stub_size - 1) & -stub_align))) - stub_off = (stub_off + stub_align - 1) & -stub_align; - off = pent->plt.offset + plt->output_offset + plt->output_section->vma; - off -= stub_off + s->output_offset + s->output_section->vma; - /* Note that for --plt-stub-align negative we have a possible - dependency between stub offset and size. Break that - dependency by assuming the max stub size when calculating - the stub offset. */ - if (PPC_HA (off) == 0) - stub_size -= 4; - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = s; - h->root.u.def.value = stub_off; - s->size = stub_off + stub_size; - break; - } - return TRUE; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *inf) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -ppc64_elf_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - struct got_entry *first_tlsld; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - 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 (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (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) - { - struct got_entry **lgot_ents; - struct got_entry **end_lgot_ents; - struct plt_entry **local_plt; - struct plt_entry **end_local_plt; - unsigned char *lgot_masks; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - - if (!is_ppc64_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct ppc_dyn_relocs *p; - - for (p = 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) - { - asection *srel = elf_section_data (p->sec)->sreloc; - if (p->ifunc) - srel = htab->elf.irelplt; - srel->size += p->count * sizeof (Elf64_External_Rela); - if ((p->sec->output_section->flags & SEC_READONLY) != 0) - info->flags |= DF_TEXTREL; - } - } - } - - lgot_ents = elf_local_got_ents (ibfd); - if (!lgot_ents) - continue; - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_lgot_ents = lgot_ents + locsymcount; - local_plt = (struct plt_entry **) end_lgot_ents; - end_local_plt = local_plt + locsymcount; - lgot_masks = (unsigned char *) end_local_plt; - s = ppc64_elf_tdata (ibfd)->got; - for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks) - { - struct got_entry **pent, *ent; - - pent = lgot_ents; - while ((ent = *pent) != NULL) - if (ent->got.refcount > 0) - { - if ((ent->tls_type & *lgot_masks & TLS_LD) != 0) - { - ppc64_tlsld_got (ibfd)->got.refcount += 1; - *pent = ent->next; - } - else - { - unsigned int ent_size = 8; - unsigned int rel_size = sizeof (Elf64_External_Rela); - - ent->got.offset = s->size; - if ((ent->tls_type & *lgot_masks & TLS_GD) != 0) - { - ent_size *= 2; - rel_size *= 2; - } - s->size += ent_size; - if ((*lgot_masks & PLT_IFUNC) != 0) - { - htab->elf.irelplt->size += rel_size; - htab->got_reli_size += rel_size; - } - else if (bfd_link_pic (info) - && !((ent->tls_type & TLS_TPREL) != 0 - && bfd_link_executable (info))) - { - asection *srel = ppc64_elf_tdata (ibfd)->relgot; - srel->size += rel_size; - } - pent = &ent->next; - } - } - else - *pent = ent->next; - } - - /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ - for (; local_plt < end_local_plt; ++local_plt) - { - struct plt_entry *ent; - - for (ent = *local_plt; ent != NULL; ent = ent->next) - if (ent->plt.refcount > 0) - { - s = htab->elf.iplt; - ent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE (htab); - - htab->elf.irelplt->size += sizeof (Elf64_External_Rela); - } - else - ent->plt.offset = (bfd_vma) -1; - } - } - - /* Allocate global sym .plt and .got entries, and space for global - sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); - - if (!htab->opd_abi && !bfd_link_pic (info)) - elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info); - - first_tlsld = NULL; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - struct got_entry *ent; - - if (!is_ppc64_elf (ibfd)) - continue; - - ent = ppc64_tlsld_got (ibfd); - if (ent->got.refcount > 0) - { - if (!htab->do_multi_toc && first_tlsld != NULL) - { - ent->is_indirect = TRUE; - ent->got.ent = first_tlsld; - } - else - { - if (first_tlsld == NULL) - first_tlsld = ent; - s = ppc64_elf_tdata (ibfd)->got; - ent->got.offset = s->size; - ent->owner = ibfd; - s->size += 16; - if (bfd_link_pic (info)) - { - asection *srel = ppc64_elf_tdata (ibfd)->relgot; - srel->size += sizeof (Elf64_External_Rela); - } - } - } - else - ent->got.offset = (bfd_vma) -1; - } - - /* 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->brlt || s == htab->relbrlt) - /* These haven't been allocated yet; don't strip. */ - continue; - else if (s == htab->elf.sgot - || s == htab->elf.splt - || s == htab->elf.iplt - || s == htab->glink - || s == htab->global_entry - || s == htab->elf.sdynbss - || s == htab->elf.sdynrelro) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (s == htab->glink_eh_frame) - { - if (!bfd_is_abs_section (s->output_section)) - /* Not sized yet. */ - continue; - } - else if (CONST_STRNEQ (s->name, ".rela")) - { - if (s->size != 0) - { - if (s != htab->elf.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - } - else - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is mostly to handle .rela.bss and - .rela.plt. We must create both sections in - create_dynamic_sections, because they must be created - before the linker maps input sections to output - sections. The linker does that before - adjust_dynamic_symbol is called, and it is that - function which decides whether anything needs to go - into these sections. */ - s->flags |= SEC_EXCLUDE; - continue; - } - - if (bfd_is_abs_section (s->output_section)) - _bfd_error_handler (_("warning: discarding dynamic section %s"), - s->name); - - 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_PPC64_NONE reloc in .rela - sections instead of garbage. - We also rely on the section contents being zero when writing - the GOT and .dynrelro. */ - s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - if (!is_ppc64_elf (ibfd)) - continue; - - s = ppc64_elf_tdata (ibfd)->got; - if (s != NULL && s != htab->elf.sgot) - { - if (s->size == 0) - s->flags |= SEC_EXCLUDE; - else - { - s->contents = bfd_zalloc (ibfd, s->size); - if (s->contents == NULL) - return FALSE; - } - } - s = ppc64_elf_tdata (ibfd)->relgot; - if (s != NULL) - { - if (s->size == 0) - s->flags |= SEC_EXCLUDE; - else - { - s->contents = bfd_zalloc (ibfd, s->size); - if (s->contents == NULL) - return FALSE; - relocs = TRUE; - s->reloc_count = 0; - } - } - } - - if (htab->elf.dynamic_sections_created) - { - bfd_boolean tls_opt; - - /* Add some entries to the .dynamic section. We fill in the - values later, in ppc64_elf_finish_dynamic_sections, but we - must add the entries now so that we get the correct size for - the .dynamic section. The DT_DEBUG entry is filled in by the - dynamic linker and used by the debugger. */ -#define add_dynamic_entry(TAG, VAL) \ - _bfd_elf_add_dynamic_entry (info, TAG, VAL) - - if (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->elf.splt != NULL && htab->elf.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0) - || !add_dynamic_entry (DT_PPC64_GLINK, 0)) - return FALSE; - } - - if (NO_OPD_RELOCS && abiversion (output_bfd) <= 1) - { - if (!add_dynamic_entry (DT_PPC64_OPD, 0) - || !add_dynamic_entry (DT_PPC64_OPDSZ, 0)) - return FALSE; - } - - tls_opt = (htab->params->tls_get_addr_opt - && htab->tls_get_addr_fd != NULL - && htab->tls_get_addr_fd->elf.plt.plist != NULL); - if (tls_opt || !htab->opd_abi) - { - if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 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, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ - -static bfd_boolean -ppc64_elf_hash_symbol (struct elf_link_hash_entry *h) -{ - if (h->plt.plist != NULL - && !h->def_regular - && !h->pointer_equality_needed) - return FALSE; - - return _bfd_elf_hash_symbol (h); -} - -/* Determine the type of stub needed, if any, for a call. */ - -static inline enum ppc_stub_type -ppc_type_of_stub (asection *input_sec, - const Elf_Internal_Rela *rel, - struct ppc_link_hash_entry **hash, - struct plt_entry **plt_ent, - bfd_vma destination, - unsigned long local_off) -{ - struct ppc_link_hash_entry *h = *hash; - bfd_vma location; - bfd_vma branch_offset; - bfd_vma max_branch_offset; - enum elf_ppc64_reloc_type r_type; - - if (h != NULL) - { - struct plt_entry *ent; - struct ppc_link_hash_entry *fdh = h; - if (h->oh != NULL - && h->oh->is_func_descriptor) - { - fdh = ppc_follow_link (h->oh); - *hash = fdh; - } - - for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend - && ent->plt.offset != (bfd_vma) -1) - { - *plt_ent = ent; - return ppc_stub_plt_call; - } - - /* Here, we know we don't have a plt entry. If we don't have a - either a defined function descriptor or a defined entry symbol - in a regular object file, then it is pointless trying to make - any other type of stub. */ - if (!is_static_defined (&fdh->elf) - && !is_static_defined (&h->elf)) - return ppc_stub_none; - } - else if (elf_local_got_ents (input_sec->owner) != NULL) - { - Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_sec->owner); - struct plt_entry **local_plt = (struct plt_entry **) - elf_local_got_ents (input_sec->owner) + symtab_hdr->sh_info; - unsigned long r_symndx = ELF64_R_SYM (rel->r_info); - - if (local_plt[r_symndx] != NULL) - { - struct plt_entry *ent; - - for (ent = local_plt[r_symndx]; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend - && ent->plt.offset != (bfd_vma) -1) - { - *plt_ent = ent; - return ppc_stub_plt_call; - } - } - } - - /* Determine where the call point is. */ - location = (input_sec->output_offset - + input_sec->output_section->vma - + rel->r_offset); - - branch_offset = destination - location; - r_type = ELF64_R_TYPE (rel->r_info); - - /* Determine if a long branch stub is needed. */ - max_branch_offset = 1 << 25; - if (r_type != R_PPC64_REL24) - max_branch_offset = 1 << 15; - - if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off) - /* We need a stub. Figure out whether a long_branch or plt_branch - is needed later. */ - return ppc_stub_long_branch; - - return ppc_stub_none; -} - -/* With power7 weakly ordered memory model, it is possible for ld.so - to update a plt entry in one thread and have another thread see a - stale zero toc entry. To avoid this we need some sort of acquire - barrier in the call stub. One solution is to make the load of the - toc word seem to appear to depend on the load of the function entry - word. Another solution is to test for r2 being zero, and branch to - the appropriate glink entry if so. - - . fake dep barrier compare - . ld 12,xxx(2) ld 12,xxx(2) - . mtctr 12 mtctr 12 - . xor 11,12,12 ld 2,xxx+8(2) - . add 2,2,11 cmpldi 2,0 - . ld 2,xxx+8(2) bnectr+ - . bctr b - - The solution involving the compare turns out to be faster, so - that's what we use unless the branch won't reach. */ - -#define ALWAYS_USE_FAKE_DEP 0 -#define ALWAYS_EMIT_R2SAVE 0 - -static inline unsigned int -plt_stub_size (struct ppc_link_hash_table *htab, - struct ppc_stub_hash_entry *stub_entry, - bfd_vma off) -{ - unsigned size = 12; - - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - size += 4; - if (PPC_HA (off) != 0) - size += 4; - if (!htab->params->speculate_indirect_jumps) - size += 8; - if (htab->opd_abi) - { - size += 4; - if (htab->params->plt_static_chain) - size += 4; - if (htab->params->plt_thread_safe - && htab->elf.dynamic_sections_created - && stub_entry->h != NULL - && stub_entry->h->elf.dynindx != -1) - size += 8; - if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off)) - size += 4; - } - if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) - && htab->params->tls_get_addr_opt) - { - size += 7 * 4; - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - { - size += 6 * 4; - if (!htab->params->speculate_indirect_jumps) - size -= 4; - } - } - return size; -} - -/* Depending on the sign of plt_stub_align: - If positive, return the padding to align to a 2**plt_stub_align - boundary. - If negative, if this stub would cross fewer 2**plt_stub_align - boundaries if we align, then return the padding needed to do so. */ - -static inline unsigned int -plt_stub_pad (struct ppc_link_hash_table *htab, - struct ppc_stub_hash_entry *stub_entry, - bfd_vma plt_off) -{ - int stub_align; - unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off); - bfd_vma stub_off = stub_entry->group->stub_sec->size; - - if (htab->params->plt_stub_align >= 0) - { - stub_align = 1 << htab->params->plt_stub_align; - if ((stub_off & (stub_align - 1)) != 0) - return stub_align - (stub_off & (stub_align - 1)); - return 0; - } - - stub_align = 1 << -htab->params->plt_stub_align; - if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align) - > ((stub_size - 1) & -stub_align)) - return stub_align - (stub_off & (stub_align - 1)); - return 0; -} - -static inline bfd_byte * -output_bctr (struct ppc_link_hash_table *htab, bfd *obfd, bfd_byte *p) -{ - if (!htab->params->speculate_indirect_jumps) - { - bfd_put_32 (obfd, CRSETEQ, p); - p += 4; - bfd_put_32 (obfd, BEQCTRM, p); - p += 4; - bfd_put_32 (obfd, B_DOT, p); - p += 4; - } - else - { - bfd_put_32 (obfd, BCTR, p); - p += 4; - } - return p; -} - -/* Build a .plt call stub. */ - -static inline bfd_byte * -build_plt_stub (struct ppc_link_hash_table *htab, - struct ppc_stub_hash_entry *stub_entry, - bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) -{ - bfd *obfd = htab->params->stub_bfd; - bfd_boolean plt_load_toc = htab->opd_abi; - bfd_boolean plt_static_chain = htab->params->plt_static_chain; - bfd_boolean plt_thread_safe = (htab->params->plt_thread_safe - && htab->elf.dynamic_sections_created - && stub_entry->h != NULL - && stub_entry->h->elf.dynindx != -1); - bfd_boolean use_fake_dep = plt_thread_safe; - bfd_vma cmp_branch_off = 0; - - if (!ALWAYS_USE_FAKE_DEP - && plt_load_toc - && plt_thread_safe - && htab->params->speculate_indirect_jumps - && !((stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) - && htab->params->tls_get_addr_opt)) - { - bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1; - bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab)) - / PLT_ENTRY_SIZE (htab)); - bfd_vma glinkoff = GLINK_PLTRESOLVE_SIZE (htab) + pltindex * 8; - bfd_vma to, from; - - if (pltindex > 32768) - glinkoff += (pltindex - 32768) * 4; - to = (glinkoff - + htab->glink->output_offset - + htab->glink->output_section->vma); - from = (p - stub_entry->group->stub_sec->contents - + 4 * (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - + 4 * (PPC_HA (offset) != 0) - + 4 * (PPC_HA (offset + 8 + 8 * plt_static_chain) - != PPC_HA (offset)) - + 4 * (plt_static_chain != 0) - + 20 - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); - cmp_branch_off = to - from; - use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26); - } - - if (PPC_HA (offset) != 0) - { - if (r != NULL) - { - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - r[0].r_offset += 4; - r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA); - r[1].r_offset = r[0].r_offset + 4; - r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); - r[1].r_addend = r[0].r_addend; - if (plt_load_toc) - { - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) - { - r[2].r_offset = r[1].r_offset + 4; - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); - r[2].r_addend = r[0].r_addend; - } - else - { - r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep; - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); - r[2].r_addend = r[0].r_addend + 8; - if (plt_static_chain) - { - r[3].r_offset = r[2].r_offset + 4; - r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); - r[3].r_addend = r[0].r_addend + 16; - } - } - } - } - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; - if (plt_load_toc) - { - bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; - bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; - } - else - { - bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; - bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (offset), p), p += 4; - } - if (plt_load_toc - && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) - { - bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p), p += 4; - offset = 0; - } - bfd_put_32 (obfd, MTCTR_R12, p), p += 4; - if (plt_load_toc) - { - if (use_fake_dep) - { - bfd_put_32 (obfd, XOR_R2_R12_R12, p), p += 4; - bfd_put_32 (obfd, ADD_R11_R11_R2, p), p += 4; - } - bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4; - if (plt_static_chain) - bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4; - } - } - else - { - if (r != NULL) - { - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - r[0].r_offset += 4; - r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - if (plt_load_toc) - { - if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) - { - r[1].r_offset = r[0].r_offset + 4; - r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); - r[1].r_addend = r[0].r_addend; - } - else - { - r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep; - r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; - if (plt_static_chain) - { - r[2].r_offset = r[1].r_offset + 4; - r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - r[2].r_addend = r[0].r_addend + 8; - } - } - } - } - if (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; - bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p), p += 4; - if (plt_load_toc - && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) - { - bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p), p += 4; - offset = 0; - } - bfd_put_32 (obfd, MTCTR_R12, p), p += 4; - if (plt_load_toc) - { - if (use_fake_dep) - { - bfd_put_32 (obfd, XOR_R11_R12_R12, p), p += 4; - bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; - } - if (plt_static_chain) - bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4; - bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4; - } - } - if (plt_load_toc && plt_thread_safe && !use_fake_dep) - { - bfd_put_32 (obfd, CMPLDI_R2_0, p), p += 4; - bfd_put_32 (obfd, BNECTR_P4, p), p += 4; - bfd_put_32 (obfd, B_DOT | (cmp_branch_off & 0x3fffffc), p), p += 4; - } - else - p = output_bctr (htab, obfd, p); - return p; -} - -/* Build a special .plt call stub for __tls_get_addr. */ - -#define LD_R11_0R3 0xe9630000 -#define LD_R12_0R3 0xe9830000 -#define MR_R0_R3 0x7c601b78 -#define CMPDI_R11_0 0x2c2b0000 -#define ADD_R3_R12_R13 0x7c6c6a14 -#define BEQLR 0x4d820020 -#define MR_R3_R0 0x7c030378 -#define STD_R11_0R1 0xf9610000 -#define BCTRL 0x4e800421 -#define LD_R11_0R1 0xe9610000 -#define MTLR_R11 0x7d6803a6 - -static inline bfd_byte * -build_tls_get_addr_stub (struct ppc_link_hash_table *htab, - struct ppc_stub_hash_entry *stub_entry, - bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) -{ - bfd *obfd = htab->params->stub_bfd; - - bfd_put_32 (obfd, LD_R11_0R3 + 0, p), p += 4; - bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4; - bfd_put_32 (obfd, MR_R0_R3, p), p += 4; - bfd_put_32 (obfd, CMPDI_R11_0, p), p += 4; - bfd_put_32 (obfd, ADD_R3_R12_R13, p), p += 4; - bfd_put_32 (obfd, BEQLR, p), p += 4; - bfd_put_32 (obfd, MR_R3_R0, p), p += 4; - if (r != NULL) - r[0].r_offset += 7 * 4; - if (!ALWAYS_EMIT_R2SAVE - && stub_entry->stub_type != ppc_stub_plt_call_r2save) - return build_plt_stub (htab, stub_entry, p, offset, r); - - bfd_put_32 (obfd, MFLR_R11, p), p += 4; - bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4; - - if (r != NULL) - r[0].r_offset += 2 * 4; - p = build_plt_stub (htab, stub_entry, p, offset, r); - if (!htab->params->speculate_indirect_jumps) - { - p -= 4; - bfd_put_32 (obfd, BEQCTRLM, p - 4); - } - else - bfd_put_32 (obfd, BCTRL, p - 4); - - bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4; - bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4; - bfd_put_32 (obfd, MTLR_R11, p), p += 4; - bfd_put_32 (obfd, BLR, p), p += 4; - - return p; -} - -static Elf_Internal_Rela * -get_relocs (asection *sec, int count) -{ - Elf_Internal_Rela *relocs; - struct bfd_elf_section_data *elfsec_data; - - elfsec_data = elf_section_data (sec); - relocs = elfsec_data->relocs; - if (relocs == NULL) - { - bfd_size_type relsize; - relsize = sec->reloc_count * sizeof (*relocs); - relocs = bfd_alloc (sec->owner, relsize); - if (relocs == NULL) - return NULL; - elfsec_data->relocs = relocs; - elfsec_data->rela.hdr = bfd_zalloc (sec->owner, - sizeof (Elf_Internal_Shdr)); - if (elfsec_data->rela.hdr == NULL) - return NULL; - elfsec_data->rela.hdr->sh_size = (sec->reloc_count - * sizeof (Elf64_External_Rela)); - elfsec_data->rela.hdr->sh_entsize = sizeof (Elf64_External_Rela); - sec->reloc_count = 0; - } - relocs += sec->reloc_count; - sec->reloc_count += count; - return relocs; -} - -static bfd_vma -get_r2off (struct bfd_link_info *info, - struct ppc_stub_hash_entry *stub_entry) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - bfd_vma r2off = htab->sec_info[stub_entry->target_section->id].toc_off; - - if (r2off == 0) - { - /* Support linking -R objects. Get the toc pointer from the - opd entry. */ - char buf[8]; - if (!htab->opd_abi) - return r2off; - asection *opd = stub_entry->h->elf.root.u.def.section; - bfd_vma opd_off = stub_entry->h->elf.root.u.def.value; - - if (strcmp (opd->name, ".opd") != 0 - || opd->reloc_count != 0) - { - info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"), - stub_entry->h->elf.root.root.string); - bfd_set_error (bfd_error_bad_value); - return (bfd_vma) -1; - } - if (!bfd_get_section_contents (opd->owner, opd, buf, opd_off + 8, 8)) - return (bfd_vma) -1; - r2off = bfd_get_64 (opd->owner, buf); - r2off -= elf_gp (info->output_bfd); - } - r2off -= htab->sec_info[stub_entry->group->link_sec->id].toc_off; - return r2off; -} - -static bfd_boolean -ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) -{ - struct ppc_stub_hash_entry *stub_entry; - struct ppc_branch_hash_entry *br_entry; - struct bfd_link_info *info; - struct ppc_link_hash_table *htab; - bfd_byte *loc; - bfd_byte *p; - bfd_vma dest, off; - Elf_Internal_Rela *r; - asection *plt; - - /* Massage our args to the form they really have. */ - stub_entry = (struct ppc_stub_hash_entry *) gen_entry; - info = in_arg; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset = stub_entry->group->stub_sec->size; - loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset; - - htab->stub_count[stub_entry->stub_type - 1] += 1; - switch (stub_entry->stub_type) - { - case ppc_stub_long_branch: - case ppc_stub_long_branch_r2off: - /* Branches are relative. This is where we are going to. */ - dest = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); - off = dest; - - /* And this is where we are coming from. */ - off -= (stub_entry->stub_offset - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); - - p = loc; - if (stub_entry->stub_type == ppc_stub_long_branch_r2off) - { - bfd_vma r2off = get_r2off (info, stub_entry); - - if (r2off == (bfd_vma) -1) - { - htab->stub_error = TRUE; - return FALSE; - } - bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p); - p += 4; - if (PPC_HA (r2off) != 0) - { - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R2_R2 | PPC_HA (r2off), p); - p += 4; - } - if (PPC_LO (r2off) != 0) - { - bfd_put_32 (htab->params->stub_bfd, - ADDI_R2_R2 | PPC_LO (r2off), p); - p += 4; - } - off -= p - loc; - } - bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), p); - p += 4; - - if (off + (1 << 25) >= (bfd_vma) (1 << 26)) - { - info->callbacks->einfo - (_("%P: long branch stub `%s' offset overflow\n"), - stub_entry->root.string); - htab->stub_error = TRUE; - return FALSE; - } - - if (info->emitrelocations) - { - r = get_relocs (stub_entry->group->stub_sec, 1); - if (r == NULL) - return FALSE; - r->r_offset = p - 4 - stub_entry->group->stub_sec->contents; - r->r_info = ELF64_R_INFO (0, R_PPC64_REL24); - r->r_addend = dest; - if (stub_entry->h != NULL) - { - struct elf_link_hash_entry **hashes; - unsigned long symndx; - struct ppc_link_hash_entry *h; - - hashes = elf_sym_hashes (htab->params->stub_bfd); - if (hashes == NULL) - { - bfd_size_type hsize; - - hsize = (htab->stub_globals + 1) * sizeof (*hashes); - hashes = bfd_zalloc (htab->params->stub_bfd, hsize); - if (hashes == NULL) - return FALSE; - elf_sym_hashes (htab->params->stub_bfd) = hashes; - htab->stub_globals = 1; - } - symndx = htab->stub_globals++; - h = stub_entry->h; - hashes[symndx] = &h->elf; - r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24); - if (h->oh != NULL && h->oh->is_func) - h = ppc_follow_link (h->oh); - if (h->elf.root.u.def.section != stub_entry->target_section) - /* H is an opd symbol. The addend must be zero. */ - r->r_addend = 0; - else - { - off = (h->elf.root.u.def.value - + h->elf.root.u.def.section->output_offset - + h->elf.root.u.def.section->output_section->vma); - r->r_addend -= off; - } - } - } - break; - - case ppc_stub_plt_branch: - case ppc_stub_plt_branch_r2off: - br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, - stub_entry->root.string + 9, - FALSE, FALSE); - if (br_entry == NULL) - { - info->callbacks->einfo (_("%P: can't find branch stub `%s'\n"), - stub_entry->root.string); - htab->stub_error = TRUE; - return FALSE; - } - - dest = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) - dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); - - bfd_put_64 (htab->brlt->owner, dest, - htab->brlt->contents + br_entry->offset); - - if (br_entry->iter == htab->stub_iteration) - { - br_entry->iter = 0; - - if (htab->relbrlt != NULL) - { - /* Create a reloc for the branch lookup table entry. */ - Elf_Internal_Rela rela; - bfd_byte *rl; - - rela.r_offset = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma); - rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - rela.r_addend = dest; - - rl = htab->relbrlt->contents; - rl += (htab->relbrlt->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl); - } - else if (info->emitrelocations) - { - r = get_relocs (htab->brlt, 1); - if (r == NULL) - return FALSE; - /* brlt, being SEC_LINKER_CREATED does not go through the - normal reloc processing. Symbols and offsets are not - translated from input file to output file form, so - set up the offset per the output file. */ - r->r_offset = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma); - r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - r->r_addend = dest; - } - } - - dest = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma); - - off = (dest - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); - - if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) - { - info->callbacks->einfo - (_("%P: linkage table error against `%T'\n"), - stub_entry->root.string); - bfd_set_error (bfd_error_bad_value); - htab->stub_error = TRUE; - return FALSE; - } - - if (info->emitrelocations) - { - r = get_relocs (stub_entry->group->stub_sec, 1 + (PPC_HA (off) != 0)); - if (r == NULL) - return FALSE; - r[0].r_offset = loc - stub_entry->group->stub_sec->contents; - if (bfd_big_endian (info->output_bfd)) - r[0].r_offset += 2; - if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) - r[0].r_offset += 4; - r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); - r[0].r_addend = dest; - if (PPC_HA (off) != 0) - { - r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA); - r[1].r_offset = r[0].r_offset + 4; - r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); - r[1].r_addend = r[0].r_addend; - } - } - - p = loc; - if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) - { - if (PPC_HA (off) != 0) - { - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R12_R2 | PPC_HA (off), p); - p += 4; - bfd_put_32 (htab->params->stub_bfd, - LD_R12_0R12 | PPC_LO (off), p); - } - else - bfd_put_32 (htab->params->stub_bfd, - LD_R12_0R2 | PPC_LO (off), p); - } - else - { - bfd_vma r2off = get_r2off (info, stub_entry); - - if (r2off == (bfd_vma) -1) - { - htab->stub_error = TRUE; - return FALSE; - } - - bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p); - p += 4; - if (PPC_HA (off) != 0) - { - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R12_R2 | PPC_HA (off), p); - p += 4; - bfd_put_32 (htab->params->stub_bfd, - LD_R12_0R12 | PPC_LO (off), p); - } - else - bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), p); - - if (PPC_HA (r2off) != 0) - { - p += 4; - bfd_put_32 (htab->params->stub_bfd, - ADDIS_R2_R2 | PPC_HA (r2off), p); - } - if (PPC_LO (r2off) != 0) - { - p += 4; - bfd_put_32 (htab->params->stub_bfd, - ADDI_R2_R2 | PPC_LO (r2off), p); - } - } - p += 4; - bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p); - p += 4; - p = output_bctr (htab, htab->params->stub_bfd, p); - break; - - case ppc_stub_plt_call: - case ppc_stub_plt_call_r2save: - if (stub_entry->h != NULL - && stub_entry->h->is_func_descriptor - && stub_entry->h->oh != NULL) - { - struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh); - - /* If the old-ABI "dot-symbol" is undefined make it weak so - we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. */ - if (fh->elf.root.type == bfd_link_hash_undefined - && (stub_entry->h->elf.root.type == bfd_link_hash_defined - || stub_entry->h->elf.root.type == bfd_link_hash_defweak)) - fh->elf.root.type = bfd_link_hash_undefweak; - } - - /* Now build the stub. */ - dest = stub_entry->plt_ent->plt.offset & ~1; - if (dest >= (bfd_vma) -2) - abort (); - - plt = htab->elf.splt; - if (!htab->elf.dynamic_sections_created - || stub_entry->h == NULL - || stub_entry->h->elf.dynindx == -1) - plt = htab->elf.iplt; - - dest += plt->output_offset + plt->output_section->vma; - - if (stub_entry->h == NULL - && (stub_entry->plt_ent->plt.offset & 1) == 0) - { - Elf_Internal_Rela rela; - bfd_byte *rl; - - rela.r_offset = dest; - if (htab->opd_abi) - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); - else - rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); - rela.r_addend = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - - rl = (htab->elf.irelplt->contents - + (htab->elf.irelplt->reloc_count++ - * sizeof (Elf64_External_Rela))); - bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl); - stub_entry->plt_ent->plt.offset |= 1; - htab->local_ifunc_resolver = 1; - } - - off = (dest - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); - - if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: linkage table error against `%T'\n"), - stub_entry->h != NULL - ? stub_entry->h->elf.root.root.string - : ""); - bfd_set_error (bfd_error_bad_value); - htab->stub_error = TRUE; - return FALSE; - } - - if (htab->params->plt_stub_align != 0) - { - unsigned pad = plt_stub_pad (htab, stub_entry, off); - - stub_entry->group->stub_sec->size += pad; - stub_entry->stub_offset = stub_entry->group->stub_sec->size; - loc += pad; - } - - r = NULL; - if (info->emitrelocations) - { - r = get_relocs (stub_entry->group->stub_sec, - ((PPC_HA (off) != 0) - + (htab->opd_abi - ? 2 + (htab->params->plt_static_chain - && PPC_HA (off + 16) == PPC_HA (off)) - : 1))); - if (r == NULL) - return FALSE; - r[0].r_offset = loc - stub_entry->group->stub_sec->contents; - if (bfd_big_endian (info->output_bfd)) - r[0].r_offset += 2; - r[0].r_addend = dest; - } - if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) - && htab->params->tls_get_addr_opt) - p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r); - else - p = build_plt_stub (htab, stub_entry, loc, off, r); - break; - - case ppc_stub_save_res: - return TRUE; - - default: - BFD_FAIL (); - return FALSE; - } - - stub_entry->group->stub_sec->size += p - loc; - - if (htab->params->emit_stub_syms) - { - struct elf_link_hash_entry *h; - size_t len1, len2; - char *name; - const char *const stub_str[] = { "long_branch", - "long_branch_r2off", - "plt_branch", - "plt_branch_r2off", - "plt_call", - "plt_call" }; - - len1 = strlen (stub_str[stub_entry->stub_type - 1]); - len2 = strlen (stub_entry->root.string); - name = bfd_malloc (len1 + len2 + 2); - if (name == NULL) - return FALSE; - memcpy (name, stub_entry->root.string, 9); - memcpy (name + 9, stub_str[stub_entry->stub_type - 1], len1); - memcpy (name + len1 + 9, stub_entry->root.string + 8, len2 - 8 + 1); - h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); - if (h == NULL) - return FALSE; - if (h->root.type == bfd_link_hash_new) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = stub_entry->group->stub_sec; - h->root.u.def.value = stub_entry->stub_offset; - h->ref_regular = 1; - h->def_regular = 1; - h->ref_regular_nonweak = 1; - h->forced_local = 1; - h->non_elf = 0; - h->root.linker_def = 1; - } - } - - return TRUE; -} - -/* As above, but don't actually build the stub. Just bump offset so - we know stub section sizes, and select plt_branch stubs where - long_branch stubs won't do. */ - -static bfd_boolean -ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) -{ - struct ppc_stub_hash_entry *stub_entry; - struct bfd_link_info *info; - struct ppc_link_hash_table *htab; - bfd_vma off; - int size; - - /* Massage our args to the form they really have. */ - stub_entry = (struct ppc_stub_hash_entry *) gen_entry; - info = in_arg; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - if (stub_entry->h != NULL - && stub_entry->h->save_res - && stub_entry->h->elf.root.type == bfd_link_hash_defined - && stub_entry->h->elf.root.u.def.section == htab->sfpr) - { - /* Don't make stubs to out-of-line register save/restore - functions. Instead, emit copies of the functions. */ - stub_entry->group->needs_save_res = 1; - stub_entry->stub_type = ppc_stub_save_res; - return TRUE; - } - - if (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - { - asection *plt; - off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; - if (off >= (bfd_vma) -2) - abort (); - plt = htab->elf.splt; - if (!htab->elf.dynamic_sections_created - || stub_entry->h == NULL - || stub_entry->h->elf.dynindx == -1) - plt = htab->elf.iplt; - off += (plt->output_offset - + plt->output_section->vma - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); - - size = plt_stub_size (htab, stub_entry, off); - if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) - && htab->params->tls_get_addr_opt - && (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save)) - stub_entry->group->tls_get_addr_opt_bctrl - = stub_entry->group->stub_sec->size + size - 5 * 4; - - if (htab->params->plt_stub_align) - size += plt_stub_pad (htab, stub_entry, off); - if (info->emitrelocations) - { - stub_entry->group->stub_sec->reloc_count - += ((PPC_HA (off) != 0) - + (htab->opd_abi - ? 2 + (htab->params->plt_static_chain - && PPC_HA (off + 16) == PPC_HA (off)) - : 1)); - stub_entry->group->stub_sec->flags |= SEC_RELOC; - } - } - else - { - /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off - variants. */ - bfd_vma r2off = 0; - bfd_vma local_off = 0; - - off = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); - off -= (stub_entry->group->stub_sec->size - + stub_entry->group->stub_sec->output_offset - + stub_entry->group->stub_sec->output_section->vma); - - /* Reset the stub type from the plt variant in case we now - can reach with a shorter stub. */ - if (stub_entry->stub_type >= ppc_stub_plt_branch) - stub_entry->stub_type += ppc_stub_long_branch - ppc_stub_plt_branch; - - size = 4; - if (stub_entry->stub_type == ppc_stub_long_branch_r2off) - { - r2off = get_r2off (info, stub_entry); - if (r2off == (bfd_vma) -1) - { - htab->stub_error = TRUE; - return FALSE; - } - size = 8; - if (PPC_HA (r2off) != 0) - size += 4; - if (PPC_LO (r2off) != 0) - size += 4; - off -= size - 4; - } - - local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); - - /* If the branch offset if too big, use a ppc_stub_plt_branch. - Do the same for -R objects without function descriptors. */ - if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off - || (stub_entry->stub_type == ppc_stub_long_branch_r2off - && r2off == 0 - && htab->sec_info[stub_entry->target_section->id].toc_off == 0)) - { - struct ppc_branch_hash_entry *br_entry; - - br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, - stub_entry->root.string + 9, - TRUE, FALSE); - if (br_entry == NULL) - { - info->callbacks->einfo (_("%P: can't build branch stub `%s'\n"), - stub_entry->root.string); - htab->stub_error = TRUE; - return FALSE; - } - - if (br_entry->iter != htab->stub_iteration) - { - br_entry->iter = htab->stub_iteration; - br_entry->offset = htab->brlt->size; - htab->brlt->size += 8; - - if (htab->relbrlt != NULL) - htab->relbrlt->size += sizeof (Elf64_External_Rela); - else if (info->emitrelocations) - { - htab->brlt->reloc_count += 1; - htab->brlt->flags |= SEC_RELOC; - } - } - - stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch; - off = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma - - elf_gp (info->output_bfd) - - htab->sec_info[stub_entry->group->link_sec->id].toc_off); - - if (info->emitrelocations) - { - stub_entry->group->stub_sec->reloc_count - += 1 + (PPC_HA (off) != 0); - stub_entry->group->stub_sec->flags |= SEC_RELOC; - } - - if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) - { - size = 12; - if (PPC_HA (off) != 0) - size = 16; - } - else - { - size = 16; - if (PPC_HA (off) != 0) - size += 4; - - if (PPC_HA (r2off) != 0) - size += 4; - if (PPC_LO (r2off) != 0) - size += 4; - } - if (!htab->params->speculate_indirect_jumps) - size += 8; - } - else if (info->emitrelocations) - { - stub_entry->group->stub_sec->reloc_count += 1; - stub_entry->group->stub_sec->flags |= SEC_RELOC; - } - } - - stub_entry->group->stub_sec->size += size; - return TRUE; -} - -/* Set up various things so that we can make a list of input sections - for each output section included in the link. Returns -1 on error, - 0 when no stubs will be needed, and 1 on success. */ - -int -ppc64_elf_setup_section_lists (struct bfd_link_info *info) -{ - unsigned int id; - bfd_size_type amt; - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab == NULL) - return -1; - - htab->sec_info_arr_size = bfd_get_next_section_id (); - amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size); - htab->sec_info = bfd_zmalloc (amt); - if (htab->sec_info == NULL) - return -1; - - /* Set toc_off for com, und, abs and ind sections. */ - for (id = 0; id < 3; id++) - htab->sec_info[id].toc_off = TOC_BASE_OFF; - - return 1; -} - -/* Set up for first pass at multitoc partitioning. */ - -void -ppc64_elf_start_multitoc_partition (struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - htab->toc_curr = ppc64_elf_set_toc (info, info->output_bfd); - htab->toc_bfd = NULL; - htab->toc_first_sec = NULL; -} - -/* The linker repeatedly calls this function for each TOC input section - and linker generated GOT section. Group input bfds such that the toc - within a group is less than 64k in size. */ - -bfd_boolean -ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - bfd_vma addr, off, limit; - - if (htab == NULL) - return FALSE; - - if (!htab->second_toc_pass) - { - /* Keep track of the first .toc or .got section for this input bfd. */ - bfd_boolean new_bfd = htab->toc_bfd != isec->owner; - - if (new_bfd) - { - htab->toc_bfd = isec->owner; - htab->toc_first_sec = isec; - } - - addr = isec->output_offset + isec->output_section->vma; - off = addr - htab->toc_curr; - limit = 0x80008000; - if (ppc64_elf_tdata (isec->owner)->has_small_toc_reloc) - limit = 0x10000; - if (off + isec->size > limit) - { - addr = (htab->toc_first_sec->output_offset - + htab->toc_first_sec->output_section->vma); - htab->toc_curr = addr; - htab->toc_curr &= -TOC_BASE_ALIGN; - } - - /* toc_curr is the base address of this toc group. Set elf_gp - for the input section to be the offset relative to the - output toc base plus 0x8000. Making the input elf_gp an - offset allows us to move the toc as a whole without - recalculating input elf_gp. */ - off = htab->toc_curr - elf_gp (info->output_bfd); - off += TOC_BASE_OFF; - - /* Die if someone uses a linker script that doesn't keep input - file .toc and .got together. */ - if (new_bfd - && elf_gp (isec->owner) != 0 - && elf_gp (isec->owner) != off) - return FALSE; - - elf_gp (isec->owner) = off; - return TRUE; - } - - /* During the second pass toc_first_sec points to the start of - a toc group, and toc_curr is used to track the old elf_gp. - We use toc_bfd to ensure we only look at each bfd once. */ - if (htab->toc_bfd == isec->owner) - return TRUE; - htab->toc_bfd = isec->owner; - - if (htab->toc_first_sec == NULL - || htab->toc_curr != elf_gp (isec->owner)) - { - htab->toc_curr = elf_gp (isec->owner); - htab->toc_first_sec = isec; - } - addr = (htab->toc_first_sec->output_offset - + htab->toc_first_sec->output_section->vma); - off = addr - elf_gp (info->output_bfd) + TOC_BASE_OFF; - elf_gp (isec->owner) = off; - - return TRUE; -} - -/* Called via elf_link_hash_traverse to merge GOT entries for global - symbol H. */ - -static bfd_boolean -merge_global_got (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) -{ - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - merge_got_entries (&h->got.glist); - - return TRUE; -} - -/* Called via elf_link_hash_traverse to allocate GOT entries for global - symbol H. */ - -static bfd_boolean -reallocate_got (struct elf_link_hash_entry *h, void *inf) -{ - struct got_entry *gent; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - for (gent = h->got.glist; gent != NULL; gent = gent->next) - if (!gent->is_indirect) - allocate_got (h, (struct bfd_link_info *) inf, gent); - return TRUE; -} - -/* Called on the first multitoc pass after the last call to - ppc64_elf_next_toc_section. This function removes duplicate GOT - entries. */ - -bfd_boolean -ppc64_elf_layout_multitoc (struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - struct bfd *ibfd, *ibfd2; - bfd_boolean done_something; - - htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd); - - if (!htab->do_multi_toc) - return FALSE; - - /* Merge global sym got entries within a toc group. */ - elf_link_hash_traverse (&htab->elf, merge_global_got, info); - - /* And tlsld_got. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - struct got_entry *ent, *ent2; - - if (!is_ppc64_elf (ibfd)) - continue; - - ent = ppc64_tlsld_got (ibfd); - if (!ent->is_indirect - && ent->got.offset != (bfd_vma) -1) - { - for (ibfd2 = ibfd->link.next; ibfd2 != NULL; ibfd2 = ibfd2->link.next) - { - if (!is_ppc64_elf (ibfd2)) - continue; - - ent2 = ppc64_tlsld_got (ibfd2); - if (!ent2->is_indirect - && ent2->got.offset != (bfd_vma) -1 - && elf_gp (ibfd2) == elf_gp (ibfd)) - { - ent2->is_indirect = TRUE; - ent2->got.ent = ent; - } - } - } - } - - /* Zap sizes of got sections. */ - htab->elf.irelplt->rawsize = htab->elf.irelplt->size; - htab->elf.irelplt->size -= htab->got_reli_size; - htab->got_reli_size = 0; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *got, *relgot; - - if (!is_ppc64_elf (ibfd)) - continue; - - got = ppc64_elf_tdata (ibfd)->got; - if (got != NULL) - { - got->rawsize = got->size; - got->size = 0; - relgot = ppc64_elf_tdata (ibfd)->relgot; - relgot->rawsize = relgot->size; - relgot->size = 0; - } - } - - /* Now reallocate the got, local syms first. We don't need to - allocate section contents again since we never increase size. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - struct got_entry **lgot_ents; - struct got_entry **end_lgot_ents; - struct plt_entry **local_plt; - struct plt_entry **end_local_plt; - unsigned char *lgot_masks; - bfd_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *s; - - if (!is_ppc64_elf (ibfd)) - continue; - - lgot_ents = elf_local_got_ents (ibfd); - if (!lgot_ents) - continue; - - symtab_hdr = &elf_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_lgot_ents = lgot_ents + locsymcount; - local_plt = (struct plt_entry **) end_lgot_ents; - end_local_plt = local_plt + locsymcount; - lgot_masks = (unsigned char *) end_local_plt; - s = ppc64_elf_tdata (ibfd)->got; - for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks) - { - struct got_entry *ent; - - for (ent = *lgot_ents; ent != NULL; ent = ent->next) - { - unsigned int ent_size = 8; - unsigned int rel_size = sizeof (Elf64_External_Rela); - - ent->got.offset = s->size; - if ((ent->tls_type & *lgot_masks & TLS_GD) != 0) - { - ent_size *= 2; - rel_size *= 2; - } - s->size += ent_size; - if ((*lgot_masks & PLT_IFUNC) != 0) - { - htab->elf.irelplt->size += rel_size; - htab->got_reli_size += rel_size; - } - else if (bfd_link_pic (info)) - { - asection *srel = ppc64_elf_tdata (ibfd)->relgot; - srel->size += rel_size; - } - } - } - } - - elf_link_hash_traverse (&htab->elf, reallocate_got, info); - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - struct got_entry *ent; - - if (!is_ppc64_elf (ibfd)) - continue; - - ent = ppc64_tlsld_got (ibfd); - if (!ent->is_indirect - && ent->got.offset != (bfd_vma) -1) - { - asection *s = ppc64_elf_tdata (ibfd)->got; - ent->got.offset = s->size; - s->size += 16; - if (bfd_link_pic (info)) - { - asection *srel = ppc64_elf_tdata (ibfd)->relgot; - srel->size += sizeof (Elf64_External_Rela); - } - } - } - - done_something = htab->elf.irelplt->rawsize != htab->elf.irelplt->size; - if (!done_something) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *got; - - if (!is_ppc64_elf (ibfd)) - continue; - - got = ppc64_elf_tdata (ibfd)->got; - if (got != NULL) - { - done_something = got->rawsize != got->size; - if (done_something) - break; - } - } - - if (done_something) - (*htab->params->layout_sections_again) (); - - /* Set up for second pass over toc sections to recalculate elf_gp - on input sections. */ - htab->toc_bfd = NULL; - htab->toc_first_sec = NULL; - htab->second_toc_pass = TRUE; - return done_something; -} - -/* Called after second pass of multitoc partitioning. */ - -void -ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - /* After the second pass, toc_curr tracks the TOC offset used - for code sections below in ppc64_elf_next_input_section. */ - htab->toc_curr = TOC_BASE_OFF; -} - -/* No toc references were found in ISEC. If the code in ISEC makes no - calls, then there's no need to use toc adjusting stubs when branching - into ISEC. Actually, indirect calls from ISEC are OK as they will - load r2. Returns -1 on error, 0 for no stub needed, 1 for stub - needed, and 2 if a cyclical call-graph was found but no other reason - for a stub was detected. If called from the top level, a return of - 2 means the same as a return of 0. */ - -static int -toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) -{ - int ret; - - /* Mark this section as checked. */ - isec->call_check_done = 1; - - /* We know none of our code bearing sections will need toc stubs. */ - if ((isec->flags & SEC_LINKER_CREATED) != 0) - return 0; - - if (isec->size == 0) - return 0; - - if (isec->output_section == NULL) - return 0; - - ret = 0; - if (isec->reloc_count != 0) - { - Elf_Internal_Rela *relstart, *rel; - Elf_Internal_Sym *local_syms; - struct ppc_link_hash_table *htab; - - relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL, - info->keep_memory); - if (relstart == NULL) - return -1; - - /* Look for branches to outside of this section. */ - local_syms = NULL; - htab = ppc_hash_table (info); - if (htab == NULL) - return -1; - - for (rel = relstart; rel < relstart + isec->reloc_count; ++rel) - { - enum elf_ppc64_reloc_type r_type; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - struct ppc_link_hash_entry *eh; - Elf_Internal_Sym *sym; - asection *sym_sec; - struct _opd_sec_data *opd; - bfd_vma sym_value; - bfd_vma dest; - - r_type = ELF64_R_TYPE (rel->r_info); - if (r_type != R_PPC64_REL24 - && r_type != R_PPC64_REL14 - && r_type != R_PPC64_REL14_BRTAKEN - && r_type != R_PPC64_REL14_BRNTAKEN) - continue; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx, - isec->owner)) - { - ret = -1; - break; - } - - /* Calls to dynamic lib functions go through a plt call stub - that uses r2. */ - eh = (struct ppc_link_hash_entry *) h; - if (eh != NULL - && (eh->elf.plt.plist != NULL - || (eh->oh != NULL - && ppc_follow_link (eh->oh)->elf.plt.plist != NULL))) - { - ret = 1; - break; - } - - if (sym_sec == NULL) - /* Ignore other undefined symbols. */ - continue; - - /* Assume branches to other sections not included in the - link need stubs too, to cover -R and absolute syms. */ - if (sym_sec->output_section == NULL) - { - ret = 1; - break; - } - - if (h == NULL) - sym_value = sym->st_value; - else - { - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - abort (); - sym_value = h->root.u.def.value; - } - sym_value += rel->r_addend; - - /* If this branch reloc uses an opd sym, find the code section. */ - opd = get_opd_info (sym_sec); - if (opd != NULL) - { - if (h == NULL && opd->adjust != NULL) - { - long adjust; - - adjust = opd->adjust[OPD_NDX (sym_value)]; - if (adjust == -1) - /* Assume deleted functions won't ever be called. */ - continue; - sym_value += adjust; - } - - dest = opd_entry_value (sym_sec, sym_value, - &sym_sec, NULL, FALSE); - if (dest == (bfd_vma) -1) - continue; - } - else - dest = (sym_value - + sym_sec->output_offset - + sym_sec->output_section->vma); - - /* Ignore branch to self. */ - if (sym_sec == isec) - continue; - - /* If the called function uses the toc, we need a stub. */ - if (sym_sec->has_toc_reloc - || sym_sec->makes_toc_func_call) - { - ret = 1; - break; - } - - /* Assume any branch that needs a long branch stub might in fact - need a plt_branch stub. A plt_branch stub uses r2. */ - else if (dest - (isec->output_offset - + isec->output_section->vma - + rel->r_offset) + (1 << 25) - >= (2u << 25) - PPC64_LOCAL_ENTRY_OFFSET (h - ? h->other - : sym->st_other)) - { - ret = 1; - break; - } - - /* If calling back to a section in the process of being - tested, we can't say for sure that no toc adjusting stubs - are needed, so don't return zero. */ - else if (sym_sec->call_check_in_progress) - ret = 2; - - /* Branches to another section that itself doesn't have any TOC - references are OK. Recursively call ourselves to check. */ - else if (!sym_sec->call_check_done) - { - int recur; - - /* Mark current section as indeterminate, so that other - sections that call back to current won't be marked as - known. */ - isec->call_check_in_progress = 1; - recur = toc_adjusting_stub_needed (info, sym_sec); - isec->call_check_in_progress = 0; - - if (recur != 0) - { - ret = recur; - if (recur != 2) - break; - } - } - } - - if (local_syms != NULL - && (elf_symtab_hdr (isec->owner).contents - != (unsigned char *) local_syms)) - free (local_syms); - if (elf_section_data (isec)->relocs != relstart) - free (relstart); - } - - if ((ret & 1) == 0 - && isec->map_head.s != NULL - && (strcmp (isec->output_section->name, ".init") == 0 - || strcmp (isec->output_section->name, ".fini") == 0)) - { - if (isec->map_head.s->has_toc_reloc - || isec->map_head.s->makes_toc_func_call) - ret = 1; - else if (!isec->map_head.s->call_check_done) - { - int recur; - isec->call_check_in_progress = 1; - recur = toc_adjusting_stub_needed (info, isec->map_head.s); - isec->call_check_in_progress = 0; - if (recur != 0) - ret = recur; - } - } - - if (ret == 1) - isec->makes_toc_func_call = 1; - - return ret; -} - -/* The linker repeatedly calls this function for each input section, - in the order that input sections are linked into output sections. - Build lists of input sections to determine groupings between which - we may insert linker stubs. */ - -bfd_boolean -ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab == NULL) - return FALSE; - - if ((isec->output_section->flags & SEC_CODE) != 0 - && isec->output_section->id < htab->sec_info_arr_size) - { - /* This happens to make the list in reverse order, - which is what we want. */ - htab->sec_info[isec->id].u.list - = htab->sec_info[isec->output_section->id].u.list; - htab->sec_info[isec->output_section->id].u.list = isec; - } - - if (htab->multi_toc_needed) - { - /* Analyse sections that aren't already flagged as needing a - valid toc pointer. Exclude .fixup for the linux kernel. - .fixup contains branches, but only back to the function that - hit an exception. */ - if (!(isec->has_toc_reloc - || (isec->flags & SEC_CODE) == 0 - || strcmp (isec->name, ".fixup") == 0 - || isec->call_check_done)) - { - if (toc_adjusting_stub_needed (info, isec) < 0) - return FALSE; - } - /* Make all sections use the TOC assigned for this object file. - This will be wrong for pasted sections; We fix that in - check_pasted_section(). */ - if (elf_gp (isec->owner) != 0) - htab->toc_curr = elf_gp (isec->owner); - } - - htab->sec_info[isec->id].toc_off = htab->toc_curr; - return TRUE; -} - -/* Check that all .init and .fini sections use the same toc, if they - have toc relocs. */ - -static bfd_boolean -check_pasted_section (struct bfd_link_info *info, const char *name) -{ - asection *o = bfd_get_section_by_name (info->output_bfd, name); - - if (o != NULL) - { - struct ppc_link_hash_table *htab = ppc_hash_table (info); - bfd_vma toc_off = 0; - asection *i; - - for (i = o->map_head.s; i != NULL; i = i->map_head.s) - if (i->has_toc_reloc) - { - if (toc_off == 0) - toc_off = htab->sec_info[i->id].toc_off; - else if (toc_off != htab->sec_info[i->id].toc_off) - return FALSE; - } - - if (toc_off == 0) - for (i = o->map_head.s; i != NULL; i = i->map_head.s) - if (i->makes_toc_func_call) - { - toc_off = htab->sec_info[i->id].toc_off; - break; - } - - /* Make sure the whole pasted function uses the same toc offset. */ - if (toc_off != 0) - for (i = o->map_head.s; i != NULL; i = i->map_head.s) - htab->sec_info[i->id].toc_off = toc_off; - } - return TRUE; -} - -bfd_boolean -ppc64_elf_check_init_fini (struct bfd_link_info *info) -{ - return (check_pasted_section (info, ".init") - & check_pasted_section (info, ".fini")); -} - -/* See whether we can group stub sections together. Grouping stub - sections may result in fewer stubs. More importantly, we need to - put all .init* and .fini* stubs at the beginning of the .init or - .fini output sections respectively, because glibc splits the - _init and _fini functions into multiple parts. Putting a stub in - the middle of a function is not a good idea. */ - -static bfd_boolean -group_sections (struct bfd_link_info *info, - bfd_size_type stub_group_size, - bfd_boolean stubs_always_before_branch) -{ - struct ppc_link_hash_table *htab; - asection *osec; - bfd_boolean suppress_size_errors; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - suppress_size_errors = FALSE; - if (stub_group_size == 1) - { - /* Default values. */ - if (stubs_always_before_branch) - stub_group_size = 0x1e00000; - else - stub_group_size = 0x1c00000; - suppress_size_errors = TRUE; - } - - for (osec = info->output_bfd->sections; osec != NULL; osec = osec->next) - { - asection *tail; - - if (osec->id >= htab->sec_info_arr_size) - continue; - - tail = htab->sec_info[osec->id].u.list; - while (tail != NULL) - { - asection *curr; - asection *prev; - bfd_size_type total; - bfd_boolean big_sec; - bfd_vma curr_toc; - struct map_stub *group; - bfd_size_type group_size; - - curr = tail; - total = tail->size; - group_size = (ppc64_elf_section_data (tail) != NULL - && ppc64_elf_section_data (tail)->has_14bit_branch - ? stub_group_size >> 10 : stub_group_size); - - big_sec = total > group_size; - if (big_sec && !suppress_size_errors) - /* xgettext:c-format */ - _bfd_error_handler (_("%B section %A exceeds stub group size"), - tail->owner, tail); - curr_toc = htab->sec_info[tail->id].toc_off; - - while ((prev = htab->sec_info[curr->id].u.list) != NULL - && ((total += curr->output_offset - prev->output_offset) - < (ppc64_elf_section_data (prev) != NULL - && ppc64_elf_section_data (prev)->has_14bit_branch - ? (group_size = stub_group_size >> 10) : group_size)) - && htab->sec_info[prev->id].toc_off == curr_toc) - curr = prev; - - /* OK, the size from the start of CURR to the end is less - than group_size and thus can be handled by one stub - section. (or the tail section is itself larger than - group_size, in which case we may be toast.) We should - really be keeping track of the total size of stubs added - here, as stubs contribute to the final output section - size. That's a little tricky, and this way will only - break if stubs added make the total size more than 2^25, - ie. for the default stub_group_size, if stubs total more - than 2097152 bytes, or nearly 75000 plt call stubs. */ - group = bfd_alloc (curr->owner, sizeof (*group)); - if (group == NULL) - return FALSE; - group->link_sec = curr; - group->stub_sec = NULL; - group->needs_save_res = 0; - group->tls_get_addr_opt_bctrl = -1u; - group->next = htab->group; - htab->group = group; - do - { - prev = htab->sec_info[tail->id].u.list; - /* Set up this stub group. */ - htab->sec_info[tail->id].u.group = group; - } - while (tail != curr && (tail = prev) != NULL); - - /* But wait, there's more! Input sections up to group_size - bytes before the stub section can be handled by it too. - Don't do this if we have a really large section after the - stubs, as adding more stubs increases the chance that - branches may not reach into the stub section. */ - if (!stubs_always_before_branch && !big_sec) - { - total = 0; - while (prev != NULL - && ((total += tail->output_offset - prev->output_offset) - < (ppc64_elf_section_data (prev) != NULL - && ppc64_elf_section_data (prev)->has_14bit_branch - ? (group_size = stub_group_size >> 10) : group_size)) - && htab->sec_info[prev->id].toc_off == curr_toc) - { - tail = prev; - prev = htab->sec_info[tail->id].u.list; - htab->sec_info[tail->id].u.group = group; - } - } - tail = prev; - } - } - return TRUE; -} - -static const unsigned char glink_eh_frame_cie[] = -{ - 0, 0, 0, 16, /* length. */ - 0, 0, 0, 0, /* id. */ - 1, /* CIE version. */ - 'z', 'R', 0, /* Augmentation string. */ - 4, /* Code alignment. */ - 0x78, /* Data alignment. */ - 65, /* RA reg. */ - 1, /* Augmentation size. */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ - DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ -}; - -static size_t -stub_eh_frame_size (struct map_stub *group, size_t align) -{ - size_t this_size = 17; - if (group->tls_get_addr_opt_bctrl != -1u) - { - unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4; - if (to_bctrl < 64) - this_size += 1; - else if (to_bctrl < 256) - this_size += 2; - else if (to_bctrl < 65536) - this_size += 3; - else - this_size += 5; - this_size += 6; - } - this_size = (this_size + align - 1) & -align; - return this_size; -} - -/* Stripping output sections is normally done before dynamic section - symbols have been allocated. This function is called later, and - handles cases like htab->brlt which is mapped to its own output - section. */ - -static void -maybe_strip_output (struct bfd_link_info *info, asection *isec) -{ - if (isec->size == 0 - && isec->output_section->size == 0 - && !(isec->output_section->flags & SEC_KEEP) - && !bfd_section_removed_from_list (info->output_bfd, - isec->output_section) - && elf_section_data (isec->output_section)->dynindx == 0) - { - isec->output_section->flags |= SEC_EXCLUDE; - bfd_section_list_remove (info->output_bfd, isec->output_section); - info->output_bfd->section_count--; - } -} - -/* Determine and set the size of the stub section for a final link. - - The basic idea here is to examine all the relocations looking for - PC-relative calls to a target that is unreachable with a "bl" - instruction. */ - -bfd_boolean -ppc64_elf_size_stubs (struct bfd_link_info *info) -{ - bfd_size_type stub_group_size; - bfd_boolean stubs_always_before_branch; - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab == NULL) - return FALSE; - - if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info)) - htab->params->plt_thread_safe = 1; - if (!htab->opd_abi) - htab->params->plt_thread_safe = 0; - else if (htab->params->plt_thread_safe == -1) - { - static const char *const thread_starter[] = - { - "pthread_create", - /* libstdc++ */ - "_ZNSt6thread15_M_start_threadESt10shared_ptrINS_10_Impl_baseEE", - /* librt */ - "aio_init", "aio_read", "aio_write", "aio_fsync", "lio_listio", - "mq_notify", "create_timer", - /* libanl */ - "getaddrinfo_a", - /* libgomp */ - "GOMP_parallel", - "GOMP_parallel_start", - "GOMP_parallel_loop_static", - "GOMP_parallel_loop_static_start", - "GOMP_parallel_loop_dynamic", - "GOMP_parallel_loop_dynamic_start", - "GOMP_parallel_loop_guided", - "GOMP_parallel_loop_guided_start", - "GOMP_parallel_loop_runtime", - "GOMP_parallel_loop_runtime_start", - "GOMP_parallel_sections", - "GOMP_parallel_sections_start", - /* libgo */ - "__go_go", - }; - unsigned i; - - for (i = 0; i < ARRAY_SIZE (thread_starter); i++) - { - struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (&htab->elf, thread_starter[i], - FALSE, FALSE, TRUE); - htab->params->plt_thread_safe = h != NULL && h->ref_regular; - if (htab->params->plt_thread_safe) - break; - } - } - stubs_always_before_branch = htab->params->group_size < 0; - if (htab->params->group_size < 0) - stub_group_size = -htab->params->group_size; - else - stub_group_size = htab->params->group_size; - - if (!group_sections (info, stub_group_size, stubs_always_before_branch)) - return FALSE; - -#define STUB_SHRINK_ITER 20 - /* Loop until no stubs added. After iteration 20 of this loop we may - exit on a stub section shrinking. This is to break out of a - pathological case where adding stubs on one iteration decreases - section gaps (perhaps due to alignment), which then requires - fewer or smaller stubs on the next iteration. */ - - while (1) - { - bfd *input_bfd; - unsigned int bfd_indx; - struct map_stub *group; - - htab->stub_iteration += 1; - - for (input_bfd = info->input_bfds, bfd_indx = 0; - input_bfd != NULL; - input_bfd = input_bfd->link.next, bfd_indx++) - { - Elf_Internal_Shdr *symtab_hdr; - asection *section; - Elf_Internal_Sym *local_syms = NULL; - - if (!is_ppc64_elf (input_bfd)) - continue; - - /* We'll need the symbol table in a second. */ - symtab_hdr = &elf_symtab_hdr (input_bfd); - if (symtab_hdr->sh_info == 0) - continue; - - /* Walk over each section attached to the input bfd. */ - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - Elf_Internal_Rela *internal_relocs, *irelaend, *irela; - - /* If there aren't any relocs, then there's nothing more - to do. */ - if ((section->flags & SEC_RELOC) == 0 - || (section->flags & SEC_ALLOC) == 0 - || (section->flags & SEC_LOAD) == 0 - || (section->flags & SEC_CODE) == 0 - || section->reloc_count == 0) - continue; - - /* If this section is a link-once section that will be - discarded, then don't create any stubs. */ - if (section->output_section == NULL - || section->output_section->owner != info->output_bfd) - continue; - - /* Get the relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_ret_free_local; - - /* Now examine each relocation. */ - irela = internal_relocs; - irelaend = irela + section->reloc_count; - for (; irela < irelaend; irela++) - { - enum elf_ppc64_reloc_type r_type; - unsigned int r_indx; - enum ppc_stub_type stub_type; - struct ppc_stub_hash_entry *stub_entry; - asection *sym_sec, *code_sec; - bfd_vma sym_value, code_value; - bfd_vma destination; - unsigned long local_off; - bfd_boolean ok_dest; - struct ppc_link_hash_entry *hash; - struct ppc_link_hash_entry *fdh; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - char *stub_name; - const asection *id_sec; - struct _opd_sec_data *opd; - struct plt_entry *plt_ent; - - r_type = ELF64_R_TYPE (irela->r_info); - r_indx = ELF64_R_SYM (irela->r_info); - - if (r_type >= R_PPC64_max) - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - - /* Only look for stubs on branch instructions. */ - if (r_type != R_PPC64_REL24 - && r_type != R_PPC64_REL14 - && r_type != R_PPC64_REL14_BRTAKEN - && r_type != R_PPC64_REL14_BRNTAKEN) - continue; - - /* Now determine the call target, its name, value, - section. */ - if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, - r_indx, input_bfd)) - goto error_ret_free_internal; - hash = (struct ppc_link_hash_entry *) h; - - ok_dest = FALSE; - fdh = NULL; - sym_value = 0; - if (hash == NULL) - { - sym_value = sym->st_value; - if (sym_sec != NULL - && sym_sec->output_section != NULL) - ok_dest = TRUE; - } - else if (hash->elf.root.type == bfd_link_hash_defined - || hash->elf.root.type == bfd_link_hash_defweak) - { - sym_value = hash->elf.root.u.def.value; - if (sym_sec->output_section != NULL) - ok_dest = TRUE; - } - else if (hash->elf.root.type == bfd_link_hash_undefweak - || hash->elf.root.type == bfd_link_hash_undefined) - { - /* Recognise an old ABI func code entry sym, and - use the func descriptor sym instead if it is - defined. */ - if (hash->elf.root.root.string[0] == '.' - && hash->oh != NULL) - { - fdh = ppc_follow_link (hash->oh); - if (fdh->elf.root.type == bfd_link_hash_defined - || fdh->elf.root.type == bfd_link_hash_defweak) - { - sym_sec = fdh->elf.root.u.def.section; - sym_value = fdh->elf.root.u.def.value; - if (sym_sec->output_section != NULL) - ok_dest = TRUE; - } - else - fdh = NULL; - } - } - else - { - bfd_set_error (bfd_error_bad_value); - goto error_ret_free_internal; - } - - destination = 0; - local_off = 0; - if (ok_dest) - { - sym_value += irela->r_addend; - destination = (sym_value - + sym_sec->output_offset - + sym_sec->output_section->vma); - local_off = PPC64_LOCAL_ENTRY_OFFSET (hash - ? hash->elf.other - : sym->st_other); - } - - code_sec = sym_sec; - code_value = sym_value; - opd = get_opd_info (sym_sec); - if (opd != NULL) - { - bfd_vma dest; - - if (hash == NULL && opd->adjust != NULL) - { - long adjust = opd->adjust[OPD_NDX (sym_value)]; - if (adjust == -1) - continue; - code_value += adjust; - sym_value += adjust; - } - dest = opd_entry_value (sym_sec, sym_value, - &code_sec, &code_value, FALSE); - if (dest != (bfd_vma) -1) - { - destination = dest; - if (fdh != NULL) - { - /* Fixup old ABI sym to point at code - entry. */ - hash->elf.root.type = bfd_link_hash_defweak; - hash->elf.root.u.def.section = code_sec; - hash->elf.root.u.def.value = code_value; - } - } - } - - /* Determine what (if any) linker stub is needed. */ - plt_ent = NULL; - stub_type = ppc_type_of_stub (section, irela, &hash, - &plt_ent, destination, - local_off); - - if (stub_type != ppc_stub_plt_call) - { - /* Check whether we need a TOC adjusting stub. - Since the linker pastes together pieces from - different object files when creating the - _init and _fini functions, it may be that a - call to what looks like a local sym is in - fact a call needing a TOC adjustment. */ - if (code_sec != NULL - && code_sec->output_section != NULL - && (htab->sec_info[code_sec->id].toc_off - != htab->sec_info[section->id].toc_off) - && (code_sec->has_toc_reloc - || code_sec->makes_toc_func_call)) - stub_type = ppc_stub_long_branch_r2off; - } - - if (stub_type == ppc_stub_none) - continue; - - /* __tls_get_addr calls might be eliminated. */ - if (stub_type != ppc_stub_plt_call - && hash != NULL - && (hash == htab->tls_get_addr - || hash == htab->tls_get_addr_fd) - && section->has_tls_reloc - && irela != internal_relocs) - { - /* Get tls info. */ - unsigned char *tls_mask; - - if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms, - irela - 1, input_bfd)) - goto error_ret_free_internal; - if (*tls_mask != 0) - continue; - } - - if (stub_type == ppc_stub_plt_call) - { - if (!htab->opd_abi - && htab->params->plt_localentry0 != 0 - && is_elfv2_localentry0 (&hash->elf)) - htab->has_plt_localentry0 = 1; - else if (irela + 1 < irelaend - && irela[1].r_offset == irela->r_offset + 4 - && (ELF64_R_TYPE (irela[1].r_info) - == R_PPC64_TOCSAVE)) - { - if (!tocsave_find (htab, INSERT, - &local_syms, irela + 1, input_bfd)) - goto error_ret_free_internal; - } - else - stub_type = ppc_stub_plt_call_r2save; - } - - /* Support for grouping stub sections. */ - id_sec = htab->sec_info[section->id].u.group->link_sec; - - /* Get the name of this stub. */ - stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela); - if (!stub_name) - goto error_ret_free_internal; - - stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, - stub_name, FALSE, FALSE); - if (stub_entry != NULL) - { - /* The proper stub has already been created. */ - free (stub_name); - if (stub_type == ppc_stub_plt_call_r2save) - stub_entry->stub_type = stub_type; - continue; - } - - stub_entry = ppc_add_stub (stub_name, section, info); - if (stub_entry == NULL) - { - free (stub_name); - error_ret_free_internal: - if (elf_section_data (section)->relocs == NULL) - free (internal_relocs); - error_ret_free_local: - if (local_syms != NULL - && (symtab_hdr->contents - != (unsigned char *) local_syms)) - free (local_syms); - return FALSE; - } - - stub_entry->stub_type = stub_type; - if (stub_type != ppc_stub_plt_call - && stub_type != ppc_stub_plt_call_r2save) - { - stub_entry->target_value = code_value; - stub_entry->target_section = code_sec; - } - else - { - stub_entry->target_value = sym_value; - stub_entry->target_section = sym_sec; - } - stub_entry->h = hash; - stub_entry->plt_ent = plt_ent; - stub_entry->other = hash ? hash->elf.other : sym->st_other; - - if (stub_entry->h != NULL) - htab->stub_globals += 1; - } - - /* We're done with the internal relocs, free them. */ - if (elf_section_data (section)->relocs != internal_relocs) - free (internal_relocs); - } - - if (local_syms != NULL - && symtab_hdr->contents != (unsigned char *) local_syms) - { - if (!info->keep_memory) - free (local_syms); - else - symtab_hdr->contents = (unsigned char *) local_syms; - } - } - - /* We may have added some stubs. Find out the new size of the - stub sections. */ - for (group = htab->group; group != NULL; group = group->next) - if (group->stub_sec != NULL) - { - asection *stub_sec = group->stub_sec; - - if (htab->stub_iteration <= STUB_SHRINK_ITER - || stub_sec->rawsize < stub_sec->size) - /* Past STUB_SHRINK_ITER, rawsize is the max size seen. */ - stub_sec->rawsize = stub_sec->size; - stub_sec->size = 0; - stub_sec->reloc_count = 0; - stub_sec->flags &= ~SEC_RELOC; - } - - if (htab->stub_iteration <= STUB_SHRINK_ITER - || htab->brlt->rawsize < htab->brlt->size) - htab->brlt->rawsize = htab->brlt->size; - htab->brlt->size = 0; - htab->brlt->reloc_count = 0; - htab->brlt->flags &= ~SEC_RELOC; - if (htab->relbrlt != NULL) - htab->relbrlt->size = 0; - - bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info); - - for (group = htab->group; group != NULL; group = group->next) - if (group->needs_save_res) - group->stub_sec->size += htab->sfpr->size; - - if (info->emitrelocations - && htab->glink != NULL && htab->glink->size != 0) - { - htab->glink->reloc_count = 1; - htab->glink->flags |= SEC_RELOC; - } - - if (htab->glink_eh_frame != NULL - && !bfd_is_abs_section (htab->glink_eh_frame->output_section) - && htab->glink_eh_frame->output_section->size > 8) - { - size_t size = 0, align = 4; - - for (group = htab->group; group != NULL; group = group->next) - if (group->stub_sec != NULL) - size += stub_eh_frame_size (group, align); - if (htab->glink != NULL && htab->glink->size != 0) - size += (24 + align - 1) & -align; - if (size != 0) - size += (sizeof (glink_eh_frame_cie) + align - 1) & -align; - align = 1ul << htab->glink_eh_frame->output_section->alignment_power; - size = (size + align - 1) & -align; - htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; - htab->glink_eh_frame->size = size; - } - - if (htab->params->plt_stub_align != 0) - for (group = htab->group; group != NULL; group = group->next) - if (group->stub_sec != NULL) - { - int align = abs (htab->params->plt_stub_align); - group->stub_sec->size - = (group->stub_sec->size + (1 << align) - 1) & -(1 << align); - } - - for (group = htab->group; group != NULL; group = group->next) - if (group->stub_sec != NULL - && group->stub_sec->rawsize != group->stub_sec->size - && (htab->stub_iteration <= STUB_SHRINK_ITER - || group->stub_sec->rawsize < group->stub_sec->size)) - break; - - if (group == NULL - && (htab->brlt->rawsize == htab->brlt->size - || (htab->stub_iteration > STUB_SHRINK_ITER - && htab->brlt->rawsize > htab->brlt->size)) - && (htab->glink_eh_frame == NULL - || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)) - break; - - /* Ask the linker to do its stuff. */ - (*htab->params->layout_sections_again) (); - } - - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->size != 0) - { - bfd_vma val; - bfd_byte *p, *last_fde; - size_t last_fde_len, size, align, pad; - struct map_stub *group; - - p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); - if (p == NULL) - return FALSE; - htab->glink_eh_frame->contents = p; - last_fde = p; - align = 4; - - memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); - /* CIE length (rewrite in case little-endian). */ - last_fde_len = ((sizeof (glink_eh_frame_cie) + align - 1) & -align) - 4; - bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += last_fde_len + 4; - - for (group = htab->group; group != NULL; group = group->next) - if (group->stub_sec != NULL) - { - last_fde = p; - last_fde_len = stub_eh_frame_size (group, align) - 4; - /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to stub section, written later. */ - p += 4; - /* stub section size. */ - bfd_put_32 (htab->elf.dynobj, group->stub_sec->size, p); - p += 4; - /* Augmentation. */ - p += 1; - if (group->tls_get_addr_opt_bctrl != -1u) - { - unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4; - - /* This FDE needs more than just the default. - Describe __tls_get_addr_opt stub LR. */ - if (to_bctrl < 64) - *p++ = DW_CFA_advance_loc + to_bctrl; - else if (to_bctrl < 256) - { - *p++ = DW_CFA_advance_loc1; - *p++ = to_bctrl; - } - else if (to_bctrl < 65536) - { - *p++ = DW_CFA_advance_loc2; - bfd_put_16 (htab->elf.dynobj, to_bctrl, p); - p += 2; - } - else - { - *p++ = DW_CFA_advance_loc4; - bfd_put_32 (htab->elf.dynobj, to_bctrl, p); - p += 4; - } - *p++ = DW_CFA_offset_extended_sf; - *p++ = 65; - *p++ = -(STK_LINKER (htab) / 8) & 0x7f; - *p++ = DW_CFA_advance_loc + 4; - *p++ = DW_CFA_restore_extended; - *p++ = 65; - } - /* Pad. */ - p = last_fde + last_fde_len + 4; - } - if (htab->glink != NULL && htab->glink->size != 0) - { - last_fde = p; - last_fde_len = ((24 + align - 1) & -align) - 4; - /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to .glink, written later. */ - p += 4; - /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p); - p += 4; - /* Augmentation. */ - p += 1; - - *p++ = DW_CFA_advance_loc + 1; - *p++ = DW_CFA_register; - *p++ = 65; - *p++ = htab->opd_abi ? 12 : 0; - *p++ = DW_CFA_advance_loc + (htab->opd_abi ? 5 : 7); - *p++ = DW_CFA_restore_extended; - *p++ = 65; - p += ((24 + align - 1) & -align) - 24; - } - /* Subsume any padding into the last FDE if user .eh_frame - sections are aligned more than glink_eh_frame. Otherwise any - zero padding will be seen as a terminator. */ - align = 1ul << htab->glink_eh_frame->output_section->alignment_power; - size = p - htab->glink_eh_frame->contents; - pad = ((size + align - 1) & -align) - size; - htab->glink_eh_frame->size = size + pad; - bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); - } - - maybe_strip_output (info, htab->brlt); - if (htab->glink_eh_frame != NULL) - maybe_strip_output (info, htab->glink_eh_frame); - - return TRUE; -} - -/* Called after we have determined section placement. If sections - move, we'll be called again. Provide a value for TOCstart. */ - -bfd_vma -ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd) -{ - asection *s; - bfd_vma TOCstart, adjust; - - if (info != NULL) - { - struct elf_link_hash_entry *h; - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (is_elf_hash_table (htab) - && htab->hgot != NULL) - h = htab->hgot; - else - { - h = elf_link_hash_lookup (htab, ".TOC.", FALSE, FALSE, TRUE); - if (is_elf_hash_table (htab)) - htab->hgot = h; - } - if (h != NULL - && h->root.type == bfd_link_hash_defined - && !h->root.linker_def - && (!is_elf_hash_table (htab) - || h->def_regular)) - { - TOCstart = (h->root.u.def.value - TOC_BASE_OFF - + h->root.u.def.section->output_offset - + h->root.u.def.section->output_section->vma); - _bfd_set_gp_value (obfd, TOCstart); - return TOCstart; - } - } - - /* The TOC consists of sections .got, .toc, .tocbss, .plt in that - order. The TOC starts where the first of these sections starts. */ - s = bfd_get_section_by_name (obfd, ".got"); - if (s == NULL || (s->flags & SEC_EXCLUDE) != 0) - s = bfd_get_section_by_name (obfd, ".toc"); - if (s == NULL || (s->flags & SEC_EXCLUDE) != 0) - s = bfd_get_section_by_name (obfd, ".tocbss"); - if (s == NULL || (s->flags & SEC_EXCLUDE) != 0) - s = bfd_get_section_by_name (obfd, ".plt"); - if (s == NULL || (s->flags & SEC_EXCLUDE) != 0) - { - /* This may happen for - o references to TOC base (SYM@toc / TOC[tc0]) without a - .toc directive - o bad linker script - o --gc-sections and empty TOC sections - - FIXME: Warn user? */ - - /* Look for a likely section. We probably won't even be - using TOCstart. */ - for (s = obfd->sections; s != NULL; s = s->next) - if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY - | SEC_EXCLUDE)) - == (SEC_ALLOC | SEC_SMALL_DATA)) - break; - if (s == NULL) - for (s = obfd->sections; s != NULL; s = s->next) - if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_EXCLUDE)) - == (SEC_ALLOC | SEC_SMALL_DATA)) - break; - if (s == NULL) - for (s = obfd->sections; s != NULL; s = s->next) - if ((s->flags & (SEC_ALLOC | SEC_READONLY | SEC_EXCLUDE)) - == SEC_ALLOC) - break; - if (s == NULL) - for (s = obfd->sections; s != NULL; s = s->next) - if ((s->flags & (SEC_ALLOC | SEC_EXCLUDE)) == SEC_ALLOC) - break; - } - - TOCstart = 0; - if (s != NULL) - TOCstart = s->output_section->vma + s->output_offset; - - /* Force alignment. */ - adjust = TOCstart & (TOC_BASE_ALIGN - 1); - TOCstart -= adjust; - _bfd_set_gp_value (obfd, TOCstart); - - if (info != NULL && s != NULL) - { - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (htab != NULL) - { - if (htab->elf.hgot != NULL) - { - htab->elf.hgot->root.u.def.value = TOC_BASE_OFF - adjust; - htab->elf.hgot->root.u.def.section = s; - } - } - else - { - struct bfd_link_hash_entry *bh = NULL; - _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL, - s, TOC_BASE_OFF - adjust, - NULL, FALSE, FALSE, &bh); - } - } - return TOCstart; -} - -/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to - write out any global entry stubs. */ - -static bfd_boolean -build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct ppc_link_hash_table *htab; - struct plt_entry *pent; - asection *s; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - if (!h->pointer_equality_needed) - return TRUE; - - if (h->def_regular) - return TRUE; - - info = inf; - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - s = htab->global_entry; - for (pent = h->plt.plist; pent != NULL; pent = pent->next) - if (pent->plt.offset != (bfd_vma) -1 - && pent->addend == 0) - { - bfd_byte *p; - asection *plt; - bfd_vma off; - - p = s->contents + h->root.u.def.value; - plt = htab->elf.splt; - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - plt = htab->elf.iplt; - off = pent->plt.offset + plt->output_offset + plt->output_section->vma; - off -= h->root.u.def.value + s->output_offset + s->output_section->vma; - - if (off + 0x80008000 > 0xffffffff || (off & 3) != 0) - { - info->callbacks->einfo - (_("%P: linkage table error against `%T'\n"), - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - htab->stub_error = TRUE; - } - - htab->stub_count[ppc_stub_global_entry - 1] += 1; - if (htab->params->emit_stub_syms) - { - size_t len = strlen (h->root.root.string); - char *name = bfd_malloc (sizeof "12345678.global_entry." + len); - - if (name == NULL) - return FALSE; - - sprintf (name, "%08x.global_entry.%s", s->id, h->root.root.string); - h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); - if (h == NULL) - return FALSE; - if (h->root.type == bfd_link_hash_new) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = s; - h->root.u.def.value = p - s->contents; - h->ref_regular = 1; - h->def_regular = 1; - h->ref_regular_nonweak = 1; - h->forced_local = 1; - h->non_elf = 0; - h->root.linker_def = 1; - } - } - - if (PPC_HA (off) != 0) - { - bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p); - p += 4; - } - bfd_put_32 (s->owner, LD_R12_0R12 | PPC_LO (off), p); - p += 4; - bfd_put_32 (s->owner, MTCTR_R12, p); - p += 4; - output_bctr (htab, s->owner, p); - break; - } - return TRUE; -} - -/* Build all the stubs associated with the current output file. - The stubs are kept in a hash table attached to the main linker - hash table. This function is called via gldelf64ppc_finish. */ - -bfd_boolean -ppc64_elf_build_stubs (struct bfd_link_info *info, - char **stats) -{ - struct ppc_link_hash_table *htab = ppc_hash_table (info); - struct map_stub *group; - asection *stub_sec; - bfd_byte *p; - int stub_sec_count = 0; - - if (htab == NULL) - return FALSE; - - /* Allocate memory to hold the linker stubs. */ - for (group = htab->group; group != NULL; group = group->next) - if ((stub_sec = group->stub_sec) != NULL - && stub_sec->size != 0) - { - stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size); - if (stub_sec->contents == NULL) - return FALSE; - stub_sec->size = 0; - } - - if (htab->glink != NULL && htab->glink->size != 0) - { - unsigned int indx; - bfd_vma plt0; - - /* Build the .glink plt call stub. */ - if (htab->params->emit_stub_syms) - { - struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", - TRUE, FALSE, FALSE); - if (h == NULL) - return FALSE; - if (h->root.type == bfd_link_hash_new) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = htab->glink; - h->root.u.def.value = 8; - h->ref_regular = 1; - h->def_regular = 1; - h->ref_regular_nonweak = 1; - h->forced_local = 1; - h->non_elf = 0; - h->root.linker_def = 1; - } - } - plt0 = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - - 16); - if (info->emitrelocations) - { - Elf_Internal_Rela *r = get_relocs (htab->glink, 1); - if (r == NULL) - return FALSE; - r->r_offset = (htab->glink->output_offset - + htab->glink->output_section->vma); - r->r_info = ELF64_R_INFO (0, R_PPC64_REL64); - r->r_addend = plt0; - } - p = htab->glink->contents; - plt0 -= htab->glink->output_section->vma + htab->glink->output_offset; - bfd_put_64 (htab->glink->owner, plt0, p); - p += 8; - if (htab->opd_abi) - { - bfd_put_32 (htab->glink->owner, MFLR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, BCL_20_31, p); - p += 4; - bfd_put_32 (htab->glink->owner, MFLR_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); - p += 4; - bfd_put_32 (htab->glink->owner, MTLR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p); - p += 4; - bfd_put_32 (htab->glink->owner, MTCTR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p); - p += 4; - } - else - { - bfd_put_32 (htab->glink->owner, MFLR_R0, p); - p += 4; - bfd_put_32 (htab->glink->owner, BCL_20_31, p); - p += 4; - bfd_put_32 (htab->glink->owner, MFLR_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, STD_R2_0R1 + 24, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); - p += 4; - bfd_put_32 (htab->glink->owner, MTLR_R0, p); - p += 4; - bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-48 & 0xffff), p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, SRDI_R0_R0_2, p); - p += 4; - bfd_put_32 (htab->glink->owner, MTCTR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p); - p += 4; - } - p = output_bctr (htab, htab->glink->owner, p); - BFD_ASSERT (p == htab->glink->contents + GLINK_PLTRESOLVE_SIZE (htab)); - - /* Build the .glink lazy link call stubs. */ - indx = 0; - while (p < htab->glink->contents + htab->glink->size) - { - if (htab->opd_abi) - { - if (indx < 0x8000) - { - bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p); - p += 4; - } - else - { - bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p); - p += 4; - bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), - p); - p += 4; - } - } - bfd_put_32 (htab->glink->owner, - B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p); - indx++; - p += 4; - } - } - - /* Build .glink global entry stubs. */ - if (htab->global_entry != NULL && htab->global_entry->size != 0) - elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info); - - if (htab->brlt != NULL && htab->brlt->size != 0) - { - htab->brlt->contents = bfd_zalloc (htab->brlt->owner, - htab->brlt->size); - if (htab->brlt->contents == NULL) - return FALSE; - } - if (htab->relbrlt != NULL && htab->relbrlt->size != 0) - { - htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner, - htab->relbrlt->size); - if (htab->relbrlt->contents == NULL) - return FALSE; - } - - /* Build the stubs as directed by the stub hash table. */ - bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); - - for (group = htab->group; group != NULL; group = group->next) - if (group->needs_save_res) - { - stub_sec = group->stub_sec; - memcpy (stub_sec->contents + stub_sec->size, htab->sfpr->contents, - htab->sfpr->size); - if (htab->params->emit_stub_syms) - { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++) - if (!sfpr_define (info, &save_res_funcs[i], stub_sec)) - return FALSE; - } - stub_sec->size += htab->sfpr->size; - } - - if (htab->relbrlt != NULL) - htab->relbrlt->reloc_count = 0; - - if (htab->params->plt_stub_align != 0) - for (group = htab->group; group != NULL; group = group->next) - if ((stub_sec = group->stub_sec) != NULL) - { - int align = abs (htab->params->plt_stub_align); - stub_sec->size = (stub_sec->size + (1 << align) - 1) & -(1 << align); - } - - for (group = htab->group; group != NULL; group = group->next) - if ((stub_sec = group->stub_sec) != NULL) - { - stub_sec_count += 1; - if (stub_sec->rawsize != stub_sec->size - && (htab->stub_iteration <= STUB_SHRINK_ITER - || stub_sec->rawsize < stub_sec->size)) - break; - } - - if (group != NULL) - { - htab->stub_error = TRUE; - info->callbacks->einfo (_("%P: stubs don't match calculated size\n")); - } - - if (htab->stub_error) - return FALSE; - - if (stats != NULL) - { - size_t len; - *stats = bfd_malloc (500); - if (*stats == NULL) - return FALSE; - - len = sprintf (*stats, - ngettext ("linker stubs in %u group\n", - "linker stubs in %u groups\n", - stub_sec_count), - stub_sec_count); - sprintf (*stats + len, _(" branch %lu\n" - " toc adjust %lu\n" - " long branch %lu\n" - " long toc adj %lu\n" - " plt call %lu\n" - " plt call toc %lu\n" - " global entry %lu"), - htab->stub_count[ppc_stub_long_branch - 1], - htab->stub_count[ppc_stub_long_branch_r2off - 1], - htab->stub_count[ppc_stub_plt_branch - 1], - htab->stub_count[ppc_stub_plt_branch_r2off - 1], - htab->stub_count[ppc_stub_plt_call - 1], - htab->stub_count[ppc_stub_plt_call_r2save - 1], - htab->stub_count[ppc_stub_global_entry - 1]); - } - return TRUE; -} - -/* What to do when ld finds relocations against symbols defined in - discarded sections. */ - -static unsigned int -ppc64_elf_action_discarded (asection *sec) -{ - if (strcmp (".opd", sec->name) == 0) - return 0; - - if (strcmp (".toc", sec->name) == 0) - return 0; - - if (strcmp (".toc1", sec->name) == 0) - return 0; - - return _bfd_elf_default_action_discarded (sec); -} - -/* 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. */ - -static bfd_boolean -ppc64_elf_relocate_section (bfd *output_bfd, - struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - struct ppc_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *wrel; - Elf_Internal_Rela *relend; - Elf_Internal_Rela outrel; - bfd_byte *loc; - struct got_entry **local_got_ents; - bfd_vma TOCstart; - bfd_boolean ret = TRUE; - bfd_boolean is_opd; - /* Assume 'at' branch hints. */ - bfd_boolean is_isa_v2 = TRUE; - bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0); - - /* Initialize howto table if needed. */ - if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) - ppc_howto_init (); - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Don't relocate stub sections. */ - if (input_section->owner == htab->params->stub_bfd) - return TRUE; - - BFD_ASSERT (is_ppc64_elf (input_bfd)); - - local_got_ents = elf_local_got_ents (input_bfd); - TOCstart = elf_gp (output_bfd); - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; - - rel = wrel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; wrel++, rel++) - { - enum elf_ppc64_reloc_type r_type; - bfd_vma addend; - bfd_reloc_status_type r; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h_elf; - struct ppc_link_hash_entry *h; - struct ppc_link_hash_entry *fdh; - const char *sym_name; - unsigned long r_symndx, toc_symndx; - bfd_vma toc_addend; - unsigned char tls_mask, tls_gd, tls_type; - unsigned char sym_type; - bfd_vma relocation; - bfd_boolean unresolved_reloc; - bfd_boolean warned; - enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest; - unsigned int insn; - unsigned int mask; - struct ppc_stub_hash_entry *stub_entry; - bfd_vma max_br_offset; - bfd_vma from; - Elf_Internal_Rela orig_rel; - reloc_howto_type *howto; - struct reloc_howto_struct alt_howto; - - again: - orig_rel = *rel; - - r_type = ELF64_R_TYPE (rel->r_info); - r_symndx = ELF64_R_SYM (rel->r_info); - - /* For old style R_PPC64_TOC relocs with a zero symbol, use the - symbol of the previous ADDR64 reloc. The symbol gives us the - proper TOC base to use. */ - if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC) - && wrel != relocs - && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64 - && is_opd) - r_symndx = ELF64_R_SYM (wrel[-1].r_info); - - sym = NULL; - sec = NULL; - h_elf = NULL; - sym_name = NULL; - unresolved_reloc = FALSE; - warned = FALSE; - - if (r_symndx < symtab_hdr->sh_info) - { - /* It's a local symbol. */ - struct _opd_sec_data *opd; - - sym = local_syms + r_symndx; - sec = local_sections[r_symndx]; - sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); - sym_type = ELF64_ST_TYPE (sym->st_info); - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - opd = get_opd_info (sec); - if (opd != NULL && opd->adjust != NULL) - { - long adjust = opd->adjust[OPD_NDX (sym->st_value - + rel->r_addend)]; - if (adjust == -1) - relocation = 0; - else - { - /* If this is a relocation against the opd section sym - and we have edited .opd, adjust the reloc addend so - that ld -r and ld --emit-relocs output is correct. - If it is a reloc against some other .opd symbol, - then the symbol value will be adjusted later. */ - if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - rel->r_addend += adjust; - else - relocation += adjust; - } - } - } - else - { - bfd_boolean ignored; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h_elf, sec, relocation, - unresolved_reloc, warned, ignored); - sym_name = h_elf->root.root.string; - sym_type = h_elf->type; - if (sec != NULL - && sec->owner == output_bfd - && strcmp (sec->name, ".opd") == 0) - { - /* This is a symbol defined in a linker script. All - such are defined in output sections, even those - defined by simple assignment from a symbol defined in - an input section. Transfer the symbol to an - appropriate input .opd section, so that a branch to - this symbol will be mapped to the location specified - by the opd entry. */ - struct bfd_link_order *lo; - for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next) - if (lo->type == bfd_indirect_link_order) - { - asection *isec = lo->u.indirect.section; - if (h_elf->root.u.def.value >= isec->output_offset - && h_elf->root.u.def.value < (isec->output_offset - + isec->size)) - { - h_elf->root.u.def.value -= isec->output_offset; - h_elf->root.u.def.section = isec; - sec = isec; - break; - } - } - } - } - h = (struct ppc_link_hash_entry *) h_elf; - - if (sec != NULL && discarded_section (sec)) - { - _bfd_clear_contents (ppc64_elf_howto_table[r_type], - input_bfd, input_section, - contents + rel->r_offset); - wrel->r_offset = rel->r_offset; - wrel->r_info = 0; - wrel->r_addend = 0; - - /* For ld -r, remove relocations in debug sections against - symbols defined in discarded sections. Not done for - non-debug to preserve relocs in .eh_frame which the - eh_frame editing code expects to be present. */ - if (bfd_link_relocatable (info) - && (input_section->flags & SEC_DEBUGGING)) - wrel--; - - continue; - } - - if (bfd_link_relocatable (info)) - goto copy_reloc; - - if (h != NULL && &h->elf == htab->elf.hgot) - { - relocation = TOCstart + htab->sec_info[input_section->id].toc_off; - sec = bfd_abs_section_ptr; - unresolved_reloc = FALSE; - } - - /* TLS optimizations. Replace instruction sequences and relocs - based on information we collected in tls_optimize. We edit - RELOCS so that --emit-relocs will output something sensible - for the final instruction stream. */ - tls_mask = 0; - tls_gd = 0; - toc_symndx = 0; - if (h != NULL) - tls_mask = h->tls_mask; - else if (local_got_ents != NULL) - { - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_ents + symtab_hdr->sh_info); - unsigned char *lgot_masks = (unsigned char *) - (local_plt + symtab_hdr->sh_info); - tls_mask = lgot_masks[r_symndx]; - } - if (tls_mask == 0 - && (r_type == R_PPC64_TLS - || r_type == R_PPC64_TLSGD - || r_type == R_PPC64_TLSLD)) - { - /* Check for toc tls entries. */ - unsigned char *toc_tls; - - if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend, - &local_syms, rel, input_bfd)) - return FALSE; - - if (toc_tls) - tls_mask = *toc_tls; - } - - /* Check that tls relocs are used with tls syms, and non-tls - relocs are used with non-tls syms. */ - if (r_symndx != STN_UNDEF - && r_type != R_PPC64_NONE - && (h == NULL - || h->elf.root.type == bfd_link_hash_defined - || h->elf.root.type == bfd_link_hash_defweak) - && (IS_PPC64_TLS_RELOC (r_type) - != (sym_type == STT_TLS - || (sym_type == STT_SECTION - && (sec->flags & SEC_THREAD_LOCAL) != 0)))) - { - if (tls_mask != 0 - && (r_type == R_PPC64_TLS - || r_type == R_PPC64_TLSGD - || r_type == R_PPC64_TLSLD)) - /* R_PPC64_TLS is OK against a symbol in the TOC. */ - ; - else - info->callbacks->einfo - (!IS_PPC64_TLS_RELOC (r_type) - /* xgettext:c-format */ - ? _("%H: %s used with TLS symbol `%T'\n") - /* xgettext:c-format */ - : _("%H: %s used with non-TLS symbol `%T'\n"), - input_bfd, input_section, rel->r_offset, - ppc64_elf_howto_table[r_type]->name, - sym_name); - } - - /* Ensure reloc mapping code below stays sane. */ - if (R_PPC64_TOC16_LO_DS != R_PPC64_TOC16_DS + 1 - || R_PPC64_TOC16_LO != R_PPC64_TOC16 + 1 - || (R_PPC64_GOT_TLSLD16 & 3) != (R_PPC64_GOT_TLSGD16 & 3) - || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TLSGD16_LO & 3) - || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TLSGD16_HI & 3) - || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TLSGD16_HA & 3) - || (R_PPC64_GOT_TLSLD16 & 3) != (R_PPC64_GOT_TPREL16_DS & 3) - || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TPREL16_LO_DS & 3) - || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TPREL16_HI & 3) - || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TPREL16_HA & 3)) - abort (); - - switch (r_type) - { - default: - break; - - case R_PPC64_LO_DS_OPT: - insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset); - if ((insn & (0x3f << 26)) != 58u << 26) - abort (); - insn += (14u << 26) - (58u << 26); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset); - r_type = R_PPC64_TOC16_LO; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - break; - - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - { - /* Check for toc tls entries. */ - unsigned char *toc_tls; - int retval; - - retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend, - &local_syms, rel, input_bfd); - if (retval == 0) - return FALSE; - - if (toc_tls) - { - tls_mask = *toc_tls; - if (r_type == R_PPC64_TOC16_DS - || r_type == R_PPC64_TOC16_LO_DS) - { - if (tls_mask != 0 - && (tls_mask & (TLS_DTPREL | TLS_TPREL)) == 0) - goto toctprel; - } - else - { - /* If we found a GD reloc pair, then we might be - doing a GD->IE transition. */ - if (retval == 2) - { - tls_gd = TLS_TPRELGD; - if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) - goto tls_ldgd_opt; - } - else if (retval == 3) - { - if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) - goto tls_ldgd_opt; - } - } - } - } - break; - - case R_PPC64_GOT_TPREL16_HI: - case R_PPC64_GOT_TPREL16_HA: - if (tls_mask != 0 - && (tls_mask & TLS_TPREL) == 0) - { - rel->r_offset -= d_offset; - bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); - r_type = R_PPC64_NONE; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC64_GOT_TPREL16_DS: - case R_PPC64_GOT_TPREL16_LO_DS: - if (tls_mask != 0 - && (tls_mask & TLS_TPREL) == 0) - { - toctprel: - insn = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - insn &= 31 << 21; - insn |= 0x3c0d0000; /* addis 0,13,0 */ - bfd_put_32 (input_bfd, insn, - contents + rel->r_offset - d_offset); - r_type = R_PPC64_TPREL16_HA; - if (toc_symndx != 0) - { - rel->r_info = ELF64_R_INFO (toc_symndx, r_type); - rel->r_addend = toc_addend; - /* We changed the symbol. Start over in order to - get h, sym, sec etc. right. */ - goto again; - } - else - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC64_TLS: - if (tls_mask != 0 - && (tls_mask & TLS_TPREL) == 0) - { - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn = _bfd_elf_ppc_at_tls_transform (insn, 13); - if (insn == 0) - abort (); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - /* Was PPC64_TLS which sits on insn boundary, now - PPC64_TPREL16_LO which is at low-order half-word. */ - rel->r_offset += d_offset; - r_type = R_PPC64_TPREL16_LO; - if (toc_symndx != 0) - { - rel->r_info = ELF64_R_INFO (toc_symndx, r_type); - rel->r_addend = toc_addend; - /* We changed the symbol. Start over in order to - get h, sym, sec etc. right. */ - goto again; - } - else - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC64_GOT_TLSGD16_HI: - case R_PPC64_GOT_TLSGD16_HA: - tls_gd = TLS_TPRELGD; - if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) - goto tls_gdld_hi; - break; - - case R_PPC64_GOT_TLSLD16_HI: - case R_PPC64_GOT_TLSLD16_HA: - if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) - { - tls_gdld_hi: - if ((tls_mask & tls_gd) != 0) - r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) - + R_PPC64_GOT_TPREL16_DS); - else - { - rel->r_offset -= d_offset; - bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); - r_type = R_PPC64_NONE; - } - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC64_GOT_TLSGD16: - case R_PPC64_GOT_TLSGD16_LO: - tls_gd = TLS_TPRELGD; - if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) - goto tls_ldgd_opt; - break; - - case R_PPC64_GOT_TLSLD16: - case R_PPC64_GOT_TLSLD16_LO: - if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) - { - unsigned int insn1, insn2; - bfd_vma offset; - - tls_ldgd_opt: - offset = (bfd_vma) -1; - /* If not using the newer R_PPC64_TLSGD/LD to mark - __tls_get_addr calls, we must trust that the call - stays with its arg setup insns, ie. that the next - reloc is the __tls_get_addr call associated with - the current reloc. Edit both insns. */ - if (input_section->has_tls_get_addr_call - && rel + 1 < relend - && branch_reloc_hash_match (input_bfd, rel + 1, - htab->tls_get_addr, - htab->tls_get_addr_fd)) - offset = rel[1].r_offset; - /* We read the low GOT_TLS (or TOC16) insn because we - need to keep the destination reg. It may be - something other than the usual r3, and moved to r3 - before the call by intervening code. */ - insn1 = bfd_get_32 (input_bfd, - contents + rel->r_offset - d_offset); - if ((tls_mask & tls_gd) != 0) - { - /* IE */ - insn1 &= (0x1f << 21) | (0x1f << 16); - insn1 |= 58 << 26; /* ld */ - insn2 = 0x7c636a14; /* add 3,3,13 */ - if (offset != (bfd_vma) -1) - rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); - if ((tls_mask & TLS_EXPLICIT) == 0) - r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) - + R_PPC64_GOT_TPREL16_DS); - else - r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - else - { - /* LE */ - insn1 &= 0x1f << 21; - insn1 |= 0x3c0d0000; /* addis r,13,0 */ - insn2 = 0x38630000; /* addi 3,3,0 */ - if (tls_gd == 0) - { - /* Was an LD reloc. */ - if (toc_symndx) - sec = local_sections[toc_symndx]; - for (r_symndx = 0; - r_symndx < symtab_hdr->sh_info; - r_symndx++) - if (local_sections[r_symndx] == sec) - break; - if (r_symndx >= symtab_hdr->sh_info) - r_symndx = STN_UNDEF; - rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != STN_UNDEF) - rel->r_addend -= (local_syms[r_symndx].st_value - + sec->output_offset - + sec->output_section->vma); - } - else if (toc_symndx != 0) - { - r_symndx = toc_symndx; - rel->r_addend = toc_addend; - } - r_type = R_PPC64_TPREL16_HA; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - if (offset != (bfd_vma) -1) - { - rel[1].r_info = ELF64_R_INFO (r_symndx, - R_PPC64_TPREL16_LO); - rel[1].r_offset = offset + d_offset; - rel[1].r_addend = rel->r_addend; - } - } - bfd_put_32 (input_bfd, insn1, - contents + rel->r_offset - d_offset); - if (offset != (bfd_vma) -1) - bfd_put_32 (input_bfd, insn2, contents + offset); - if ((tls_mask & tls_gd) == 0 - && (tls_gd == 0 || toc_symndx != 0)) - { - /* We changed the symbol. Start over in order - to get h, sym, sec etc. right. */ - goto again; - } - } - break; - - case R_PPC64_TLSGD: - if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) - { - unsigned int insn2; - bfd_vma offset = rel->r_offset; - - if ((tls_mask & TLS_TPRELGD) != 0) - { - /* IE */ - r_type = R_PPC64_NONE; - insn2 = 0x7c636a14; /* add 3,3,13 */ - } - else - { - /* LE */ - if (toc_symndx != 0) - { - r_symndx = toc_symndx; - rel->r_addend = toc_addend; - } - r_type = R_PPC64_TPREL16_LO; - rel->r_offset = offset + d_offset; - insn2 = 0x38630000; /* addi 3,3,0 */ - } - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - /* Zap the reloc on the _tls_get_addr call too. */ - BFD_ASSERT (offset == rel[1].r_offset); - rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); - bfd_put_32 (input_bfd, insn2, contents + offset); - if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0) - goto again; - } - break; - - case R_PPC64_TLSLD: - if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) - { - unsigned int insn2; - bfd_vma offset = rel->r_offset; - - if (toc_symndx) - sec = local_sections[toc_symndx]; - for (r_symndx = 0; - r_symndx < symtab_hdr->sh_info; - r_symndx++) - if (local_sections[r_symndx] == sec) - break; - if (r_symndx >= symtab_hdr->sh_info) - r_symndx = STN_UNDEF; - rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != STN_UNDEF) - rel->r_addend -= (local_syms[r_symndx].st_value - + sec->output_offset - + sec->output_section->vma); - - r_type = R_PPC64_TPREL16_LO; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - rel->r_offset = offset + d_offset; - /* Zap the reloc on the _tls_get_addr call too. */ - BFD_ASSERT (offset == rel[1].r_offset); - rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); - insn2 = 0x38630000; /* addi 3,3,0 */ - bfd_put_32 (input_bfd, insn2, contents + offset); - goto again; - } - break; - - case R_PPC64_DTPMOD64: - if (rel + 1 < relend - && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64) - && rel[1].r_offset == rel->r_offset + 8) - { - if ((tls_mask & TLS_GD) == 0) - { - rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE); - if ((tls_mask & TLS_TPRELGD) != 0) - r_type = R_PPC64_TPREL64; - else - { - bfd_put_64 (output_bfd, 1, contents + rel->r_offset); - r_type = R_PPC64_NONE; - } - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - } - else - { - if ((tls_mask & TLS_LD) == 0) - { - bfd_put_64 (output_bfd, 1, contents + rel->r_offset); - r_type = R_PPC64_NONE; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - } - break; - - case R_PPC64_TPREL64: - if ((tls_mask & TLS_TPREL) == 0) - { - r_type = R_PPC64_NONE; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - } - break; - - case R_PPC64_ENTRY: - relocation = TOCstart + htab->sec_info[input_section->id].toc_off; - if (!bfd_link_pic (info) - && !info->traditional_format - && relocation + 0x80008000 <= 0xffffffff) - { - unsigned int insn1, insn2; - - insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); - if ((insn1 & ~0xfffc) == LD_R2_0R12 - && insn2 == ADD_R2_R2_R12) - { - bfd_put_32 (input_bfd, - LIS_R2 + PPC_HA (relocation), - contents + rel->r_offset); - bfd_put_32 (input_bfd, - ADDI_R2_R2 + PPC_LO (relocation), - contents + rel->r_offset + 4); - } - } - else - { - relocation -= (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma); - if (relocation + 0x80008000 <= 0xffffffff) - { - unsigned int insn1, insn2; - - insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); - if ((insn1 & ~0xfffc) == LD_R2_0R12 - && insn2 == ADD_R2_R2_R12) - { - bfd_put_32 (input_bfd, - ADDIS_R2_R12 + PPC_HA (relocation), - contents + rel->r_offset); - bfd_put_32 (input_bfd, - ADDI_R2_R2 + PPC_LO (relocation), - contents + rel->r_offset + 4); - } - } - } - break; - - case R_PPC64_REL16_HA: - /* If we are generating a non-PIC executable, edit - . 0: addis 2,12,.TOC.-0b@ha - . addi 2,2,.TOC.-0b@l - used by ELFv2 global entry points to set up r2, to - . lis 2,.TOC.@ha - . addi 2,2,.TOC.@l - if .TOC. is in range. */ - if (!bfd_link_pic (info) - && !info->traditional_format - && !htab->opd_abi - && rel->r_addend == d_offset - && h != NULL && &h->elf == htab->elf.hgot - && rel + 1 < relend - && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO) - && rel[1].r_offset == rel->r_offset + 4 - && rel[1].r_addend == rel->r_addend + 4 - && relocation + 0x80008000 <= 0xffffffff) - { - unsigned int insn1, insn2; - bfd_vma offset = rel->r_offset - d_offset; - insn1 = bfd_get_32 (input_bfd, contents + offset); - insn2 = bfd_get_32 (input_bfd, contents + offset + 4); - if ((insn1 & 0xffff0000) == ADDIS_R2_R12 - && (insn2 & 0xffff0000) == ADDI_R2_R2) - { - r_type = R_PPC64_ADDR16_HA; - rel->r_info = ELF64_R_INFO (r_symndx, r_type); - rel->r_addend -= d_offset; - rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO); - rel[1].r_addend -= d_offset + 4; - bfd_put_32 (input_bfd, LIS_R2, contents + offset); - } - } - break; - } - - /* Handle other relocations that tweak non-addend part of insn. */ - insn = 0; - max_br_offset = 1 << 25; - addend = rel->r_addend; - reloc_dest = DEST_NORMAL; - switch (r_type) - { - default: - break; - - case R_PPC64_TOCSAVE: - if (relocation + addend == (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma) - && tocsave_find (htab, NO_INSERT, - &local_syms, rel, input_bfd)) - { - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if (insn == NOP - || insn == CROR_151515 || insn == CROR_313131) - bfd_put_32 (input_bfd, - STD_R2_0R1 + STK_TOC (htab), - contents + rel->r_offset); - } - break; - - /* Branch taken prediction relocations. */ - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_REL14_BRTAKEN: - insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */ - /* Fall through. */ - - /* Branch not taken prediction relocations. */ - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_REL14_BRNTAKEN: - insn |= bfd_get_32 (input_bfd, - contents + rel->r_offset) & ~(0x01 << 21); - /* Fall through. */ - - case R_PPC64_REL14: - max_br_offset = 1 << 15; - /* Fall through. */ - - case R_PPC64_REL24: - /* Calls to functions with a different TOC, such as calls to - shared objects, need to alter the TOC pointer. This is - done using a linkage stub. A REL24 branching to these - linkage stubs needs to be followed by a nop, as the nop - will be replaced with an instruction to restore the TOC - base pointer. */ - fdh = h; - if (h != NULL - && h->oh != NULL - && h->oh->is_func_descriptor) - fdh = ppc_follow_link (h->oh); - stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel, - htab); - if (stub_entry != NULL - && (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save - || stub_entry->stub_type == ppc_stub_plt_branch_r2off - || stub_entry->stub_type == ppc_stub_long_branch_r2off)) - { - bfd_boolean can_plt_call = FALSE; - - if (stub_entry->stub_type == ppc_stub_plt_call - && !htab->opd_abi - && htab->params->plt_localentry0 != 0 - && is_elfv2_localentry0 (&h->elf)) - { - /* The function doesn't use or change r2. */ - can_plt_call = TRUE; - } - - /* All of these stubs may modify r2, so there must be a - branch and link followed by a nop. The nop is - replaced by an insn to restore r2. */ - else if (rel->r_offset + 8 <= input_section->size) - { - unsigned long br; - - br = bfd_get_32 (input_bfd, - contents + rel->r_offset); - if ((br & 1) != 0) - { - unsigned long nop; - - nop = bfd_get_32 (input_bfd, - contents + rel->r_offset + 4); - if (nop == NOP - || nop == CROR_151515 || nop == CROR_313131) - { - if (h != NULL - && (h == htab->tls_get_addr_fd - || h == htab->tls_get_addr) - && htab->params->tls_get_addr_opt) - { - /* Special stub used, leave nop alone. */ - } - else - bfd_put_32 (input_bfd, - LD_R2_0R1 + STK_TOC (htab), - contents + rel->r_offset + 4); - can_plt_call = TRUE; - } - } - } - - if (!can_plt_call && h != NULL) - { - const char *name = h->elf.root.root.string; - - if (*name == '.') - ++name; - - if (strncmp (name, "__libc_start_main", 17) == 0 - && (name[17] == 0 || name[17] == '@')) - { - /* Allow crt1 branch to go via a toc adjusting - stub. Other calls that never return could do - the same, if we could detect such. */ - can_plt_call = TRUE; - } - } - - if (!can_plt_call) - { - /* g++ as of 20130507 emits self-calls without a - following nop. This is arguably wrong since we - have conflicting information. On the one hand a - global symbol and on the other a local call - sequence, but don't error for this special case. - It isn't possible to cheaply verify we have - exactly such a call. Allow all calls to the same - section. */ - asection *code_sec = sec; - - if (get_opd_info (sec) != NULL) - { - bfd_vma off = (relocation + addend - - sec->output_section->vma - - sec->output_offset); - - opd_entry_value (sec, off, &code_sec, NULL, FALSE); - } - if (code_sec == input_section) - can_plt_call = TRUE; - } - - if (!can_plt_call) - { - if (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: call to `%T' lacks nop, can't restore toc; " - "recompile with -fPIC\n"), - input_bfd, input_section, rel->r_offset, sym_name); - else - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: call to `%T' lacks nop, can't restore toc; " - "(-mcmodel=small toc adjust stub)\n"), - input_bfd, input_section, rel->r_offset, sym_name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - } - - if (can_plt_call - && (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save)) - unresolved_reloc = FALSE; - } - - if ((stub_entry == NULL - || stub_entry->stub_type == ppc_stub_long_branch - || stub_entry->stub_type == ppc_stub_plt_branch) - && get_opd_info (sec) != NULL) - { - /* The branch destination is the value of the opd entry. */ - bfd_vma off = (relocation + addend - - sec->output_section->vma - - sec->output_offset); - bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE); - if (dest != (bfd_vma) -1) - { - relocation = dest; - addend = 0; - reloc_dest = DEST_OPD; - } - } - - /* If the branch is out of reach we ought to have a long - branch stub. */ - from = (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma); - - relocation += PPC64_LOCAL_ENTRY_OFFSET (fdh - ? fdh->elf.other - : sym->st_other); - - if (stub_entry != NULL - && (stub_entry->stub_type == ppc_stub_long_branch - || stub_entry->stub_type == ppc_stub_plt_branch) - && (r_type == R_PPC64_ADDR14_BRTAKEN - || r_type == R_PPC64_ADDR14_BRNTAKEN - || (relocation + addend - from + max_br_offset - < 2 * max_br_offset))) - /* Don't use the stub if this branch is in range. */ - stub_entry = NULL; - - if (stub_entry != NULL) - { - /* Munge up the value and addend so that we call the stub - rather than the procedure directly. */ - asection *stub_sec = stub_entry->group->stub_sec; - - if (stub_entry->stub_type == ppc_stub_save_res) - relocation += (stub_sec->output_offset - + stub_sec->output_section->vma - + stub_sec->size - htab->sfpr->size - - htab->sfpr->output_offset - - htab->sfpr->output_section->vma); - else - relocation = (stub_entry->stub_offset - + stub_sec->output_offset - + stub_sec->output_section->vma); - addend = 0; - reloc_dest = DEST_STUB; - - if ((stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - && (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - && rel + 1 < relend - && rel[1].r_offset == rel->r_offset + 4 - && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE) - relocation += 4; - } - - if (insn != 0) - { - if (is_isa_v2) - { - /* Set 'a' bit. This is 0b00010 in BO field for branch - on CR(BI) insns (BO == 001at or 011at), and 0b01000 - for branch on CTR insns (BO == 1a00t or 1a01t). */ - if ((insn & (0x14 << 21)) == (0x04 << 21)) - insn |= 0x02 << 21; - else if ((insn & (0x14 << 21)) == (0x10 << 21)) - insn |= 0x08 << 21; - else - break; - } - else - { - /* Invert 'y' bit if not the default. */ - if ((bfd_signed_vma) (relocation + addend - from) < 0) - insn ^= 0x01 << 21; - } - - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - } - - /* NOP out calls to undefined weak functions. - We can thus call a weak function without first - checking whether the function is defined. */ - else if (h != NULL - && h->elf.root.type == bfd_link_hash_undefweak - && h->elf.dynindx == -1 - && r_type == R_PPC64_REL24 - && relocation == 0 - && addend == 0) - { - bfd_put_32 (input_bfd, NOP, contents + rel->r_offset); - goto copy_reloc; - } - break; - } - - /* Set `addend'. */ - tls_type = 0; - switch (r_type) - { - default: - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: unknown relocation type %d for `%T'\n"), - input_bfd, (int) r_type, sym_name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - goto copy_reloc; - - case R_PPC64_NONE: - case R_PPC64_TLS: - case R_PPC64_TLSGD: - case R_PPC64_TLSLD: - case R_PPC64_TOCSAVE: - case R_PPC64_GNU_VTINHERIT: - case R_PPC64_GNU_VTENTRY: - case R_PPC64_ENTRY: - goto copy_reloc; - - /* GOT16 relocations. Like an ADDR16 using the symbol's - address in the GOT as relocation value instead of the - symbol's value itself. Also, create a GOT entry for the - symbol and put the symbol value there. */ - case R_PPC64_GOT_TLSGD16: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TLSGD16_HI: - case R_PPC64_GOT_TLSGD16_HA: - tls_type = TLS_TLS | TLS_GD; - goto dogot; - - case R_PPC64_GOT_TLSLD16: - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSLD16_HI: - case R_PPC64_GOT_TLSLD16_HA: - tls_type = TLS_TLS | TLS_LD; - goto dogot; - - case R_PPC64_GOT_TPREL16_DS: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_TPREL16_HI: - case R_PPC64_GOT_TPREL16_HA: - tls_type = TLS_TLS | TLS_TPREL; - goto dogot; - - case R_PPC64_GOT_DTPREL16_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_HI: - case R_PPC64_GOT_DTPREL16_HA: - tls_type = TLS_TLS | TLS_DTPREL; - goto dogot; - - case R_PPC64_GOT16: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_HI: - case R_PPC64_GOT16_HA: - case R_PPC64_GOT16_DS: - case R_PPC64_GOT16_LO_DS: - dogot: - { - /* Relocation is to the entry for this symbol in the global - offset table. */ - asection *got; - bfd_vma *offp; - bfd_vma off; - unsigned long indx = 0; - struct got_entry *ent; - - if (tls_type == (TLS_TLS | TLS_LD) - && (h == NULL - || !h->elf.def_dynamic)) - ent = ppc64_tlsld_got (input_bfd); - else - { - if (h != NULL) - { - if (!htab->elf.dynamic_sections_created - || h->elf.dynindx == -1 - || SYMBOL_REFERENCES_LOCAL (info, &h->elf) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)) - /* 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. */ - ; - else - { - indx = h->elf.dynindx; - unresolved_reloc = FALSE; - } - ent = h->elf.got.glist; - } - else - { - if (local_got_ents == NULL) - abort (); - ent = local_got_ents[r_symndx]; - } - - for (; ent != NULL; ent = ent->next) - if (ent->addend == orig_rel.r_addend - && ent->owner == input_bfd - && ent->tls_type == tls_type) - break; - } - - if (ent == NULL) - abort (); - if (ent->is_indirect) - ent = ent->got.ent; - offp = &ent->got.offset; - got = ppc64_elf_tdata (ent->owner)->got; - if (got == NULL) - abort (); - - /* The offset must always be a multiple of 8. We use the - least significant bit to record whether we have already - processed this entry. */ - off = *offp; - if ((off & 1) != 0) - off &= ~1; - else - { - /* Generate relocs for the dynamic linker, except in - the case of TLSLD where we'll use one entry per - module. */ - asection *relgot; - bfd_boolean ifunc; - - *offp = off | 1; - relgot = NULL; - ifunc = (h != NULL - ? h->elf.type == STT_GNU_IFUNC - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); - if (ifunc) - { - relgot = htab->elf.irelplt; - if (indx == 0) - htab->local_ifunc_resolver = 1; - else if (is_static_defined (&h->elf)) - htab->maybe_local_ifunc_resolver = 1; - } - else if (indx != 0 - || (bfd_link_pic (info) - && (h == NULL - || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf) - || (tls_type == (TLS_TLS | TLS_LD) - && !h->elf.def_dynamic)) - && !(tls_type == (TLS_TLS | TLS_TPREL) - && bfd_link_executable (info) - && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))) - relgot = ppc64_elf_tdata (ent->owner)->relgot; - if (relgot != NULL) - { - outrel.r_offset = (got->output_section->vma - + got->output_offset - + off); - outrel.r_addend = addend; - if (tls_type & (TLS_LD | TLS_GD)) - { - outrel.r_addend = 0; - outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64); - if (tls_type == (TLS_TLS | TLS_GD)) - { - loc = relgot->contents; - loc += (relgot->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (output_bfd, - &outrel, loc); - outrel.r_offset += 8; - outrel.r_addend = addend; - outrel.r_info - = ELF64_R_INFO (indx, R_PPC64_DTPREL64); - } - } - else if (tls_type == (TLS_TLS | TLS_DTPREL)) - outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64); - else if (tls_type == (TLS_TLS | TLS_TPREL)) - outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64); - else if (indx != 0) - outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT); - else - { - if (ifunc) - outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); - else - outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - - /* Write the .got section contents for the sake - of prelink. */ - loc = got->contents + off; - bfd_put_64 (output_bfd, outrel.r_addend + relocation, - loc); - } - - if (indx == 0 && tls_type != (TLS_TLS | TLS_LD)) - { - outrel.r_addend += relocation; - if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - { - if (htab->elf.tls_sec == NULL) - outrel.r_addend = 0; - else - outrel.r_addend -= htab->elf.tls_sec->vma; - } - } - loc = relgot->contents; - loc += (relgot->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - } - - /* Init the .got section contents here if we're not - emitting a reloc. */ - else - { - relocation += addend; - if (tls_type != 0) - { - if (htab->elf.tls_sec == NULL) - relocation = 0; - else - { - if (tls_type & TLS_LD) - relocation = 0; - else - relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; - if (tls_type & TLS_TPREL) - relocation += DTP_OFFSET - TP_OFFSET; - } - - if (tls_type & (TLS_GD | TLS_LD)) - { - bfd_put_64 (output_bfd, relocation, - got->contents + off + 8); - relocation = 1; - } - } - bfd_put_64 (output_bfd, relocation, - got->contents + off); - } - } - - if (off >= (bfd_vma) -2) - abort (); - - relocation = got->output_section->vma + got->output_offset + off; - addend = -(TOCstart + htab->sec_info[input_section->id].toc_off); - } - break; - - case R_PPC64_PLT16_HA: - case R_PPC64_PLT16_HI: - case R_PPC64_PLT16_LO: - case R_PPC64_PLT32: - case R_PPC64_PLT64: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - { - struct plt_entry **plt_list = NULL; - if (h != NULL) - plt_list = &h->elf.plt.plist; - else if (local_got_ents != NULL) - { - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_ents + symtab_hdr->sh_info); - unsigned char *local_got_tls_masks = (unsigned char *) - (local_plt + symtab_hdr->sh_info); - if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) - plt_list = local_plt + r_symndx; - } - if (plt_list) - { - struct plt_entry *ent; - - for (ent = *plt_list; ent != NULL; ent = ent->next) - if (ent->plt.offset != (bfd_vma) -1 - && ent->addend == orig_rel.r_addend) - { - asection *plt; - - plt = htab->elf.splt; - if (!htab->elf.dynamic_sections_created - || h == NULL - || h->elf.dynindx == -1) - plt = htab->elf.iplt; - relocation = (plt->output_section->vma - + plt->output_offset - + ent->plt.offset); - addend = 0; - unresolved_reloc = FALSE; - break; - } - } - } - break; - - case R_PPC64_TOC: - /* Relocation value is TOC base. */ - relocation = TOCstart; - if (r_symndx == STN_UNDEF) - relocation += htab->sec_info[input_section->id].toc_off; - else if (unresolved_reloc) - ; - else if (sec != NULL && sec->id < htab->sec_info_arr_size) - relocation += htab->sec_info[sec->id].toc_off; - else - unresolved_reloc = TRUE; - goto dodyn; - - /* TOC16 relocs. We want the offset relative to the TOC base, - which is the address of the start of the TOC plus 0x8000. - The TOC consists of sections .got, .toc, .tocbss, and .plt, - in this order. */ - case R_PPC64_TOC16: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_HI: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - case R_PPC64_TOC16_HA: - addend -= TOCstart + htab->sec_info[input_section->id].toc_off; - break; - - /* Relocate against the beginning of the section. */ - case R_PPC64_SECTOFF: - case R_PPC64_SECTOFF_LO: - case R_PPC64_SECTOFF_HI: - case R_PPC64_SECTOFF_DS: - case R_PPC64_SECTOFF_LO_DS: - case R_PPC64_SECTOFF_HA: - if (sec != NULL) - addend -= sec->output_section->vma; - break; - - case R_PPC64_REL16: - case R_PPC64_REL16_LO: - case R_PPC64_REL16_HI: - case R_PPC64_REL16_HA: - case R_PPC64_REL16DX_HA: - break; - - case R_PPC64_REL14: - case R_PPC64_REL14_BRNTAKEN: - case R_PPC64_REL14_BRTAKEN: - case R_PPC64_REL24: - break; - - case R_PPC64_TPREL16: - case R_PPC64_TPREL16_LO: - case R_PPC64_TPREL16_HI: - case R_PPC64_TPREL16_HA: - case R_PPC64_TPREL16_DS: - case R_PPC64_TPREL16_LO_DS: - case R_PPC64_TPREL16_HIGH: - case R_PPC64_TPREL16_HIGHA: - case R_PPC64_TPREL16_HIGHER: - case R_PPC64_TPREL16_HIGHERA: - case R_PPC64_TPREL16_HIGHEST: - case R_PPC64_TPREL16_HIGHESTA: - if (h != NULL - && h->elf.root.type == bfd_link_hash_undefweak - && h->elf.dynindx == -1) - { - /* Make this relocation against an undefined weak symbol - resolve to zero. This is really just a tweak, since - code using weak externs ought to check that they are - defined before using them. */ - bfd_byte *p = contents + rel->r_offset - d_offset; - - insn = bfd_get_32 (input_bfd, p); - insn = _bfd_elf_ppc_at_tprel_transform (insn, 13); - if (insn != 0) - bfd_put_32 (input_bfd, insn, p); - break; - } - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + TP_OFFSET; - /* The TPREL16 relocs shouldn't really be used in shared - libs or with non-local symbols as that will result in - DT_TEXTREL being set, but support them anyway. */ - goto dodyn; - - case R_PPC64_DTPREL16: - case R_PPC64_DTPREL16_LO: - case R_PPC64_DTPREL16_HI: - case R_PPC64_DTPREL16_HA: - case R_PPC64_DTPREL16_DS: - case R_PPC64_DTPREL16_LO_DS: - case R_PPC64_DTPREL16_HIGH: - case R_PPC64_DTPREL16_HIGHA: - case R_PPC64_DTPREL16_HIGHER: - case R_PPC64_DTPREL16_HIGHERA: - case R_PPC64_DTPREL16_HIGHEST: - case R_PPC64_DTPREL16_HIGHESTA: - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; - break; - - case R_PPC64_ADDR64_LOCAL: - addend += PPC64_LOCAL_ENTRY_OFFSET (h != NULL - ? h->elf.other - : sym->st_other); - break; - - case R_PPC64_DTPMOD64: - relocation = 1; - addend = 0; - goto dodyn; - - case R_PPC64_TPREL64: - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + TP_OFFSET; - goto dodyn; - - case R_PPC64_DTPREL64: - if (htab->elf.tls_sec != NULL) - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; - /* Fall through. */ - - /* Relocations that may need to be propagated if this is a - dynamic object. */ - case R_PPC64_REL30: - case R_PPC64_REL32: - case R_PPC64_REL64: - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_ADDR16: - case R_PPC64_ADDR16_DS: - case R_PPC64_ADDR16_HA: - case R_PPC64_ADDR16_HI: - case R_PPC64_ADDR16_HIGH: - case R_PPC64_ADDR16_HIGHA: - case R_PPC64_ADDR16_HIGHER: - case R_PPC64_ADDR16_HIGHERA: - case R_PPC64_ADDR16_HIGHEST: - case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_ADDR16_LO: - case R_PPC64_ADDR16_LO_DS: - case R_PPC64_ADDR24: - case R_PPC64_ADDR32: - case R_PPC64_ADDR64: - case R_PPC64_UADDR16: - case R_PPC64_UADDR32: - case R_PPC64_UADDR64: - dodyn: - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - if (NO_OPD_RELOCS && is_opd) - break; - - if (bfd_link_pic (info) - ? ((h == NULL - || h->dyn_relocs != NULL) - && ((h != NULL && pc_dynrelocs (h)) - || must_be_dyn_reloc (info, r_type))) - : (h != NULL - ? h->dyn_relocs != NULL - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) - { - bfd_boolean skip, relocate; - asection *sreloc; - bfd_vma out_off; - long indx = 0; - - /* When generating a dynamic object, these relocations - are copied into the output file to be resolved at run - time. */ - - skip = FALSE; - relocate = FALSE; - - out_off = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - if (out_off == (bfd_vma) -1) - skip = TRUE; - else if (out_off == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; - out_off += (input_section->output_section->vma - + input_section->output_offset); - outrel.r_offset = out_off; - outrel.r_addend = rel->r_addend; - - /* Optimize unaligned reloc use. */ - if ((r_type == R_PPC64_ADDR64 && (out_off & 7) != 0) - || (r_type == R_PPC64_UADDR64 && (out_off & 7) == 0)) - r_type ^= R_PPC64_ADDR64 ^ R_PPC64_UADDR64; - else if ((r_type == R_PPC64_ADDR32 && (out_off & 3) != 0) - || (r_type == R_PPC64_UADDR32 && (out_off & 3) == 0)) - r_type ^= R_PPC64_ADDR32 ^ R_PPC64_UADDR32; - else if ((r_type == R_PPC64_ADDR16 && (out_off & 1) != 0) - || (r_type == R_PPC64_UADDR16 && (out_off & 1) == 0)) - r_type ^= R_PPC64_ADDR16 ^ R_PPC64_UADDR16; - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf) - && !is_opd - && r_type != R_PPC64_TOC) - { - indx = h->elf.dynindx; - BFD_ASSERT (indx != -1); - outrel.r_info = ELF64_R_INFO (indx, r_type); - } - else - { - /* This symbol is local, or marked to become local, - or this is an opd section reloc which must point - at a local function. */ - outrel.r_addend += relocation; - if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC) - { - if (is_opd && h != NULL) - { - /* Lie about opd entries. This case occurs - when building shared libraries and we - reference a function in another shared - lib. The same thing happens for a weak - definition in an application that's - overridden by a strong definition in a - shared lib. (I believe this is a generic - bug in binutils handling of weak syms.) - In these cases we won't use the opd - entry in this lib. */ - unresolved_reloc = FALSE; - } - if (!is_opd - && r_type == R_PPC64_ADDR64 - && (h != NULL - ? h->elf.type == STT_GNU_IFUNC - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) - outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); - else - { - outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - - /* We need to relocate .opd contents for ld.so. - Prelink also wants simple and consistent rules - for relocs. This make all RELATIVE relocs have - *r_offset equal to r_addend. */ - relocate = TRUE; - } - } - else - { - if (h != NULL - ? h->elf.type == STT_GNU_IFUNC - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s for indirect " - "function `%T' unsupported\n"), - input_bfd, input_section, rel->r_offset, - ppc64_elf_howto_table[r_type]->name, - sym_name); - ret = FALSE; - } - else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) - ; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - asection *osec; - - osec = sec->output_section; - indx = elf_section_data (osec)->dynindx; - - if (indx == 0) - { - if ((osec->flags & SEC_READONLY) == 0 - && htab->elf.data_index_section != NULL) - osec = htab->elf.data_index_section; - else - osec = htab->elf.text_index_section; - indx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (indx != 0); - - /* We are turning this relocation into one - against a section symbol, so subtract out - the output section's address but not the - offset of the input section in the output - section. */ - outrel.r_addend -= osec->vma; - } - - outrel.r_info = ELF64_R_INFO (indx, r_type); - } - } - - sreloc = elf_section_data (input_section)->sreloc; - if (h != NULL - ? h->elf.type == STT_GNU_IFUNC - : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - sreloc = htab->elf.irelplt; - if (indx == 0) - htab->local_ifunc_resolver = 1; - else if (is_static_defined (&h->elf)) - htab->maybe_local_ifunc_resolver = 1; - } - if (sreloc == NULL) - abort (); - - if (sreloc->reloc_count * sizeof (Elf64_External_Rela) - >= sreloc->size) - 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, it will - be computed at runtime, so there's no need to do - anything now. However, for the sake of prelink ensure - that the section contents are a known value. */ - if (! relocate) - { - unresolved_reloc = FALSE; - /* The value chosen here is quite arbitrary as ld.so - ignores section contents except for the special - case of .opd where the contents might be accessed - before relocation. Choose zero, as that won't - cause reloc overflow. */ - relocation = 0; - addend = 0; - /* Use *r_offset == r_addend for R_PPC64_ADDR64 relocs - to improve backward compatibility with older - versions of ld. */ - if (r_type == R_PPC64_ADDR64) - addend = outrel.r_addend; - /* Adjust pc_relative relocs to have zero in *r_offset. */ - else if (ppc64_elf_howto_table[r_type]->pc_relative) - addend = outrel.r_offset; - } - } - break; - - case R_PPC64_COPY: - case R_PPC64_GLOB_DAT: - case R_PPC64_JMP_SLOT: - case R_PPC64_JMP_IREL: - case R_PPC64_RELATIVE: - /* We shouldn't ever see these dynamic relocs in relocatable - files. */ - /* Fall through. */ - - case R_PPC64_PLTGOT16: - case R_PPC64_PLTGOT16_DS: - case R_PPC64_PLTGOT16_HA: - case R_PPC64_PLTGOT16_HI: - case R_PPC64_PLTGOT16_LO: - case R_PPC64_PLTGOT16_LO_DS: - case R_PPC64_PLTREL32: - case R_PPC64_PLTREL64: - /* These ones haven't been implemented yet. */ - - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: %B: %s is not supported for `%T'\n"), - input_bfd, - ppc64_elf_howto_table[r_type]->name, sym_name); - - bfd_set_error (bfd_error_invalid_operation); - ret = FALSE; - goto copy_reloc; - } - - /* Multi-instruction sequences that access the TOC can be - optimized, eg. addis ra,r2,0; addi rb,ra,x; - to nop; addi rb,r2,x; */ - howto = ppc64_elf_howto_table[(int) r_type]; - switch (r_type) - { - default: - break; - - case R_PPC64_GOT_TLSLD16_HI: - case R_PPC64_GOT_TLSGD16_HI: - case R_PPC64_GOT_TPREL16_HI: - case R_PPC64_GOT_DTPREL16_HI: - case R_PPC64_GOT16_HI: - case R_PPC64_TOC16_HI: - /* These relocs would only be useful if building up an - offset to later add to r2, perhaps in an indexed - addressing mode instruction. Don't try to optimize. - Unfortunately, the possibility of someone building up an - offset like this or even with the HA relocs, means that - we need to check the high insn when optimizing the low - insn. */ - break; - - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: - case R_PPC64_GOT16_HA: - case R_PPC64_TOC16_HA: - if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000 - && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn) - { - bfd_byte *p = contents + (rel->r_offset & ~3); - bfd_put_32 (input_bfd, NOP, p); - } - break; - - case R_PPC64_GOT_TLSLD16_LO: - case R_PPC64_GOT_TLSGD16_LO: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_GOT16_LO: - case R_PPC64_GOT16_LO_DS: - case R_PPC64_TOC16_LO: - case R_PPC64_TOC16_LO_DS: - if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000 - && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn) - { - bfd_byte *p = contents + (rel->r_offset & ~3); - insn = bfd_get_32 (input_bfd, p); - if ((insn & (0x3f << 26)) == 12u << 26 /* addic */) - { - /* Transform addic to addi when we change reg. */ - insn &= ~((0x3f << 26) | (0x1f << 16)); - insn |= (14u << 26) | (2 << 16); - } - else - { - insn &= ~(0x1f << 16); - insn |= 2 << 16; - } - bfd_put_32 (input_bfd, insn, p); - } - break; - - case R_PPC64_TPREL16_HA: - if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) - { - bfd_byte *p = contents + (rel->r_offset & ~3); - insn = bfd_get_32 (input_bfd, p); - if ((insn & ((0x3f << 26) | 0x1f << 16)) - != ((15u << 26) | (13 << 16)) /* addis rt,13,imm */) - /* xgettext:c-format */ - info->callbacks->minfo - (_("%H: warning: %s unexpected insn %#x.\n"), - input_bfd, input_section, rel->r_offset, howto->name, insn); - else - bfd_put_32 (input_bfd, NOP, p); - } - break; - - case R_PPC64_TPREL16_LO: - case R_PPC64_TPREL16_LO_DS: - if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000) - { - bfd_byte *p = contents + (rel->r_offset & ~3); - insn = bfd_get_32 (input_bfd, p); - insn &= ~(0x1f << 16); - insn |= 13 << 16; - bfd_put_32 (input_bfd, insn, p); - } - break; - } - - /* Do any further special processing. */ - switch (r_type) - { - default: - break; - - case R_PPC64_REL16_HA: - case R_PPC64_REL16DX_HA: - case R_PPC64_ADDR16_HA: - case R_PPC64_ADDR16_HIGHA: - case R_PPC64_ADDR16_HIGHERA: - case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_TOC16_HA: - case R_PPC64_SECTOFF_HA: - case R_PPC64_TPREL16_HA: - case R_PPC64_TPREL16_HIGHA: - case R_PPC64_TPREL16_HIGHERA: - case R_PPC64_TPREL16_HIGHESTA: - case R_PPC64_DTPREL16_HA: - case R_PPC64_DTPREL16_HIGHA: - case R_PPC64_DTPREL16_HIGHERA: - case R_PPC64_DTPREL16_HIGHESTA: - /* It's just possible that this symbol is a weak symbol - that's not actually defined anywhere. In that case, - 'sec' would be NULL, and we should leave the symbol - alone (it will be set to zero elsewhere in the link). */ - if (sec == NULL) - break; - /* Fall through. */ - - case R_PPC64_GOT16_HA: - case R_PPC64_PLTGOT16_HA: - case R_PPC64_PLT16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: - /* Add 0x10000 if sign bit in 0:15 is set. - Bits 0:15 are not used. */ - addend += 0x8000; - break; - - case R_PPC64_ADDR16_DS: - case R_PPC64_ADDR16_LO_DS: - case R_PPC64_GOT16_DS: - case R_PPC64_GOT16_LO_DS: - case R_PPC64_PLT16_LO_DS: - case R_PPC64_SECTOFF_DS: - case R_PPC64_SECTOFF_LO_DS: - case R_PPC64_TOC16_DS: - case R_PPC64_TOC16_LO_DS: - case R_PPC64_PLTGOT16_DS: - case R_PPC64_PLTGOT16_LO_DS: - case R_PPC64_GOT_TPREL16_DS: - case R_PPC64_GOT_TPREL16_LO_DS: - case R_PPC64_GOT_DTPREL16_DS: - case R_PPC64_GOT_DTPREL16_LO_DS: - case R_PPC64_TPREL16_DS: - case R_PPC64_TPREL16_LO_DS: - case R_PPC64_DTPREL16_DS: - case R_PPC64_DTPREL16_LO_DS: - insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - mask = 3; - /* If this reloc is against an lq, lxv, or stxv insn, then - the value must be a multiple of 16. This is somewhat of - a hack, but the "correct" way to do this by defining _DQ - forms of all the _DS relocs bloats all reloc switches in - this file. It doesn't make much sense to use these - relocs in data, so testing the insn should be safe. */ - if ((insn & (0x3f << 26)) == (56u << 26) - || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1)) - mask = 15; - relocation += addend; - addend = insn & (mask ^ 3); - if ((relocation & mask) != 0) - { - relocation ^= relocation & mask; - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: error: %s not a multiple of %u\n"), - input_bfd, input_section, rel->r_offset, - howto->name, - mask + 1); - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - goto copy_reloc; - } - break; - } - - /* Dynamic relocs are not propagated for SEC_DEBUGGING sections - because such sections are not SEC_ALLOC and thus ld.so will - not process them. */ - if (unresolved_reloc - && !((input_section->flags & SEC_DEBUGGING) != 0 - && h->elf.def_dynamic) - && _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: unresolvable %s against `%T'\n"), - input_bfd, input_section, rel->r_offset, - howto->name, - h->elf.root.root.string); - ret = FALSE; - } - - /* 16-bit fields in insns mostly have signed values, but a - few insns have 16-bit unsigned values. Really, we should - have different reloc types. */ - if (howto->complain_on_overflow != complain_overflow_dont - && howto->dst_mask == 0xffff - && (input_section->flags & SEC_CODE) != 0) - { - enum complain_overflow complain = complain_overflow_signed; - - insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) - complain = complain_overflow_bitfield; - else if (howto->rightshift == 0 - ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */ - || (insn & (0x3f << 26)) == 24u << 26 /* ori */ - || (insn & (0x3f << 26)) == 26u << 26 /* xori */) - : ((insn & (0x3f << 26)) == 29u << 26 /* andis */ - || (insn & (0x3f << 26)) == 25u << 26 /* oris */ - || (insn & (0x3f << 26)) == 27u << 26 /* xoris */)) - complain = complain_overflow_unsigned; - if (howto->complain_on_overflow != complain) - { - alt_howto = *howto; - alt_howto.complain_on_overflow = complain; - howto = &alt_howto; - } - } - - if (r_type == R_PPC64_REL16DX_HA) - { - /* Split field reloc isn't handled by _bfd_final_link_relocate. */ - if (rel->r_offset + 4 > input_section->size) - r = bfd_reloc_outofrange; - else - { - relocation += addend; - relocation -= (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma); - relocation = (bfd_signed_vma) relocation >> 16; - insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn &= ~0x1fffc1; - insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); - bfd_put_32 (input_bfd, insn, contents + rel->r_offset); - r = bfd_reloc_ok; - if (relocation + 0x8000 > 0xffff) - r = bfd_reloc_overflow; - } - } - else - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, relocation, addend); - - if (r != bfd_reloc_ok) - { - char *more_info = NULL; - const char *reloc_name = howto->name; - - if (reloc_dest != DEST_NORMAL) - { - more_info = bfd_malloc (strlen (reloc_name) + 8); - if (more_info != NULL) - { - strcpy (more_info, reloc_name); - strcat (more_info, (reloc_dest == DEST_OPD - ? " (OPD)" : " (stub)")); - reloc_name = more_info; - } - } - - if (r == bfd_reloc_overflow) - { - /* On code like "if (foo) foo();" don't report overflow - on a branch to zero when foo is undefined. */ - if (!warned - && (reloc_dest == DEST_STUB - || !(h != NULL - && (h->elf.root.type == bfd_link_hash_undefweak - || h->elf.root.type == bfd_link_hash_undefined) - && is_branch_reloc (r_type)))) - info->callbacks->reloc_overflow (info, &h->elf.root, - sym_name, reloc_name, - orig_rel.r_addend, - input_bfd, input_section, - rel->r_offset); - } - else - { - info->callbacks->einfo - /* xgettext:c-format */ - (_("%H: %s against `%T': error %d\n"), - input_bfd, input_section, rel->r_offset, - reloc_name, sym_name, (int) r); - ret = FALSE; - } - if (more_info != NULL) - free (more_info); - } - copy_reloc: - if (wrel != rel) - *wrel = *rel; - } - - if (wrel != rel) - { - Elf_Internal_Shdr *rel_hdr; - size_t deleted = rel - wrel; - - rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - if (rel_hdr->sh_size == 0) - { - /* It is too late to remove an empty reloc section. Leave - one NONE reloc. - ??? What is wrong with an empty section??? */ - rel_hdr->sh_size = rel_hdr->sh_entsize; - deleted -= 1; - } - rel_hdr = _bfd_elf_single_rel_hdr (input_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - input_section->reloc_count -= deleted; - } - - /* If we're emitting relocations, then shortly after this function - returns, reloc offsets and addends for this section will be - adjusted. Worse, reloc symbol indices will be for the output - file rather than the input. Save a copy of the relocs for - opd_entry_value. */ - if (is_opd && (info->emitrelocations || bfd_link_relocatable (info))) - { - bfd_size_type amt; - amt = input_section->reloc_count * sizeof (Elf_Internal_Rela); - rel = bfd_alloc (input_bfd, amt); - BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd.relocs == NULL); - ppc64_elf_tdata (input_bfd)->opd.relocs = rel; - if (rel == NULL) - return FALSE; - memcpy (rel, relocs, amt); - } - return ret; -} - -/* Adjust the value of any local symbols in opd sections. */ - -static int -ppc64_elf_output_symbol_hook (struct bfd_link_info *info, - const char *name ATTRIBUTE_UNUSED, - Elf_Internal_Sym *elfsym, - asection *input_sec, - struct elf_link_hash_entry *h) -{ - struct _opd_sec_data *opd; - long adjust; - bfd_vma value; - - if (h != NULL) - return 1; - - opd = get_opd_info (input_sec); - if (opd == NULL || opd->adjust == NULL) - return 1; - - value = elfsym->st_value - input_sec->output_offset; - if (!bfd_link_relocatable (info)) - value -= input_sec->output_section->vma; - - adjust = opd->adjust[OPD_NDX (value)]; - if (adjust == -1) - return 2; - - elfsym->st_value += adjust; - return 1; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct ppc_link_hash_table *htab; - struct plt_entry *ent; - Elf_Internal_Rela rela; - bfd_byte *loc; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - for (ent = h->plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.offset != (bfd_vma) -1) - { - /* This symbol has an entry in the procedure linkage - table. Set it up. */ - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - BFD_ASSERT (h->type == STT_GNU_IFUNC - && h->def_regular - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - rela.r_offset = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + ent->plt.offset); - if (htab->opd_abi) - rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); - else - rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_offset - + h->root.u.def.section->output_section->vma - + ent->addend); - loc = (htab->elf.irelplt->contents - + (htab->elf.irelplt->reloc_count++ - * sizeof (Elf64_External_Rela))); - htab->local_ifunc_resolver = 1; - } - else - { - rela.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset); - rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT); - rela.r_addend = ent->addend; - loc = (htab->elf.srelplt->contents - + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab)) - / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); - if (h->type == STT_GNU_IFUNC && is_static_defined (h)) - htab->maybe_local_ifunc_resolver = 1; - } - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - - if (!htab->opd_abi) - { - if (!h->def_regular) - { - /* Mark the symbol as undefined, rather than as - defined in glink. 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. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; - else if (!h->ref_regular_nonweak) - { - /* This breaks function pointer comparisons, but - that is better than breaking tests for a NULL - function pointer. */ - sym->st_value = 0; - } - } - } - } - - if (h->needs_copy) - { - /* This symbol needs a copy reloc. Set it up. */ - asection *srel; - - if (h->dynindx == -1 - || (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - || htab->elf.srelbss == NULL - || htab->elf.sreldynrelro == 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_PPC64_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - srel = htab->elf.sreldynrelro; - else - srel = htab->elf.srelbss; - loc = srel->contents; - loc += srel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - } - - 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 -ppc64_elf_reloc_type_class (const struct bfd_link_info *info, - const asection *rel_sec, - const Elf_Internal_Rela *rela) -{ - enum elf_ppc64_reloc_type r_type; - struct ppc_link_hash_table *htab = ppc_hash_table (info); - - if (rel_sec == htab->elf.irelplt) - return reloc_class_ifunc; - - r_type = ELF64_R_TYPE (rela->r_info); - switch (r_type) - { - case R_PPC64_RELATIVE: - return reloc_class_relative; - case R_PPC64_JMP_SLOT: - return reloc_class_plt; - case R_PPC64_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -ppc64_elf_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct ppc_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->elf.dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->elf.dynamic_sections_created) - { - Elf64_External_Dyn *dyncon, *dynconend; - - if (sdyn == NULL || htab->elf.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_PPC64_GLINK: - s = htab->glink; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - /* We stupidly defined DT_PPC64_GLINK to be the start - of glink rather than the first entry point, which is - what ld.so needs, and now have a bigger stub to - support automatic multiple TOCs. */ - dyn.d_un.d_ptr += GLINK_PLTRESOLVE_SIZE (htab) - 8 * 4; - break; - - case DT_PPC64_OPD: - s = bfd_get_section_by_name (output_bfd, ".opd"); - if (s == NULL) - continue; - dyn.d_un.d_ptr = s->vma; - break; - - case DT_PPC64_OPT: - if (htab->do_multi_toc && htab->multi_toc_needed) - dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC; - if (htab->has_plt_localentry0) - dyn.d_un.d_val |= PPC64_OPT_LOCALENTRY; - break; - - case DT_PPC64_OPDSZ: - s = bfd_get_section_by_name (output_bfd, ".opd"); - if (s == NULL) - continue; - dyn.d_un.d_val = s->size; - break; - - case DT_PLTGOT: - s = htab->elf.splt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_JMPREL: - s = htab->elf.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = htab->elf.srelplt->size; - break; - - case DT_TEXTREL: - if (htab->local_ifunc_resolver) - info->callbacks->einfo - (_("%X%P: text relocations and GNU indirect " - "functions will result in a segfault at runtime\n")); - else if (htab->maybe_local_ifunc_resolver) - info->callbacks->einfo - (_("%P: warning: text relocations and GNU indirect " - "functions may result in a segfault at runtime\n")); - continue; - } - - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - - if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0 - && htab->elf.sgot->output_section != bfd_abs_section_ptr) - { - /* Fill in the first entry in the global offset table. - We use it to hold the link-time TOCbase. */ - bfd_put_64 (output_bfd, - elf_gp (output_bfd) + TOC_BASE_OFF, - htab->elf.sgot->contents); - - /* Set .got entry size. */ - elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8; - } - - if (htab->elf.splt != NULL && htab->elf.splt->size != 0 - && htab->elf.splt->output_section != bfd_abs_section_ptr) - { - /* Set .plt entry size. */ - elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE (htab); - } - - /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for - brlt ourselves if emitrelocations. */ - if (htab->brlt != NULL - && htab->brlt->reloc_count != 0 - && !_bfd_elf_link_output_relocs (output_bfd, - htab->brlt, - elf_section_data (htab->brlt)->rela.hdr, - elf_section_data (htab->brlt)->relocs, - NULL)) - return FALSE; - - if (htab->glink != NULL - && htab->glink->reloc_count != 0 - && !_bfd_elf_link_output_relocs (output_bfd, - htab->glink, - elf_section_data (htab->glink)->rela.hdr, - elf_section_data (htab->glink)->relocs, - NULL)) - return FALSE; - - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->size != 0) - { - bfd_vma val; - bfd_byte *p; - struct map_stub *group; - size_t align = 4; - - p = htab->glink_eh_frame->contents; - p += (sizeof (glink_eh_frame_cie) + align - 1) & -align; - - for (group = htab->group; group != NULL; group = group->next) - if (group->stub_sec != NULL) - { - /* Offset to stub section. */ - val = (group->stub_sec->output_section->vma - + group->stub_sec->output_offset); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset - + (p + 8 - htab->glink_eh_frame->contents)); - if (val + 0x80000000 > 0xffffffff) - { - info->callbacks->einfo - (_("%P: %s offset too large for .eh_frame sdata4 encoding"), - group->stub_sec->name); - return FALSE; - } - bfd_put_32 (dynobj, val, p + 8); - p += stub_eh_frame_size (group, align); - } - if (htab->glink != NULL && htab->glink->size != 0) - { - /* Offset to .glink. */ - val = (htab->glink->output_section->vma - + htab->glink->output_offset - + 8); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset - + (p + 8 - htab->glink_eh_frame->contents)); - if (val + 0x80000000 > 0xffffffff) - { - info->callbacks->einfo - (_("%P: %s offset too large for .eh_frame sdata4 encoding"), - htab->glink->name); - return FALSE; - } - bfd_put_32 (dynobj, val, p + 8); - p += (24 + align - 1) & -align; - } - - if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME - && !_bfd_elf_write_section_eh_frame (output_bfd, info, - htab->glink_eh_frame, - htab->glink_eh_frame->contents)) - return FALSE; - } - - /* We need to handle writing out multiple GOT sections ourselves, - since we didn't add them to DYNOBJ. We know dynobj is the first - bfd. */ - while ((dynobj = dynobj->link.next) != NULL) - { - asection *s; - - if (!is_ppc64_elf (dynobj)) - continue; - - s = ppc64_elf_tdata (dynobj)->got; - if (s != NULL - && s->size != 0 - && s->output_section != bfd_abs_section_ptr - && !bfd_set_section_contents (output_bfd, s->output_section, - s->contents, s->output_offset, - s->size)) - return FALSE; - s = ppc64_elf_tdata (dynobj)->relgot; - if (s != NULL - && s->size != 0 - && s->output_section != bfd_abs_section_ptr - && !bfd_set_section_contents (output_bfd, s->output_section, - s->contents, s->output_offset, - s->size)) - return FALSE; - } - - return TRUE; -} - -#include "elf64-target.h" - -/* FreeBSD support */ - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM powerpc_elf64_fbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-powerpc-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf64_bed -#define elf64_bed elf64_powerpc_fbsd_bed - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-ppc.h b/sdcc/support/sdbinutils/bfd/elf64-ppc.h deleted file mode 100644 index b3d4d599e..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-ppc.h +++ /dev/null @@ -1,102 +0,0 @@ -/* PowerPC64-specific support for 64-bit ELF. - Copyright (C) 2002-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -/* Used to pass info between ld and bfd. */ -struct ppc64_elf_params -{ - /* Linker stub bfd. */ - bfd *stub_bfd; - - /* Linker call-backs. */ - asection * (*add_stub_section) (const char *, asection *); - void (*layout_sections_again) (void); - - /* Maximum size of a group of input sections that can be handled by - one stub section. A value of +/-1 indicates the bfd back-end - should use a suitable default size. */ - bfd_signed_vma group_size; - - /* Whether to use a special call stub for __tls_get_addr. */ - int tls_get_addr_opt; - - /* Whether to allow multiple toc sections. */ - int no_multi_toc; - - /* Set if PLT call stubs should load r11. */ - int plt_static_chain; - - /* Set if PLT call stubs need to be thread safe on power7+. */ - int plt_thread_safe; - - /* Set if individual PLT call stubs should be aligned. */ - int plt_stub_align; - - /* Set if PLT call stubs for localentry:0 functions should omit r2 save. */ - int plt_localentry0; - - /* Clear if PLT call stubs should use a speculative execution barrier. */ - int speculate_indirect_jumps; - - /* Whether to canonicalize .opd so that there are no overlapping - .opd entries. */ - int non_overlapping_opd; - - /* Whether to emit symbols for stubs. */ - int emit_stub_syms; - - /* Whether to generate out-of-line register save/restore for gcc -Os code. */ - int save_restore_funcs; - - /* Set when a potential variable is detected in .toc. */ - int object_in_toc; -}; - -bfd_boolean ppc64_elf_init_stub_bfd - (struct bfd_link_info *, struct ppc64_elf_params *); -bfd_boolean ppc64_elf_edit_opd - (struct bfd_link_info *); -asection *ppc64_elf_tls_setup - (struct bfd_link_info *); -bfd_boolean ppc64_elf_tls_optimize - (struct bfd_link_info *); -bfd_boolean ppc64_elf_edit_toc - (struct bfd_link_info *); -bfd_boolean ppc64_elf_has_small_toc_reloc - (asection *); -bfd_vma ppc64_elf_set_toc - (struct bfd_link_info *, bfd *); -int ppc64_elf_setup_section_lists - (struct bfd_link_info *); -void ppc64_elf_start_multitoc_partition - (struct bfd_link_info *); -bfd_boolean ppc64_elf_next_toc_section - (struct bfd_link_info *, asection *); -bfd_boolean ppc64_elf_layout_multitoc - (struct bfd_link_info *); -void ppc64_elf_finish_multitoc_partition - (struct bfd_link_info *); -bfd_boolean ppc64_elf_check_init_fini - (struct bfd_link_info *); -bfd_boolean ppc64_elf_next_input_section - (struct bfd_link_info *, asection *); -bfd_boolean ppc64_elf_size_stubs -(struct bfd_link_info *); -bfd_boolean ppc64_elf_build_stubs - (struct bfd_link_info *, char **); diff --git a/sdcc/support/sdbinutils/bfd/elf64-s390.c b/sdcc/support/sdbinutils/bfd/elf64-s390.c deleted file mode 100644 index 754997146..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-s390.c +++ /dev/null @@ -1,3965 +0,0 @@ -/* IBM S/390-specific support for 64-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - Contributed Martin Schwidefsky (schwidefsky@de.ibm.com). - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/s390.h" -#include "elf-s390.h" -#include - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -static bfd_reloc_status_type -s390_tls_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); -static bfd_reloc_status_type -s390_elf_ldisp_reloc (bfd *, arelent *, asymbol *, void *, - asection *, bfd *, char **); - -/* The relocation "howto" table. */ -static reloc_howto_type elf_howto_table[] = -{ - HOWTO (R_390_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = 2 byte, 2 = 4 byte) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_390_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO(R_390_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_8", FALSE, 0,0x000000ff, FALSE), - HOWTO(R_390_12, 0, 1, 12, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_390_12", FALSE, 0,0x00000fff, FALSE), - HOWTO(R_390_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_PC32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC32", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_GOT12, 0, 1, 12, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT12", FALSE, 0,0x00000fff, FALSE), - HOWTO(R_390_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_PLT32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT32", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_COPY, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_COPY", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_GLOB_DAT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GLOB_DAT", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_JMP_SLOT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_JMP_SLOT", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_RELATIVE, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_RELATIVE", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_GOTOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTOFF32", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_GOTPC, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPC", FALSE, 0,MINUS_ONE, TRUE), - HOWTO(R_390_GOT16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_PC16, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC16", FALSE, 0,0x0000ffff, TRUE), - HOWTO(R_390_PC16DBL, 1, 1, 16, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC16DBL", FALSE, 0,0x0000ffff, TRUE), - HOWTO(R_390_PLT16DBL, 1, 1, 16, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT16DBL", FALSE, 0,0x0000ffff, TRUE), - HOWTO(R_390_PC32DBL, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC32DBL", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_PLT32DBL, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT32DBL", FALSE, 0,0xffffffff, TRUE), - HOWTO(R_390_GOTPCDBL, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPCDBL", FALSE, 0,MINUS_ONE, TRUE), - HOWTO(R_390_64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_64", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_PC64, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC64", FALSE, 0,MINUS_ONE, TRUE), - HOWTO(R_390_GOT64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOT64", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_PLT64, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT64", FALSE, 0,MINUS_ONE, TRUE), - HOWTO(R_390_GOTENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTENT", FALSE, 0,MINUS_ONE, TRUE), - HOWTO(R_390_GOTOFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTOFF16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_GOTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTOFF64", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_GOTPLT12, 0, 1, 12, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_390_GOTPLT12", FALSE, 0,0x00000fff, FALSE), - HOWTO(R_390_GOTPLT16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLT16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_GOTPLT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLT32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_GOTPLT64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLT64", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_GOTPLTENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_GOTPLTENT",FALSE, 0,MINUS_ONE, TRUE), - HOWTO(R_390_PLTOFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLTOFF16", FALSE, 0,0x0000ffff, FALSE), - HOWTO(R_390_PLTOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLTOFF32", FALSE, 0,0xffffffff, FALSE), - HOWTO(R_390_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLTOFF64", FALSE, 0,MINUS_ONE, FALSE), - HOWTO(R_390_TLS_LOAD, 0, 0, 0, FALSE, 0, complain_overflow_dont, - s390_tls_reloc, "R_390_TLS_LOAD", FALSE, 0, 0, FALSE), - HOWTO(R_390_TLS_GDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - s390_tls_reloc, "R_390_TLS_GDCALL", FALSE, 0, 0, FALSE), - HOWTO(R_390_TLS_LDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, - s390_tls_reloc, "R_390_TLS_LDCALL", FALSE, 0, 0, FALSE), - EMPTY_HOWTO (R_390_TLS_GD32), /* Empty entry for R_390_TLS_GD32. */ - HOWTO(R_390_TLS_GD64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_GD64", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_TLS_GOTIE12, 0, 1, 12, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_390_TLS_GOTIE12", FALSE, 0, 0x00000fff, FALSE), - EMPTY_HOWTO (R_390_TLS_GOTIE32), /* Empty entry for R_390_TLS_GOTIE32. */ - HOWTO(R_390_TLS_GOTIE64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_GOTIE64", FALSE, 0, MINUS_ONE, FALSE), - EMPTY_HOWTO (R_390_TLS_LDM32), /* Empty entry for R_390_TLS_LDM32. */ - HOWTO(R_390_TLS_LDM64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_LDM64", FALSE, 0, MINUS_ONE, FALSE), - EMPTY_HOWTO (R_390_TLS_IE32), /* Empty entry for R_390_TLS_IE32. */ - HOWTO(R_390_TLS_IE64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_IE64", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_TLS_IEENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_IEENT", FALSE, 0, MINUS_ONE, TRUE), - EMPTY_HOWTO (R_390_TLS_LE32), /* Empty entry for R_390_TLS_LE32. */ - HOWTO(R_390_TLS_LE64, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_LE64", FALSE, 0, MINUS_ONE, FALSE), - EMPTY_HOWTO (R_390_TLS_LDO32), /* Empty entry for R_390_TLS_LDO32. */ - HOWTO(R_390_TLS_LDO64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_LDO64", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_TLS_DTPMOD, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_DTPMOD", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_TLS_DTPOFF, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_DTPOFF", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_TLS_TPOFF, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_TLS_TPOFF", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_GOT20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_GOT20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_GOTPLT20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_GOTPLT20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_TLS_GOTIE20, 0, 2, 20, FALSE, 8, complain_overflow_dont, - s390_elf_ldisp_reloc, "R_390_TLS_GOTIE20", FALSE, 0,0x0fffff00, FALSE), - HOWTO(R_390_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_IRELATIVE", FALSE, 0, MINUS_ONE, FALSE), - HOWTO(R_390_PC12DBL, 1, 1, 12, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC12DBL", FALSE, 0,0x00000fff, TRUE), - HOWTO(R_390_PLT12DBL, 1, 1, 12, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT12DBL", FALSE, 0,0x00000fff, TRUE), - HOWTO(R_390_PC24DBL, 1, 2, 24, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PC24DBL", FALSE, 0,0x00ffffff, TRUE), - HOWTO(R_390_PLT24DBL, 1, 2, 24, TRUE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_390_PLT24DBL", FALSE, 0,0x00ffffff, TRUE), -}; - -/* GNU extension to record C++ vtable hierarchy. */ -static reloc_howto_type elf64_s390_vtinherit_howto = - HOWTO (R_390_GNU_VTINHERIT, 0,4,0,FALSE,0,complain_overflow_dont, NULL, "R_390_GNU_VTINHERIT", FALSE,0, 0, FALSE); -static reloc_howto_type elf64_s390_vtentry_howto = - HOWTO (R_390_GNU_VTENTRY, 0,4,0,FALSE,0,complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_390_GNU_VTENTRY", FALSE,0,0, FALSE); - -static reloc_howto_type * -elf_s390_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - switch (code) - { - case BFD_RELOC_NONE: - return &elf_howto_table[(int) R_390_NONE]; - case BFD_RELOC_8: - return &elf_howto_table[(int) R_390_8]; - case BFD_RELOC_390_12: - return &elf_howto_table[(int) R_390_12]; - case BFD_RELOC_16: - return &elf_howto_table[(int) R_390_16]; - case BFD_RELOC_32: - return &elf_howto_table[(int) R_390_32]; - case BFD_RELOC_CTOR: - return &elf_howto_table[(int) R_390_32]; - case BFD_RELOC_32_PCREL: - return &elf_howto_table[(int) R_390_PC32]; - case BFD_RELOC_390_GOT12: - return &elf_howto_table[(int) R_390_GOT12]; - case BFD_RELOC_32_GOT_PCREL: - return &elf_howto_table[(int) R_390_GOT32]; - case BFD_RELOC_390_PLT32: - return &elf_howto_table[(int) R_390_PLT32]; - case BFD_RELOC_390_COPY: - return &elf_howto_table[(int) R_390_COPY]; - case BFD_RELOC_390_GLOB_DAT: - return &elf_howto_table[(int) R_390_GLOB_DAT]; - case BFD_RELOC_390_JMP_SLOT: - return &elf_howto_table[(int) R_390_JMP_SLOT]; - case BFD_RELOC_390_RELATIVE: - return &elf_howto_table[(int) R_390_RELATIVE]; - case BFD_RELOC_32_GOTOFF: - return &elf_howto_table[(int) R_390_GOTOFF32]; - case BFD_RELOC_390_GOTPC: - return &elf_howto_table[(int) R_390_GOTPC]; - case BFD_RELOC_390_GOT16: - return &elf_howto_table[(int) R_390_GOT16]; - case BFD_RELOC_16_PCREL: - return &elf_howto_table[(int) R_390_PC16]; - case BFD_RELOC_390_PC12DBL: - return &elf_howto_table[(int) R_390_PC12DBL]; - case BFD_RELOC_390_PLT12DBL: - return &elf_howto_table[(int) R_390_PLT12DBL]; - case BFD_RELOC_390_PC16DBL: - return &elf_howto_table[(int) R_390_PC16DBL]; - case BFD_RELOC_390_PLT16DBL: - return &elf_howto_table[(int) R_390_PLT16DBL]; - case BFD_RELOC_390_PC24DBL: - return &elf_howto_table[(int) R_390_PC24DBL]; - case BFD_RELOC_390_PLT24DBL: - return &elf_howto_table[(int) R_390_PLT24DBL]; - case BFD_RELOC_390_PC32DBL: - return &elf_howto_table[(int) R_390_PC32DBL]; - case BFD_RELOC_390_PLT32DBL: - return &elf_howto_table[(int) R_390_PLT32DBL]; - case BFD_RELOC_390_GOTPCDBL: - return &elf_howto_table[(int) R_390_GOTPCDBL]; - case BFD_RELOC_64: - return &elf_howto_table[(int) R_390_64]; - case BFD_RELOC_64_PCREL: - return &elf_howto_table[(int) R_390_PC64]; - case BFD_RELOC_390_GOT64: - return &elf_howto_table[(int) R_390_GOT64]; - case BFD_RELOC_390_PLT64: - return &elf_howto_table[(int) R_390_PLT64]; - case BFD_RELOC_390_GOTENT: - return &elf_howto_table[(int) R_390_GOTENT]; - case BFD_RELOC_16_GOTOFF: - return &elf_howto_table[(int) R_390_GOTOFF16]; - case BFD_RELOC_390_GOTOFF64: - return &elf_howto_table[(int) R_390_GOTOFF64]; - case BFD_RELOC_390_GOTPLT12: - return &elf_howto_table[(int) R_390_GOTPLT12]; - case BFD_RELOC_390_GOTPLT16: - return &elf_howto_table[(int) R_390_GOTPLT16]; - case BFD_RELOC_390_GOTPLT32: - return &elf_howto_table[(int) R_390_GOTPLT32]; - case BFD_RELOC_390_GOTPLT64: - return &elf_howto_table[(int) R_390_GOTPLT64]; - case BFD_RELOC_390_GOTPLTENT: - return &elf_howto_table[(int) R_390_GOTPLTENT]; - case BFD_RELOC_390_PLTOFF16: - return &elf_howto_table[(int) R_390_PLTOFF16]; - case BFD_RELOC_390_PLTOFF32: - return &elf_howto_table[(int) R_390_PLTOFF32]; - case BFD_RELOC_390_PLTOFF64: - return &elf_howto_table[(int) R_390_PLTOFF64]; - case BFD_RELOC_390_TLS_LOAD: - return &elf_howto_table[(int) R_390_TLS_LOAD]; - case BFD_RELOC_390_TLS_GDCALL: - return &elf_howto_table[(int) R_390_TLS_GDCALL]; - case BFD_RELOC_390_TLS_LDCALL: - return &elf_howto_table[(int) R_390_TLS_LDCALL]; - case BFD_RELOC_390_TLS_GD64: - return &elf_howto_table[(int) R_390_TLS_GD64]; - case BFD_RELOC_390_TLS_GOTIE12: - return &elf_howto_table[(int) R_390_TLS_GOTIE12]; - case BFD_RELOC_390_TLS_GOTIE64: - return &elf_howto_table[(int) R_390_TLS_GOTIE64]; - case BFD_RELOC_390_TLS_LDM64: - return &elf_howto_table[(int) R_390_TLS_LDM64]; - case BFD_RELOC_390_TLS_IE64: - return &elf_howto_table[(int) R_390_TLS_IE64]; - case BFD_RELOC_390_TLS_IEENT: - return &elf_howto_table[(int) R_390_TLS_IEENT]; - case BFD_RELOC_390_TLS_LE64: - return &elf_howto_table[(int) R_390_TLS_LE64]; - case BFD_RELOC_390_TLS_LDO64: - return &elf_howto_table[(int) R_390_TLS_LDO64]; - case BFD_RELOC_390_TLS_DTPMOD: - return &elf_howto_table[(int) R_390_TLS_DTPMOD]; - case BFD_RELOC_390_TLS_DTPOFF: - return &elf_howto_table[(int) R_390_TLS_DTPOFF]; - case BFD_RELOC_390_TLS_TPOFF: - return &elf_howto_table[(int) R_390_TLS_TPOFF]; - case BFD_RELOC_390_20: - return &elf_howto_table[(int) R_390_20]; - case BFD_RELOC_390_GOT20: - return &elf_howto_table[(int) R_390_GOT20]; - case BFD_RELOC_390_GOTPLT20: - return &elf_howto_table[(int) R_390_GOTPLT20]; - case BFD_RELOC_390_TLS_GOTIE20: - return &elf_howto_table[(int) R_390_TLS_GOTIE20]; - case BFD_RELOC_390_IRELATIVE: - return &elf_howto_table[(int) R_390_IRELATIVE]; - case BFD_RELOC_VTABLE_INHERIT: - return &elf64_s390_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &elf64_s390_vtentry_howto; - default: - break; - } - return 0; -} - -static reloc_howto_type * -elf_s390_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); - i++) - if (elf_howto_table[i].name != NULL - && strcasecmp (elf_howto_table[i].name, r_name) == 0) - return &elf_howto_table[i]; - - if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0) - return &elf64_s390_vtinherit_howto; - if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0) - return &elf64_s390_vtentry_howto; - - return NULL; -} - -/* We need to use ELF64_R_TYPE so we have our own copy of this function, - and elf64-s390.c has its own copy. */ - -static void -elf_s390_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r_type = ELF64_R_TYPE(dst->r_info); - switch (r_type) - { - case R_390_GNU_VTINHERIT: - cache_ptr->howto = &elf64_s390_vtinherit_howto; - break; - - case R_390_GNU_VTENTRY: - cache_ptr->howto = &elf64_s390_vtentry_howto; - break; - - default: - if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0])) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: invalid relocation type %d"), - abfd, (int) r_type); - r_type = R_390_NONE; - } - cache_ptr->howto = &elf_howto_table[r_type]; - } -} - -/* A relocation function which doesn't do anything. */ -static bfd_reloc_status_type -s390_tls_reloc (bfd *abfd ATTRIBUTE_UNUSED, - arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void * data ATTRIBUTE_UNUSED, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -/* Handle the large displacement relocs. */ -static bfd_reloc_status_type -s390_elf_ldisp_reloc (bfd *abfd, - arelent *reloc_entry, - asymbol *symbol, - void * data, - asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - reloc_howto_type *howto = reloc_entry->howto; - bfd_vma relocation; - bfd_vma insn; - - if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (! howto->partial_inplace - || reloc_entry->addend == 0)) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - if (output_bfd != NULL) - return bfd_reloc_continue; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - relocation = (symbol->value - + symbol->section->output_section->vma - + symbol->section->output_offset); - relocation += reloc_entry->addend; - if (howto->pc_relative) - { - relocation -= (input_section->output_section->vma - + input_section->output_offset); - relocation -= reloc_entry->address; - } - - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - insn |= (relocation & 0xfff) << 16 | (relocation & 0xff000) >> 4; - bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); - - if ((bfd_signed_vma) relocation < - 0x80000 - || (bfd_signed_vma) relocation > 0x7ffff) - return bfd_reloc_overflow; - else - return bfd_reloc_ok; -} - -static bfd_boolean -elf_s390_is_local_label_name (bfd *abfd, const char *name) -{ - if (name[0] == '.' && (name[1] == 'X' || name[1] == 'L')) - return TRUE; - - return _bfd_elf_is_local_label_name (abfd, name); -} - -/* Functions for the 390 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 the first entry in the procedure linkage table. */ -#define PLT_FIRST_ENTRY_SIZE 32 -/* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE 32 - -#define GOT_ENTRY_SIZE 8 - -#define RELA_ENTRY_SIZE sizeof (Elf64_External_Rela) - -/* The first three entries in a procedure linkage table are reserved, - and the initial contents are unimportant (we zero them out). - Subsequent entries look like this. See the SVR4 ABI 386 - supplement to see how this works. */ - -/* For the s390, simple addr offset can only be 0 - 4096. - To use the full 16777216 TB address space, several instructions - are needed to load an address in a register and execute - a branch( or just saving the address) - - Furthermore, only r 0 and 1 are free to use!!! */ - -/* The first 3 words in the GOT are then reserved. - Word 0 is the address of the dynamic table. - Word 1 is a pointer to a structure describing the object - Word 2 is used to point to the loader entry address. - - The code for PLT entries looks like this: - - The GOT holds the address in the PLT to be executed. - The loader then gets: - 48(15) = Pointer to the structure describing the object. - 56(15) = Offset in symbol table - The loader must then find the module where the function is - and insert the address in the GOT. - - PLT1: LARL 1,@GOTENT # 6 bytes Load address of GOT entry in r1 - LG 1,0(1) # 6 bytes Load address from GOT in r1 - BCR 15,1 # 2 bytes Jump to address - RET1: BASR 1,0 # 2 bytes Return from GOT 1st time - LGF 1,12(1) # 6 bytes Load offset in symbl table in r1 - BRCL 15,-x # 6 bytes Jump to start of PLT - .long ? # 4 bytes offset into .rela.plt - - Total = 32 bytes per PLT entry - Fixup at offset 2: relative address to GOT entry - Fixup at offset 22: relative branch to PLT0 - Fixup at offset 28: 32 bit offset into .rela.plt - - A 32 bit offset into the symbol table is enough. It allows for - .rela.plt sections up to a size of 2 gigabyte. A single dynamic - object (the main program, any shared library) is limited to 4GB in - size. Having a .rela.plt of 2GB would already make the .plt - section bigger than 8GB. */ - -static const bfd_byte elf_s390x_plt_entry[PLT_ENTRY_SIZE] = - { - 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, /* larl %r1,. */ - 0xe3, 0x10, 0x10, 0x00, 0x00, 0x04, /* lg %r1,0(%r1) */ - 0x07, 0xf1, /* br %r1 */ - 0x0d, 0x10, /* basr %r1,%r0 */ - 0xe3, 0x10, 0x10, 0x0c, 0x00, 0x14, /* lgf %r1,12(%r1) */ - 0xc0, 0xf4, 0x00, 0x00, 0x00, 0x00, /* jg first plt */ - 0x00, 0x00, 0x00, 0x00 /* .long 0x00000000 */ - }; - -/* The first PLT entry pushes the offset into the symbol table - from R1 onto the stack at 56(15) and the loader object info - at 48(15), loads the loader address in R1 and jumps to it. */ - -/* The first entry in the PLT: - - PLT0: - STG 1,56(15) # r1 contains the offset into the symbol table - LARL 1,_GLOBAL_OFFSET_TABLE # load address of global offset table - MVC 48(8,15),8(1) # move loader ino (object struct address) to stack - LG 1,16(1) # get entry address of loader - BCR 15,1 # jump to loader - - Fixup at offset 8: relative address to start of GOT. */ - -static const bfd_byte elf_s390x_first_plt_entry[PLT_FIRST_ENTRY_SIZE] = - { - 0xe3, 0x10, 0xf0, 0x38, 0x00, 0x24, /* stg %r1,56(%r15) */ - 0xc0, 0x10, 0x00, 0x00, 0x00, 0x00, /* larl %r1,. */ - 0xd2, 0x07, 0xf0, 0x30, 0x10, 0x08, /* mvc 48(8,%r15),8(%r1) */ - 0xe3, 0x10, 0x10, 0x10, 0x00, 0x04, /* lg %r1,16(%r1) */ - 0x07, 0xf1, /* br %r1 */ - 0x07, 0x00, /* nopr %r0 */ - 0x07, 0x00, /* nopr %r0 */ - 0x07, 0x00 /* nopr %r0 */ - }; - - -/* s390 ELF linker hash entry. */ - -struct elf_s390_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - - /* Number of GOTPLT references for a function. */ - bfd_signed_vma gotplt_refcount; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 -#define GOT_TLS_IE 3 -#define GOT_TLS_IE_NLT 3 - unsigned char tls_type; - - /* For pointer equality reasons we might need to change the symbol - type from STT_GNU_IFUNC to STT_FUNC together with its value and - section entry. So after alloc_dynrelocs only these values should - be used. In order to check whether a symbol is IFUNC use - s390_is_ifunc_symbol_p. */ - bfd_vma ifunc_resolver_address; - asection *ifunc_resolver_section; -}; - -#define elf_s390_hash_entry(ent) \ - ((struct elf_s390_link_hash_entry *)(ent)) - -/* This structure represents an entry in the local PLT list needed for - local IFUNC symbols. */ -struct plt_entry -{ - /* The section of the local symbol. - Set in relocate_section and used in finish_dynamic_sections. */ - asection *sec; - - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } plt; -}; - -/* NOTE: Keep this structure in sync with - the one declared in elf32-s390.c. */ -struct elf_s390_obj_tdata -{ - struct elf_obj_tdata root; - - /* A local PLT is needed for ifunc symbols. */ - struct plt_entry *local_plt; - - /* TLS type for each local got entry. */ - char *local_got_tls_type; -}; - -#define elf_s390_tdata(abfd) \ - ((struct elf_s390_obj_tdata *) (abfd)->tdata.any) - -#define elf_s390_local_plt(abfd) \ - (elf_s390_tdata (abfd)->local_plt) - -#define elf_s390_local_got_tls_type(abfd) \ - (elf_s390_tdata (abfd)->local_got_tls_type) - -#define is_s390_elf(bfd) \ - (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_tdata (bfd) != NULL \ - && elf_object_id (bfd) == S390_ELF_DATA) - -static bfd_boolean -elf_s390_mkobject (bfd *abfd) -{ - return bfd_elf_allocate_object (abfd, sizeof (struct elf_s390_obj_tdata), - S390_ELF_DATA); -} - -static bfd_boolean -elf_s390_object_p (bfd *abfd) -{ - /* Set the right machine number for an s390 elf32 file. */ - return bfd_default_set_arch_mach (abfd, bfd_arch_s390, bfd_mach_s390_64); -} - -/* s390 ELF linker hash table. */ - -struct elf_s390_link_hash_table -{ - struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *irelifunc; - - union { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* Options passed from the linker. */ - struct s390_elf_params *params; -}; - -/* Get the s390 ELF linker hash table from a link_info structure. */ - -#define elf_s390_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == S390_ELF_DATA ? ((struct elf_s390_link_hash_table *) ((p)->hash)) : NULL) - -#define ELF64 1 -#include "elf-s390-common.c" - -/* Create an entry in an s390 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_s390_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_s390_link_hash_entry *eh; - - eh = (struct elf_s390_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - eh->gotplt_refcount = 0; - eh->tls_type = GOT_UNKNOWN; - eh->ifunc_resolver_address = 0; - eh->ifunc_resolver_section = NULL; - } - - return entry; -} - -/* Create an s390 ELF linker hash table. */ - -static struct bfd_link_hash_table * -elf_s390_link_hash_table_create (bfd *abfd) -{ - struct elf_s390_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_s390_link_hash_table); - - ret = (struct elf_s390_link_hash_table *) bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, - sizeof (struct elf_s390_link_hash_entry), - S390_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->elf.root; -} - -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf_s390_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_s390_link_hash_entry *edir, *eind; - - edir = (struct elf_s390_link_hash_entry *) dir; - eind = (struct elf_s390_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_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_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. */ - if (dir->versioned != versioned_hidden) - 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; - } - else - _bfd_elf_link_hash_copy_indirect (info, dir, ind); -} - -static int -elf_s390_tls_transition (struct bfd_link_info *info, - int r_type, - int is_local) -{ - if (bfd_link_pic (info)) - return r_type; - - switch (r_type) - { - case R_390_TLS_GD64: - case R_390_TLS_IE64: - if (is_local) - return R_390_TLS_LE64; - return R_390_TLS_IE64; - case R_390_TLS_GOTIE64: - if (is_local) - return R_390_TLS_LE64; - return R_390_TLS_GOTIE64; - case R_390_TLS_LDM64: - return R_390_TLS_LE64; - } - - return r_type; -} - -/* Look through the relocs for a section during the first phase, and - allocate space in the global offset table or procedure linkage - table. */ - -static bfd_boolean -elf_s390_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_s390_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; - bfd_signed_vma *local_got_refcounts; - int tls_type, old_tls_type; - - if (bfd_link_relocatable (info)) - return TRUE; - - BFD_ASSERT (is_s390_elf (abfd)); - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); - - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned int r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *isym; - - r_symndx = ELF64_R_SYM (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), - abfd, r_symndx); - return FALSE; - } - - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - struct plt_entry *plt; - - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - if (!s390_elf_create_ifunc_sections (htab->elf.dynobj, info)) - return FALSE; - - if (local_got_refcounts == NULL) - { - if (!elf_s390_allocate_local_syminfo (abfd, symtab_hdr)) - return FALSE; - local_got_refcounts = elf_local_got_refcounts (abfd); - } - plt = elf_s390_local_plt (abfd); - plt[r_symndx].plt.refcount++; - } - 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; - } - - /* Create got section and local_got_refcounts array if they - are needed. */ - r_type = elf_s390_tls_transition (info, - ELF64_R_TYPE (rel->r_info), - h == NULL); - switch (r_type) - { - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOT64: - case R_390_GOTENT: - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLT64: - case R_390_GOTPLTENT: - case R_390_TLS_GD64: - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_GOTIE64: - case R_390_TLS_IEENT: - case R_390_TLS_IE64: - case R_390_TLS_LDM64: - if (h == NULL - && local_got_refcounts == NULL) - { - if (!elf_s390_allocate_local_syminfo (abfd, symtab_hdr)) - return FALSE; - local_got_refcounts = elf_local_got_refcounts (abfd); - } - - /* Fall through. */ - case R_390_GOTOFF16: - case R_390_GOTOFF32: - case R_390_GOTOFF64: - case R_390_GOTPC: - case R_390_GOTPCDBL: - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } - } - - if (h != NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!s390_elf_create_ifunc_sections (htab->elf.dynobj, info)) - return FALSE; - - /* Make sure an IFUNC symbol defined in a non-shared object - always gets a PLT slot. */ - if (s390_is_ifunc_symbol_p (h) && h->def_regular) - { - /* The symbol is called by the dynamic loader in order - to resolve the relocation. So it is in fact also - referenced. */ - h->ref_regular = 1; - h->needs_plt = 1; - } - } - - switch (r_type) - { - case R_390_GOTPC: - case R_390_GOTPCDBL: - /* These relocs do not need a GOT slot. They just load the - GOT pointer itself or address something else relative to - the GOT. Since the GOT pointer has been set up above we - are done. */ - break; - case R_390_GOTOFF16: - case R_390_GOTOFF32: - case R_390_GOTOFF64: - if (h == NULL || !s390_is_ifunc_symbol_p (h) || !h->def_regular) - break; - /* Fall through. */ - - case R_390_PLT12DBL: - case R_390_PLT16DBL: - case R_390_PLT24DBL: - case R_390_PLT32: - case R_390_PLT32DBL: - case R_390_PLT64: - case R_390_PLTOFF16: - case R_390_PLTOFF32: - case R_390_PLTOFF64: - /* 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) - { - h->needs_plt = 1; - h->plt.refcount += 1; - } - break; - - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLT64: - case R_390_GOTPLTENT: - /* This symbol requires either a procedure linkage table entry - or an entry in the local got. We actually build the entry - in adjust_dynamic_symbol because whether this is really a - global reference can change and with it the fact if we have - to create a plt entry or a local got entry. To be able to - make a once global symbol a local one we have to keep track - of the number of gotplt references that exist for this - symbol. */ - if (h != NULL) - { - ((struct elf_s390_link_hash_entry *) h)->gotplt_refcount++; - h->needs_plt = 1; - h->plt.refcount += 1; - } - else - local_got_refcounts[r_symndx] += 1; - break; - - case R_390_TLS_LDM64: - htab->tls_ldm_got.refcount += 1; - break; - - case R_390_TLS_IE64: - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_GOTIE64: - case R_390_TLS_IEENT: - if (bfd_link_pic (info)) - info->flags |= DF_STATIC_TLS; - /* Fall through */ - - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOT64: - case R_390_GOTENT: - case R_390_TLS_GD64: - /* This symbol requires a global offset table entry. */ - switch (r_type) - { - default: - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOTENT: - tls_type = GOT_NORMAL; - break; - case R_390_TLS_GD64: - tls_type = GOT_TLS_GD; - break; - case R_390_TLS_IE64: - case R_390_TLS_GOTIE64: - tls_type = GOT_TLS_IE; - break; - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_IEENT: - tls_type = GOT_TLS_IE_NLT; - break; - } - - if (h != NULL) - { - h->got.refcount += 1; - old_tls_type = elf_s390_hash_entry(h)->tls_type; - } - else - { - local_got_refcounts[r_symndx] += 1; - old_tls_type = elf_s390_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) - { - if (old_tls_type == GOT_NORMAL || tls_type == GOT_NORMAL) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: `%s' accessed both as normal and thread local symbol"), - abfd, h->root.root.string); - return FALSE; - } - if (old_tls_type > tls_type) - tls_type = old_tls_type; - } - - if (old_tls_type != tls_type) - { - if (h != NULL) - elf_s390_hash_entry (h)->tls_type = tls_type; - else - elf_s390_local_got_tls_type (abfd) [r_symndx] = tls_type; - } - - if (r_type != R_390_TLS_IE64) - break; - /* Fall through */ - - case R_390_TLS_LE64: - /* For static linking and executables this reloc will be - calculated at linktime otherwise a TLS_TPOFF runtime - reloc will be generated. */ - if (r_type == R_390_TLS_LE64 && bfd_link_pie (info)) - break; - - if (!bfd_link_pic (info)) - break; - info->flags |= DF_STATIC_TLS; - /* Fall through */ - - case R_390_8: - case R_390_16: - case R_390_32: - case R_390_64: - case R_390_PC12DBL: - case R_390_PC16: - case R_390_PC16DBL: - case R_390_PC24DBL: - case R_390_PC32: - case R_390_PC32DBL: - case R_390_PC64: - if (h != NULL && bfd_link_executable (info)) - { - /* 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; - - if (!bfd_link_pic (info)) - { - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - h->plt.refcount += 1; - } - } - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). In case of a weak definition, - DEF_REGULAR may be cleared later by a strong definition in - a shared library. We account for that possibility below by - storing information in the relocs_copied field of the hash - table entry. A similar situation occurs when creating - shared libraries and symbol visibility changes render the - symbol local. - - If on the other hand, we are creating an executable, we - may need to keep relocations for symbols satisfied by a - dynamic library if we manage to avoid copy relocs for the - symbol. */ - if ((bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && ((ELF64_R_TYPE (rel->r_info) != R_390_PC16 - && ELF64_R_TYPE (rel->r_info) != R_390_PC12DBL - && ELF64_R_TYPE (rel->r_info) != R_390_PC16DBL - && ELF64_R_TYPE (rel->r_info) != R_390_PC24DBL - && ELF64_R_TYPE (rel->r_info) != R_390_PC32 - && ELF64_R_TYPE (rel->r_info) != R_390_PC32DBL - && ELF64_R_TYPE (rel->r_info) != R_390_PC64) - || (h != NULL - && (! SYMBOLIC_BIND (info, h) - || h->root.type == bfd_link_hash_defweak - || !h->def_regular)))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && h != NULL - && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) - { - struct elf_dyn_relocs *p; - struct elf_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) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - { - head = &((struct elf_s390_link_hash_entry *) h)->dyn_relocs; - } - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - asection *s; - void *vpp; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - return FALSE; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_dyn_relocs **) vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = ((struct elf_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 (ELF64_R_TYPE (rel->r_info) == R_390_PC16 - || ELF64_R_TYPE (rel->r_info) == R_390_PC12DBL - || ELF64_R_TYPE (rel->r_info) == R_390_PC16DBL - || ELF64_R_TYPE (rel->r_info) == R_390_PC16DBL - || ELF64_R_TYPE (rel->r_info) == R_390_PC32 - || ELF64_R_TYPE (rel->r_info) == R_390_PC32DBL - || ELF64_R_TYPE (rel->r_info) == R_390_PC64) - p->pc_count += 1; - } - break; - - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_390_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_390_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !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 * -elf_s390_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_390_GNU_VTINHERIT: - case R_390_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Make sure we emit a GOT entry if the symbol was supposed to have a PLT - entry but we found we will not create any. Called when we find we will - not have any PLT for this symbol, by for example - elf_s390_adjust_dynamic_symbol when we're doing a proper dynamic link, - or elf_s390_size_dynamic_sections if no dynamic sections will be - created (we're only linking static objects). */ - -static void -elf_s390_adjust_gotplt (struct elf_s390_link_hash_entry *h) -{ - if (h->elf.root.type == bfd_link_hash_warning) - h = (struct elf_s390_link_hash_entry *) h->elf.root.u.i.link; - - if (h->gotplt_refcount <= 0) - return; - - /* We simply add the number of gotplt references to the number - * of got references for this symbol. */ - h->elf.got.refcount += h->gotplt_refcount; - h->gotplt_refcount = -1; -} - -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = elf_s390_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - -/* 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_s390_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - struct elf_s390_link_hash_table *htab; - asection *s, *srel; - - /* STT_GNU_IFUNC symbol must go through PLT. */ - if (s390_is_ifunc_symbol_p (h)) - { - /* All local STT_GNU_IFUNC references must be treated as local - calls via local PLT. */ - if (h->ref_regular && SYMBOL_CALLS_LOCAL (info, h)) - { - bfd_size_type pc_count = 0, count = 0; - struct elf_dyn_relocs **pp; - struct elf_s390_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - eh = (struct elf_s390_link_hash_entry *) h; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - pc_count += p->pc_count; - p->count -= p->pc_count; - p->pc_count = 0; - count += p->count; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - - if (pc_count || count) - { - h->needs_plt = 1; - h->non_got_ref = 1; - if (h->plt.refcount <= 0) - h->plt.refcount = 1; - else - h->plt.refcount += 1; - } - } - - if (h->plt.refcount <= 0) - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - return TRUE; - } - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later - (although we could actually do it here). */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (h->plt.refcount <= 0 - || SYMBOL_CALLS_LOCAL (info, h) - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - { - /* 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; - elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h); - } - - return TRUE; - } - else - /* It's possible that we incorrectly decided a .plt reloc was - needed for an R_390_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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) - h->non_got_ref = def->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 (bfd_link_pic (info)) - 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 we don't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h)) - { - h->non_got_ref = 0; - return TRUE; - } - - /* We must allocate the symbol in our .dynbss section, which will - become part of the .bss section of the executable. There will be - an entry for this symbol in the .dynsym section. The dynamic - object will contain position independent code, so all references - from the dynamic object to this symbol will go through the global - offset table. The dynamic linker will use the .dynsym entry to - determine the address it must put in the global offset table, so - both the dynamic object and the regular object will refer to the - same memory location for the variable. */ - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - /* We must generate a R_390_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_READONLY) != 0) - { - s = htab->elf.sdynrelro; - srel = htab->elf.sreldynrelro; - } - else - { - s = htab->elf.sdynbss; - srel = htab->elf.srelbss; - } - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - srel->size += sizeof (Elf64_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, - void * inf) -{ - struct bfd_link_info *info; - struct elf_s390_link_hash_table *htab; - struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry *)h; - struct elf_dyn_relocs *p; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - info = (struct bfd_link_info *) inf; - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it - here if it is defined and referenced in a non-shared object. */ - if (s390_is_ifunc_symbol_p (h) && h->def_regular) - return s390_elf_allocate_ifunc_dyn_relocs (info, h); - else 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 (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - asection *s = htab->elf.splt; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += PLT_FIRST_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 (! bfd_link_pic (info) - && !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->elf.sgotplt->size += GOT_ENTRY_SIZE; - - /* We also need to make an entry in the .rela.plt section. */ - htab->elf.srelplt->size += sizeof (Elf64_External_Rela); - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h); - } - } - else - { - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h); - } - - /* If R_390_TLS_{IE64,GOTIE64,GOTIE12,IEENT} symbol is now local to - the binary, we can optimize a bit. IE64 and GOTIE64 get converted - to R_390_TLS_LE64 requiring no TLS entry. For GOTIE12 and IEENT - we can save the dynamic TLS relocation. */ - if (h->got.refcount > 0 - && !bfd_link_pic (info) - && h->dynindx == -1 - && elf_s390_hash_entry(h)->tls_type >= GOT_TLS_IE) - { - if (elf_s390_hash_entry(h)->tls_type == GOT_TLS_IE_NLT) - /* For the GOTIE access without a literal pool entry the offset has - to be stored somewhere. The immediate value in the instruction - is not bit enough so the value is stored in the got. */ - { - h->got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += GOT_ENTRY_SIZE; - } - else - h->got.offset = (bfd_vma) -1; - } - else if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = elf_s390_hash_entry(h)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->elf.sgot; - h->got.offset = s->size; - s->size += GOT_ENTRY_SIZE; - /* R_390_TLS_GD64 needs 2 consecutive GOT slots. */ - if (tls_type == GOT_TLS_GD) - s->size += GOT_ENTRY_SIZE; - dyn = htab->elf.dynamic_sections_created; - /* R_390_TLS_IE64 needs one dynamic relocation, - R_390_TLS_GD64 needs one if local symbol and two if global. */ - if ((tls_type == GOT_TLS_GD && h->dynindx == -1) - || tls_type >= GOT_TLS_IE) - htab->elf.srelgot->size += sizeof (Elf64_External_Rela); - else if (tls_type == GOT_TLS_GD) - htab->elf.srelgot->size += 2 * sizeof (Elf64_External_Rela); - else if (!UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->elf.srelgot->size += sizeof (Elf64_External_Rela); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_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 - || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - 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; -} - -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -elf_s390_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_s390_link_hash_table *htab; - bfd *dynobj; - asection *s; - bfd_boolean relocs; - bfd *ibfd; - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - 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 (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (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_size_type locsymcount; - Elf_Internal_Shdr *symtab_hdr; - asection *srela; - struct plt_entry *local_plt; - unsigned int i; - - if (! is_s390_elf (ibfd)) - continue; - - for (s = ibfd->sections; s != NULL; s = s->next) - { - struct elf_dyn_relocs *p; - - for (p = 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) - { - srela = elf_section_data (p->sec)->sreloc; - srela->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_symtab_hdr (ibfd); - locsymcount = symtab_hdr->sh_info; - end_local_got = local_got + locsymcount; - local_tls_type = elf_s390_local_got_tls_type (ibfd); - s = htab->elf.sgot; - srela = htab->elf.srelgot; - for (; local_got < end_local_got; ++local_got, ++local_tls_type) - { - if (*local_got > 0) - { - *local_got = s->size; - s->size += GOT_ENTRY_SIZE; - if (*local_tls_type == GOT_TLS_GD) - s->size += GOT_ENTRY_SIZE; - if (bfd_link_pic (info)) - srela->size += sizeof (Elf64_External_Rela); - } - else - *local_got = (bfd_vma) -1; - } - - local_plt = elf_s390_local_plt (ibfd); - for (i = 0; i < symtab_hdr->sh_info; i++) - { - if (local_plt[i].plt.refcount > 0) - { - local_plt[i].plt.offset = htab->elf.iplt->size; - htab->elf.iplt->size += PLT_ENTRY_SIZE; - htab->elf.igotplt->size += GOT_ENTRY_SIZE; - htab->elf.irelplt->size += sizeof (Elf64_External_Rela); - } - else - local_plt[i].plt.offset = (bfd_vma) -1; - } - } - - if (htab->tls_ldm_got.refcount > 0) - { - /* Allocate 2 got entries and 1 dynamic reloc for R_390_TLS_LDM64 - relocs. */ - htab->tls_ldm_got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += 2 * GOT_ENTRY_SIZE; - htab->elf.srelgot->size += sizeof (Elf64_External_Rela); - } - 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, info); - - /* We now have determined the sizes of the various dynamic sections. - Allocate memory for them. */ - relocs = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - if (s == htab->elf.splt - || s == htab->elf.sgot - || s == htab->elf.sgotplt - || s == htab->elf.sdynbss - || s == htab->elf.sdynrelro - || s == htab->elf.iplt - || s == htab->elf.igotplt - || s == htab->irelifunc) - { - /* Strip this section if we don't need it; see the - comment below. */ - } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) - { - if (s->size != 0 && s != htab->elf.srelplt) - relocs = TRUE; - - /* We use the reloc_count field as a counter if we need - to copy relocs into the output file. */ - s->reloc_count = 0; - } - else - { - /* It's not one of our sections, so don't allocate space. */ - continue; - } - - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is to handle .rela.bss and - .rela.plt. We must create it in - create_dynamic_sections, because it 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_390_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 elf_s390_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 (bfd_link_executable (info)) - { - if (!add_dynamic_entry (DT_DEBUG, 0)) - return FALSE; - } - - if (htab->elf.splt->size != 0) - { - if (!add_dynamic_entry (DT_PLTGOT, 0) - || !add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_RELA) - || !add_dynamic_entry (DT_JMPREL, 0)) - 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, maybe_set_textrel, info); - - if ((info->flags & DF_TEXTREL) != 0) - { - if (!add_dynamic_entry (DT_TEXTREL, 0)) - return FALSE; - } - } - } -#undef add_dynamic_entry - - return TRUE; -} - -/* Return the base VMA address which should be subtracted from real addresses - when resolving @dtpoff relocation. - This is PT_TLS segment p_vaddr. */ - -static bfd_vma -dtpoff_base (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; -} - -/* Complain if TLS instruction relocation is against an invalid - instruction. */ - -static void -invalid_tls_insn (bfd *input_bfd, - asection *input_section, - Elf_Internal_Rela *rel) -{ - reloc_howto_type *howto; - - howto = elf_howto_table + ELF64_R_TYPE (rel->r_info); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): invalid instruction for TLS relocation %s"), - input_bfd, - input_section, - rel->r_offset, - howto->name); - bfd_set_error (bfd_error_bad_value); -} - -/* Relocate a 390 ELF section. */ - -static bfd_boolean -elf_s390_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_s390_link_hash_table *htab; - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; - Elf_Internal_Rela *rel; - Elf_Internal_Rela *relend; - - BFD_ASSERT (is_s390_elf (input_bfd)); - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - unsigned int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; - asection *sec; - bfd_vma off; - bfd_vma relocation; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - int tls_type; - asection *base_got = htab->elf.sgot; - bfd_boolean resolved_to_zero; - - r_type = ELF64_R_TYPE (rel->r_info); - if (r_type == (int) R_390_GNU_VTINHERIT - || r_type == (int) R_390_GNU_VTENTRY) - continue; - if (r_type >= (int) R_390_max) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - howto = 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]; - - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - struct plt_entry *local_plt = elf_s390_local_plt (input_bfd); - if (local_plt == NULL) - return FALSE; - - /* Address of the PLT slot. */ - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + local_plt[r_symndx].plt.offset); - - switch (r_type) - { - case R_390_PLTOFF16: - case R_390_PLTOFF32: - case R_390_PLTOFF64: - relocation -= htab->elf.sgot->output_section->vma; - break; - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLT64: - case R_390_GOTPLTENT: - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOT64: - case R_390_GOTENT: - { - /* Write the PLT slot address into the GOT slot. */ - bfd_put_64 (output_bfd, relocation, - htab->elf.sgot->contents + - local_got_offsets[r_symndx]); - relocation = (local_got_offsets[r_symndx] + - htab->elf.sgot->output_offset); - - if (r_type == R_390_GOTENT || r_type == R_390_GOTPLTENT) - relocation += htab->elf.sgot->output_section->vma; - break; - } - default: - break; - } - /* The output section is needed later in - finish_dynamic_section when creating the dynamic - relocation. */ - local_plt[r_symndx].sec = sec; - goto do_relocation; - } - else - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - } - else - { - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - resolved_to_zero = (h != NULL - && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)); - - switch (r_type) - { - case R_390_GOTPLT12: - case R_390_GOTPLT16: - case R_390_GOTPLT20: - case R_390_GOTPLT32: - case R_390_GOTPLT64: - case R_390_GOTPLTENT: - /* There are three cases for a GOTPLT relocation. 1) The - relocation is against the jump slot entry of a plt that - will get emitted to the output file. 2) The relocation - is against the jump slot of a plt entry that has been - removed. elf_s390_adjust_gotplt has created a GOT entry - as replacement. 3) The relocation is against a local symbol. - Cases 2) and 3) are the same as the GOT relocation code - so we just have to test for case 1 and fall through for - the other two. */ - if (h != NULL && h->plt.offset != (bfd_vma) -1) - { - bfd_vma plt_index; - - if (s390_is_ifunc_symbol_p (h)) - { - plt_index = h->plt.offset / PLT_ENTRY_SIZE; - relocation = (plt_index * GOT_ENTRY_SIZE + - htab->elf.igotplt->output_offset); - if (r_type == R_390_GOTPLTENT) - relocation += htab->elf.igotplt->output_section->vma; - } - else - { - /* Calc. index no. - Current offset - size first entry / entry size. */ - plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) / - PLT_ENTRY_SIZE; - - /* Offset in GOT is PLT index plus GOT headers(3) - times 8, addr & GOT addr. */ - relocation = (plt_index + 3) * GOT_ENTRY_SIZE; - if (r_type == R_390_GOTPLTENT) - relocation += htab->elf.sgot->output_section->vma; - } - unresolved_reloc = FALSE; - break; - } - /* Fall through. */ - - case R_390_GOT12: - case R_390_GOT16: - case R_390_GOT20: - case R_390_GOT32: - case R_390_GOT64: - case R_390_GOTENT: - /* Relocation is to the entry for this symbol in the global - offset table. */ - if (base_got == NULL) - abort (); - - if (h != NULL) - { - bfd_boolean dyn; - - off = h->got.offset; - dyn = htab->elf.dynamic_sections_created; - - if (s390_is_ifunc_symbol_p (h)) - { - BFD_ASSERT (h->plt.offset != (bfd_vma) -1); - if (off == (bfd_vma)-1) - { - /* No explicit GOT usage so redirect to the - got.iplt slot. */ - base_got = htab->elf.igotplt; - off = h->plt.offset / PLT_ENTRY_SIZE * GOT_ENTRY_SIZE; - } - else - { - /* Explicit GOT slots must contain the address - of the PLT slot. This will be handled in - finish_dynamic_symbol. */ - } - } - else if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, - bfd_link_pic (info), - h) - || (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - || resolved_to_zero) - { - /* 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 2, 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_64 (output_bfd, relocation, - base_got->contents + off); - h->got.offset |= 1; - } - - if ((h->def_regular - && bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - /* lgrl rx,sym@GOTENT -> larl rx, sym */ - && ((r_type == R_390_GOTENT - && (bfd_get_16 (input_bfd, - contents + rel->r_offset - 2) - & 0xff0f) == 0xc408) - /* lg rx, sym@GOT(r12) -> larl rx, sym */ - || (r_type == R_390_GOT20 - && (bfd_get_32 (input_bfd, - contents + rel->r_offset - 2) - & 0xff00f000) == 0xe300c000 - && bfd_get_8 (input_bfd, - contents + rel->r_offset + 3) == 0x04))) - - { - unsigned short new_insn = - (0xc000 | (bfd_get_8 (input_bfd, - contents + rel->r_offset - 1) & 0xf0)); - bfd_put_16 (output_bfd, new_insn, - contents + rel->r_offset - 2); - r_type = R_390_PC32DBL; - rel->r_addend = 2; - howto = elf_howto_table + r_type; - relocation = h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset; - goto do_relocation; - } - } - else - unresolved_reloc = FALSE; - } - else - { - if (local_got_offsets == NULL) - abort (); - - off = local_got_offsets[r_symndx]; - - /* The offset must always be a multiple of 8. We use - the least significant bit to record whether we have - already generated the necessary reloc. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_64 (output_bfd, relocation, - htab->elf.sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *s; - Elf_Internal_Rela outrel; - bfd_byte *loc; - - s = htab->elf.srelgot; - if (s == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - outrel.r_info = ELF64_R_INFO (0, R_390_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_offset + off; - - /* For @GOTENT the relocation is against the offset between - the instruction and the symbols entry in the GOT and not - between the start of the GOT and the symbols entry. We - add the vma of the GOT to get the correct value. */ - if ( r_type == R_390_GOTENT - || r_type == R_390_GOTPLTENT) - relocation += base_got->output_section->vma; - - break; - - case R_390_GOTOFF16: - case R_390_GOTOFF32: - case R_390_GOTOFF64: - /* Relocation is relative to the start of the global offset - table. */ - - if (h != NULL - && s390_is_ifunc_symbol_p (h) - && h->def_regular - && !bfd_link_executable (info)) - { - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset - - htab->elf.sgot->output_section->vma); - goto do_relocation; - } - - /* Note that sgot->output_offset is not involved in this - calculation. We always want the start of .got. If we - defined _GLOBAL_OFFSET_TABLE in a different way, as is - permitted by the ABI, we might have to change this - calculation. */ - relocation -= htab->elf.sgot->output_section->vma; - break; - - case R_390_GOTPC: - case R_390_GOTPCDBL: - /* Use global offset table as symbol value. */ - relocation = htab->elf.sgot->output_section->vma; - unresolved_reloc = FALSE; - break; - - case R_390_PLT12DBL: - case R_390_PLT16DBL: - case R_390_PLT24DBL: - case R_390_PLT32: - case R_390_PLT32DBL: - case R_390_PLT64: - /* 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->elf.splt == NULL && !s390_is_ifunc_symbol_p (h))) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } - if (s390_is_ifunc_symbol_p (h)) - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset); - unresolved_reloc = FALSE; - break; - - case R_390_PLTOFF16: - case R_390_PLTOFF32: - case R_390_PLTOFF64: - /* Relocation is to the entry for this symbol in the - procedure linkage table relative to the start of the GOT. */ - - /* For local symbols or if we didn't make a PLT entry for - this symbol resolve the symbol directly. */ - if (h == NULL - || h->plt.offset == (bfd_vma) -1 - || (htab->elf.splt == NULL && !s390_is_ifunc_symbol_p (h))) - { - relocation -= htab->elf.sgot->output_section->vma; - break; - } - - if (s390_is_ifunc_symbol_p (h)) - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset - - htab->elf.sgot->output_section->vma); - else - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset - - htab->elf.sgot->output_section->vma); - unresolved_reloc = FALSE; - break; - - case R_390_PC16: - case R_390_PC12DBL: - case R_390_PC16DBL: - case R_390_PC24DBL: - case R_390_PC32: - case R_390_PC32DBL: - case R_390_PC64: - if (h != NULL - && bfd_link_pie (info) - && !h->def_regular) - { - _bfd_error_handler (_("%B: `%s' non-PLT reloc for symbol defined " - "in shared library and accessed " - "from executable " - "(rebuild file with -fPIC ?)"), - input_bfd, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - /* The target of these relocs are instruction operands - residing in read-only sections. We cannot emit a runtime - reloc for it. */ - if (h != NULL - && s390_is_ifunc_symbol_p (h) - && h->def_regular - && bfd_link_pic (info)) - { - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset); - goto do_relocation; - } - /* Fall through. */ - - case R_390_8: - case R_390_16: - case R_390_32: - case R_390_64: - - if (h != NULL - && s390_is_ifunc_symbol_p (h) - && h->def_regular) - { - if (!bfd_link_pic (info)) - { - /* For a non-shared object the symbol will not - change. Hence we can write the address of the - target IPLT slot now. */ - relocation = (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h ->plt.offset); - goto do_relocation; - } - else - { - /* For shared objects a runtime relocation is needed. */ - - Elf_Internal_Rela outrel; - asection *sreloc; - - /* Need a dynamic relocation to get the real function - address. */ - outrel.r_offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1 - || outrel.r_offset == (bfd_vma) -2) - abort (); - - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (h->dynindx == -1 - || h->forced_local - || bfd_link_executable (info)) - { - /* This symbol is resolved locally. */ - outrel.r_info = ELF64_R_INFO (0, R_390_IRELATIVE); - outrel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - outrel.r_info = ELF64_R_INFO (h->dynindx, r_type); - outrel.r_addend = 0; - } - - sreloc = htab->elf.irelifunc; - elf_append_rela (output_bfd, sreloc, &outrel); - - /* 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. For an - internal symbol, we have updated addend. */ - continue; - } - } - - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - if ((bfd_link_pic (info) - && (h == NULL - || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && ((r_type != R_390_PC16 - && r_type != R_390_PC12DBL - && r_type != R_390_PC16DBL - && r_type != R_390_PC24DBL - && r_type != R_390_PC32 - && r_type != R_390_PC32DBL - && r_type != R_390_PC64) - || !SYMBOL_CALLS_LOCAL (info, h))) - || (ELIMINATE_COPY_RELOCS - && !bfd_link_pic (info) - && 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_boolean skip, relocate; - asection *sreloc; - bfd_byte *loc; - - /* 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_390_PC16 - || r_type == R_390_PC12DBL - || r_type == R_390_PC16DBL - || r_type == R_390_PC24DBL - || r_type == R_390_PC32 - || r_type == R_390_PC32DBL - || r_type == R_390_PC64 - || !bfd_link_pic (info) - || !SYMBOLIC_BIND (info, h) - || !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. */ - outrel.r_addend = relocation + rel->r_addend; - if (r_type == R_390_64) - { - relocate = TRUE; - outrel.r_info = ELF64_R_INFO (0, R_390_RELATIVE); - } - 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; - - if (sindx == 0) - { - osec = htab->elf.text_index_section; - sindx = elf_section_data (osec)->dynindx; - } - BFD_ASSERT (sindx != 0); - - /* We are turning this relocation into one - against a section symbol, so subtract out - the output section's address but not the - offset of the input section in the output - section. */ - outrel.r_addend -= osec->vma; - } - outrel.r_info = ELF64_R_INFO (sindx, r_type); - } - } - - 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; - - /* Relocations for tls literal pool entries. */ - case R_390_TLS_IE64: - if (bfd_link_pic (info)) - { - Elf_Internal_Rela outrel; - asection *sreloc; - bfd_byte *loc; - - outrel.r_offset = rel->r_offset - + input_section->output_section->vma - + input_section->output_offset; - outrel.r_info = ELF64_R_INFO (0, R_390_RELATIVE); - 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_reloc_out (output_bfd, &outrel, loc); - } - /* Fall through. */ - - case R_390_TLS_GD64: - case R_390_TLS_GOTIE64: - r_type = elf_s390_tls_transition (info, r_type, h == NULL); - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = elf_s390_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - { - tls_type = elf_s390_hash_entry(h)->tls_type; - if (!bfd_link_pic (info) && h->dynindx == -1 && tls_type >= GOT_TLS_IE) - r_type = R_390_TLS_LE64; - } - if (r_type == R_390_TLS_GD64 && tls_type >= GOT_TLS_IE) - r_type = R_390_TLS_IE64; - - if (r_type == R_390_TLS_LE64) - { - /* This relocation gets optimized away by the local exec - access optimization. */ - BFD_ASSERT (! unresolved_reloc); - bfd_put_64 (output_bfd, -tpoff (info, relocation), - contents + rel->r_offset); - continue; - } - - if (htab->elf.sgot == NULL) - abort (); - - if (h != NULL) - off = h->got.offset; - else - { - if (local_got_offsets == NULL) - abort (); - - off = local_got_offsets[r_symndx]; - } - - emit_tls_relocs: - - if ((off & 1) != 0) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - int dr_type, indx; - - if (htab->elf.srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - - indx = h && h->dynindx != -1 ? h->dynindx : 0; - if (r_type == R_390_TLS_GD64) - dr_type = R_390_TLS_DTPMOD; - else - dr_type = R_390_TLS_TPOFF; - if (dr_type == R_390_TLS_TPOFF && indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - outrel.r_info = ELF64_R_INFO (indx, dr_type); - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ - * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - - if (r_type == R_390_TLS_GD64) - { - if (indx == 0) - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_64 (output_bfd, - relocation - dtpoff_base (info), - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - } - else - { - outrel.r_info = ELF64_R_INFO (indx, R_390_TLS_DTPOFF); - outrel.r_offset += GOT_ENTRY_SIZE; - outrel.r_addend = 0; - htab->elf.srelgot->reloc_count++; - loc += sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - } - } - - if (h != NULL) - h->got.offset |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - if (off >= (bfd_vma) -2) - abort (); - if (r_type == ELF64_R_TYPE (rel->r_info)) - { - relocation = htab->elf.sgot->output_offset + off; - if (r_type == R_390_TLS_IE64 || r_type == R_390_TLS_IEENT) - relocation += htab->elf.sgot->output_section->vma; - unresolved_reloc = FALSE; - } - else - { - bfd_put_64 (output_bfd, htab->elf.sgot->output_offset + off, - contents + rel->r_offset); - continue; - } - break; - - case R_390_TLS_GOTIE12: - case R_390_TLS_GOTIE20: - case R_390_TLS_IEENT: - if (h == NULL) - { - if (local_got_offsets == NULL) - abort(); - off = local_got_offsets[r_symndx]; - if (bfd_link_pic (info)) - goto emit_tls_relocs; - } - else - { - off = h->got.offset; - tls_type = elf_s390_hash_entry(h)->tls_type; - if (bfd_link_pic (info) || h->dynindx != -1 || tls_type < GOT_TLS_IE) - goto emit_tls_relocs; - } - - if (htab->elf.sgot == NULL) - abort (); - - BFD_ASSERT (! unresolved_reloc); - bfd_put_64 (output_bfd, -tpoff (info, relocation), - htab->elf.sgot->contents + off); - relocation = htab->elf.sgot->output_offset + off; - if (r_type == R_390_TLS_IEENT) - relocation += htab->elf.sgot->output_section->vma; - unresolved_reloc = FALSE; - break; - - case R_390_TLS_LDM64: - if (! bfd_link_pic (info)) - /* The literal pool entry this relocation refers to gets ignored - by the optimized code of the local exec model. Do nothing - and the value will turn out zero. */ - continue; - - if (htab->elf.sgot == NULL) - abort (); - - off = htab->tls_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - - if (htab->elf.srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - - bfd_put_64 (output_bfd, 0, - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - outrel.r_info = ELF64_R_INFO (0, R_390_TLS_DTPMOD); - outrel.r_addend = 0; - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ - * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - htab->tls_ldm_got.offset |= 1; - } - relocation = htab->elf.sgot->output_offset + off; - unresolved_reloc = FALSE; - break; - - case R_390_TLS_LE64: - if (bfd_link_dll (info)) - { - /* Linking a shared library with non-fpic code requires - a R_390_TLS_TPOFF relocation. */ - 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; - outrel.r_info = ELF64_R_INFO (indx, R_390_TLS_TPOFF); - if (indx == 0) - outrel.r_addend = relocation - dtpoff_base (info); - else - outrel.r_addend = 0; - 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); - } - else - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_64 (output_bfd, -tpoff (info, relocation), - contents + rel->r_offset); - } - continue; - - case R_390_TLS_LDO64: - if (bfd_link_pic (info) || (input_section->flags & SEC_DEBUGGING)) - relocation -= dtpoff_base (info); - else - /* When converting LDO to LE, we must negate. */ - relocation = -tpoff (info, relocation); - break; - - /* Relocations for tls instructions. */ - case R_390_TLS_LOAD: - case R_390_TLS_GDCALL: - case R_390_TLS_LDCALL: - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = elf_s390_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - tls_type = elf_s390_hash_entry(h)->tls_type; - - if (tls_type == GOT_TLS_GD) - continue; - - if (r_type == R_390_TLS_LOAD) - { - if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) - { - /* IE->LE transition. Four valid cases: - lg %rx,(0,%ry) -> sllg %rx,%ry,0 - lg %rx,(%ry,0) -> sllg %rx,%ry,0 - lg %rx,(%ry,%r12) -> sllg %rx,%ry,0 - lg %rx,(%r12,%ry) -> sllg %rx,%ry,0 */ - unsigned int insn0, insn1, ry; - - insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4); - if (insn1 != 0x0004) - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - if ((insn0 & 0xff00f000) == 0xe3000000) - /* lg %rx,0(%ry,0) -> sllg %rx,%ry,0 */ - ry = (insn0 & 0x000f0000); - else if ((insn0 & 0xff0f0000) == 0xe3000000) - /* lg %rx,0(0,%ry) -> sllg %rx,%ry,0 */ - ry = (insn0 & 0x0000f000) << 4; - else if ((insn0 & 0xff00f000) == 0xe300c000) - /* lg %rx,0(%ry,%r12) -> sllg %rx,%ry,0 */ - ry = (insn0 & 0x000f0000); - else if ((insn0 & 0xff0f0000) == 0xe30c0000) - /* lg %rx,0(%r12,%ry) -> sllg %rx,%ry,0 */ - ry = (insn0 & 0x0000f000) << 4; - else - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - insn0 = 0xeb000000 | (insn0 & 0x00f00000) | ry; - insn1 = 0x000d; - bfd_put_32 (output_bfd, insn0, contents + rel->r_offset); - bfd_put_16 (output_bfd, insn1, contents + rel->r_offset + 4); - } - } - else if (r_type == R_390_TLS_GDCALL) - { - unsigned int insn0, insn1; - - insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4); - if ((insn0 & 0xffff0000) != 0xc0e50000) - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) - { - /* GD->LE transition. - brasl %r14,__tls_get_addr@plt -> brcl 0,. */ - insn0 = 0xc0040000; - insn1 = 0x0000; - } - else - { - /* GD->IE transition. - brasl %r14,__tls_get_addr@plt -> lg %r2,0(%r2,%r12) */ - insn0 = 0xe322c000; - insn1 = 0x0004; - } - bfd_put_32 (output_bfd, insn0, contents + rel->r_offset); - bfd_put_16 (output_bfd, insn1, contents + rel->r_offset + 4); - } - else if (r_type == R_390_TLS_LDCALL) - { - if (!bfd_link_pic (info)) - { - unsigned int insn0, insn1; - - insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset); - insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4); - if ((insn0 & 0xffff0000) != 0xc0e50000) - { - invalid_tls_insn (input_bfd, input_section, rel); - return FALSE; - } - /* LD->LE transition. - brasl %r14,__tls_get_addr@plt -> brcl 0,. */ - insn0 = 0xc0040000; - insn1 = 0x0000; - bfd_put_32 (output_bfd, insn0, contents + rel->r_offset); - bfd_put_16 (output_bfd, insn1, contents + rel->r_offset + 4); - } - } - continue; - - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - - do_relocation: - - /* When applying a 24 bit reloc we need to start one byte - earlier. Otherwise the 32 bit get/put bfd operations might - access a byte after the actual section. */ - if (r_type == R_390_PC24DBL - || r_type == R_390_PLT24DBL) - rel->r_offset--; - - if (r_type == R_390_20 - || r_type == R_390_GOT20 - || r_type == R_390_GOTPLT20 - || r_type == R_390_TLS_GOTIE20) - { - relocation += rel->r_addend; - relocation = (relocation&0xfff) << 8 | (relocation&0xff000) >> 12; - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, 0); - } - else - 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) - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), - input_bfd, input_section, - rel->r_offset, name, (int) r); - return FALSE; - } - } - } - - return TRUE; -} - -/* Generate the PLT slots together with the dynamic relocations needed - for IFUNC symbols. */ - -static void -elf_s390_finish_ifunc_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - struct elf_s390_link_hash_table *htab, - bfd_vma plt_offset, - bfd_vma resolver_address) -{ - bfd_vma plt_index; - bfd_vma got_offset; - Elf_Internal_Rela rela; - bfd_byte *loc; - asection *plt, *gotplt, *relplt; - - if (htab->elf.iplt == NULL - || htab->elf.igotplt == NULL - || htab->elf.irelplt == NULL) - abort (); - - /* Index of the PLT slot within iplt section. */ - plt_index = plt_offset / PLT_ENTRY_SIZE; - plt = htab->elf.iplt; - /* Offset into the igot.plt section. */ - got_offset = plt_index * GOT_ENTRY_SIZE; - gotplt = htab->elf.igotplt; - relplt = htab->elf.irelplt; - - /* Fill in the blueprint of a PLT. */ - memcpy (plt->contents + plt_offset, elf_s390x_plt_entry, - PLT_ENTRY_SIZE); - - /* Fixup the relative address to the GOT entry */ - bfd_put_32 (output_bfd, - (gotplt->output_section->vma + - gotplt->output_offset + got_offset - - (plt->output_section->vma + - plt->output_offset + - plt_offset))/2, - plt->contents + plt_offset + 2); - /* Fixup the relative branch to PLT 0 */ - bfd_put_32 (output_bfd, - (plt->output_offset + - (PLT_ENTRY_SIZE * plt_index) + 22)/2, - plt->contents + plt_offset + 24); - /* Fixup offset into .rela.plt section. */ - bfd_put_32 (output_bfd, relplt->output_offset + - plt_index * sizeof (Elf64_External_Rela), - plt->contents + plt_offset + 28); - - /* Fill in the entry in the global offset table. - Points to instruction after GOT offset. */ - bfd_put_64 (output_bfd, - (plt->output_section->vma - + plt->output_offset - + plt_offset - + 14), - gotplt->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (gotplt->output_section->vma - + gotplt->output_offset - + got_offset); - - if (!h - || h->dynindx == -1 - || ((bfd_link_executable (info) - || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) - && h->def_regular)) - { - /* The symbol can be locally resolved. */ - rela.r_info = ELF64_R_INFO (0, R_390_IRELATIVE); - rela.r_addend = resolver_address; - } - else - { - rela.r_info = ELF64_R_INFO (h->dynindx, R_390_JMP_SLOT); - rela.r_addend = 0; - } - - loc = relplt->contents + plt_index * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); -} - - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_s390_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_s390_link_hash_table *htab; - struct elf_s390_link_hash_entry *eh = (struct elf_s390_link_hash_entry*)h; - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - 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 (s390_is_ifunc_symbol_p (h) && h->def_regular) - { - elf_s390_finish_ifunc_symbol (output_bfd, info, h, - htab, h->plt.offset, - eh->ifunc_resolver_address + - eh->ifunc_resolver_section->output_offset + - eh->ifunc_resolver_section->output_section->vma); - - /* Do not return yet. Handling of explicit GOT slots of - IFUNC symbols is below. */ - } - else - { - if (h->dynindx == -1 - || htab->elf.splt == NULL - || htab->elf.sgotplt == NULL - || htab->elf.srelplt == NULL) - abort (); - - /* Calc. index no. - Current offset - size first entry / entry size. */ - plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) / PLT_ENTRY_SIZE; - - /* Offset in GOT is PLT index plus GOT headers(3) times 8, - addr & GOT addr. */ - got_offset = (plt_index + 3) * GOT_ENTRY_SIZE; - - /* Fill in the blueprint of a PLT. */ - memcpy (htab->elf.splt->contents + h->plt.offset, elf_s390x_plt_entry, - PLT_ENTRY_SIZE); - - /* Fixup the relative address to the GOT entry */ - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma + - htab->elf.sgotplt->output_offset + got_offset - - (htab->elf.splt->output_section->vma + - htab->elf.splt->output_offset + - h->plt.offset))/2, - htab->elf.splt->contents + h->plt.offset + 2); - /* Fixup the relative branch to PLT 0 */ - bfd_put_32 (output_bfd, - (PLT_FIRST_ENTRY_SIZE + - (PLT_ENTRY_SIZE * plt_index) + 22)/2, - htab->elf.splt->contents + h->plt.offset + 24); - /* Fixup offset into .rela.plt section. */ - bfd_put_32 (output_bfd, plt_index * sizeof (Elf64_External_Rela), - htab->elf.splt->contents + h->plt.offset + 28); - - /* Fill in the entry in the global offset table. - Points to instruction after GOT offset. */ - bfd_put_64 (output_bfd, - (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + h->plt.offset - + 14), - htab->elf.sgotplt->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + got_offset); - rela.r_info = ELF64_R_INFO (h->dynindx, R_390_JMP_SLOT); - rela.r_addend = 0; - loc = htab->elf.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 alone. This is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library. */ - sym->st_shndx = SHN_UNDEF; - } - } - } - - if (h->got.offset != (bfd_vma) -1 - && elf_s390_hash_entry(h)->tls_type != GOT_TLS_GD - && elf_s390_hash_entry(h)->tls_type != GOT_TLS_IE - && elf_s390_hash_entry(h)->tls_type != GOT_TLS_IE_NLT) - { - Elf_Internal_Rela rela; - bfd_byte *loc; - - /* This symbol has an entry in the global offset table. Set it - up. */ - if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL) - abort (); - - rela.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + (h->got.offset &~ (bfd_vma) 1)); - - if (h->def_regular && s390_is_ifunc_symbol_p (h)) - { - if (bfd_link_pic (info)) - { - /* An explicit GOT slot usage needs GLOB_DAT. If the - symbol references local the implicit got.iplt slot - will be used and the IRELATIVE reloc has been created - above. */ - goto do_glob_dat; - } - else - { - /* For non-shared objects explicit GOT slots must be - filled with the PLT slot address for pointer - equality reasons. */ - bfd_put_64 (output_bfd, (htab->elf.iplt->output_section->vma - + htab->elf.iplt->output_offset - + h->plt.offset), - htab->elf.sgot->contents + h->got.offset); - return TRUE; - } - } - else if (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL (info, h)) - { - if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - return TRUE; - - /* 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 (!(h->def_regular || ELF_COMMON_DEF_P (h))) - return FALSE; - BFD_ASSERT((h->got.offset & 1) != 0); - rela.r_info = ELF64_R_INFO (0, R_390_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); - do_glob_dat: - bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgot->contents + h->got.offset); - rela.r_info = ELF64_R_INFO (h->dynindx, R_390_GLOB_DAT); - rela.r_addend = 0; - } - - loc = htab->elf.srelgot->contents; - loc += htab->elf.srelgot->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - } - - if (h->needs_copy) - { - Elf_Internal_Rela rela; - asection *s; - bfd_byte *loc; - - /* This symbols 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->elf.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_390_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - loc = s->contents + s->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - } - - /* Mark some specially defined symbols as absolute. */ - if (h == htab->elf.hdynamic - || h == htab->elf.hgot - || h == htab->elf.hplt) - 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_s390_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - bfd *abfd = info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_s390_link_hash_table *htab = elf_s390_hash_table (info); - unsigned long r_symndx = ELF64_R_SYM (rela->r_info); - Elf_Internal_Sym sym; - - if (htab->elf.dynsym == NULL - || !bed->s->swap_symbol_in (abfd, - (htab->elf.dynsym->contents - + r_symndx * bed->s->sizeof_sym), - 0, &sym)) - abort (); - - /* Check relocation against STT_GNU_IFUNC symbol. */ - if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) - return reloc_class_ifunc; - - switch ((int) ELF64_R_TYPE (rela->r_info)) - { - case R_390_RELATIVE: - return reloc_class_relative; - case R_390_JMP_SLOT: - return reloc_class_plt; - case R_390_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -elf_s390_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_s390_link_hash_table *htab; - bfd *dynobj; - asection *sdyn; - bfd *ibfd; - unsigned int i; - - htab = elf_s390_hash_table (info); - if (htab == NULL) - return FALSE; - - dynobj = htab->elf.dynobj; - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (htab->elf.dynamic_sections_created) - { - Elf64_External_Dyn *dyncon, *dynconend; - - if (sdyn == NULL || htab->elf.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->elf.sgotplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_JMPREL: - s = htab->elf.srelplt; - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - break; - - case DT_PLTRELSZ: - dyn.d_un.d_val = htab->elf.srelplt->size; - if (htab->elf.irelplt) - dyn.d_un.d_val += htab->elf.irelplt->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. */ - dyn.d_un.d_val -= htab->elf.srelplt->size; - if (htab->elf.irelplt) - dyn.d_un.d_val -= htab->elf.irelplt->size; - break; - } - - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - } - - /* Fill in the special first entry in the procedure linkage table. */ - if (htab->elf.splt && htab->elf.splt->size > 0) - { - /* fill in blueprint for plt 0 entry */ - memcpy (htab->elf.splt->contents, elf_s390x_first_plt_entry, - PLT_FIRST_ENTRY_SIZE); - /* Fixup relative address to start of GOT */ - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - - htab->elf.splt->output_section->vma - - htab->elf.splt->output_offset - 6)/2, - htab->elf.splt->contents + 8); - } - if (elf_section_data (htab->elf.splt->output_section) != NULL) - elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize - = PLT_ENTRY_SIZE; - } - - if (htab->elf.sgotplt) - { - /* Fill in the first three entries in the global offset table. */ - if (htab->elf.sgotplt->size > 0) - { - bfd_put_64 (output_bfd, - (sdyn == NULL ? (bfd_vma) 0 - : sdyn->output_section->vma + sdyn->output_offset), - htab->elf.sgotplt->contents); - /* One entry for shared object struct ptr. */ - bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 8); - /* One entry for _dl_runtime_resolve. */ - bfd_put_64 (output_bfd, (bfd_vma) 0, htab->elf.sgotplt->contents + 16); - } - - elf_section_data (htab->elf.sgot->output_section) - ->this_hdr.sh_entsize = 8; - } - - /* Finish dynamic symbol for local IFUNC symbols. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - struct plt_entry *local_plt; - Elf_Internal_Sym *isym; - Elf_Internal_Shdr *symtab_hdr; - - symtab_hdr = &elf_symtab_hdr (ibfd); - - if (!is_s390_elf (ibfd)) - continue; - - local_plt = elf_s390_local_plt (ibfd); - if (local_plt != NULL) - for (i = 0; i < symtab_hdr->sh_info; i++) - { - if (local_plt[i].plt.offset != (bfd_vma) -1) - { - asection *sec = local_plt[i].sec; - isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, i); - if (isym == NULL) - return FALSE; - - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - elf_s390_finish_ifunc_symbol (output_bfd, info, NULL, htab, - local_plt[i].plt.offset, - isym->st_value - + sec->output_section->vma - + sec->output_offset); - - } - } - } - - return TRUE; -} - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -elf_s390_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 336: /* sizeof(struct elf_prstatus) on s390x */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = 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 -elf_s390_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 136: /* sizeof(struct elf_prpsinfo) on s390x */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 24); - 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; -} - -static char * -elf_s390_write_core_note (bfd *abfd, char *buf, int *bufsiz, - int note_type, ...) -{ - va_list ap; - - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - { - char data[136] = { 0 }; - const char *fname, *psargs; - - va_start (ap, note_type); - fname = va_arg (ap, const char *); - psargs = va_arg (ap, const char *); - va_end (ap); - - strncpy (data + 40, fname, 16); - strncpy (data + 56, psargs, 80); - return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type, - &data, sizeof (data)); - } - - case NT_PRSTATUS: - { - char data[336] = { 0 }; - long pid; - int cursig; - const void *gregs; - - va_start (ap, note_type); - pid = va_arg (ap, long); - cursig = va_arg (ap, int); - gregs = va_arg (ap, const void *); - va_end (ap); - - bfd_put_16 (abfd, cursig, data + 12); - bfd_put_32 (abfd, pid, data + 32); - memcpy (data + 112, gregs, 216); - return elfcore_write_note (abfd, buf, bufsiz, "CORE", note_type, - &data, sizeof (data)); - } - } - /* NOTREACHED */ -} - -/* 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_s390_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) -{ - return plt->vma + PLT_FIRST_ENTRY_SIZE + i * PLT_ENTRY_SIZE; -} - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf64_s390_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - if (!is_s390_elf (ibfd) || !is_s390_elf (info->output_bfd)) - return TRUE; - - return elf_s390_merge_obj_attributes (ibfd, info); -} - -/* We may add a PT_S390_PGSTE program header. */ - -static int -elf_s390_additional_program_headers (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - struct elf_s390_link_hash_table *htab; - - if (info) - { - htab = elf_s390_hash_table (info); - if (htab) - return htab->params->pgste; - } - return 0; -} - - -/* Add the PT_S390_PGSTE program header. */ - -static bfd_boolean -elf_s390_modify_segment_map (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_s390_link_hash_table *htab; - struct elf_segment_map *m, *pm = NULL; - - if (!abfd || !info) - return TRUE; - - htab = elf_s390_hash_table (info); - if (!htab || !htab->params->pgste) - return TRUE; - - /* If there is already a PT_S390_PGSTE header, avoid adding - another. */ - m = elf_seg_map (abfd); - while (m && m->p_type != PT_S390_PGSTE) - { - pm = m; - m = m->next; - } - - if (m) - return TRUE; - - m = (struct elf_segment_map *) - bfd_zalloc (abfd, sizeof (struct elf_segment_map)); - if (m == NULL) - return FALSE; - m->p_type = PT_S390_PGSTE; - m->count = 0; - m->next = NULL; - if (pm) - pm->next = m; - - return TRUE; -} - -bfd_boolean -bfd_elf_s390_set_options (struct bfd_link_info *info, - struct s390_elf_params *params) -{ - struct elf_s390_link_hash_table *htab; - - if (info) - { - htab = elf_s390_hash_table (info); - if (htab) - htab->params = params; - } - - return TRUE; -} - - -/* Why was the hash table entry size definition changed from - ARCH_SIZE/8 to 4? This breaks the 64 bit dynamic linker and - this is the only reason for the s390_elf64_size_info structure. */ - -const struct elf_size_info s390_elf64_size_info = -{ - sizeof (Elf64_External_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_External_Rel), - sizeof (Elf64_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 8, /* hash-table entry size. */ - 1, /* internal relocations per external relocations. */ - 64, /* arch_size. */ - 3, /* log_file_align. */ - ELFCLASS64, EV_CURRENT, - bfd_elf64_write_out_phdrs, - bfd_elf64_write_shdrs_and_ehdr, - bfd_elf64_checksum_contents, - bfd_elf64_write_relocs, - bfd_elf64_swap_symbol_in, - bfd_elf64_swap_symbol_out, - bfd_elf64_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - bfd_elf64_swap_reloc_in, - bfd_elf64_swap_reloc_out, - bfd_elf64_swap_reloca_in, - bfd_elf64_swap_reloca_out -}; - -#define TARGET_BIG_SYM s390_elf64_vec -#define TARGET_BIG_NAME "elf64-s390" -#define ELF_ARCH bfd_arch_s390 -#define ELF_TARGET_ID S390_ELF_DATA -#define ELF_MACHINE_CODE EM_S390 -#define ELF_MACHINE_ALT1 EM_S390_OLD -#define ELF_MAXPAGESIZE 0x1000 - -#define elf_backend_size_info s390_elf64_size_info - -#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 24 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 - -#define elf_info_to_howto elf_s390_info_to_howto - -#define bfd_elf64_bfd_is_local_label_name elf_s390_is_local_label_name -#define bfd_elf64_bfd_link_hash_table_create elf_s390_link_hash_table_create -#define bfd_elf64_bfd_reloc_type_lookup elf_s390_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup elf_s390_reloc_name_lookup -#define bfd_elf64_bfd_merge_private_bfd_data elf64_s390_merge_private_bfd_data - -#define elf_backend_adjust_dynamic_symbol elf_s390_adjust_dynamic_symbol -#define elf_backend_check_relocs elf_s390_check_relocs -#define elf_backend_copy_indirect_symbol elf_s390_copy_indirect_symbol -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections elf_s390_finish_dynamic_sections -#define elf_backend_finish_dynamic_symbol elf_s390_finish_dynamic_symbol -#define elf_backend_gc_mark_hook elf_s390_gc_mark_hook -#define elf_backend_reloc_type_class elf_s390_reloc_type_class -#define elf_backend_relocate_section elf_s390_relocate_section -#define elf_backend_size_dynamic_sections elf_s390_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_grok_prstatus elf_s390_grok_prstatus -#define elf_backend_grok_psinfo elf_s390_grok_psinfo -#define elf_backend_write_core_note elf_s390_write_core_note -#define elf_backend_plt_sym_val elf_s390_plt_sym_val -#define elf_backend_add_symbol_hook elf_s390_add_symbol_hook -#define elf_backend_sort_relocs_p elf_s390_elf_sort_relocs_p -#define elf_backend_additional_program_headers elf_s390_additional_program_headers -#define elf_backend_modify_segment_map elf_s390_modify_segment_map - -#define bfd_elf64_mkobject elf_s390_mkobject -#define elf_backend_object_p elf_s390_object_p - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-sh64.c b/sdcc/support/sdbinutils/bfd/elf64-sh64.c deleted file mode 100644 index 8a41764ff..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-sh64.c +++ /dev/null @@ -1,3977 +0,0 @@ -/* SuperH SH64-specific support for 64-bit ELF - Copyright (C) 2000-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define SH64_ELF64 - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/sh.h" - -/* Add a suffix for datalabel indirection symbols. It must not match any - other symbols; user symbols with or without version or other - decoration. It must only be used internally and not emitted by any - means. */ -#define DATALABEL_SUFFIX " DL" - -#define GOT_BIAS (-((long)-32768)) - -#define PLT_ENTRY_SIZE 64 - -/* Return size of a PLT entry. */ -#define elf_sh64_sizeof_plt(info) PLT_ENTRY_SIZE - -/* Return offset of the PLT0 address in an absolute PLT entry. */ -#define elf_sh64_plt_plt0_offset(info) 32 - -/* Return offset of the linker in PLT0 entry. */ -#define elf_sh64_plt0_gotplt_offset(info) 0 - -/* Return offset of the trampoline in PLT entry */ -#define elf_sh64_plt_temp_offset(info) 33 /* Add one because it's SHmedia. */ - -/* Return offset of the symbol in PLT entry. */ -#define elf_sh64_plt_symbol_offset(info) 0 - -/* Return offset of the relocation in PLT entry. */ -#define elf_sh64_plt_reloc_offset(info) (bfd_link_pic (info) ? 52 : 44) - -#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" - -/* The sh linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that - it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ - -/* This structure keeps track of the number of PC relative relocs we - have copied for a given symbol. */ - -struct elf_sh64_pcrel_relocs_copied -{ - /* Next section. */ - struct elf_sh64_pcrel_relocs_copied *next; - /* A section in dynobj. */ - asection *section; - /* Number of relocs copied in this section. */ - bfd_size_type count; -}; - -/* sh ELF linker hash entry. */ - -struct elf_sh64_link_hash_entry -{ - struct elf_link_hash_entry root; - - bfd_vma datalabel_got_offset; - - /* Number of PC relative relocs copied for this symbol. */ - struct elf_sh64_pcrel_relocs_copied *pcrel_relocs_copied; -}; - -/* Traverse an sh ELF linker hash table. */ - -#define sh64_elf64_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - ((table), \ - (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ - (info))) - -static bfd_reloc_status_type sh_elf64_ignore_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type sh_elf64_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); - -static reloc_howto_type sh_elf64_howto_table[] = { - /* No relocation. */ - HOWTO (R_SH_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - sh_elf64_ignore_reloc, /* special_function */ - "R_SH_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit absolute relocation. Setting partial_inplace to TRUE and - src_mask to a non-zero value is similar to the COFF toolchain. */ - HOWTO (R_SH_DIR32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - sh_elf64_reloc, /* special_function */ - "R_SH_DIR32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit PC relative relocation. */ - HOWTO (R_SH_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - sh_elf64_ignore_reloc, /* special_function */ - "R_SH_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* For 32-bit sh, this is R_SH_DIR8WPN. */ - EMPTY_HOWTO (3), - - /* For 32-bit sh, this is R_SH_IND12W. */ - EMPTY_HOWTO (4), - - /* For 32-bit sh, this is R_SH_DIR8WPL. */ - EMPTY_HOWTO (5), - - /* For 32-bit sh, this is R_SH_DIR8WPZ. */ - EMPTY_HOWTO (6), - - /* For 32-bit sh, this is R_SH_DIR8BP. */ - EMPTY_HOWTO (7), - - /* For 32-bit sh, this is R_SH_DIR8W. */ - EMPTY_HOWTO (8), - - /* For 32-bit sh, this is R_SH_DIR8L. */ - EMPTY_HOWTO (9), - - EMPTY_HOWTO (10), - EMPTY_HOWTO (11), - EMPTY_HOWTO (12), - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - EMPTY_HOWTO (16), - EMPTY_HOWTO (17), - EMPTY_HOWTO (18), - EMPTY_HOWTO (19), - EMPTY_HOWTO (20), - EMPTY_HOWTO (21), - EMPTY_HOWTO (22), - EMPTY_HOWTO (23), - EMPTY_HOWTO (24), - - /* The remaining relocs are a GNU extension used for relaxing. The - final pass of the linker never needs to do anything with any of - these relocs. Any required operations are handled by the - relaxation code. */ - - /* A 16 bit switch table entry. This is generated for an expression - such as ``.word L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_SH_SWITCH16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf64_ignore_reloc, /* special_function */ - "R_SH_SWITCH16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* A 32 bit switch table entry. This is generated for an expression - such as ``.long L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_SH_SWITCH32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf64_ignore_reloc, /* special_function */ - "R_SH_SWITCH32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* For 32-bit sh, this is R_SH_USES. */ - EMPTY_HOWTO (27), - - /* For 32-bit sh, this is R_SH_COUNT. */ - EMPTY_HOWTO (28), - - /* For 32-bit sh, this is R_SH_ALIGN. FIXME: For linker relaxation, - this might be emitted. When linker relaxation is implemented, we - might want to use it. */ - EMPTY_HOWTO (29), - - /* For 32-bit sh, this is R_SH_CODE. FIXME: For linker relaxation, - this might be emitted. When linker relaxation is implemented, we - might want to use it. */ - EMPTY_HOWTO (30), - - /* For 32-bit sh, this is R_SH_DATA. FIXME: For linker relaxation, - this might be emitted. When linker relaxation is implemented, we - might want to use it. */ - EMPTY_HOWTO (31), - - /* For 32-bit sh, this is R_SH_LABEL. FIXME: For linker relaxation, - this might be emitted. When linker relaxation is implemented, we - might want to use it. */ - EMPTY_HOWTO (32), - - /* An 8 bit switch table entry. This is generated for an expression - such as ``.word L1 - L2''. The offset holds the difference - between the reloc address and L2. */ - HOWTO (R_SH_SWITCH8, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 8, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf64_ignore_reloc, /* special_function */ - "R_SH_SWITCH8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* GNU extension to record C++ vtable hierarchy */ - HOWTO (R_SH_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_SH_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_SH_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_SH_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* For 32-bit sh, this is R_SH_LOOP_START. */ - EMPTY_HOWTO (36), - - /* For 32-bit sh, this is R_SH_LOOP_END. */ - EMPTY_HOWTO (37), - - EMPTY_HOWTO (38), - EMPTY_HOWTO (39), - EMPTY_HOWTO (40), - EMPTY_HOWTO (41), - EMPTY_HOWTO (42), - EMPTY_HOWTO (43), - EMPTY_HOWTO (44), - - /* Used in SHLLI.L and SHLRI.L. */ - HOWTO (R_SH_DIR5U, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR5U", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in SHARI, SHLLI et al. */ - HOWTO (R_SH_DIR6U, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR6U", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in BxxI, LDHI.L et al. */ - HOWTO (R_SH_DIR6S, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR6S", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xfc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in ADDI, ANDI et al. */ - HOWTO (R_SH_DIR10S, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10S", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in LD.UW, ST.W et al. */ - HOWTO (R_SH_DIR10SW, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10SW", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in LD.L, FLD.S et al. */ - HOWTO (R_SH_DIR10SL, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10SL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in FLD.D, FST.P et al. */ - HOWTO (R_SH_DIR10SQ, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_DIR10SQ", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - EMPTY_HOWTO (60), - EMPTY_HOWTO (61), - EMPTY_HOWTO (62), - EMPTY_HOWTO (63), - EMPTY_HOWTO (64), - EMPTY_HOWTO (65), - EMPTY_HOWTO (66), - EMPTY_HOWTO (67), - EMPTY_HOWTO (68), - EMPTY_HOWTO (69), - EMPTY_HOWTO (70), - EMPTY_HOWTO (71), - EMPTY_HOWTO (72), - EMPTY_HOWTO (73), - EMPTY_HOWTO (74), - EMPTY_HOWTO (75), - EMPTY_HOWTO (76), - EMPTY_HOWTO (77), - EMPTY_HOWTO (78), - EMPTY_HOWTO (79), - EMPTY_HOWTO (80), - EMPTY_HOWTO (81), - EMPTY_HOWTO (82), - EMPTY_HOWTO (83), - EMPTY_HOWTO (84), - EMPTY_HOWTO (85), - EMPTY_HOWTO (86), - EMPTY_HOWTO (87), - EMPTY_HOWTO (88), - EMPTY_HOWTO (89), - EMPTY_HOWTO (90), - EMPTY_HOWTO (91), - EMPTY_HOWTO (92), - EMPTY_HOWTO (93), - EMPTY_HOWTO (94), - EMPTY_HOWTO (95), - EMPTY_HOWTO (96), - EMPTY_HOWTO (97), - EMPTY_HOWTO (98), - EMPTY_HOWTO (99), - EMPTY_HOWTO (100), - EMPTY_HOWTO (101), - EMPTY_HOWTO (102), - EMPTY_HOWTO (103), - EMPTY_HOWTO (104), - EMPTY_HOWTO (105), - EMPTY_HOWTO (106), - EMPTY_HOWTO (107), - EMPTY_HOWTO (108), - EMPTY_HOWTO (109), - EMPTY_HOWTO (110), - EMPTY_HOWTO (111), - EMPTY_HOWTO (112), - EMPTY_HOWTO (113), - EMPTY_HOWTO (114), - EMPTY_HOWTO (115), - EMPTY_HOWTO (116), - EMPTY_HOWTO (117), - EMPTY_HOWTO (118), - EMPTY_HOWTO (119), - EMPTY_HOWTO (120), - EMPTY_HOWTO (121), - EMPTY_HOWTO (122), - EMPTY_HOWTO (123), - EMPTY_HOWTO (124), - EMPTY_HOWTO (125), - EMPTY_HOWTO (126), - EMPTY_HOWTO (127), - EMPTY_HOWTO (128), - EMPTY_HOWTO (129), - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - EMPTY_HOWTO (133), - EMPTY_HOWTO (134), - EMPTY_HOWTO (135), - EMPTY_HOWTO (136), - EMPTY_HOWTO (137), - EMPTY_HOWTO (138), - EMPTY_HOWTO (139), - EMPTY_HOWTO (140), - EMPTY_HOWTO (141), - EMPTY_HOWTO (142), - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - EMPTY_HOWTO (145), - EMPTY_HOWTO (146), - EMPTY_HOWTO (147), - EMPTY_HOWTO (148), - EMPTY_HOWTO (149), - EMPTY_HOWTO (150), - EMPTY_HOWTO (151), - EMPTY_HOWTO (152), - EMPTY_HOWTO (153), - EMPTY_HOWTO (154), - EMPTY_HOWTO (155), - EMPTY_HOWTO (156), - EMPTY_HOWTO (157), - EMPTY_HOWTO (158), - EMPTY_HOWTO (159), - - /* Relocs for dynamic linking for 32-bit SH would follow. We don't have - any dynamic linking support for 64-bit SH at present. */ - - EMPTY_HOWTO (160), - EMPTY_HOWTO (161), - EMPTY_HOWTO (162), - EMPTY_HOWTO (163), - EMPTY_HOWTO (164), - EMPTY_HOWTO (165), - EMPTY_HOWTO (166), - EMPTY_HOWTO (167), - EMPTY_HOWTO (168), - - /* Back to SH5 relocations. */ - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOT_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOT_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOT_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOT_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOTPLT_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOTPLT_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOTPLT_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOTPLT_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_PLT_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_PLT_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_PLT_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_PLT_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PLT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOTOFF_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOTOFF_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOTOFF_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOTOFF_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTOFF_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_GOTPC_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_GOTPC_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_GOTPC_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_GOTPC_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPC_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in LD.L, FLD.S et al. */ - HOWTO (R_SH_GOT10BY4, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT10BY4", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in LD.L, FLD.S et al. */ - HOWTO (R_SH_GOTPLT10BY4, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT10BY4", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in FLD.D, FST.P et al. */ - HOWTO (R_SH_GOT10BY8, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOT10BY8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in FLD.D, FST.P et al. */ - HOWTO (R_SH_GOTPLT10BY8, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 13, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GOTPLT10BY8", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_COPY64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_COPY64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_GLOB_DAT64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_GLOB_DAT64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_JMP_SLOT64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_JMP_SLOT64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_SH_RELATIVE64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_RELATIVE64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (197), - EMPTY_HOWTO (198), - EMPTY_HOWTO (199), - EMPTY_HOWTO (200), - EMPTY_HOWTO (201), - EMPTY_HOWTO (202), - EMPTY_HOWTO (203), - EMPTY_HOWTO (204), - EMPTY_HOWTO (205), - EMPTY_HOWTO (206), - EMPTY_HOWTO (207), - EMPTY_HOWTO (208), - EMPTY_HOWTO (209), - EMPTY_HOWTO (210), - EMPTY_HOWTO (211), - EMPTY_HOWTO (212), - EMPTY_HOWTO (213), - EMPTY_HOWTO (214), - EMPTY_HOWTO (215), - EMPTY_HOWTO (216), - EMPTY_HOWTO (217), - EMPTY_HOWTO (218), - EMPTY_HOWTO (219), - EMPTY_HOWTO (220), - EMPTY_HOWTO (221), - EMPTY_HOWTO (222), - EMPTY_HOWTO (223), - EMPTY_HOWTO (224), - EMPTY_HOWTO (225), - EMPTY_HOWTO (226), - EMPTY_HOWTO (227), - EMPTY_HOWTO (228), - EMPTY_HOWTO (229), - EMPTY_HOWTO (230), - EMPTY_HOWTO (231), - EMPTY_HOWTO (232), - EMPTY_HOWTO (233), - EMPTY_HOWTO (234), - EMPTY_HOWTO (235), - EMPTY_HOWTO (236), - EMPTY_HOWTO (237), - EMPTY_HOWTO (238), - EMPTY_HOWTO (239), - EMPTY_HOWTO (240), - EMPTY_HOWTO (241), - - /* Relocations for SHmedia code. None of these are partial_inplace or - use the field being relocated. */ - - /* The assembler will generate this reloc before a block of SHmedia - instructions. A section should be processed as assuming it contains - data, unless this reloc is seen. Note that a block of SHcompact - instructions are instead preceded by R_SH_CODE. - This is currently not implemented, but should be used for SHmedia - linker relaxation. */ - HOWTO (R_SH_SHMEDIA_CODE, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - sh_elf64_ignore_reloc, /* special_function */ - "R_SH_SHMEDIA_CODE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The assembler will generate this reloc at a PTA or PTB instruction, - and the linker checks the right type of target, or changes a PTA to a - PTB, if the original insn was PT. */ - HOWTO (R_SH_PT_16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_PT_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in unexpanded MOVI. */ - HOWTO (R_SH_IMMS16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMMS16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in SHORI. */ - HOWTO (R_SH_IMMU16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMMU16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (x & 65536). */ - HOWTO (R_SH_IMM_LOW16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_LOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x - $) & 65536). */ - HOWTO (R_SH_IMM_LOW16_PCREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_LOW16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 16) & 65536). */ - HOWTO (R_SH_IMM_MEDLOW16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDLOW16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (((x - $) >> 16) & 65536). */ - HOWTO (R_SH_IMM_MEDLOW16_PCREL, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDLOW16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 32) & 65536). */ - HOWTO (R_SH_IMM_MEDHI16, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (((x - $) >> 32) & 65536). */ - HOWTO (R_SH_IMM_MEDHI16_PCREL, /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_MEDHI16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Used in MOVI and SHORI ((x >> 48) & 65536). */ - HOWTO (R_SH_IMM_HI16, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Used in MOVI and SHORI (((x - $) >> 48) & 65536). */ - HOWTO (R_SH_IMM_HI16_PCREL, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_IMM_HI16_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3fffc00, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* For the .uaquad pseudo. */ - HOWTO (R_SH_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* For the .uaquad pseudo, (x - $). */ - HOWTO (R_SH_64_PCREL, /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_SH_64_PCREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ((bfd_vma) 0) - 1, /* dst_mask */ - TRUE), /* pcrel_offset */ - -}; - -/* This function is used for relocs which are only used for relaxing, - which the linker should otherwise ignore. */ - -static bfd_reloc_status_type -sh_elf64_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, - asymbol *symbol ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, asection *input_section, - bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - if (output_bfd != NULL) - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; -} - -/* This function is used for normal relocs. This used to be like the COFF - function, and is almost certainly incorrect for other ELF targets. - - See sh_elf_reloc in elf32-sh.c for the original. */ - -static bfd_reloc_status_type -sh_elf64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol_in, - void *data, asection *input_section, bfd *output_bfd, - char **error_message ATTRIBUTE_UNUSED) -{ - unsigned long insn; - bfd_vma sym_value; - enum elf_sh_reloc_type r_type; - bfd_vma addr = reloc_entry->address; - bfd_byte *hit_data = addr + (bfd_byte *) data; - - r_type = (enum elf_sh_reloc_type) reloc_entry->howto->type; - - if (output_bfd != NULL) - { - /* Partial linking--do nothing. */ - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (symbol_in != NULL - && bfd_is_und_section (symbol_in->section)) - return bfd_reloc_undefined; - - if (bfd_is_com_section (symbol_in->section)) - sym_value = 0; - else - sym_value = (symbol_in->value + - symbol_in->section->output_section->vma + - symbol_in->section->output_offset); - - switch (r_type) - { - case R_SH_DIR32: - insn = bfd_get_32 (abfd, hit_data); - insn += sym_value + reloc_entry->addend; - bfd_put_32 (abfd, insn, hit_data); - break; - - default: - abort (); - break; - } - - return bfd_reloc_ok; -} - -/* This structure is used to map BFD reloc codes to SH ELF relocs. */ - -struct elf_reloc_map -{ - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -/* An array mapping BFD reloc codes to SH ELF relocs. */ - -static const struct elf_reloc_map sh64_reloc_map[] = -{ - { BFD_RELOC_NONE, R_SH_NONE }, - { BFD_RELOC_32, R_SH_DIR32 }, - { BFD_RELOC_CTOR, R_SH_DIR32 }, - { BFD_RELOC_32_PCREL, R_SH_REL32 }, - { BFD_RELOC_8_PCREL, R_SH_SWITCH8 }, - { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 }, - { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 }, - { BFD_RELOC_VTABLE_INHERIT, R_SH_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_SH_GNU_VTENTRY }, - { BFD_RELOC_SH_GOT_LOW16, R_SH_GOT_LOW16 }, - { BFD_RELOC_SH_GOT_MEDLOW16, R_SH_GOT_MEDLOW16 }, - { BFD_RELOC_SH_GOT_MEDHI16, R_SH_GOT_MEDHI16 }, - { BFD_RELOC_SH_GOT_HI16, R_SH_GOT_HI16 }, - { BFD_RELOC_SH_GOTPLT_LOW16, R_SH_GOTPLT_LOW16 }, - { BFD_RELOC_SH_GOTPLT_MEDLOW16, R_SH_GOTPLT_MEDLOW16 }, - { BFD_RELOC_SH_GOTPLT_MEDHI16, R_SH_GOTPLT_MEDHI16 }, - { BFD_RELOC_SH_GOTPLT_HI16, R_SH_GOTPLT_HI16 }, - { BFD_RELOC_SH_PLT_LOW16, R_SH_PLT_LOW16 }, - { BFD_RELOC_SH_PLT_MEDLOW16, R_SH_PLT_MEDLOW16 }, - { BFD_RELOC_SH_PLT_MEDHI16, R_SH_PLT_MEDHI16 }, - { BFD_RELOC_SH_PLT_HI16, R_SH_PLT_HI16 }, - { BFD_RELOC_SH_GOTOFF_LOW16, R_SH_GOTOFF_LOW16 }, - { BFD_RELOC_SH_GOTOFF_MEDLOW16, R_SH_GOTOFF_MEDLOW16 }, - { BFD_RELOC_SH_GOTOFF_MEDHI16, R_SH_GOTOFF_MEDHI16 }, - { BFD_RELOC_SH_GOTOFF_HI16, R_SH_GOTOFF_HI16 }, - { BFD_RELOC_SH_GOTPC_LOW16, R_SH_GOTPC_LOW16 }, - { BFD_RELOC_SH_GOTPC_MEDLOW16, R_SH_GOTPC_MEDLOW16 }, - { BFD_RELOC_SH_GOTPC_MEDHI16, R_SH_GOTPC_MEDHI16 }, - { BFD_RELOC_SH_GOTPC_HI16, R_SH_GOTPC_HI16 }, - { BFD_RELOC_SH_COPY64, R_SH_COPY64 }, - { BFD_RELOC_SH_GLOB_DAT64, R_SH_GLOB_DAT64 }, - { BFD_RELOC_SH_JMP_SLOT64, R_SH_JMP_SLOT64 }, - { BFD_RELOC_SH_RELATIVE64, R_SH_RELATIVE64 }, - { BFD_RELOC_SH_GOT10BY4, R_SH_GOT10BY4 }, - { BFD_RELOC_SH_GOT10BY8, R_SH_GOT10BY8 }, - { BFD_RELOC_SH_GOTPLT10BY4, R_SH_GOTPLT10BY4 }, - { BFD_RELOC_SH_GOTPLT10BY8, R_SH_GOTPLT10BY8 }, - { BFD_RELOC_SH_PT_16, R_SH_PT_16 }, - { BFD_RELOC_SH_SHMEDIA_CODE, R_SH_SHMEDIA_CODE }, - { BFD_RELOC_SH_IMMU5, R_SH_DIR5U }, - { BFD_RELOC_SH_IMMS6, R_SH_DIR6S }, - { BFD_RELOC_SH_IMMU6, R_SH_DIR6U }, - { BFD_RELOC_SH_IMMS10, R_SH_DIR10S }, - { BFD_RELOC_SH_IMMS10BY2, R_SH_DIR10SW }, - { BFD_RELOC_SH_IMMS10BY4, R_SH_DIR10SL }, - { BFD_RELOC_SH_IMMS10BY8, R_SH_DIR10SQ }, - { BFD_RELOC_SH_IMMS16, R_SH_IMMS16 }, - { BFD_RELOC_SH_IMMU16, R_SH_IMMU16 }, - { BFD_RELOC_SH_IMM_LOW16, R_SH_IMM_LOW16 }, - { BFD_RELOC_SH_IMM_LOW16_PCREL, R_SH_IMM_LOW16_PCREL }, - { BFD_RELOC_SH_IMM_MEDLOW16, R_SH_IMM_MEDLOW16 }, - { BFD_RELOC_SH_IMM_MEDLOW16_PCREL, R_SH_IMM_MEDLOW16_PCREL }, - { BFD_RELOC_SH_IMM_MEDHI16, R_SH_IMM_MEDHI16 }, - { BFD_RELOC_SH_IMM_MEDHI16_PCREL, R_SH_IMM_MEDHI16_PCREL }, - { BFD_RELOC_SH_IMM_HI16, R_SH_IMM_HI16 }, - { BFD_RELOC_SH_IMM_HI16_PCREL, R_SH_IMM_HI16_PCREL }, - { BFD_RELOC_64, R_SH_64 }, - { BFD_RELOC_64_PCREL, R_SH_64_PCREL }, -}; - -/* Given a BFD reloc code, return the howto structure for the - corresponding SH ELf reloc. */ - -static reloc_howto_type * -sh_elf64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - - for (i = 0; i < sizeof (sh64_reloc_map) / sizeof (struct elf_reloc_map); i++) - { - if (sh64_reloc_map[i].bfd_reloc_val == code) - return &sh_elf64_howto_table[(int) sh64_reloc_map[i].elf_reloc_val]; - } - - return NULL; -} - -static reloc_howto_type * -sh_elf64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < sizeof (sh_elf64_howto_table) / sizeof (sh_elf64_howto_table[0]); - i++) - if (sh_elf64_howto_table[i].name != NULL - && strcasecmp (sh_elf64_howto_table[i].name, r_name) == 0) - return &sh_elf64_howto_table[i]; - - return NULL; -} - -/* Given an ELF reloc, fill in the howto field of a relent. - - See sh_elf_info_to_howto in elf32-sh.c for the original. */ - -static void -sh_elf64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned int r; - - r = ELF64_R_TYPE (dst->r_info); - - BFD_ASSERT (r <= (unsigned int) R_SH_64_PCREL); - BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC || r > R_SH_LAST_INVALID_RELOC); - BFD_ASSERT (r < R_SH_DIR8WPN || r > R_SH_LAST_INVALID_RELOC_2); - BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_3 || r > R_SH_GOTPLT32); - BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_4 || r > R_SH_LAST_INVALID_RELOC_4); - - cache_ptr->howto = &sh_elf64_howto_table[r]; -} - -/* Relocate an SH ELF section. - - See sh_elf_info_to_howto in elf32-sh.c for the original. */ - -static bfd_boolean -sh_elf64_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, bfd *input_bfd, - asection *input_section, bfd_byte *contents, - Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, - asection **local_sections) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - Elf_Internal_Rela *rel, *relend; - bfd_vma *local_got_offsets; - asection *sgot; - asection *sgotplt; - asection *splt; - asection *sreloc; - bfd_vma disp, dropped; - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - - sreloc = NULL; - - rel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) - { - int r_type; - reloc_howto_type *howto; - unsigned long r_symndx; - Elf_Internal_Sym *sym; - asection *sec; - struct elf_link_hash_entry *h; - bfd_vma relocation; - bfd_vma addend = (bfd_vma)0; - bfd_reloc_status_type r; - int seen_stt_datalabel = 0; - - r_symndx = ELF64_R_SYM (rel->r_info); - - r_type = ELF64_R_TYPE (rel->r_info); - - if (r_type == (int) R_SH_NONE) - continue; - - if (r_type < 0 - || r_type > R_SH_64_PCREL - || (r_type >= (int) R_SH_FIRST_INVALID_RELOC - && r_type <= (int) R_SH_LAST_INVALID_RELOC) - || (r_type >= (int) R_SH_DIR8WPN - && r_type <= (int) R_SH_LAST_INVALID_RELOC) - || (r_type >= (int) R_SH_GNU_VTINHERIT - && r_type <= (int) R_SH_PSHL) - || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2 - && r_type <= R_SH_GOTPLT32) - || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_4 - && r_type <= (int) R_SH_LAST_INVALID_RELOC_4)) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - howto = sh_elf64_howto_table + r_type; - - h = NULL; - sym = NULL; - sec = NULL; - relocation = 0; - 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) - | ((sym->st_other & STO_SH5_ISA32) != 0)); - - /* A local symbol never has STO_SH5_ISA32, so we don't need - datalabel processing here. Make sure this does not change - without notice. */ - if ((sym->st_other & STO_SH5_ISA32) != 0) - (*info->callbacks->reloc_dangerous) - (info, - _("Unexpected STO_SH5_ISA32 on local symbol is not handled"), - input_bfd, input_section, rel->r_offset); - - if (sec != NULL && discarded_section (sec)) - /* Handled below. */ - ; - else if (bfd_link_relocatable (info)) - { - /* 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 (ELF_ST_TYPE (sym->st_info) == STT_SECTION) - goto final_link_relocate; - - continue; - } - else if (! howto->partial_inplace) - { - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); - relocation |= ((sym->st_other & STO_SH5_ISA32) != 0); - } - else if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) - { - asection *msec; - - if (howto->rightshift || howto->src_mask != 0xffffffff) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): %s relocation against SEC_MERGE section"), - input_bfd, input_section, - rel->r_offset, howto->name); - return FALSE; - } - - addend = bfd_get_32 (input_bfd, contents + rel->r_offset); - msec = sec; - addend = - _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - - relocation; - addend += msec->output_section->vma + msec->output_offset; - bfd_put_32 (input_bfd, addend, contents + rel->r_offset); - addend = 0; - } - } - else - { - /* ??? Could we use the RELOC_FOR_GLOBAL_SYMBOL macro here ? */ - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - { - /* If the reference passes a symbol marked with - STT_DATALABEL, then any STO_SH5_ISA32 on the final value - doesn't count. */ - seen_stt_datalabel |= h->type == STT_DATALABEL; - 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; - /* In these cases, we don't need the relocation value. - We check specially because in some obscure cases - sec->output_section will be NULL. */ - if (r_type == R_SH_GOTPC_LOW16 - || r_type == R_SH_GOTPC_MEDLOW16 - || r_type == R_SH_GOTPC_MEDHI16 - || r_type == R_SH_GOTPC_HI16 - || ((r_type == R_SH_PLT_LOW16 - || r_type == R_SH_PLT_MEDLOW16 - || r_type == R_SH_PLT_MEDHI16 - || r_type == R_SH_PLT_HI16) - && h->plt.offset != (bfd_vma) -1) - || ((r_type == R_SH_GOT_LOW16 - || r_type == R_SH_GOT_MEDLOW16 - || r_type == R_SH_GOT_MEDHI16 - || r_type == R_SH_GOT_HI16) - && elf_hash_table (info)->dynamic_sections_created - && (! bfd_link_pic (info) - || (! info->symbolic && h->dynindx != -1) - || !h->def_regular)) - /* The cases above are those in which relocation is - overwritten in the switch block below. The cases - below are those in which we must defer relocation - to run-time, because we can't resolve absolute - addresses when creating a shared library. */ - || (bfd_link_pic (info) - && ((! info->symbolic && h->dynindx != -1) - || !h->def_regular) - && ((r_type == R_SH_64 - && !(ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN)) - || r_type == R_SH_64_PCREL) - && ((input_section->flags & SEC_ALLOC) != 0 - /* DWARF will emit R_SH_DIR32 relocations in its - sections against symbols defined externally - in shared libraries. We can't do anything - with them here. */ - || (input_section->flags & SEC_DEBUGGING) != 0)) - /* Dynamic relocs are not propagated for SEC_DEBUGGING - sections because such sections are not SEC_ALLOC and - thus ld.so will not process them. */ - || (sec->output_section == NULL - && ((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic))) - ; - else if (sec->output_section != NULL) - relocation = ((h->root.u.def.value - + sec->output_section->vma - + sec->output_offset) - /* A STO_SH5_ISA32 causes a "bitor 1" to the - symbol value, unless we've seen - STT_DATALABEL on the way to it. */ - | ((h->other & STO_SH5_ISA32) != 0 - && ! seen_stt_datalabel)); - else if (!bfd_link_relocatable (info) - && (_bfd_elf_section_offset (output_bfd, info, - input_section, - rel->r_offset) - != (bfd_vma) -1)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - } - } - 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 if (!bfd_link_relocatable (info)) - (*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, rel->r_offset, - (info->unresolved_syms_in_objects == RM_GENERATE_ERROR - || ELF_ST_VISIBILITY (h->other))); - } - - if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, howto, 0, contents); - - if (bfd_link_relocatable (info)) - continue; - - disp = (relocation - - input_section->output_section->vma - - input_section->output_offset - - rel->r_offset); - dropped = 0; - switch ((int)r_type) - { - case R_SH_PT_16: dropped = disp & 2; break; - case R_SH_DIR10SW: dropped = disp & 1; break; - case R_SH_DIR10SL: dropped = disp & 3; break; - case R_SH_DIR10SQ: dropped = disp & 7; break; - } - if (dropped != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: error: unaligned relocation type %d at %08Lx reloc %08Lx"), - input_bfd, (int) r_type, rel->r_offset, - relocation); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - switch ((int)r_type) - { - case R_SH_64: - case R_SH_64_PCREL: - if (bfd_link_pic (info) - && (input_section->flags & SEC_ALLOC) != 0 - && (r_type != R_SH_64_PCREL - || (h != NULL - && h->dynindx != -1 - && (! info->symbolic - || !h->def_regular)))) - { - Elf_Internal_Rela outrel; - bfd_byte *loc; - bfd_boolean skip, relocate; - - /* When generating a shared object, these relocations - are copied into the output file to be resolved at run - time. */ - - if (sreloc == NULL) - { - sreloc = _bfd_elf_get_dynamic_reloc_section - (input_bfd, input_section, /*rela?*/ TRUE); - if (sreloc == NULL) - return FALSE; - } - - skip = FALSE; - relocate = FALSE; - - outrel.r_offset - = _bfd_elf_section_offset (output_bfd, info, - input_section, rel->r_offset); - - if (outrel.r_offset == (bfd_vma) -1) - skip = TRUE; - else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; - - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (skip) - memset (&outrel, 0, sizeof outrel); - else if (r_type == R_SH_64_PCREL) - { - BFD_ASSERT (h != NULL && h->dynindx != -1); - outrel.r_info = ELF64_R_INFO (h->dynindx, R_SH_64_PCREL); - outrel.r_addend = rel->r_addend; - } - else - { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (h == NULL - || ((info->symbolic || h->dynindx == -1) - && h->def_regular)) - { - relocate = TRUE; - outrel.r_info = ELF64_R_INFO (0, R_SH_RELATIVE64); - outrel.r_addend = relocation + rel->r_addend; - } - else - { - BFD_ASSERT (h->dynindx != -1); - outrel.r_info = ELF64_R_INFO (h->dynindx, R_SH_64); - outrel.r_addend = relocation + rel->r_addend; - } - } - - 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; - } - else if (r_type == R_SH_64) - addend = rel->r_addend; - goto final_link_relocate; - - case R_SH_GOTPLT_LOW16: - case R_SH_GOTPLT_MEDLOW16: - case R_SH_GOTPLT_MEDHI16: - case R_SH_GOTPLT_HI16: - case R_SH_GOTPLT10BY4: - case R_SH_GOTPLT10BY8: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - if (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN - || ! bfd_link_pic (info) - || info->symbolic - || h->dynindx == -1 - || h->plt.offset == (bfd_vma) -1 - || h->got.offset != (bfd_vma) -1) - goto force_got; - - /* Relocation is to the entry for this symbol in the global - offset table extension for the procedure linkage table. */ - sgotplt = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgotplt != NULL); - - relocation = (sgotplt->output_offset - + ((h->plt.offset / elf_sh64_sizeof_plt (info) - - 1 + 3) * 8)); - - relocation -= GOT_BIAS; - - goto final_link_relocate; - - force_got: - case R_SH_GOT_LOW16: - case R_SH_GOT_MEDLOW16: - case R_SH_GOT_MEDHI16: - case R_SH_GOT_HI16: - case R_SH_GOT10BY4: - case R_SH_GOT10BY8: - /* Relocation is to the entry for this symbol in the global - offset table. */ - sgot = elf_hash_table (info)->sgot; - BFD_ASSERT (sgot != NULL); - - if (h != NULL) - { - bfd_vma off; - - off = h->got.offset; - if (seen_stt_datalabel) - { - struct elf_sh64_link_hash_entry *hsh; - - hsh = (struct elf_sh64_link_hash_entry *)h; - off = hsh->datalabel_got_offset; - } - BFD_ASSERT (off != (bfd_vma) -1); - - if (! elf_hash_table (info)->dynamic_sections_created - || (bfd_link_pic (info) - && (info->symbolic || h->dynindx == -1 - || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) - && h->def_regular)) - { - /* This is actually a static link, or it is a - -Bsymbolic link and the symbol is defined - locally, or the symbol was forced to be local - because of a version file. We must initialize - this entry in the global offset table. Since the - offset must always be a multiple of 4, we use the - least significant bit to record whether we have - initialized it already. - - When doing a dynamic link, we create a .rela.got - relocation entry to initialize the value. This - is done in the finish_dynamic_symbol routine. */ - if ((off & 1) != 0) - off &= ~1; - else - { - bfd_put_64 (output_bfd, relocation, - sgot->contents + off); - if (seen_stt_datalabel) - { - struct elf_sh64_link_hash_entry *hsh; - - hsh = (struct elf_sh64_link_hash_entry *)h; - hsh->datalabel_got_offset |= 1; - } - else - h->got.offset |= 1; - } - } - - relocation = sgot->output_offset + off; - } - else - { - bfd_vma off; - - if (rel->r_addend) - { - BFD_ASSERT (local_got_offsets != NULL - && (local_got_offsets[symtab_hdr->sh_info - + r_symndx] - != (bfd_vma) -1)); - - off = local_got_offsets[symtab_hdr->sh_info - + r_symndx]; - } - else - { - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); - - off = local_got_offsets[r_symndx]; - } - - /* The offset must always be a multiple of 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, sgot->contents + off); - - if (bfd_link_pic (info)) - { - asection *s; - Elf_Internal_Rela outrel; - bfd_byte *loc; - - s = elf_hash_table (info)->srelgot; - BFD_ASSERT (s != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + off); - outrel.r_info = ELF64_R_INFO (0, R_SH_RELATIVE64); - outrel.r_addend = relocation; - loc = s->contents; - loc += s->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - } - - if (rel->r_addend) - local_got_offsets[symtab_hdr->sh_info + r_symndx] |= 1; - else - local_got_offsets[r_symndx] |= 1; - } - - relocation = sgot->output_offset + off; - } - - relocation -= GOT_BIAS; - - goto final_link_relocate; - - case R_SH_GOTOFF_LOW16: - case R_SH_GOTOFF_MEDLOW16: - case R_SH_GOTOFF_MEDHI16: - case R_SH_GOTOFF_HI16: - /* Relocation is relative to the start of the global offset - table. */ - - sgot = elf_hash_table (info)->sgot; - BFD_ASSERT (sgot != NULL); - - /* Note that sgot->output_offset is not involved in this - calculation. We always want the start of .got. If we - defined _GLOBAL_OFFSET_TABLE in a different way, as is - permitted by the ABI, we might have to change this - calculation. */ - relocation -= sgot->output_section->vma; - - relocation -= GOT_BIAS; - - addend = rel->r_addend; - - goto final_link_relocate; - - case R_SH_GOTPC_LOW16: - case R_SH_GOTPC_MEDLOW16: - case R_SH_GOTPC_MEDHI16: - case R_SH_GOTPC_HI16: - /* Use global offset table as symbol value. */ - - sgot = elf_hash_table (info)->sgot; - BFD_ASSERT (sgot != NULL); - - relocation = sgot->output_section->vma; - - relocation += GOT_BIAS; - - addend = rel->r_addend; - - goto final_link_relocate; - - case R_SH_PLT_LOW16: - case R_SH_PLT_MEDLOW16: - case R_SH_PLT_MEDHI16: - case R_SH_PLT_HI16: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* Resolve a PLT reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL) - goto final_link_relocate; - - if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) - goto final_link_relocate; - - if (h->plt.offset == (bfd_vma) -1) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - goto final_link_relocate; - } - - splt = elf_hash_table (info)->splt; - BFD_ASSERT (splt != NULL); - - relocation = (splt->output_section->vma - + splt->output_offset - + h->plt.offset); - relocation++; - - addend = rel->r_addend; - - goto final_link_relocate; - - case R_SH_DIR32: - case R_SH_SHMEDIA_CODE: - case R_SH_PT_16: - case R_SH_DIR5U: - case R_SH_DIR6S: - case R_SH_DIR6U: - case R_SH_DIR10S: - case R_SH_DIR10SW: - case R_SH_DIR10SL: - case R_SH_DIR10SQ: - case R_SH_IMMS16: - case R_SH_IMMU16: - case R_SH_IMM_LOW16: - case R_SH_IMM_LOW16_PCREL: - case R_SH_IMM_MEDLOW16: - case R_SH_IMM_MEDLOW16_PCREL: - case R_SH_IMM_MEDHI16: - case R_SH_IMM_MEDHI16_PCREL: - case R_SH_IMM_HI16: - case R_SH_IMM_HI16_PCREL: - addend = rel->r_addend; - /* Fall through. */ - case R_SH_REL32: - final_link_relocate: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, addend); - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - - } - - if (r != bfd_reloc_ok) - { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: - { - const char *name; - - if (h != NULL) - name = NULL; - 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); - } - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - } - break; - } - } - } - - return TRUE; -} - -/* This is a version of bfd_generic_get_relocated_section_contents - that uses sh_elf64_relocate_section. - - See sh_elf_relocate_section in elf32-sh.c for the original. */ - -static bfd_byte * -sh_elf64_get_relocated_section_contents (bfd *output_bfd, - struct bfd_link_info *link_info, - struct bfd_link_order *link_order, - bfd_byte *data, - bfd_boolean relocatable, - asymbol **symbols) -{ - Elf_Internal_Shdr *symtab_hdr; - asection *input_section = link_order->u.indirect.section; - bfd *input_bfd = input_section->owner; - asection **sections = NULL; - Elf_Internal_Rela *internal_relocs = NULL; - Elf_Internal_Sym *isymbuf = NULL; - - /* We only need to handle the case of relaxing, or of having a - particular set of section contents, specially. */ - if (relocatable - || elf_section_data (input_section)->this_hdr.contents == NULL) - return bfd_generic_get_relocated_section_contents (output_bfd, link_info, - link_order, data, - relocatable, - symbols); - - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - - memcpy (data, elf_section_data (input_section)->this_hdr.contents, - input_section->size); - - if ((input_section->flags & SEC_RELOC) != 0 - && input_section->reloc_count > 0) - { - Elf_Internal_Sym *isymp; - Elf_Internal_Sym *isymend; - asection **secpp; - - /* Read this BFD's local symbols. */ - if (symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } - - internal_relocs = (_bfd_elf_link_read_relocs - (input_bfd, input_section, NULL, - (Elf_Internal_Rela *) NULL, FALSE)); - if (internal_relocs == NULL) - goto error_return; - - sections = (asection **) bfd_malloc (symtab_hdr->sh_info - * sizeof (asection *)); - if (sections == NULL && symtab_hdr->sh_info > 0) - goto error_return; - - secpp = sections; - isymend = isymbuf + symtab_hdr->sh_info; - for (isymp = isymbuf; isymp < isymend; ++isymp, ++secpp) - { - asection *isec; - - if (isymp->st_shndx == SHN_UNDEF) - isec = bfd_und_section_ptr; - else if (isymp->st_shndx == SHN_ABS) - isec = bfd_abs_section_ptr; - else if (isymp->st_shndx == SHN_COMMON) - isec = bfd_com_section_ptr; - else - isec = bfd_section_from_elf_index (input_bfd, isymp->st_shndx); - - *secpp = isec; - } - - if (! sh_elf64_relocate_section (output_bfd, link_info, input_bfd, - input_section, data, internal_relocs, - isymbuf, sections)) - goto error_return; - - if (sections != NULL) - free (sections); - if (internal_relocs != elf_section_data (input_section)->relocs) - free (internal_relocs); - if (isymbuf != NULL - && (unsigned char *) isymbuf != symtab_hdr->contents) - free (isymbuf); - } - - return data; - - error_return: - if (sections != NULL) - free (sections); - if (internal_relocs != NULL - && internal_relocs != elf_section_data (input_section)->relocs) - free (internal_relocs); - if (isymbuf != NULL - && (unsigned char *) isymbuf != symtab_hdr->contents) - free (isymbuf); - return NULL; -} - -/* Set the SHF_SH5_ISA32 flag for ISA SHmedia code sections. */ - -static bfd_boolean -sh64_elf64_fake_sections (bfd *output_bfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *elf_section_hdr, - asection *asect) -{ - /* Code sections can only contain SH64 code, so mark them as such. */ - if (bfd_get_section_flags (output_bfd, asect) & SEC_CODE) - elf_section_hdr->sh_flags |= SHF_SH5_ISA32; - - return TRUE; -} - -static bfd_boolean -sh_elf64_set_mach_from_flags (bfd *abfd) -{ - flagword flags = elf_elfheader (abfd)->e_flags; - - switch (flags & EF_SH_MACH_MASK) - { - case EF_SH5: - /* Just one, but keep the switch construct to make additions easy. */ - bfd_default_set_arch_mach (abfd, bfd_arch_sh, bfd_mach_sh5); - break; - - default: - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - return TRUE; -} - -/* Function to keep SH64 specific file flags. - - See sh64_elf_set_private_flags in elf32-sh64.c for the original. */ - -static bfd_boolean -sh_elf64_set_private_flags (bfd *abfd, flagword flags) -{ - BFD_ASSERT (! elf_flags_init (abfd) - || elf_elfheader (abfd)->e_flags == flags); - - elf_elfheader (abfd)->e_flags = flags; - elf_flags_init (abfd) = TRUE; - return sh_elf64_set_mach_from_flags (abfd); -} - -/* Copy the SHF_SH5_ISA32 attribute that we keep on all sections with - code, to keep attributes the same as for SHmedia in 32-bit ELF. */ - -static bfd_boolean -sh_elf64_copy_private_data_internal (bfd *ibfd, bfd *obfd) -{ - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - /* Copy object attributes. */ - _bfd_elf_copy_private_bfd_data (ibfd, obfd); - - return sh_elf64_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags); -} - -static bfd_boolean -sh_elf64_copy_private_data (bfd *ibfd, bfd *obfd) -{ - return sh_elf64_copy_private_data_internal (ibfd, obfd); -} - -static bfd_boolean -sh_elf64_merge_private_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - flagword old_flags, new_flags; - - if (! _bfd_generic_verify_endian_match (ibfd, info)) - return FALSE; - - if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - if (bfd_get_arch_size (ibfd) != bfd_get_arch_size (obfd)) - { - const char *msg; - - if (bfd_get_arch_size (ibfd) == 32 - && bfd_get_arch_size (obfd) == 64) - /* xgettext:c-format */ - msg = _("%B: compiled as 32-bit object and %B is 64-bit"); - else if (bfd_get_arch_size (ibfd) == 64 - && bfd_get_arch_size (obfd) == 32) - /* xgettext:c-format */ - msg = _("%B: compiled as 64-bit object and %B is 32-bit"); - else - /* xgettext:c-format */ - msg = _("%B: object size does not match that of target %B"); - - _bfd_error_handler (msg, ibfd, obfd); - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - old_flags = elf_elfheader (obfd)->e_flags; - new_flags = elf_elfheader (ibfd)->e_flags; - if (! elf_flags_init (obfd)) - { - /* This happens when ld starts out with a 'blank' output file. */ - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = old_flags = new_flags; - } - /* We don't allow linking in anything else than SH64 code, and since - this is a 64-bit ELF, we assume the 64-bit ABI is used. Add code - here as things change. */ - else if ((new_flags & EF_SH_MACH_MASK) != EF_SH5) - { - _bfd_error_handler - ("%B: does not use the SH64 64-bit ABI as previous modules do", ibfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - sh_elf64_copy_private_data_internal (ibfd, obfd); - - /* I can't think of anything sane other than old_flags being EF_SH5 and - that we need to preserve that. */ - elf_elfheader (obfd)->e_flags = old_flags; - - return sh_elf64_set_mach_from_flags (obfd); -} - -/* Return the section that should be marked against GC for a given - relocation. */ - -static asection * -sh_elf64_gc_mark_hook (asection *sec, - struct bfd_link_info *info, - Elf_Internal_Rela *rel, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_SH_GNU_VTINHERIT: - case R_SH_GNU_VTENTRY: - return NULL; - } - - return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); -} - -/* Look through the relocs for a section during the first phase. - Since we don't do .gots or .plts, we just need to consider the - virtual table relocs for gc. */ - -static bfd_boolean -sh_elf64_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, const Elf_Internal_Rela *relocs) -{ - Elf_Internal_Shdr *symtab_hdr; - struct elf_link_hash_entry **sym_hashes; - const Elf_Internal_Rela *rel; - const Elf_Internal_Rela *rel_end; - bfd *dynobj; - bfd_vma *local_got_offsets; - asection *sgot; - asection *srelgot; - asection *sreloc; - - sreloc = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - - dynobj = elf_hash_table (info)->dynobj; - local_got_offsets = elf_local_got_offsets (abfd); - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - struct elf_link_hash_entry *h; - unsigned long r_symndx; - - r_symndx = ELF64_R_SYM (rel->r_info); - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - - /* Some relocs require a global offset table. */ - if (dynobj == NULL) - { - switch (ELF64_R_TYPE (rel->r_info)) - { - case R_SH_GOTPLT_LOW16: - case R_SH_GOTPLT_MEDLOW16: - case R_SH_GOTPLT_MEDHI16: - case R_SH_GOTPLT_HI16: - case R_SH_GOTPLT10BY4: - case R_SH_GOTPLT10BY8: - case R_SH_GOT_LOW16: - case R_SH_GOT_MEDLOW16: - case R_SH_GOT_MEDHI16: - case R_SH_GOT_HI16: - case R_SH_GOT10BY4: - case R_SH_GOT10BY8: - case R_SH_GOTOFF_LOW16: - case R_SH_GOTOFF_MEDLOW16: - case R_SH_GOTOFF_MEDHI16: - case R_SH_GOTOFF_HI16: - case R_SH_GOTPC_LOW16: - case R_SH_GOTPC_MEDLOW16: - case R_SH_GOTPC_MEDHI16: - case R_SH_GOTPC_HI16: - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! _bfd_elf_create_got_section (dynobj, info)) - return FALSE; - break; - - default: - break; - } - } - - switch (ELF64_R_TYPE (rel->r_info)) - { - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - case R_SH_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_SH_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; - - force_got: - case R_SH_GOT_LOW16: - case R_SH_GOT_MEDLOW16: - case R_SH_GOT_MEDHI16: - case R_SH_GOT_HI16: - case R_SH_GOT10BY4: - case R_SH_GOT10BY8: - /* This symbol requires a global offset table entry. */ - - sgot = elf_hash_table (info)->sgot; - srelgot = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srelgot != NULL); - - if (h != NULL) - { - if (h->type == STT_DATALABEL) - { - struct elf_sh64_link_hash_entry *hsh; - - h = (struct elf_link_hash_entry *) h->root.u.i.link; - hsh = (struct elf_sh64_link_hash_entry *)h; - if (hsh->datalabel_got_offset != (bfd_vma) -1) - break; - - hsh->datalabel_got_offset = sgot->size; - } - else - { - if (h->got.offset != (bfd_vma) -1) - { - /* We have already allocated space in the .got. */ - break; - } - h->got.offset = sgot->size; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - srelgot->size += sizeof (Elf64_External_Rela); - } - else - { - /* This is a global offset table entry for a local - symbol. */ - if (local_got_offsets == NULL) - { - size_t size; - register unsigned int i; - - size = symtab_hdr->sh_info * sizeof (bfd_vma); - /* Reserve space for both the datalabel and - codelabel local GOT offsets. */ - size *= 2; - local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); - if (local_got_offsets == NULL) - return FALSE; - elf_local_got_offsets (abfd) = local_got_offsets; - for (i = 0; i < symtab_hdr->sh_info; i++) - local_got_offsets[i] = (bfd_vma) -1; - for (; i < 2 * symtab_hdr->sh_info; i++) - local_got_offsets[i] = (bfd_vma) -1; - } - if ((rel->r_addend & 1) != 0) - { - if (local_got_offsets[symtab_hdr->sh_info - + r_symndx] != (bfd_vma) -1) - { - /* We have already allocated space in the .got. */ - break; - } - local_got_offsets[symtab_hdr->sh_info - + r_symndx] = sgot->size; - } - else - { - if (local_got_offsets[r_symndx] != (bfd_vma) -1) - { - /* We have already allocated space in the .got. */ - break; - } - local_got_offsets[r_symndx] = sgot->size; - } - - if (bfd_link_pic (info)) - { - /* If we are generating a shared object, we need to - output a R_SH_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. */ - srelgot->size += sizeof (Elf64_External_Rela); - } - } - - sgot->size += 8; - - break; - - case R_SH_GOTPLT_LOW16: - case R_SH_GOTPLT_MEDLOW16: - case R_SH_GOTPLT_MEDHI16: - case R_SH_GOTPLT_HI16: - case R_SH_GOTPLT10BY4: - case R_SH_GOTPLT10BY8: - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - - if (h == NULL - || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN - || ! bfd_link_pic (info) - || info->symbolic - || h->dynindx == -1 - || h->got.offset != (bfd_vma) -1) - goto force_got; - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - h->needs_plt = 1; - - break; - - case R_SH_PLT_LOW16: - case R_SH_PLT_MEDLOW16: - case R_SH_PLT_MEDHI16: - case R_SH_PLT_HI16: - /* 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; - - if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL - || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) - break; - - h->needs_plt = 1; - - break; - - case R_SH_64: - case R_SH_64_PCREL: - if (h != NULL) - h->non_got_ref = 1; - - /* If we are creating a shared library, and this is a reloc - against a global symbol, or a non PC relative reloc - against a local symbol, then we need to copy the reloc - into the shared library. However, if we are linking with - -Bsymbolic, we do not need to copy a reloc against a - global symbol which is defined in an object we are - including in the link (i.e., DEF_REGULAR is set). At - this point we have not seen all the input files, so it is - possible that DEF_REGULAR is not set now but will be set - later (it is never cleared). We account for that - possibility below by storing information in the - pcrel_relocs_copied field of the hash table entry. */ - if (bfd_link_pic (info) - && (sec->flags & SEC_ALLOC) != 0 - && (ELF32_R_TYPE (rel->r_info) != R_SH_64_PCREL - || (h != NULL - && (! info->symbolic - || !h->def_regular)))) - { - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, dynobj, 2, abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - return FALSE; - } - - sreloc->size += sizeof (Elf64_External_Rela); - - /* If we are linking with -Bsymbolic, and this is a - global symbol, we count the number of PC relative - relocations we have entered for this symbol, so that - we can discard them again if the symbol is later - defined by a regular object. Note that this function - is only called if we are using an elf_sh linker - hash table, which means that h is really a pointer to - an elf_sh_link_hash_entry. */ - if (h != NULL && info->symbolic - && ELF64_R_TYPE (rel->r_info) == R_SH_64_PCREL) - { - struct elf_sh64_link_hash_entry *eh; - struct elf_sh64_pcrel_relocs_copied *p; - - eh = (struct elf_sh64_link_hash_entry *) h; - - for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next) - if (p->section == sreloc) - break; - - if (p == NULL) - { - p = ((struct elf_sh64_pcrel_relocs_copied *) - bfd_alloc (dynobj, sizeof *p)); - if (p == NULL) - return FALSE; - p->next = eh->pcrel_relocs_copied; - eh->pcrel_relocs_copied = p; - p->section = sreloc; - p->count = 0; - } - - ++p->count; - } - } - - break; - } - } - - return TRUE; -} - -static int -sh64_elf64_get_symbol_type (Elf_Internal_Sym * elf_sym, int type) -{ - if (ELF_ST_TYPE (elf_sym->st_info) == STT_DATALABEL) - return STT_DATALABEL; - - return type; -} - -/* FIXME: This is a copy of sh64_elf_add_symbol_hook in elf32-sh64.c. - Either file can presumably exist without the other, but do not differ - in elf-size-ness. How to share? - - Hook called by the linker routine which adds symbols from an object - file. We must make indirect symbols for undefined symbols marked with - STT_DATALABEL, so relocations passing them will pick up that attribute - and neutralize STO_SH5_ISA32 found on the symbol definition. - - There is a problem, though: We want to fill in the hash-table entry for - this symbol and signal to the caller that no further processing is - needed. But we don't have the index for this hash-table entry. We - rely here on that the current entry is the first hash-entry with NULL, - which seems brittle. Also, iterating over the hash-table to find that - entry is a linear operation on the number of symbols in this input - file, and this function should take constant time, so that's not good - too. Only comfort is that DataLabel references should only be found in - hand-written assembly code and thus be rare. FIXME: Talk maintainers - into adding an option to elf_add_symbol_hook (preferably) for the index - or the hash entry, alternatively adding the index to Elf_Internal_Sym - (not so good). */ - -static bfd_boolean -sh64_elf64_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, const char **namep, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp, bfd_vma *valp) -{ - /* We want to do this for relocatable as well as final linking. */ - if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL - && is_elf_hash_table (info->hash)) - { - struct elf_link_hash_entry *h; - - /* For relocatable links, we register the DataLabel sym in its own - right, and tweak the name when it's output. Otherwise, we make - an indirect symbol of it. */ - flagword flags - = bfd_link_relocatable (info) || info->emitrelocations - ? BSF_GLOBAL : BSF_GLOBAL | BSF_INDIRECT; - - char *dl_name - = bfd_malloc (strlen (*namep) + sizeof (DATALABEL_SUFFIX)); - struct elf_link_hash_entry ** sym_hash = elf_sym_hashes (abfd); - - BFD_ASSERT (sym_hash != NULL); - - /* Allocation may fail. */ - if (dl_name == NULL) - return FALSE; - - strcpy (dl_name, *namep); - strcat (dl_name, DATALABEL_SUFFIX); - - h = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (info->hash, dl_name, FALSE, FALSE, FALSE); - - if (h == NULL) - { - /* No previous datalabel symbol. Make one. */ - struct bfd_link_hash_entry *bh = NULL; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - if (! _bfd_generic_link_add_one_symbol (info, abfd, dl_name, - flags, *secp, *valp, - *namep, FALSE, - bed->collect, &bh)) - { - free (dl_name); - return FALSE; - } - - h = (struct elf_link_hash_entry *) bh; - h->non_elf = 0; - h->type = STT_DATALABEL; - } - else - /* If a new symbol was created, it holds the allocated name. - Otherwise, we don't need it anymore and should deallocate it. */ - free (dl_name); - - if (h->type != STT_DATALABEL - || ((bfd_link_relocatable (info) || info->emitrelocations) - && h->root.type != bfd_link_hash_undefined) - || (! bfd_link_relocatable (info) && !info->emitrelocations - && h->root.type != bfd_link_hash_indirect)) - { - /* Make sure we don't get confused on invalid input. */ - _bfd_error_handler - (_("%B: encountered datalabel symbol in input"), abfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Now find the hash-table slot for this entry and fill it in. */ - while (*sym_hash != NULL) - sym_hash++; - *sym_hash = h; - - /* Signal to caller to skip this symbol - we've handled it. */ - *namep = NULL; - } - - return TRUE; -} - -/* This hook function is called before the linker writes out a global - symbol. For relocatable links, DataLabel symbols will be present in - linker output. We cut off the special suffix on those symbols, so the - right name appears in the output. - - When linking and emitting relocations, there can appear global symbols - that are not referenced by relocs, but rather only implicitly through - DataLabel references, a relation that is not visible to the linker. - Since no stripping of global symbols in done when doing such linking, - we don't need to look up and make sure to emit the main symbol for each - DataLabel symbol. */ - -static int -sh64_elf64_link_output_symbol_hook (struct bfd_link_info *info, - const char *cname, - Elf_Internal_Sym *sym, - asection *input_sec ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) -{ - char *name = (char *) cname; - - if (bfd_link_relocatable (info) || info->emitrelocations) - { - if (ELF_ST_TYPE (sym->st_info) == STT_DATALABEL) - name[strlen (name) - strlen (DATALABEL_SUFFIX)] = 0; - } - - return 1; -} - -/* Set bit 0 on the entry address; it always points to SHmedia code. This - is mostly for symmetry with the 32-bit format, where code can be - SHcompact and we need to make a distinction to make sure execution - starts in the right ISA mode. It is also convenient for a loader, - which would otherwise have to set this bit when loading a TR register - before jumping to the program entry. */ - -static void -sh64_elf64_final_write_processing (bfd *abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) -{ - /* FIXME: Perhaps we shouldn't do this if the entry address was supplied - numerically, but we currently lack the infrastructure to recognize - that: The entry symbol, and info whether it is numeric or a symbol - name is kept private in the linker. */ - if (elf_elfheader (abfd)->e_type == ET_EXEC) - elf_elfheader (abfd)->e_entry |= 1; -} - -/* First entry in an absolute procedure linkage table look like this. */ - -static const bfd_byte elf_sh64_plt0_entry_be[PLT_ENTRY_SIZE] = -{ - 0xcc, 0x00, 0x01, 0x10, /* movi .got.plt >> 48, r17 */ - 0xc8, 0x00, 0x01, 0x10, /* shori (.got.plt >> 32) & 65535, r17 */ - 0xc8, 0x00, 0x01, 0x10, /* shori (.got.plt >> 16) & 65535, r17 */ - 0xc8, 0x00, 0x01, 0x10, /* shori .got.plt & 65535, r17 */ - 0x8d, 0x10, 0x09, 0x90, /* ld.q r17, 16, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x8d, 0x10, 0x05, 0x10, /* ld.q r17, 8, r17 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ -}; - -static const bfd_byte elf_sh64_plt0_entry_le[PLT_ENTRY_SIZE] = -{ - 0x10, 0x01, 0x00, 0xcc, /* movi .got.plt >> 16, r17 */ - 0x10, 0x01, 0x00, 0xc8, /* shori (.got.plt >> 32) & 65535, r17 */ - 0x10, 0x01, 0x00, 0xc8, /* shori (.got.plt >> 16) & 65535, r17 */ - 0x10, 0x01, 0x00, 0xc8, /* shori .got.plt & 65535, r17 */ - 0x90, 0x09, 0x10, 0x8d, /* ld.q r17, 16, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0x10, 0x05, 0x10, 0x8d, /* ld.q r17, 8, r17 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ -}; - -/* Sebsequent entries in an absolute procedure linkage table look like - this. */ - -static const bfd_byte elf_sh64_plt_entry_be[PLT_ENTRY_SIZE] = -{ - 0xcc, 0x00, 0x01, 0x90, /* movi nameN-in-GOT >> 48, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori (nameN-in-GOT >> 32) & 65535, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori (nameN-in-GOT >> 16) & 65535, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori nameN-in-GOT & 65535, r25 */ - 0x8d, 0x90, 0x01, 0x90, /* ld.q r25, 0, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0xcc, 0x00, 0x01, 0x90, /* movi (.+8-.PLT0) >> 16, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori (.+4-.PLT0) & 65535, r25 */ - 0x6b, 0xf5, 0x66, 0x00, /* ptrel r25, tr0 */ - 0xcc, 0x00, 0x01, 0x50, /* movi reloc-offset >> 16, r21 */ - 0xc8, 0x00, 0x01, 0x50, /* shori reloc-offset & 65535, r21 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ -}; - -static const bfd_byte elf_sh64_plt_entry_le[PLT_ENTRY_SIZE] = -{ - 0x90, 0x01, 0x00, 0xcc, /* movi nameN-in-GOT >> 16, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori nameN-in-GOT & 65535, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori nameN-in-GOT & 65535, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori nameN-in-GOT & 65535, r25 */ - 0x90, 0x01, 0x90, 0x8d, /* ld.q r25, 0, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0x90, 0x01, 0x00, 0xcc, /* movi (.+8-.PLT0) >> 16, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori (.+4-.PLT0) & 65535, r25 */ - 0x00, 0x66, 0xf5, 0x6b, /* ptrel r25, tr0 */ - 0x50, 0x01, 0x00, 0xcc, /* movi reloc-offset >> 16, r21 */ - 0x50, 0x01, 0x00, 0xc8, /* shori reloc-offset & 65535, r21 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ -}; - -/* Entries in a PIC procedure linkage table look like this. */ - -static const bfd_byte elf_sh64_pic_plt_entry_be[PLT_ENTRY_SIZE] = -{ - 0xcc, 0x00, 0x01, 0x90, /* movi nameN@GOT >> 16, r25 */ - 0xc8, 0x00, 0x01, 0x90, /* shori nameN@GOT & 65535, r25 */ - 0x40, 0xc3, 0x65, 0x90, /* ldx.q r12, r25, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0x6f, 0xf0, 0xff, 0xf0, /* nop */ - 0xce, 0x00, 0x01, 0x10, /* movi -GOT_BIAS, r17 */ - 0x00, 0xc9, 0x45, 0x10, /* add r12, r17, r17 */ - 0x8d, 0x10, 0x09, 0x90, /* ld.q r17, 16, r25 */ - 0x6b, 0xf1, 0x66, 0x00, /* ptabs r25, tr0 */ - 0x8d, 0x10, 0x05, 0x10, /* ld.q r17, 8, r17 */ - 0xcc, 0x00, 0x01, 0x50, /* movi reloc-offset >> 16, r21 */ - 0xc8, 0x00, 0x01, 0x50, /* shori reloc-offset & 65535, r21 */ - 0x44, 0x01, 0xff, 0xf0, /* blink tr0, r63 */ -}; - -static const bfd_byte elf_sh64_pic_plt_entry_le[PLT_ENTRY_SIZE] = -{ - 0x90, 0x01, 0x00, 0xcc, /* movi nameN@GOT >> 16, r25 */ - 0x90, 0x01, 0x00, 0xc8, /* shori nameN@GOT & 65535, r25 */ - 0x90, 0x65, 0xc3, 0x40, /* ldx.q r12, r25, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0xf0, 0xff, 0xf0, 0x6f, /* nop */ - 0x10, 0x01, 0x00, 0xce, /* movi -GOT_BIAS, r17 */ - 0x10, 0x45, 0xc9, 0x00, /* add r12, r17, r17 */ - 0x90, 0x09, 0x10, 0x8d, /* ld.q r17, 16, r25 */ - 0x00, 0x66, 0xf1, 0x6b, /* ptabs r25, tr0 */ - 0x10, 0x05, 0x10, 0x8d, /* ld.q r17, 8, r17 */ - 0x50, 0x01, 0x00, 0xcc, /* movi reloc-offset >> 16, r21 */ - 0x50, 0x01, 0x00, 0xc8, /* shori reloc-offset & 65535, r21 */ - 0xf0, 0xff, 0x01, 0x44, /* blink tr0, r63 */ -}; - -static const bfd_byte *elf_sh64_plt0_entry; -static const bfd_byte *elf_sh64_plt_entry; -static const bfd_byte *elf_sh64_pic_plt_entry; - -/* Create an entry in an sh ELF linker hash table. */ - -static struct bfd_hash_entry * -sh64_elf64_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct elf_sh64_link_hash_entry *ret = - (struct elf_sh64_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == (struct elf_sh64_link_hash_entry *) NULL) - ret = ((struct elf_sh64_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_sh64_link_hash_entry))); - if (ret == (struct elf_sh64_link_hash_entry *) NULL) - return (struct bfd_hash_entry *) ret; - - /* Call the allocation method of the superclass. */ - ret = ((struct elf_sh64_link_hash_entry *) - _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != (struct elf_sh64_link_hash_entry *) NULL) - { - ret->pcrel_relocs_copied = NULL; - ret->datalabel_got_offset = (bfd_vma) -1; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create an sh64 ELF linker hash table. */ - -static struct bfd_link_hash_table * -sh64_elf64_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_table *ret; - - ret = (struct elf_link_hash_table *) bfd_zmalloc (sizeof (* ret)); - if (ret == (struct elf_link_hash_table *) NULL) - return NULL; - - if (!_bfd_elf_link_hash_table_init (ret, abfd, - sh64_elf64_link_hash_newfunc, - sizeof (struct elf_sh64_link_hash_entry), - GENERIC_ELF_DATA)) - { - free (ret); - return NULL; - } - - return &ret->root; -} - -inline static void -movi_shori_putval (bfd *output_bfd, unsigned long value, bfd_byte *addr) -{ - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr) - | ((value >> 6) & 0x3fffc00), - addr); - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr + 4) - | ((value << 10) & 0x3fffc00), - addr + 4); -} - -inline static void -movi_3shori_putval (bfd *output_bfd, bfd_vma value, bfd_byte *addr) -{ - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr) - | ((value >> 38) & 0x3fffc00), - addr); - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr + 4) - | ((value >> 22) & 0x3fffc00), - addr + 4); - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr + 8) - | ((value >> 6) & 0x3fffc00), - addr + 8); - bfd_put_32 (output_bfd, - bfd_get_32 (output_bfd, addr + 12) - | ((value << 10) & 0x3fffc00), - addr + 12); -} - -/* Create dynamic sections when linking against a dynamic object. */ - -static bfd_boolean -sh64_elf64_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) -{ - flagword flags, pltflags; - register asection *s; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - int ptralign = 0; - - switch (bed->s->arch_size) - { - case 32: - ptralign = 2; - break; - - case 64: - ptralign = 3; - break; - - default: - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and - .rel[a].bss sections. */ - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - pltflags = flags; - pltflags |= SEC_CODE; - if (bed->plt_not_loaded) - pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); - if (bed->plt_readonly) - pltflags |= SEC_READONLY; - - s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - - if (bed->want_plt_sym) - { - /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the - .plt section. */ - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh = NULL; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, - (bfd_vma) 0, (const char *) NULL, FALSE, bed->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - elf_hash_table (info)->hplt = h; - - if (bfd_link_pic (info) - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = bfd_make_section_anyway_with_flags (abfd, - bed->default_use_rela_p - ? ".rela.plt" : ".rel.plt", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - - if (! _bfd_elf_create_got_section (abfd, info)) - return FALSE; - - if (bed->want_dynbss) - { - /* The .dynbss section is a place to put symbols which are defined - by dynamic objects, are referenced by regular objects, and are - not functions. We must allocate space for them in the process - image and use a R_*_COPY reloc to tell the dynamic linker to - initialize them at run time. The linker script puts the .dynbss - section into the .bss section of the final image. */ - s = bfd_make_section_anyway_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 (! bfd_link_pic (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->default_use_rela_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, ptralign)) - return FALSE; - } - } - - 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 -sh64_elf64_adjust_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - bfd *dynobj; - asection *s; - - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && (h->needs_plt - || h->is_weakalias - || (h->def_dynamic - && h->ref_regular - && !h->def_regular))); - - /* If this is a function, put it in the procedure linkage table. We - will fill in the contents of the procedure linkage table later, - when we know the address of the .got section. */ - if (h->type == STT_FUNC - || h->needs_plt) - { - if (! bfd_link_pic (info) - && !h->def_dynamic - && !h->ref_dynamic) - { - /* This case can occur if we saw a PLT reloc in an input - file, but the symbol was never referred to by a dynamic - object. In such a case, we don't actually need to build - a procedure linkage table, and we can just do a REL64 - reloc instead. */ - BFD_ASSERT (h->needs_plt); - return TRUE; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = elf_hash_table (info)->splt; - BFD_ASSERT (s != NULL); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->size == 0) - s->size += PLT_ENTRY_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 (! bfd_link_pic (info) - && !h->def_regular) - { - h->root.u.def.section = s; - h->root.u.def.value = s->size; - } - - h->plt.offset = s->size; - - /* Make room for this entry. */ - s->size += elf_sh64_sizeof_plt (info); - - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - - s = elf_hash_table (info)->sgotplt; - BFD_ASSERT (s != NULL); - s->size += 8; - - /* We also need to make an entry in the .rela.plt section. */ - - s = elf_hash_table (info)->srelplt; - BFD_ASSERT (s != NULL); - s->size += sizeof (Elf64_External_Rela); - - return TRUE; - } - - /* 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - h->root.u.def.section = def->root.u.def.section; - h->root.u.def.value = def->root.u.def.value; - return TRUE; - } - - /* This is a reference to a symbol defined by a dynamic object which - is not a function. */ - - /* If we are creating a shared library, we must presume that the - only references to the symbol are via the global offset table. - For such cases we need not do anything here; the relocations will - be handled correctly by relocate_section. */ - if (bfd_link_pic (info)) - 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; - - /* 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. */ - - s = bfd_get_linker_section (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); - - /* We must generate a R_SH_COPY reloc to tell the dynamic linker to - copy the initial value out of the dynamic object and into the - runtime process image. We need to remember the offset into the - .rela.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) - { - asection *srel; - - srel = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (srel != NULL); - srel->size += sizeof (Elf64_External_Rela); - h->needs_copy = 1; - } - - return _bfd_elf_adjust_dynamic_copy (info, h, s); -} - -/* This function is called via sh_elf_link_hash_traverse if we are - creating a shared object with -Bsymbolic. It discards the space - allocated to copy PC relative relocs against symbols which are - defined in regular objects. We allocated space for them in the - check_relocs routine, but we won't fill them in in the - relocate_section routine. */ - -static bfd_boolean -sh64_elf64_discard_copies (struct elf_sh64_link_hash_entry *h, - void *ignore ATTRIBUTE_UNUSED) -{ - struct elf_sh64_pcrel_relocs_copied *s; - - /* We only discard relocs for symbols defined in a regular object. */ - if (!h->root.def_regular) - return TRUE; - - for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) - s->section->size -= s->count * sizeof (Elf64_External_Rela); - - return TRUE; -} - -/* Set the sizes of the dynamic sections. */ - -static bfd_boolean -sh64_elf64_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *s; - bfd_boolean plt; - bfd_boolean relocs; - bfd_boolean reltext; - - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (s != NULL); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; - } - } - else - { - /* We may have created entries in the .rela.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rela.got, - which will cause it to get stripped from the output file - below. */ - s = elf_hash_table (info)->srelgot; - if (s != NULL) - s->size = 0; - } - - /* If this is a -Bsymbolic shared link, then we need to discard all - PC relative relocs against symbols defined in a regular object. - We allocated space for them in the check_relocs routine, but we - will not fill them in in the relocate_section routine. */ - if (bfd_link_pic (info) && info->symbolic) - sh64_elf64_link_hash_traverse (elf_hash_table (info), - sh64_elf64_discard_copies, NULL); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = FALSE; - relocs = FALSE; - reltext = FALSE; - for (s = dynobj->sections; s != NULL; s = s->next) - { - const char *name; - - if ((s->flags & SEC_LINKER_CREATED) == 0) - continue; - - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strcmp (name, ".plt") == 0) - { - /* Remember whether there is a PLT. */ - plt = s->size != 0; - } - else if (CONST_STRNEQ (name, ".rela")) - { - if (s->size != 0) - { - asection *target; - - /* Remember whether there are any reloc sections other - than .rela.plt. */ - if (strcmp (name, ".rela.plt") != 0) - { - const char *outname; - - relocs = TRUE; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL - entry. The entries in the .rela.plt section - really apply to the .got section, which we - created ourselves and so know is not readonly. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 5); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = 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 if (! CONST_STRNEQ (name, ".got") - && strcmp (name, ".dynbss") != 0) - { - /* 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. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - - if (elf_hash_table (info)->dynamic_sections_created) - { - /* Add some entries to the .dynamic section. We fill in the - values later, in sh64_elf64_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. */ - if (bfd_link_executable (info)) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_DEBUG, 0)) - return FALSE; - } - - if (plt) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA) - || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)) - return FALSE; - } - - if (relocs) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_RELAENT, - sizeof (Elf64_External_Rela))) - return FALSE; - } - - if (reltext) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0)) - return FALSE; - } - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -sh64_elf64_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - bfd *dynobj; - - dynobj = elf_hash_table (info)->dynobj; - - if (h->plt.offset != (bfd_vma) -1) - { - asection *splt; - asection *sgot; - asection *srel; - - 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. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = elf_hash_table (info)->splt; - sgot = elf_hash_table (info)->sgotplt; - srel = elf_hash_table (info)->srelplt; - BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); - - /* Get the index in the procedure linkage table which - corresponds to this symbol. This is the index of this symbol - in all the symbols for which we are making plt entries. The - first entry in the procedure linkage table is reserved. */ - plt_index = h->plt.offset / elf_sh64_sizeof_plt (info) - 1; - - /* Get the offset into the .got table of the entry that - corresponds to this function. Each .got entry is 8 bytes. - The first three are reserved. */ - got_offset = (plt_index + 3) * 8; - - if (bfd_link_pic (info)) - got_offset -= GOT_BIAS; - - /* Fill in the entry in the procedure linkage table. */ - if (! bfd_link_pic (info)) - { - if (elf_sh64_plt_entry == NULL) - { - elf_sh64_plt_entry = (bfd_big_endian (output_bfd) ? - elf_sh64_plt_entry_be : elf_sh64_plt_entry_le); - } - memcpy (splt->contents + h->plt.offset, elf_sh64_plt_entry, - elf_sh64_sizeof_plt (info)); - movi_3shori_putval (output_bfd, - (sgot->output_section->vma - + sgot->output_offset - + got_offset), - (splt->contents + h->plt.offset - + elf_sh64_plt_symbol_offset (info))); - - /* Set bottom bit because its for a branch to SHmedia */ - movi_shori_putval (output_bfd, - -(h->plt.offset - + elf_sh64_plt_plt0_offset (info) + 8) - | 1, - (splt->contents + h->plt.offset - + elf_sh64_plt_plt0_offset (info))); - } - else - { - if (elf_sh64_pic_plt_entry == NULL) - { - elf_sh64_pic_plt_entry = (bfd_big_endian (output_bfd) ? - elf_sh64_pic_plt_entry_be : - elf_sh64_pic_plt_entry_le); - } - memcpy (splt->contents + h->plt.offset, elf_sh64_pic_plt_entry, - elf_sh64_sizeof_plt (info)); - movi_shori_putval (output_bfd, got_offset, - (splt->contents + h->plt.offset - + elf_sh64_plt_symbol_offset (info))); - } - - if (bfd_link_pic (info)) - got_offset += GOT_BIAS; - - movi_shori_putval (output_bfd, - plt_index * sizeof (Elf64_External_Rela), - (splt->contents + h->plt.offset - + elf_sh64_plt_reloc_offset (info))); - - /* Fill in the entry in the global offset table. */ - bfd_put_64 (output_bfd, - (splt->output_section->vma - + splt->output_offset - + h->plt.offset - + elf_sh64_plt_temp_offset (info)), - sgot->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + got_offset); - rel.r_info = ELF64_R_INFO (h->dynindx, R_SH_JMP_SLOT64); - rel.r_addend = 0; - rel.r_addend = GOT_BIAS; - loc = srel->contents + plt_index * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_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 alone. */ - sym->st_shndx = SHN_UNDEF; - } - } - - if (h->got.offset != (bfd_vma) -1) - { - asection *sgot; - asection *srel; - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* This symbol has an entry in the global offset table. Set it - up. */ - - sgot = elf_hash_table (info)->sgot; - srel = elf_hash_table (info)->srelgot; - BFD_ASSERT (sgot != NULL && srel != NULL); - - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + (h->got.offset &~ 1)); - - /* If this is a -Bsymbolic link, and the symbol is defined - locally, we just want to emit a RELATIVE reloc. Likewise if - the symbol was forced to be local because of a version file. - The entry in the global offset table will already have been - initialized in the relocate_section function. */ - if (bfd_link_pic (info) - && (info->symbolic || h->dynindx == -1) - && h->def_regular) - { - rel.r_info = ELF64_R_INFO (0, R_SH_RELATIVE64); - rel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); - rel.r_info = ELF64_R_INFO (h->dynindx, R_SH_GLOB_DAT64); - rel.r_addend = 0; - } - - loc = srel->contents; - loc += srel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rel, loc); - } - - if (h->needs_copy) - { - asection *s; - Elf_Internal_Rela rel; - bfd_byte *loc; - - /* This symbol needs a copy reloc. Set it up. */ - - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_linker_section (dynobj, ".rela.bss"); - BFD_ASSERT (s != NULL); - - 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 = ELF64_R_INFO (h->dynindx, R_SH_COPY64); - rel.r_addend = 0; - loc = s->contents; - loc += s->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rel, loc); - } - - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (h == elf_hash_table (info)->hdynamic - || h == elf_hash_table (info)->hgot) - sym->st_shndx = SHN_ABS; - - return TRUE; -} - -/* Finish up the dynamic sections. */ - -static bfd_boolean -sh64_elf64_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - bfd *dynobj; - asection *sgot; - asection *sdyn; - - dynobj = elf_hash_table (info)->dynobj; - - sgot = elf_hash_table (info)->sgotplt; - BFD_ASSERT (sgot != NULL); - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - - if (elf_hash_table (info)->dynamic_sections_created) - { - asection *splt; - Elf64_External_Dyn *dyncon, *dynconend; - - BFD_ASSERT (sdyn != NULL); - - dyncon = (Elf64_External_Dyn *) sdyn->contents; - dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - const char *name; - asection *s; - struct elf_link_hash_entry *h; - - bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - default: - break; - - case DT_INIT: - name = info->init_function; - goto get_sym; - - case DT_FINI: - name = info->fini_function; - get_sym: - if (dyn.d_un.d_val != 0) - { - h = elf_link_hash_lookup (elf_hash_table (info), name, - FALSE, FALSE, TRUE); - if (h != NULL && (h->other & STO_SH5_ISA32)) - { - dyn.d_un.d_val |= 1; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - break; - - case DT_PLTGOT: - s = elf_hash_table (info)->sgotplt; - goto get_vma; - - case DT_JMPREL: - s = elf_hash_table (info)->srelplt; - get_vma: - dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - - case DT_PLTRELSZ: - s = elf_hash_table (info)->srelplt; - dyn.d_un.d_val = s->size; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - break; - } - } - - /* Fill in the first entry in the procedure linkage table. */ - splt = elf_hash_table (info)->splt; - if (splt && splt->size > 0) - { - if (bfd_link_pic (info)) - { - if (elf_sh64_pic_plt_entry == NULL) - { - elf_sh64_pic_plt_entry = (bfd_big_endian (output_bfd) ? - elf_sh64_pic_plt_entry_be : - elf_sh64_pic_plt_entry_le); - } - memcpy (splt->contents, elf_sh64_pic_plt_entry, - elf_sh64_sizeof_plt (info)); - } - else - { - if (elf_sh64_plt0_entry == NULL) - { - elf_sh64_plt0_entry = (bfd_big_endian (output_bfd) ? - elf_sh64_plt0_entry_be : - elf_sh64_plt0_entry_le); - } - memcpy (splt->contents, elf_sh64_plt0_entry, PLT_ENTRY_SIZE); - movi_3shori_putval (output_bfd, - sgot->output_section->vma - + sgot->output_offset, - splt->contents - + elf_sh64_plt0_gotplt_offset (info)); - } - - /* UnixWare sets the entsize of .plt to 8, although that doesn't - really seem like the right value. */ - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 8; - } - } - - /* Fill in the first three entries in the global offset table. */ - if (sgot->size > 0) - { - if (sdyn == NULL) - bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_64 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + 16); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 8; - - return TRUE; -} - -/* Merge non visibility st_other attribute when the symbol comes from - a dynamic object. */ -static void -sh64_elf64_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic ATTRIBUTE_UNUSED) -{ - if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0) - { - unsigned char other; - - /* Take the balance of OTHER from the definition. */ - other = (definition ? isym->st_other : h->other); - other &= ~ ELF_ST_VISIBILITY (-1); - h->other = other | ELF_ST_VISIBILITY (h->other); - } - - return; -} - -static const struct bfd_elf_special_section sh64_elf64_special_sections[]= -{ - { STRING_COMMA_LEN (".cranges"), 0, SHT_PROGBITS, 0 }, - { NULL, 0, 0, 0, 0 } -}; - -#define TARGET_BIG_SYM sh64_elf64_vec -#define TARGET_BIG_NAME "elf64-sh64" -#define TARGET_LITTLE_SYM sh64_elf64_le_vec -#define TARGET_LITTLE_NAME "elf64-sh64l" -#define ELF_ARCH bfd_arch_sh -#define ELF_MACHINE_CODE EM_SH -#define ELF_MAXPAGESIZE 128 - -#define elf_symbol_leading_char '_' - -#define bfd_elf64_bfd_reloc_type_lookup sh_elf64_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup \ - sh_elf64_reloc_name_lookup -#define elf_info_to_howto sh_elf64_info_to_howto - -/* Note: there's no relaxation at present. */ - -#define elf_backend_relocate_section sh_elf64_relocate_section -#define bfd_elf64_bfd_get_relocated_section_contents \ - sh_elf64_get_relocated_section_contents -#define elf_backend_object_p sh_elf64_set_mach_from_flags -#define bfd_elf64_bfd_set_private_flags \ - sh_elf64_set_private_flags -#define bfd_elf64_bfd_copy_private_bfd_data \ - sh_elf64_copy_private_data -#define bfd_elf64_bfd_merge_private_bfd_data \ - sh_elf64_merge_private_data -#define elf_backend_fake_sections sh64_elf64_fake_sections - -#define elf_backend_gc_mark_hook sh_elf64_gc_mark_hook -#define elf_backend_check_relocs sh_elf64_check_relocs - -#define elf_backend_can_gc_sections 1 - -#define elf_backend_get_symbol_type sh64_elf64_get_symbol_type - -#define elf_backend_add_symbol_hook sh64_elf64_add_symbol_hook - -#define elf_backend_link_output_symbol_hook \ - sh64_elf64_link_output_symbol_hook - -#define elf_backend_merge_symbol_attribute \ - sh64_elf64_merge_symbol_attribute - -#define elf_backend_final_write_processing \ - sh64_elf64_final_write_processing - -#define elf_backend_create_dynamic_sections \ - sh64_elf64_create_dynamic_sections -#define bfd_elf64_bfd_link_hash_table_create \ - sh64_elf64_link_hash_table_create -#define elf_backend_adjust_dynamic_symbol \ - sh64_elf64_adjust_dynamic_symbol -#define elf_backend_size_dynamic_sections \ - sh64_elf64_size_dynamic_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_finish_dynamic_symbol \ - sh64_elf64_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - sh64_elf64_finish_dynamic_sections -#define elf_backend_special_sections sh64_elf64_special_sections - -#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 24 -#define elf_backend_dtrel_excludes_plt 1 - -#define elf_backend_linux_prpsinfo64_ugid16 TRUE - -#include "elf64-target.h" - -/* NetBSD support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh64_elf64_nbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-sh64-nbsd" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh64_elf64_nbsd_le_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-sh64l-nbsd" -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x10000 -#undef elf_symbol_leading_char -#define elf_symbol_leading_char 0 - -#define elf64_bed elf64_sh64_nbsd_bed - -#include "elf64-target.h" - -/* Linux support. */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sh64_elf64_linux_be_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-sh64big-linux" -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM sh64_elf64_linux_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-sh64-linux" -#undef elf64_bed -#define elf64_bed elf64_sh64_linux_bed - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-sparc.c b/sdcc/support/sdbinutils/bfd/elf64-sparc.c deleted file mode 100644 index 089636fb5..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-sparc.c +++ /dev/null @@ -1,981 +0,0 @@ -/* SPARC-specific support for 64-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf/sparc.h" -#include "opcode/sparc.h" -#include "elfxx-sparc.h" - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ -#define MINUS_ONE (~ (bfd_vma) 0) - -/* Due to the way how we handle R_SPARC_OLO10, each entry in a SHT_RELA - section can represent up to two relocs, we must tell the user to allocate - more space. */ - -static long -elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) -{ - return (sec->reloc_count * 2 + 1) * sizeof (arelent *); -} - -static long -elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd) -{ - return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 2; -} - -/* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of - them. We cannot use generic elf routines for this, because R_SPARC_OLO10 - has secondary addend in ELF64_R_TYPE_DATA. We handle it as two relocations - for the same location, R_SPARC_LO10 and R_SPARC_13. */ - -static bfd_boolean -elf64_sparc_slurp_one_reloc_table (bfd *abfd, asection *asect, - Elf_Internal_Shdr *rel_hdr, - asymbol **symbols, bfd_boolean dynamic) -{ - void * allocated = NULL; - bfd_byte *native_relocs; - arelent *relent; - unsigned int i; - int entsize; - bfd_size_type count; - arelent *relents; - - 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 = (bfd_byte *) allocated; - - relents = asect->relocation + canon_reloc_count (asect); - - entsize = rel_hdr->sh_entsize; - BFD_ASSERT (entsize == sizeof (Elf64_External_Rela)); - - count = rel_hdr->sh_size / entsize; - - for (i = 0, relent = relents; i < count; - i++, relent++, native_relocs += entsize) - { - Elf_Internal_Rela rela; - unsigned int r_type; - - bfd_elf64_swap_reloca_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 (ELF64_R_SYM (rela.r_info) == STN_UNDEF - /* PR 17512: file: 996185f8. */ - || (!dynamic && ELF64_R_SYM(rela.r_info) > bfd_get_symcount(abfd)) - || (dynamic - && ELF64_R_SYM(rela.r_info) > bfd_get_dynamic_symcount(abfd))) - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - else - { - asymbol **ps, *s; - - ps = symbols + ELF64_R_SYM (rela.r_info) - 1; - s = *ps; - - /* Canonicalize ELF section symbols. FIXME: Why? */ - if ((s->flags & BSF_SECTION_SYM) == 0) - relent->sym_ptr_ptr = ps; - else - relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; - } - - relent->addend = rela.r_addend; - - r_type = ELF64_R_TYPE_ID (rela.r_info); - if (r_type == R_SPARC_OLO10) - { - relent->howto = _bfd_sparc_elf_info_to_howto_ptr (R_SPARC_LO10); - relent[1].address = relent->address; - relent++; - relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; - relent->addend = ELF64_R_TYPE_DATA (rela.r_info); - relent->howto = _bfd_sparc_elf_info_to_howto_ptr (R_SPARC_13); - } - else - relent->howto = _bfd_sparc_elf_info_to_howto_ptr (r_type); - } - - canon_reloc_count (asect) += relent - relents; - - if (allocated != NULL) - free (allocated); - - return TRUE; - - error_return: - if (allocated != NULL) - free (allocated); - return FALSE; -} - -/* Read in and swap the external relocs. */ - -static bfd_boolean -elf64_sparc_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 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; - rel_hdr2 = d->rela.hdr; - - BFD_ASSERT ((rel_hdr && 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; - asect->reloc_count = NUM_SHDR_ENTRIES (rel_hdr); - rel_hdr2 = NULL; - } - - amt = asect->reloc_count; - amt *= 2 * sizeof (arelent); - asect->relocation = (arelent *) bfd_alloc (abfd, amt); - if (asect->relocation == NULL) - return FALSE; - - /* The elf64_sparc_slurp_one_reloc_table routine increments - canon_reloc_count. */ - canon_reloc_count (asect) = 0; - - if (rel_hdr - && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr, symbols, - dynamic)) - return FALSE; - - if (rel_hdr2 - && !elf64_sparc_slurp_one_reloc_table (abfd, asect, rel_hdr2, symbols, - dynamic)) - return FALSE; - - return TRUE; -} - -/* Canonicalize the relocs. */ - -static long -elf64_sparc_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 < canon_reloc_count (section); i++) - *relptr++ = tblptr++; - - *relptr = NULL; - - return canon_reloc_count (section); -} - - -/* Canonicalize the dynamic relocation entries. Note that we return - the dynamic relocations as a single block, although they are - actually associated with particular sections; the interface, which - was designed for SunOS style shared libraries, expects that there - is only one set of dynamic relocs. Any section that was actually - installed in the BFD, and has type SHT_REL or SHT_RELA, and uses - the dynamic symbol table, is considered to be a dynamic reloc - section. */ - -static long -elf64_sparc_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage, - asymbol **syms) -{ - asection *s; - long ret; - - if (elf_dynsymtab (abfd) == 0) - { - bfd_set_error (bfd_error_invalid_operation); - return -1; - } - - ret = 0; - for (s = abfd->sections; s != NULL; s = s->next) - { - if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) - && (elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) - { - arelent *p; - long count, i; - - if (! elf64_sparc_slurp_reloc_table (abfd, s, syms, TRUE)) - return -1; - count = canon_reloc_count (s); - p = s->relocation; - for (i = 0; i < count; i++) - *storage++ = p++; - ret += count; - } - } - - *storage = NULL; - - return ret; -} - -/* Install a new set of internal relocs. */ - -static void -elf64_sparc_set_reloc (bfd *abfd ATTRIBUTE_UNUSED, - asection *asect, - arelent **location, - unsigned int count) -{ - asect->orelocation = location; - canon_reloc_count (asect) = count; -} - -/* Write out the relocs. */ - -static void -elf64_sparc_write_relocs (bfd *abfd, asection *sec, void * data) -{ - bfd_boolean *failedp = (bfd_boolean *) data; - Elf_Internal_Shdr *rela_hdr; - bfd_vma addr_offset; - Elf64_External_Rela *outbound_relocas, *src_rela; - unsigned int idx, count; - asymbol *last_sym = 0; - int last_sym_idx = 0; - - /* 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 (canon_reloc_count (sec) == 0) - return; - - /* We can combine two relocs that refer to the same address - into R_SPARC_OLO10 if first one is R_SPARC_LO10 and the - latter is R_SPARC_13 with no associated symbol. */ - count = 0; - for (idx = 0; idx < canon_reloc_count (sec); idx++) - { - bfd_vma addr; - - ++count; - - addr = sec->orelocation[idx]->address; - if (sec->orelocation[idx]->howto->type == R_SPARC_LO10 - && idx < canon_reloc_count (sec) - 1) - { - arelent *r = sec->orelocation[idx + 1]; - - if (r->howto->type == R_SPARC_13 - && r->address == addr - && bfd_is_abs_section ((*r->sym_ptr_ptr)->section) - && (*r->sym_ptr_ptr)->value == 0) - ++idx; - } - } - - rela_hdr = elf_section_data (sec)->rela.hdr; - - rela_hdr->sh_size = rela_hdr->sh_entsize * 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) - 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... */ - outbound_relocas = (Elf64_External_Rela *) rela_hdr->contents; - src_rela = outbound_relocas; - - for (idx = 0; idx < canon_reloc_count (sec); idx++) - { - Elf_Internal_Rela dst_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; - } - - if (ptr->howto->type == R_SPARC_LO10 - && idx < canon_reloc_count (sec) - 1) - { - arelent *r = sec->orelocation[idx + 1]; - - if (r->howto->type == R_SPARC_13 - && r->address == ptr->address - && bfd_is_abs_section ((*r->sym_ptr_ptr)->section) - && (*r->sym_ptr_ptr)->value == 0) - { - idx++; - dst_rela.r_info - = ELF64_R_INFO (n, ELF64_R_TYPE_INFO (r->addend, - R_SPARC_OLO10)); - } - else - dst_rela.r_info = ELF64_R_INFO (n, R_SPARC_LO10); - } - else - dst_rela.r_info = ELF64_R_INFO (n, ptr->howto->type); - - dst_rela.r_offset = ptr->address + addr_offset; - dst_rela.r_addend = ptr->addend; - - bfd_elf64_swap_reloca_out (abfd, &dst_rela, (bfd_byte *) src_rela); - ++src_rela; - } -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it for STT_REGISTER symbols. */ - -static bfd_boolean -elf64_sparc_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, - Elf_Internal_Sym *sym, const char **namep, - flagword *flagsp ATTRIBUTE_UNUSED, - asection **secp ATTRIBUTE_UNUSED, - bfd_vma *valp ATTRIBUTE_UNUSED) -{ - static const char *const stt_types[] = { "NOTYPE", "OBJECT", "FUNCTION" }; - - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - - if (ELF_ST_TYPE (sym->st_info) == STT_REGISTER) - { - int reg; - struct _bfd_sparc_elf_app_reg *p; - - reg = (int)sym->st_value; - switch (reg & ~1) - { - case 2: reg -= 2; break; - case 6: reg -= 4; break; - default: - _bfd_error_handler - (_("%B: Only registers %%g[2367] can be declared using STT_REGISTER"), - abfd); - return FALSE; - } - - if (info->output_bfd->xvec != abfd->xvec - || (abfd->flags & DYNAMIC) != 0) - { - /* STT_REGISTER only works when linking an elf64_sparc object. - If STT_REGISTER comes from a dynamic object, don't put it into - the output bfd. The dynamic linker will recheck it. */ - *namep = NULL; - return TRUE; - } - - p = _bfd_sparc_elf_hash_table(info)->app_regs + reg; - - if (p->name != NULL && strcmp (p->name, *namep)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("Register %%g%d used incompatibly: %s in %B," - " previously %s in %B"), - (int) sym->st_value, **namep ? *namep : "#scratch", abfd, - *p->name ? p->name : "#scratch", p->abfd); - return FALSE; - } - - if (p->name == NULL) - { - if (**namep) - { - struct elf_link_hash_entry *h; - - h = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (info->hash, *namep, FALSE, FALSE, FALSE); - - if (h != NULL) - { - unsigned char type = h->type; - - if (type > STT_FUNC) - type = 0; - _bfd_error_handler - /* xgettext:c-format */ - (_("Symbol `%s' has differing types: REGISTER in %B," - " previously %s in %B"), - *namep, abfd, stt_types[type], p->abfd); - return FALSE; - } - - p->name = bfd_hash_allocate (&info->hash->table, - strlen (*namep) + 1); - if (!p->name) - return FALSE; - - strcpy (p->name, *namep); - } - else - p->name = ""; - p->bind = ELF_ST_BIND (sym->st_info); - p->abfd = abfd; - p->shndx = sym->st_shndx; - } - else - { - if (p->bind == STB_WEAK - && ELF_ST_BIND (sym->st_info) == STB_GLOBAL) - { - p->bind = STB_GLOBAL; - p->abfd = abfd; - } - } - *namep = NULL; - return TRUE; - } - else if (*namep && **namep - && info->output_bfd->xvec == abfd->xvec) - { - int i; - struct _bfd_sparc_elf_app_reg *p; - - p = _bfd_sparc_elf_hash_table(info)->app_regs; - for (i = 0; i < 4; i++, p++) - if (p->name != NULL && ! strcmp (p->name, *namep)) - { - unsigned char type = ELF_ST_TYPE (sym->st_info); - - if (type > STT_FUNC) - type = 0; - _bfd_error_handler - /* xgettext:c-format */ - (_("Symbol `%s' has differing types: %s in %B," - " previously REGISTER in %B"), - *namep, stt_types[type], abfd, p->abfd); - return FALSE; - } - } - return TRUE; -} - -/* This function takes care of emitting STT_REGISTER symbols - which we cannot easily keep in the symbol hash table. */ - -static bfd_boolean -elf64_sparc_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - void * flaginfo, - int (*func) (void *, const char *, - Elf_Internal_Sym *, - asection *, - struct elf_link_hash_entry *)) -{ - int reg; - struct _bfd_sparc_elf_app_reg *app_regs = - _bfd_sparc_elf_hash_table(info)->app_regs; - Elf_Internal_Sym sym; - - /* We arranged in size_dynamic_sections to put the STT_REGISTER entries - at the end of the dynlocal list, so they came at the end of the local - symbols in the symtab. Except that they aren't STB_LOCAL, so we need - to back up symtab->sh_info. */ - if (elf_hash_table (info)->dynlocal) - { - bfd * dynobj = elf_hash_table (info)->dynobj; - asection *dynsymsec = bfd_get_linker_section (dynobj, ".dynsym"); - struct elf_link_local_dynamic_entry *e; - - for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) - if (e->input_indx == -1) - break; - if (e) - { - elf_section_data (dynsymsec->output_section)->this_hdr.sh_info - = e->dynindx; - } - } - - if (info->strip == strip_all) - return TRUE; - - for (reg = 0; reg < 4; reg++) - if (app_regs [reg].name != NULL) - { - if (info->strip == strip_some - && bfd_hash_lookup (info->keep_hash, - app_regs [reg].name, - FALSE, FALSE) == NULL) - continue; - - sym.st_value = reg < 2 ? reg + 2 : reg + 4; - sym.st_size = 0; - sym.st_other = 0; - sym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER); - sym.st_shndx = app_regs [reg].shndx; - sym.st_target_internal = 0; - if ((*func) (flaginfo, app_regs [reg].name, &sym, - sym.st_shndx == SHN_ABS - ? bfd_abs_section_ptr : bfd_und_section_ptr, - NULL) != 1) - return FALSE; - } - - return TRUE; -} - -static int -elf64_sparc_get_symbol_type (Elf_Internal_Sym *elf_sym, int type) -{ - if (ELF_ST_TYPE (elf_sym->st_info) == STT_REGISTER) - return STT_REGISTER; - else - return type; -} - -/* A STB_GLOBAL,STT_REGISTER symbol should be BSF_GLOBAL - even in SHN_UNDEF section. */ - -static void -elf64_sparc_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym) -{ - elf_symbol_type *elfsym; - - elfsym = (elf_symbol_type *) asym; - if (elfsym->internal_elf_sym.st_info - == ELF_ST_INFO (STB_GLOBAL, STT_REGISTER)) - { - asym->flags |= BSF_GLOBAL; - } -} - - -/* Functions for dealing with the e_flags field. */ - -/* Merge backend specific data from an object file to the output - object file when linking. */ - -static bfd_boolean -elf64_sparc_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) -{ - bfd *obfd = info->output_bfd; - bfd_boolean error; - flagword new_flags, old_flags; - int new_mm, old_mm; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) - return TRUE; - - new_flags = elf_elfheader (ibfd)->e_flags; - old_flags = elf_elfheader (obfd)->e_flags; - - if (!elf_flags_init (obfd)) /* First call, no flags set */ - { - elf_flags_init (obfd) = TRUE; - elf_elfheader (obfd)->e_flags = new_flags; - } - - else if (new_flags == old_flags) /* Compatible flags are ok */ - ; - - else /* Incompatible flags */ - { - error = FALSE; - -#define EF_SPARC_ISA_EXTENSIONS \ - (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3 | EF_SPARC_HAL_R1) - - if ((ibfd->flags & DYNAMIC) != 0) - { - /* We don't want dynamic objects memory ordering and - architecture to have any role. That's what dynamic linker - should do. */ - new_flags &= ~(EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS); - new_flags |= (old_flags - & (EF_SPARCV9_MM | EF_SPARC_ISA_EXTENSIONS)); - } - else - { - /* Choose the highest architecture requirements. */ - old_flags |= (new_flags & EF_SPARC_ISA_EXTENSIONS); - new_flags |= (old_flags & EF_SPARC_ISA_EXTENSIONS); - if ((old_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3)) - && (old_flags & EF_SPARC_HAL_R1)) - { - error = TRUE; - _bfd_error_handler - (_("%B: linking UltraSPARC specific with HAL specific code"), - ibfd); - } - /* Choose the most restrictive memory ordering. */ - old_mm = (old_flags & EF_SPARCV9_MM); - new_mm = (new_flags & EF_SPARCV9_MM); - old_flags &= ~EF_SPARCV9_MM; - new_flags &= ~EF_SPARCV9_MM; - if (new_mm < old_mm) - old_mm = new_mm; - old_flags |= old_mm; - new_flags |= old_mm; - } - - /* Warn about any other mismatches */ - if (new_flags != old_flags) - { - error = TRUE; - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: uses different e_flags (%#x) fields than previous modules (%#x)"), - ibfd, new_flags, old_flags); - } - - elf_elfheader (obfd)->e_flags = old_flags; - - if (error) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - return _bfd_sparc_elf_merge_private_bfd_data (ibfd, info); -} - -/* MARCO: Set the correct entry size for the .stab section. */ - -static bfd_boolean -elf64_sparc_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *hdr ATTRIBUTE_UNUSED, - asection *sec) -{ - const char *name; - - name = bfd_get_section_name (abfd, sec); - - if (strcmp (name, ".stab") == 0) - { - /* Even in the 64bit case the stab entries are only 12 bytes long. */ - elf_section_data (sec)->this_hdr.sh_entsize = 12; - } - - return TRUE; -} - -/* Print a STT_REGISTER symbol to file FILE. */ - -static const char * -elf64_sparc_print_symbol_all (bfd *abfd ATTRIBUTE_UNUSED, void * filep, - asymbol *symbol) -{ - FILE *file = (FILE *) filep; - int reg, type; - - if (ELF_ST_TYPE (((elf_symbol_type *) symbol)->internal_elf_sym.st_info) - != STT_REGISTER) - return NULL; - - reg = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; - type = symbol->flags; - fprintf (file, "REG_%c%c%11s%c%c R", "GOLI" [reg / 8], '0' + (reg & 7), "", - ((type & BSF_LOCAL) - ? (type & BSF_GLOBAL) ? '!' : 'l' - : (type & BSF_GLOBAL) ? 'g' : ' '), - (type & BSF_WEAK) ? 'w' : ' '); - if (symbol->name == NULL || symbol->name [0] == '\0') - return "#scratch"; - else - return symbol->name; -} - -static enum elf_reloc_type_class -elf64_sparc_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - switch ((int) ELF64_R_TYPE (rela->r_info)) - { - case R_SPARC_RELATIVE: - return reloc_class_relative; - case R_SPARC_JMP_SLOT: - return reloc_class_plt; - case R_SPARC_COPY: - return reloc_class_copy; - default: - return reloc_class_normal; - } -} - -/* Relocations in the 64 bit SPARC ELF ABI are more complex than in - standard ELF, because R_SPARC_OLO10 has secondary addend in - ELF64_R_TYPE_DATA field. This structure is used to redirect the - relocation handling routines. */ - -const struct elf_size_info elf64_sparc_size_info = -{ - sizeof (Elf64_External_Ehdr), - sizeof (Elf64_External_Phdr), - sizeof (Elf64_External_Shdr), - sizeof (Elf64_External_Rel), - sizeof (Elf64_External_Rela), - sizeof (Elf64_External_Sym), - sizeof (Elf64_External_Dyn), - sizeof (Elf_External_Note), - 4, /* hash-table entry size. */ - /* Internal relocations per external relocations. - For link purposes we use just 1 internal per - 1 external, for assembly and slurp symbol table - we use 2. */ - 1, - 64, /* arch_size. */ - 3, /* log_file_align. */ - ELFCLASS64, - EV_CURRENT, - bfd_elf64_write_out_phdrs, - bfd_elf64_write_shdrs_and_ehdr, - bfd_elf64_checksum_contents, - elf64_sparc_write_relocs, - bfd_elf64_swap_symbol_in, - bfd_elf64_swap_symbol_out, - elf64_sparc_slurp_reloc_table, - bfd_elf64_slurp_symbol_table, - bfd_elf64_swap_dyn_in, - bfd_elf64_swap_dyn_out, - bfd_elf64_swap_reloc_in, - bfd_elf64_swap_reloc_out, - bfd_elf64_swap_reloca_in, - bfd_elf64_swap_reloca_out -}; - -#define TARGET_BIG_SYM sparc_elf64_vec -#define TARGET_BIG_NAME "elf64-sparc" -#define ELF_ARCH bfd_arch_sparc -#define ELF_MAXPAGESIZE 0x100000 -#define ELF_COMMONPAGESIZE 0x2000 - -/* This is the official ABI value. */ -#define ELF_MACHINE_CODE EM_SPARCV9 - -/* This is the value that we used before the ABI was released. */ -#define ELF_MACHINE_ALT1 EM_OLD_SPARCV9 - -#define elf_backend_reloc_type_class \ - elf64_sparc_reloc_type_class -#define bfd_elf64_get_reloc_upper_bound \ - elf64_sparc_get_reloc_upper_bound -#define bfd_elf64_get_dynamic_reloc_upper_bound \ - elf64_sparc_get_dynamic_reloc_upper_bound -#define bfd_elf64_canonicalize_reloc \ - elf64_sparc_canonicalize_reloc -#define bfd_elf64_canonicalize_dynamic_reloc \ - elf64_sparc_canonicalize_dynamic_reloc -#define bfd_elf64_set_reloc \ - elf64_sparc_set_reloc -#define elf_backend_add_symbol_hook \ - elf64_sparc_add_symbol_hook -#define elf_backend_get_symbol_type \ - elf64_sparc_get_symbol_type -#define elf_backend_symbol_processing \ - elf64_sparc_symbol_processing -#define elf_backend_print_symbol_all \ - elf64_sparc_print_symbol_all -#define elf_backend_output_arch_syms \ - elf64_sparc_output_arch_syms -#define bfd_elf64_bfd_merge_private_bfd_data \ - elf64_sparc_merge_private_bfd_data -#define elf_backend_fake_sections \ - elf64_sparc_fake_sections -#define elf_backend_size_info \ - elf64_sparc_size_info - -#define elf_backend_plt_sym_val \ - _bfd_sparc_elf_plt_sym_val -#define bfd_elf64_bfd_link_hash_table_create \ - _bfd_sparc_elf_link_hash_table_create -#define elf_info_to_howto \ - _bfd_sparc_elf_info_to_howto -#define elf_backend_copy_indirect_symbol \ - _bfd_sparc_elf_copy_indirect_symbol -#define bfd_elf64_bfd_reloc_type_lookup \ - _bfd_sparc_elf_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup \ - _bfd_sparc_elf_reloc_name_lookup -#define bfd_elf64_bfd_relax_section \ - _bfd_sparc_elf_relax_section -#define bfd_elf64_new_section_hook \ - _bfd_sparc_elf_new_section_hook - -#define elf_backend_create_dynamic_sections \ - _bfd_sparc_elf_create_dynamic_sections -#define elf_backend_relocs_compatible \ - _bfd_elf_relocs_compatible -#define elf_backend_check_relocs \ - _bfd_sparc_elf_check_relocs -#define elf_backend_adjust_dynamic_symbol \ - _bfd_sparc_elf_adjust_dynamic_symbol -#define elf_backend_omit_section_dynsym \ - _bfd_sparc_elf_omit_section_dynsym -#define elf_backend_size_dynamic_sections \ - _bfd_sparc_elf_size_dynamic_sections -#define elf_backend_relocate_section \ - _bfd_sparc_elf_relocate_section -#define elf_backend_finish_dynamic_symbol \ - _bfd_sparc_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_sparc_elf_finish_dynamic_sections -#define elf_backend_fixup_symbol \ - _bfd_sparc_elf_fixup_symbol - -#define bfd_elf64_mkobject \ - _bfd_sparc_elf_mkobject -#define elf_backend_object_p \ - _bfd_sparc_elf_object_p -#define elf_backend_gc_mark_hook \ - _bfd_sparc_elf_gc_mark_hook -#define elf_backend_init_index_section \ - _bfd_elf_init_1_index_section - -#define elf_backend_can_gc_sections 1 -#define elf_backend_can_refcount 1 -#define elf_backend_want_got_plt 0 -#define elf_backend_plt_readonly 0 -#define elf_backend_want_plt_sym 1 -#define elf_backend_got_header_size 8 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 - -/* Section 5.2.4 of the ABI specifies a 256-byte boundary for the table. */ -#define elf_backend_plt_alignment 8 - -#include "elf64-target.h" - -/* FreeBSD support */ -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sparc_elf64_fbsd_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-sparc-freebsd" -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf64_bed -#define elf64_bed elf64_sparc_fbsd_bed - -#include "elf64-target.h" - -/* Solaris 2. */ - -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM sparc_elf64_sol2_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elf64-sparc-sol2" - -/* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE - objects won't be recognized. */ -#undef ELF_OSABI - -#undef elf64_bed -#define elf64_bed elf64_sparc_sol2_bed - -/* The 64-bit static TLS arena size is rounded to the nearest 16-byte - boundary. */ -#undef elf_backend_static_tls_alignment -#define elf_backend_static_tls_alignment 16 - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-tilegx.c b/sdcc/support/sdbinutils/bfd/elf64-tilegx.c deleted file mode 100644 index 235be2570..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-tilegx.c +++ /dev/null @@ -1,135 +0,0 @@ -/* TILE-Gx-specific support for 64-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elfxx-tilegx.h" -#include "elf64-tilegx.h" - - -/* Support for core dump NOTE sections. */ - -static bfd_boolean -tilegx_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - if (note->descsz != TILEGX_PRSTATUS_SIZEOF) - return FALSE; - - /* pr_cursig */ - elf_tdata (abfd)->core->signal = - bfd_get_16 (abfd, note->descdata + TILEGX_PRSTATUS_OFFSET_PR_CURSIG); - - /* pr_pid */ - elf_tdata (abfd)->core->pid = - bfd_get_32 (abfd, note->descdata + TILEGX_PRSTATUS_OFFSET_PR_PID); - - /* pr_reg */ - offset = TILEGX_PRSTATUS_OFFSET_PR_REG; - size = TILEGX_GREGSET_T_SIZE; - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -static bfd_boolean -tilegx_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - if (note->descsz != TILEGX_PRPSINFO_SIZEOF) - return FALSE; - - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + TILEGX_PRPSINFO_OFFSET_PR_FNAME, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + TILEGX_PRPSINFO_OFFSET_PR_PSARGS, ELF_PR_PSARGS_SIZE); - - - /* 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; -} - - -#define ELF_ARCH bfd_arch_tilegx -#define ELF_TARGET_ID TILEGX_ELF_DATA -#define ELF_MACHINE_CODE EM_TILEGX -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x10000 - - -#define TARGET_BIG_SYM tilegx_elf64_be_vec -#define TARGET_BIG_NAME "elf64-tilegx-be" -#define TARGET_LITTLE_SYM tilegx_elf64_le_vec -#define TARGET_LITTLE_NAME "elf64-tilegx-le" - -#define elf_backend_reloc_type_class tilegx_reloc_type_class - -#define bfd_elf64_bfd_reloc_name_lookup tilegx_reloc_name_lookup -#define bfd_elf64_bfd_link_hash_table_create tilegx_elf_link_hash_table_create -#define bfd_elf64_bfd_reloc_type_lookup tilegx_reloc_type_lookup -#define bfd_elf64_bfd_merge_private_bfd_data \ - _bfd_tilegx_elf_merge_private_bfd_data - -#define elf_backend_copy_indirect_symbol tilegx_elf_copy_indirect_symbol -#define elf_backend_create_dynamic_sections tilegx_elf_create_dynamic_sections -#define elf_backend_check_relocs tilegx_elf_check_relocs -#define elf_backend_adjust_dynamic_symbol tilegx_elf_adjust_dynamic_symbol -#define elf_backend_omit_section_dynsym tilegx_elf_omit_section_dynsym -#define elf_backend_size_dynamic_sections tilegx_elf_size_dynamic_sections -#define elf_backend_relocate_section tilegx_elf_relocate_section -#define elf_backend_finish_dynamic_symbol tilegx_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections tilegx_elf_finish_dynamic_sections -#define elf_backend_gc_mark_hook tilegx_elf_gc_mark_hook -#define elf_backend_plt_sym_val tilegx_elf_plt_sym_val -#define elf_info_to_howto_rel NULL -#define elf_info_to_howto tilegx_info_to_howto_rela -#define elf_backend_grok_prstatus tilegx_elf_grok_prstatus -#define elf_backend_grok_psinfo tilegx_elf_grok_psinfo -#define elf_backend_additional_program_headers tilegx_additional_program_headers - -#define elf_backend_init_index_section _bfd_elf_init_1_index_section - -#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 -/* Align PLT mod 64 byte L2 line size. */ -#define elf_backend_plt_alignment 6 -#define elf_backend_want_plt_sym 1 -#define elf_backend_got_header_size 8 -#define elf_backend_want_dynrelro 1 -#define elf_backend_rela_normal 1 -#define elf_backend_default_execstack 0 - -#include "elf64-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64-tilegx.h b/sdcc/support/sdbinutils/bfd/elf64-tilegx.h deleted file mode 100644 index 102310acf..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-tilegx.h +++ /dev/null @@ -1,38 +0,0 @@ -/* TILE-Gx-specific support for 64-bit ELF. - Copyright (C) 2011-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _ELF64_TILEGX_H -#define _ELF64_TILEGX_H - -/* This file contains sizes and offsets of Linux data structures. */ - -#define TILEGX_PRSTATUS_SIZEOF 632 -#define TILEGX_PRSTATUS_OFFSET_PR_CURSIG 12 -#define TILEGX_PRSTATUS_OFFSET_PR_PID 32 -#define TILEGX_PRSTATUS_OFFSET_PR_REG 112 - -#define TILEGX_PRPSINFO_SIZEOF 136 -#define TILEGX_PRPSINFO_OFFSET_PR_FNAME 40 -#define TILEGX_PRPSINFO_OFFSET_PR_PSARGS 56 -#define ELF_PR_PSARGS_SIZE 80 - -#define TILEGX_GREGSET_T_SIZE 512 - -#endif /* _ELF64_TILEGX_H */ diff --git a/sdcc/support/sdbinutils/bfd/elf64-x86-64.c b/sdcc/support/sdbinutils/bfd/elf64-x86-64.c deleted file mode 100644 index ba4f47bff..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64-x86-64.c +++ /dev/null @@ -1,5421 +0,0 @@ -/* X86-64 specific support for ELF - Copyright (C) 2000-2018 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public 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 "elfxx-x86.h" -#include "elf-nacl.h" -#include "dwarf2.h" -#include "libiberty.h" - -#include "opcode/i386.h" -#include "elf/x86-64.h" - -#ifdef CORE_HEADER -#include -#include CORE_HEADER -#endif - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ -#define MINUS_ONE (~ (bfd_vma) 0) - -/* Since both 32-bit and 64-bit x86-64 encode relocation type in the - identical manner, we use ELF32_R_TYPE instead of ELF64_R_TYPE to get - relocation type. We also use ELF_ST_TYPE instead of ELF64_ST_TYPE - since they are the same. */ - -/* 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, 3, 0, FALSE, 0, complain_overflow_dont, - bfd_elf_generic_reloc, "R_X86_64_NONE", FALSE, 0x00000000, 0x00000000, - FALSE), - HOWTO(R_X86_64_64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - 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), - HOWTO(R_X86_64_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, - bfd_elf_generic_reloc, "R_X86_64_SIZE32", FALSE, 0xffffffff, 0xffffffff, - FALSE), - HOWTO(R_X86_64_SIZE64, 0, 4, 64, FALSE, 0, complain_overflow_unsigned, - bfd_elf_generic_reloc, "R_X86_64_SIZE64", FALSE, MINUS_ONE, MINUS_ONE, - FALSE), - 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), - HOWTO(R_X86_64_IRELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_X86_64_IRELATIVE", FALSE, MINUS_ONE, - MINUS_ONE, FALSE), - HOWTO(R_X86_64_RELATIVE64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_X86_64_RELATIVE64", FALSE, MINUS_ONE, - MINUS_ONE, FALSE), - HOWTO(R_X86_64_PC32_BND, 0, 2, 32, TRUE, 0, complain_overflow_signed, - bfd_elf_generic_reloc, "R_X86_64_PC32_BND", FALSE, 0xffffffff, 0xffffffff, - TRUE), - HOWTO(R_X86_64_PLT32_BND, 0, 2, 32, TRUE, 0, complain_overflow_signed, - bfd_elf_generic_reloc, "R_X86_64_PLT32_BND", FALSE, 0xffffffff, 0xffffffff, - TRUE), - HOWTO(R_X86_64_GOTPCRELX, 0, 2, 32, TRUE, 0, complain_overflow_signed, - bfd_elf_generic_reloc, "R_X86_64_GOTPCRELX", FALSE, 0xffffffff, - 0xffffffff, TRUE), - HOWTO(R_X86_64_REX_GOTPCRELX, 0, 2, 32, TRUE, 0, complain_overflow_signed, - bfd_elf_generic_reloc, "R_X86_64_REX_GOTPCRELX", FALSE, 0xffffffff, - 0xffffffff, TRUE), - - /* We have a gap in the reloc numbers here. - R_X86_64_standard counts the number up to this point, and - R_X86_64_vt_offset is the value to subtract from a reloc type of - R_X86_64_GNU_VT* to form an index into this table. */ -#define R_X86_64_standard (R_X86_64_REX_GOTPCRELX + 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), - -/* Use complain_overflow_bitfield on R_X86_64_32 for x32. */ - HOWTO(R_X86_64_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, - bfd_elf_generic_reloc, "R_X86_64_32", FALSE, 0xffffffff, 0xffffffff, - FALSE) -}; - -/* Set if a relocation is converted from a GOTPCREL relocation. */ -#define R_X86_64_converted_reloc_bit (1 << 7) - -#define X86_PCREL_TYPE_P(TYPE) \ - ( ((TYPE) == R_X86_64_PC8) \ - || ((TYPE) == R_X86_64_PC16) \ - || ((TYPE) == R_X86_64_PC32) \ - || ((TYPE) == R_X86_64_PC32_BND) \ - || ((TYPE) == R_X86_64_PC64)) - -#define X86_SIZE_TYPE_P(TYPE) \ - ((TYPE) == R_X86_64_SIZE32 || (TYPE) == R_X86_64_SIZE64) - -/* 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_SIZE32, R_X86_64_SIZE32, }, - { BFD_RELOC_SIZE64, R_X86_64_SIZE64, }, - { 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_X86_64_IRELATIVE, R_X86_64_IRELATIVE, }, - { BFD_RELOC_X86_64_PC32_BND, R_X86_64_PC32_BND, }, - { BFD_RELOC_X86_64_PLT32_BND, R_X86_64_PLT32_BND, }, - { BFD_RELOC_X86_64_GOTPCRELX, R_X86_64_GOTPCRELX, }, - { BFD_RELOC_X86_64_REX_GOTPCRELX, R_X86_64_REX_GOTPCRELX, }, - { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, - { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, -}; - -static reloc_howto_type * -elf_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type) -{ - unsigned i; - - if (r_type == (unsigned int) R_X86_64_32) - { - if (ABI_64_P (abfd)) - i = r_type; - else - i = ARRAY_SIZE (x86_64_elf_howto_table) - 1; - } - else 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) - { - /* xgettext:c-format */ - _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 * -elf_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 elf_x86_64_rtype_to_howto (abfd, - x86_64_reloc_map[i].elf_reloc_val); - } - return NULL; -} - -static reloc_howto_type * -elf_x86_64_reloc_name_lookup (bfd *abfd, - const char *r_name) -{ - unsigned int i; - - if (!ABI_64_P (abfd) && strcasecmp (r_name, "R_X86_64_32") == 0) - { - /* Get x32 R_X86_64_32. */ - reloc_howto_type *reloc - = &x86_64_elf_howto_table[ARRAY_SIZE (x86_64_elf_howto_table) - 1]; - BFD_ASSERT (reloc->type == (unsigned int) R_X86_64_32); - return reloc; - } - - for (i = 0; i < ARRAY_SIZE (x86_64_elf_howto_table); i++) - if (x86_64_elf_howto_table[i].name != NULL - && strcasecmp (x86_64_elf_howto_table[i].name, r_name) == 0) - return &x86_64_elf_howto_table[i]; - - return NULL; -} - -/* Given an x86_64 ELF reloc type, fill in an arelent structure. */ - -static void -elf_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, - Elf_Internal_Rela *dst) -{ - unsigned r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - if (r_type != (unsigned int) R_X86_64_GNU_VTINHERIT - && r_type != (unsigned int) R_X86_64_GNU_VTENTRY) - r_type &= ~R_X86_64_converted_reloc_bit; - cache_ptr->howto = elf_x86_64_rtype_to_howto (abfd, r_type); - - BFD_ASSERT (r_type == cache_ptr->howto->type || cache_ptr->howto->type == R_X86_64_NONE); -} - -/* Support for core dump NOTE sections. */ -static bfd_boolean -elf_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - size_t size; - - switch (note->descsz) - { - default: - return FALSE; - - case 296: /* sizeof(istruct elf_prstatus) on Linux/x32 */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 216; - - break; - - 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->lwpid - = 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 -elf_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 124: /* sizeof(struct elf_prpsinfo) on Linux/x32 */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 12); - 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); - break; - - case 136: /* sizeof(struct elf_prpsinfo) on Linux/x86_64 */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 24); - 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; -} - -#ifdef CORE_HEADER -static char * -elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, - int note_type, ...) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - va_list ap; - const char *fname, *psargs; - long pid; - int cursig; - const void *gregs; - - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - va_start (ap, note_type); - fname = va_arg (ap, const char *); - psargs = va_arg (ap, const char *); - va_end (ap); - - if (bed->s->elfclass == ELFCLASS32) - { - prpsinfo32_t data; - 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, "CORE", note_type, - &data, sizeof (data)); - } - else - { - prpsinfo64_t data; - 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, "CORE", note_type, - &data, sizeof (data)); - } - /* NOTREACHED */ - - case NT_PRSTATUS: - va_start (ap, note_type); - pid = va_arg (ap, long); - cursig = va_arg (ap, int); - gregs = va_arg (ap, const void *); - va_end (ap); - - if (bed->s->elfclass == ELFCLASS32) - { - if (bed->elf_machine_code == EM_X86_64) - { - prstatusx32_t prstat; - 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, "CORE", note_type, - &prstat, sizeof (prstat)); - } - else - { - prstatus32_t prstat; - 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, "CORE", note_type, - &prstat, sizeof (prstat)); - } - } - else - { - prstatus64_t prstat; - 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, "CORE", note_type, - &prstat, sizeof (prstat)); - } - } - /* NOTREACHED */ -} -#endif - -/* Functions for the x86-64 ELF linker. */ - -/* 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 lazy procedure linkage table. */ - -#define LAZY_PLT_ENTRY_SIZE 16 - -/* The size in bytes of an entry in the non-lazy procedure linkage - table. */ - -#define NON_LAZY_PLT_ENTRY_SIZE 8 - -/* The first entry in a lazy 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 elf_x86_64_lazy_plt0_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ - 0xff, 0x25, 16, 0, 0, 0, /* jmpq *GOT+16(%rip) */ - 0x0f, 0x1f, 0x40, 0x00 /* nopl 0(%rax) */ -}; - -/* Subsequent entries in a lazy procedure linkage table look like this. */ - -static const bfd_byte elf_x86_64_lazy_plt_entry[LAZY_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 first entry in a lazy procedure linkage table with BND prefix - like this. */ - -static const bfd_byte elf_x86_64_lazy_bnd_plt0_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ - 0xf2, 0xff, 0x25, 16, 0, 0, 0, /* bnd jmpq *GOT+16(%rip) */ - 0x0f, 0x1f, 0 /* nopl (%rax) */ -}; - -/* Subsequent entries for branches with BND prefx in a lazy procedure - linkage table look like this. */ - -static const bfd_byte elf_x86_64_lazy_bnd_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0x68, 0, 0, 0, 0, /* pushq immediate */ - 0xf2, 0xe9, 0, 0, 0, 0, /* bnd jmpq relative */ - 0x0f, 0x1f, 0x44, 0, 0 /* nopl 0(%rax,%rax,1) */ -}; - -/* The first entry in the IBT-enabled lazy procedure linkage table is the - the same as the lazy PLT with BND prefix so that bound registers are - preserved when control is passed to dynamic linker. Subsequent - entries for a IBT-enabled lazy procedure linkage table look like - this. */ - -static const bfd_byte elf_x86_64_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfa, /* endbr64 */ - 0x68, 0, 0, 0, 0, /* pushq immediate */ - 0xf2, 0xe9, 0, 0, 0, 0, /* bnd jmpq relative */ - 0x90 /* nop */ -}; - -/* The first entry in the x32 IBT-enabled lazy procedure linkage table - is the same as the normal lazy PLT. Subsequent entries for an - x32 IBT-enabled lazy procedure linkage table look like this. */ - -static const bfd_byte elf_x32_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfa, /* endbr64 */ - 0x68, 0, 0, 0, 0, /* pushq immediate */ - 0xe9, 0, 0, 0, 0, /* jmpq relative */ - 0x66, 0x90 /* xchg %ax,%ax */ -}; - -/* Entries in the non-lazey procedure linkage table look like this. */ - -static const bfd_byte elf_x86_64_non_lazy_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] = -{ - 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ - 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ - 0x66, 0x90 /* xchg %ax,%ax */ -}; - -/* Entries for branches with BND prefix in the non-lazey procedure - linkage table look like this. */ - -static const bfd_byte elf_x86_64_non_lazy_bnd_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] = -{ - 0xf2, 0xff, 0x25, /* bnd jmpq *name@GOTPC(%rip) */ - 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ - 0x90 /* nop */ -}; - -/* Entries for branches with IBT-enabled in the non-lazey procedure - linkage table look like this. They have the same size as the lazy - PLT entry. */ - -static const bfd_byte elf_x86_64_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfa, /* endbr64 */ - 0xf2, 0xff, 0x25, /* bnd jmpq *name@GOTPC(%rip) */ - 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ - 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopl 0x0(%rax,%rax,1) */ -}; - -/* Entries for branches with IBT-enabled in the x32 non-lazey procedure - linkage table look like this. They have the same size as the lazy - PLT entry. */ - -static const bfd_byte elf_x32_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = -{ - 0xf3, 0x0f, 0x1e, 0xfa, /* endbr64 */ - 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ - 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ - 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */ -}; - -/* .eh_frame covering the lazy .plt section. */ - -static const bfd_byte elf_x86_64_eh_frame_lazy_plt[] = -{ - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x78, /* Data alignment factor */ - 16, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ - DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ - DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 11, /* Block length */ - DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ - DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ - DW_OP_lit15, DW_OP_and, DW_OP_lit11, DW_OP_ge, - DW_OP_lit3, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* .eh_frame covering the lazy BND .plt section. */ - -static const bfd_byte elf_x86_64_eh_frame_lazy_bnd_plt[] = -{ - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x78, /* Data alignment factor */ - 16, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ - DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ - DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 11, /* Block length */ - DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ - DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ - DW_OP_lit15, DW_OP_and, DW_OP_lit5, DW_OP_ge, - DW_OP_lit3, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* .eh_frame covering the lazy .plt section with IBT-enabled. */ - -static const bfd_byte elf_x86_64_eh_frame_lazy_ibt_plt[] = -{ - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x78, /* Data alignment factor */ - 16, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ - DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ - DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 11, /* Block length */ - DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ - DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ - DW_OP_lit15, DW_OP_and, DW_OP_lit10, DW_OP_ge, - DW_OP_lit3, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* .eh_frame covering the x32 lazy .plt section with IBT-enabled. */ - -static const bfd_byte elf_x32_eh_frame_lazy_ibt_plt[] = -{ - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x78, /* Data alignment factor */ - 16, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ - DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ - DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 11, /* Block length */ - DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ - DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ - DW_OP_lit15, DW_OP_and, DW_OP_lit9, DW_OP_ge, - DW_OP_lit3, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* .eh_frame covering the non-lazy .plt section. */ - -static const bfd_byte elf_x86_64_eh_frame_non_lazy_plt[] = -{ -#define PLT_GOT_FDE_LENGTH 20 - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x78, /* Data alignment factor */ - 16, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ - DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_GOT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* the start of non-lazy .plt goes here */ - 0, 0, 0, 0, /* non-lazy .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, - DW_CFA_nop, DW_CFA_nop, DW_CFA_nop -}; - -/* These are the standard parameters. */ -static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt = - { - elf_x86_64_lazy_plt0_entry, /* plt0_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ - elf_x86_64_lazy_plt_entry, /* plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 8, /* plt0_got2_offset */ - 12, /* plt0_got2_insn_end */ - 2, /* plt_got_offset */ - 7, /* plt_reloc_offset */ - 12, /* plt_plt_offset */ - 6, /* plt_got_insn_size */ - LAZY_PLT_ENTRY_SIZE, /* plt_plt_insn_end */ - 6, /* plt_lazy_offset */ - elf_x86_64_lazy_plt0_entry, /* pic_plt0_entry */ - elf_x86_64_lazy_plt_entry, /* pic_plt_entry */ - elf_x86_64_eh_frame_lazy_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_plt = - { - elf_x86_64_non_lazy_plt_entry, /* plt_entry */ - elf_x86_64_non_lazy_plt_entry, /* pic_plt_entry */ - NON_LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt_got_offset */ - 6, /* plt_got_insn_size */ - elf_x86_64_eh_frame_non_lazy_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_bnd_plt = - { - elf_x86_64_lazy_bnd_plt0_entry, /* plt0_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ - elf_x86_64_lazy_bnd_plt_entry, /* plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 1+8, /* plt0_got2_offset */ - 1+12, /* plt0_got2_insn_end */ - 1+2, /* plt_got_offset */ - 1, /* plt_reloc_offset */ - 7, /* plt_plt_offset */ - 1+6, /* plt_got_insn_size */ - 11, /* plt_plt_insn_end */ - 0, /* plt_lazy_offset */ - elf_x86_64_lazy_bnd_plt0_entry, /* pic_plt0_entry */ - elf_x86_64_lazy_bnd_plt_entry, /* pic_plt_entry */ - elf_x86_64_eh_frame_lazy_bnd_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_lazy_bnd_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_bnd_plt = - { - elf_x86_64_non_lazy_bnd_plt_entry, /* plt_entry */ - elf_x86_64_non_lazy_bnd_plt_entry, /* pic_plt_entry */ - NON_LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 1+2, /* plt_got_offset */ - 1+6, /* plt_got_insn_size */ - elf_x86_64_eh_frame_non_lazy_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_ibt_plt = - { - elf_x86_64_lazy_bnd_plt0_entry, /* plt0_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ - elf_x86_64_lazy_ibt_plt_entry, /* plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 1+8, /* plt0_got2_offset */ - 1+12, /* plt0_got2_insn_end */ - 4+1+2, /* plt_got_offset */ - 4+1, /* plt_reloc_offset */ - 4+1+6, /* plt_plt_offset */ - 4+1+6, /* plt_got_insn_size */ - 4+1+5+5, /* plt_plt_insn_end */ - 0, /* plt_lazy_offset */ - elf_x86_64_lazy_bnd_plt0_entry, /* pic_plt0_entry */ - elf_x86_64_lazy_ibt_plt_entry, /* pic_plt_entry */ - elf_x86_64_eh_frame_lazy_ibt_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_lazy_plt_layout elf_x32_lazy_ibt_plt = - { - elf_x86_64_lazy_plt0_entry, /* plt0_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt0_entry_size */ - elf_x32_lazy_ibt_plt_entry, /* plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 8, /* plt0_got2_offset */ - 12, /* plt0_got2_insn_end */ - 4+2, /* plt_got_offset */ - 4+1, /* plt_reloc_offset */ - 4+6, /* plt_plt_offset */ - 4+6, /* plt_got_insn_size */ - 4+5+5, /* plt_plt_insn_end */ - 0, /* plt_lazy_offset */ - elf_x86_64_lazy_plt0_entry, /* pic_plt0_entry */ - elf_x32_lazy_ibt_plt_entry, /* pic_plt_entry */ - elf_x32_eh_frame_lazy_ibt_plt, /* eh_frame_plt */ - sizeof (elf_x32_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_ibt_plt = - { - elf_x86_64_non_lazy_ibt_plt_entry, /* plt_entry */ - elf_x86_64_non_lazy_ibt_plt_entry, /* pic_plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 4+1+2, /* plt_got_offset */ - 4+1+6, /* plt_got_insn_size */ - elf_x86_64_eh_frame_non_lazy_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_non_lazy_plt_layout elf_x32_non_lazy_ibt_plt = - { - elf_x32_non_lazy_ibt_plt_entry, /* plt_entry */ - elf_x32_non_lazy_ibt_plt_entry, /* pic_plt_entry */ - LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ - 4+2, /* plt_got_offset */ - 4+6, /* plt_got_insn_size */ - elf_x86_64_eh_frame_non_lazy_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_backend_data elf_x86_64_arch_bed = - { - is_normal /* os */ - }; - -#define elf_backend_arch_data &elf_x86_64_arch_bed - -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 bfd_boolean -elf32_x86_64_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for an x86-64 elf32 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x64_32); - return TRUE; -} - -/* Return TRUE if the TLS access code sequence support transition - from R_TYPE. */ - -static bfd_boolean -elf_x86_64_check_tls_transition (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - bfd_byte *contents, - Elf_Internal_Shdr *symtab_hdr, - struct elf_link_hash_entry **sym_hashes, - unsigned int r_type, - const Elf_Internal_Rela *rel, - const Elf_Internal_Rela *relend) -{ - unsigned int val; - unsigned long r_symndx; - bfd_boolean largepic = FALSE; - struct elf_link_hash_entry *h; - bfd_vma offset; - struct elf_x86_link_hash_table *htab; - bfd_byte *call; - bfd_boolean indirect_call; - - htab = elf_x86_hash_table (info, X86_64_ELF_DATA); - offset = rel->r_offset; - switch (r_type) - { - case R_X86_64_TLSGD: - case R_X86_64_TLSLD: - if ((rel + 1) >= relend) - return FALSE; - - if (r_type == R_X86_64_TLSGD) - { - /* Check transition from GD access model. For 64bit, only - .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@PLT - or - .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .byte 0x66; rex64 - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - can transit to different access model. For 32bit, only - leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@PLT - or - leaq foo@tlsgd(%rip), %rdi - .byte 0x66; rex64 - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - can transit to different access model. For largepic, - we also support: - leaq foo@tlsgd(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq $r15, %rax - call *%rax - or - leaq foo@tlsgd(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq $rbx, %rax - call *%rax */ - - static const unsigned char leaq[] = { 0x66, 0x48, 0x8d, 0x3d }; - - if ((offset + 12) > sec->size) - return FALSE; - - call = contents + offset + 4; - if (call[0] != 0x66 - || !((call[1] == 0x48 - && call[2] == 0xff - && call[3] == 0x15) - || (call[1] == 0x48 - && call[2] == 0x67 - && call[3] == 0xe8) - || (call[1] == 0x66 - && call[2] == 0x48 - && call[3] == 0xe8))) - { - if (!ABI_64_P (abfd) - || (offset + 19) > sec->size - || offset < 3 - || memcmp (call - 7, leaq + 1, 3) != 0 - || memcmp (call, "\x48\xb8", 2) != 0 - || call[11] != 0x01 - || call[13] != 0xff - || call[14] != 0xd0 - || !((call[10] == 0x48 && call[12] == 0xd8) - || (call[10] == 0x4c && call[12] == 0xf8))) - return FALSE; - largepic = TRUE; - } - else if (ABI_64_P (abfd)) - { - if (offset < 4 - || memcmp (contents + offset - 4, leaq, 4) != 0) - return FALSE; - } - else - { - if (offset < 3 - || memcmp (contents + offset - 3, leaq + 1, 3) != 0) - return FALSE; - } - indirect_call = call[2] == 0xff; - } - else - { - /* Check transition from LD access model. Only - leaq foo@tlsld(%rip), %rdi; - call __tls_get_addr@PLT - or - leaq foo@tlsld(%rip), %rdi; - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - can transit to different access model. For largepic - we also support: - leaq foo@tlsld(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq $r15, %rax - call *%rax - or - leaq foo@tlsld(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq $rbx, %rax - call *%rax */ - - static const unsigned char lea[] = { 0x48, 0x8d, 0x3d }; - - if (offset < 3 || (offset + 9) > sec->size) - return FALSE; - - if (memcmp (contents + offset - 3, lea, 3) != 0) - return FALSE; - - call = contents + offset + 4; - if (!(call[0] == 0xe8 - || (call[0] == 0xff && call[1] == 0x15) - || (call[0] == 0x67 && call[1] == 0xe8))) - { - if (!ABI_64_P (abfd) - || (offset + 19) > sec->size - || memcmp (call, "\x48\xb8", 2) != 0 - || call[11] != 0x01 - || call[13] != 0xff - || call[14] != 0xd0 - || !((call[10] == 0x48 && call[12] == 0xd8) - || (call[10] == 0x4c && call[12] == 0xf8))) - return FALSE; - largepic = TRUE; - } - indirect_call = call[0] == 0xff; - } - - r_symndx = htab->r_sym (rel[1].r_info); - if (r_symndx < symtab_hdr->sh_info) - return FALSE; - - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h == NULL - || !((struct elf_x86_link_hash_entry *) h)->tls_get_addr) - return FALSE; - else - { - r_type = (ELF32_R_TYPE (rel[1].r_info) - & ~R_X86_64_converted_reloc_bit); - if (largepic) - return r_type == R_X86_64_PLTOFF64; - else if (indirect_call) - return r_type == R_X86_64_GOTPCRELX; - else - return (r_type == R_X86_64_PC32 || r_type == R_X86_64_PLT32); - } - - case R_X86_64_GOTTPOFF: - /* Check transition from IE access model: - mov foo@gottpoff(%rip), %reg - add foo@gottpoff(%rip), %reg - */ - - /* Check REX prefix first. */ - if (offset >= 3 && (offset + 4) <= sec->size) - { - val = bfd_get_8 (abfd, contents + offset - 3); - if (val != 0x48 && val != 0x4c) - { - /* X32 may have 0x44 REX prefix or no REX prefix. */ - if (ABI_64_P (abfd)) - return FALSE; - } - } - else - { - /* X32 may not have any REX prefix. */ - if (ABI_64_P (abfd)) - return FALSE; - if (offset < 2 || (offset + 3) > sec->size) - return FALSE; - } - - val = bfd_get_8 (abfd, contents + offset - 2); - if (val != 0x8b && val != 0x03) - return FALSE; - - val = bfd_get_8 (abfd, contents + offset - 1); - return (val & 0xc7) == 5; - - case R_X86_64_GOTPC32_TLSDESC: - /* Check transition from GDesc access model: - leaq x@tlsdesc(%rip), %rax - - 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. */ - - if (offset < 3 || (offset + 4) > sec->size) - return FALSE; - - val = bfd_get_8 (abfd, contents + offset - 3); - if ((val & 0xfb) != 0x48) - return FALSE; - - if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d) - return FALSE; - - val = bfd_get_8 (abfd, contents + offset - 1); - return (val & 0xc7) == 0x05; - - case R_X86_64_TLSDESC_CALL: - /* Check transition from GDesc access model: - call *x@tlsdesc(%rax) - */ - if (offset + 2 <= sec->size) - { - /* Make sure that it's a call *x@tlsdesc(%rax). */ - call = contents + offset; - return call[0] == 0xff && call[1] == 0x10; - } - - return FALSE; - - default: - abort (); - } -} - -/* Return TRUE if the TLS access transition is OK or no transition - will be performed. Update R_TYPE if there is a transition. */ - -static bfd_boolean -elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, - asection *sec, bfd_byte *contents, - Elf_Internal_Shdr *symtab_hdr, - struct elf_link_hash_entry **sym_hashes, - unsigned int *r_type, int tls_type, - const Elf_Internal_Rela *rel, - const Elf_Internal_Rela *relend, - struct elf_link_hash_entry *h, - unsigned long r_symndx, - bfd_boolean from_relocate_section) -{ - unsigned int from_type = *r_type; - unsigned int to_type = from_type; - bfd_boolean check = TRUE; - - /* Skip TLS transition for functions. */ - if (h != NULL - && (h->type == STT_FUNC - || h->type == STT_GNU_IFUNC)) - return TRUE; - - switch (from_type) - { - case R_X86_64_TLSGD: - case R_X86_64_GOTPC32_TLSDESC: - case R_X86_64_TLSDESC_CALL: - case R_X86_64_GOTTPOFF: - if (bfd_link_executable (info)) - { - if (h == NULL) - to_type = R_X86_64_TPOFF32; - else - to_type = R_X86_64_GOTTPOFF; - } - - /* When we are called from elf_x86_64_relocate_section, there may - be additional transitions based on TLS_TYPE. */ - if (from_relocate_section) - { - unsigned int new_to_type = to_type; - - if (TLS_TRANSITION_IE_TO_LE_P (info, h, tls_type)) - new_to_type = R_X86_64_TPOFF32; - - if (to_type == R_X86_64_TLSGD - || to_type == R_X86_64_GOTPC32_TLSDESC - || to_type == R_X86_64_TLSDESC_CALL) - { - if (tls_type == GOT_TLS_IE) - new_to_type = R_X86_64_GOTTPOFF; - } - - /* We checked the transition before when we were called from - elf_x86_64_check_relocs. We only want to check the new - transition which hasn't been checked before. */ - check = new_to_type != to_type && from_type == to_type; - to_type = new_to_type; - } - - break; - - case R_X86_64_TLSLD: - if (bfd_link_executable (info)) - to_type = R_X86_64_TPOFF32; - break; - - default: - return TRUE; - } - - /* Return TRUE if there is no transition. */ - if (from_type == to_type) - return TRUE; - - /* Check if the transition can be performed. */ - if (check - && ! elf_x86_64_check_tls_transition (abfd, info, sec, contents, - symtab_hdr, sym_hashes, - from_type, rel, relend)) - { - reloc_howto_type *from, *to; - const char *name; - - from = elf_x86_64_rtype_to_howto (abfd, from_type); - to = elf_x86_64_rtype_to_howto (abfd, to_type); - - if (h) - name = h->root.root.string; - else - { - struct elf_x86_link_hash_table *htab; - - htab = elf_x86_hash_table (info, X86_64_ELF_DATA); - if (htab == NULL) - name = "*unknown*"; - else - { - Elf_Internal_Sym *isym; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); - } - } - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: TLS transition from %s to %s against `%s' at %#Lx " - "in section `%A' failed"), - abfd, from->name, to->name, name, rel->r_offset, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - *r_type = to_type; - return TRUE; -} - -/* Rename some of the generic section flags to better document how they - are used here. */ -#define check_relocs_failed sec_flg0 - -static bfd_boolean -elf_x86_64_need_pic (struct bfd_link_info *info, - bfd *input_bfd, asection *sec, - struct elf_link_hash_entry *h, - Elf_Internal_Shdr *symtab_hdr, - Elf_Internal_Sym *isym, - reloc_howto_type *howto) -{ - const char *v = ""; - const char *und = ""; - const char *pic = ""; - const char *object; - - const char *name; - if (h) - { - name = h->root.root.string; - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_HIDDEN: - v = _("hidden symbol "); - break; - case STV_INTERNAL: - v = _("internal symbol "); - break; - case STV_PROTECTED: - v = _("protected symbol "); - break; - default: - if (((struct elf_x86_link_hash_entry *) h)->def_protected) - v = _("protected symbol "); - else - v = _("symbol "); - pic = _("; recompile with -fPIC"); - break; - } - - if (!h->def_regular && !h->def_dynamic) - und = _("undefined "); - } - else - { - name = bfd_elf_sym_name (input_bfd, symtab_hdr, isym, NULL); - pic = _("; recompile with -fPIC"); - } - - if (bfd_link_dll (info)) - object = _("a shared object"); - else if (bfd_link_pie (info)) - object = _("a PIE object"); - else - object = _("a PDE object"); - - /* xgettext:c-format */ - _bfd_error_handler (_("%B: relocation %s against %s%s`%s' can " - "not be used when making %s%s"), - input_bfd, howto->name, und, v, name, - object, pic); - bfd_set_error (bfd_error_bad_value); - sec->check_relocs_failed = 1; - return FALSE; -} - -/* With the local symbol, foo, we convert - mov foo@GOTPCREL(%rip), %reg - to - lea foo(%rip), %reg - and convert - call/jmp *foo@GOTPCREL(%rip) - to - nop call foo/jmp foo nop - When PIC is false, convert - test %reg, foo@GOTPCREL(%rip) - to - test $foo, %reg - and convert - binop foo@GOTPCREL(%rip), %reg - to - binop $foo, %reg - where binop is one of adc, add, and, cmp, or, sbb, sub, xor - instructions. */ - -static bfd_boolean -elf_x86_64_convert_load_reloc (bfd *abfd, - bfd_byte *contents, - unsigned int *r_type_p, - Elf_Internal_Rela *irel, - struct elf_link_hash_entry *h, - bfd_boolean *converted, - struct bfd_link_info *link_info) -{ - struct elf_x86_link_hash_table *htab; - bfd_boolean is_pic; - bfd_boolean no_overflow; - bfd_boolean relocx; - bfd_boolean to_reloc_pc32; - asection *tsec; - bfd_signed_vma raddend; - unsigned int opcode; - unsigned int modrm; - unsigned int r_type = *r_type_p; - unsigned int r_symndx; - bfd_vma roff = irel->r_offset; - - if (roff < (r_type == R_X86_64_REX_GOTPCRELX ? 3 : 2)) - return TRUE; - - raddend = irel->r_addend; - /* Addend for 32-bit PC-relative relocation must be -4. */ - if (raddend != -4) - return TRUE; - - htab = elf_x86_hash_table (link_info, X86_64_ELF_DATA); - is_pic = bfd_link_pic (link_info); - - relocx = (r_type == R_X86_64_GOTPCRELX - || r_type == R_X86_64_REX_GOTPCRELX); - - /* TRUE if --no-relax is used. */ - no_overflow = link_info->disable_target_specific_optimizations > 1; - - r_symndx = htab->r_sym (irel->r_info); - - opcode = bfd_get_8 (abfd, contents + roff - 2); - - /* Convert mov to lea since it has been done for a while. */ - if (opcode != 0x8b) - { - /* Only convert R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX - for call, jmp or one of adc, add, and, cmp, or, sbb, sub, - test, xor instructions. */ - if (!relocx) - return TRUE; - } - - /* We convert only to R_X86_64_PC32: - 1. Branch. - 2. R_X86_64_GOTPCREL since we can't modify REX byte. - 3. no_overflow is true. - 4. PIC. - */ - to_reloc_pc32 = (opcode == 0xff - || !relocx - || no_overflow - || is_pic); - - /* Get the symbol referred to by the reloc. */ - if (h == NULL) - { - Elf_Internal_Sym *isym - = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); - - /* Skip relocation against undefined symbols. */ - if (isym->st_shndx == SHN_UNDEF) - return TRUE; - - if (isym->st_shndx == SHN_ABS) - tsec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - tsec = bfd_com_section_ptr; - else if (isym->st_shndx == SHN_X86_64_LCOMMON) - tsec = &_bfd_elf_large_com_section; - else - tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); - } - else - { - /* Undefined weak symbol is only bound locally in executable - and its reference is resolved as 0 without relocation - overflow. We can only perform this optimization for - GOTPCRELX relocations since we need to modify REX byte. - It is OK convert mov with R_X86_64_GOTPCREL to - R_X86_64_PC32. */ - bfd_boolean local_ref; - struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h); - - /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P. */ - local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h); - if ((relocx || opcode == 0x8b) - && (h->root.type == bfd_link_hash_undefweak - && !eh->linker_def - && local_ref)) - { - if (opcode == 0xff) - { - /* Skip for branch instructions since R_X86_64_PC32 - may overflow. */ - if (no_overflow) - return TRUE; - } - else if (relocx) - { - /* For non-branch instructions, we can convert to - R_X86_64_32/R_X86_64_32S since we know if there - is a REX byte. */ - to_reloc_pc32 = FALSE; - } - - /* Since we don't know the current PC when PIC is true, - we can't convert to R_X86_64_PC32. */ - if (to_reloc_pc32 && is_pic) - return TRUE; - - goto convert; - } - /* Avoid optimizing GOTPCREL relocations againt _DYNAMIC since - ld.so may use its link-time address. */ - else if (h->start_stop - || eh->linker_def - || ((h->def_regular - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h != htab->elf.hdynamic - && local_ref)) - { - /* bfd_link_hash_new or bfd_link_hash_undefined is - set by an assignment in a linker script in - bfd_elf_record_link_assignment. start_stop is set - on __start_SECNAME/__stop_SECNAME which mark section - SECNAME. */ - if (h->start_stop - || eh->linker_def - || (h->def_regular - && (h->root.type == bfd_link_hash_new - || h->root.type == bfd_link_hash_undefined - || ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section == bfd_und_section_ptr)))) - { - /* Skip since R_X86_64_32/R_X86_64_32S may overflow. */ - if (no_overflow) - return TRUE; - goto convert; - } - tsec = h->root.u.def.section; - } - else - return TRUE; - } - - /* Don't convert GOTPCREL relocation against large section. */ - if (elf_section_data (tsec) != NULL - && (elf_section_flags (tsec) & SHF_X86_64_LARGE) != 0) - return TRUE; - - /* Skip since R_X86_64_PC32/R_X86_64_32/R_X86_64_32S may overflow. */ - if (no_overflow) - return TRUE; - -convert: - if (opcode == 0xff) - { - /* We have "call/jmp *foo@GOTPCREL(%rip)". */ - unsigned int nop; - unsigned int disp; - bfd_vma nop_offset; - - /* Convert R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX to - R_X86_64_PC32. */ - modrm = bfd_get_8 (abfd, contents + roff - 1); - if (modrm == 0x25) - { - /* Convert to "jmp foo nop". */ - modrm = 0xe9; - nop = NOP_OPCODE; - nop_offset = irel->r_offset + 3; - disp = bfd_get_32 (abfd, contents + irel->r_offset); - irel->r_offset -= 1; - bfd_put_32 (abfd, disp, contents + irel->r_offset); - } - else - { - struct elf_x86_link_hash_entry *eh - = (struct elf_x86_link_hash_entry *) h; - - /* Convert to "nop call foo". ADDR_PREFIX_OPCODE - is a nop prefix. */ - modrm = 0xe8; - /* To support TLS optimization, always use addr32 prefix for - "call *__tls_get_addr@GOTPCREL(%rip)". */ - if (eh && eh->tls_get_addr) - { - nop = 0x67; - nop_offset = irel->r_offset - 2; - } - else - { - nop = link_info->call_nop_byte; - if (link_info->call_nop_as_suffix) - { - nop_offset = irel->r_offset + 3; - disp = bfd_get_32 (abfd, contents + irel->r_offset); - irel->r_offset -= 1; - bfd_put_32 (abfd, disp, contents + irel->r_offset); - } - else - nop_offset = irel->r_offset - 2; - } - } - bfd_put_8 (abfd, nop, contents + nop_offset); - bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1); - r_type = R_X86_64_PC32; - } - else - { - unsigned int rex; - unsigned int rex_mask = REX_R; - - if (r_type == R_X86_64_REX_GOTPCRELX) - rex = bfd_get_8 (abfd, contents + roff - 3); - else - rex = 0; - - if (opcode == 0x8b) - { - if (to_reloc_pc32) - { - /* Convert "mov foo@GOTPCREL(%rip), %reg" to - "lea foo(%rip), %reg". */ - opcode = 0x8d; - r_type = R_X86_64_PC32; - } - else - { - /* Convert "mov foo@GOTPCREL(%rip), %reg" to - "mov $foo, %reg". */ - opcode = 0xc7; - modrm = bfd_get_8 (abfd, contents + roff - 1); - modrm = 0xc0 | (modrm & 0x38) >> 3; - if ((rex & REX_W) != 0 - && ABI_64_P (link_info->output_bfd)) - { - /* Keep the REX_W bit in REX byte for LP64. */ - r_type = R_X86_64_32S; - goto rewrite_modrm_rex; - } - else - { - /* If the REX_W bit in REX byte isn't needed, - use R_X86_64_32 and clear the W bit to avoid - sign-extend imm32 to imm64. */ - r_type = R_X86_64_32; - /* Clear the W bit in REX byte. */ - rex_mask |= REX_W; - goto rewrite_modrm_rex; - } - } - } - else - { - /* R_X86_64_PC32 isn't supported. */ - if (to_reloc_pc32) - return TRUE; - - modrm = bfd_get_8 (abfd, contents + roff - 1); - if (opcode == 0x85) - { - /* Convert "test %reg, foo@GOTPCREL(%rip)" to - "test $foo, %reg". */ - modrm = 0xc0 | (modrm & 0x38) >> 3; - opcode = 0xf7; - } - else - { - /* Convert "binop foo@GOTPCREL(%rip), %reg" to - "binop $foo, %reg". */ - modrm = 0xc0 | (modrm & 0x38) >> 3 | (opcode & 0x3c); - opcode = 0x81; - } - - /* Use R_X86_64_32 with 32-bit operand to avoid relocation - overflow when sign-extending imm32 to imm64. */ - r_type = (rex & REX_W) != 0 ? R_X86_64_32S : R_X86_64_32; - -rewrite_modrm_rex: - bfd_put_8 (abfd, modrm, contents + roff - 1); - - if (rex) - { - /* Move the R bit to the B bit in REX byte. */ - rex = (rex & ~rex_mask) | (rex & REX_R) >> 2; - bfd_put_8 (abfd, rex, contents + roff - 3); - } - - /* No addend for R_X86_64_32/R_X86_64_32S relocations. */ - irel->r_addend = 0; - } - - bfd_put_8 (abfd, opcode, contents + roff - 2); - } - - *r_type_p = r_type; - irel->r_info = htab->r_info (r_symndx, - r_type | R_X86_64_converted_reloc_bit); - - *converted = TRUE; - - return TRUE; -} - -/* 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_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) -{ - struct elf_x86_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; - bfd_byte *contents; - bfd_boolean converted; - - if (bfd_link_relocatable (info)) - return TRUE; - - /* Don't do anything special with non-loaded, non-alloced sections. - In particular, any relocs in such sections should not affect GOT - and PLT reference counting (ie. we don't allow them to create GOT - or PLT entries), there's no possibility or desire to optimize TLS - relocs, and there's not much point in propagating relocs to shared - libs that the dynamic linker won't relocate. */ - if ((sec->flags & SEC_ALLOC) == 0) - return TRUE; - - htab = elf_x86_hash_table (info, X86_64_ELF_DATA); - if (htab == NULL) - { - sec->check_relocs_failed = 1; - return FALSE; - } - - BFD_ASSERT (is_x86_elf (abfd, htab)); - - /* Get the section contents. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (!bfd_malloc_and_get_section (abfd, sec, &contents)) - { - sec->check_relocs_failed = 1; - return FALSE; - } - - symtab_hdr = &elf_symtab_hdr (abfd); - sym_hashes = elf_sym_hashes (abfd); - - converted = FALSE; - - sreloc = NULL; - - rel_end = relocs + sec->reloc_count; - for (rel = relocs; rel < rel_end; rel++) - { - unsigned int r_type; - unsigned int r_symndx; - struct elf_link_hash_entry *h; - struct elf_x86_link_hash_entry *eh; - Elf_Internal_Sym *isym; - const char *name; - bfd_boolean size_reloc; - bfd_boolean converted_reloc; - - r_symndx = htab->r_sym (rel->r_info); - r_type = ELF32_R_TYPE (rel->r_info); - - if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) - { - /* xgettext:c-format */ - _bfd_error_handler (_("%B: bad symbol index: %d"), - abfd, r_symndx); - goto error_return; - } - - if (r_symndx < symtab_hdr->sh_info) - { - /* A local symbol. */ - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - goto error_return; - - /* Check relocation against local STT_GNU_IFUNC symbol. */ - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) - { - h = _bfd_elf_x86_get_local_sym_hash (htab, abfd, rel, - TRUE); - if (h == NULL) - goto error_return; - - /* Fake a STT_GNU_IFUNC symbol. */ - h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr, - isym, NULL); - h->type = STT_GNU_IFUNC; - h->def_regular = 1; - h->ref_regular = 1; - h->forced_local = 1; - h->root.type = bfd_link_hash_defined; - } - else - h = NULL; - } - else - { - isym = NULL; - 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; - } - - /* Check invalid x32 relocations. */ - if (!ABI_64_P (abfd)) - switch (r_type) - { - default: - break; - - case R_X86_64_DTPOFF64: - case R_X86_64_TPOFF64: - case R_X86_64_PC64: - case R_X86_64_GOTOFF64: - case R_X86_64_GOT64: - case R_X86_64_GOTPCREL64: - case R_X86_64_GOTPC64: - case R_X86_64_GOTPLT64: - case R_X86_64_PLTOFF64: - { - if (h) - name = h->root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, - NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s against symbol `%s' isn't " - "supported in x32 mode"), abfd, - x86_64_elf_howto_table[r_type].name, name); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - break; - } - - if (h != NULL) - { - /* It is referenced by a non-shared object. */ - h->ref_regular = 1; - - if (h->type == STT_GNU_IFUNC) - elf_tdata (info->output_bfd)->has_gnu_symbols - |= elf_gnu_symbol_ifunc; - } - - converted_reloc = FALSE; - if ((r_type == R_X86_64_GOTPCREL - || r_type == R_X86_64_GOTPCRELX - || r_type == R_X86_64_REX_GOTPCRELX) - && (h == NULL || h->type != STT_GNU_IFUNC)) - { - Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel; - if (!elf_x86_64_convert_load_reloc (abfd, contents, &r_type, - irel, h, &converted_reloc, - info)) - goto error_return; - - if (converted_reloc) - converted = TRUE; - } - - if (! elf_x86_64_tls_transition (info, abfd, sec, contents, - symtab_hdr, sym_hashes, - &r_type, GOT_UNKNOWN, - rel, rel_end, h, r_symndx, FALSE)) - goto error_return; - - eh = (struct elf_x86_link_hash_entry *) h; - switch (r_type) - { - case R_X86_64_TLSLD: - htab->tls_ld_or_ldm_got.refcount = 1; - goto create_got; - - case R_X86_64_TPOFF32: - if (!bfd_link_executable (info) && ABI_64_P (abfd)) - return elf_x86_64_need_pic (info, abfd, sec, h, symtab_hdr, isym, - &x86_64_elf_howto_table[r_type]); - if (eh != NULL) - eh->zero_undefweak &= 0x2; - break; - - case R_X86_64_GOTTPOFF: - if (!bfd_link_executable (info)) - info->flags |= DF_STATIC_TLS; - /* Fall through */ - - case R_X86_64_GOT32: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - 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) - { - h->got.refcount = 1; - old_tls_type = eh->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) - goto error_return; - elf_local_got_refcounts (abfd) = local_got_refcounts; - elf_x86_local_tlsdesc_gotent (abfd) - = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); - elf_x86_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx] = 1; - old_tls_type - = elf_x86_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 - { - if (h) - name = h->root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, - isym, NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: '%s' accessed both as normal and" - " thread local symbol"), - abfd, name); - bfd_set_error (bfd_error_bad_value); - goto error_return; - } - } - - if (old_tls_type != tls_type) - { - if (eh != NULL) - eh->tls_type = tls_type; - else - elf_x86_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 (eh != NULL) - eh->zero_undefweak &= 0x2; - break; - - case R_X86_64_PLT32: - case R_X86_64_PLT32_BND: - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code which is - 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; - - eh->zero_undefweak &= 0x2; - 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_SIZE32: - case R_X86_64_SIZE64: - size_reloc = TRUE; - goto do_size; - - case R_X86_64_32: - if (!ABI_64_P (abfd)) - goto pointer; - /* Fall through. */ - case R_X86_64_8: - case R_X86_64_16: - case R_X86_64_32S: - /* Check relocation overflow as these relocs may lead to - run-time relocation overflow. Don't error out for - sections we don't care about, such as debug sections or - when relocation overflow check is disabled. */ - if (!info->no_reloc_overflow_check - && !converted_reloc - && (bfd_link_pic (info) - || (bfd_link_executable (info) - && h != NULL - && !h->def_regular - && h->def_dynamic - && (sec->flags & SEC_READONLY) == 0))) - return elf_x86_64_need_pic (info, abfd, sec, h, symtab_hdr, isym, - &x86_64_elf_howto_table[r_type]); - /* Fall through. */ - - case R_X86_64_PC8: - case R_X86_64_PC16: - case R_X86_64_PC32: - case R_X86_64_PC32_BND: - case R_X86_64_PC64: - case R_X86_64_64: -pointer: - if (eh != NULL && (sec->flags & SEC_CODE) != 0) - eh->zero_undefweak |= 0x2; - /* We are called after all symbols have been resolved. Only - relocation against STT_GNU_IFUNC symbol must go through - PLT. */ - if (h != NULL - && (bfd_link_executable (info) - || h->type == STT_GNU_IFUNC)) - { - bfd_boolean func_pointer_ref = FALSE; - - if (r_type == R_X86_64_PC32) - { - /* Since something like ".long foo - ." may be used - as pointer, make sure that PLT is used if foo is - a function defined in a shared library. */ - if ((sec->flags & SEC_CODE) == 0) - h->pointer_equality_needed = 1; - } - else if (r_type != R_X86_64_PC32_BND - && r_type != R_X86_64_PC64) - { - h->pointer_equality_needed = 1; - /* At run-time, R_X86_64_64 can be resolved for both - x86-64 and x32. But R_X86_64_32 and R_X86_64_32S - can only be resolved for x32. */ - if ((sec->flags & SEC_READONLY) == 0 - && (r_type == R_X86_64_64 - || (!ABI_64_P (abfd) - && (r_type == R_X86_64_32 - || r_type == R_X86_64_32S)))) - func_pointer_ref = TRUE; - } - - if (!func_pointer_ref) - { - /* 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 symbol is a function - defined in a shared lib or is a function referenced - from the code or read-only section. */ - if (!h->def_regular - || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0) - h->plt.refcount = 1; - } - } - - size_reloc = FALSE; -do_size: - if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type, - htab->pointer_r_type)) - { - struct elf_dyn_relocs *p; - struct elf_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) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, ABI_64_P (abfd) ? 3 : 2, - abfd, /*rela?*/ TRUE); - - if (sreloc == NULL) - goto error_return; - } - - /* If this is a global symbol, we count the number of - relocations we need for this symbol. */ - if (h != NULL) - head = &eh->dyn_relocs; - else - { - /* Track dynamic relocs needed for local syms too. - We really need local syms available to do this - easily. Oh well. */ - asection *s; - void **vpp; - - isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) - goto error_return; - - s = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (s == NULL) - s = sec; - - /* Beware of type punned pointers vs strict aliasing - rules. */ - vpp = &(elf_section_data (s)->local_dynrel); - head = (struct elf_dyn_relocs **)vpp; - } - - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - - p = ((struct elf_dyn_relocs *) - bfd_alloc (htab->elf.dynobj, amt)); - if (p == NULL) - goto error_return; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - - p->count += 1; - /* Count size relocation as PC-relative relocation. */ - if (X86_PCREL_TYPE_P (r_type) || size_reloc) - 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)) - goto error_return; - break; - - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - case R_X86_64_GNU_VTENTRY: - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - goto error_return; - break; - - default: - break; - } - } - - if (elf_section_data (sec)->this_hdr.contents != contents) - { - if (!converted && !info->keep_memory) - free (contents); - else - { - /* Cache the section contents for elf_link_input_bfd if any - load is converted or --no-keep-memory isn't used. */ - elf_section_data (sec)->this_hdr.contents = contents; - } - } - - /* Cache relocations if any load is converted. */ - if (elf_section_data (sec)->relocs != relocs && converted) - elf_section_data (sec)->relocs = (Elf_Internal_Rela *) relocs; - - return TRUE; - -error_return: - if (elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - sec->check_relocs_failed = 1; - return FALSE; -} - -/* Return the relocation value for @tpoff relocation - if STT_TLS virtual address is ADDRESS. */ - -static bfd_vma -elf_x86_64_tpoff (struct bfd_link_info *info, bfd_vma address) -{ - struct elf_link_hash_table *htab = elf_hash_table (info); - const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); - bfd_vma static_tls_size; - - /* If tls_segment is NULL, we should have signalled an error already. */ - if (htab->tls_sec == NULL) - return 0; - - /* Consider special static TLS alignment requirements. */ - static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment); - return address - static_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 -elf_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 elf_x86_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 *wrel; - Elf_Internal_Rela *relend; - unsigned int plt_entry_size; - - /* Skip if check_relocs failed. */ - if (input_section->check_relocs_failed) - return FALSE; - - htab = elf_x86_hash_table (info, X86_64_ELF_DATA); - if (htab == NULL) - return FALSE; - - BFD_ASSERT (is_x86_elf (input_bfd, htab)); - - plt_entry_size = htab->plt.plt_entry_size; - symtab_hdr = &elf_symtab_hdr (input_bfd); - sym_hashes = elf_sym_hashes (input_bfd); - local_got_offsets = elf_local_got_offsets (input_bfd); - local_tlsdesc_gotents = elf_x86_local_tlsdesc_gotent (input_bfd); - - _bfd_x86_elf_set_tls_module_base (info); - - rel = wrel = relocs; - relend = relocs + input_section->reloc_count; - for (; rel < relend; wrel++, rel++) - { - unsigned int r_type, r_type_tls; - reloc_howto_type *howto; - unsigned long r_symndx; - struct elf_link_hash_entry *h; - struct elf_x86_link_hash_entry *eh; - Elf_Internal_Sym *sym; - asection *sec; - bfd_vma off, offplt, plt_offset; - bfd_vma relocation; - bfd_boolean unresolved_reloc; - bfd_reloc_status_type r; - int tls_type; - asection *base_got, *resolved_plt; - bfd_vma st_size; - bfd_boolean resolved_to_zero; - bfd_boolean relative_reloc; - bfd_boolean converted_reloc; - bfd_boolean need_copy_reloc_in_pie; - - r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == (int) R_X86_64_GNU_VTINHERIT - || r_type == (int) R_X86_64_GNU_VTENTRY) - { - if (wrel != rel) - *wrel = *rel; - continue; - } - - converted_reloc = (r_type & R_X86_64_converted_reloc_bit) != 0; - r_type &= ~R_X86_64_converted_reloc_bit; - - if (r_type >= (int) R_X86_64_standard) - return _bfd_unrecognized_reloc (input_bfd, input_section, r_type); - - if (r_type != (int) R_X86_64_32 - || ABI_64_P (output_bfd)) - howto = x86_64_elf_howto_table + r_type; - else - howto = (x86_64_elf_howto_table - + ARRAY_SIZE (x86_64_elf_howto_table) - 1); - r_symndx = htab->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); - st_size = sym->st_size; - - /* Relocate against local STT_GNU_IFUNC symbol. */ - if (!bfd_link_relocatable (info) - && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) - { - h = _bfd_elf_x86_get_local_sym_hash (htab, input_bfd, - rel, FALSE); - if (h == NULL) - abort (); - - /* Set STT_GNU_IFUNC symbol value. */ - h->root.u.def.value = sym->st_value; - h->root.u.def.section = sec; - } - } - else - { - bfd_boolean warned ATTRIBUTE_UNUSED; - bfd_boolean ignored ATTRIBUTE_UNUSED; - - RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, - r_symndx, symtab_hdr, sym_hashes, - h, sec, relocation, - unresolved_reloc, warned, ignored); - st_size = h->size; - } - - if (sec != NULL && discarded_section (sec)) - { - _bfd_clear_contents (howto, input_bfd, input_section, - contents + rel->r_offset); - wrel->r_offset = rel->r_offset; - wrel->r_info = 0; - wrel->r_addend = 0; - - /* For ld -r, remove relocations in debug sections against - sections defined in discarded sections. Not done for - eh_frame editing code expects to be present. */ - if (bfd_link_relocatable (info) - && (input_section->flags & SEC_DEBUGGING)) - wrel--; - - continue; - } - - if (bfd_link_relocatable (info)) - { - if (wrel != rel) - *wrel = *rel; - continue; - } - - if (rel->r_addend == 0 && !ABI_64_P (output_bfd)) - { - if (r_type == R_X86_64_64) - { - /* For x32, treat R_X86_64_64 like R_X86_64_32 and - zero-extend it to 64bit if addend is zero. */ - r_type = R_X86_64_32; - memset (contents + rel->r_offset + 4, 0, 4); - } - else if (r_type == R_X86_64_SIZE64) - { - /* For x32, treat R_X86_64_SIZE64 like R_X86_64_SIZE32 and - zero-extend it to 64bit if addend is zero. */ - r_type = R_X86_64_SIZE32; - memset (contents + rel->r_offset + 4, 0, 4); - } - } - - eh = (struct elf_x86_link_hash_entry *) h; - - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle - it here if it is defined in a non-shared object. */ - if (h != NULL - && h->type == STT_GNU_IFUNC - && h->def_regular) - { - bfd_vma plt_index; - const char *name; - - if ((input_section->flags & SEC_ALLOC) == 0) - { - /* 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 ((input_section->flags & SEC_DEBUGGING) != 0) - continue; - abort (); - } - - switch (r_type) - { - default: - break; - - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_GOTPCREL64: - base_got = htab->elf.sgot; - off = h->got.offset; - - if (base_got == NULL) - abort (); - - if (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. */ - - if (h->plt.offset == (bfd_vma) -1) - abort (); - - if (htab->elf.splt != NULL) - { - plt_index = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); - off = (plt_index + 3) * GOT_ENTRY_SIZE; - base_got = htab->elf.sgotplt; - } - else - { - plt_index = h->plt.offset / plt_entry_size; - off = plt_index * GOT_ENTRY_SIZE; - base_got = htab->elf.igotplt; - } - - if (h->dynindx == -1 - || h->forced_local - || info->symbolic) - { - /* This references the local defitionion. 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; - } - } - } - - relocation = (base_got->output_section->vma - + base_got->output_offset + off); - - goto do_relocation; - } - - if (h->plt.offset == (bfd_vma) -1) - { - /* Handle static pointers of STT_GNU_IFUNC symbols. */ - if (r_type == htab->pointer_r_type - && (input_section->flags & SEC_CODE) == 0) - goto do_ifunc_pointer; - goto bad_ifunc_reloc; - } - - /* STT_GNU_IFUNC symbol must go through PLT. */ - if (htab->elf.splt != NULL) - { - if (htab->plt_second != NULL) - { - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = htab->elf.splt; - plt_offset = h->plt.offset; - } - } - else - { - resolved_plt = htab->elf.iplt; - plt_offset = h->plt.offset; - } - - relocation = (resolved_plt->output_section->vma - + resolved_plt->output_offset + plt_offset); - - switch (r_type) - { - default: -bad_ifunc_reloc: - if (h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' isn't supported"), input_bfd, - howto->name, name); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case R_X86_64_32S: - if (bfd_link_pic (info)) - abort (); - goto do_relocation; - - case R_X86_64_32: - if (ABI_64_P (output_bfd)) - goto do_relocation; - /* FALLTHROUGH */ - case R_X86_64_64: -do_ifunc_pointer: - if (rel->r_addend != 0) - { - if (h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, - sym, NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' has non-zero addend: %Ld"), - input_bfd, howto->name, name, rel->r_addend); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* Generate dynamic relcoation only when there is a - non-GOT reference in a shared object or there is no - PLT. */ - if ((bfd_link_pic (info) && h->non_got_ref) - || h->plt.offset == (bfd_vma) -1) - { - Elf_Internal_Rela outrel; - asection *sreloc; - - /* Need a dynamic relocation to get the real function - address. */ - outrel.r_offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (outrel.r_offset == (bfd_vma) -1 - || outrel.r_offset == (bfd_vma) -2) - abort (); - - outrel.r_offset += (input_section->output_section->vma - + input_section->output_offset); - - if (POINTER_LOCAL_IFUNC_P (info, h)) - { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), - h->root.root.string, - h->root.u.def.section->owner); - - /* This symbol is resolved locally. */ - outrel.r_info = htab->r_info (0, R_X86_64_IRELATIVE); - outrel.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - { - outrel.r_info = htab->r_info (h->dynindx, r_type); - outrel.r_addend = 0; - } - - /* Dynamic relocations are stored in - 1. .rela.ifunc section in PIC object. - 2. .rela.got section in dynamic executable. - 3. .rela.iplt section in static executable. */ - if (bfd_link_pic (info)) - sreloc = htab->elf.irelifunc; - else if (htab->elf.splt != NULL) - sreloc = htab->elf.srelgot; - else - sreloc = htab->elf.irelplt; - elf_append_rela (output_bfd, sreloc, &outrel); - - /* 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. For an - internal symbol, we have updated addend. */ - continue; - } - /* FALLTHROUGH */ - case R_X86_64_PC32: - case R_X86_64_PC32_BND: - case R_X86_64_PC64: - case R_X86_64_PLT32: - case R_X86_64_PLT32_BND: - goto do_relocation; - } - } - - resolved_to_zero = (eh != NULL - && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh)); - - /* When generating a shared object, the relocations handled here are - copied into the output file to be resolved at run time. */ - switch (r_type) - { - case R_X86_64_GOT32: - 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_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_GOTPCREL64: - /* Use global offset table entry as symbol value. */ - case R_X86_64_GOTPLT64: - /* This is obsolete and treated the same as GOT64. */ - base_got = htab->elf.sgot; - - if (htab->elf.sgot == NULL) - abort (); - - relative_reloc = FALSE; - if (h != NULL) - { - 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 - - htab->plt.has_plt0); - off = (plt_index + 3) * GOT_ENTRY_SIZE; - base_got = htab->elf.sgotplt; - } - - if (RESOLVED_LOCALLY_P (info, h, htab)) - { - /* 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; - - if (GENERATE_RELATIVE_RELOC_P (info, h)) - { - /* If this symbol isn't dynamic in PIC, - generate R_X86_64_RELATIVE here. */ - eh->no_finish_dynamic_symbol = 1; - relative_reloc = TRUE; - } - } - } - 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); - local_got_offsets[r_symndx] |= 1; - - if (bfd_link_pic (info)) - relative_reloc = TRUE; - } - } - - if (relative_reloc) - { - asection *s; - Elf_Internal_Rela outrel; - - /* We need to generate a R_X86_64_RELATIVE reloc - for the dynamic linker. */ - s = htab->elf.srelgot; - if (s == NULL) - abort (); - - outrel.r_offset = (base_got->output_section->vma - + base_got->output_offset - + off); - outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE); - outrel.r_addend = relocation; - elf_append_rela (output_bfd, s, &outrel); - } - - 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_GOTPCRELX - && r_type != R_X86_64_REX_GOTPCRELX - && r_type != R_X86_64_GOTPCREL64) - relocation -= htab->elf.sgotplt->output_section->vma - - htab->elf.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 or data - symbol for shared library since it may not be local when - used as function address or with copy relocation. We also - need to make sure that a symbol is referenced locally. */ - if (bfd_link_pic (info) && h) - { - if (!h->def_regular) - { - const char *v; - - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_HIDDEN: - v = _("hidden symbol"); - break; - case STV_INTERNAL: - v = _("internal symbol"); - break; - case STV_PROTECTED: - v = _("protected symbol"); - break; - default: - v = _("symbol"); - break; - } - - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation R_X86_64_GOTOFF64 against undefined %s" - " `%s' can not be used when making a shared object"), - input_bfd, v, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else if (!bfd_link_executable (info) - && !SYMBOL_REFERENCES_LOCAL_P (info, h) - && (h->type == STT_FUNC - || h->type == STT_OBJECT) - && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation R_X86_64_GOTOFF64 against protected %s" - " `%s' can not be used when making a shared object"), - input_bfd, - h->type == STT_FUNC ? "function" : "data", - h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - - /* Note that sgot is not involved in this - 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->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset; - break; - - case R_X86_64_GOTPC32: - case R_X86_64_GOTPC64: - /* Use global offset table as symbol value. */ - relocation = htab->elf.sgotplt->output_section->vma - + htab->elf.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 - || eh->plt_got.offset != (bfd_vma) -1) - && htab->elf.splt != NULL) - { - if (eh->plt_got.offset != (bfd_vma) -1) - { - /* Use the GOT PLT. */ - resolved_plt = htab->plt_got; - plt_offset = eh->plt_got.offset; - } - else if (htab->plt_second != NULL) - { - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = htab->elf.splt; - plt_offset = h->plt.offset; - } - - relocation = (resolved_plt->output_section->vma - + resolved_plt->output_offset - + plt_offset); - unresolved_reloc = FALSE; - } - - relocation -= htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset; - break; - - case R_X86_64_PLT32: - case R_X86_64_PLT32_BND: - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - - /* 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 - && eh->plt_got.offset == (bfd_vma) -1) - || htab->elf.splt == NULL) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } - - if (h->plt.offset != (bfd_vma) -1) - { - if (htab->plt_second != NULL) - { - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = htab->elf.splt; - plt_offset = h->plt.offset; - } - } - else - { - /* Use the GOT PLT. */ - resolved_plt = htab->plt_got; - plt_offset = eh->plt_got.offset; - } - - relocation = (resolved_plt->output_section->vma - + resolved_plt->output_offset - + plt_offset); - unresolved_reloc = FALSE; - break; - - case R_X86_64_SIZE32: - case R_X86_64_SIZE64: - /* Set to symbol size. */ - relocation = st_size; - goto direct; - - case R_X86_64_PC8: - case R_X86_64_PC16: - case R_X86_64_PC32: - case R_X86_64_PC32_BND: - /* Don't complain about -fPIC if the symbol is undefined when - building executable unless it is unresolved weak symbol or - -z nocopyreloc is used. */ - if ((input_section->flags & SEC_ALLOC) != 0 - && (input_section->flags & SEC_READONLY) != 0 - && h != NULL - && ((bfd_link_executable (info) - && ((h->root.type == bfd_link_hash_undefweak - && !resolved_to_zero) - || ((info->nocopyreloc - || (eh->def_protected - && elf_has_no_copy_on_protected (h->root.u.def.section->owner))) - && h->def_dynamic - && !(h->root.u.def.section->flags & SEC_CODE)))) - || bfd_link_dll (info))) - { - bfd_boolean fail = FALSE; - bfd_boolean branch - = ((r_type == R_X86_64_PC32 - || r_type == R_X86_64_PC32_BND) - && is_32bit_relative_branch (contents, rel->r_offset)); - - if (SYMBOL_REFERENCES_LOCAL_P (info, h)) - { - /* Symbol is referenced locally. Make sure it is - defined locally or for a branch. */ - fail = (!(h->def_regular || ELF_COMMON_DEF_P (h)) - && !branch); - } - else if (!(bfd_link_pie (info) - && (h->needs_copy || eh->needs_copy))) - { - /* Symbol doesn't need copy reloc and isn't referenced - locally. We only allow branch to symbol with - non-default visibility. */ - fail = (!branch - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT); - } - - if (fail) - return elf_x86_64_need_pic (info, input_bfd, input_section, - h, NULL, NULL, howto); - } - /* 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. */ - -direct: - if ((input_section->flags & SEC_ALLOC) == 0) - break; - - need_copy_reloc_in_pie = (bfd_link_pie (info) - && h != NULL - && (h->needs_copy - || eh->needs_copy - || (h->root.type - == bfd_link_hash_undefined)) - && (X86_PCREL_TYPE_P (r_type) - || X86_SIZE_TYPE_P (r_type))); - - if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, - need_copy_reloc_in_pie, - resolved_to_zero, FALSE)) - { - Elf_Internal_Rela outrel; - 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 (COPY_INPUT_RELOC_P (info, h, r_type)) - { - outrel.r_info = htab->r_info (h->dynindx, r_type); - outrel.r_addend = rel->r_addend; - } - else - { - /* This symbol is local, or marked to become local. - When relocation overflow check is disabled, we - convert R_X86_64_32 to dynamic R_X86_64_RELATIVE. */ - if (r_type == htab->pointer_r_type - || (r_type == R_X86_64_32 - && info->no_reloc_overflow_check)) - { - relocate = TRUE; - outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE); - outrel.r_addend = relocation + rel->r_addend; - } - else if (r_type == R_X86_64_64 - && !ABI_64_P (output_bfd)) - { - relocate = TRUE; - outrel.r_info = htab->r_info (0, - R_X86_64_RELATIVE64); - outrel.r_addend = relocation + rel->r_addend; - /* Check addend overflow. */ - if ((outrel.r_addend & 0x80000000) - != (rel->r_addend & 0x80000000)) - { - const char *name; - int addend = rel->r_addend; - if (h && h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, - sym, NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: addend %s%#x in relocation %s against " - "symbol `%s' at %#Lx in section `%A' is " - "out of range"), - input_bfd, addend < 0 ? "-" : "", addend, - howto->name, name, rel->r_offset, input_section); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - 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; - - /* We are turning this relocation into one - against a section symbol. It would be - proper to subtract the symbol's value, - osec->vma, from the emitted reloc addend, - but ld.so expects buggy relocs. */ - osec = sec->output_section; - sindx = elf_section_data (osec)->dynindx; - if (sindx == 0) - { - asection *oi = htab->elf.text_index_section; - sindx = elf_section_data (oi)->dynindx; - } - BFD_ASSERT (sindx != 0); - } - - outrel.r_info = htab->r_info (sindx, r_type); - outrel.r_addend = relocation + rel->r_addend; - } - } - - sreloc = elf_section_data (input_section)->sreloc; - - if (sreloc == NULL || sreloc->contents == NULL) - { - r = bfd_reloc_notsupported; - goto check_relocation_error; - } - - elf_append_rela (output_bfd, sreloc, &outrel); - - /* 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: - tls_type = GOT_UNKNOWN; - if (h == NULL && local_got_offsets) - tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx]; - else if (h != NULL) - tls_type = elf_x86_hash_entry (h)->tls_type; - - r_type_tls = r_type; - if (! elf_x86_64_tls_transition (info, input_bfd, - input_section, contents, - symtab_hdr, sym_hashes, - &r_type_tls, tls_type, rel, - relend, h, r_symndx, TRUE)) - return FALSE; - - if (r_type_tls == R_X86_64_TPOFF32) - { - bfd_vma roff = rel->r_offset; - - BFD_ASSERT (! unresolved_reloc); - - if (r_type == R_X86_64_TLSGD) - { - /* GD->LE transition. For 64bit, change - .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@PLT - or - .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .byte 0x66; rex64 - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - into: - movq %fs:0, %rax - leaq foo@tpoff(%rax), %rax - For 32bit, change - leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@PLT - or - leaq foo@tlsgd(%rip), %rdi - .byte 0x66; rex64 - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - into: - movl %fs:0, %eax - leaq foo@tpoff(%rax), %rax - For largepic, change: - leaq foo@tlsgd(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq %r15, %rax - call *%rax - into: - movq %fs:0, %rax - leaq foo@tpoff(%rax), %rax - nopw 0x0(%rax,%rax,1) */ - int largepic = 0; - if (ABI_64_P (output_bfd)) - { - if (contents[roff + 5] == 0xb8) - { - memcpy (contents + roff - 3, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80" - "\0\0\0\0\x66\x0f\x1f\x44\0", 22); - largepic = 1; - } - else - memcpy (contents + roff - 4, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", - 16); - } - else - memcpy (contents + roff - 3, - "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", - 15); - bfd_put_32 (output_bfd, - elf_x86_64_tpoff (info, relocation), - contents + roff + 8 + largepic); - /* Skip R_X86_64_PC32, R_X86_64_PLT32, - R_X86_64_GOTPCRELX and R_X86_64_PLTOFF64. */ - rel++; - wrel++; - continue; - } - else if (r_type == 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. */ - - unsigned int val, type; - - type = bfd_get_8 (input_bfd, contents + roff - 3); - val = bfd_get_8 (input_bfd, contents + roff - 1); - 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, - elf_x86_64_tpoff (info, relocation), - contents + roff); - continue; - } - else if (r_type == R_X86_64_TLSDESC_CALL) - { - /* GDesc -> LE transition. - It's originally: - call *(%rax) - Turn it into: - xchg %ax,%ax. */ - bfd_put_8 (output_bfd, 0x66, contents + roff); - bfd_put_8 (output_bfd, 0x90, contents + roff + 1); - continue; - } - else if (r_type == R_X86_64_GOTTPOFF) - { - /* IE->LE transition: - For 64bit, originally it can be one of: - movq foo@gottpoff(%rip), %reg - addq foo@gottpoff(%rip), %reg - We change it into: - movq $foo, %reg - leaq foo(%reg), %reg - addq $foo, %reg. - For 32bit, originally it can be one of: - movq foo@gottpoff(%rip), %reg - addl foo@gottpoff(%rip), %reg - We change it into: - movq $foo, %reg - leal foo(%reg), %reg - addl $foo, %reg. */ - - unsigned int val, type, reg; - - if (roff >= 3) - val = bfd_get_8 (input_bfd, contents + roff - 3); - else - val = 0; - type = bfd_get_8 (input_bfd, contents + roff - 2); - reg = bfd_get_8 (input_bfd, contents + roff - 1); - reg >>= 3; - if (type == 0x8b) - { - /* movq */ - if (val == 0x4c) - bfd_put_8 (output_bfd, 0x49, - contents + roff - 3); - else if (!ABI_64_P (output_bfd) && val == 0x44) - bfd_put_8 (output_bfd, 0x41, - contents + roff - 3); - bfd_put_8 (output_bfd, 0xc7, - contents + roff - 2); - bfd_put_8 (output_bfd, 0xc0 | reg, - contents + roff - 1); - } - else if (reg == 4) - { - /* addq/addl -> addq/addl - addressing with %rsp/%r12 - is special */ - if (val == 0x4c) - bfd_put_8 (output_bfd, 0x49, - contents + roff - 3); - else if (!ABI_64_P (output_bfd) && val == 0x44) - bfd_put_8 (output_bfd, 0x41, - contents + roff - 3); - bfd_put_8 (output_bfd, 0x81, - contents + roff - 2); - bfd_put_8 (output_bfd, 0xc0 | reg, - contents + roff - 1); - } - else - { - /* addq/addl -> leaq/leal */ - if (val == 0x4c) - bfd_put_8 (output_bfd, 0x4d, - contents + roff - 3); - else if (!ABI_64_P (output_bfd) && val == 0x44) - bfd_put_8 (output_bfd, 0x45, - contents + roff - 3); - bfd_put_8 (output_bfd, 0x8d, - contents + roff - 2); - bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3), - contents + roff - 1); - } - bfd_put_32 (output_bfd, - elf_x86_64_tpoff (info, relocation), - contents + roff); - continue; - } - else - BFD_ASSERT (FALSE); - } - - if (htab->elf.sgot == NULL) - abort (); - - if (h != NULL) - { - off = h->got.offset; - offplt = elf_x86_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; - int dr_type, indx; - asection *sreloc; - - if (htab->elf.srelgot == NULL) - abort (); - - indx = h && h->dynindx != -1 ? h->dynindx : 0; - - if (GOT_TLS_GDESC_P (tls_type)) - { - outrel.r_info = htab->r_info (indx, R_X86_64_TLSDESC); - BFD_ASSERT (htab->sgotplt_jump_table_size + offplt - + 2 * GOT_ENTRY_SIZE <= htab->elf.sgotplt->size); - outrel.r_offset = (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + offplt - + htab->sgotplt_jump_table_size); - sreloc = htab->elf.srelplt; - if (indx == 0) - outrel.r_addend = relocation - _bfd_x86_elf_dtpoff_base (info); - else - outrel.r_addend = 0; - elf_append_rela (output_bfd, sreloc, &outrel); - } - - sreloc = htab->elf.srelgot; - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.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->elf.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 - _bfd_x86_elf_dtpoff_base (info); - outrel.r_info = htab->r_info (indx, dr_type); - - elf_append_rela (output_bfd, sreloc, &outrel); - - if (GOT_TLS_GD_P (tls_type)) - { - if (indx == 0) - { - BFD_ASSERT (! unresolved_reloc); - bfd_put_64 (output_bfd, - relocation - _bfd_x86_elf_dtpoff_base (info), - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - } - else - { - bfd_put_64 (output_bfd, 0, - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - outrel.r_info = htab->r_info (indx, - R_X86_64_DTPOFF64); - outrel.r_offset += GOT_ENTRY_SIZE; - elf_append_rela (output_bfd, sreloc, - &outrel); - } - } - - 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_tls == r_type) - { - if (r_type == R_X86_64_GOTPC32_TLSDESC - || r_type == R_X86_64_TLSDESC_CALL) - relocation = htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + offplt + htab->sgotplt_jump_table_size; - else - relocation = htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off; - unresolved_reloc = FALSE; - } - else - { - bfd_vma roff = rel->r_offset; - - if (r_type == R_X86_64_TLSGD) - { - /* GD->IE transition. For 64bit, change - .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@PLT - or - .byte 0x66; leaq foo@tlsgd(%rip), %rdi - .byte 0x66; rex64 - call *__tls_get_addr@GOTPCREL(%rip - which may be converted to - addr32 call __tls_get_addr - into: - movq %fs:0, %rax - addq foo@gottpoff(%rip), %rax - For 32bit, change - leaq foo@tlsgd(%rip), %rdi - .word 0x6666; rex64; call __tls_get_addr@PLT - or - leaq foo@tlsgd(%rip), %rdi - .byte 0x66; rex64; - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - into: - movl %fs:0, %eax - addq foo@gottpoff(%rip), %rax - For largepic, change: - leaq foo@tlsgd(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq %r15, %rax - call *%rax - into: - movq %fs:0, %rax - addq foo@gottpoff(%rax), %rax - nopw 0x0(%rax,%rax,1) */ - int largepic = 0; - if (ABI_64_P (output_bfd)) - { - if (contents[roff + 5] == 0xb8) - { - memcpy (contents + roff - 3, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05" - "\0\0\0\0\x66\x0f\x1f\x44\0", 22); - largepic = 1; - } - else - memcpy (contents + roff - 4, - "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", - 16); - } - else - memcpy (contents + roff - 3, - "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", - 15); - - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - roff - - largepic - - input_section->output_section->vma - - input_section->output_offset - - 12); - bfd_put_32 (output_bfd, relocation, - contents + roff + 8 + largepic); - /* Skip R_X86_64_PLT32/R_X86_64_PLTOFF64. */ - rel++; - wrel++; - continue; - } - else if (r_type == 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 xchg %ax,%ax. */ - - /* 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->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off - - rel->r_offset - - input_section->output_section->vma - - input_section->output_offset - - 4, - contents + roff); - continue; - } - else if (r_type == R_X86_64_TLSDESC_CALL) - { - /* GDesc -> IE transition. - It's originally: - call *(%rax) - - Change it to: - xchg %ax, %ax. */ - - bfd_put_8 (output_bfd, 0x66, contents + roff); - bfd_put_8 (output_bfd, 0x90, contents + roff + 1); - continue; - } - else - BFD_ASSERT (FALSE); - } - break; - - case R_X86_64_TLSLD: - if (! elf_x86_64_tls_transition (info, input_bfd, - input_section, contents, - symtab_hdr, sym_hashes, - &r_type, GOT_UNKNOWN, rel, - relend, h, r_symndx, TRUE)) - return FALSE; - - if (r_type != R_X86_64_TLSLD) - { - /* LD->LE transition: - leaq foo@tlsld(%rip), %rdi - call __tls_get_addr@PLT - For 64bit, we change it into: - .word 0x6666; .byte 0x66; movq %fs:0, %rax - For 32bit, we change it into: - nopl 0x0(%rax); movl %fs:0, %eax - Or - leaq foo@tlsld(%rip), %rdi; - call *__tls_get_addr@GOTPCREL(%rip) - which may be converted to - addr32 call __tls_get_addr - For 64bit, we change it into: - .word 0x6666; .word 0x6666; movq %fs:0, %rax - For 32bit, we change it into: - nopw 0x0(%rax); movl %fs:0, %eax - For largepic, change: - leaq foo@tlsgd(%rip), %rdi - movabsq $__tls_get_addr@pltoff, %rax - addq %rbx, %rax - call *%rax - into - data16 data16 data16 nopw %cs:0x0(%rax,%rax,1) - movq %fs:0, %eax */ - - BFD_ASSERT (r_type == R_X86_64_TPOFF32); - if (ABI_64_P (output_bfd)) - { - if (contents[rel->r_offset + 5] == 0xb8) - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x66\x2e\x0f\x1f\x84\0\0\0\0\0" - "\x64\x48\x8b\x04\x25\0\0\0", 22); - else if (contents[rel->r_offset + 4] == 0xff - || contents[rel->r_offset + 4] == 0x67) - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", - 13); - else - memcpy (contents + rel->r_offset - 3, - "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); - } - else - { - if (contents[rel->r_offset + 4] == 0xff) - memcpy (contents + rel->r_offset - 3, - "\x66\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", - 13); - else - memcpy (contents + rel->r_offset - 3, - "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12); - } - /* Skip R_X86_64_PC32, R_X86_64_PLT32, R_X86_64_GOTPCRELX - and R_X86_64_PLTOFF64. */ - rel++; - wrel++; - continue; - } - - if (htab->elf.sgot == NULL) - abort (); - - off = htab->tls_ld_or_ldm_got.offset; - if (off & 1) - off &= ~1; - else - { - Elf_Internal_Rela outrel; - - if (htab->elf.srelgot == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - - bfd_put_64 (output_bfd, 0, - htab->elf.sgot->contents + off); - bfd_put_64 (output_bfd, 0, - htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); - outrel.r_info = htab->r_info (0, R_X86_64_DTPMOD64); - outrel.r_addend = 0; - elf_append_rela (output_bfd, htab->elf.srelgot, - &outrel); - htab->tls_ld_or_ldm_got.offset |= 1; - } - relocation = htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off; - unresolved_reloc = FALSE; - break; - - case R_X86_64_DTPOFF32: - if (!bfd_link_executable (info) - || (input_section->flags & SEC_CODE) == 0) - relocation -= _bfd_x86_elf_dtpoff_base (info); - else - relocation = elf_x86_64_tpoff (info, relocation); - break; - - case R_X86_64_TPOFF32: - case R_X86_64_TPOFF64: - BFD_ASSERT (bfd_link_executable (info)); - relocation = elf_x86_64_tpoff (info, relocation); - break; - - case R_X86_64_DTPOFF64: - BFD_ASSERT ((input_section->flags & SEC_CODE) == 0); - relocation -= _bfd_x86_elf_dtpoff_base (info); - 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_elf_section_offset (output_bfd, info, input_section, - rel->r_offset) != (bfd_vma) -1) - { - switch (r_type) - { - case R_X86_64_32S: - sec = h->root.u.def.section; - if ((info->nocopyreloc - || (eh->def_protected - && elf_has_no_copy_on_protected (h->root.u.def.section->owner))) - && !(h->root.u.def.section->flags & SEC_CODE)) - return elf_x86_64_need_pic (info, input_bfd, input_section, - h, NULL, NULL, howto); - /* Fall through. */ - - default: - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - return FALSE; - } - } - -do_relocation: - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - -check_relocation_error: - 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 (converted_reloc) - { - info->callbacks->einfo - (_("%F%P: failed to convert GOTPCREL relocation; relink with --no-relax\n")); - return FALSE; - } - (*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, rel->r_offset); - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): reloc against `%s': error %d"), - input_bfd, input_section, - rel->r_offset, name, (int) r); - return FALSE; - } - } - - if (wrel != rel) - *wrel = *rel; - } - - if (wrel != rel) - { - Elf_Internal_Shdr *rel_hdr; - size_t deleted = rel - wrel; - - rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - if (rel_hdr->sh_size == 0) - { - /* It is too late to remove an empty reloc section. Leave - one NONE reloc. - ??? What is wrong with an empty section??? */ - rel_hdr->sh_size = rel_hdr->sh_entsize; - deleted -= 1; - } - rel_hdr = _bfd_elf_single_rel_hdr (input_section); - rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; - input_section->reloc_count -= deleted; - } - - return TRUE; -} - -/* Finish up dynamic symbol handling. We set the contents of various - dynamic sections here. */ - -static bfd_boolean -elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct elf_x86_link_hash_table *htab; - bfd_boolean use_plt_second; - struct elf_x86_link_hash_entry *eh; - bfd_boolean local_undefweak; - - htab = elf_x86_hash_table (info, X86_64_ELF_DATA); - if (htab == NULL) - return FALSE; - - /* Use the second PLT section only if there is .plt section. */ - use_plt_second = htab->elf.splt != NULL && htab->plt_second != NULL; - - eh = (struct elf_x86_link_hash_entry *) h; - if (eh->no_finish_dynamic_symbol) - abort (); - - /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for - resolved undefined weak symbols in executable so that their - references have value 0 at run-time. */ - local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh); - - if (h->plt.offset != (bfd_vma) -1) - { - bfd_vma plt_index; - bfd_vma got_offset, plt_offset; - Elf_Internal_Rela rela; - bfd_byte *loc; - asection *plt, *gotplt, *relplt, *resolved_plt; - const struct elf_backend_data *bed; - bfd_vma plt_got_pcrel_offset; - - /* When building a static executable, use .iplt, .igot.plt and - .rela.iplt sections for STT_GNU_IFUNC symbols. */ - if (htab->elf.splt != NULL) - { - plt = htab->elf.splt; - gotplt = htab->elf.sgotplt; - relplt = htab->elf.srelplt; - } - else - { - plt = htab->elf.iplt; - gotplt = htab->elf.igotplt; - relplt = htab->elf.irelplt; - } - - VERIFY_PLT_ENTRY (info, h, plt, gotplt, relplt, local_undefweak) - - /* 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. - - 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. - - For static executables, we don't reserve anything. */ - - if (plt == htab->elf.splt) - { - got_offset = (h->plt.offset / htab->plt.plt_entry_size - - htab->plt.has_plt0); - got_offset = (got_offset + 3) * GOT_ENTRY_SIZE; - } - else - { - got_offset = h->plt.offset / htab->plt.plt_entry_size; - got_offset = got_offset * GOT_ENTRY_SIZE; - } - - /* Fill in the entry in the procedure linkage table. */ - memcpy (plt->contents + h->plt.offset, htab->plt.plt_entry, - htab->plt.plt_entry_size); - if (use_plt_second) - { - memcpy (htab->plt_second->contents + eh->plt_second.offset, - htab->non_lazy_plt->plt_entry, - htab->non_lazy_plt->plt_entry_size); - - resolved_plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - resolved_plt = plt; - plt_offset = h->plt.offset; - } - - /* Insert the relocation positions of the plt section. */ - - /* Put offset the PC-relative instruction referring to the GOT entry, - subtracting the size of that instruction. */ - plt_got_pcrel_offset = (gotplt->output_section->vma - + gotplt->output_offset - + got_offset - - resolved_plt->output_section->vma - - resolved_plt->output_offset - - plt_offset - - htab->plt.plt_got_insn_size); - - /* Check PC-relative offset overflow in PLT entry. */ - if ((plt_got_pcrel_offset + 0x80000000) > 0xffffffff) - /* xgettext:c-format */ - info->callbacks->einfo (_("%F%B: PC-relative offset overflow in PLT entry for `%s'\n"), - output_bfd, h->root.root.string); - - bfd_put_32 (output_bfd, plt_got_pcrel_offset, - (resolved_plt->contents + plt_offset - + htab->plt.plt_got_offset)); - - /* Fill in the entry in the global offset table, initially this - points to the second part of the PLT entry. Leave the entry - as zero for undefined weak symbol in PIE. No PLT relocation - against undefined weak symbol in PIE. */ - if (!local_undefweak) - { - if (htab->plt.has_plt0) - bfd_put_64 (output_bfd, (plt->output_section->vma - + plt->output_offset - + h->plt.offset - + htab->lazy_plt->plt_lazy_offset), - gotplt->contents + got_offset); - - /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (gotplt->output_section->vma - + gotplt->output_offset - + got_offset); - if (PLT_LOCAL_IFUNC_P (info, h)) - { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), - h->root.root.string, - h->root.u.def.section->owner); - - /* If an STT_GNU_IFUNC symbol is locally defined, generate - R_X86_64_IRELATIVE instead of R_X86_64_JUMP_SLOT. */ - rela.r_info = htab->r_info (0, R_X86_64_IRELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - /* R_X86_64_IRELATIVE comes last. */ - plt_index = htab->next_irelative_index--; - } - else - { - rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT); - rela.r_addend = 0; - plt_index = htab->next_jump_slot_index++; - } - - /* Don't fill the second and third slots in PLT entry for - static executables nor without PLT0. */ - if (plt == htab->elf.splt && htab->plt.has_plt0) - { - bfd_vma plt0_offset - = h->plt.offset + htab->lazy_plt->plt_plt_insn_end; - - /* Put relocation index. */ - bfd_put_32 (output_bfd, plt_index, - (plt->contents + h->plt.offset - + htab->lazy_plt->plt_reloc_offset)); - - /* Put offset for jmp .PLT0 and check for overflow. We don't - check relocation index for overflow since branch displacement - will overflow first. */ - if (plt0_offset > 0x80000000) - /* xgettext:c-format */ - info->callbacks->einfo (_("%F%B: branch displacement overflow in PLT entry for `%s'\n"), - output_bfd, h->root.root.string); - bfd_put_32 (output_bfd, - plt0_offset, - (plt->contents + h->plt.offset - + htab->lazy_plt->plt_plt_offset)); - } - - bed = get_elf_backend_data (output_bfd); - loc = relplt->contents + plt_index * bed->s->sizeof_rela; - bed->s->swap_reloca_out (output_bfd, &rela, loc); - } - } - else if (eh->plt_got.offset != (bfd_vma) -1) - { - bfd_vma got_offset, plt_offset; - asection *plt, *got; - bfd_boolean got_after_plt; - int32_t got_pcrel_offset; - - /* Set the entry in the GOT procedure linkage table. */ - plt = htab->plt_got; - got = htab->elf.sgot; - got_offset = h->got.offset; - - if (got_offset == (bfd_vma) -1 - || (h->type == STT_GNU_IFUNC && h->def_regular) - || plt == NULL - || got == NULL) - abort (); - - /* Use the non-lazy PLT entry template for the GOT PLT since they - are the identical. */ - /* Fill in the entry in the GOT procedure linkage table. */ - plt_offset = eh->plt_got.offset; - memcpy (plt->contents + plt_offset, - htab->non_lazy_plt->plt_entry, - htab->non_lazy_plt->plt_entry_size); - - /* Put offset the PC-relative instruction referring to the GOT - entry, subtracting the size of that instruction. */ - got_pcrel_offset = (got->output_section->vma - + got->output_offset - + got_offset - - plt->output_section->vma - - plt->output_offset - - plt_offset - - htab->non_lazy_plt->plt_got_insn_size); - - /* Check PC-relative offset overflow in GOT PLT entry. */ - got_after_plt = got->output_section->vma > plt->output_section->vma; - if ((got_after_plt && got_pcrel_offset < 0) - || (!got_after_plt && got_pcrel_offset > 0)) - /* xgettext:c-format */ - info->callbacks->einfo (_("%F%B: PC-relative offset overflow in GOT PLT entry for `%s'\n"), - output_bfd, h->root.root.string); - - bfd_put_32 (output_bfd, got_pcrel_offset, - (plt->contents + plt_offset - + htab->non_lazy_plt->plt_got_offset)); - } - - if (!local_undefweak - && !h->def_regular - && (h->plt.offset != (bfd_vma) -1 - || eh->plt_got.offset != (bfd_vma) -1)) - { - /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value if there were any - relocations where pointer equality matters (this is a clue - for the dynamic linker, to make function pointer - comparisons work between an application and shared - library), otherwise set it to zero. If a function is only - called from a binary, there is no need to slow down - shared libraries because of that. */ - sym->st_shndx = SHN_UNDEF; - if (!h->pointer_equality_needed) - sym->st_value = 0; - } - - /* Don't generate dynamic GOT relocation against undefined weak - symbol in executable. */ - if (h->got.offset != (bfd_vma) -1 - && ! GOT_TLS_GD_ANY_P (elf_x86_hash_entry (h)->tls_type) - && elf_x86_hash_entry (h)->tls_type != GOT_TLS_IE - && !local_undefweak) - { - Elf_Internal_Rela rela; - asection *relgot = htab->elf.srelgot; - - /* This symbol has an entry in the global offset table. Set it - up. */ - if (htab->elf.sgot == NULL || htab->elf.srelgot == NULL) - abort (); - - rela.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.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 (h->def_regular - && h->type == STT_GNU_IFUNC) - { - if (h->plt.offset == (bfd_vma) -1) - { - /* STT_GNU_IFUNC is referenced without PLT. */ - if (htab->elf.splt == NULL) - { - /* use .rel[a].iplt section to store .got relocations - in static executable. */ - relgot = htab->elf.irelplt; - } - if (SYMBOL_REFERENCES_LOCAL_P (info, h)) - { - info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), - h->root.root.string, - h->root.u.def.section->owner); - - rela.r_info = htab->r_info (0, - R_X86_64_IRELATIVE); - rela.r_addend = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - else - goto do_glob_dat; - } - else if (bfd_link_pic (info)) - { - /* Generate R_X86_64_GLOB_DAT. */ - goto do_glob_dat; - } - else - { - asection *plt; - bfd_vma plt_offset; - - if (!h->pointer_equality_needed) - abort (); - - /* For non-shared object, we can't use .got.plt, which - contains the real function addres if we need pointer - equality. We load the GOT entry with the PLT entry. */ - if (htab->plt_second != NULL) - { - plt = htab->plt_second; - plt_offset = eh->plt_second.offset; - } - else - { - plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; - plt_offset = h->plt.offset; - } - bfd_put_64 (output_bfd, (plt->output_section->vma - + plt->output_offset - + plt_offset), - htab->elf.sgot->contents + h->got.offset); - return TRUE; - } - } - else if (bfd_link_pic (info) - && SYMBOL_REFERENCES_LOCAL_P (info, h)) - { - if (!(h->def_regular || ELF_COMMON_DEF_P (h))) - return FALSE; - BFD_ASSERT((h->got.offset & 1) != 0); - rela.r_info = htab->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); -do_glob_dat: - bfd_put_64 (output_bfd, (bfd_vma) 0, - htab->elf.sgot->contents + h->got.offset); - rela.r_info = htab->r_info (h->dynindx, R_X86_64_GLOB_DAT); - rela.r_addend = 0; - } - - elf_append_rela (output_bfd, relgot, &rela); - } - - if (h->needs_copy) - { - Elf_Internal_Rela rela; - asection *s; - - /* This symbol needs a copy reloc. Set it up. */ - VERIFY_COPY_RELOC (h, htab) - - 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 = htab->r_info (h->dynindx, R_X86_64_COPY); - rela.r_addend = 0; - if (h->root.u.def.section == htab->elf.sdynrelro) - s = htab->elf.sreldynrelro; - else - s = htab->elf.srelbss; - elf_append_rela (output_bfd, s, &rela); - } - - return TRUE; -} - -/* Finish up local dynamic symbol handling. We set the contents of - various dynamic sections here. */ - -static bfd_boolean -elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) *slot; - struct bfd_link_info *info - = (struct bfd_link_info *) inf; - - return elf_x86_64_finish_dynamic_symbol (info->output_bfd, - info, h, NULL); -} - -/* Finish up undefined weak symbol handling in PIE. Fill its PLT entry - here since undefined weak symbol may not be dynamic and may not be - called for elf_x86_64_finish_dynamic_symbol. */ - -static bfd_boolean -elf_x86_64_pie_finish_undefweak_symbol (struct bfd_hash_entry *bh, - void *inf) -{ - struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh; - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - if (h->root.type != bfd_link_hash_undefweak - || h->dynindx != -1) - return TRUE; - - return elf_x86_64_finish_dynamic_symbol (info->output_bfd, - info, h, NULL); -} - -/* 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_x86_64_reloc_type_class (const struct bfd_link_info *info, - const asection *rel_sec ATTRIBUTE_UNUSED, - const Elf_Internal_Rela *rela) -{ - bfd *abfd = info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_x86_link_hash_table *htab - = elf_x86_hash_table (info, X86_64_ELF_DATA); - - if (htab->elf.dynsym != NULL - && htab->elf.dynsym->contents != NULL) - { - /* Check relocation against STT_GNU_IFUNC symbol if there are - dynamic symbols. */ - unsigned long r_symndx = htab->r_sym (rela->r_info); - if (r_symndx != STN_UNDEF) - { - Elf_Internal_Sym sym; - if (!bed->s->swap_symbol_in (abfd, - (htab->elf.dynsym->contents - + r_symndx * bed->s->sizeof_sym), - 0, &sym)) - abort (); - - if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC) - return reloc_class_ifunc; - } - } - - switch ((int) ELF32_R_TYPE (rela->r_info)) - { - case R_X86_64_IRELATIVE: - return reloc_class_ifunc; - case R_X86_64_RELATIVE: - case R_X86_64_RELATIVE64: - 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 -elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - struct elf_x86_link_hash_table *htab; - - htab = _bfd_x86_elf_finish_dynamic_sections (output_bfd, info); - if (htab == NULL) - return FALSE; - - if (! htab->elf.dynamic_sections_created) - return TRUE; - - if (htab->elf.splt && htab->elf.splt->size > 0) - { - elf_section_data (htab->elf.splt->output_section) - ->this_hdr.sh_entsize = htab->plt.plt_entry_size; - - if (htab->plt.has_plt0) - { - /* Fill in the special first entry in the procedure linkage - table. */ - memcpy (htab->elf.splt->contents, - htab->lazy_plt->plt0_entry, - htab->lazy_plt->plt0_entry_size); - /* Add offset for pushq GOT+8(%rip), since the instruction - uses 6 bytes subtract this value. */ - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 8 - - htab->elf.splt->output_section->vma - - htab->elf.splt->output_offset - - 6), - (htab->elf.splt->contents - + htab->lazy_plt->plt0_got1_offset)); - /* Add offset for the PC-relative instruction accessing - GOT+16, subtracting the offset to the end of that - instruction. */ - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 16 - - htab->elf.splt->output_section->vma - - htab->elf.splt->output_offset - - htab->lazy_plt->plt0_got2_insn_end), - (htab->elf.splt->contents - + htab->lazy_plt->plt0_got2_offset)); - } - - if (htab->tlsdesc_plt) - { - bfd_put_64 (output_bfd, (bfd_vma) 0, - htab->elf.sgot->contents + htab->tlsdesc_got); - - memcpy (htab->elf.splt->contents + htab->tlsdesc_plt, - htab->lazy_plt->plt0_entry, - htab->lazy_plt->plt0_entry_size); - - /* Add offset for pushq GOT+8(%rip), since the - instruction uses 6 bytes subtract this value. */ - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 8 - - htab->elf.splt->output_section->vma - - htab->elf.splt->output_offset - - htab->tlsdesc_plt - - 6), - (htab->elf.splt->contents - + htab->tlsdesc_plt - + htab->lazy_plt->plt0_got1_offset)); - /* Add offset for the PC-relative instruction accessing - GOT+TDG, where TDG stands for htab->tlsdesc_got, - subtracting the offset to the end of that - instruction. */ - bfd_put_32 (output_bfd, - (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + htab->tlsdesc_got - - htab->elf.splt->output_section->vma - - htab->elf.splt->output_offset - - htab->tlsdesc_plt - - htab->lazy_plt->plt0_got2_insn_end), - (htab->elf.splt->contents - + htab->tlsdesc_plt - + htab->lazy_plt->plt0_got2_offset)); - } - } - - /* Fill PLT entries for undefined weak symbols in PIE. */ - if (bfd_link_pie (info)) - bfd_hash_traverse (&info->hash->table, - elf_x86_64_pie_finish_undefweak_symbol, - info); - - return TRUE; -} - -/* Fill PLT/GOT entries and allocate dynamic relocations for local - STT_GNU_IFUNC symbols, which aren't in the ELF linker hash table. - It has to be done before elf_link_sort_relocs is called so that - dynamic relocations are properly sorted. */ - -static bfd_boolean -elf_x86_64_output_arch_local_syms - (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info, - void *flaginfo ATTRIBUTE_UNUSED, - int (*func) (void *, const char *, - Elf_Internal_Sym *, - asection *, - struct elf_link_hash_entry *) ATTRIBUTE_UNUSED) -{ - struct elf_x86_link_hash_table *htab - = elf_x86_hash_table (info, X86_64_ELF_DATA); - if (htab == NULL) - return FALSE; - - /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ - htab_traverse (htab->loc_hash_table, - elf_x86_64_finish_local_dynamic_symbol, - info); - - return TRUE; -} - -/* Forward declaration. */ -static const struct elf_x86_lazy_plt_layout elf_x86_64_nacl_plt; - -/* Similar to _bfd_elf_get_synthetic_symtab. Support PLTs with all - dynamic relocations. */ - -static long -elf_x86_64_get_synthetic_symtab (bfd *abfd, - long symcount ATTRIBUTE_UNUSED, - asymbol **syms ATTRIBUTE_UNUSED, - long dynsymcount, - asymbol **dynsyms, - asymbol **ret) -{ - long count, i, n; - int j; - bfd_byte *plt_contents; - long relsize; - const struct elf_x86_lazy_plt_layout *lazy_plt; - const struct elf_x86_non_lazy_plt_layout *non_lazy_plt; - const struct elf_x86_lazy_plt_layout *lazy_bnd_plt; - const struct elf_x86_non_lazy_plt_layout *non_lazy_bnd_plt; - const struct elf_x86_lazy_plt_layout *lazy_ibt_plt; - const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt; - asection *plt; - enum elf_x86_plt_type plt_type; - struct elf_x86_plt plts[] = - { - { ".plt", NULL, NULL, plt_unknown, 0, 0, 0, 0 }, - { ".plt.got", NULL, NULL, plt_non_lazy, 0, 0, 0, 0 }, - { ".plt.sec", NULL, NULL, plt_second, 0, 0, 0, 0 }, - { ".plt.bnd", NULL, NULL, plt_second, 0, 0, 0, 0 }, - { NULL, NULL, NULL, plt_non_lazy, 0, 0, 0, 0 } - }; - - *ret = NULL; - - if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) - return 0; - - if (dynsymcount <= 0) - return 0; - - relsize = bfd_get_dynamic_reloc_upper_bound (abfd); - if (relsize <= 0) - return -1; - - if (get_elf_x86_backend_data (abfd)->target_os == is_normal) - { - lazy_plt = &elf_x86_64_lazy_plt; - non_lazy_plt = &elf_x86_64_non_lazy_plt; - lazy_bnd_plt = &elf_x86_64_lazy_bnd_plt; - non_lazy_bnd_plt = &elf_x86_64_non_lazy_bnd_plt; - if (ABI_64_P (abfd)) - { - lazy_ibt_plt = &elf_x86_64_lazy_ibt_plt; - non_lazy_ibt_plt = &elf_x86_64_non_lazy_ibt_plt; - } - else - { - lazy_ibt_plt = &elf_x32_lazy_ibt_plt; - non_lazy_ibt_plt = &elf_x32_non_lazy_ibt_plt; - } - } - else - { - lazy_plt = &elf_x86_64_nacl_plt; - non_lazy_plt = NULL; - lazy_bnd_plt = NULL; - non_lazy_bnd_plt = NULL; - lazy_ibt_plt = NULL; - non_lazy_ibt_plt = NULL; - } - - count = 0; - for (j = 0; plts[j].name != NULL; j++) - { - plt = bfd_get_section_by_name (abfd, plts[j].name); - if (plt == NULL || plt->size == 0) - continue; - - /* Get the PLT section contents. */ - plt_contents = (bfd_byte *) bfd_malloc (plt->size); - if (plt_contents == NULL) - break; - if (!bfd_get_section_contents (abfd, (asection *) plt, - plt_contents, 0, plt->size)) - { - free (plt_contents); - break; - } - - /* Check what kind of PLT it is. */ - plt_type = plt_unknown; - if (plts[j].type == plt_unknown - && (plt->size >= (lazy_plt->plt_entry_size - + lazy_plt->plt_entry_size))) - { - /* Match lazy PLT first. Need to check the first two - instructions. */ - if ((memcmp (plt_contents, lazy_plt->plt0_entry, - lazy_plt->plt0_got1_offset) == 0) - && (memcmp (plt_contents + 6, lazy_plt->plt0_entry + 6, - 2) == 0)) - plt_type = plt_lazy; - else if (lazy_bnd_plt != NULL - && (memcmp (plt_contents, lazy_bnd_plt->plt0_entry, - lazy_bnd_plt->plt0_got1_offset) == 0) - && (memcmp (plt_contents + 6, - lazy_bnd_plt->plt0_entry + 6, 3) == 0)) - { - plt_type = plt_lazy | plt_second; - /* The fist entry in the lazy IBT PLT is the same as the - lazy BND PLT. */ - if ((memcmp (plt_contents + lazy_ibt_plt->plt_entry_size, - lazy_ibt_plt->plt_entry, - lazy_ibt_plt->plt_got_offset) == 0)) - lazy_plt = lazy_ibt_plt; - else - lazy_plt = lazy_bnd_plt; - } - } - - if (non_lazy_plt != NULL - && (plt_type == plt_unknown || plt_type == plt_non_lazy) - && plt->size >= non_lazy_plt->plt_entry_size) - { - /* Match non-lazy PLT. */ - if (memcmp (plt_contents, non_lazy_plt->plt_entry, - non_lazy_plt->plt_got_offset) == 0) - plt_type = plt_non_lazy; - } - - if (plt_type == plt_unknown || plt_type == plt_second) - { - if (non_lazy_bnd_plt != NULL - && plt->size >= non_lazy_bnd_plt->plt_entry_size - && (memcmp (plt_contents, non_lazy_bnd_plt->plt_entry, - non_lazy_bnd_plt->plt_got_offset) == 0)) - { - /* Match BND PLT. */ - plt_type = plt_second; - non_lazy_plt = non_lazy_bnd_plt; - } - else if (non_lazy_ibt_plt != NULL - && plt->size >= non_lazy_ibt_plt->plt_entry_size - && (memcmp (plt_contents, - non_lazy_ibt_plt->plt_entry, - non_lazy_ibt_plt->plt_got_offset) == 0)) - { - /* Match IBT PLT. */ - plt_type = plt_second; - non_lazy_plt = non_lazy_ibt_plt; - } - } - - if (plt_type == plt_unknown) - { - free (plt_contents); - continue; - } - - plts[j].sec = plt; - plts[j].type = plt_type; - - if ((plt_type & plt_lazy)) - { - plts[j].plt_got_offset = lazy_plt->plt_got_offset; - plts[j].plt_got_insn_size = lazy_plt->plt_got_insn_size; - plts[j].plt_entry_size = lazy_plt->plt_entry_size; - /* Skip PLT0 in lazy PLT. */ - i = 1; - } - else - { - plts[j].plt_got_offset = non_lazy_plt->plt_got_offset; - plts[j].plt_got_insn_size = non_lazy_plt->plt_got_insn_size; - plts[j].plt_entry_size = non_lazy_plt->plt_entry_size; - i = 0; - } - - /* Skip lazy PLT when the second PLT is used. */ - if (plt_type == (plt_lazy | plt_second)) - plts[j].count = 0; - else - { - n = plt->size / plts[j].plt_entry_size; - plts[j].count = n; - count += n - i; - } - - plts[j].contents = plt_contents; - } - - return _bfd_x86_elf_get_synthetic_symtab (abfd, count, relsize, - (bfd_vma) 0, plts, dynsyms, - ret); -} - -/* Handle an x86-64 specific section when reading an object file. This - is called when elfcode.h finds a section with an unknown type. */ - -static bfd_boolean -elf_x86_64_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, - const char *name, int shindex) -{ - 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 -elf_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; - return TRUE; - } - - return TRUE; -} - - -/* Given a BFD section, try to locate the corresponding ELF section - index. */ - -static bfd_boolean -elf_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, int *index_return) -{ - if (sec == &_bfd_elf_large_com_section) - { - *index_return = SHN_X86_64_LCOMMON; - return TRUE; - } - return FALSE; -} - -/* Process a symbol. */ - -static void -elf_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 -elf_x86_64_common_definition (Elf_Internal_Sym *sym) -{ - return (sym->st_shndx == SHN_COMMON - || sym->st_shndx == SHN_X86_64_LCOMMON); -} - -static unsigned int -elf_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 * -elf_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 -elf_x86_64_merge_symbol (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *sym, - asection **psec, - bfd_boolean newdef, - bfd_boolean olddef, - bfd *oldbfd, - const asection *oldsec) -{ - /* A normal common symbol and a large common symbol result in a - normal common symbol. We turn the large common symbol into a - normal one. */ - if (!olddef - && h->root.type == bfd_link_hash_common - && !newdef - && bfd_is_com_section (*psec) - && oldsec != *psec) - { - 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 = bfd_com_section_ptr; - } - - return TRUE; -} - -static int -elf_x86_64_additional_program_headers (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED) -{ - 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; -} - -/* Return TRUE iff relocations for INPUT are compatible with OUTPUT. */ - -static bfd_boolean -elf_x86_64_relocs_compatible (const bfd_target *input, - const bfd_target *output) -{ - return ((xvec_get_elf_backend_data (input)->s->elfclass - == xvec_get_elf_backend_data (output)->s->elfclass) - && _bfd_elf_relocs_compatible (input, output)); -} - -/* Set up x86-64 GNU properties. Return the first relocatable ELF input - with GNU properties if found. Otherwise, return NULL. */ - -static bfd * -elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info) -{ - struct elf_x86_init_table init_table; - - if ((int) R_X86_64_standard >= (int) R_X86_64_converted_reloc_bit - || (int) R_X86_64_max <= (int) R_X86_64_converted_reloc_bit - || ((int) (R_X86_64_GNU_VTINHERIT | R_X86_64_converted_reloc_bit) - != (int) R_X86_64_GNU_VTINHERIT) - || ((int) (R_X86_64_GNU_VTENTRY | R_X86_64_converted_reloc_bit) - != (int) R_X86_64_GNU_VTENTRY)) - abort (); - - /* This is unused for x86-64. */ - init_table.plt0_pad_byte = 0x90; - - if (get_elf_x86_backend_data (info->output_bfd)->target_os - == is_normal) - { - if (info->bndplt) - { - init_table.lazy_plt = &elf_x86_64_lazy_bnd_plt; - init_table.non_lazy_plt = &elf_x86_64_non_lazy_bnd_plt; - } - else - { - init_table.lazy_plt = &elf_x86_64_lazy_plt; - init_table.non_lazy_plt = &elf_x86_64_non_lazy_plt; - } - - if (ABI_64_P (info->output_bfd)) - { - init_table.lazy_ibt_plt = &elf_x86_64_lazy_ibt_plt; - init_table.non_lazy_ibt_plt = &elf_x86_64_non_lazy_ibt_plt; - } - else - { - init_table.lazy_ibt_plt = &elf_x32_lazy_ibt_plt; - init_table.non_lazy_ibt_plt = &elf_x32_non_lazy_ibt_plt; - } - } - else - { - init_table.lazy_plt = &elf_x86_64_nacl_plt; - init_table.non_lazy_plt = NULL; - init_table.lazy_ibt_plt = NULL; - init_table.non_lazy_ibt_plt = NULL; - } - - if (ABI_64_P (info->output_bfd)) - { - init_table.r_info = elf64_r_info; - init_table.r_sym = elf64_r_sym; - } - else - { - init_table.r_info = elf32_r_info; - init_table.r_sym = elf32_r_sym; - } - - return _bfd_x86_elf_link_setup_gnu_properties (info, &init_table); -} - -static const struct bfd_elf_special_section -elf_x86_64_special_sections[]= -{ - { STRING_COMMA_LEN (".gnu.linkonce.lb"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, - { STRING_COMMA_LEN (".gnu.linkonce.lr"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, - { STRING_COMMA_LEN (".gnu.linkonce.lt"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR + SHF_X86_64_LARGE}, - { STRING_COMMA_LEN (".lbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, - { STRING_COMMA_LEN (".ldata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, - { STRING_COMMA_LEN (".lrodata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, - { NULL, 0, 0, 0, 0 } -}; - -#define TARGET_LITTLE_SYM x86_64_elf64_vec -#define TARGET_LITTLE_NAME "elf64-x86-64" -#define ELF_ARCH bfd_arch_i386 -#define ELF_TARGET_ID X86_64_ELF_DATA -#define ELF_MACHINE_CODE EM_X86_64 -#define ELF_MAXPAGESIZE 0x200000 -#define ELF_MINPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 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 (GOT_ENTRY_SIZE*3) -#define elf_backend_rela_normal 1 -#define elf_backend_plt_alignment 4 -#define elf_backend_extern_protected_data 1 -#define elf_backend_caches_rawsize 1 -#define elf_backend_dtrel_excludes_plt 1 -#define elf_backend_want_dynrelro 1 - -#define elf_info_to_howto elf_x86_64_info_to_howto - -#define bfd_elf64_bfd_reloc_type_lookup elf_x86_64_reloc_type_lookup -#define bfd_elf64_bfd_reloc_name_lookup \ - elf_x86_64_reloc_name_lookup - -#define elf_backend_relocs_compatible elf_x86_64_relocs_compatible -#define elf_backend_check_relocs elf_x86_64_check_relocs -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections -#define elf_backend_finish_dynamic_sections elf_x86_64_finish_dynamic_sections -#define elf_backend_finish_dynamic_symbol elf_x86_64_finish_dynamic_symbol -#define elf_backend_output_arch_local_syms elf_x86_64_output_arch_local_syms -#define elf_backend_grok_prstatus elf_x86_64_grok_prstatus -#define elf_backend_grok_psinfo elf_x86_64_grok_psinfo -#ifdef CORE_HEADER -#define elf_backend_write_core_note elf_x86_64_write_core_note -#endif -#define elf_backend_reloc_type_class elf_x86_64_reloc_type_class -#define elf_backend_relocate_section elf_x86_64_relocate_section -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_object_p elf64_x86_64_elf_object_p -#define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab - -#define elf_backend_section_from_shdr \ - elf_x86_64_section_from_shdr - -#define elf_backend_section_from_bfd_section \ - elf_x86_64_elf_section_from_bfd_section -#define elf_backend_add_symbol_hook \ - elf_x86_64_add_symbol_hook -#define elf_backend_symbol_processing \ - elf_x86_64_symbol_processing -#define elf_backend_common_section_index \ - elf_x86_64_common_section_index -#define elf_backend_common_section \ - elf_x86_64_common_section -#define elf_backend_common_definition \ - elf_x86_64_common_definition -#define elf_backend_merge_symbol \ - elf_x86_64_merge_symbol -#define elf_backend_special_sections \ - elf_x86_64_special_sections -#define elf_backend_additional_program_headers \ - elf_x86_64_additional_program_headers -#define elf_backend_setup_gnu_properties \ - elf_x86_64_link_setup_gnu_properties -#define elf_backend_hide_symbol \ - _bfd_x86_elf_hide_symbol - -#include "elf64-target.h" - -/* CloudABI support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM x86_64_elf64_cloudabi_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-x86-64-cloudabi" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_CLOUDABI - -#undef elf64_bed -#define elf64_bed elf64_x86_64_cloudabi_bed - -#include "elf64-target.h" - -/* FreeBSD support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM x86_64_elf64_fbsd_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-x86-64-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf64_bed -#define elf64_bed elf64_x86_64_fbsd_bed - -#include "elf64-target.h" - -/* Solaris 2 support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM x86_64_elf64_sol2_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-x86-64-sol2" - -/* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE - objects won't be recognized. */ -#undef ELF_OSABI - -#undef elf64_bed -#define elf64_bed elf64_x86_64_sol2_bed - -/* The 64-bit static TLS arena size is rounded to the nearest 16-byte - boundary. */ -#undef elf_backend_static_tls_alignment -#define elf_backend_static_tls_alignment 16 - -/* The Solaris 2 ABI requires a plt symbol on all platforms. - - Cf. Linker and Libraries Guide, Ch. 2, Link-Editor, Generating the Output - File, p.63. */ -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 1 - -#undef elf_backend_strtab_flags -#define elf_backend_strtab_flags SHF_STRINGS - -static bfd_boolean -elf64_x86_64_copy_solaris_special_section_fields (const bfd *ibfd ATTRIBUTE_UNUSED, - bfd *obfd ATTRIBUTE_UNUSED, - const Elf_Internal_Shdr *isection ATTRIBUTE_UNUSED, - Elf_Internal_Shdr *osection ATTRIBUTE_UNUSED) -{ - /* PR 19938: FIXME: Need to add code for setting the sh_info - and sh_link fields of Solaris specific section types. */ - return FALSE; -} - -#undef elf_backend_copy_special_section_fields -#define elf_backend_copy_special_section_fields elf64_x86_64_copy_solaris_special_section_fields - -#include "elf64-target.h" - -/* Native Client support. */ - -static bfd_boolean -elf64_x86_64_nacl_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for a NaCl x86-64 ELF64 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64_nacl); - return TRUE; -} - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM x86_64_elf64_nacl_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-x86-64-nacl" -#undef elf64_bed -#define elf64_bed elf64_x86_64_nacl_bed - -#undef ELF_MAXPAGESIZE -#undef ELF_MINPAGESIZE -#undef ELF_COMMONPAGESIZE -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_MINPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x10000 - -/* Restore defaults. */ -#undef ELF_OSABI -#undef elf_backend_static_tls_alignment -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 0 -#undef elf_backend_strtab_flags -#undef elf_backend_copy_special_section_fields - -/* NaCl uses substantially different PLT entries for the same effects. */ - -#undef elf_backend_plt_alignment -#define elf_backend_plt_alignment 5 -#define NACL_PLT_ENTRY_SIZE 64 -#define NACLMASK 0xe0 /* 32-byte alignment mask. */ - -static const bfd_byte elf_x86_64_nacl_plt0_entry[NACL_PLT_ENTRY_SIZE] = - { - 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ - 0x4c, 0x8b, 0x1d, 16, 0, 0, 0, /* mov GOT+16(%rip), %r11 */ - 0x41, 0x83, 0xe3, NACLMASK, /* and $-32, %r11d */ - 0x4d, 0x01, 0xfb, /* add %r15, %r11 */ - 0x41, 0xff, 0xe3, /* jmpq *%r11 */ - - /* 9-byte nop sequence to pad out to the next 32-byte boundary. */ - 0x66, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw 0x0(%rax,%rax,1) */ - - /* 32 bytes of nop to pad out to the standard size. */ - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data16 prefixes */ - 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data16 prefixes */ - 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ - 0x66, /* excess data16 prefix */ - 0x90 /* nop */ - }; - -static const bfd_byte elf_x86_64_nacl_plt_entry[NACL_PLT_ENTRY_SIZE] = - { - 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, /* mov name@GOTPCREL(%rip),%r11 */ - 0x41, 0x83, 0xe3, NACLMASK, /* and $-32, %r11d */ - 0x4d, 0x01, 0xfb, /* add %r15, %r11 */ - 0x41, 0xff, 0xe3, /* jmpq *%r11 */ - - /* 15-byte nop sequence to pad out to the next 32-byte boundary. */ - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data16 prefixes */ - 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ - - /* Lazy GOT entries point here (32-byte aligned). */ - 0x68, /* pushq immediate */ - 0, 0, 0, 0, /* replaced with index into relocation table. */ - 0xe9, /* jmp relative */ - 0, 0, 0, 0, /* replaced with offset to start of .plt0. */ - - /* 22 bytes of nop to pad out to the standard size. */ - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, /* excess data16 prefixes */ - 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, /* nopw %cs:0x0(%rax,%rax,1) */ - 0x0f, 0x1f, 0x80, 0, 0, 0, 0, /* nopl 0x0(%rax) */ - }; - -/* .eh_frame covering the .plt section. */ - -static const bfd_byte elf_x86_64_nacl_eh_frame_plt[] = - { -#if (PLT_CIE_LENGTH != 20 \ - || PLT_FDE_LENGTH != 36 \ - || PLT_FDE_START_OFFSET != 4 + PLT_CIE_LENGTH + 8 \ - || PLT_FDE_LEN_OFFSET != 4 + PLT_CIE_LENGTH + 12) -# error "Need elf_x86_backend_data parameters for eh_frame_plt offsets!" -#endif - PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ - 0, 0, 0, 0, /* CIE ID */ - 1, /* CIE version */ - 'z', 'R', 0, /* Augmentation string */ - 1, /* Code alignment factor */ - 0x78, /* Data alignment factor */ - 16, /* Return address column */ - 1, /* Augmentation size */ - DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ - DW_CFA_def_cfa, 7, 8, /* DW_CFA_def_cfa: r7 (rsp) ofs 8 */ - DW_CFA_offset + 16, 1, /* DW_CFA_offset: r16 (rip) at cfa-8 */ - DW_CFA_nop, DW_CFA_nop, - - PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ - PLT_CIE_LENGTH + 8, 0, 0, 0,/* CIE pointer */ - 0, 0, 0, 0, /* R_X86_64_PC32 .plt goes here */ - 0, 0, 0, 0, /* .plt size goes here */ - 0, /* Augmentation size */ - DW_CFA_def_cfa_offset, 16, /* DW_CFA_def_cfa_offset: 16 */ - DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ - DW_CFA_def_cfa_offset, 24, /* DW_CFA_def_cfa_offset: 24 */ - DW_CFA_advance_loc + 58, /* DW_CFA_advance_loc: 58 to __PLT__+64 */ - DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ - 13, /* Block length */ - DW_OP_breg7, 8, /* DW_OP_breg7 (rsp): 8 */ - DW_OP_breg16, 0, /* DW_OP_breg16 (rip): 0 */ - DW_OP_const1u, 63, DW_OP_and, DW_OP_const1u, 37, DW_OP_ge, - DW_OP_lit3, DW_OP_shl, DW_OP_plus, - DW_CFA_nop, DW_CFA_nop - }; - -static const struct elf_x86_lazy_plt_layout elf_x86_64_nacl_plt = - { - elf_x86_64_nacl_plt0_entry, /* plt0_entry */ - NACL_PLT_ENTRY_SIZE, /* plt0_entry_size */ - elf_x86_64_nacl_plt_entry, /* plt_entry */ - NACL_PLT_ENTRY_SIZE, /* plt_entry_size */ - 2, /* plt0_got1_offset */ - 9, /* plt0_got2_offset */ - 13, /* plt0_got2_insn_end */ - 3, /* plt_got_offset */ - 33, /* plt_reloc_offset */ - 38, /* plt_plt_offset */ - 7, /* plt_got_insn_size */ - 42, /* plt_plt_insn_end */ - 32, /* plt_lazy_offset */ - elf_x86_64_nacl_plt0_entry, /* pic_plt0_entry */ - elf_x86_64_nacl_plt_entry, /* pic_plt_entry */ - elf_x86_64_nacl_eh_frame_plt, /* eh_frame_plt */ - sizeof (elf_x86_64_nacl_eh_frame_plt) /* eh_frame_plt_size */ - }; - -static const struct elf_x86_backend_data elf_x86_64_nacl_arch_bed = - { - is_nacl /* os */ - }; - -#undef elf_backend_arch_data -#define elf_backend_arch_data &elf_x86_64_nacl_arch_bed - -#undef elf_backend_object_p -#define elf_backend_object_p elf64_x86_64_nacl_elf_object_p -#undef elf_backend_modify_segment_map -#define elf_backend_modify_segment_map nacl_modify_segment_map -#undef elf_backend_modify_program_headers -#define elf_backend_modify_program_headers nacl_modify_program_headers -#undef elf_backend_final_write_processing -#define elf_backend_final_write_processing nacl_final_write_processing - -#include "elf64-target.h" - -/* Native Client x32 support. */ - -static bfd_boolean -elf32_x86_64_nacl_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for a NaCl x86-64 ELF32 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x64_32_nacl); - return TRUE; -} - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM x86_64_elf32_nacl_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-x86-64-nacl" -#undef elf32_bed -#define elf32_bed elf32_x86_64_nacl_bed - -#define bfd_elf32_bfd_reloc_type_lookup \ - elf_x86_64_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup \ - elf_x86_64_reloc_name_lookup -#define bfd_elf32_get_synthetic_symtab \ - elf_x86_64_get_synthetic_symtab - -#undef elf_backend_object_p -#define elf_backend_object_p \ - elf32_x86_64_nacl_elf_object_p - -#undef elf_backend_bfd_from_remote_memory -#define elf_backend_bfd_from_remote_memory \ - _bfd_elf32_bfd_from_remote_memory - -#undef elf_backend_size_info -#define elf_backend_size_info \ - _bfd_elf32_size_info - -#include "elf32-target.h" - -/* Restore defaults. */ -#undef elf_backend_object_p -#define elf_backend_object_p elf64_x86_64_elf_object_p -#undef elf_backend_bfd_from_remote_memory -#undef elf_backend_size_info -#undef elf_backend_modify_segment_map -#undef elf_backend_modify_program_headers -#undef elf_backend_final_write_processing - -/* Intel L1OM support. */ - -static bfd_boolean -elf64_l1om_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for an L1OM elf64 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_l1om, bfd_mach_l1om); - return TRUE; -} - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM l1om_elf64_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-l1om" -#undef ELF_ARCH -#define ELF_ARCH bfd_arch_l1om - -#undef ELF_MACHINE_CODE -#define ELF_MACHINE_CODE EM_L1OM - -#undef ELF_OSABI - -#undef elf64_bed -#define elf64_bed elf64_l1om_bed - -#undef elf_backend_object_p -#define elf_backend_object_p elf64_l1om_elf_object_p - -/* Restore defaults. */ -#undef ELF_MAXPAGESIZE -#undef ELF_MINPAGESIZE -#undef ELF_COMMONPAGESIZE -#define ELF_MAXPAGESIZE 0x200000 -#define ELF_MINPAGESIZE 0x1000 -#define ELF_COMMONPAGESIZE 0x1000 -#undef elf_backend_plt_alignment -#define elf_backend_plt_alignment 4 -#undef elf_backend_arch_data -#define elf_backend_arch_data &elf_x86_64_arch_bed - -#include "elf64-target.h" - -/* FreeBSD L1OM support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM l1om_elf64_fbsd_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-l1om-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf64_bed -#define elf64_bed elf64_l1om_fbsd_bed - -#include "elf64-target.h" - -/* Intel K1OM support. */ - -static bfd_boolean -elf64_k1om_elf_object_p (bfd *abfd) -{ - /* Set the right machine number for an K1OM elf64 file. */ - bfd_default_set_arch_mach (abfd, bfd_arch_k1om, bfd_mach_k1om); - return TRUE; -} - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM k1om_elf64_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-k1om" -#undef ELF_ARCH -#define ELF_ARCH bfd_arch_k1om - -#undef ELF_MACHINE_CODE -#define ELF_MACHINE_CODE EM_K1OM - -#undef ELF_OSABI - -#undef elf64_bed -#define elf64_bed elf64_k1om_bed - -#undef elf_backend_object_p -#define elf_backend_object_p elf64_k1om_elf_object_p - -#undef elf_backend_static_tls_alignment - -#undef elf_backend_want_plt_sym -#define elf_backend_want_plt_sym 0 - -#include "elf64-target.h" - -/* FreeBSD K1OM support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM k1om_elf64_fbsd_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf64-k1om-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf64_bed -#define elf64_bed elf64_k1om_fbsd_bed - -#include "elf64-target.h" - -/* 32bit x86-64 support. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM x86_64_elf32_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elf32-x86-64" -#undef elf32_bed - -#undef ELF_ARCH -#define ELF_ARCH bfd_arch_i386 - -#undef ELF_MACHINE_CODE -#define ELF_MACHINE_CODE EM_X86_64 - -#undef ELF_OSABI - -#undef elf_backend_object_p -#define elf_backend_object_p \ - elf32_x86_64_elf_object_p - -#undef elf_backend_bfd_from_remote_memory -#define elf_backend_bfd_from_remote_memory \ - _bfd_elf32_bfd_from_remote_memory - -#undef elf_backend_size_info -#define elf_backend_size_info \ - _bfd_elf32_size_info - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elf64.c b/sdcc/support/sdbinutils/bfd/elf64.c deleted file mode 100644 index 253863f81..000000000 --- a/sdcc/support/sdbinutils/bfd/elf64.c +++ /dev/null @@ -1,23 +0,0 @@ -/* ELF 64-bit executable support for BFD. - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define ARCH_SIZE 64 - -#include "elfcode.h" diff --git a/sdcc/support/sdbinutils/bfd/elfcore.h b/sdcc/support/sdbinutils/bfd/elfcore.h deleted file mode 100644 index 562b70889..000000000 --- a/sdcc/support/sdbinutils/bfd/elfcore.h +++ /dev/null @@ -1,315 +0,0 @@ -/* ELF core file support for BFD. - Copyright (C) 1995-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -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; -} - -int -elf_core_file_pid (bfd *abfd) -{ - return elf_tdata (abfd)->core->pid; -} - -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; - bfd_size_type amt; - - /* 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; - } - - /* Give abfd an elf_obj_tdata. */ - if (! (*abfd->xvec->_bfd_set_format[bfd_core]) (abfd)) - goto fail; - - /* 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 = xvec_get_elf_backend_data (*target_ptr); - if (back->s->arch_size != ARCH_SIZE) - continue; - 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; - - /* If the program header count is PN_XNUM(0xffff), the actual - count is in the first section header. */ - if (i_ehdrp->e_shoff != 0 && i_ehdrp->e_phnum == PN_XNUM) - { - Elf_External_Shdr x_shdr; - Elf_Internal_Shdr i_shdr; - file_ptr where = (file_ptr) i_ehdrp->e_shoff; - - /* Seek to the section header table in the file. */ - if (bfd_seek (abfd, where, SEEK_SET) != 0) - goto fail; - - /* 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 fail; - elf_swap_shdr_in (abfd, &x_shdr, &i_shdr); - - if (i_shdr.sh_info != 0) - { - i_ehdrp->e_phnum = i_shdr.sh_info; - if (i_ehdrp->e_phnum != i_shdr.sh_info) - goto wrong; - } - } - - /* Sanity check that we can read all of the program headers. - It ought to be good enough to just read the last one. */ - if (i_ehdrp->e_phnum > 1) - { - Elf_External_Phdr x_phdr; - Elf_Internal_Phdr i_phdr; - file_ptr where; - - /* Check that we don't have a totally silly number of - program headers. */ - if (i_ehdrp->e_phnum > (unsigned int) -1 / sizeof (x_phdr) - || i_ehdrp->e_phnum > (unsigned int) -1 / sizeof (i_phdr)) - goto wrong; - - where = (file_ptr)(i_ehdrp->e_phoff + (i_ehdrp->e_phnum - 1) * sizeof (x_phdr)); - if ((bfd_size_type) where <= i_ehdrp->e_phoff) - goto wrong; - - if (bfd_seek (abfd, where, SEEK_SET) != 0) - goto fail; - if (bfd_bread (&x_phdr, sizeof (x_phdr), abfd) != sizeof (x_phdr)) - goto fail; - } - - /* Move to the start of the program headers. */ - if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0) - goto wrong; - - /* Allocate space for the program headers. */ - amt = sizeof (*i_phdrp) * i_ehdrp->e_phnum; - i_phdrp = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); - if (!i_phdrp) - goto fail; - - elf_tdata (abfd)->phdr = i_phdrp; - - /* Read and convert to internal form. */ - for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) - { - Elf_External_Phdr x_phdr; - - if (bfd_bread (&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; - - /* Check for core truncation. */ - { - bfd_size_type high = 0; - struct stat statbuf; - for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) - { - Elf_Internal_Phdr *p = i_phdrp + phindex; - if (p->p_filesz) - { - bfd_size_type current = p->p_offset + p->p_filesz; - if (high < current) - high = current; - } - } - if (bfd_stat (abfd, &statbuf) == 0) - { - if ((bfd_size_type) statbuf.st_size < high) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("warning: %B is truncated: expected core file " - "size >= %Lu, found: %llu"), - abfd, high, (unsigned long long) statbuf.st_size); - } - } - } - - /* Save the entry point from the ELF header. */ - bfd_get_start_address (abfd) = i_ehdrp->e_entry; - return abfd->xvec; - -wrong: - bfd_set_error (bfd_error_wrong_format); -fail: - return NULL; -} diff --git a/sdcc/support/sdbinutils/bfd/elflink.c b/sdcc/support/sdbinutils/bfd/elflink.c deleted file mode 100644 index e3751fa12..000000000 --- a/sdcc/support/sdbinutils/bfd/elflink.c +++ /dev/null @@ -1,14362 +0,0 @@ -/* ELF linking support for BFD. - Copyright (C) 1995-2018 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "bfd_stdint.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" -#if BFD_SUPPORTS_PLUGINS -#include "plugin-api.h" -#include "plugin.h" -#endif - -/* This struct is used to pass information to routines called via - elf_link_hash_traverse which must return failure. */ - -struct elf_info_failed -{ - struct bfd_link_info *info; - bfd_boolean failed; -}; - -/* This structure is used to pass information to - _bfd_elf_link_find_version_dependencies. */ - -struct elf_find_verdep_info -{ - /* General link information. */ - struct bfd_link_info *info; - /* The number of dependencies. */ - unsigned int vers; - /* Whether we had a failure. */ - bfd_boolean failed; -}; - -static bfd_boolean _bfd_elf_fix_symbol_flags - (struct elf_link_hash_entry *, struct elf_info_failed *); - -asection * -_bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie, - unsigned long r_symndx, - bfd_boolean discard) -{ - if (r_symndx >= cookie->locsymcount - || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) - { - struct elf_link_hash_entry *h; - - h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && discarded_section (h->root.u.def.section)) - return h->root.u.def.section; - else - return NULL; - } - else - { - /* It's not a relocation against a global symbol, - but it could be a relocation against a local - symbol for a discarded section. */ - asection *isec; - Elf_Internal_Sym *isym; - - /* Need to: get the symbol; get the section. */ - isym = &cookie->locsyms[r_symndx]; - isec = bfd_section_from_elf_index (cookie->abfd, isym->st_shndx); - if (isec != NULL - && discard ? discarded_section (isec) : 1) - return isec; - } - return NULL; -} - -/* Define a symbol in a dynamic linkage section. */ - -struct elf_link_hash_entry * -_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; - } - else - bh = NULL; - - bed = get_elf_backend_data (abfd); - if (!_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_GLOBAL, - sec, 0, NULL, FALSE, bed->collect, - &bh)) - return NULL; - h = (struct elf_link_hash_entry *) bh; - BFD_ASSERT (h != NULL); - h->def_regular = 1; - h->non_elf = 0; - h->root.linker_def = 1; - h->type = STT_OBJECT; - if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; - - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - 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); - struct elf_link_hash_table *htab = elf_hash_table (info); - - /* This function may be called more than once. */ - if (htab->sgot != NULL) - return TRUE; - - flags = bed->dynamic_sec_flags; - - s = bfd_make_section_anyway_with_flags (abfd, - (bed->rela_plts_and_copies_p - ? ".rela.got" : ".rel.got"), - (bed->dynamic_sec_flags - | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - htab->srelgot = s; - - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - htab->sgot = s; - - if (bed->want_got_plt) - { - s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); - if (s == NULL - || !bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->sgotplt = s; - } - - /* The first bit of the global offset table is the header. */ - s->size += bed->got_header_size; - - 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; - } - - 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) - { - /* We may not set dynobj, an input file holding linker created - dynamic sections to abfd, which may be a dynamic object with - its own dynamic sections. We need to find a normal input file - to hold linker created sections if possible. */ - if ((abfd->flags & (DYNAMIC | BFD_PLUGIN)) != 0) - { - bfd *ibfd; - asection *s; - for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next) - if ((ibfd->flags - & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0 - && bfd_get_flavour (ibfd) == bfd_target_elf_flavour - && !((s = ibfd->sections) != NULL - && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)) - { - abfd = ibfd; - break; - } - } - 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; - asection *s; - const struct elf_backend_data *bed; - struct elf_link_hash_entry *h; - - 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 (bfd_link_executable (info) && !info->nointerp) - { - s = bfd_make_section_anyway_with_flags (abfd, ".interp", - flags | SEC_READONLY); - if (s == NULL) - return FALSE; - } - - /* Create sections to hold version informations. These are removed - if they are not needed. */ - s = bfd_make_section_anyway_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_anyway_with_flags (abfd, ".gnu.version", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 1)) - return FALSE; - - s = bfd_make_section_anyway_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_anyway_with_flags (abfd, ".dynsym", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - elf_hash_table (info)->dynsym = s; - - s = bfd_make_section_anyway_with_flags (abfd, ".dynstr", - flags | SEC_READONLY); - if (s == NULL) - return FALSE; - - s = bfd_make_section_anyway_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. */ - h = _bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC"); - elf_hash_table (info)->hdynamic = h; - if (h == NULL) - return FALSE; - - if (info->emit_hash) - { - s = bfd_make_section_anyway_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; - } - - if (info->emit_gnu_hash) - { - s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - /* For 64-bit ELF, .gnu.hash is a non-uniform entity size section: - 4 32-bit words followed by variable count of 64-bit words, then - variable count of 32-bit words. */ - if (bed->s->arch_size == 64) - elf_section_data (s)->this_hdr.sh_entsize = 0; - else - elf_section_data (s)->this_hdr.sh_entsize = 4; - } - - /* 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 == NULL - || ! (*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); - struct elf_link_hash_table *htab = elf_hash_table (info); - - /* 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_anyway_with_flags (abfd, ".plt", pltflags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) - return FALSE; - htab->splt = s; - - /* 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_anyway_with_flags (abfd, - (bed->rela_plts_and_copies_p - ? ".rela.plt" : ".rel.plt"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - htab->srelplt = s; - - 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_anyway_with_flags (abfd, ".dynbss", - SEC_ALLOC | SEC_LINKER_CREATED); - if (s == NULL) - return FALSE; - htab->sdynbss = s; - - if (bed->want_dynrelro) - { - /* Similarly, but for symbols that were originally in read-only - sections. This section doesn't really need to have contents, - but make it like other .data.rel.ro sections. */ - s = bfd_make_section_anyway_with_flags (abfd, ".data.rel.ro", - flags); - if (s == NULL) - return FALSE; - htab->sdynrelro = s; - } - - /* 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 (bfd_link_executable (info)) - { - s = bfd_make_section_anyway_with_flags (abfd, - (bed->rela_plts_and_copies_p - ? ".rela.bss" : ".rel.bss"), - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) - return FALSE; - htab->srelbss = s; - - if (bed->want_dynrelro) - { - s = (bfd_make_section_anyway_with_flags - (abfd, (bed->rela_plts_and_copies_p - ? ".rela.data.rel.ro" : ".rel.data.rel.ro"), - flags | SEC_READONLY)); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) - return FALSE; - htab->sreldynrelro = s; - } - } - } - - 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; - size_t 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 == (size_t) -1) - return FALSE; - h->dynstr_index = indx; - } - - return TRUE; -} - -/* Mark a symbol dynamic. */ - -static void -bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - struct bfd_elf_dynamic_list *d = info->dynamic_list; - - /* It may be called more than once on the same H. */ - if(h->dynamic || bfd_link_relocatable (info)) - return; - - if ((info->dynamic_data - && (h->type == STT_OBJECT - || h->type == STT_COMMON - || (sym != NULL - && (ELF_ST_TYPE (sym->st_info) == STT_OBJECT - || ELF_ST_TYPE (sym->st_info) == STT_COMMON)))) - || (d != NULL - && h->non_elf - && (*d->match) (&d->head, NULL, h->root.root.string))) - h->dynamic = 1; -} - -/* 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, *hv; - struct elf_link_hash_table *htab; - const struct elf_backend_data *bed; - - 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; - - if (h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->versioned == unknown) - { - /* Set versioned if symbol version is unknown. */ - char *version = strrchr (name, ELF_VER_CHR); - if (version) - { - if (version > name && version[-1] != ELF_VER_CHR) - h->versioned = versioned_hidden; - else - h->versioned = versioned; - } - } - - /* Symbols defined in a linker script but not referenced anywhere - else will have non_elf set. */ - if (h->non_elf) - { - bfd_elf_link_mark_dynamic_symbol (info, h, NULL); - h->non_elf = 0; - } - - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - case bfd_link_hash_common: - break; - case bfd_link_hash_undefweak: - case bfd_link_hash_undefined: - /* 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. */ - 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); - break; - case bfd_link_hash_new: - break; - case bfd_link_hash_indirect: - /* We had a versioned symbol in a dynamic library. We make the - the versioned symbol point to this one. */ - bed = get_elf_backend_data (output_bfd); - hv = h; - while (hv->root.type == bfd_link_hash_indirect - || hv->root.type == bfd_link_hash_warning) - hv = (struct elf_link_hash_entry *) hv->root.u.i.link; - /* We don't need to update h->root.u since linker will set them - later. */ - h->root.type = bfd_link_hash_undefined; - hv->root.type = bfd_link_hash_indirect; - hv->root.u.i.link = (struct bfd_link_hash_entry *) h; - (*bed->elf_backend_copy_indirect_symbol) (info, h, hv); - break; - default: - BFD_FAIL (); - return FALSE; - } - - /* 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; - - /* Make sure this symbol is not garbage collected. */ - h->mark = 1; - - h->def_regular = 1; - - if (hidden) - { - bed = get_elf_backend_data (output_bfd); - if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - } - - /* STV_HIDDEN and STV_INTERNAL symbols must be STB_LOCAL in shared objects - and executables. */ - if (!bfd_link_relocatable (info) - && 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 - || bfd_link_dll (info) - || 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - - if (def->dynindx == -1 - && !bfd_elf_link_record_dynamic_symbol (info, def)) - 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; - size_t 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 = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt); - if (entry == NULL) - return 0; - - /* Go find the symbol, so that we can find it's name. */ - if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr, - 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) - { - 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 == (size_t) -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 = (size_t *) data; - - 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 = (size_t *) data; - - 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) -{ - struct elf_link_hash_table *htab; - asection *ip; - - 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: - htab = elf_hash_table (info); - if (p == htab->tls_sec) - return FALSE; - - if (htab->text_index_section != NULL) - return p != htab->text_index_section && p != htab->data_index_section; - - return (htab->dynobj != NULL - && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL - && ip->output_section == p); - - /* 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. If SECTION_SYM_COUNT is NULL, section dynindx is not set. - (This prevents the early call before elf_backend_init_index_section - and strip_excluded_output_sections setting dynindx for sections - that are stripped.) */ - -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; - bfd_boolean do_sec = section_sym_count != NULL; - - if (bfd_link_pic (info) - || 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)) - { - ++dynsymcount; - if (do_sec) - elf_section_data (p)->dynindx = dynsymcount; - } - else if (do_sec) - elf_section_data (p)->dynindx = 0; - } - if (do_sec) - *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_hash_table (info)->local_dynsymcount = 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 even if the table is empty since it - is intended for the mandatory DT_SYMTAB tag (.dynsym section) in - .dynamic section. */ - dynsymcount++; - - elf_hash_table (info)->dynsymcount = dynsymcount; - return dynsymcount; -} - -/* Merge st_other field. */ - -static void -elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, asection *sec, - bfd_boolean definition, bfd_boolean dynamic) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - - /* If st_other has a processor-specific meaning, specific - code might be needed here. */ - if (bed->elf_backend_merge_symbol_attribute) - (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, - dynamic); - - if (!dynamic) - { - unsigned symvis = ELF_ST_VISIBILITY (isym->st_other); - unsigned hvis = ELF_ST_VISIBILITY (h->other); - - /* Keep the most constraining visibility. Leave the remainder - of the st_other field to elf_backend_merge_symbol_attribute. */ - if (symvis - 1 < hvis - 1) - h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1)); - } - else if (definition - && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT - && (sec->flags & SEC_READONLY) == 0) - h->protected_def = 1; -} - -/* This function is called when we want to merge a new symbol with an - existing symbol. It handles the various cases which arise when we - find a definition in a dynamic object, or when there is already a - definition in a dynamic object. The new symbol is described by - NAME, SYM, PSEC, and PVALUE. We set SYM_HASH to the hash table - entry. We set POLDBFD to the old symbol's BFD. We set POLD_WEAK - if the old symbol was weak. We set POLD_ALIGNMENT to the alignment - of an old common symbol. We set OVERRIDE if the old symbol is - overriding a new definition. We set TYPE_CHANGE_OK if it is OK for - the type to change. We set SIZE_CHANGE_OK if it is OK for the size - to change. By OK to change, we mean that we shouldn't warn if the - type or size does change. */ - -static bfd_boolean -_bfd_elf_merge_symbol (bfd *abfd, - struct bfd_link_info *info, - const char *name, - Elf_Internal_Sym *sym, - asection **psec, - bfd_vma *pvalue, - struct elf_link_hash_entry **sym_hash, - bfd **poldbfd, - bfd_boolean *pold_weak, - unsigned int *pold_alignment, - bfd_boolean *skip, - bfd_boolean *override, - bfd_boolean *type_change_ok, - bfd_boolean *size_change_ok, - bfd_boolean *matched) -{ - asection *sec, *oldsec; - struct elf_link_hash_entry *h; - struct elf_link_hash_entry *hi; - struct elf_link_hash_entry *flip; - int bind; - bfd *oldbfd; - bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon; - bfd_boolean newweak, oldweak, newfunc, oldfunc; - const struct elf_backend_data *bed; - char *new_version; - bfd_boolean default_sym = *matched; - - *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; - - bed = get_elf_backend_data (abfd); - - /* NEW_VERSION is the symbol version of the new symbol. */ - if (h->versioned != unversioned) - { - /* Symbol version is unknown or versioned. */ - new_version = strrchr (name, ELF_VER_CHR); - if (new_version) - { - if (h->versioned == unknown) - { - if (new_version > name && new_version[-1] != ELF_VER_CHR) - h->versioned = versioned_hidden; - else - h->versioned = versioned; - } - new_version += 1; - if (new_version[0] == '\0') - new_version = NULL; - } - else - h->versioned = unversioned; - } - else - new_version = NULL; - - /* For merging, we only care about real symbols. But we need to make - sure that indirect symbol dynamic flags are updated. */ - hi = h; - 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 (!*matched) - { - if (hi == h || h->root.type == bfd_link_hash_new) - *matched = TRUE; - else - { - /* OLD_HIDDEN is true if the existing symbol is only visible - to the symbol with the same symbol version. NEW_HIDDEN is - true if the new symbol is only visible to the symbol with - the same symbol version. */ - bfd_boolean old_hidden = h->versioned == versioned_hidden; - bfd_boolean new_hidden = hi->versioned == versioned_hidden; - if (!old_hidden && !new_hidden) - /* The new symbol matches the existing symbol if both - aren't hidden. */ - *matched = TRUE; - else - { - /* OLD_VERSION is the symbol version of the existing - symbol. */ - char *old_version; - - if (h->versioned >= versioned) - old_version = strrchr (h->root.root.string, - ELF_VER_CHR) + 1; - else - old_version = NULL; - - /* The new symbol matches the existing symbol if they - have the same symbol version. */ - *matched = (old_version == new_version - || (old_version != NULL - && new_version != NULL - && strcmp (old_version, new_version) == 0)); - } - } - } - - /* OLDBFD and OLDSEC are a BFD and an ASECTION associated with the - existing symbol. */ - - oldbfd = NULL; - oldsec = NULL; - switch (h->root.type) - { - default: - break; - - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - oldbfd = h->root.u.undef.abfd; - break; - - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - oldbfd = h->root.u.def.section->owner; - oldsec = h->root.u.def.section; - break; - - case bfd_link_hash_common: - oldbfd = h->root.u.c.p->section->owner; - oldsec = h->root.u.c.p->section; - if (pold_alignment) - *pold_alignment = h->root.u.c.p->alignment_power; - break; - } - if (poldbfd && *poldbfd == NULL) - *poldbfd = oldbfd; - - /* Differentiate strong and weak symbols. */ - newweak = bind == STB_WEAK; - oldweak = (h->root.type == bfd_link_hash_defweak - || h->root.type == bfd_link_hash_undefweak); - if (pold_weak) - *pold_weak = oldweak; - - /* We have to check it for every instance since the first few may be - references and not all compilers emit symbol type for undefined - symbols. */ - bfd_elf_link_mark_dynamic_symbol (info, h, sym); - - /* NEWDYN and OLDDYN indicate whether the new or old symbol, - respectively, is from a dynamic object. */ - - newdyn = (abfd->flags & DYNAMIC) != 0; - - /* ref_dynamic_nonweak and dynamic_def flags track actual undefined - syms and defined syms in dynamic libraries respectively. - ref_dynamic on the other hand can be set for a symbol defined in - a dynamic library, and def_dynamic may not be set; When the - definition in a dynamic lib is overridden by a definition in the - executable use of the symbol in the dynamic lib becomes a - reference to the executable symbol. */ - if (newdyn) - { - if (bfd_is_und_section (sec)) - { - if (bind != STB_WEAK) - { - h->ref_dynamic_nonweak = 1; - hi->ref_dynamic_nonweak = 1; - } - } - else - { - /* Update the existing symbol only if they match. */ - if (*matched) - h->dynamic_def = 1; - hi->dynamic_def = 1; - } - } - - /* 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; - } - - /* 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 - && (newweak || oldweak) - && ((abfd->flags & DYNAMIC) == 0 - || !h->def_regular)) - return TRUE; - - 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; - } - - /* Handle a case where plugin_notice won't be called and thus won't - set the non_ir_ref flags on the first pass over symbols. */ - if (oldbfd != NULL - && (oldbfd->flags & BFD_PLUGIN) != (abfd->flags & BFD_PLUGIN) - && newdyn != olddyn) - { - h->root.non_ir_ref_dynamic = TRUE; - hi->root.non_ir_ref_dynamic = TRUE; - } - - /* 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); - - /* NEWFUNC and OLDFUNC indicate whether the new or old symbol, - respectively, appear to be a function. */ - - newfunc = (ELF_ST_TYPE (sym->st_info) != STT_NOTYPE - && bed->is_function_type (ELF_ST_TYPE (sym->st_info))); - - oldfunc = (h->type != STT_NOTYPE - && bed->is_function_type (h->type)); - - if (!(newfunc && oldfunc) - && ELF_ST_TYPE (sym->st_info) != h->type - && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE - && h->type != STT_NOTYPE - && (newdef || bfd_is_com_section (sec)) - && (olddef || h->root.type == bfd_link_hash_common)) - { - /* If creating a default indirect symbol ("foo" or "foo@") from - a dynamic versioned definition ("foo@@") skip doing so if - there is an existing regular definition with a different - type. We don't want, for example, a "time" variable in the - executable overriding a "time" function in a shared library. */ - if (newdyn - && !olddyn) - { - *skip = TRUE; - return TRUE; - } - - /* When adding a symbol from a regular object file after we have - created indirect symbols, undo the indirection and any - dynamic state. */ - if (hi != h - && !newdyn - && olddyn) - { - h = hi; - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - h->forced_local = 0; - h->ref_dynamic = 0; - h->def_dynamic = 0; - h->dynamic_def = 0; - if (h->root.u.undef.next || info->hash->undefs_tail == &h->root) - { - 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; - } - return TRUE; - } - } - - /* Check TLS symbols. We don't check undefined symbols introduced - by "ld -u" which have no type (and oldbfd NULL), and we don't - check symbols from plugins because they also have no type. */ - if (oldbfd != NULL - && (oldbfd->flags & BFD_PLUGIN) == 0 - && (abfd->flags & BFD_PLUGIN) == 0 - && ELF_ST_TYPE (sym->st_info) != h->type - && (ELF_ST_TYPE (sym->st_info) == STT_TLS || h->type == STT_TLS)) - { - bfd *ntbfd, *tbfd; - bfd_boolean ntdef, tdef; - 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 - /* xgettext:c-format */ - (_("%s: TLS definition in %B section %A " - "mismatches non-TLS definition in %B section %A"), - h->root.root.string, tbfd, tsec, ntbfd, ntsec); - else if (!tdef && !ntdef) - _bfd_error_handler - /* xgettext:c-format */ - (_("%s: TLS reference in %B " - "mismatches non-TLS reference in %B"), - h->root.root.string, tbfd, ntbfd); - else if (tdef) - _bfd_error_handler - /* xgettext:c-format */ - (_("%s: TLS definition in %B section %A " - "mismatches non-TLS reference in %B"), - h->root.root.string, tbfd, tsec, ntbfd); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("%s: TLS reference in %B " - "mismatches non-TLS definition in %B section %A"), - h->root.root.string, tbfd, ntbfd, ntsec); - - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - /* 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; - hi->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 (hi->root.type == bfd_link_hash_indirect) - { - /* Handle the case where the old dynamic definition is - default versioned. We need to copy the symbol info from - the symbol with default version to the normal one if it - was referenced before. */ - if (h->ref_regular) - { - hi->root.type = h->root.type; - h->root.type = bfd_link_hash_indirect; - (*bed->elf_backend_copy_indirect_symbol) (info, hi, h); - - h->root.u.i.link = (struct bfd_link_hash_entry *) hi; - if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) - { - /* If the new symbol is hidden or internal, completely undo - any dynamic link state. */ - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - h->forced_local = 0; - h->ref_dynamic = 0; - } - else - h->ref_dynamic = 1; - - h->def_dynamic = 0; - /* FIXME: Should we check type and size for protected symbol? */ - h->size = 0; - h->type = 0; - - h = hi; - } - else - h = hi; - } - - /* If the old symbol was undefined before, then it will still be - on the undefs list. If the new symbol is undefined or - common, we can't make it bfd_link_hash_new here, because new - undefined or common symbols will be added to the undefs list - by _bfd_generic_link_add_one_symbol. Symbols may not be - added twice to the undefs list. Also, if the new symbol is - undefweak then we don't want to lose the strong undef. */ - if (h->root.u.undef.next || info->hash->undefs_tail == &h->root) - { - 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 (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED) - { - /* If the new symbol is hidden or internal, completely undo - any dynamic link state. */ - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - h->forced_local = 0; - h->ref_dynamic = 0; - } - else - h->ref_dynamic = 1; - h->def_dynamic = 0; - /* FIXME: Should we check type and size for protected symbol? */ - h->size = 0; - h->type = 0; - return TRUE; - } - - /* 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. - - Also allow a weak symbol to override a linker script symbol - defined by an early pass over the script. This is done so the - linker knows the symbol is defined in an object file, for the - DEFINED script function. - - 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 || h->root.ldscript_def)) - newweak = FALSE; - if (olddef && newdyn) - oldweak = FALSE; - - /* Allow changes between different types of function symbol. */ - if (newfunc && oldfunc) - *type_change_ok = TRUE; - - /* 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 - && !newfunc) - 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 - && !oldfunc) - 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. */ - if (bed->merge_symbol != NULL) - { - if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec)) - return FALSE; - sec = *psec; - } - - /* There are multiple definitions of a normal symbol. Skip the - default symbol as well as definition from an IR object. */ - if (olddef && !olddyn && !oldweak && newdef && !newdyn && !newweak - && !default_sym && h->def_regular - && !(oldbfd != NULL - && (oldbfd->flags & BFD_PLUGIN) != 0 - && (abfd->flags & BFD_PLUGIN) == 0)) - { - /* Handle a multiple definition. */ - (*info->callbacks->multiple_definition) (info, &h->root, - abfd, sec, *pvalue); - *skip = TRUE; - return TRUE; - } - - /* If both the old and the new symbols look like common symbols in a - dynamic object, set the size of the symbol to the larger of the - two. */ - - if (olddyncommon - && newdyncommon - && sym->st_size != h->size) - { - /* Since we think we have two common symbols, issue a multiple - common warning if desired. Note that we only warn if the - size is different. If the size is the same, we simply let - the old symbol override the new one as normally happens with - symbols defined in dynamic objects. */ - - (*info->callbacks->multiple_common) (info, &h->root, abfd, - bfd_link_hash_common, sym->st_size); - 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 || newfunc)))) - { - *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) - { - /* Don't skip new non-IR weak syms. */ - if (!(oldbfd != NULL - && (oldbfd->flags & BFD_PLUGIN) != 0 - && (abfd->flags & BFD_PLUGIN) == 0)) - { - newdef = FALSE; - *skip = TRUE; - } - - /* Merge st_other. If the symbol already has a dynamic index, - but visibility says it should not be visible, turn it into a - local symbol. */ - elf_merge_st_other (abfd, h, sym, sec, newdef, newdyn); - if (h->dynindx != -1) - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - break; - } - } - - /* 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 || oldfunc))) - && 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)) - { - if (oldfunc) - { - /* If a common symbol overrides a function, make sure - that it isn't defined dynamically nor has type - function. */ - h->def_dynamic = 0; - h->type = STT_NOTYPE; - } - *type_change_ok = TRUE; - } - - if (hi->root.type == bfd_link_hash_indirect) - flip = hi; - else - /* This union may have been set to be non-NULL when this symbol - was seen in a dynamic object. We must force the union to be - 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. */ - (*info->callbacks->multiple_common) (info, &h->root, abfd, - bfd_link_hash_common, sym->st_size); - - /* 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 (hi->root.type == bfd_link_hash_indirect) - flip = hi; - 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. */ - flip->root.type = h->root.type; - flip->root.u.undef.abfd = h->root.u.undef.abfd; - 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); - 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, SEC, and VALUE. We - set DYNSYM if the new indirect symbol is dynamic. */ - -static 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 *sec, - bfd_vma value, - bfd **poldbfd, - bfd_boolean *dynsym) -{ - 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; - bfd_boolean override; - char *p; - size_t len, shortlen; - asection *tmp_sec; - bfd_boolean matched; - - if (h->versioned == unversioned || h->versioned == versioned_hidden) - return TRUE; - - /* 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 (h->versioned == unknown) - { - if (p == NULL) - { - h->versioned = unversioned; - return TRUE; - } - else - { - if (p[1] != ELF_VER_CHR) - { - h->versioned = versioned_hidden; - return TRUE; - } - else - h->versioned = versioned; - } - } - else - { - /* PR ld/19073: We may see an unversioned definition after the - default version. */ - if (p == NULL) - return TRUE; - } - - bed = get_elf_backend_data (abfd); - collect = bed->collect; - dynamic = (abfd->flags & DYNAMIC) != 0; - - shortlen = p - name; - shortname = (char *) 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; - matched = TRUE; - tmp_sec = sec; - if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, - &hi, poldbfd, NULL, NULL, &skip, &override, - &type_change_ok, &size_change_ok, &matched)) - return FALSE; - - if (skip) - goto nondefault; - - if (hi->def_regular) - { - /* If the undecorated symbol will have a version added by a - script different to H, then don't indirect to/from the - undecorated symbol. This isn't ideal because we may not yet - have seen symbol versions, if given by a script on the - command line rather than via --version-script. */ - if (hi->verinfo.vertree == NULL && info->version_info != NULL) - { - bfd_boolean hide; - - hi->verinfo.vertree - = bfd_find_version_for_sym (info->version_info, - hi->root.root.string, &hide); - if (hi->verinfo.vertree != NULL && hide) - { - (*bed->elf_backend_hide_symbol) (info, hi, TRUE); - goto nondefault; - } - } - if (hi->verinfo.vertree != NULL - && strcmp (p + 1 + (p[1] == '@'), hi->verinfo.vertree->name) != 0) - goto nondefault; - } - - if (! override) - { - /* Add the default symbol if not performing a relocatable link. */ - if (! bfd_link_relocatable (info)) - { - 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; - } - - /* Check if HI is a warning symbol. */ - if (hi->root.type == bfd_link_hash_warning) - hi = (struct elf_link_hash_entry *) hi->root.u.i.link; - - /* 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); - - /* A reference to the SHORTNAME symbol from a dynamic library - will be satisfied by the versioned symbol at runtime. In - effect, we have a reference to the versioned symbol. */ - ht->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; - hi->dynamic_def |= ht->dynamic_def; - - /* See if the new flags lead us to realize that the symbol must - be dynamic. */ - if (! *dynsym) - { - if (! dynamic) - { - if (! bfd_link_executable (info) - || hi->def_dynamic - || 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 = (char *) 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; - tmp_sec = sec; - if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value, - &hi, poldbfd, NULL, NULL, &skip, &override, - &type_change_ok, &size_change_ok, &matched)) - 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 - /* xgettext:c-format */ - (_("%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); - h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; - hi->dynamic_def |= h->dynamic_def; - - /* See if the new flags lead us to realize that the symbol - must be dynamic. */ - if (! *dynsym) - { - if (! dynamic) - { - if (! bfd_link_executable (info) - || 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. */ - -static bfd_boolean -_bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data) -{ - struct elf_info_failed *eif = (struct elf_info_failed *) data; - - /* Ignore indirect symbols. These are added by the versioning code. */ - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - /* Ignore this if we won't export it. */ - if (!eif->info->export_dynamic && !h->dynamic) - return TRUE; - - if (h->dynindx == -1 - && (h->def_regular || h->ref_regular) - && ! bfd_hide_sym_by_version (eif->info->version_info, - h->root.root.string)) - { - if (! bfd_elf_link_record_dynamic_symbol (eif->info, h)) - { - eif->failed = TRUE; - return FALSE; - } - } - - return TRUE; -} - -/* Look through the symbols which are defined in other shared - libraries and referenced here. Update the list of version - dependencies. This will be put into the .gnu.version_r section. - This function is called via elf_link_hash_traverse. */ - -static bfd_boolean -_bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, - void *data) -{ - struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data; - Elf_Internal_Verneed *t; - Elf_Internal_Vernaux *a; - bfd_size_type amt; - - /* 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 - || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd) - & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED))) - return TRUE; - - /* See if we already know about this version. */ - for (t = elf_tdata (rinfo->info->output_bfd)->verref; - t != NULL; - t = t->vn_nextref) - { - if (t->vn_bfd != h->verinfo.verdef->vd_bfd) - continue; - - for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) - if (a->vna_nodename == h->verinfo.verdef->vd_nodename) - return TRUE; - - break; - } - - /* This is a new version. Add it to tree we are building. */ - - if (t == NULL) - { - amt = sizeof *t; - t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->info->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->info->output_bfd)->verref; - elf_tdata (rinfo->info->output_bfd)->verref = t; - } - - amt = sizeof *a; - a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->info->output_bfd, amt); - if (a == NULL) - { - rinfo->failed = TRUE; - return FALSE; - } - - /* Note that we are copying a string pointer here, and testing it - above. If bfd_elf_string_from_elf_section is ever changed to - discard the string data when low in memory, this will have to be - fixed. */ - a->vna_nodename = h->verinfo.verdef->vd_nodename; - - a->vna_flags = h->verinfo.verdef->vd_flags; - a->vna_nextptr = t->vn_auxptr; - - h->verinfo.verdef->vd_exp_refno = rinfo->vers; - ++rinfo->vers; - - a->vna_other = h->verinfo.verdef->vd_exp_refno + 1; - - t->vn_auxptr = a; - - return TRUE; -} - -/* Figure out appropriate versions for all the symbols. We may not - have the version number script until we have read all of the input - files, so until that point we don't know which symbols should be - local. This function is called via elf_link_hash_traverse. */ - -static bfd_boolean -_bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data) -{ - struct elf_info_failed *sinfo; - struct bfd_link_info *info; - const struct elf_backend_data *bed; - struct elf_info_failed eif; - char *p; - - sinfo = (struct elf_info_failed *) data; - info = sinfo->info; - - /* 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 (info->output_bfd); - p = strchr (h->root.root.string, ELF_VER_CHR); - if (p != NULL && h->verinfo.vertree == NULL) - { - struct bfd_elf_version_tree *t; - - ++p; - if (*p == ELF_VER_CHR) - ++p; - - /* If there is no version string, we can just return out. */ - if (*p == '\0') - return TRUE; - - /* Look for the version. If we find it, it is no longer weak. */ - for (t = sinfo->info->version_info; 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 = (char *) bfd_malloc (len); - if (alc == NULL) - { - sinfo->failed = TRUE; - 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 && bfd_link_executable (info)) - { - 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; - - t = (struct bfd_elf_version_tree *) bfd_zalloc (info->output_bfd, - sizeof *t); - 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->info->version_info != NULL - && sinfo->info->version_info->vernum == 0) - version_index = 0; - for (pp = &sinfo->info->version_info; - *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 - /* xgettext:c-format */ - (_("%B: version node not found for symbol %s"), - info->output_bfd, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - sinfo->failed = TRUE; - return FALSE; - } - } - - /* If we don't have a version for this symbol, see if we can find - something. */ - if (h->verinfo.vertree == NULL && sinfo->info->version_info != NULL) - { - bfd_boolean hide; - - h->verinfo.vertree - = bfd_find_version_for_sym (sinfo->info->version_info, - h->root.root.string, &hide); - if (h->verinfo.vertree != NULL && hide) - (*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 = NUM_SHDR_ENTRIES (symtab_hdr); - - 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 = (const bfd_byte *) 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 (nsyms > 0) - { - if ((size_t) r_symndx >= nsyms) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: bad reloc symbol index (%#Lx >= %#lx)" - " for offset %#Lx in section `%A'"), - abfd, r_symndx, (unsigned long) nsyms, - irela->r_offset, sec); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - } - else if (r_symndx != STN_UNDEF) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: non-zero symbol index (%#Lx)" - " for offset %#Lx in section `%A'" - " when the object file has no symbol table"), - abfd, r_symndx, - irela->r_offset, sec); - 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 - RELA_HDR 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) -{ - void *alloc1 = NULL; - Elf_Internal_Rela *alloc2 = NULL; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct bfd_elf_section_data *esdo = elf_section_data (o); - Elf_Internal_Rela *internal_rela_relocs; - - if (esdo->relocs != NULL) - return esdo->relocs; - - if (o->reloc_count == 0) - return NULL; - - if (internal_relocs == NULL) - { - bfd_size_type size; - - size = (bfd_size_type) o->reloc_count * sizeof (Elf_Internal_Rela); - if (keep_memory) - internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_alloc (abfd, size); - else - internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size); - if (internal_relocs == NULL) - goto error_return; - } - - if (external_relocs == NULL) - { - bfd_size_type size = 0; - - if (esdo->rel.hdr) - size += esdo->rel.hdr->sh_size; - if (esdo->rela.hdr) - size += esdo->rela.hdr->sh_size; - - alloc1 = bfd_malloc (size); - if (alloc1 == NULL) - goto error_return; - external_relocs = alloc1; - } - - internal_rela_relocs = internal_relocs; - if (esdo->rel.hdr) - { - if (!elf_link_read_relocs_from_section (abfd, o, esdo->rel.hdr, - external_relocs, - internal_relocs)) - goto error_return; - external_relocs = (((bfd_byte *) external_relocs) - + esdo->rel.hdr->sh_size); - internal_rela_relocs += (NUM_SHDR_ENTRIES (esdo->rel.hdr) - * bed->s->int_rels_per_ext_rel); - } - - if (esdo->rela.hdr - && (!elf_link_read_relocs_from_section (abfd, o, esdo->rela.hdr, - external_relocs, - internal_rela_relocs))) - goto error_return; - - /* Cache the results for next time, if we can. */ - if (keep_memory) - esdo->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) - { - if (keep_memory) - bfd_release (abfd, alloc2); - else - 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. */ - -static bfd_boolean -_bfd_elf_link_size_reloc_section (bfd *abfd, - struct bfd_elf_section_reloc_data *reldata) -{ - Elf_Internal_Shdr *rel_hdr = reldata->hdr; - - /* That allows us to calculate the size of the section. */ - rel_hdr->sh_size = rel_hdr->sh_entsize * reldata->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 = (unsigned char *) bfd_zalloc (abfd, rel_hdr->sh_size); - if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) - return FALSE; - - if (reldata->hashes == NULL && reldata->count) - { - struct elf_link_hash_entry **p; - - p = ((struct elf_link_hash_entry **) - bfd_zmalloc (reldata->count * sizeof (*p))); - if (p == NULL) - return FALSE; - - reldata->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; - struct bfd_elf_section_reloc_data *output_reldata; - asection *output_section; - const struct elf_backend_data *bed; - void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); - struct bfd_elf_section_data *esdo; - - output_section = input_section->output_section; - - bed = get_elf_backend_data (output_bfd); - esdo = elf_section_data (output_section); - if (esdo->rel.hdr && esdo->rel.hdr->sh_entsize == input_rel_hdr->sh_entsize) - { - output_reldata = &esdo->rel; - swap_out = bed->s->swap_reloc_out; - } - else if (esdo->rela.hdr - && esdo->rela.hdr->sh_entsize == input_rel_hdr->sh_entsize) - { - output_reldata = &esdo->rela; - swap_out = bed->s->swap_reloca_out; - } - else - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: relocation size mismatch in %B section %A"), - output_bfd, input_section->owner, input_section); - bfd_set_error (bfd_error_wrong_format); - return FALSE; - } - - erel = output_reldata->hdr->contents; - erel += output_reldata->count * 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. */ - output_reldata->count += 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 (bfd_link_pie (info) - && 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. */ - -static bfd_boolean -_bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, - struct elf_info_failed *eif) -{ - const struct elf_backend_data *bed; - - /* 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. */ - 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 | BFD_PLUGIN)) == 0) - h->def_regular = 1; - - /* 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) - (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE); - - /* A hidden versioned symbol in executable should be forced local if - it is is locally defined, not referenced by shared library and not - exported. */ - else if (bfd_link_executable (eif->info) - && h->versioned == versioned_hidden - && !eif->info->export_dynamic - && !h->dynamic - && !h->ref_dynamic - && h->def_regular) - (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE); - - /* 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. */ - else if (h->needs_plt - && bfd_link_pic (eif->info) - && is_elf_hash_table (eif->info->hash) - && (SYMBOLIC_BIND (eif->info, h) - || 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 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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - - /* 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 (def->def_regular) - { - h = def; - while ((h = h->u.alias) != def) - h->is_weakalias = 0; - } - else - { - while (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 (def->def_dynamic); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); - (*bed->elf_backend_copy_indirect_symbol) (eif->info, def, h); - } - } - - return TRUE; -} - -/* Make the backend pick a good value for a dynamic symbol. This is - called via elf_link_hash_traverse, and also calls itself - recursively. */ - -static bfd_boolean -_bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) -{ - struct elf_info_failed *eif = (struct elf_info_failed *) data; - struct elf_link_hash_table *htab; - const struct elf_backend_data *bed; - - if (! is_elf_hash_table (eif->info->hash)) - return FALSE; - - /* 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; - - htab = elf_hash_table (eif->info); - bed = get_elf_backend_data (htab->dynobj); - - if (h->root.type == bfd_link_hash_undefweak) - { - if (eif->info->dynamic_undefined_weak == 0) - (*bed->elf_backend_hide_symbol) (eif->info, h, TRUE); - else if (eif->info->dynamic_undefined_weak > 0 - && h->ref_regular - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !bfd_hide_sym_by_version (eif->info->version_info, - h->root.root.string)) - { - if (!bfd_elf_link_record_dynamic_symbol (eif->info, h)) - { - eif->failed = TRUE; - 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->type != STT_GNU_IFUNC - && (h->def_regular - || !h->def_dynamic - || (!h->ref_regular - && (!h->is_weakalias || weakdef (h)->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->is_weakalias) - { - struct elf_link_hash_entry *def = weakdef (h); - - /* If we get to this point, there is an implicit reference to - the alias by a regular object file via the weak symbol H. */ - def->ref_regular = 1; - - /* Ensure that the backend adjust_dynamic_symbol function sees - the strong alias before H by recursively calling ourselves. */ - if (!_bfd_elf_adjust_dynamic_symbol (def, 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); - - if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h)) - { - eif->failed = TRUE; - return FALSE; - } - - return TRUE; -} - -/* Adjust the dynamic symbol, H, for copy in the dynamic bss section, - DYNBSS. */ - -bfd_boolean -_bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - asection *dynbss) -{ - unsigned int power_of_two; - bfd_vma mask; - asection *sec = h->root.u.def.section; - - /* The section alignment of the definition is the maximum alignment - requirement of symbols defined in the section. Since we don't - know the symbol alignment requirement, we start with the - maximum alignment and check low bits of the symbol address - for the minimum alignment. */ - power_of_two = bfd_get_section_alignment (sec->owner, sec); - mask = ((bfd_vma) 1 << power_of_two) - 1; - while ((h->root.u.def.value & mask) != 0) - { - mask >>= 1; - --power_of_two; - } - - if (power_of_two > bfd_get_section_alignment (dynbss->owner, - dynbss)) - { - /* Adjust the section alignment if needed. */ - if (! bfd_set_section_alignment (dynbss->owner, dynbss, - power_of_two)) - return FALSE; - } - - /* We make sure that the symbol will be aligned properly. */ - dynbss->size = BFD_ALIGN (dynbss->size, mask + 1); - - /* Define the symbol as being at this point in DYNBSS. */ - h->root.u.def.section = dynbss; - h->root.u.def.value = dynbss->size; - - /* Increment the size of DYNBSS to make room for the symbol. */ - dynbss->size += h->size; - - /* No error if extern_protected_data is true. */ - if (h->protected_def - && (!info->extern_protected_data - || (info->extern_protected_data < 0 - && !get_elf_backend_data (dynbss->owner)->extern_protected_data))) - info->callbacks->einfo - (_("%P: copy reloc against protected `%T' is dangerous\n"), - h->root.root.string); - - return TRUE; -} - -/* Adjust all external symbols pointing into SEC_MERGE sections - to reflect the object merging within the sections. */ - -static 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_defined - || h->root.type == bfd_link_hash_defweak) - && ((sec = h->root.u.def.section)->flags & SEC_MERGE) - && sec->sec_info_type == SEC_INFO_TYPE_MERGE) - { - bfd *output_bfd = (bfd *) data; - - h->root.u.def.value = - _bfd_merged_section_offset (output_bfd, - &h->root.u.def.section, - elf_section_data (sec)->sec_info, - h->root.u.def.value); - } - - 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 not_local_protected) -{ - bfd_boolean binding_stays_local_p; - const struct elf_backend_data *bed; - struct elf_link_hash_table *hash_table; - - 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 = (bfd_link_executable (info) - || SYMBOLIC_BIND (info, h)); - - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - return FALSE; - - case STV_PROTECTED: - hash_table = elf_hash_table (info); - if (!is_elf_hash_table (hash_table)) - return FALSE; - - bed = get_elf_backend_data (hash_table->dynobj); - - /* 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 (!not_local_protected || !bed->is_function_type (h->type)) - binding_stays_local_p = TRUE; - break; - - default: - break; - } - - /* If it isn't defined locally, then clearly it's dynamic. */ - if (!h->def_regular && !ELF_COMMON_DEF_P (h)) - 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. The two functions are virtually identical except - for the place where dynindx == -1 is tested. If that test is true, - _bfd_elf_dynamic_symbol_p will say the symbol is local, while - _bfd_elf_symbol_refs_local_p will say the symbol is local only for - defined symbols. - It might seem that _bfd_elf_dynamic_symbol_p could be rewritten as - !_bfd_elf_symbol_refs_local_p, except that targets differ in their - treatment of undefined weak symbols. For those that do not make - undefined weak symbols dynamic, both functions may return false. */ - -bfd_boolean -_bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h, - struct bfd_link_info *info, - bfd_boolean local_protected) -{ - const struct elf_backend_data *bed; - struct elf_link_hash_table *hash_table; - - /* If it's a local sym, of course we resolve locally. */ - if (h == NULL) - return TRUE; - - /* STV_HIDDEN or STV_INTERNAL ones must be local. */ - if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN - || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL) - return TRUE; - - /* Forced local symbols resolve locally. */ - if (h->forced_local) - 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; - - /* Non-dynamic symbols resolve locally. */ - 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 (bfd_link_executable (info) || SYMBOLIC_BIND (info, h)) - 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; - - hash_table = elf_hash_table (info); - if (!is_elf_hash_table (hash_table)) - return TRUE; - - bed = get_elf_backend_data (hash_table->dynobj); - - /* If extern_protected_data is false, STV_PROTECTED non-function - symbols are local. */ - if ((!info->extern_protected_data - || (info->extern_protected_data < 0 - && !bed->extern_protected_data)) - && !bed->is_function_type (h->type)) - return TRUE; - - /* Function pointer equality tests may require that STV_PROTECTED - symbols be treated as dynamic symbols. If the address of a - function not defined in an executable is set to that function's - plt entry in the executable, then the address of the function in - a shared library must also be the plt entry in the executable. */ - 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; - - bed = get_elf_backend_data (abfd); - /* Function symbols do not count. */ - if (bed->is_function_type (ELF_ST_TYPE (sym->st_info))) - return FALSE; - - /* If the section is undefined, then so is the symbol. */ - if (sym->st_shndx == SHN_UNDEF) - return FALSE; - - /* If the symbol is defined in the common section, then - it is a common definition and so does not count. */ - if (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; - size_t symcount; - size_t extsymcount; - size_t 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; - - /* Select the appropriate symbol table. If we don't know if the - object file is an IR object, give linker LTO plugin a chance to - get the correct symbol table. */ - if (abfd->plugin_format == bfd_plugin_yes -#if BFD_SUPPORTS_PLUGINS - || (abfd->plugin_format == bfd_plugin_unknown - && bfd_link_plugin_object_p (abfd)) -#endif - ) - { - /* Use the IR symbol table if the object has been claimed by - plugin. */ - abfd = abfd->plugin_dummy_bfd; - hdr = &elf_tdata (abfd)->symtab_hdr; - } - else 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_linker_section (hash_table->dynobj, ".dynamic"); - BFD_ASSERT (s != NULL); - - newsize = s->size + bed->s->sizeof_dyn; - newcontents = (bfd_byte *) 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; - size_t strindex; - - if (!_bfd_elf_link_create_dynstrtab (abfd, info)) - return -1; - - hash_table = elf_hash_table (info); - strindex = _bfd_elf_strtab_add (hash_table->dynstr, soname, FALSE); - if (strindex == (size_t) -1) - return -1; - - if (_bfd_elf_strtab_refcount (hash_table->dynstr, strindex) != 1) - { - asection *sdyn; - const struct elf_backend_data *bed; - bfd_byte *extdyn; - - bed = get_elf_backend_data (hash_table->dynobj); - sdyn = bfd_get_linker_section (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; -} - -/* Return true if SONAME is on the needed list between NEEDED and STOP - (or the end of list if STOP is NULL), and needed by a library that - will be loaded. */ - -static bfd_boolean -on_needed_list (const char *soname, - struct bfd_link_needed_list *needed, - struct bfd_link_needed_list *stop) -{ - struct bfd_link_needed_list *look; - for (look = needed; look != stop; look = look->next) - if (strcmp (soname, look->name) == 0 - && ((elf_dyn_lib_class (look->by) & DYN_AS_NEEDED) == 0 - /* If needed by a library that itself is not directly - needed, recursively check whether that library is - indirectly needed. Since we add DT_NEEDED entries to - the end of the list, library dependencies appear after - the library. Therefore search prior to the current - LOOK, preventing possible infinite recursion. */ - || on_needed_list (elf_dt_name (look->by), needed, look))) - return TRUE; - - return FALSE; -} - -/* Sort symbol by value, section, and size. */ -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 - { - int sdiff = h1->root.u.def.section->id - h2->root.u.def.section->id; - if (sdiff != 0) - return sdiff > 0 ? 1 : -1; - } - vdiff = h1->size - h2->size; - return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1; -} - -/* 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 = (struct elf_strtab_hash *) data; - - 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_linker_section (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: - case DT_AUDIT: - case DT_DEPAUDIT: - 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; - size_t i; - Elf_Internal_Verdef def; - Elf_Internal_Verdaux defaux; - - s = bfd_get_linker_section (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; - size_t i; - Elf_Internal_Verneed need; - Elf_Internal_Vernaux needaux; - - s = bfd_get_linker_section (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; -} - -/* Return TRUE iff relocations for INPUT are compatible with OUTPUT. - The default is to only match when the INPUT and OUTPUT are exactly - the same target. */ - -bfd_boolean -_bfd_elf_default_relocs_compatible (const bfd_target *input, - const bfd_target *output) -{ - return input == output; -} - -/* Return TRUE iff relocations for INPUT are compatible with OUTPUT. - This version is used when different targets for the same architecture - are virtually identical. */ - -bfd_boolean -_bfd_elf_relocs_compatible (const bfd_target *input, - const bfd_target *output) -{ - const struct elf_backend_data *obed, *ibed; - - if (input == output) - return TRUE; - - ibed = xvec_get_elf_backend_data (input); - obed = xvec_get_elf_backend_data (output); - - if (ibed->arch != obed->arch) - return FALSE; - - /* If both backends are using this function, deem them compatible. */ - return ibed->relocs_compatible == obed->relocs_compatible; -} - -/* Make a special call to the linker "notice" function to tell it that - we are about to handle an as-needed lib, or have finished - processing the lib. */ - -bfd_boolean -_bfd_elf_notice_as_needed (bfd *ibfd, - struct bfd_link_info *info, - enum notice_asneeded_action act) -{ - return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0); -} - -/* Check relocations an ELF object file. */ - -bfd_boolean -_bfd_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab = elf_hash_table (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 ((abfd->flags & DYNAMIC) == 0 - && is_elf_hash_table (htab) - && bed->check_relocs != NULL - && elf_object_id (abfd) == elf_hash_table_id (htab) - && (*bed->relocs_compatible) (abfd->xvec, info->output_bfd->xvec)) - { - asection *o; - - for (o = abfd->sections; o != NULL; o = o->next) - { - Elf_Internal_Rela *internal_relocs; - bfd_boolean ok; - - /* Don't check relocations in excluded sections. */ - if ((o->flags & SEC_RELOC) == 0 - || (o->flags & SEC_EXCLUDE) != 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) - return FALSE; - - ok = (*bed->check_relocs) (abfd, info, o, internal_relocs); - - if (elf_section_data (o)->relocs != internal_relocs) - free (internal_relocs); - - if (! ok) - return FALSE; - } - } - - 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_Ehdr *ehdr; - Elf_Internal_Shdr *hdr; - size_t symcount; - size_t extsymcount; - size_t 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; - size_t 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; - struct bfd_hash_entry **old_table = NULL; - unsigned int old_size = 0; - unsigned int old_count = 0; - void *old_tab = NULL; - void *old_ent; - struct bfd_link_hash_entry *old_undefs = NULL; - struct bfd_link_hash_entry *old_undefs_tail = NULL; - void *old_strtab = NULL; - size_t tabsize = 0; - asection *s; - bfd_boolean just_syms; - - 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 (bfd_link_relocatable (info) - || !is_elf_hash_table (htab) - || info->output_bfd->xvec != abfd->xvec) - { - if (bfd_link_relocatable (info)) - bfd_set_error (bfd_error_invalid_operation); - else - bfd_set_error (bfd_error_wrong_format); - goto error_return; - } - } - - ehdr = elf_elfheader (abfd); - if (info->warn_alternate_em - && bed->elf_machine_code != ehdr->e_machine - && ((bed->elf_machine_alt1 != 0 - && ehdr->e_machine == bed->elf_machine_alt1) - || (bed->elf_machine_alt2 != 0 - && ehdr->e_machine == bed->elf_machine_alt2))) - info->callbacks->einfo - /* xgettext:c-format */ - (_("%P: alternate ELF machine code found (%d) in %B, expecting %d\n"), - ehdr->e_machine, abfd, bed->elf_machine_code); - - /* 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. */ - /* PR 12761: Also generate this warning when building shared libraries. */ - for (s = abfd->sections; s != NULL; s = s->next) - { - const char *name; - - name = bfd_get_section_name (abfd, s); - if (CONST_STRNEQ (name, ".gnu.warning.")) - { - 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)) - continue; - } - - sz = s->size; - msg = (char *) bfd_alloc (abfd, sz + 1); - if (msg == NULL) - goto error_return; - - if (! bfd_get_section_contents (abfd, s, msg, 0, sz)) - goto error_return; - - msg[sz] = '\0'; - - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_WARNING, s, 0, msg, - FALSE, bed->collect, NULL))) - goto error_return; - - if (bfd_link_executable (info)) - { - /* 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; - } - } - } - - just_syms = ((s = abfd->sections) != NULL - && s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS); - - add_needed = TRUE; - if (! dynamic) - { - /* If we are creating a shared library, create all the dynamic - sections immediately. We need to attach them to something, - so we attach them to this BFD, provided it is the right - format and is not from ld --just-symbols. Always create the - dynamic sections for -E/--dynamic-list. FIXME: If there - are no input BFD's of the same format as the output, we can't - make a shared library. */ - if (!just_syms - && (bfd_link_pic (info) - || (!bfd_link_relocatable (info) - && info->nointerp - && (info->export_dynamic || info->dynamic))) - && is_elf_hash_table (htab) - && info->output_bfd->xvec == 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 - { - const char *soname = NULL; - char *audit = NULL; - struct bfd_link_needed_list *rpath = NULL, *runpath = NULL; - const Elf_Internal_Phdr *phdr; - int ret; - - /* ld --just-symbols and dynamic objects don't mix very well. - ld shouldn't allow it. */ - if (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; - unsigned int elfsec; - unsigned long shlink; - - if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) - { -error_free_dyn: - free (dynbuf); - goto error_return; - } - - elfsec = _bfd_elf_section_from_bfd_section (abfd, s); - if (elfsec == SHN_BAD) - 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 = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); - fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); - if (n == NULL || fnm == NULL) - goto error_free_dyn; - amt = strlen (fnm) + 1; - anm = (char *) 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 = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); - fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); - if (n == NULL || fnm == NULL) - goto error_free_dyn; - amt = strlen (fnm) + 1; - anm = (char *) 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 = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); - fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); - if (n == NULL || fnm == NULL) - goto error_free_dyn; - amt = strlen (fnm) + 1; - anm = (char *) 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 = & rpath; - *pn != NULL; - pn = &(*pn)->next) - ; - *pn = n; - } - if (dyn.d_tag == DT_AUDIT) - { - unsigned int tagv = dyn.d_un.d_val; - audit = bfd_elf_string_from_elf_section (abfd, shlink, tagv); - } - } - - 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; - } - - /* If we have a PT_GNU_RELRO program header, mark as read-only - all sections contained fully therein. This makes relro - shared library sections appear as they will at run-time. */ - phdr = elf_tdata (abfd)->phdr + elf_elfheader (abfd)->e_phnum; - while (--phdr >= elf_tdata (abfd)->phdr) - if (phdr->p_type == PT_GNU_RELRO) - { - for (s = abfd->sections; s != NULL; s = s->next) - if ((s->flags & SEC_ALLOC) != 0 - && s->vma >= phdr->p_vaddr - && s->vma + s->size <= phdr->p_vaddr + phdr->p_memsz) - s->flags |= SEC_READONLY; - break; - } - - /* 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; - - /* Save the DT_AUDIT entry for the linker emulation code. */ - elf_dt_audit (abfd) = audit; - } - - /* 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 = elf_sym_hashes (abfd); - if (extsymcount != 0) - { - isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - - if (sym_hash == NULL) - { - /* We store a pointer to the hash table entry for each - external symbol. */ - amt = extsymcount; - amt *= sizeof (struct elf_link_hash_entry *); - sym_hash = (struct elf_link_hash_entry **) bfd_zalloc (abfd, amt); - if (sym_hash == NULL) - goto error_free_sym; - elf_sym_hashes (abfd) = sym_hash; - } - } - - if (dynamic) - { - /* 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 = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); - if (extversym == NULL) - goto error_free_sym; - amt = versymhdr->sh_size; - if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (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 *); - old_tab = bfd_malloc (tabsize + entsize); - 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; - - /* Make a special call to the linker "notice" function to - tell it that we are about to handle an as-needed lib. */ - if (!(*bed->notice_as_needed) (abfd, info, notice_as_needed)) - goto error_free_vers; - - /* Clone the symbol table. Remember some pointers into the - symbol table, and dynamic symbol count. */ - old_ent = (char *) old_tab + tabsize; - memcpy (old_tab, htab->root.table.table, tabsize); - old_undefs = htab->root.undefs; - old_undefs_tail = htab->root.undefs_tail; - old_table = htab->root.table.table; - old_size = htab->root.table.size; - old_count = htab->root.table.count; - old_strtab = _bfd_elf_strtab_save (htab->dynstr); - if (old_strtab == NULL) - goto error_free_vers; - - 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; - struct elf_link_hash_entry *hi; - bfd_boolean definition; - bfd_boolean size_change_ok; - bfd_boolean type_change_ok; - bfd_boolean new_weak; - bfd_boolean old_weak; - bfd_boolean override; - bfd_boolean common; - bfd_boolean discarded; - unsigned int old_alignment; - bfd *old_bfd; - bfd_boolean matched; - - override = FALSE; - - flags = BSF_NO_FLAGS; - sec = NULL; - value = isym->st_value; - common = bed->common_definition (isym); - if (common && info->inhibit_common_definition) - { - /* Treat common symbol as undefined for --no-define-common. */ - isym->st_shndx = SHN_UNDEF; - common = FALSE; - } - discarded = FALSE; - - bind = ELF_ST_BIND (isym->st_info); - switch (bind) - { - case 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; - - case STB_GLOBAL: - if (isym->st_shndx != SHN_UNDEF && !common) - flags = BSF_GLOBAL; - break; - - case STB_WEAK: - flags = BSF_WEAK; - break; - - case STB_GNU_UNIQUE: - flags = BSF_GNU_UNIQUE; - break; - - default: - /* Leave it up to the processor backend. */ - break; - } - - if (isym->st_shndx == SHN_UNDEF) - sec = bfd_und_section_ptr; - 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 - { - sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - if (sec == NULL) - sec = bfd_abs_section_ptr; - else if (discarded_section (sec)) - { - /* Symbols from discarded section are undefined. We keep - its visibility. */ - sec = bfd_und_section_ptr; - discarded = TRUE; - isym->st_shndx = SHN_UNDEF; - } - else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) - value -= sec->vma; - } - - 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 - && (abfd->flags & BFD_PLUGIN) != 0) - { - asection *xc = bfd_get_section_by_name (abfd, "COMMON"); - - if (xc == NULL) - { - flagword sflags = (SEC_ALLOC | SEC_IS_COMMON | SEC_KEEP - | SEC_EXCLUDE); - xc = bfd_make_section_with_flags (abfd, "COMMON", sflags); - if (xc == NULL) - goto error_free_vers; - } - sec = xc; - } - else if (isym->st_shndx == SHN_COMMON - && ELF_ST_TYPE (isym->st_info) == STT_TLS - && !bfd_link_relocatable (info)) - { - asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon"); - - if (tcomm == NULL) - { - flagword sflags = (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_IS_COMMON - | SEC_LINKER_CREATED); - tcomm = bfd_make_section_with_flags (abfd, ".tcommon", sflags); - 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; - } - - /* Silently discard TLS symbols from --just-syms. There's - no way to combine a static TLS block with a new TLS block - for this executable. */ - if (ELF_ST_TYPE (isym->st_info) == STT_TLS - && sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - if (bfd_is_und_section (sec) - || bfd_is_com_section (sec)) - definition = FALSE; - else - definition = TRUE; - - size_change_ok = FALSE; - type_change_ok = bed->type_change_ok; - old_weak = FALSE; - matched = FALSE; - 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) - || bed->is_function_type (ELF_ST_TYPE (isym->st_info))))) - { - 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 - /* xgettext:c-format */ - (_("%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 - /* xgettext:c-format */ - (_("%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 = (char *) 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 this symbol has default visibility and the user has - requested we not re-export it, then mark it as hidden. */ - if (!bfd_is_und_section (sec) - && !dynamic - && abfd->no_export - && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) - isym->st_other = (STV_HIDDEN - | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); - - if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value, - sym_hash, &old_bfd, &old_weak, - &old_alignment, &skip, &override, - &type_change_ok, &size_change_ok, - &matched)) - goto error_free_vers; - - if (skip) - continue; - - /* Override a definition only if the new symbol matches the - existing one. */ - if (override && matched) - 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; - - if (elf_tdata (abfd)->verdef != NULL - && 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; - - if ((flags & BSF_GNU_UNIQUE) - && (abfd->flags & DYNAMIC) == 0 - && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) - elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_unique; - - h = *sym_hash; - /* We need to make sure that indirect symbol dynamic flags are - updated. */ - hi = h; - 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; - - /* Setting the index to -3 tells elf_link_output_extsym that - this symbol is defined in a discarded section. */ - if (discarded) - h->indx = -3; - - *sym_hash = h; - - new_weak = (flags & BSF_WEAK) != 0; - if (dynamic - && definition - && new_weak - && !bed->is_function_type (ELF_ST_TYPE (isym->st_info)) - && is_elf_hash_table (htab) - && h->u.alias == NULL) - { - /* Keep a list of all weak defined non function symbols from - a dynamic object, using the alias field. Later in this - function we will set the alias 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 alias 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.alias = weaks; - weaks = h; - } - - /* 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) - h->root.u.c.p->alignment_power = align; - else - h->root.u.c.p->alignment_power = old_alignment; - } - - if (is_elf_hash_table (htab)) - { - /* Set a flag in the hash table entry indicating the type of - reference or definition we just found. A dynamic symbol - is one which is referenced or defined by both a regular - object and a shared object. */ - bfd_boolean dynsym = FALSE; - - /* Plugin symbols aren't normal. Don't set def_regular or - ref_regular for them, or make them dynamic. */ - if ((abfd->flags & BFD_PLUGIN) != 0) - ; - else if (! dynamic) - { - if (! definition) - { - h->ref_regular = 1; - if (bind != STB_WEAK) - h->ref_regular_nonweak = 1; - } - else - { - h->def_regular = 1; - if (h->def_dynamic) - { - h->def_dynamic = 0; - h->ref_dynamic = 1; - } - } - - /* If the indirect symbol has been forced local, don't - make the real symbol dynamic. */ - if ((h == hi || !hi->forced_local) - && (bfd_link_dll (info) - || h->def_dynamic - || h->ref_dynamic)) - dynsym = TRUE; - } - else - { - if (! definition) - { - h->ref_dynamic = 1; - hi->ref_dynamic = 1; - } - else - { - h->def_dynamic = 1; - hi->def_dynamic = 1; - } - - /* If the indirect symbol has been forced local, don't - make the real symbol dynamic. */ - if ((h == hi || !hi->forced_local) - && (h->def_regular - || h->ref_regular - || (h->is_weakalias - && weakdef (h)->dynindx != -1))) - dynsym = TRUE; - } - - /* Check to see if we need to add an indirect symbol for - the default name. */ - if (definition - || (!override && h->root.type == bfd_link_hash_common)) - if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym, - sec, value, &old_bfd, &dynsym)) - goto error_free_vers; - - /* Check the alignment when a common symbol is involved. This - can change when a common symbol is overridden by a normal - 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; - - BFD_ASSERT (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak); - - symbol_align = ffs (h->root.u.def.value) - 1; - if (h->root.u.def.section->owner != NULL - && (h->root.u.def.section->owner->flags - & (DYNAMIC | BFD_PLUGIN)) == 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) - { - /* PR binutils/2735 */ - if (normal_bfd == NULL) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: alignment %u of common symbol `%s' in %B is" - " greater than the alignment (%u) of its section %A"), - 1 << common_align, name, common_bfd, - 1 << normal_align, h->root.u.def.section); - else - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: alignment %u of symbol `%s' in %B" - " is smaller than %u in %B"), - 1 << normal_align, name, normal_bfd, - 1 << common_align, common_bfd); - } - } - - /* Remember the symbol size if it isn't undefined. */ - if (isym->st_size != 0 - && isym->st_shndx != SHN_UNDEF - && (definition || h->size == 0)) - { - if (h->size != 0 - && h->size != isym->st_size - && ! size_change_ok) - _bfd_error_handler - /* xgettext:c-format */ - (_("Warning: size of symbol `%s' changed" - " from %Lu in %B to %Lu in %B"), - name, h->size, old_bfd, isym->st_size, abfd); - - h->size = isym->st_size; - } - - /* If this is a common symbol, then we always want H->SIZE - to be the size of the common symbol. The code just above - won't fix the size if a common symbol becomes larger. We - don't warn about a size change here, because that is - covered by --warn-common. Allow changes between different - function types. */ - 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 && !new_weak) - || (old_weak && h->root.type == bfd_link_hash_common) - || h->type == STT_NOTYPE)) - { - unsigned int type = ELF_ST_TYPE (isym->st_info); - - /* Turn an IFUNC symbol from a DSO into a normal FUNC - symbol. */ - if (type == STT_GNU_IFUNC - && (abfd->flags & DYNAMIC) != 0) - type = STT_FUNC; - - if (h->type != type) - { - if (h->type != STT_NOTYPE && ! type_change_ok) - /* xgettext:c-format */ - _bfd_error_handler - (_("Warning: type of symbol `%s' changed" - " from %d to %d in %B"), - name, h->type, type, abfd); - - h->type = type; - } - } - - /* Merge st_other field. */ - elf_merge_st_other (abfd, h, isym, sec, definition, dynamic); - - /* We don't want to make debug symbol dynamic. */ - if (definition - && (sec->flags & SEC_DEBUGGING) - && !bfd_link_relocatable (info)) - dynsym = FALSE; - - /* Nor should we make plugin symbols dynamic. */ - if ((abfd->flags & BFD_PLUGIN) != 0) - dynsym = FALSE; - - if (definition) - { - h->target_internal = isym->st_target_internal; - h->unique_global = (flags & BSF_GNU_UNIQUE) != 0; - } - - 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 - = (struct elf_link_hash_entry **) bfd_malloc (amt); - if (!nondeflt_vers) - goto error_free_vers; - } - 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->is_weakalias - && weakdef (h)->dynindx == -1) - { - if (!bfd_elf_link_record_dynamic_symbol (info, weakdef (h))) - goto error_free_vers; - } - } - else if (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; - } - - /* Don't add DT_NEEDED for references from the dummy bfd nor - for unmatched symbol. */ - if (!add_needed - && matched - && definition - && ((dynsym - && h->ref_regular_nonweak - && (old_bfd == NULL - || (old_bfd->flags & BFD_PLUGIN) == 0)) - || (h->ref_dynamic_nonweak - && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0 - && !on_needed_list (elf_dt_name (abfd), - htab->needed, NULL)))) - { - int ret; - const char *soname = elf_dt_name (abfd); - - info->callbacks->minfo ("%!", soname, old_bfd, - h->root.root.string); - - /* A symbol from a library loaded via DT_NEEDED of some - other library is referenced by a regular object. - Add a DT_NEEDED entry for it. Issue an error if - --no-add-needed is used and the reference was not - a weak one. */ - if (old_bfd != NULL - && (elf_dyn_lib_class (abfd) & DYN_NO_NEEDED) != 0) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: undefined reference to symbol '%s'"), - old_bfd, name); - bfd_set_error (bfd_error_missing_dso); - goto error_free_vers; - } - - elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class) - (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); - - 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 (info->lto_plugin_active - && !bfd_link_relocatable (info) - && (abfd->flags & BFD_PLUGIN) == 0 - && !just_syms - && extsymcount) - { - int r_sym_shift; - - if (bed->s->arch_size == 32) - r_sym_shift = 8; - else - r_sym_shift = 32; - - /* If linker plugin is enabled, set non_ir_ref_regular on symbols - referenced in regular objects so that linker plugin will get - the correct symbol resolution. */ - - sym_hash = elf_sym_hashes (abfd); - for (s = abfd->sections; s != NULL; s = s->next) - { - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *rel, *relend; - - /* Don't check relocations in excluded sections. */ - if ((s->flags & SEC_RELOC) == 0 - || s->reloc_count == 0 - || (s->flags & SEC_EXCLUDE) != 0 - || ((info->strip == strip_all - || info->strip == strip_debugger) - && (s->flags & SEC_DEBUGGING) != 0)) - continue; - - internal_relocs = _bfd_elf_link_read_relocs (abfd, s, NULL, - NULL, - info->keep_memory); - if (internal_relocs == NULL) - goto error_free_vers; - - rel = internal_relocs; - relend = rel + s->reloc_count; - for ( ; rel < relend; rel++) - { - unsigned long r_symndx = rel->r_info >> r_sym_shift; - struct elf_link_hash_entry *h; - - /* Skip local symbols. */ - if (r_symndx < extsymoff) - continue; - - h = sym_hash[r_symndx - extsymoff]; - if (h != NULL) - h->root.non_ir_ref_regular = 1; - } - - if (elf_section_data (s)->relocs != internal_relocs) - free (internal_relocs); - } - } - - 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_ent = (char *) old_tab + tabsize; - memset (elf_sym_hashes (abfd), 0, - extsymcount * sizeof (struct elf_link_hash_entry *)); - htab->root.table.table = old_table; - htab->root.table.size = old_size; - htab->root.table.count = old_count; - memcpy (htab->root.table.table, old_tab, tabsize); - htab->root.undefs = old_undefs; - htab->root.undefs_tail = old_undefs_tail; - _bfd_elf_strtab_restore (htab->dynstr, old_strtab); - free (old_strtab); - old_strtab = NULL; - for (i = 0; i < htab->root.table.size; i++) - { - struct bfd_hash_entry *p; - struct elf_link_hash_entry *h; - bfd_size_type size; - unsigned int alignment_power; - unsigned int non_ir_ref_dynamic; - - 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; - - /* Preserve the maximum alignment and size for common - symbols even if this dynamic lib isn't on DT_NEEDED - since it can still be loaded at run time by another - dynamic lib. */ - if (h->root.type == bfd_link_hash_common) - { - size = h->root.u.c.size; - alignment_power = h->root.u.c.p->alignment_power; - } - else - { - size = 0; - alignment_power = 0; - } - /* Preserve non_ir_ref_dynamic so that this symbol - will be exported when the dynamic lib becomes needed - in the second pass. */ - non_ir_ref_dynamic = h->root.non_ir_ref_dynamic; - 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; - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } - if (h->root.type == bfd_link_hash_common) - { - if (size > h->root.u.c.size) - h->root.u.c.size = size; - if (alignment_power > h->root.u.c.p->alignment_power) - h->root.u.c.p->alignment_power = alignment_power; - } - h->root.non_ir_ref_dynamic = non_ir_ref_dynamic; - } - } - - /* Make a special call to the linker "notice" function to - tell it that symbols added for crefs may need to be removed. */ - if (!(*bed->notice_as_needed) (abfd, info, notice_not_needed)) - goto error_free_vers; - - 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) - { - if (!(*bed->notice_as_needed) (abfd, info, notice_needed)) - goto error_free_vers; - free (old_tab); - old_tab = NULL; - } - - /* Now that all the symbols from this input file are created, if - not performing a relocatable link, handle .symver foo, foo@BAR - such that any relocs against foo become foo@BAR. */ - if (!bfd_link_relocatable (info) && nondeflt_vers != NULL) - { - size_t 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 = (char *) bfd_malloc (amt + 1); - if (!shortname) - goto error_free_vers; - 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 alias 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; - amt *= sizeof (struct elf_link_hash_entry *); - sorted_sym_hash = (struct elf_link_hash_entry **) 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 - && !bed->is_function_type (h->type)) - { - *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; - size_t i, j, idx = 0; - - hlook = weaks; - weaks = hlook->u.alias; - hlook->u.alias = NULL; - - if (hlook->root.type != bfd_link_hash_defined - && hlook->root.type != bfd_link_hash_defweak) - continue; - - slook = hlook->root.u.def.section; - vlook = hlook->root.u.def.value; - - 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 - { - int sdiff = slook->id - h->root.u.def.section->id; - if (sdiff < 0) - j = idx; - else if (sdiff > 0) - i = idx + 1; - else - break; - } - } - - /* We didn't find a value/section match. */ - if (i == j) - continue; - - /* With multiple aliases, or when the weak symbol is already - strongly defined, we have multiple matching symbols and - the binary search above may land on any of them. Step - one past the matching symbol(s). */ - while (++idx != j) - { - h = sorted_sym_hash[idx]; - if (h->root.u.def.section != slook - || h->root.u.def.value != vlook) - break; - } - - /* Now look back over the aliases. Since we sorted by size - as well as value and section, we'll choose the one with - the largest size. */ - while (idx-- != i) - { - h = sorted_sym_hash[idx]; - - /* Stop if value or section doesn't match. */ - if (h->root.u.def.section != slook - || h->root.u.def.value != vlook) - break; - else if (h != hlook) - { - struct elf_link_hash_entry *t; - - hlook->u.alias = h; - hlook->is_weakalias = 1; - t = h; - if (t->u.alias != NULL) - while (t->u.alias != h) - t = t->u.alias; - t->u.alias = hlook; - - /* 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)) - { - err_free_sym_hash: - free (sorted_sym_hash); - 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 err_free_sym_hash; - } - break; - } - } - } - - free (sorted_sym_hash); - } - - if (bed->check_directives - && !(*bed->check_directives) (abfd, info)) - return FALSE; - - /* 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 (CONST_STRNEQ (stab->name, ".stab") - && (!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 = SEC_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 = (struct elf_link_loaded_list *) bfd_alloc (abfd, sizeof (*n)); - 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 (old_strtab != NULL) - free (old_strtab); - 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, TRUE); - 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 = (char *) 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, TRUE); - 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, TRUE); - } - - 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 we need to - handle versioned symbols. - - Fortunately, ELF archive handling is simpler than that done by - _bfd_generic_link_add_archive_symbols, which has to allow for a.out - 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; - unsigned char *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 (*included); - included = (unsigned char *) bfd_zmalloc (amt); - if (included == NULL) - return FALSE; - - 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 (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) - /* Symbol must be defined. Don't check it again. */ - included[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; - - undefs_tail = info->hash->undefs_tail; - - if (!(*info->callbacks - ->add_archive_element) (info, element, symdef->name, &element)) - continue; - 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 (included); - - return TRUE; - - error_return: - 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; - } -} - -struct hash_codes_info -{ - unsigned long *hashcodes; - bfd_boolean error; -}; - -/* 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) -{ - struct hash_codes_info *inf = (struct hash_codes_info *) data; - const char *name; - unsigned long ha; - char *alc = NULL; - - /* Ignore indirect symbols. These are added by the versioning code. */ - if (h->dynindx == -1) - return TRUE; - - name = h->root.root.string; - if (h->versioned >= versioned) - { - char *p = strchr (name, ELF_VER_CHR); - if (p != NULL) - { - alc = (char *) bfd_malloc (p - name + 1); - if (alc == NULL) - { - inf->error = TRUE; - return FALSE; - } - 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. */ - *(inf->hashcodes)++ = 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; -} - -struct collect_gnu_hash_codes -{ - bfd *output_bfd; - const struct elf_backend_data *bed; - unsigned long int nsyms; - unsigned long int maskbits; - unsigned long int *hashcodes; - unsigned long int *hashval; - unsigned long int *indx; - unsigned long int *counts; - bfd_vma *bitmask; - bfd_byte *contents; - long int min_dynindx; - unsigned long int bucketcount; - unsigned long int symindx; - long int local_indx; - long int shift1, shift2; - unsigned long int mask; - bfd_boolean error; -}; - -/* 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_gnu_hash_codes (struct elf_link_hash_entry *h, void *data) -{ - struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data; - const char *name; - unsigned long ha; - char *alc = NULL; - - /* Ignore indirect symbols. These are added by the versioning code. */ - if (h->dynindx == -1) - return TRUE; - - /* Ignore also local symbols and undefined symbols. */ - if (! (*s->bed->elf_hash_symbol) (h)) - return TRUE; - - name = h->root.root.string; - if (h->versioned >= versioned) - { - char *p = strchr (name, ELF_VER_CHR); - if (p != NULL) - { - alc = (char *) bfd_malloc (p - name + 1); - if (alc == NULL) - { - s->error = TRUE; - return FALSE; - } - memcpy (alc, name, p - name); - alc[p - name] = '\0'; - name = alc; - } - } - - /* Compute the hash value. */ - ha = bfd_elf_gnu_hash (name); - - /* Store the found hash value in the array for compute_bucket_count, - and also for .dynsym reordering purposes. */ - s->hashcodes[s->nsyms] = ha; - s->hashval[h->dynindx] = ha; - ++s->nsyms; - if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx) - s->min_dynindx = h->dynindx; - - if (alc != NULL) - free (alc); - - return TRUE; -} - -/* This function will be called though elf_link_hash_traverse to do - final dynaminc symbol renumbering. */ - -static bfd_boolean -elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data) -{ - struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data; - unsigned long int bucket; - unsigned long int val; - - /* Ignore indirect symbols. */ - if (h->dynindx == -1) - return TRUE; - - /* Ignore also local symbols and undefined symbols. */ - if (! (*s->bed->elf_hash_symbol) (h)) - { - if (h->dynindx >= s->min_dynindx) - h->dynindx = s->local_indx++; - return TRUE; - } - - bucket = s->hashval[h->dynindx] % s->bucketcount; - val = (s->hashval[h->dynindx] >> s->shift1) - & ((s->maskbits >> s->shift1) - 1); - s->bitmask[val] |= ((bfd_vma) 1) << (s->hashval[h->dynindx] & s->mask); - s->bitmask[val] - |= ((bfd_vma) 1) << ((s->hashval[h->dynindx] >> s->shift2) & s->mask); - val = s->hashval[h->dynindx] & ~(unsigned long int) 1; - if (s->counts[bucket] == 1) - /* Last element terminates the chain. */ - val |= 1; - bfd_put_32 (s->output_bfd, val, - s->contents + (s->indx[bucket] - s->symindx) * 4); - --s->counts[bucket]; - h->dynindx = s->indx[bucket]++; - return TRUE; -} - -/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ - -bfd_boolean -_bfd_elf_hash_symbol (struct elf_link_hash_entry *h) -{ - return !(h->forced_local - || h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak - || ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section == NULL)); -} - -/* 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 ATTRIBUTE_UNUSED, - unsigned long int *hashcodes ATTRIBUTE_UNUSED, - unsigned long int nsyms, - int gnu_hash) -{ - size_t best_size = 0; - unsigned long int i; - - /* 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) - { - size_t minsize; - size_t maxsize; - BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0); - bfd *dynobj = elf_hash_table (info)->dynobj; - size_t dynsymcount = elf_hash_table (info)->dynsymcount; - const struct elf_backend_data *bed = get_elf_backend_data (dynobj); - unsigned long int *counts; - bfd_size_type amt; - unsigned int no_improvement_count = 0; - - /* 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; - if (gnu_hash) - { - if (minsize < 2) - minsize = 2; - if ((best_size & 31) == 0) - ++best_size; - } - - /* Create array where we count the collisions in. We must use bfd_malloc - since the size could be large. */ - amt = maxsize; - amt *= sizeof (unsigned long int); - counts = (unsigned long int *) bfd_malloc (amt); - if (counts == NULL) - 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; - - if (gnu_hash && (i & 31) == 0) - continue; - - 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 + DYNSYMCOUNT entries for the size values - and the chains. */ - max = (2 + dynsymcount) * bed->s->sizeof_hash_entry; - -# 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->sizeof_hash_entry) + 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->sizeof_hash_entry) + 1; - max *= fact; -# endif - - /* Compare with current best results. */ - if (max < best_chlen) - { - best_chlen = max; - best_size = i; - no_improvement_count = 0; - } - /* PR 11843: Avoid futile long searches for the best bucket size - when there are a large number of symbols. */ - else if (++no_improvement_count == 100) - break; - } - - 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 (nsyms < elf_buckets[i + 1]) - break; - } - if (gnu_hash && best_size < 2) - best_size = 2; - } - - return best_size; -} - -/* Size any SHT_GROUP section for ld -r. */ - -bfd_boolean -_bfd_elf_size_group_sections (struct bfd_link_info *info) -{ - bfd *ibfd; - asection *s; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour - && (s = ibfd->sections) != NULL - && s->sec_info_type != SEC_INFO_TYPE_JUST_SYMS - && !_bfd_elf_fixup_group_sections (ibfd, bfd_abs_section_ptr)) - return FALSE; - return TRUE; -} - -/* Set a default stack segment size. The value in INFO wins. If it - is unset, LEGACY_SYMBOL's value is used, and if that symbol is - undefined it is initialized. */ - -bfd_boolean -bfd_elf_stack_segment_size (bfd *output_bfd, - struct bfd_link_info *info, - const char *legacy_symbol, - bfd_vma default_size) -{ - struct elf_link_hash_entry *h = NULL; - - /* Look for legacy symbol. */ - if (legacy_symbol) - h = elf_link_hash_lookup (elf_hash_table (info), legacy_symbol, - FALSE, FALSE, FALSE); - if (h && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->def_regular - && (h->type == STT_NOTYPE || h->type == STT_OBJECT)) - { - /* The symbol has no type if specified on the command line. */ - h->type = STT_OBJECT; - if (info->stacksize) - /* xgettext:c-format */ - _bfd_error_handler (_("%B: stack size specified and %s set"), - output_bfd, legacy_symbol); - else if (h->root.u.def.section != bfd_abs_section_ptr) - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %s not absolute"), - output_bfd, legacy_symbol); - else - info->stacksize = h->root.u.def.value; - } - - if (!info->stacksize) - /* If the user didn't set a size, or explicitly inhibit the - size, set it now. */ - info->stacksize = default_size; - - /* Provide the legacy symbol, if it is referenced. */ - if (h && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) - { - struct bfd_link_hash_entry *bh = NULL; - - if (!(_bfd_generic_link_add_one_symbol - (info, output_bfd, legacy_symbol, - BSF_GLOBAL, bfd_abs_section_ptr, - info->stacksize >= 0 ? info->stacksize : 0, - NULL, FALSE, get_elf_backend_data (output_bfd)->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->def_regular = 1; - h->type = STT_OBJECT; - } - - return TRUE; -} - -/* 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->mark - && (((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !((h->def_regular || ELF_COMMON_DEF_P (h)) - && h->root.u.def.section->gc_mark)) - || h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak)) - { - struct elf_gc_sweep_symbol_info *inf; - - inf = (struct elf_gc_sweep_symbol_info *) data; - (*inf->hide_symbol) (inf->info, h, TRUE); - h->def_regular = 0; - h->ref_regular = 0; - h->ref_regular_nonweak = 0; - } - - return TRUE; -} - -/* 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 *audit, - const char *depaudit, - const char * const *auxiliary_filters, - struct bfd_link_info *info, - asection **sinterpptr) -{ - bfd *dynobj; - const struct elf_backend_data *bed; - - *sinterpptr = NULL; - - if (!is_elf_hash_table (info->hash)) - return TRUE; - - dynobj = elf_hash_table (info)->dynobj; - - if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) - { - struct bfd_elf_version_tree *verdefs; - struct elf_info_failed asvinfo; - struct bfd_elf_version_tree *t; - struct bfd_elf_version_expr *d; - asection *s; - size_t soname_indx; - - /* 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 - || (bfd_link_executable (info) && info->dynamic)) - { - struct elf_info_failed eif; - - eif.info = info; - eif.failed = FALSE; - elf_link_hash_traverse (elf_hash_table (info), - _bfd_elf_export_symbol, - &eif); - if (eif.failed) - return FALSE; - } - - if (soname != NULL) - { - soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, - soname, TRUE); - if (soname_indx == (size_t) -1 - || !_bfd_elf_add_dynamic_entry (info, DT_SONAME, soname_indx)) - return FALSE; - } - else - soname_indx = (size_t) -1; - - /* Make all global versions with definition. */ - for (t = info->version_info; t != NULL; t = t->next) - for (d = t->globals.list; d != NULL; d = d->next) - if (!d->symver && d->literal) - { - const char *verstr, *name; - size_t namelen, verlen, newlen; - char *newname, *p, leading_char; - struct elf_link_hash_entry *newh; - - leading_char = bfd_get_symbol_leading_char (output_bfd); - name = d->pattern; - namelen = strlen (name) + (leading_char != '\0'); - verstr = t->name; - verlen = strlen (verstr); - newlen = namelen + verlen + 3; - - newname = (char *) bfd_malloc (newlen); - if (newname == NULL) - return FALSE; - newname[0] = leading_char; - memcpy (newname + (leading_char != '\0'), 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.info = info; - 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. */ - bfd_boolean all_defined = TRUE; - for (t = info->version_info; t != NULL; t = t->next) - for (d = t->globals.list; d != NULL; d = d->next) - if (d->literal && !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; - } - } - - /* Set up the version definition section. */ - s = bfd_get_linker_section (dynobj, ".gnu.version_d"); - BFD_ASSERT (s != NULL); - - /* We may have created additional version definitions if we are - just linking a regular application. */ - verdefs = info->version_info; - - /* 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; - 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; - - /* Don't emit base version twice. */ - if (t->vernum == 0) - continue; - - 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 = (unsigned char *) 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 != (size_t) -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 - { - size_t 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 == (size_t) -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; - - /* Don't emit the base version twice. */ - if (t->vernum == 0) - continue; - - 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 a basever node is next, it *must* be the last node in - the chain, otherwise Verdef construction breaks. */ - if (t->next != NULL && t->next->vernum == 0) - BFD_ASSERT (t->next->next == NULL); - - if (t->next != NULL && t->next->vernum != 0) - 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); - } - } - - elf_tdata (output_bfd)->cverdefs = cdefs; - } - } - - bed = get_elf_backend_data (output_bfd); - - if (info->gc_sections && bed->can_gc_sections) - { - struct elf_gc_sweep_symbol_info sweep_info; - - /* Remove the symbols that were in the swept sections from the - dynamic symbol table. */ - 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); - } - - if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) - { - asection *s; - struct elf_find_verdep_info sinfo; - - /* Work out the size of the version reference section. */ - - s = bfd_get_linker_section (dynobj, ".gnu.version_r"); - BFD_ASSERT (s != NULL); - - 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 (sinfo.failed) - return FALSE; - - if (elf_tdata (output_bfd)->verref == NULL) - s->flags |= SEC_EXCLUDE; - else - { - Elf_Internal_Verneed *vn; - unsigned int size; - unsigned int crefs; - bfd_byte *p; - - /* Build the version dependency section. */ - size = 0; - crefs = 0; - for (vn = elf_tdata (output_bfd)->verref; - vn != NULL; - vn = vn->vn_nextref) - { - Elf_Internal_Vernaux *a; - - size += sizeof (Elf_External_Verneed); - ++crefs; - for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) - size += sizeof (Elf_External_Vernaux); - } - - s->size = size; - s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size); - if (s->contents == NULL) - return FALSE; - - p = s->contents; - for (vn = elf_tdata (output_bfd)->verref; - vn != NULL; - vn = vn->vn_nextref) - { - unsigned int caux; - Elf_Internal_Vernaux *a; - size_t indx; - - caux = 0; - for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) - ++caux; - - vn->vn_version = VER_NEED_CURRENT; - vn->vn_cnt = caux; - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, - elf_dt_name (vn->vn_bfd) != NULL - ? elf_dt_name (vn->vn_bfd) - : lbasename (vn->vn_bfd->filename), - FALSE); - if (indx == (size_t) -1) - return FALSE; - vn->vn_file = indx; - vn->vn_aux = sizeof (Elf_External_Verneed); - if (vn->vn_nextref == NULL) - vn->vn_next = 0; - else - vn->vn_next = (sizeof (Elf_External_Verneed) - + caux * sizeof (Elf_External_Vernaux)); - - _bfd_elf_swap_verneed_out (output_bfd, vn, - (Elf_External_Verneed *) p); - p += sizeof (Elf_External_Verneed); - - for (a = vn->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 == (size_t) -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); - } - } - - elf_tdata (output_bfd)->cverrefs = crefs; - } - } - - /* 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; - - if (bfd_link_relocatable (info) - && !_bfd_elf_size_group_sections (info)) - return FALSE; - - /* The backend may have to create some sections regardless of whether - we're dynamic or not. */ - if (bed->elf_backend_always_size_sections - && ! (*bed->elf_backend_always_size_sections) (output_bfd, info)) - return FALSE; - - /* Determine any GNU_STACK segment requirements, after the backend - has had a chance to set a default segment size. */ - if (info->execstack) - elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X; - else if (info->noexecstack) - elf_stack_flags (output_bfd) = 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 | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED)) - continue; - s = inputobj->sections; - if (s == NULL || s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - s = bfd_get_section_by_name (inputobj, ".note.GNU-stack"); - if (s) - { - if (s->flags & SEC_CODE) - exec = PF_X; - notesec = s; - } - else if (bed->default_execstack) - exec = PF_X; - } - if (notesec || info->stacksize > 0) - elf_stack_flags (output_bfd) = PF_R | PF_W | exec; - if (notesec && exec && bfd_link_relocatable (info) - && notesec->output_section != bfd_abs_section_ptr) - notesec->output_section->flags |= SEC_CODE; - } - - if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) - { - struct elf_info_failed eif; - struct elf_link_hash_entry *h; - asection *dynstr; - asection *s; - - *sinterpptr = bfd_get_linker_section (dynobj, ".interp"); - BFD_ASSERT (*sinterpptr != NULL || !bfd_link_executable (info) || info->nointerp); - - if (info->symbolic) - { - if (!_bfd_elf_add_dynamic_entry (info, DT_SYMBOLIC, 0)) - return FALSE; - info->flags |= DF_SYMBOLIC; - } - - if (rpath != NULL) - { - size_t indx; - bfd_vma tag; - - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath, - TRUE); - if (indx == (size_t) -1) - return FALSE; - - tag = info->new_dtags ? DT_RUNPATH : DT_RPATH; - if (!_bfd_elf_add_dynamic_entry (info, tag, indx)) - return FALSE; - } - - if (filter_shlib != NULL) - { - size_t indx; - - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, - filter_shlib, TRUE); - if (indx == (size_t) -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++) - { - size_t indx; - - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, - *p, TRUE); - if (indx == (size_t) -1 - || !_bfd_elf_add_dynamic_entry (info, DT_AUXILIARY, indx)) - return FALSE; - } - } - - if (audit != NULL) - { - size_t indx; - - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, audit, - TRUE); - if (indx == (size_t) -1 - || !_bfd_elf_add_dynamic_entry (info, DT_AUDIT, indx)) - return FALSE; - } - - if (depaudit != NULL) - { - size_t indx; - - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, depaudit, - TRUE); - if (indx == (size_t) -1 - || !_bfd_elf_add_dynamic_entry (info, DT_DEPAUDIT, indx)) - return FALSE; - } - - eif.info = info; - eif.failed = 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 (! bfd_link_executable (info)) - { - bfd *sub; - asection *o; - - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - if (bfd_get_flavour (sub) == bfd_target_elf_flavour - && (o = sub->sections) != NULL - && o->sec_info_type != SEC_INFO_TYPE_JUST_SYMS) - 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_linker_section (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 ((info->emit_hash - && !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0)) - || (info->emit_gnu_hash - && !_bfd_elf_add_dynamic_entry (info, DT_GNU_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; - } - } - - if (! _bfd_elf_maybe_strip_eh_frame_hdr (info)) - return FALSE; - - /* The backend must work out the sizes of all the other dynamic - sections. */ - if (dynobj != NULL - && bed->elf_backend_size_dynamic_sections != NULL - && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) - return FALSE; - - if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) - { - if (elf_tdata (output_bfd)->cverdefs) - { - unsigned int crefs = elf_tdata (output_bfd)->cverdefs; - - if (!_bfd_elf_add_dynamic_entry (info, DT_VERDEF, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_VERDEFNUM, crefs)) - return FALSE; - } - - 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 (bfd_link_executable (info)) - 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; - } - - if (elf_tdata (output_bfd)->cverrefs) - { - unsigned int crefs = elf_tdata (output_bfd)->cverrefs; - - if (!_bfd_elf_add_dynamic_entry (info, DT_VERNEED, 0) - || !_bfd_elf_add_dynamic_entry (info, DT_VERNEEDNUM, crefs)) - return FALSE; - } - - if ((elf_tdata (output_bfd)->cverrefs == 0 - && elf_tdata (output_bfd)->cverdefs == 0) - || _bfd_elf_link_renumber_dynsyms (output_bfd, info, NULL) <= 1) - { - asection *s; - - s = bfd_get_linker_section (dynobj, ".gnu.version"); - s->flags |= SEC_EXCLUDE; - } - } - return TRUE; -} - -/* Find the first non-excluded output section. We'll use its - section symbol for some emitted relocs. */ -void -_bfd_elf_init_1_index_section (bfd *output_bfd, struct bfd_link_info *info) -{ - asection *s; - - for (s = output_bfd->sections; s != NULL; s = s->next) - if ((s->flags & (SEC_EXCLUDE | SEC_ALLOC)) == SEC_ALLOC - && !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s)) - { - elf_hash_table (info)->text_index_section = s; - break; - } -} - -/* Find two non-excluded output sections, one for code, one for data. - We'll use their section symbols for some emitted relocs. */ -void -_bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info) -{ - asection *s; - - /* Data first, since setting text_index_section changes - _bfd_elf_link_omit_section_dynsym. */ - for (s = output_bfd->sections; s != NULL; s = s->next) - if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC) - && !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s)) - { - elf_hash_table (info)->data_index_section = s; - break; - } - - for (s = output_bfd->sections; s != NULL; s = s->next) - if (((s->flags & (SEC_EXCLUDE | SEC_ALLOC | SEC_READONLY)) - == (SEC_ALLOC | SEC_READONLY)) - && !_bfd_elf_link_omit_section_dynsym (output_bfd, info, s)) - { - elf_hash_table (info)->text_index_section = s; - break; - } - - if (elf_hash_table (info)->text_index_section == NULL) - elf_hash_table (info)->text_index_section - = elf_hash_table (info)->data_index_section; -} - -bfd_boolean -bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) -{ - const struct elf_backend_data *bed; - unsigned long section_sym_count; - bfd_size_type dynsymcount = 0; - - if (!is_elf_hash_table (info->hash)) - return TRUE; - - bed = get_elf_backend_data (output_bfd); - (*bed->elf_backend_init_index_section) (output_bfd, info); - - /* Assign dynsym indices. In a shared library we generate a section - symbol for each output section, which come first. Next come all - of the back-end allocated local dynamic syms, followed by the rest - of the global symbols. - - This is usually not needed for static binaries, however backends - can request to always do it, e.g. the MIPS backend uses dynamic - symbol counts to lay out GOT, which will be produced in the - presence of GOT relocations even in static binaries (holding fixed - data in that case, to satisfy those relocations). */ - - if (elf_hash_table (info)->dynamic_sections_created - || bed->always_renumber_dynsyms) - dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info, - §ion_sym_count); - - if (elf_hash_table (info)->dynamic_sections_created) - { - bfd *dynobj; - asection *s; - unsigned int dtagcount; - - dynobj = elf_hash_table (info)->dynobj; - - /* Work out the size of the symbol version section. */ - s = bfd_get_linker_section (dynobj, ".gnu.version"); - BFD_ASSERT (s != NULL); - if ((s->flags & SEC_EXCLUDE) == 0) - { - s->size = dynsymcount * sizeof (Elf_External_Versym); - s->contents = (unsigned char *) 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 = elf_hash_table (info)->dynsym; - BFD_ASSERT (s != NULL); - s->size = dynsymcount * bed->s->sizeof_sym; - - s->contents = (unsigned char *) 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); - - elf_hash_table (info)->bucketcount = 0; - - /* Compute the size of the hashing table. As a side effect this - computes the hash values for all the names we export. */ - if (info->emit_hash) - { - unsigned long int *hashcodes; - struct hash_codes_info hashinf; - bfd_size_type amt; - unsigned long int nsyms; - size_t bucketcount; - size_t hash_entry_size; - - /* 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 * sizeof (unsigned long int); - hashcodes = (unsigned long int *) bfd_malloc (amt); - if (hashcodes == NULL) - return FALSE; - hashinf.hashcodes = hashcodes; - hashinf.error = FALSE; - - /* Put all hash values in HASHCODES. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_collect_hash_codes, &hashinf); - if (hashinf.error) - { - free (hashcodes); - return FALSE; - } - - nsyms = hashinf.hashcodes - hashcodes; - bucketcount - = compute_bucket_count (info, hashcodes, nsyms, 0); - free (hashcodes); - - if (bucketcount == 0 && nsyms > 0) - return FALSE; - - elf_hash_table (info)->bucketcount = bucketcount; - - s = bfd_get_linker_section (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 = (unsigned char *) 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); - } - - if (info->emit_gnu_hash) - { - size_t i, cnt; - unsigned char *contents; - struct collect_gnu_hash_codes cinfo; - bfd_size_type amt; - size_t bucketcount; - - memset (&cinfo, 0, sizeof (cinfo)); - - /* 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 * 2 * sizeof (unsigned long int); - cinfo.hashcodes = (long unsigned int *) bfd_malloc (amt); - if (cinfo.hashcodes == NULL) - return FALSE; - - cinfo.hashval = cinfo.hashcodes + dynsymcount; - cinfo.min_dynindx = -1; - cinfo.output_bfd = output_bfd; - cinfo.bed = bed; - - /* Put all hash values in HASHCODES. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_collect_gnu_hash_codes, &cinfo); - if (cinfo.error) - { - free (cinfo.hashcodes); - return FALSE; - } - - bucketcount - = compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1); - - if (bucketcount == 0) - { - free (cinfo.hashcodes); - return FALSE; - } - - s = bfd_get_linker_section (dynobj, ".gnu.hash"); - BFD_ASSERT (s != NULL); - - if (cinfo.nsyms == 0) - { - /* Empty .gnu.hash section is special. */ - BFD_ASSERT (cinfo.min_dynindx == -1); - free (cinfo.hashcodes); - s->size = 5 * 4 + bed->s->arch_size / 8; - contents = (unsigned char *) bfd_zalloc (output_bfd, s->size); - if (contents == NULL) - return FALSE; - s->contents = contents; - /* 1 empty bucket. */ - bfd_put_32 (output_bfd, 1, contents); - /* SYMIDX above the special symbol 0. */ - bfd_put_32 (output_bfd, 1, contents + 4); - /* Just one word for bitmask. */ - bfd_put_32 (output_bfd, 1, contents + 8); - /* Only hash fn bloom filter. */ - bfd_put_32 (output_bfd, 0, contents + 12); - /* No hashes are valid - empty bitmask. */ - bfd_put (bed->s->arch_size, output_bfd, 0, contents + 16); - /* No hashes in the only bucket. */ - bfd_put_32 (output_bfd, 0, - contents + 16 + bed->s->arch_size / 8); - } - else - { - unsigned long int maskwords, maskbitslog2, x; - BFD_ASSERT (cinfo.min_dynindx != -1); - - x = cinfo.nsyms; - maskbitslog2 = 1; - while ((x >>= 1) != 0) - ++maskbitslog2; - if (maskbitslog2 < 3) - maskbitslog2 = 5; - else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms) - maskbitslog2 = maskbitslog2 + 3; - else - maskbitslog2 = maskbitslog2 + 2; - if (bed->s->arch_size == 64) - { - if (maskbitslog2 == 5) - maskbitslog2 = 6; - cinfo.shift1 = 6; - } - else - cinfo.shift1 = 5; - cinfo.mask = (1 << cinfo.shift1) - 1; - cinfo.shift2 = maskbitslog2; - cinfo.maskbits = 1 << maskbitslog2; - maskwords = 1 << (maskbitslog2 - cinfo.shift1); - amt = bucketcount * sizeof (unsigned long int) * 2; - amt += maskwords * sizeof (bfd_vma); - cinfo.bitmask = (bfd_vma *) bfd_malloc (amt); - if (cinfo.bitmask == NULL) - { - free (cinfo.hashcodes); - return FALSE; - } - - cinfo.counts = (long unsigned int *) (cinfo.bitmask + maskwords); - cinfo.indx = cinfo.counts + bucketcount; - cinfo.symindx = dynsymcount - cinfo.nsyms; - memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma)); - - /* Determine how often each hash bucket is used. */ - memset (cinfo.counts, 0, bucketcount * sizeof (cinfo.counts[0])); - for (i = 0; i < cinfo.nsyms; ++i) - ++cinfo.counts[cinfo.hashcodes[i] % bucketcount]; - - for (i = 0, cnt = cinfo.symindx; i < bucketcount; ++i) - if (cinfo.counts[i] != 0) - { - cinfo.indx[i] = cnt; - cnt += cinfo.counts[i]; - } - BFD_ASSERT (cnt == dynsymcount); - cinfo.bucketcount = bucketcount; - cinfo.local_indx = cinfo.min_dynindx; - - s->size = (4 + bucketcount + cinfo.nsyms) * 4; - s->size += cinfo.maskbits / 8; - contents = (unsigned char *) bfd_zalloc (output_bfd, s->size); - if (contents == NULL) - { - free (cinfo.bitmask); - free (cinfo.hashcodes); - return FALSE; - } - - s->contents = contents; - bfd_put_32 (output_bfd, bucketcount, contents); - bfd_put_32 (output_bfd, cinfo.symindx, contents + 4); - bfd_put_32 (output_bfd, maskwords, contents + 8); - bfd_put_32 (output_bfd, cinfo.shift2, contents + 12); - contents += 16 + cinfo.maskbits / 8; - - for (i = 0; i < bucketcount; ++i) - { - if (cinfo.counts[i] == 0) - bfd_put_32 (output_bfd, 0, contents); - else - bfd_put_32 (output_bfd, cinfo.indx[i], contents); - contents += 4; - } - - cinfo.contents = contents; - - /* Renumber dynamic symbols, populate .gnu.hash section. */ - elf_link_hash_traverse (elf_hash_table (info), - elf_renumber_gnu_hash_syms, &cinfo); - - contents = s->contents + 16; - for (i = 0; i < maskwords; ++i) - { - bfd_put (bed->s->arch_size, output_bfd, cinfo.bitmask[i], - contents); - contents += bed->s->arch_size / 8; - } - - free (cinfo.bitmask); - free (cinfo.hashcodes); - } - } - - s = bfd_get_linker_section (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; -} - -/* 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 == SEC_INFO_TYPE_MERGE); - sec->sec_info_type = SEC_INFO_TYPE_NONE; -} - -/* Finish SHF_MERGE section merging. */ - -bfd_boolean -_bfd_elf_merge_sections (bfd *obfd, 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 - && bfd_get_flavour (ibfd) == bfd_target_elf_flavour - && (elf_elfheader (ibfd)->e_ident[EI_CLASS] - == get_elf_backend_data (obfd)->s->elfclass)) - 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 (obfd, - &elf_hash_table (info)->merge_info, - sec, &secdata->sec_info)) - return FALSE; - else if (secdata->sec_info) - sec->sec_info_type = SEC_INFO_TYPE_MERGE; - } - - if (elf_hash_table (info)->merge_info != NULL) - _bfd_merge_sections (obfd, info, elf_hash_table (info)->merge_info, - merge_sections_remove_hook); - return TRUE; -} - -/* 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 = (struct bfd_hash_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. */ - - if (dir->versioned != versioned_hidden) - 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) -{ - /* STT_GNU_IFUNC symbol must go through PLT. */ - if (h->type != STT_GNU_IFUNC) - { - h->plt = elf_hash_table (info)->init_plt_offset; - h->needs_plt = 0; - } - if (force_local) - { - h->forced_local = 1; - if (h->dynindx != -1) - { - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - h->dynstr_index); - h->dynindx = -1; - h->dynstr_index = 0; - } - } -} - -/* Initialize an ELF linker hash table. *TABLE has been zeroed by our - caller. */ - -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, - enum elf_target_id target_id) -{ - bfd_boolean ret; - int can_refcount = get_elf_backend_data (abfd)->can_refcount; - - 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; - - ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); - - table->root.type = bfd_link_elf_hash_table; - table->hash_table_id = target_id; - - 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 = (struct elf_link_hash_table *) bfd_zmalloc (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), - GENERIC_ELF_DATA)) - { - free (ret); - return NULL; - } - ret->root.hash_table_free = _bfd_elf_link_hash_table_free; - - return &ret->root; -} - -/* Destroy an ELF linker hash table. */ - -void -_bfd_elf_link_hash_table_free (bfd *obfd) -{ - struct elf_link_hash_table *htab; - - htab = (struct elf_link_hash_table *) obfd->link.hash; - if (htab->dynstr != NULL) - _bfd_elf_strtab_free (htab->dynstr); - _bfd_merge_sections_free (htab->merge_info); - _bfd_generic_link_hash_table_free (obfd); -} - -/* 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, enum dynamic_lib_link_class 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; - unsigned 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 == SHN_BAD) - 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 = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); - if (l == NULL) - goto error_return; - - l->by = abfd; - l->name = string; - l->next = *pneeded; - *pneeded = l; - } - } - - free (dynbuf); - - return TRUE; - - error_return: - if (dynbuf != NULL) - free (dynbuf); - return FALSE; -} - -struct elf_symbuf_symbol -{ - unsigned long st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* Visibilty, and target specific */ -}; - -struct elf_symbuf_head -{ - struct elf_symbuf_symbol *ssym; - size_t count; - unsigned int st_shndx; -}; - -struct elf_symbol -{ - union - { - Elf_Internal_Sym *isym; - struct elf_symbuf_symbol *ssym; - } u; - const char *name; -}; - -/* Sort references to symbols by ascending section number. */ - -static int -elf_sort_elf_symbol (const void *arg1, const void *arg2) -{ - const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1; - const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2; - - return s1->st_shndx - s2->st_shndx; -} - -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); -} - -static struct elf_symbuf_head * -elf_create_symbuf (size_t symcount, Elf_Internal_Sym *isymbuf) -{ - Elf_Internal_Sym **ind, **indbufend, **indbuf; - struct elf_symbuf_symbol *ssym; - struct elf_symbuf_head *ssymbuf, *ssymhead; - size_t i, shndx_count, total_size; - - indbuf = (Elf_Internal_Sym **) bfd_malloc2 (symcount, sizeof (*indbuf)); - if (indbuf == NULL) - return NULL; - - for (ind = indbuf, i = 0; i < symcount; i++) - if (isymbuf[i].st_shndx != SHN_UNDEF) - *ind++ = &isymbuf[i]; - indbufend = ind; - - qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *), - elf_sort_elf_symbol); - - shndx_count = 0; - if (indbufend > indbuf) - for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++) - if (ind[0]->st_shndx != ind[1]->st_shndx) - shndx_count++; - - total_size = ((shndx_count + 1) * sizeof (*ssymbuf) - + (indbufend - indbuf) * sizeof (*ssym)); - ssymbuf = (struct elf_symbuf_head *) bfd_malloc (total_size); - if (ssymbuf == NULL) - { - free (indbuf); - return NULL; - } - - ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count + 1); - ssymbuf->ssym = NULL; - ssymbuf->count = shndx_count; - ssymbuf->st_shndx = 0; - for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++) - { - if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx) - { - ssymhead++; - ssymhead->ssym = ssym; - ssymhead->count = 0; - ssymhead->st_shndx = (*ind)->st_shndx; - } - ssym->st_name = (*ind)->st_name; - ssym->st_info = (*ind)->st_info; - ssym->st_other = (*ind)->st_other; - ssymhead->count++; - } - BFD_ASSERT ((size_t) (ssymhead - ssymbuf) == shndx_count - && (((bfd_hostptr_t) ssym - (bfd_hostptr_t) ssymbuf) - == total_size)); - - free (indbuf); - return ssymbuf; -} - -/* Check if 2 sections define the same set of local and global - symbols. */ - -static bfd_boolean -bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, - struct bfd_link_info *info) -{ - bfd *bfd1, *bfd2; - const struct elf_backend_data *bed1, *bed2; - Elf_Internal_Shdr *hdr1, *hdr2; - size_t symcount1, symcount2; - Elf_Internal_Sym *isymbuf1, *isymbuf2; - struct elf_symbuf_head *ssymbuf1, *ssymbuf2; - Elf_Internal_Sym *isym, *isymend; - struct elf_symbol *symtable1 = NULL, *symtable2 = NULL; - size_t count1, count2, i; - unsigned int shndx1, shndx2; - bfd_boolean result; - - bfd1 = sec1->owner; - bfd2 = sec2->owner; - - /* 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; - - shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1); - shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2); - if (shndx1 == SHN_BAD || shndx2 == SHN_BAD) - 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; - - result = FALSE; - isymbuf1 = NULL; - isymbuf2 = NULL; - ssymbuf1 = (struct elf_symbuf_head *) elf_tdata (bfd1)->symbuf; - ssymbuf2 = (struct elf_symbuf_head *) elf_tdata (bfd2)->symbuf; - - if (ssymbuf1 == NULL) - { - isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, - NULL, NULL, NULL); - if (isymbuf1 == NULL) - goto done; - - if (!info->reduce_memory_overheads) - elf_tdata (bfd1)->symbuf = ssymbuf1 - = elf_create_symbuf (symcount1, isymbuf1); - } - - if (ssymbuf1 == NULL || ssymbuf2 == NULL) - { - isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, - NULL, NULL, NULL); - if (isymbuf2 == NULL) - goto done; - - if (ssymbuf1 != NULL && !info->reduce_memory_overheads) - elf_tdata (bfd2)->symbuf = ssymbuf2 - = elf_create_symbuf (symcount2, isymbuf2); - } - - if (ssymbuf1 != NULL && ssymbuf2 != NULL) - { - /* Optimized faster version. */ - size_t lo, hi, mid; - struct elf_symbol *symp; - struct elf_symbuf_symbol *ssym, *ssymend; - - lo = 0; - hi = ssymbuf1->count; - ssymbuf1++; - count1 = 0; - while (lo < hi) - { - mid = (lo + hi) / 2; - if (shndx1 < ssymbuf1[mid].st_shndx) - hi = mid; - else if (shndx1 > ssymbuf1[mid].st_shndx) - lo = mid + 1; - else - { - count1 = ssymbuf1[mid].count; - ssymbuf1 += mid; - break; - } - } - - lo = 0; - hi = ssymbuf2->count; - ssymbuf2++; - count2 = 0; - while (lo < hi) - { - mid = (lo + hi) / 2; - if (shndx2 < ssymbuf2[mid].st_shndx) - hi = mid; - else if (shndx2 > ssymbuf2[mid].st_shndx) - lo = mid + 1; - else - { - count2 = ssymbuf2[mid].count; - ssymbuf2 += mid; - break; - } - } - - if (count1 == 0 || count2 == 0 || count1 != count2) - goto done; - - symtable1 - = (struct elf_symbol *) bfd_malloc (count1 * sizeof (*symtable1)); - symtable2 - = (struct elf_symbol *) bfd_malloc (count2 * sizeof (*symtable2)); - if (symtable1 == NULL || symtable2 == NULL) - goto done; - - symp = symtable1; - for (ssym = ssymbuf1->ssym, ssymend = ssym + count1; - ssym < ssymend; ssym++, symp++) - { - symp->u.ssym = ssym; - symp->name = bfd_elf_string_from_elf_section (bfd1, - hdr1->sh_link, - ssym->st_name); - } - - symp = symtable2; - for (ssym = ssymbuf2->ssym, ssymend = ssym + count2; - ssym < ssymend; ssym++, symp++) - { - symp->u.ssym = ssym; - symp->name = bfd_elf_string_from_elf_section (bfd2, - hdr2->sh_link, - ssym->st_name); - } - - /* 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].u.ssym->st_info != symtable2 [i].u.ssym->st_info - || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other - || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) - goto done; - - result = TRUE; - goto done; - } - - symtable1 = (struct elf_symbol *) - bfd_malloc (symcount1 * sizeof (struct elf_symbol)); - symtable2 = (struct elf_symbol *) - bfd_malloc (symcount2 * sizeof (struct elf_symbol)); - if (symtable1 == NULL || symtable2 == NULL) - goto done; - - /* Count definitions in the section. */ - count1 = 0; - for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++) - if (isym->st_shndx == shndx1) - symtable1[count1++].u.isym = isym; - - count2 = 0; - for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++) - if (isym->st_shndx == shndx2) - symtable2[count2++].u.isym = isym; - - if (count1 == 0 || count2 == 0 || count1 != count2) - goto done; - - for (i = 0; i < count1; i++) - symtable1[i].name - = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, - symtable1[i].u.isym->st_name); - - for (i = 0; i < count2; i++) - symtable2[i].name - = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, - symtable2[i].u.isym->st_name); - - /* 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].u.isym->st_info != symtable2 [i].u.isym->st_info - || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->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; -} - -/* 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); -} - -/* 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 elf_strtab_hash *symstrtab; - /* .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 for SHT_SYMTAB_SHNDX section. */ - Elf_External_Sym_Shndx *symshndxbuf; - /* Number of STT_FILE syms seen. */ - size_t filesym_count; -}; - -/* This struct is used to pass information to elf_link_output_extsym. */ - -struct elf_outext_info -{ - bfd_boolean failed; - bfd_boolean localsyms; - bfd_boolean file_sym_done; - struct elf_final_link_info *flinfo; -}; - - -/* Support for evaluating a complex relocation. - - Complex relocations are generalized, self-describing relocations. The - implementation of them consists of two parts: complex symbols, and the - relocations themselves. - - The relocations are use a reserved elf-wide relocation type code (R_RELC - external / BFD_RELOC_RELC internal) and an encoding of relocation field - information (start bit, end bit, word width, etc) into the addend. This - information is extracted from CGEN-generated operand tables within gas. - - Complex symbols are mangled symbols (BSF_RELC external / STT_RELC - internal) representing prefix-notation expressions, including but not - limited to those sorts of expressions normally encoded as addends in the - addend field. The symbol mangling format is: - - := - | ':' - | ':' ':' - ; - - := 's' ':' - | 'S' ':' - | '#' - ; - - := as in C - := as in C, plus "0-" for unambiguous negation. */ - -static void -set_symbol_value (bfd *bfd_with_globals, - Elf_Internal_Sym *isymbuf, - size_t locsymcount, - size_t symidx, - bfd_vma val) -{ - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry *h; - size_t extsymoff = locsymcount; - - if (symidx < locsymcount) - { - Elf_Internal_Sym *sym; - - sym = isymbuf + symidx; - if (ELF_ST_BIND (sym->st_info) == STB_LOCAL) - { - /* It is a local symbol: move it to the - "absolute" section and give it a value. */ - sym->st_shndx = SHN_ABS; - sym->st_value = val; - return; - } - BFD_ASSERT (elf_bad_symtab (bfd_with_globals)); - extsymoff = 0; - } - - /* It is a global symbol: set its link type - to "defined" and give it a value. */ - - sym_hashes = elf_sym_hashes (bfd_with_globals); - h = sym_hashes [symidx - 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; - h->root.type = bfd_link_hash_defined; - h->root.u.def.value = val; - h->root.u.def.section = bfd_abs_section_ptr; -} - -static bfd_boolean -resolve_symbol (const char *name, - bfd *input_bfd, - struct elf_final_link_info *flinfo, - bfd_vma *result, - Elf_Internal_Sym *isymbuf, - size_t locsymcount) -{ - Elf_Internal_Sym *sym; - struct bfd_link_hash_entry *global_entry; - const char *candidate = NULL; - Elf_Internal_Shdr *symtab_hdr; - size_t i; - - symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; - - for (i = 0; i < locsymcount; ++ i) - { - sym = isymbuf + i; - - if (ELF_ST_BIND (sym->st_info) != STB_LOCAL) - continue; - - candidate = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); -#ifdef DEBUG - printf ("Comparing string: '%s' vs. '%s' = 0x%lx\n", - name, candidate, (unsigned long) sym->st_value); -#endif - if (candidate && strcmp (candidate, name) == 0) - { - asection *sec = flinfo->sections [i]; - - *result = _bfd_elf_rel_local_sym (input_bfd, sym, &sec, 0); - *result += sec->output_offset + sec->output_section->vma; -#ifdef DEBUG - printf ("Found symbol with value %8.8lx\n", - (unsigned long) *result); -#endif - return TRUE; - } - } - - /* Hmm, haven't found it yet. perhaps it is a global. */ - global_entry = bfd_link_hash_lookup (flinfo->info->hash, name, - FALSE, FALSE, TRUE); - if (!global_entry) - return FALSE; - - if (global_entry->type == bfd_link_hash_defined - || global_entry->type == bfd_link_hash_defweak) - { - *result = (global_entry->u.def.value - + global_entry->u.def.section->output_section->vma - + global_entry->u.def.section->output_offset); -#ifdef DEBUG - printf ("Found GLOBAL symbol '%s' with value %8.8lx\n", - global_entry->root.string, (unsigned long) *result); -#endif - return TRUE; - } - - return FALSE; -} - -/* Looks up NAME in SECTIONS. If found sets RESULT to NAME's address (in - bytes) and returns TRUE, otherwise returns FALSE. Accepts pseudo-section - names like "foo.end" which is the end address of section "foo". */ - -static bfd_boolean -resolve_section (const char *name, - asection *sections, - bfd_vma *result, - bfd * abfd) -{ - asection *curr; - unsigned int len; - - for (curr = sections; curr; curr = curr->next) - if (strcmp (curr->name, name) == 0) - { - *result = curr->vma; - return TRUE; - } - - /* Hmm. still haven't found it. try pseudo-section names. */ - /* FIXME: This could be coded more efficiently... */ - for (curr = sections; curr; curr = curr->next) - { - len = strlen (curr->name); - if (len > strlen (name)) - continue; - - if (strncmp (curr->name, name, len) == 0) - { - if (strncmp (".end", name + len, 4) == 0) - { - *result = curr->vma + curr->size / bfd_octets_per_byte (abfd); - return TRUE; - } - - /* Insert more pseudo-section names here, if you like. */ - } - } - - return FALSE; -} - -static void -undefined_reference (const char *reftype, const char *name) -{ - /* xgettext:c-format */ - _bfd_error_handler (_("undefined %s reference in complex symbol: %s"), - reftype, name); -} - -static bfd_boolean -eval_symbol (bfd_vma *result, - const char **symp, - bfd *input_bfd, - struct elf_final_link_info *flinfo, - bfd_vma dot, - Elf_Internal_Sym *isymbuf, - size_t locsymcount, - int signed_p) -{ - size_t len; - size_t symlen; - bfd_vma a; - bfd_vma b; - char symbuf[4096]; - const char *sym = *symp; - const char *symend; - bfd_boolean symbol_is_section = FALSE; - - len = strlen (sym); - symend = sym + len; - - if (len < 1 || len > sizeof (symbuf)) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - switch (* sym) - { - case '.': - *result = dot; - *symp = sym + 1; - return TRUE; - - case '#': - ++sym; - *result = strtoul (sym, (char **) symp, 16); - return TRUE; - - case 'S': - symbol_is_section = TRUE; - /* Fall through. */ - case 's': - ++sym; - symlen = strtol (sym, (char **) symp, 10); - sym = *symp + 1; /* Skip the trailing ':'. */ - - if (symend < sym || symlen + 1 > sizeof (symbuf)) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - memcpy (symbuf, sym, symlen); - symbuf[symlen] = '\0'; - *symp = sym + symlen; - - /* Is it always possible, with complex symbols, that gas "mis-guessed" - the symbol as a section, or vice-versa. so we're pretty liberal in our - interpretation here; section means "try section first", not "must be a - section", and likewise with symbol. */ - - if (symbol_is_section) - { - if (!resolve_section (symbuf, flinfo->output_bfd->sections, result, input_bfd) - && !resolve_symbol (symbuf, input_bfd, flinfo, result, - isymbuf, locsymcount)) - { - undefined_reference ("section", symbuf); - return FALSE; - } - } - else - { - if (!resolve_symbol (symbuf, input_bfd, flinfo, result, - isymbuf, locsymcount) - && !resolve_section (symbuf, flinfo->output_bfd->sections, - result, input_bfd)) - { - undefined_reference ("symbol", symbuf); - return FALSE; - } - } - - return TRUE; - - /* All that remains are operators. */ - -#define UNARY_OP(op) \ - if (strncmp (sym, #op, strlen (#op)) == 0) \ - { \ - sym += strlen (#op); \ - if (*sym == ':') \ - ++sym; \ - *symp = sym; \ - if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \ - isymbuf, locsymcount, signed_p)) \ - return FALSE; \ - if (signed_p) \ - *result = op ((bfd_signed_vma) a); \ - else \ - *result = op a; \ - return TRUE; \ - } - -#define BINARY_OP(op) \ - if (strncmp (sym, #op, strlen (#op)) == 0) \ - { \ - sym += strlen (#op); \ - if (*sym == ':') \ - ++sym; \ - *symp = sym; \ - if (!eval_symbol (&a, symp, input_bfd, flinfo, dot, \ - isymbuf, locsymcount, signed_p)) \ - return FALSE; \ - ++*symp; \ - if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \ - isymbuf, locsymcount, signed_p)) \ - return FALSE; \ - if (signed_p) \ - *result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \ - else \ - *result = a op b; \ - return TRUE; \ - } - - default: - UNARY_OP (0-); - BINARY_OP (<<); - BINARY_OP (>>); - BINARY_OP (==); - BINARY_OP (!=); - BINARY_OP (<=); - BINARY_OP (>=); - BINARY_OP (&&); - BINARY_OP (||); - UNARY_OP (~); - UNARY_OP (!); - BINARY_OP (*); - BINARY_OP (/); - BINARY_OP (%); - BINARY_OP (^); - BINARY_OP (|); - BINARY_OP (&); - BINARY_OP (+); - BINARY_OP (-); - BINARY_OP (<); - BINARY_OP (>); -#undef UNARY_OP -#undef BINARY_OP - _bfd_error_handler (_("unknown operator '%c' in complex symbol"), * sym); - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } -} - -static void -put_value (bfd_vma size, - unsigned long chunksz, - bfd *input_bfd, - bfd_vma x, - bfd_byte *location) -{ - location += (size - chunksz); - - for (; size; size -= chunksz, location -= chunksz) - { - switch (chunksz) - { - case 1: - bfd_put_8 (input_bfd, x, location); - x >>= 8; - break; - case 2: - bfd_put_16 (input_bfd, x, location); - x >>= 16; - break; - case 4: - bfd_put_32 (input_bfd, x, location); - /* Computed this way because x >>= 32 is undefined if x is a 32-bit value. */ - x >>= 16; - x >>= 16; - break; -#ifdef BFD64 - case 8: - bfd_put_64 (input_bfd, x, location); - /* Computed this way because x >>= 64 is undefined if x is a 64-bit value. */ - x >>= 32; - x >>= 32; - break; -#endif - default: - abort (); - break; - } - } -} - -static bfd_vma -get_value (bfd_vma size, - unsigned long chunksz, - bfd *input_bfd, - bfd_byte *location) -{ - int shift; - bfd_vma x = 0; - - /* Sanity checks. */ - BFD_ASSERT (chunksz <= sizeof (x) - && size >= chunksz - && chunksz != 0 - && (size % chunksz) == 0 - && input_bfd != NULL - && location != NULL); - - if (chunksz == sizeof (x)) - { - BFD_ASSERT (size == chunksz); - - /* Make sure that we do not perform an undefined shift operation. - We know that size == chunksz so there will only be one iteration - of the loop below. */ - shift = 0; - } - else - shift = 8 * chunksz; - - for (; size; size -= chunksz, location += chunksz) - { - switch (chunksz) - { - case 1: - x = (x << shift) | bfd_get_8 (input_bfd, location); - break; - case 2: - x = (x << shift) | bfd_get_16 (input_bfd, location); - break; - case 4: - x = (x << shift) | bfd_get_32 (input_bfd, location); - break; -#ifdef BFD64 - case 8: - x = (x << shift) | bfd_get_64 (input_bfd, location); - break; -#endif - default: - abort (); - } - } - return x; -} - -static void -decode_complex_addend (unsigned long *start, /* in bits */ - unsigned long *oplen, /* in bits */ - unsigned long *len, /* in bits */ - unsigned long *wordsz, /* in bytes */ - unsigned long *chunksz, /* in bytes */ - unsigned long *lsb0_p, - unsigned long *signed_p, - unsigned long *trunc_p, - unsigned long encoded) -{ - * start = encoded & 0x3F; - * len = (encoded >> 6) & 0x3F; - * oplen = (encoded >> 12) & 0x3F; - * wordsz = (encoded >> 18) & 0xF; - * chunksz = (encoded >> 22) & 0xF; - * lsb0_p = (encoded >> 27) & 1; - * signed_p = (encoded >> 28) & 1; - * trunc_p = (encoded >> 29) & 1; -} - -bfd_reloc_status_type -bfd_elf_perform_complex_relocation (bfd *input_bfd, - asection *input_section ATTRIBUTE_UNUSED, - bfd_byte *contents, - Elf_Internal_Rela *rel, - bfd_vma relocation) -{ - bfd_vma shift, x, mask; - unsigned long start, oplen, len, wordsz, chunksz, lsb0_p, signed_p, trunc_p; - bfd_reloc_status_type r; - - /* Perform this reloc, since it is complex. - (this is not to say that it necessarily refers to a complex - symbol; merely that it is a self-describing CGEN based reloc. - i.e. the addend has the complete reloc information (bit start, end, - word size, etc) encoded within it.). */ - - decode_complex_addend (&start, &oplen, &len, &wordsz, - &chunksz, &lsb0_p, &signed_p, - &trunc_p, rel->r_addend); - - mask = (((1L << (len - 1)) - 1) << 1) | 1; - - if (lsb0_p) - shift = (start + 1) - len; - else - shift = (8 * wordsz) - (start + len); - - x = get_value (wordsz, chunksz, input_bfd, - contents + rel->r_offset * bfd_octets_per_byte (input_bfd)); - -#ifdef DEBUG - printf ("Doing complex reloc: " - "lsb0? %ld, signed? %ld, trunc? %ld, wordsz %ld, " - "chunksz %ld, start %ld, len %ld, oplen %ld\n" - " dest: %8.8lx, mask: %8.8lx, reloc: %8.8lx\n", - lsb0_p, signed_p, trunc_p, wordsz, chunksz, start, len, - oplen, (unsigned long) x, (unsigned long) mask, - (unsigned long) relocation); -#endif - - r = bfd_reloc_ok; - if (! trunc_p) - /* Now do an overflow check. */ - r = bfd_check_overflow ((signed_p - ? complain_overflow_signed - : complain_overflow_unsigned), - len, 0, (8 * wordsz), - relocation); - - /* Do the deed. */ - x = (x & ~(mask << shift)) | ((relocation & mask) << shift); - -#ifdef DEBUG - printf (" relocation: %8.8lx\n" - " shifted mask: %8.8lx\n" - " shifted/masked reloc: %8.8lx\n" - " result: %8.8lx\n", - (unsigned long) relocation, (unsigned long) (mask << shift), - (unsigned long) ((relocation & mask) << shift), (unsigned long) x); -#endif - put_value (wordsz, chunksz, input_bfd, x, - contents + rel->r_offset * bfd_octets_per_byte (input_bfd)); - return r; -} - -/* Functions to read r_offset from external (target order) reloc - entry. Faster than bfd_getl32 et al, because we let the compiler - know the value is aligned. */ - -static bfd_vma -ext32l_r_offset (const void *p) -{ - union aligned32 - { - uint32_t v; - unsigned char c[4]; - }; - const union aligned32 *a - = (const union aligned32 *) &((const Elf32_External_Rel *) p)->r_offset; - - uint32_t aval = ( (uint32_t) a->c[0] - | (uint32_t) a->c[1] << 8 - | (uint32_t) a->c[2] << 16 - | (uint32_t) a->c[3] << 24); - return aval; -} - -static bfd_vma -ext32b_r_offset (const void *p) -{ - union aligned32 - { - uint32_t v; - unsigned char c[4]; - }; - const union aligned32 *a - = (const union aligned32 *) &((const Elf32_External_Rel *) p)->r_offset; - - uint32_t aval = ( (uint32_t) a->c[0] << 24 - | (uint32_t) a->c[1] << 16 - | (uint32_t) a->c[2] << 8 - | (uint32_t) a->c[3]); - return aval; -} - -#ifdef BFD_HOST_64_BIT -static bfd_vma -ext64l_r_offset (const void *p) -{ - union aligned64 - { - uint64_t v; - unsigned char c[8]; - }; - const union aligned64 *a - = (const union aligned64 *) &((const Elf64_External_Rel *) p)->r_offset; - - uint64_t aval = ( (uint64_t) a->c[0] - | (uint64_t) a->c[1] << 8 - | (uint64_t) a->c[2] << 16 - | (uint64_t) a->c[3] << 24 - | (uint64_t) a->c[4] << 32 - | (uint64_t) a->c[5] << 40 - | (uint64_t) a->c[6] << 48 - | (uint64_t) a->c[7] << 56); - return aval; -} - -static bfd_vma -ext64b_r_offset (const void *p) -{ - union aligned64 - { - uint64_t v; - unsigned char c[8]; - }; - const union aligned64 *a - = (const union aligned64 *) &((const Elf64_External_Rel *) p)->r_offset; - - uint64_t aval = ( (uint64_t) a->c[0] << 56 - | (uint64_t) a->c[1] << 48 - | (uint64_t) a->c[2] << 40 - | (uint64_t) a->c[3] << 32 - | (uint64_t) a->c[4] << 24 - | (uint64_t) a->c[5] << 16 - | (uint64_t) a->c[6] << 8 - | (uint64_t) a->c[7]); - return aval; -} -#endif - -/* When performing a relocatable link, the input relocations are - preserved. But, if they reference global symbols, the indices - referenced must be updated. Update all the relocations found in - RELDATA. */ - -static bfd_boolean -elf_link_adjust_relocs (bfd *abfd, - asection *sec, - struct bfd_elf_section_reloc_data *reldata, - bfd_boolean sort, - struct bfd_link_info *info) -{ - 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; - unsigned int count = reldata->count; - struct elf_link_hash_entry **rel_hash = reldata->hashes; - - if (reldata->hdr->sh_entsize == bed->s->sizeof_rel) - { - swap_in = bed->s->swap_reloc_in; - swap_out = bed->s->swap_reloc_out; - } - else if (reldata->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 = reldata->hdr->contents; - for (i = 0; i < count; i++, rel_hash++, erela += reldata->hdr->sh_entsize) - { - Elf_Internal_Rela irela[MAX_INT_RELS_PER_EXT_REL]; - unsigned int j; - - if (*rel_hash == NULL) - continue; - - if ((*rel_hash)->indx == -2 - && info->gc_sections - && ! info->gc_keep_exported) - { - /* PR 21524: Let the user know if a symbol was removed by garbage collection. */ - _bfd_error_handler (_("%B:%A: error: relocation references symbol %s which was removed by garbage collection."), - abfd, sec, - (*rel_hash)->root.root.string); - _bfd_error_handler (_("%B:%A: error: try relinking with --gc-keep-exported enabled."), - abfd, sec); - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - 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); - } - - if (bed->elf_backend_update_relocs) - (*bed->elf_backend_update_relocs) (sec, reldata); - - if (sort && count != 0) - { - bfd_vma (*ext_r_off) (const void *); - bfd_vma r_off; - size_t elt_size; - bfd_byte *base, *end, *p, *loc; - bfd_byte *buf = NULL; - - if (bed->s->arch_size == 32) - { - if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) - ext_r_off = ext32l_r_offset; - else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) - ext_r_off = ext32b_r_offset; - else - abort (); - } - else - { -#ifdef BFD_HOST_64_BIT - if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) - ext_r_off = ext64l_r_offset; - else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) - ext_r_off = ext64b_r_offset; - else -#endif - abort (); - } - - /* Must use a stable sort here. A modified insertion sort, - since the relocs are mostly sorted already. */ - elt_size = reldata->hdr->sh_entsize; - base = reldata->hdr->contents; - end = base + count * elt_size; - if (elt_size > sizeof (Elf64_External_Rela)) - abort (); - - /* Ensure the first element is lowest. This acts as a sentinel, - speeding the main loop below. */ - r_off = (*ext_r_off) (base); - for (p = loc = base; (p += elt_size) < end; ) - { - bfd_vma r_off2 = (*ext_r_off) (p); - if (r_off > r_off2) - { - r_off = r_off2; - loc = p; - } - } - if (loc != base) - { - /* Don't just swap *base and *loc as that changes the order - of the original base[0] and base[1] if they happen to - have the same r_offset. */ - bfd_byte onebuf[sizeof (Elf64_External_Rela)]; - memcpy (onebuf, loc, elt_size); - memmove (base + elt_size, base, loc - base); - memcpy (base, onebuf, elt_size); - } - - for (p = base + elt_size; (p += elt_size) < end; ) - { - /* base to p is sorted, *p is next to insert. */ - r_off = (*ext_r_off) (p); - /* Search the sorted region for location to insert. */ - loc = p - elt_size; - while (r_off < (*ext_r_off) (loc)) - loc -= elt_size; - loc += elt_size; - if (loc != p) - { - /* Chances are there is a run of relocs to insert here, - from one of more input files. Files are not always - linked in order due to the way elf_link_input_bfd is - called. See pr17666. */ - size_t sortlen = p - loc; - bfd_vma r_off2 = (*ext_r_off) (loc); - size_t runlen = elt_size; - size_t buf_size = 96 * 1024; - while (p + runlen < end - && (sortlen <= buf_size - || runlen + elt_size <= buf_size) - && r_off2 > (*ext_r_off) (p + runlen)) - runlen += elt_size; - if (buf == NULL) - { - buf = bfd_malloc (buf_size); - if (buf == NULL) - return FALSE; - } - if (runlen < sortlen) - { - memcpy (buf, p, runlen); - memmove (loc + runlen, loc, sortlen); - memcpy (loc, buf, runlen); - } - else - { - memcpy (buf, loc, sortlen); - memmove (loc, p, runlen); - memcpy (loc + runlen, buf, sortlen); - } - p += runlen - elt_size; - } - } - /* Hashes are no longer valid. */ - free (reldata->hashes); - reldata->hashes = NULL; - free (buf); - } - return TRUE; -} - -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 = (const struct elf_link_sort_rela *) A; - const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B; - int relativea, relativeb; - - relativea = a->type == reloc_class_relative; - relativeb = b->type == reloc_class_relative; - - if (relativea < relativeb) - return 1; - if (relativea > relativeb) - return -1; - if ((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 = (const struct elf_link_sort_rela *) A; - const struct elf_link_sort_rela *b = (const struct elf_link_sort_rela *) B; - - if (a->type < b->type) - return -1; - if (a->type > b->type) - return 1; - if (a->u.offset < b->u.offset) - return -1; - if (a->u.offset > b->u.offset) - 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 *dynamic_relocs; - asection *rela_dyn; - asection *rel_dyn; - 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; - unsigned int opb = bfd_octets_per_byte (abfd); - 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; - bfd_boolean use_rela; - - /* Find a dynamic reloc section. */ - rela_dyn = bfd_get_section_by_name (abfd, ".rela.dyn"); - rel_dyn = bfd_get_section_by_name (abfd, ".rel.dyn"); - if (rela_dyn != NULL && rela_dyn->size > 0 - && rel_dyn != NULL && rel_dyn->size > 0) - { - bfd_boolean use_rela_initialised = FALSE; - - /* This is just here to stop gcc from complaining. - Its initialization checking code is not perfect. */ - use_rela = TRUE; - - /* Both sections are present. Examine the sizes - of the indirect sections to help us choose. */ - for (lo = rela_dyn->map_head.link_order; lo != NULL; lo = lo->next) - if (lo->type == bfd_indirect_link_order) - { - asection *o = lo->u.indirect.section; - - if ((o->size % bed->s->sizeof_rela) == 0) - { - if ((o->size % bed->s->sizeof_rel) == 0) - /* Section size is divisible by both rel and rela sizes. - It is of no help to us. */ - ; - else - { - /* Section size is only divisible by rela. */ - if (use_rela_initialised && !use_rela) - { - _bfd_error_handler (_("%B: Unable to sort relocs - " - "they are in more than one size"), - abfd); - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - else - { - use_rela = TRUE; - use_rela_initialised = TRUE; - } - } - } - else if ((o->size % bed->s->sizeof_rel) == 0) - { - /* Section size is only divisible by rel. */ - if (use_rela_initialised && use_rela) - { - _bfd_error_handler (_("%B: Unable to sort relocs - " - "they are in more than one size"), - abfd); - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - else - { - use_rela = FALSE; - use_rela_initialised = TRUE; - } - } - else - { - /* The section size is not divisible by either - - something is wrong. */ - _bfd_error_handler (_("%B: Unable to sort relocs - " - "they are of an unknown size"), abfd); - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - } - - for (lo = rel_dyn->map_head.link_order; lo != NULL; lo = lo->next) - if (lo->type == bfd_indirect_link_order) - { - asection *o = lo->u.indirect.section; - - if ((o->size % bed->s->sizeof_rela) == 0) - { - if ((o->size % bed->s->sizeof_rel) == 0) - /* Section size is divisible by both rel and rela sizes. - It is of no help to us. */ - ; - else - { - /* Section size is only divisible by rela. */ - if (use_rela_initialised && !use_rela) - { - _bfd_error_handler (_("%B: Unable to sort relocs - " - "they are in more than one size"), - abfd); - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - else - { - use_rela = TRUE; - use_rela_initialised = TRUE; - } - } - } - else if ((o->size % bed->s->sizeof_rel) == 0) - { - /* Section size is only divisible by rel. */ - if (use_rela_initialised && use_rela) - { - _bfd_error_handler (_("%B: Unable to sort relocs - " - "they are in more than one size"), - abfd); - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - else - { - use_rela = FALSE; - use_rela_initialised = TRUE; - } - } - else - { - /* The section size is not divisible by either - - something is wrong. */ - _bfd_error_handler (_("%B: Unable to sort relocs - " - "they are of an unknown size"), abfd); - bfd_set_error (bfd_error_invalid_operation); - return 0; - } - } - - if (! use_rela_initialised) - /* Make a guess. */ - use_rela = TRUE; - } - else if (rela_dyn != NULL && rela_dyn->size > 0) - use_rela = TRUE; - else if (rel_dyn != NULL && rel_dyn->size > 0) - use_rela = FALSE; - else - return 0; - - if (use_rela) - { - dynamic_relocs = rela_dyn; - ext_size = bed->s->sizeof_rela; - swap_in = bed->s->swap_reloca_in; - swap_out = bed->s->swap_reloca_out; - } - else - { - dynamic_relocs = rel_dyn; - ext_size = bed->s->sizeof_rel; - swap_in = bed->s->swap_reloc_in; - swap_out = bed->s->swap_reloc_out; - } - - size = 0; - for (lo = dynamic_relocs->map_head.link_order; lo != NULL; lo = lo->next) - if (lo->type == bfd_indirect_link_order) - size += lo->u.indirect.section->size; - - if (size != dynamic_relocs->size) - return 0; - - sort_elt = (sizeof (struct elf_link_sort_rela) - + (i2e - 1) * sizeof (Elf_Internal_Rela)); - - count = dynamic_relocs->size / ext_size; - if (count == 0) - return 0; - sort = (bfd_byte *) 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 = dynamic_relocs->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 * opb / 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) (info, o, 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); - - struct elf_link_hash_table *htab = elf_hash_table (info); - if (htab->srelplt && htab->srelplt->output_section == dynamic_relocs) - { - /* We have plt relocs in .rela.dyn. */ - sq = (struct elf_link_sort_rela *) sort; - for (i = 0; i < count; i++) - if (sq[count - i - 1].type != reloc_class_plt) - break; - if (i != 0 && htab->srelplt->size == i * ext_size) - { - struct bfd_link_order **plo; - /* Put srelplt link_order last. This is so the output_offset - set in the next loop is correct for DT_JMPREL. */ - for (plo = &dynamic_relocs->map_head.link_order; *plo != NULL; ) - if ((*plo)->type == bfd_indirect_link_order - && (*plo)->u.indirect.section == htab->srelplt) - { - lo = *plo; - *plo = lo->next; - } - else - plo = &(*plo)->next; - *plo = lo; - lo->next = NULL; - dynamic_relocs->map_tail.link_order = lo; - } - } - - p = sort; - for (lo = dynamic_relocs->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; - o->output_offset = (p - sort) / sort_elt * ext_size / opb; - 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 = dynamic_relocs; - return ret; -} - -/* Add a symbol to the output symbol string table. */ - -static int -elf_link_output_symstrtab (struct elf_final_link_info *flinfo, - const char *name, - Elf_Internal_Sym *elfsym, - asection *input_sec, - struct elf_link_hash_entry *h) -{ - int (*output_symbol_hook) - (struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *, - struct elf_link_hash_entry *); - struct elf_link_hash_table *hash_table; - const struct elf_backend_data *bed; - bfd_size_type strtabsize; - - BFD_ASSERT (elf_onesymtab (flinfo->output_bfd)); - - bed = get_elf_backend_data (flinfo->output_bfd); - output_symbol_hook = bed->elf_backend_link_output_symbol_hook; - if (output_symbol_hook != NULL) - { - int ret = (*output_symbol_hook) (flinfo->info, name, elfsym, input_sec, h); - if (ret != 1) - return ret; - } - - if (name == NULL - || *name == '\0' - || (input_sec->flags & SEC_EXCLUDE)) - elfsym->st_name = (unsigned long) -1; - else - { - /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize - to get the final offset for st_name. */ - elfsym->st_name - = (unsigned long) _bfd_elf_strtab_add (flinfo->symstrtab, - name, FALSE); - if (elfsym->st_name == (unsigned long) -1) - return 0; - } - - hash_table = elf_hash_table (flinfo->info); - strtabsize = hash_table->strtabsize; - if (strtabsize <= hash_table->strtabcount) - { - strtabsize += strtabsize; - hash_table->strtabsize = strtabsize; - strtabsize *= sizeof (*hash_table->strtab); - hash_table->strtab - = (struct elf_sym_strtab *) bfd_realloc (hash_table->strtab, - strtabsize); - if (hash_table->strtab == NULL) - return 0; - } - hash_table->strtab[hash_table->strtabcount].sym = *elfsym; - hash_table->strtab[hash_table->strtabcount].dest_index - = hash_table->strtabcount; - hash_table->strtab[hash_table->strtabcount].destshndx_index - = flinfo->symshndxbuf ? bfd_get_symcount (flinfo->output_bfd) : 0; - - bfd_get_symcount (flinfo->output_bfd) += 1; - hash_table->strtabcount += 1; - - return 1; -} - -/* Swap symbols out to the symbol table and flush the output symbols to - the file. */ - -static bfd_boolean -elf_link_swap_symbols_out (struct elf_final_link_info *flinfo) -{ - struct elf_link_hash_table *hash_table = elf_hash_table (flinfo->info); - bfd_size_type amt; - size_t i; - const struct elf_backend_data *bed; - bfd_byte *symbuf; - Elf_Internal_Shdr *hdr; - file_ptr pos; - bfd_boolean ret; - - if (!hash_table->strtabcount) - return TRUE; - - BFD_ASSERT (elf_onesymtab (flinfo->output_bfd)); - - bed = get_elf_backend_data (flinfo->output_bfd); - - amt = bed->s->sizeof_sym * hash_table->strtabcount; - symbuf = (bfd_byte *) bfd_malloc (amt); - if (symbuf == NULL) - return FALSE; - - if (flinfo->symshndxbuf) - { - amt = sizeof (Elf_External_Sym_Shndx); - amt *= bfd_get_symcount (flinfo->output_bfd); - flinfo->symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); - if (flinfo->symshndxbuf == NULL) - { - free (symbuf); - return FALSE; - } - } - - for (i = 0; i < hash_table->strtabcount; i++) - { - struct elf_sym_strtab *elfsym = &hash_table->strtab[i]; - if (elfsym->sym.st_name == (unsigned long) -1) - elfsym->sym.st_name = 0; - else - elfsym->sym.st_name - = (unsigned long) _bfd_elf_strtab_offset (flinfo->symstrtab, - elfsym->sym.st_name); - bed->s->swap_symbol_out (flinfo->output_bfd, &elfsym->sym, - ((bfd_byte *) symbuf - + (elfsym->dest_index - * bed->s->sizeof_sym)), - (flinfo->symshndxbuf - + elfsym->destshndx_index)); - } - - hdr = &elf_tdata (flinfo->output_bfd)->symtab_hdr; - pos = hdr->sh_offset + hdr->sh_size; - amt = hash_table->strtabcount * bed->s->sizeof_sym; - if (bfd_seek (flinfo->output_bfd, pos, SEEK_SET) == 0 - && bfd_bwrite (symbuf, amt, flinfo->output_bfd) == amt) - { - hdr->sh_size += amt; - ret = TRUE; - } - else - ret = FALSE; - - free (symbuf); - - free (hash_table->strtab); - hash_table->strtab = NULL; - - return ret; -} - -/* 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_LORESERVE & 0xffff) - && sym->st_shndx < SHN_LORESERVE) - { - /* The gABI doesn't support dynamic symbols in output sections - beyond 64k. */ - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: Too many sections: %d (>= %d)"), - abfd, bfd_count_sections (abfd), SHN_LORESERVE & 0xffff); - 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; - - /* Check indirect symbol. */ - while (h->root.type == bfd_link_hash_indirect) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - 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 == NULL - || (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; - size_t symcount; - size_t extsymcount; - size_t 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 = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); - if (extversym == NULL) - goto error_ret; - - if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0 - || (bfd_bread (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 - && !(h->def_regular - && h->forced_local)) - { - /* If we have a non-hidden versioned sym, then it should - have provided a definition for the undefined sym unless - it is defined in a non-shared object and forced local. - */ - 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; -} - -/* Convert ELF common symbol TYPE. */ - -static int -elf_link_convert_common_type (struct bfd_link_info *info, int type) -{ - /* Commom symbol can only appear in relocatable link. */ - if (!bfd_link_relocatable (info)) - abort (); - switch (info->elf_stt_common) - { - case unchanged: - break; - case elf_stt_common: - type = STT_COMMON; - break; - case no_elf_stt_common: - type = STT_OBJECT; - break; - } - return type; -} - -/* 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 bfd_hash_entry *bh, void *data) -{ - struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh; - struct elf_outext_info *eoinfo = (struct elf_outext_info *) data; - struct elf_final_link_info *flinfo = eoinfo->flinfo; - bfd_boolean strip; - Elf_Internal_Sym sym; - asection *input_sec; - const struct elf_backend_data *bed; - long indx; - int ret; - unsigned int type; - - 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 (flinfo->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 unless - they are in unreferenced sections which are removed by garbage - collection). */ - 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 - && h->ref_dynamic - && (!h->ref_regular || flinfo->info->gc_sections) - && !elf_link_check_versioned_symbol (flinfo->info, bed, h) - && flinfo->info->unresolved_syms_in_shared_libs != RM_IGNORE) - (*flinfo->info->callbacks->undefined_symbol) - (flinfo->info, h->root.root.string, - h->ref_regular ? NULL : h->root.u.undef.abfd, - NULL, 0, - flinfo->info->unresolved_syms_in_shared_libs == RM_GENERATE_ERROR); - - /* Strip a global symbol defined in a discarded section. */ - if (h->indx == -3) - return TRUE; - } - - /* We should also warn if a forced local symbol is referenced from - shared libraries. */ - if (bfd_link_executable (flinfo->info) - && h->forced_local - && h->ref_dynamic - && h->def_regular - && !h->dynamic_def - && h->ref_dynamic_nonweak - && !elf_link_check_versioned_symbol (flinfo->info, bed, h)) - { - bfd *def_bfd; - const char *msg; - struct elf_link_hash_entry *hi = h; - - /* Check indirect symbol. */ - while (hi->root.type == bfd_link_hash_indirect) - hi = (struct elf_link_hash_entry *) hi->root.u.i.link; - - if (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL) - /* xgettext:c-format */ - msg = _("%B: internal symbol `%s' in %B is referenced by DSO"); - else if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) - /* xgettext:c-format */ - msg = _("%B: hidden symbol `%s' in %B is referenced by DSO"); - else - /* xgettext:c-format */ - msg = _("%B: local symbol `%s' in %B is referenced by DSO"); - def_bfd = flinfo->output_bfd; - if (hi->root.u.def.section != bfd_abs_section_ptr) - def_bfd = hi->root.u.def.section->owner; - _bfd_error_handler (msg, flinfo->output_bfd, - h->root.root.string, def_bfd); - bfd_set_error (bfd_error_bad_value); - 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. */ - strip = FALSE; - if (h->indx == -2) - ; - 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 (flinfo->info->strip == strip_all) - strip = TRUE; - else if (flinfo->info->strip == strip_some - && bfd_hash_lookup (flinfo->info->keep_hash, - h->root.root.string, FALSE, FALSE) == NULL) - strip = TRUE; - else if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && ((flinfo->info->strip_discarded - && discarded_section (h->root.u.def.section)) - || ((h->root.u.def.section->flags & SEC_LINKER_CREATED) == 0 - && h->root.u.def.section->owner != NULL - && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0))) - strip = TRUE; - else if ((h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - && h->root.u.undef.abfd != NULL - && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0) - strip = TRUE; - - type = h->type; - - /* If we're stripping it, and it's not a dynamic symbol, there's - nothing else to do. However, if it is a forced local symbol or - an ifunc symbol we need to give the backend finish_dynamic_symbol - function a chance to make it dynamic. */ - if (strip - && h->dynindx == -1 - && type != STT_GNU_IFUNC - && !h->forced_local) - return TRUE; - - sym.st_value = 0; - sym.st_size = h->size; - sym.st_other = h->other; - 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 (flinfo->output_bfd, - input_sec->output_section); - if (sym.st_shndx == SHN_BAD) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: could not find output section %A for input section %A"), - flinfo->output_bfd, input_sec->output_section, input_sec); - bfd_set_error (bfd_error_nonrepresentable_section); - 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 (!bfd_link_relocatable (flinfo->info)) - { - sym.st_value += input_sec->output_section->vma; - if (h->type == STT_TLS) - { - asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec; - if (tls_sec != NULL) - sym.st_value -= 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; - } - - if (type == STT_COMMON || type == STT_OBJECT) - switch (h->root.type) - { - case bfd_link_hash_common: - type = elf_link_convert_common_type (flinfo->info, type); - break; - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - if (bed->common_definition (&sym)) - type = elf_link_convert_common_type (flinfo->info, type); - else - type = STT_OBJECT; - break; - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - break; - default: - abort (); - } - - if (h->forced_local) - { - sym.st_info = ELF_ST_INFO (STB_LOCAL, type); - /* Turn off visibility on local symbol. */ - sym.st_other &= ~ELF_ST_VISIBILITY (-1); - } - /* Set STB_GNU_UNIQUE only if symbol is defined in regular object. */ - else if (h->unique_global && h->def_regular) - sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, 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, type); - else - sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); - sym.st_target_internal = h->target_internal; - - /* 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. - STT_GNU_IFUNC symbol must go through PLT. */ - if ((h->type == STT_GNU_IFUNC - && h->def_regular - && !bfd_link_relocatable (flinfo->info)) - || ((h->dynindx != -1 - || h->forced_local) - && ((bfd_link_pic (flinfo->info) - && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - || !h->forced_local) - && elf_hash_table (flinfo->info)->dynamic_sections_created)) - { - if (! ((*bed->elf_backend_finish_dynamic_symbol) - (flinfo->output_bfd, flinfo->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; - type = ELF_ST_TYPE (sym.st_info); - - /* Turn an undefined IFUNC symbol into a normal FUNC symbol. */ - if (type == STT_GNU_IFUNC) - type = STT_FUNC; - - if (h->ref_regular_nonweak) - bindtype = STB_GLOBAL; - else - bindtype = STB_WEAK; - sym.st_info = ELF_ST_INFO (bindtype, type); - } - - /* If this is a symbol defined in a dynamic library, don't use the - symbol size from the dynamic library. Relinking an executable - against a new library may introduce gratuitous changes in the - executable's symbols if we keep the size. */ - if (sym.st_shndx == SHN_UNDEF - && !h->def_regular - && h->def_dynamic) - sym.st_size = 0; - - /* If a non-weak symbol with non-default visibility is not defined - locally, it is a fatal error. */ - if (!bfd_link_relocatable (flinfo->info) - && 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) - { - const char *msg; - - if (ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED) - /* xgettext:c-format */ - msg = _("%B: protected symbol `%s' isn't defined"); - else if (ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL) - /* xgettext:c-format */ - msg = _("%B: internal symbol `%s' isn't defined"); - else - /* xgettext:c-format */ - msg = _("%B: hidden symbol `%s' isn't defined"); - _bfd_error_handler (msg, flinfo->output_bfd, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - 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 (elf_hash_table (flinfo->info)->dynsym != NULL - && h->dynindx != -1 - && elf_hash_table (flinfo->info)->dynamic_sections_created) - { - bfd_byte *esym; - - /* Since there is no version information in the dynamic string, - if there is no version info in symbol version section, we will - have a run-time problem if not linking executable, referenced - by shared library, or not bound locally. */ - if (h->verinfo.verdef == NULL - && (!bfd_link_executable (flinfo->info) - || h->ref_dynamic - || !h->def_regular)) - { - char *p = strrchr (h->root.root.string, ELF_VER_CHR); - - if (p && p [1] != '\0') - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: No symbol version section for versioned symbol `%s'"), - flinfo->output_bfd, h->root.root.string); - eoinfo->failed = TRUE; - return FALSE; - } - } - - sym.st_name = h->dynstr_index; - esym = (elf_hash_table (flinfo->info)->dynsym->contents - + h->dynindx * bed->s->sizeof_sym); - if (!check_dynsym (flinfo->output_bfd, &sym)) - { - eoinfo->failed = TRUE; - return FALSE; - } - bed->s->swap_symbol_out (flinfo->output_bfd, &sym, esym, 0); - - if (flinfo->hash_sec != NULL) - { - size_t hash_entry_size; - bfd_byte *bucketpos; - bfd_vma chain; - size_t bucketcount; - size_t bucket; - - bucketcount = elf_hash_table (flinfo->info)->bucketcount; - bucket = h->u.elf_hash_value % bucketcount; - - hash_entry_size - = elf_section_data (flinfo->hash_sec)->this_hdr.sh_entsize; - bucketpos = ((bfd_byte *) flinfo->hash_sec->contents - + (bucket + 2) * hash_entry_size); - chain = bfd_get (8 * hash_entry_size, flinfo->output_bfd, bucketpos); - bfd_put (8 * hash_entry_size, flinfo->output_bfd, h->dynindx, - bucketpos); - bfd_put (8 * hash_entry_size, flinfo->output_bfd, chain, - ((bfd_byte *) flinfo->hash_sec->contents - + (bucketcount + 2 + h->dynindx) * hash_entry_size)); - } - - if (flinfo->symver_sec != NULL && flinfo->symver_sec->contents != NULL) - { - Elf_Internal_Versym iversym; - Elf_External_Versym *eversym; - - if (!h->def_regular) - { - if (h->verinfo.verdef == NULL - || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd) - & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED))) - iversym.vs_vers = 0; - else - iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; - } - else - { - if (h->verinfo.vertree == NULL) - iversym.vs_vers = 1; - else - iversym.vs_vers = h->verinfo.vertree->vernum + 1; - if (flinfo->info->create_default_symver) - iversym.vs_vers++; - } - - /* Turn on VERSYM_HIDDEN only if the hidden versioned symbol is - defined locally. */ - if (h->versioned == versioned_hidden && h->def_regular) - iversym.vs_vers |= VERSYM_HIDDEN; - - eversym = (Elf_External_Versym *) flinfo->symver_sec->contents; - eversym += h->dynindx; - _bfd_elf_swap_versym_out (flinfo->output_bfd, &iversym, eversym); - } - } - - /* If the symbol is undefined, and we didn't output it to .dynsym, - strip it from .symtab too. Obviously we can't do this for - relocatable output or when needed for --emit-relocs. */ - else if (input_sec == bfd_und_section_ptr - && h->indx != -2 - /* PR 22319 Do not strip global undefined symbols marked as being needed. */ - && (h->mark != 1 || ELF_ST_BIND (sym.st_info) != STB_GLOBAL) - && !bfd_link_relocatable (flinfo->info)) - return TRUE; - - /* Also strip others that we couldn't earlier due to dynamic symbol - processing. */ - if (strip) - return TRUE; - if ((input_sec->flags & SEC_EXCLUDE) != 0) - return TRUE; - - /* Output a FILE symbol so that following locals are not associated - with the wrong input file. We need one for forced local symbols - if we've seen more than one FILE symbol or when we have exactly - one FILE symbol but global symbols are present in a file other - than the one with the FILE symbol. We also need one if linker - defined symbols are present. In practice these conditions are - always met, so just emit the FILE symbol unconditionally. */ - if (eoinfo->localsyms - && !eoinfo->file_sym_done - && eoinfo->flinfo->filesym_count != 0) - { - Elf_Internal_Sym fsym; - - memset (&fsym, 0, sizeof (fsym)); - fsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); - fsym.st_shndx = SHN_ABS; - if (!elf_link_output_symstrtab (eoinfo->flinfo, NULL, &fsym, - bfd_und_section_ptr, NULL)) - return FALSE; - - eoinfo->file_sym_done = TRUE; - } - - indx = bfd_get_symcount (flinfo->output_bfd); - ret = elf_link_output_symstrtab (flinfo, h->root.root.string, &sym, - input_sec, h); - if (ret == 0) - { - eoinfo->failed = TRUE; - return FALSE; - } - else if (ret == 1) - h->indx = indx; - else if (h->indx == -2) - abort(); - - 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 SEC_INFO_TYPE_STABS: - case SEC_INFO_TYPE_EH_FRAME: - case SEC_INFO_TYPE_EH_FRAME_ENTRY: - 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, - struct bfd_link_info *info) -{ - asection *first = elf_next_in_group (group); - asection *s = first; - - while (s != NULL) - { - if (bfd_elf_match_symbols_in_sections (s, sec, info)) - 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, struct bfd_link_info *info) -{ - asection *kept; - - kept = sec->kept_section; - if (kept != NULL) - { - if ((kept->flags & SEC_GROUP) != 0) - kept = match_group_member (sec, kept, info); - if (kept != NULL - && ((sec->rawsize != 0 ? sec->rawsize : sec->size) - != (kept->rawsize != 0 ? kept->rawsize : kept->size))) - kept = NULL; - sec->kept_section = kept; - } - 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 *flinfo, bfd *input_bfd) -{ - int (*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; - struct elf_link_hash_entry **sym_hashes; - bfd_size_type address_size; - bfd_vma r_type_mask; - int r_sym_shift; - bfd_boolean have_file_sym = FALSE; - - output_bfd = flinfo->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; - - 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, - flinfo->internal_syms, - flinfo->external_syms, - flinfo->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 = flinfo->indices, ppsection = flinfo->sections; - isym < isymend; - isym++, pindex++, ppsection++) - { - asection *isec; - const char *name; - Elf_Internal_Sym osym; - long indx; - int ret; - - *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_ABS) - isec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - isec = bfd_com_section_ptr; - else - { - isec = bfd_section_from_elf_index (input_bfd, isym->st_shndx); - if (isec == NULL) - { - /* Don't attempt to output symbols with st_shnx in the - reserved range other than SHN_ABS and SHN_COMMON. */ - *ppsection = NULL; - continue; - } - else if (isec->sec_info_type == SEC_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); - } - - *ppsection = isec; - - /* Don't output the first, undefined, symbol. In fact, don't - output any undefined local symbol. */ - if (isec == bfd_und_section_ptr) - continue; - - if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) - { - /* 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 (flinfo->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 (flinfo->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 - && 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 ((flinfo->info->strip == strip_some - && (bfd_hash_lookup (flinfo->info->keep_hash, name, FALSE, FALSE) - == NULL)) - || (((flinfo->info->discard == discard_sec_merge - && (isec->flags & SEC_MERGE) - && !bfd_link_relocatable (flinfo->info)) - || flinfo->info->discard == discard_l) - && bfd_is_local_label_name (input_bfd, name))) - continue; - - if (ELF_ST_TYPE (isym->st_info) == STT_FILE) - { - if (input_bfd->lto_output) - /* -flto puts a temp file name here. This means builds - are not reproducible. Discard the symbol. */ - continue; - have_file_sym = TRUE; - flinfo->filesym_count += 1; - } - if (!have_file_sym) - { - /* In the absence of debug info, bfd_find_nearest_line uses - FILE symbols to determine the source file for local - function symbols. Provide a FILE symbol here if input - files lack such, so that their symbols won't be - associated with a previous input file. It's not the - source file, but the best we can do. */ - have_file_sym = TRUE; - flinfo->filesym_count += 1; - memset (&osym, 0, sizeof (osym)); - osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); - osym.st_shndx = SHN_ABS; - if (!elf_link_output_symstrtab (flinfo, - (input_bfd->lto_output ? NULL - : input_bfd->filename), - &osym, bfd_abs_section_ptr, - NULL)) - return FALSE; - } - - 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; - - /* 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 (!bfd_link_relocatable (flinfo->info)) - { - 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 (flinfo->info)->tls_sec != NULL); - osym.st_value -= elf_hash_table (flinfo->info)->tls_sec->vma; - } - } - - indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_symstrtab (flinfo, name, &osym, isec, NULL); - if (ret == 0) - return FALSE; - else if (ret == 1) - *pindex = indx; - } - - if (bed->s->arch_size == 32) - { - r_type_mask = 0xff; - r_sym_shift = 8; - address_size = 4; - } - else - { - r_type_mask = 0xffffffff; - r_sym_shift = 32; - address_size = 8; - } - - /* 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 (!flinfo->info->resolve_section_groups - && (o->flags & (SEC_LINKER_CREATED | SEC_GROUP)) == SEC_GROUP) - { - /* Deal with the group signature symbol. */ - struct bfd_elf_section_data *sec_data = elf_section_data (o); - unsigned long symndx = sec_data->this_hdr.sh_info; - asection *osec = o->output_section; - - BFD_ASSERT (bfd_link_relocatable (flinfo->info)); - if (symndx >= locsymcount - || (elf_bad_symtab (input_bfd) - && flinfo->sections[symndx] == NULL)) - { - struct elf_link_hash_entry *h = sym_hashes[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; - /* Arrange for symbol to be output. */ - h->indx = -2; - elf_section_data (osec)->this_hdr.sh_info = -2; - } - else if (ELF_ST_TYPE (isymbuf[symndx].st_info) == STT_SECTION) - { - /* We'll use the output section target_index. */ - asection *sec = flinfo->sections[symndx]->output_section; - elf_section_data (osec)->this_hdr.sh_info = sec->target_index; - } - else - { - if (flinfo->indices[symndx] == -1) - { - /* Otherwise output the local symbol now. */ - Elf_Internal_Sym sym = isymbuf[symndx]; - asection *sec = flinfo->sections[symndx]->output_section; - const char *name; - long indx; - int ret; - - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym.st_name); - if (name == NULL) - return FALSE; - - sym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, - sec); - if (sym.st_shndx == SHN_BAD) - return FALSE; - - sym.st_value += o->output_offset; - - indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_symstrtab (flinfo, name, &sym, o, - NULL); - if (ret == 0) - return FALSE; - else if (ret == 1) - flinfo->indices[symndx] = indx; - else - abort (); - } - elf_section_data (osec)->this_hdr.sh_info - = flinfo->indices[symndx]; - } - } - - 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; - if (bed->caches_rawsize - && o->rawsize != 0 - && o->rawsize < o->size) - { - memcpy (flinfo->contents, contents, o->rawsize); - contents = flinfo->contents; - } - } - else - { - contents = flinfo->contents; - if (! bfd_get_full_section_contents (input_bfd, o, &contents)) - return FALSE; - } - - if ((o->flags & SEC_RELOC) != 0) - { - Elf_Internal_Rela *internal_relocs; - Elf_Internal_Rela *rel, *relend; - int action_discarded; - int ret; - - /* Get the swapped relocs. */ - internal_relocs - = _bfd_elf_link_read_relocs (input_bfd, o, flinfo->external_relocs, - flinfo->internal_relocs, FALSE); - if (internal_relocs == NULL - && o->reloc_count > 0) - return FALSE; - - /* We need to reverse-copy input .ctors/.dtors sections if - they are placed in .init_array/.finit_array for output. */ - if (o->size > address_size - && ((strncmp (o->name, ".ctors", 6) == 0 - && strcmp (o->output_section->name, - ".init_array") == 0) - || (strncmp (o->name, ".dtors", 6) == 0 - && strcmp (o->output_section->name, - ".fini_array") == 0)) - && (o->name[6] == 0 || o->name[6] == '.')) - { - if (o->size * bed->s->int_rels_per_ext_rel - != o->reloc_count * address_size) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B: size of section %A is not " - "multiple of address size"), - input_bfd, o); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - o->flags |= SEC_ELF_REVERSE_COPY; - } - - action_discarded = -1; - if (!elf_section_ignore_discarded_relocs (o)) - action_discarded = (*bed->action_discarded) (o); - - /* Run through the relocs evaluating complex reloc symbols and - looking for relocs against symbols from discarded sections - or section symbols from removed link-once sections. - Complain about relocs against discarded sections. Zero - relocs against removed link-once sections. */ - - rel = internal_relocs; - relend = rel + o->reloc_count; - for ( ; rel < relend; rel++) - { - unsigned long r_symndx = rel->r_info >> r_sym_shift; - unsigned int s_type; - 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) - && flinfo->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) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("error: %B contains a reloc (%#Lx) for section %A " - "that references a non-existent global symbol"), - input_bfd, rel->r_info, o); - 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; - - s_type = h->type; - - /* If a plugin symbol is referenced from a non-IR file, - mark the symbol as undefined. Note that the - linker may attach linker created dynamic sections - to the plugin bfd. Symbols defined in linker - created sections are not plugin symbols. */ - if ((h->root.non_ir_ref_regular - || h->root.non_ir_ref_dynamic) - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && (h->root.u.def.section->flags - & SEC_LINKER_CREATED) == 0 - && h->root.u.def.section->owner != NULL - && (h->root.u.def.section->owner->flags - & BFD_PLUGIN) != 0) - { - h->root.type = bfd_link_hash_undefined; - h->root.u.undef.abfd = h->root.u.def.section->owner; - } - - ps = NULL; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - ps = &h->root.u.def.section; - - sym_name = h->root.root.string; - } - else - { - Elf_Internal_Sym *sym = isymbuf + r_symndx; - - s_type = ELF_ST_TYPE (sym->st_info); - ps = &flinfo->sections[r_symndx]; - sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, - sym, *ps); - } - - if ((s_type == STT_RELC || s_type == STT_SRELC) - && !bfd_link_relocatable (flinfo->info)) - { - bfd_vma val; - bfd_vma dot = (rel->r_offset - + o->output_offset + o->output_section->vma); -#ifdef DEBUG - printf ("Encountered a complex symbol!"); - printf (" (input_bfd %s, section %s, reloc %ld\n", - input_bfd->filename, o->name, - (long) (rel - internal_relocs)); - printf (" symbol: idx %8.8lx, name %s\n", - r_symndx, sym_name); - printf (" reloc : info %8.8lx, addr %8.8lx\n", - (unsigned long) rel->r_info, - (unsigned long) rel->r_offset); -#endif - if (!eval_symbol (&val, &sym_name, input_bfd, flinfo, dot, - isymbuf, locsymcount, s_type == STT_SRELC)) - return FALSE; - - /* Symbol evaluated OK. Update to absolute value. */ - set_symbol_value (input_bfd, isymbuf, locsymcount, - r_symndx, val); - continue; - } - - if (action_discarded != -1 && ps != NULL) - { - /* Complain if the definition comes from a - discarded section. */ - if ((sec = *ps) != NULL && discarded_section (sec)) - { - BFD_ASSERT (r_symndx != STN_UNDEF); - if (action_discarded & COMPLAIN) - (*flinfo->info->callbacks->einfo) - /* xgettext:c-format */ - (_("%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_discarded & PRETEND) - { - asection *kept; - - kept = _bfd_elf_check_kept_section (sec, - flinfo->info); - if (kept != NULL) - { - *ps = kept; - continue; - } - } - } - } - } - - /* 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. */ - - ret = (*relocate_section) (output_bfd, flinfo->info, - input_bfd, o, contents, - internal_relocs, - isymbuf, - flinfo->sections); - if (!ret) - return FALSE; - - if (ret == 2 - || bfd_link_relocatable (flinfo->info) - || flinfo->info->emitrelocations) - { - Elf_Internal_Rela *irela; - Elf_Internal_Rela *irelaend, *irelamid; - bfd_vma last_offset; - struct elf_link_hash_entry **rel_hash; - struct elf_link_hash_entry **rel_hash_list, **rela_hash_list; - Elf_Internal_Shdr *input_rel_hdr, *input_rela_hdr; - unsigned int next_erel; - bfd_boolean rela_normal; - struct bfd_elf_section_data *esdi, *esdo; - - esdi = elf_section_data (o); - esdo = elf_section_data (o->output_section); - rela_normal = FALSE; - - /* Adjust the reloc addresses and symbol indices. */ - - irela = internal_relocs; - irelaend = irela + o->reloc_count; - rel_hash = esdo->rel.hashes + esdo->rel.count; - /* We start processing the REL relocs, if any. When we reach - IRELAMID in the loop, we switch to the RELA relocs. */ - irelamid = irela; - if (esdi->rel.hdr != NULL) - irelamid += (NUM_SHDR_ENTRIES (esdi->rel.hdr) - * bed->s->int_rels_per_ext_rel); - rel_hash_list = rel_hash; - rela_hash_list = NULL; - last_offset = o->output_offset; - if (!bfd_link_relocatable (flinfo->info)) - 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; - } - - if (irela == irelamid) - { - rel_hash = esdo->rela.hashes + esdo->rela.count; - rela_hash_list = rel_hash; - rela_normal = bed->rela_normal; - } - - irela->r_offset = _bfd_elf_section_offset (output_bfd, - flinfo->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 - bfd_elf_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 (!bfd_link_relocatable (flinfo->info)) - 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) - && flinfo->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 = flinfo->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 = STN_UNDEF; - 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 SEC_MERGE sections, use - the kept section. relocate_section should - have already handled discarded linkonce - sections. */ - 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; - if (r_symndx == STN_UNDEF) - { - irela->r_addend += osec->vma; - osec = _bfd_nearby_section (output_bfd, osec, - osec->vma); - irela->r_addend -= osec->vma; - r_symndx = osec->target_index; - } - } - } - - /* 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 (flinfo->indices[r_symndx] == -1) - { - unsigned long shlink; - const char *name; - asection *osec; - long indx; - - if (flinfo->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 (!bfd_link_relocatable (flinfo->info)) - { - 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 (flinfo->info) - ->tls_sec != NULL); - sym.st_value -= (elf_hash_table (flinfo->info) - ->tls_sec->vma); - } - } - - indx = bfd_get_symcount (output_bfd); - ret = elf_link_output_symstrtab (flinfo, name, - &sym, sec, - NULL); - if (ret == 0) - return FALSE; - else if (ret == 1) - flinfo->indices[r_symndx] = indx; - else - abort (); - } - - r_symndx = flinfo->indices[r_symndx]; - } - - irela->r_info = ((bfd_vma) r_symndx << r_sym_shift - | (irela->r_info & r_type_mask)); - } - - /* Swap out the relocs. */ - input_rel_hdr = esdi->rel.hdr; - if (input_rel_hdr && input_rel_hdr->sh_size != 0) - { - if (!bed->elf_backend_emit_relocs (output_bfd, o, - input_rel_hdr, - internal_relocs, - rel_hash_list)) - return FALSE; - internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr) - * bed->s->int_rels_per_ext_rel); - rel_hash_list += NUM_SHDR_ENTRIES (input_rel_hdr); - } - - input_rela_hdr = esdi->rela.hdr; - if (input_rela_hdr && input_rela_hdr->sh_size != 0) - { - if (!bed->elf_backend_emit_relocs (output_bfd, o, - input_rela_hdr, - internal_relocs, - rela_hash_list)) - return FALSE; - } - } - } - - /* Write out the modified section contents. */ - if (bed->elf_backend_write_section - && (*bed->elf_backend_write_section) (output_bfd, flinfo->info, o, - contents)) - { - /* Section written out. */ - } - else switch (o->sec_info_type) - { - case SEC_INFO_TYPE_STABS: - if (! (_bfd_write_section_stabs - (output_bfd, - &elf_hash_table (flinfo->info)->stab_info, - o, &elf_section_data (o)->sec_info, contents))) - return FALSE; - break; - case SEC_INFO_TYPE_MERGE: - if (! _bfd_write_merged_section (output_bfd, o, - elf_section_data (o)->sec_info)) - return FALSE; - break; - case SEC_INFO_TYPE_EH_FRAME: - { - if (! _bfd_elf_write_section_eh_frame (output_bfd, flinfo->info, - o, contents)) - return FALSE; - } - break; - case SEC_INFO_TYPE_EH_FRAME_ENTRY: - { - if (! _bfd_elf_write_section_eh_frame_entry (output_bfd, - flinfo->info, - o, contents)) - return FALSE; - } - break; - default: - { - if (! (o->flags & SEC_EXCLUDE)) - { - file_ptr offset = (file_ptr) o->output_offset; - bfd_size_type todo = o->size; - - offset *= bfd_octets_per_byte (output_bfd); - - if ((o->flags & SEC_ELF_REVERSE_COPY)) - { - /* Reverse-copy input section to output. */ - do - { - todo -= address_size; - if (! bfd_set_section_contents (output_bfd, - o->output_section, - contents + todo, - offset, - address_size)) - return FALSE; - if (todo == 0) - break; - offset += address_size; - } - while (1); - } - else if (! bfd_set_section_contents (output_bfd, - o->output_section, - contents, - offset, todo)) - 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 bfd_elf_section_reloc_data *reldata; - 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; - struct bfd_elf_section_data *esdo = elf_section_data (output_section); - - 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; - - if (esdo->rel.hdr) - reldata = &esdo->rel; - else if (esdo->rela.hdr) - reldata = &esdo->rela; - else - { - reldata = NULL; - BFD_ASSERT (0); - } - - /* Figure out the symbol index. */ - rel_hash_ptr = reldata->hashes + reldata->count; - 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 - { - (*info->callbacks->unattached_reloc) - (info, link_order->u.reloc.p->u.name, NULL, NULL, 0); - 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_size_type) bfd_get_reloc_size (howto); - buf = (bfd_byte *) bfd_zmalloc (size); - if (buf == NULL && size != 0) - 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; - (*info->callbacks->reloc_overflow) (info, NULL, sym_name, - howto->name, addend, NULL, NULL, - (bfd_vma) 0); - break; - } - - ok = bfd_set_section_contents (output_bfd, output_section, buf, - link_order->offset - * bfd_octets_per_byte (output_bfd), - 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 (! bfd_link_relocatable (info)) - 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 = reldata->hdr; - erel = rel_hdr->contents; - if (rel_hdr->sh_type == SHT_REL) - { - erel += reldata->count * bed->s->sizeof_rel; - (*bed->s->swap_reloc_out) (output_bfd, irel, erel); - } - else - { - irel[0].r_addend = addend; - erel += reldata->count * bed->s->sizeof_rela; - (*bed->s->swap_reloca_out) (output_bfd, irel, erel); - } - - ++reldata->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 - /* xgettext:c-format */ - (_("%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 - && elf_elfsections (sub)[elfsec]->sh_link < elf_numsections (sub)) - { - 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 - /* xgettext:c-format */ - (_("%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 **) - bfd_malloc (seen_linkorder * sizeof (struct bfd_link_order *)); - if (sections == NULL) - return FALSE; - 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) 0 << s->alignment_power; - s->output_offset = offset / bfd_octets_per_byte (abfd); - sections[n]->offset = offset; - offset += sections[n]->size; - } - - free (sections); - return TRUE; -} - -/* Generate an import library in INFO->implib_bfd from symbols in ABFD. - Returns TRUE upon success, FALSE otherwise. */ - -static bfd_boolean -elf_output_implib (bfd *abfd, struct bfd_link_info *info) -{ - bfd_boolean ret = FALSE; - bfd *implib_bfd; - const struct elf_backend_data *bed; - flagword flags; - enum bfd_architecture arch; - unsigned int mach; - asymbol **sympp = NULL; - long symsize; - long symcount; - long src_count; - elf_symbol_type *osymbuf; - - implib_bfd = info->out_implib_bfd; - bed = get_elf_backend_data (abfd); - - if (!bfd_set_format (implib_bfd, bfd_object)) - return FALSE; - - /* Use flag from executable but make it a relocatable object. */ - flags = bfd_get_file_flags (abfd); - flags &= ~HAS_RELOC; - if (!bfd_set_start_address (implib_bfd, 0) - || !bfd_set_file_flags (implib_bfd, flags & ~EXEC_P)) - return FALSE; - - /* Copy architecture of output file to import library file. */ - arch = bfd_get_arch (abfd); - mach = bfd_get_mach (abfd); - if (!bfd_set_arch_mach (implib_bfd, arch, mach) - && (abfd->target_defaulted - || bfd_get_arch (abfd) != bfd_get_arch (implib_bfd))) - return FALSE; - - /* Get symbol table size. */ - symsize = bfd_get_symtab_upper_bound (abfd); - if (symsize < 0) - return FALSE; - - /* Read in the symbol table. */ - sympp = (asymbol **) xmalloc (symsize); - symcount = bfd_canonicalize_symtab (abfd, sympp); - if (symcount < 0) - goto free_sym_buf; - - /* Allow the BFD backend to copy any private header data it - understands from the output BFD to the import library BFD. */ - if (! bfd_copy_private_header_data (abfd, implib_bfd)) - goto free_sym_buf; - - /* Filter symbols to appear in the import library. */ - if (bed->elf_backend_filter_implib_symbols) - symcount = bed->elf_backend_filter_implib_symbols (abfd, info, sympp, - symcount); - else - symcount = _bfd_elf_filter_global_symbols (abfd, info, sympp, symcount); - if (symcount == 0) - { - bfd_set_error (bfd_error_no_symbols); - _bfd_error_handler (_("%B: no symbol found for import library"), - implib_bfd); - goto free_sym_buf; - } - - - /* Make symbols absolute. */ - osymbuf = (elf_symbol_type *) bfd_alloc2 (implib_bfd, symcount, - sizeof (*osymbuf)); - for (src_count = 0; src_count < symcount; src_count++) - { - memcpy (&osymbuf[src_count], (elf_symbol_type *) sympp[src_count], - sizeof (*osymbuf)); - osymbuf[src_count].symbol.section = bfd_abs_section_ptr; - osymbuf[src_count].internal_elf_sym.st_shndx = SHN_ABS; - osymbuf[src_count].symbol.value += sympp[src_count]->section->vma; - osymbuf[src_count].internal_elf_sym.st_value = - osymbuf[src_count].symbol.value; - sympp[src_count] = &osymbuf[src_count].symbol; - } - - bfd_set_symtab (implib_bfd, sympp, symcount); - - /* Allow the BFD backend to copy any private data it understands - from the output BFD to the import library BFD. This is done last - to permit the routine to look at the filtered symbol table. */ - if (! bfd_copy_private_bfd_data (abfd, implib_bfd)) - goto free_sym_buf; - - if (!bfd_close (implib_bfd)) - goto free_sym_buf; - - ret = TRUE; - -free_sym_buf: - free (sympp); - return ret; -} - -static void -elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo) -{ - asection *o; - - if (flinfo->symstrtab != NULL) - _bfd_elf_strtab_free (flinfo->symstrtab); - if (flinfo->contents != NULL) - free (flinfo->contents); - if (flinfo->external_relocs != NULL) - free (flinfo->external_relocs); - if (flinfo->internal_relocs != NULL) - free (flinfo->internal_relocs); - if (flinfo->external_syms != NULL) - free (flinfo->external_syms); - if (flinfo->locsym_shndx != NULL) - free (flinfo->locsym_shndx); - if (flinfo->internal_syms != NULL) - free (flinfo->internal_syms); - if (flinfo->indices != NULL) - free (flinfo->indices); - if (flinfo->sections != NULL) - free (flinfo->sections); - if (flinfo->symshndxbuf != NULL) - free (flinfo->symshndxbuf); - for (o = obfd->sections; o != NULL; o = o->next) - { - struct bfd_elf_section_data *esdo = elf_section_data (o); - if ((o->flags & SEC_RELOC) != 0 && esdo->rel.hashes != NULL) - free (esdo->rel.hashes); - if ((o->flags & SEC_RELOC) != 0 && esdo->rela.hashes != NULL) - free (esdo->rela.hashes); - } -} - -/* 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 flinfo; - asection *o; - struct bfd_link_order *p; - 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; - Elf_Internal_Sym elfsym; - unsigned int i; - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Shdr *symtab_shndx_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; - asection *attr_section = NULL; - bfd_vma attr_size = 0; - const char *std_attrs_section; - struct elf_link_hash_table *htab = elf_hash_table (info); - - if (!is_elf_hash_table (htab)) - return FALSE; - - if (bfd_link_pic (info)) - abfd->flags |= DYNAMIC; - - dynamic = htab->dynamic_sections_created; - dynobj = htab->dynobj; - - emit_relocs = (bfd_link_relocatable (info) - || info->emitrelocations); - - flinfo.info = info; - flinfo.output_bfd = abfd; - flinfo.symstrtab = _bfd_elf_strtab_init (); - if (flinfo.symstrtab == NULL) - return FALSE; - - if (! dynamic) - { - flinfo.hash_sec = NULL; - flinfo.symver_sec = NULL; - } - else - { - flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash"); - /* Note that dynsym_sec can be NULL (on VMS). */ - flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version"); - /* Note that it is OK if symver_sec is NULL. */ - } - - flinfo.contents = NULL; - flinfo.external_relocs = NULL; - flinfo.internal_relocs = NULL; - flinfo.external_syms = NULL; - flinfo.locsym_shndx = NULL; - flinfo.internal_syms = NULL; - flinfo.indices = NULL; - flinfo.sections = NULL; - flinfo.symshndxbuf = NULL; - flinfo.filesym_count = 0; - - /* The object attributes have been merged. Remove the input - sections from the link, and set the contents of the output - secton. */ - std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section; - for (o = abfd->sections; o != NULL; o = o->next) - { - if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0) - || strcmp (o->name, ".gnu.attributes") == 0) - { - for (p = o->map_head.link_order; p != NULL; p = p->next) - { - asection *input_section; - - if (p->type != bfd_indirect_link_order) - continue; - input_section = p->u.indirect.section; - /* Hack: reset the SEC_HAS_CONTENTS flag so that - elf_link_input_bfd ignores this section. */ - input_section->flags &= ~SEC_HAS_CONTENTS; - } - - attr_size = bfd_elf_obj_attr_size (abfd); - if (attr_size) - { - bfd_set_section_size (abfd, o, attr_size); - attr_section = o; - /* Skip this section later on. */ - o->map_head.link_order = NULL; - } - else - o->flags |= SEC_EXCLUDE; - } - } - - /* 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; - unsigned int additional_reloc_count = 0; - struct bfd_elf_section_data *esdi = NULL; - - 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; - - /* 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 (sec->rawsize > max_contents_size) - max_contents_size = sec->rawsize; - if (sec->size > max_contents_size) - max_contents_size = sec->size; - - if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour - && (sec->owner->flags & DYNAMIC) == 0) - { - size_t sym_count; - - /* We are interested in just local symbols, not all - symbols. */ - 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_list (sec->owner) != NULL) - max_sym_shndx_count = sym_count; - - if (esdo->this_hdr.sh_type == SHT_REL - || esdo->this_hdr.sh_type == SHT_RELA) - /* Some backends use reloc_count in relocation sections - to count particular types of relocs. Of course, - reloc sections themselves can't have relocations. */ - ; - else if (emit_relocs) - { - reloc_count = sec->reloc_count; - if (bed->elf_backend_count_additional_relocs) - { - int c; - c = (*bed->elf_backend_count_additional_relocs) (sec); - additional_reloc_count += c; - } - } - else if (bed->elf_backend_count_relocs) - reloc_count = (*bed->elf_backend_count_relocs) (info, sec); - - esdi = elf_section_data (sec); - - if ((sec->flags & SEC_RELOC) != 0) - { - size_t ext_size = 0; - - if (esdi->rel.hdr != NULL) - ext_size = esdi->rel.hdr->sh_size; - if (esdi->rela.hdr != NULL) - ext_size += esdi->rela.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; - - reloc_count += additional_reloc_count; - o->reloc_count += reloc_count; - - if (p->type == bfd_indirect_link_order && emit_relocs) - { - if (esdi->rel.hdr) - { - esdo->rel.count += NUM_SHDR_ENTRIES (esdi->rel.hdr); - esdo->rel.count += additional_reloc_count; - } - if (esdi->rela.hdr) - { - esdo->rela.count += NUM_SHDR_ENTRIES (esdi->rela.hdr); - esdo->rela.count += additional_reloc_count; - } - } - else - { - if (o->use_rela_p) - esdo->rela.count += reloc_count; - else - esdo->rel.count += 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 (! bfd_link_relocatable (info) && merged) - elf_link_hash_traverse (htab, _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 || emit_relocs; - 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) - { - struct bfd_elf_section_data *esdo = elf_section_data (o); - if ((o->flags & SEC_RELOC) != 0) - { - if (esdo->rel.hdr - && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rel))) - goto error_return; - - if (esdo->rela.hdr - && !(_bfd_elf_link_size_reloc_section (abfd, &esdo->rela))) - goto error_return; - } - - /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them - to count upwards while actually outputting the relocations. */ - esdo->rel.count = 0; - esdo->rela.count = 0; - - if (esdo->this_hdr.sh_offset == (file_ptr) -1) - { - /* Cache the section contents so that they can be compressed - later. Use bfd_malloc since it will be freed by - bfd_compress_section_contents. */ - unsigned char *contents = esdo->this_hdr.contents; - if ((o->flags & SEC_ELF_COMPRESS) == 0 || contents != NULL) - abort (); - contents - = (unsigned char *) bfd_malloc (esdo->this_hdr.sh_size); - if (contents == NULL) - goto error_return; - esdo->this_hdr.contents = contents; - } - } - - /* We have now assigned file positions for all the sections except - .symtab, .strtab, and non-loaded reloc sections. We start the - .symtab section at the current file position, and write directly - to it. We build the .strtab section in memory. */ - bfd_get_symcount (abfd) = 0; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - /* sh_name is set in prep_headers. */ - 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 = (bfd_vma) 1 << bed->s->log_file_align; - - if (max_sym_count < 20) - max_sym_count = 20; - htab->strtabsize = max_sym_count; - amt = max_sym_count * sizeof (struct elf_sym_strtab); - htab->strtab = (struct elf_sym_strtab *) bfd_malloc (amt); - if (htab->strtab == NULL) - goto error_return; - /* The real buffer will be allocated in elf_link_swap_symbols_out. */ - flinfo.symshndxbuf - = (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF) - ? (Elf_External_Sym_Shndx *) -1 : NULL); - - if (info->strip != strip_all || emit_relocs) - { - file_ptr off = elf_next_file_pos (abfd); - - _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); - - /* Note that at this point elf_next_file_pos (abfd) is - incorrect. We do not yet know the size of the .symtab section. - We correct next_file_pos below, after we do know the size. */ - - /* Start writing out the symbol table. The first symbol is always a - dummy symbol. */ - elfsym.st_value = 0; - elfsym.st_size = 0; - elfsym.st_info = 0; - elfsym.st_other = 0; - elfsym.st_shndx = SHN_UNDEF; - elfsym.st_target_internal = 0; - if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, - bfd_und_section_ptr, NULL) != 1) - goto error_return; - - /* Output a symbol for each section. We output these even if we are - discarding local symbols, since they are used for relocs. These - symbols have no names. We store the index of each one in the - index field of the section, so that we can find it again when - outputting relocs. */ - - elfsym.st_size = 0; - elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); - elfsym.st_other = 0; - elfsym.st_value = 0; - elfsym.st_target_internal = 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 (!bfd_link_relocatable (info)) - elfsym.st_value = o->vma; - if (elf_link_output_symstrtab (&flinfo, NULL, &elfsym, o, - NULL) != 1) - goto error_return; - } - } - } - - /* Allocate some memory to hold information read in from the input - files. */ - if (max_contents_size != 0) - { - flinfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); - if (flinfo.contents == NULL) - goto error_return; - } - - if (max_external_reloc_size != 0) - { - flinfo.external_relocs = bfd_malloc (max_external_reloc_size); - if (flinfo.external_relocs == NULL) - goto error_return; - } - - if (max_internal_reloc_count != 0) - { - amt = max_internal_reloc_count * sizeof (Elf_Internal_Rela); - flinfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); - if (flinfo.internal_relocs == NULL) - goto error_return; - } - - if (max_sym_count != 0) - { - amt = max_sym_count * bed->s->sizeof_sym; - flinfo.external_syms = (bfd_byte *) bfd_malloc (amt); - if (flinfo.external_syms == NULL) - goto error_return; - - amt = max_sym_count * sizeof (Elf_Internal_Sym); - flinfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); - if (flinfo.internal_syms == NULL) - goto error_return; - - amt = max_sym_count * sizeof (long); - flinfo.indices = (long int *) bfd_malloc (amt); - if (flinfo.indices == NULL) - goto error_return; - - amt = max_sym_count * sizeof (asection *); - flinfo.sections = (asection **) bfd_malloc (amt); - if (flinfo.sections == NULL) - goto error_return; - } - - if (max_sym_shndx_count != 0) - { - amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx); - flinfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); - if (flinfo.locsym_shndx == NULL) - goto error_return; - } - - if (htab->tls_sec) - { - bfd_vma base, end = 0; - asection *sec; - - for (sec = htab->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 *ord = sec->map_tail.link_order; - - if (ord != NULL) - size = ord->offset + ord->size; - } - end = sec->vma + size; - } - base = htab->tls_sec->vma; - /* Only align end of TLS section if static TLS doesn't have special - alignment requirements. */ - if (bed->static_tls_alignment == 1) - end = align_power (end, htab->tls_sec->alignment_power); - htab->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; - } - - if (!_bfd_elf_fixup_eh_frame_hdr (info)) - return FALSE; - - /* Since ELF permits relocations to be against local symbols, we - must have the local symbols available when we do the relocations. - Since we would rather only read the local symbols once, and we - 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 (&flinfo, 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)) - { - if (p->type == bfd_indirect_link_order - && (bfd_get_flavour (sub) - == bfd_target_elf_flavour) - && (elf_elfheader (sub)->e_ident[EI_CLASS] - != bed->s->elfclass)) - { - const char *iclass, *oclass; - - switch (bed->s->elfclass) - { - case ELFCLASS64: oclass = "ELFCLASS64"; break; - case ELFCLASS32: oclass = "ELFCLASS32"; break; - case ELFCLASSNONE: oclass = "ELFCLASSNONE"; break; - default: abort (); - } - - switch (elf_elfheader (sub)->e_ident[EI_CLASS]) - { - case ELFCLASS64: iclass = "ELFCLASS64"; break; - case ELFCLASS32: iclass = "ELFCLASS32"; break; - case ELFCLASSNONE: iclass = "ELFCLASSNONE"; break; - default: abort (); - } - - bfd_set_error (bfd_error_wrong_format); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: file class %s incompatible with %s"), - sub, iclass, oclass); - } - - goto error_return; - } - } - } - } - - /* Free symbol buffer if needed. */ - if (!info->reduce_memory_overheads) - { - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - if (bfd_get_flavour (sub) == bfd_target_elf_flavour - && elf_tdata (sub)->symbuf) - { - free (elf_tdata (sub)->symbuf); - elf_tdata (sub)->symbuf = NULL; - } - } - - /* 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.flinfo = &flinfo; - eoinfo.localsyms = TRUE; - eoinfo.file_sym_done = FALSE; - bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); - if (eoinfo.failed) - return FALSE; - - /* If backend needs to output some local symbols not present in the hash - table, do it now. */ - if (bed->elf_backend_output_arch_local_syms - && (info->strip != strip_all || emit_relocs)) - { - typedef int (*out_sym_func) - (void *, const char *, Elf_Internal_Sym *, asection *, - struct elf_link_hash_entry *); - - if (! ((*bed->elf_backend_output_arch_local_syms) - (abfd, info, &flinfo, - (out_sym_func) elf_link_output_symstrtab))) - 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 - && htab->dynsym != NULL - && htab->dynsym->output_section != bfd_abs_section_ptr) - { - Elf_Internal_Sym sym; - bfd_byte *dynsym = htab->dynsym->contents; - - o = htab->dynsym->output_section; - elf_section_data (o)->this_hdr.sh_info = htab->local_dynsymcount + 1; - - /* Write out the section symbols for the output sections. */ - if (bfd_link_pic (info) - || htab->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; - sym.st_target_internal = 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; - bed->s->swap_symbol_out (abfd, &sym, dest, 0); - } - } - - /* Write out the local dynsyms. */ - if (htab->dynlocal) - { - struct elf_link_local_dynamic_entry *e; - for (e = htab->dynlocal; e ; e = e->next) - { - asection *s; - bfd_byte *dest; - - /* Copy the internal symbol and turn off visibility. - Note that we saved a word of storage and overwrote - the original st_name with the dynstr_index. */ - sym = e->isym; - sym.st_other &= ~ELF_ST_VISIBILITY (-1); - - s = bfd_section_from_elf_index (e->input_bfd, - e->isym.st_shndx); - if (s != NULL) - { - 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); - } - - dest = dynsym + e->dynindx * bed->s->sizeof_sym; - bed->s->swap_symbol_out (abfd, &sym, dest, 0); - } - } - } - - /* We get the global symbols from the hash table. */ - eoinfo.failed = FALSE; - eoinfo.localsyms = FALSE; - eoinfo.flinfo = &flinfo; - bfd_hash_traverse (&info->hash->table, 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 - && (info->strip != strip_all || emit_relocs)) - { - typedef int (*out_sym_func) - (void *, const char *, Elf_Internal_Sym *, asection *, - struct elf_link_hash_entry *); - - if (! ((*bed->elf_backend_output_arch_syms) - (abfd, info, &flinfo, - (out_sym_func) elf_link_output_symstrtab))) - return FALSE; - } - - /* Finalize the .strtab section. */ - _bfd_elf_strtab_finalize (flinfo.symstrtab); - - /* Swap out the .strtab section. */ - if (!elf_link_swap_symbols_out (&flinfo)) - return FALSE; - - /* Now we know the size of the symtab section. */ - if (bfd_get_symcount (abfd) > 0) - { - /* Finish up and write out the symbol string table (.strtab) - section. */ - Elf_Internal_Shdr *symstrtab_hdr = NULL; - file_ptr off = symtab_hdr->sh_offset + symtab_hdr->sh_size; - - if (elf_symtab_shndx_list (abfd)) - { - symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; - - if (symtab_shndx_hdr != NULL && 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 (flinfo.symshndxbuf, amt, abfd) != amt)) - return FALSE; - } - } - - symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; - /* sh_name was set in prep_headers. */ - symstrtab_hdr->sh_type = SHT_STRTAB; - symstrtab_hdr->sh_flags = bed->elf_strtab_flags; - symstrtab_hdr->sh_addr = 0; - symstrtab_hdr->sh_size = _bfd_elf_strtab_size (flinfo.symstrtab); - symstrtab_hdr->sh_entsize = 0; - symstrtab_hdr->sh_link = 0; - symstrtab_hdr->sh_info = 0; - /* sh_offset is set just below. */ - symstrtab_hdr->sh_addralign = 1; - - off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, - off, TRUE); - elf_next_file_pos (abfd) = off; - - if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 - || ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab)) - return FALSE; - } - - if (info->out_implib_bfd && !elf_output_implib (abfd, info)) - { - _bfd_error_handler (_("%B: failed to generate import library"), - info->out_implib_bfd); - return FALSE; - } - - /* Adjust the relocs to have the correct symbol indices. */ - for (o = abfd->sections; o != NULL; o = o->next) - { - struct bfd_elf_section_data *esdo = elf_section_data (o); - bfd_boolean sort; - - if ((o->flags & SEC_RELOC) == 0) - continue; - - sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o); - if (esdo->rel.hdr != NULL - && !elf_link_adjust_relocs (abfd, o, &esdo->rel, sort, info)) - return FALSE; - if (esdo->rela.hdr != NULL - && !elf_link_adjust_relocs (abfd, o, &esdo->rela, sort, info)) - return FALSE; - - /* 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_linker_section (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; - bfd_size_type sh_size; - bfd_vma sh_addr; - - 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 (htab, 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_ptr = h->root.u.def.value; - o = h->root.u.def.section; - if (o->output_section != NULL) - dyn.d_un.d_ptr += (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_ptr = 0; - } - break; - } - } - continue; - - case DT_PREINIT_ARRAYSZ: - name = ".preinit_array"; - goto get_out_size; - case DT_INIT_ARRAYSZ: - name = ".init_array"; - goto get_out_size; - case DT_FINI_ARRAYSZ: - name = ".fini_array"; - get_out_size: - o = bfd_get_section_by_name (abfd, name); - if (o == NULL) - { - _bfd_error_handler - (_("could not find section %s"), 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_out_vma; - case DT_INIT_ARRAY: - name = ".init_array"; - goto get_out_vma; - case DT_FINI_ARRAY: - name = ".fini_array"; - get_out_vma: - o = bfd_get_section_by_name (abfd, name); - goto do_vma; - - case DT_HASH: - name = ".hash"; - goto get_vma; - case DT_GNU_HASH: - name = ".gnu.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_linker_section (dynobj, name); - do_vma: - if (o == NULL || bfd_is_abs_section (o->output_section)) - { - _bfd_error_handler - (_("could not find section %s"), name); - goto error_return; - } - if (elf_section_data (o->output_section)->this_hdr.sh_type == SHT_NOTE) - { - _bfd_error_handler - (_("warning: section '%s' is being made into a note"), name); - bfd_set_error (bfd_error_nonrepresentable_section); - goto error_return; - } - dyn.d_un.d_ptr = o->output_section->vma + o->output_offset; - 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; - sh_size = 0; - sh_addr = 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) - { - sh_size += hdr->sh_size; - if (sh_addr == 0 - || sh_addr > hdr->sh_addr) - sh_addr = hdr->sh_addr; - } - } - - if (bed->dtrel_excludes_plt && htab->srelplt != NULL) - { - /* Don't count procedure linkage table relocs in the - overall reloc count. */ - sh_size -= htab->srelplt->size; - if (sh_size == 0) - /* If the size is zero, make the address zero too. - This is to avoid a glibc bug. If the backend - emits DT_RELA/DT_RELASZ even when DT_RELASZ is - zero, then we'll put DT_RELA at the end of - DT_JMPREL. glibc will interpret the end of - DT_RELA matching the end of DT_JMPREL as the - case where DT_RELA includes DT_JMPREL, and for - LD_BIND_NOW will decide that processing DT_RELA - will process the PLT relocs too. Net result: - No PLT relocs applied. */ - sh_addr = 0; - - /* If .rela.plt is the first .rela section, exclude - it from DT_RELA. */ - else if (sh_addr == (htab->srelplt->output_section->vma - + htab->srelplt->output_offset)) - sh_addr += htab->srelplt->size; - } - - if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) - dyn.d_un.d_val = sh_size; - else - dyn.d_un.d_ptr = 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 && bfd_link_pic (info)) - || info->error_textrel) - && (o = bfd_get_linker_section (dynobj, ".dynamic")) != NULL) - { - bfd_byte *dyncon, *dynconend; - - 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) - { - if (info->error_textrel) - info->callbacks->einfo - (_("%P%X: read-only segment has dynamic relocations.\n")); - else - info->callbacks->einfo - (_("%P: warning: creating a DT_TEXTREL in a shared object.\n")); - 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 (htab->stab_info.stabstr == o) - continue; - if (htab->eh_info.hdr_sec == o) - continue; - if (strcmp (o->name, ".dynstr") != 0) - { - if (! bfd_set_section_contents (abfd, o->output_section, - o->contents, - (file_ptr) o->output_offset - * bfd_octets_per_byte (abfd), - o->size)) - goto error_return; - } - else - { - /* The contents of the .dynstr section are actually in a - stringtab. */ - file_ptr off; - - off = elf_section_data (o->output_section)->this_hdr.sh_offset; - if (bfd_seek (abfd, off, SEEK_SET) != 0 - || !_bfd_elf_strtab_emit (abfd, htab->dynstr)) - goto error_return; - } - } - } - - if (!info->resolve_section_groups) - { - bfd_boolean failed = FALSE; - - BFD_ASSERT (bfd_link_relocatable (info)); - 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 (htab->stab_info.stabstr != NULL) - { - if (!_bfd_write_stab_strings (abfd, &htab->stab_info)) - goto error_return; - } - - if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info)) - goto error_return; - - elf_final_link_free (abfd, &flinfo); - - elf_linker (abfd) = TRUE; - - if (attr_section) - { - bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size); - if (contents == NULL) - return FALSE; /* Bail out and fail. */ - bfd_elf_set_obj_attr_contents (abfd, contents, attr_size); - bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size); - free (contents); - } - - return TRUE; - - error_return: - elf_final_link_free (abfd, &flinfo); - return FALSE; -} - -/* Initialize COOKIE for input bfd ABFD. */ - -static bfd_boolean -init_reloc_cookie (struct elf_reloc_cookie *cookie, - struct bfd_link_info *info, bfd *abfd) -{ - Elf_Internal_Shdr *symtab_hdr; - const struct elf_backend_data *bed; - - bed = get_elf_backend_data (abfd); - 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) - { - info->callbacks->einfo (_("%P%X: can not read symbols: %E\n")); - return FALSE; - } - if (info->keep_memory) - symtab_hdr->contents = (bfd_byte *) cookie->locsyms; - } - return TRUE; -} - -/* Free the memory allocated by init_reloc_cookie, if appropriate. */ - -static void -fini_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd) -{ - Elf_Internal_Shdr *symtab_hdr; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - if (cookie->locsyms != NULL - && symtab_hdr->contents != (unsigned char *) cookie->locsyms) - free (cookie->locsyms); -} - -/* Initialize the relocation information in COOKIE for input section SEC - of input bfd ABFD. */ - -static bfd_boolean -init_reloc_cookie_rels (struct elf_reloc_cookie *cookie, - struct bfd_link_info *info, bfd *abfd, - asection *sec) -{ - if (sec->reloc_count == 0) - { - cookie->rels = NULL; - cookie->relend = NULL; - } - else - { - cookie->rels = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, - info->keep_memory); - if (cookie->rels == NULL) - return FALSE; - cookie->rel = cookie->rels; - cookie->relend = cookie->rels + sec->reloc_count; - } - cookie->rel = cookie->rels; - return TRUE; -} - -/* Free the memory allocated by init_reloc_cookie_rels, - if appropriate. */ - -static void -fini_reloc_cookie_rels (struct elf_reloc_cookie *cookie, - asection *sec) -{ - if (cookie->rels && elf_section_data (sec)->relocs != cookie->rels) - free (cookie->rels); -} - -/* Initialize the whole of COOKIE for input section SEC. */ - -static bfd_boolean -init_reloc_cookie_for_section (struct elf_reloc_cookie *cookie, - struct bfd_link_info *info, - asection *sec) -{ - if (!init_reloc_cookie (cookie, info, sec->owner)) - goto error1; - if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) - goto error2; - return TRUE; - - error2: - fini_reloc_cookie (cookie, sec->owner); - error1: - return FALSE; -} - -/* Free the memory allocated by init_reloc_cookie_for_section, - if appropriate. */ - -static void -fini_reloc_cookie_for_section (struct elf_reloc_cookie *cookie, - asection *sec) -{ - fini_reloc_cookie_rels (cookie, sec); - fini_reloc_cookie (cookie, sec->owner); -} - -/* Garbage collect unused sections. */ - -/* Default gc_mark_hook. */ - -asection * -_bfd_elf_gc_mark_hook (asection *sec, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Rela *rel ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym) -{ - if (h != NULL) - { - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - return h->root.u.def.section; - - case bfd_link_hash_common: - return h->root.u.c.p->section; - - default: - break; - } - } - else - return bfd_section_from_elf_index (sec->owner, sym->st_shndx); - - return NULL; -} - -/* Return the global debug definition section. */ - -static asection * -elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - Elf_Internal_Rela *rel ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h, - Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) -{ - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && (h->root.u.def.section->flags & SEC_DEBUGGING) != 0) - return h->root.u.def.section; - - return NULL; -} - -/* COOKIE->rel describes a relocation against section SEC, which is - a section we've decided to keep. Return the section that contains - the relocation symbol, or NULL if no section contains it. */ - -asection * -_bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, - elf_gc_mark_hook_fn gc_mark_hook, - struct elf_reloc_cookie *cookie, - bfd_boolean *start_stop) -{ - unsigned long r_symndx; - struct elf_link_hash_entry *h; - - r_symndx = cookie->rel->r_info >> cookie->r_sym_shift; - if (r_symndx == STN_UNDEF) - return NULL; - - if (r_symndx >= cookie->locsymcount - || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) - { - h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; - if (h == NULL) - { - info->callbacks->einfo (_("%F%P: corrupt input: %B\n"), - sec->owner); - return NULL; - } - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - h->mark = 1; - /* If this symbol is weak and there is a non-weak definition, we - keep the non-weak definition because many backends put - dynamic reloc info on the non-weak definition for code - handling copy relocs. */ - if (h->is_weakalias) - weakdef (h)->mark = 1; - - if (start_stop != NULL) - { - /* To work around a glibc bug, mark XXX input sections - when there is a reference to __start_XXX or __stop_XXX - symbols. */ - if (h->start_stop) - { - asection *s = h->u2.start_stop_section; - *start_stop = !s->gc_mark; - return s; - } - } - - return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); - } - - return (*gc_mark_hook) (sec, info, cookie->rel, NULL, - &cookie->locsyms[r_symndx]); -} - -/* COOKIE->rel describes a relocation against section SEC, which is - a section we've decided to keep. Mark the section that contains - the relocation symbol. */ - -bfd_boolean -_bfd_elf_gc_mark_reloc (struct bfd_link_info *info, - asection *sec, - elf_gc_mark_hook_fn gc_mark_hook, - struct elf_reloc_cookie *cookie) -{ - asection *rsec; - bfd_boolean start_stop = FALSE; - - rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie, &start_stop); - while (rsec != NULL) - { - if (!rsec->gc_mark) - { - if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour - || (rsec->owner->flags & DYNAMIC) != 0) - rsec->gc_mark = 1; - else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) - return FALSE; - } - if (!start_stop) - break; - rsec = bfd_get_next_section_by_name (rsec->owner, rsec); - } - return TRUE; -} - -/* The mark phase of garbage collection. For a given section, mark - it and any sections in this section's group, and all the sections - which define symbols to which it refers. */ - -bfd_boolean -_bfd_elf_gc_mark (struct bfd_link_info *info, - asection *sec, - elf_gc_mark_hook_fn gc_mark_hook) -{ - bfd_boolean ret; - asection *group_sec, *eh_frame; - - 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; - eh_frame = elf_eh_frame_section (sec->owner); - if ((sec->flags & SEC_RELOC) != 0 - && sec->reloc_count > 0 - && sec != eh_frame) - { - struct elf_reloc_cookie cookie; - - if (!init_reloc_cookie_for_section (&cookie, info, sec)) - ret = FALSE; - else - { - for (; cookie.rel < cookie.relend; cookie.rel++) - if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) - { - ret = FALSE; - break; - } - fini_reloc_cookie_for_section (&cookie, sec); - } - } - - if (ret && eh_frame && elf_fde_list (sec)) - { - struct elf_reloc_cookie cookie; - - if (!init_reloc_cookie_for_section (&cookie, info, eh_frame)) - ret = FALSE; - else - { - if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame, - gc_mark_hook, &cookie)) - ret = FALSE; - fini_reloc_cookie_for_section (&cookie, eh_frame); - } - } - - eh_frame = elf_section_eh_frame_entry (sec); - if (ret && eh_frame && !eh_frame->gc_mark) - if (!_bfd_elf_gc_mark (info, eh_frame, gc_mark_hook)) - ret = FALSE; - - return ret; -} - -/* Scan and mark sections in a special or debug section group. */ - -static void -_bfd_elf_gc_mark_debug_special_section_group (asection *grp) -{ - /* Point to first section of section group. */ - asection *ssec; - /* Used to iterate the section group. */ - asection *msec; - - bfd_boolean is_special_grp = TRUE; - bfd_boolean is_debug_grp = TRUE; - - /* First scan to see if group contains any section other than debug - and special section. */ - ssec = msec = elf_next_in_group (grp); - do - { - if ((msec->flags & SEC_DEBUGGING) == 0) - is_debug_grp = FALSE; - - if ((msec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) != 0) - is_special_grp = FALSE; - - msec = elf_next_in_group (msec); - } - while (msec != ssec); - - /* If this is a pure debug section group or pure special section group, - keep all sections in this group. */ - if (is_debug_grp || is_special_grp) - { - do - { - msec->gc_mark = 1; - msec = elf_next_in_group (msec); - } - while (msec != ssec); - } -} - -/* Keep debug and special sections. */ - -bfd_boolean -_bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, - elf_gc_mark_hook_fn mark_hook ATTRIBUTE_UNUSED) -{ - bfd *ibfd; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *isec; - bfd_boolean some_kept; - bfd_boolean debug_frag_seen; - bfd_boolean has_kept_debug_info; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - isec = ibfd->sections; - if (isec == NULL || isec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - /* Ensure all linker created sections are kept, - see if any other section is already marked, - and note if we have any fragmented debug sections. */ - debug_frag_seen = some_kept = has_kept_debug_info = FALSE; - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - { - if ((isec->flags & SEC_LINKER_CREATED) != 0) - isec->gc_mark = 1; - else if (isec->gc_mark - && (isec->flags & SEC_ALLOC) != 0 - && elf_section_type (isec) != SHT_NOTE) - some_kept = TRUE; - - if (!debug_frag_seen - && (isec->flags & SEC_DEBUGGING) - && CONST_STRNEQ (isec->name, ".debug_line.")) - debug_frag_seen = TRUE; - } - - /* If no non-note alloc section in this file will be kept, then - we can toss out the debug and special sections. */ - if (!some_kept) - continue; - - /* Keep debug and special sections like .comment when they are - not part of a group. Also keep section groups that contain - just debug sections or special sections. */ - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - { - if ((isec->flags & SEC_GROUP) != 0) - _bfd_elf_gc_mark_debug_special_section_group (isec); - else if (((isec->flags & SEC_DEBUGGING) != 0 - || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) - && elf_next_in_group (isec) == NULL) - isec->gc_mark = 1; - if (isec->gc_mark && (isec->flags & SEC_DEBUGGING) != 0) - has_kept_debug_info = TRUE; - } - - /* Look for CODE sections which are going to be discarded, - and find and discard any fragmented debug sections which - are associated with that code section. */ - if (debug_frag_seen) - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - if ((isec->flags & SEC_CODE) != 0 - && isec->gc_mark == 0) - { - unsigned int ilen; - asection *dsec; - - ilen = strlen (isec->name); - - /* Association is determined by the name of the debug - section containing the name of the code section as - a suffix. For example .debug_line.text.foo is a - debug section associated with .text.foo. */ - for (dsec = ibfd->sections; dsec != NULL; dsec = dsec->next) - { - unsigned int dlen; - - if (dsec->gc_mark == 0 - || (dsec->flags & SEC_DEBUGGING) == 0) - continue; - - dlen = strlen (dsec->name); - - if (dlen > ilen - && strncmp (dsec->name + (dlen - ilen), - isec->name, ilen) == 0) - dsec->gc_mark = 0; - } - } - - /* Mark debug sections referenced by kept debug sections. */ - if (has_kept_debug_info) - for (isec = ibfd->sections; isec != NULL; isec = isec->next) - if (isec->gc_mark - && (isec->flags & SEC_DEBUGGING) != 0) - if (!_bfd_elf_gc_mark (info, isec, - elf_gc_mark_debug_section)) - return FALSE; - } - return TRUE; -} - -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); - - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - asection *o; - - if (bfd_get_flavour (sub) != bfd_target_elf_flavour - || elf_object_id (sub) != elf_hash_table_id (elf_hash_table (info)) - || !(*bed->relocs_compatible) (sub->xvec, abfd->xvec)) - continue; - o = sub->sections; - if (o == NULL || o->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - for (o = sub->sections; o != NULL; o = o->next) - { - /* When any section in a section group is kept, we keep all - sections in the section group. If the first member of - the section group is excluded, we will also exclude the - group section. */ - if (o->flags & SEC_GROUP) - { - asection *first = elf_next_in_group (o); - o->gc_mark = first->gc_mark; - } - - if (o->gc_mark) - continue; - - /* Skip sweeping sections already excluded. */ - if (o->flags & SEC_EXCLUDE) - continue; - - /* Since this is early in the link process, it is simple - to remove a section from the output. */ - o->flags |= SEC_EXCLUDE; - - if (info->print_gc_sections && o->size != 0) - /* xgettext:c-format */ - _bfd_error_handler (_("Removing unused section '%A' in file '%B'"), - o, sub); - } - } - - 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) -{ - /* Those that are not vtables. */ - if (h->start_stop - || h->u2.vtable == NULL - || h->u2.vtable->parent == NULL) - return TRUE; - - /* Those vtables that do not have parents, we cannot merge. */ - if (h->u2.vtable->parent == (struct elf_link_hash_entry *) -1) - return TRUE; - - /* If we've already been done, exit. */ - if (h->u2.vtable->used && h->u2.vtable->used[-1]) - return TRUE; - - /* Make sure the parent's table is up to date. */ - elf_gc_propagate_vtable_entries_used (h->u2.vtable->parent, okp); - - if (h->u2.vtable->used == NULL) - { - /* None of this table's entries were referenced. Re-use the - parent's table. */ - h->u2.vtable->used = h->u2.vtable->parent->u2.vtable->used; - h->u2.vtable->size = h->u2.vtable->parent->u2.vtable->size; - } - else - { - size_t n; - bfd_boolean *cu, *pu; - - /* Or the parent's entries into ours. */ - cu = h->u2.vtable->used; - cu[-1] = TRUE; - pu = h->u2.vtable->parent->u2.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->u2.vtable->parent->u2.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; - - /* Take care of both those symbols that do not describe vtables as - well as those that are not loaded. */ - if (h->start_stop - || h->u2.vtable == NULL - || h->u2.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; - - 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->u2.vtable->used - && (rel->r_offset - hstart) < h->u2.vtable->size) - { - bfd_vma entry = (rel->r_offset - hstart) >> log_file_align; - if (h->u2.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; - struct bfd_elf_dynamic_list *d = info->dynamic_list; - - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && ((h->ref_dynamic && !h->forced_local) - || ((h->def_regular || ELF_COMMON_DEF_P (h)) - && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL - && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN - && (!bfd_link_executable (info) - || info->gc_keep_exported - || info->export_dynamic - || (h->dynamic - && d != NULL - && (*d->match) (&d->head, NULL, h->root.root.string))) - && (h->versioned >= versioned - || !bfd_hide_sym_by_version (info->version_info, - h->root.root.string))))) - h->root.u.def.section->flags |= SEC_KEEP; - - return TRUE; -} - -/* Keep all sections containing symbols undefined on the command-line, - and the section containing the entry symbol. */ - -void -_bfd_elf_gc_keep (struct bfd_link_info *info) -{ - struct bfd_sym_chain *sym; - - for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) - { - struct elf_link_hash_entry *h; - - h = elf_link_hash_lookup (elf_hash_table (info), sym->name, - FALSE, FALSE, FALSE); - - if (h != NULL - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && !bfd_is_abs_section (h->root.u.def.section) - && !bfd_is_und_section (h->root.u.def.section)) - h->root.u.def.section->flags |= SEC_KEEP; - } -} - -bfd_boolean -bfd_elf_parse_eh_frame_entries (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - bfd *ibfd = info->input_bfds; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) - { - asection *sec; - struct elf_reloc_cookie cookie; - - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) - continue; - sec = ibfd->sections; - if (sec == NULL || sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - if (!init_reloc_cookie (&cookie, info, ibfd)) - return FALSE; - - for (sec = ibfd->sections; sec; sec = sec->next) - { - if (CONST_STRNEQ (bfd_section_name (ibfd, sec), ".eh_frame_entry") - && init_reloc_cookie_rels (&cookie, info, ibfd, sec)) - { - _bfd_elf_parse_eh_frame_entry (info, sec, &cookie); - fini_reloc_cookie_rels (&cookie, sec); - } - } - } - return TRUE; -} - -/* Do mark and sweep of unused sections. */ - -bfd_boolean -bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info) -{ - bfd_boolean ok = TRUE; - bfd *sub; - elf_gc_mark_hook_fn gc_mark_hook; - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_link_hash_table *htab; - - if (!bed->can_gc_sections - || !is_elf_hash_table (info->hash)) - { - _bfd_error_handler(_("Warning: gc-sections option ignored")); - return TRUE; - } - - bed->gc_keep (info); - htab = elf_hash_table (info); - - /* Try to parse each bfd's .eh_frame section. Point elf_eh_frame_section - at the .eh_frame section if we can mark the FDEs individually. */ - for (sub = info->input_bfds; - info->eh_frame_hdr_type != COMPACT_EH_HDR && sub != NULL; - sub = sub->link.next) - { - asection *sec; - struct elf_reloc_cookie cookie; - - sec = sub->sections; - if (sec == NULL || sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - sec = bfd_get_section_by_name (sub, ".eh_frame"); - while (sec && init_reloc_cookie_for_section (&cookie, info, sec)) - { - _bfd_elf_parse_eh_frame (sub, info, sec, &cookie); - if (elf_section_data (sec)->sec_info - && (sec->flags & SEC_LINKER_CREATED) == 0) - elf_eh_frame_section (sub) = sec; - fini_reloc_cookie_for_section (&cookie, sec); - sec = bfd_get_next_section_by_name (NULL, sec); - } - } - - /* Apply transitive closure to the vtable entry usage info. */ - elf_link_hash_traverse (htab, elf_gc_propagate_vtable_entries_used, &ok); - if (!ok) - return FALSE; - - /* Kill the vtable relocations that were not used. */ - elf_link_hash_traverse (htab, elf_gc_smash_unused_vtentry_relocs, &ok); - if (!ok) - return FALSE; - - /* Mark dynamically referenced symbols. */ - if (htab->dynamic_sections_created || info->gc_keep_exported) - elf_link_hash_traverse (htab, bed->gc_mark_dynamic_ref, info); - - /* Grovel through relocs to find out who stays ... */ - gc_mark_hook = bed->gc_mark_hook; - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - asection *o; - - if (bfd_get_flavour (sub) != bfd_target_elf_flavour - || elf_object_id (sub) != elf_hash_table_id (htab) - || !(*bed->relocs_compatible) (sub->xvec, abfd->xvec)) - continue; - - o = sub->sections; - if (o == NULL || o->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - /* Start at sections marked with SEC_KEEP (ref _bfd_elf_gc_keep). - Also treat note sections as a root, if the section is not part - of a group. We must keep all PREINIT_ARRAY, INIT_ARRAY as - well as FINI_ARRAY sections for ld -r. */ - for (o = sub->sections; o != NULL; o = o->next) - if (!o->gc_mark - && (o->flags & SEC_EXCLUDE) == 0 - && ((o->flags & SEC_KEEP) != 0 - || (bfd_link_relocatable (info) - && ((elf_section_data (o)->this_hdr.sh_type - == SHT_PREINIT_ARRAY) - || (elf_section_data (o)->this_hdr.sh_type - == SHT_INIT_ARRAY) - || (elf_section_data (o)->this_hdr.sh_type - == SHT_FINI_ARRAY))) - || (elf_section_data (o)->this_hdr.sh_type == SHT_NOTE - && elf_next_in_group (o) == NULL ))) - { - if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) - return FALSE; - } - } - - /* Allow the backend to mark additional target specific sections. */ - bed->gc_mark_extra_sections (info, gc_mark_hook); - - /* ... 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; - size_t 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; - } - - /* xgettext:c-format */ - _bfd_error_handler (_("%B: %A+%#Lx: No symbol found for INHERIT"), - abfd, sec, offset); - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - - win: - if (!child->u2.vtable) - { - child->u2.vtable = ((struct elf_link_virtual_table_entry *) - bfd_zalloc (abfd, sizeof (*child->u2.vtable))); - if (!child->u2.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->u2.vtable->parent = (struct elf_link_hash_entry *) -1; - } - else - child->u2.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->u2.vtable) - { - h->u2.vtable = ((struct elf_link_virtual_table_entry *) - bfd_zalloc (abfd, sizeof (*h->u2.vtable))); - if (!h->u2.vtable) - return FALSE; - } - - if (addend >= h->u2.vtable->size) - { - size_t size, bytes, file_align; - bfd_boolean *ptr = h->u2.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_boolean *) bfd_realloc (ptr - 1, bytes); - - if (ptr != NULL) - { - size_t oldbytes; - - oldbytes = (((h->u2.vtable->size >> log_file_align) + 1) - * sizeof (bfd_boolean)); - memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes); - } - } - else - ptr = (bfd_boolean *) bfd_zmalloc (bytes); - - if (ptr == NULL) - return FALSE; - - /* And arrange for that done flag to be at index -1. */ - h->u2.vtable->used = ptr + 1; - h->u2.vtable->size = size; - } - - h->u2.vtable->used[addend >> log_file_align] = TRUE; - - return TRUE; -} - -/* Map an ELF section header flag to its corresponding string. */ -typedef struct -{ - char *flag_name; - flagword flag_value; -} elf_flags_to_name_table; - -static elf_flags_to_name_table elf_flags_to_names [] = -{ - { "SHF_WRITE", SHF_WRITE }, - { "SHF_ALLOC", SHF_ALLOC }, - { "SHF_EXECINSTR", SHF_EXECINSTR }, - { "SHF_MERGE", SHF_MERGE }, - { "SHF_STRINGS", SHF_STRINGS }, - { "SHF_INFO_LINK", SHF_INFO_LINK}, - { "SHF_LINK_ORDER", SHF_LINK_ORDER}, - { "SHF_OS_NONCONFORMING", SHF_OS_NONCONFORMING}, - { "SHF_GROUP", SHF_GROUP }, - { "SHF_TLS", SHF_TLS }, - { "SHF_MASKOS", SHF_MASKOS }, - { "SHF_EXCLUDE", SHF_EXCLUDE }, -}; - -/* Returns TRUE if the section is to be included, otherwise FALSE. */ -bfd_boolean -bfd_elf_lookup_section_flags (struct bfd_link_info *info, - struct flag_info *flaginfo, - asection *section) -{ - const bfd_vma sh_flags = elf_section_flags (section); - - if (!flaginfo->flags_initialized) - { - bfd *obfd = info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (obfd); - struct flag_info_list *tf = flaginfo->flag_list; - int with_hex = 0; - int without_hex = 0; - - for (tf = flaginfo->flag_list; tf != NULL; tf = tf->next) - { - unsigned i; - flagword (*lookup) (char *); - - lookup = bed->elf_backend_lookup_section_flags_hook; - if (lookup != NULL) - { - flagword hexval = (*lookup) ((char *) tf->name); - - if (hexval != 0) - { - if (tf->with == with_flags) - with_hex |= hexval; - else if (tf->with == without_flags) - without_hex |= hexval; - tf->valid = TRUE; - continue; - } - } - for (i = 0; i < ARRAY_SIZE (elf_flags_to_names); ++i) - { - if (strcmp (tf->name, elf_flags_to_names[i].flag_name) == 0) - { - if (tf->with == with_flags) - with_hex |= elf_flags_to_names[i].flag_value; - else if (tf->with == without_flags) - without_hex |= elf_flags_to_names[i].flag_value; - tf->valid = TRUE; - break; - } - } - if (!tf->valid) - { - info->callbacks->einfo - (_("Unrecognized INPUT_SECTION_FLAG %s\n"), tf->name); - return FALSE; - } - } - flaginfo->flags_initialized = TRUE; - flaginfo->only_with_flags |= with_hex; - flaginfo->not_with_flags |= without_hex; - } - - if ((flaginfo->only_with_flags & sh_flags) != flaginfo->only_with_flags) - return FALSE; - - if ((flaginfo->not_with_flags & sh_flags) != 0) - return FALSE; - - return TRUE; -} - -struct alloc_got_off_arg { - bfd_vma gotoff; - struct bfd_link_info *info; -}; - -/* 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 = (struct alloc_got_off_arg *) arg; - bfd *obfd = gofarg->info->output_bfd; - const struct elf_backend_data *bed = get_elf_backend_data (obfd); - - if (h->got.refcount > 0) - { - h->got.offset = gofarg->gotoff; - gofarg->gotoff += bed->got_elt_size (obfd, gofarg->info, h, NULL, 0); - } - 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; - struct alloc_got_off_arg gofarg; - - BFD_ASSERT (abfd == info->output_bfd); - - 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; - size_t 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 += bed->got_elt_size (abfd, info, NULL, i, j); - } - else - local_got[j] = (bfd_vma) -1; - } - } - - /* Then the global .got entries. .plt refcounts are handled by - adjust_dynamic_symbol */ - gofarg.gotoff = gotoff; - gofarg.info = info; - 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 = (struct elf_reloc_cookie *) cookie; - - if (rcookie->bad_symtab) - rcookie->rel = rcookie->rels; - - for (; rcookie->rel < rcookie->relend; rcookie->rel++) - { - unsigned long r_symndx; - - if (! rcookie->bad_symtab) - if (rcookie->rel->r_offset > offset) - return FALSE; - if (rcookie->rel->r_offset != offset) - continue; - - r_symndx = rcookie->rel->r_info >> rcookie->r_sym_shift; - if (r_symndx == STN_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) - && (h->root.u.def.section->owner != rcookie->abfd - || h->root.u.def.section->kept_section != NULL - || discarded_section (h->root.u.def.section))) - return TRUE; - } - else - { - /* 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]; - isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx); - if (isec != NULL - && (isec->kept_section != NULL - || discarded_section (isec))) - return TRUE; - } - return FALSE; - } - return FALSE; -} - -/* Discard unneeded references to discarded sections. - Returns -1 on error, 1 if any section's size was changed, 0 if - nothing changed. This function assumes that the relocations are in - sorted order, which is true for all known assemblers. */ - -int -bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) -{ - struct elf_reloc_cookie cookie; - asection *o; - bfd *abfd; - int changed = 0; - - if (info->traditional_format - || !is_elf_hash_table (info->hash)) - return 0; - - o = bfd_get_section_by_name (output_bfd, ".stab"); - if (o != NULL) - { - asection *i; - - for (i = o->map_head.s; i != NULL; i = i->map_head.s) - { - if (i->size == 0 - || i->reloc_count == 0 - || i->sec_info_type != SEC_INFO_TYPE_STABS) - continue; - - abfd = i->owner; - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - continue; - - if (!init_reloc_cookie_for_section (&cookie, info, i)) - return -1; - - if (_bfd_discard_section_stabs (abfd, i, - elf_section_data (i)->sec_info, - bfd_elf_reloc_symbol_deleted_p, - &cookie)) - changed = 1; - - fini_reloc_cookie_for_section (&cookie, i); - } - } - - o = NULL; - if (info->eh_frame_hdr_type != COMPACT_EH_HDR) - o = bfd_get_section_by_name (output_bfd, ".eh_frame"); - if (o != NULL) - { - asection *i; - int eh_changed = 0; - unsigned int eh_alignment; - - for (i = o->map_head.s; i != NULL; i = i->map_head.s) - { - if (i->size == 0) - continue; - - abfd = i->owner; - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - continue; - - if (!init_reloc_cookie_for_section (&cookie, info, i)) - return -1; - - _bfd_elf_parse_eh_frame (abfd, info, i, &cookie); - if (_bfd_elf_discard_section_eh_frame (abfd, info, i, - bfd_elf_reloc_symbol_deleted_p, - &cookie)) - { - eh_changed = 1; - if (i->size != i->rawsize) - changed = 1; - } - - fini_reloc_cookie_for_section (&cookie, i); - } - - eh_alignment = 1 << o->alignment_power; - /* Skip over zero terminator, and prevent empty sections from - adding alignment padding at the end. */ - for (i = o->map_tail.s; i != NULL; i = i->map_tail.s) - if (i->size == 0) - i->flags |= SEC_EXCLUDE; - else if (i->size > 4) - break; - /* The last non-empty eh_frame section doesn't need padding. */ - if (i != NULL) - i = i->map_tail.s; - /* Any prior sections must pad the last FDE out to the output - section alignment. Otherwise we might have zero padding - between sections, which would be seen as a terminator. */ - for (; i != NULL; i = i->map_tail.s) - if (i->size == 4) - /* All but the last zero terminator should have been removed. */ - BFD_FAIL (); - else - { - bfd_size_type size - = (i->size + eh_alignment - 1) & -eh_alignment; - if (i->size != size) - { - i->size = size; - changed = 1; - eh_changed = 1; - } - } - if (eh_changed) - elf_link_hash_traverse (elf_hash_table (info), - _bfd_elf_adjust_eh_frame_global_symbol, NULL); - } - - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) - { - const struct elf_backend_data *bed; - asection *s; - - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) - continue; - s = abfd->sections; - if (s == NULL || s->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) - continue; - - bed = get_elf_backend_data (abfd); - - if (bed->elf_backend_discard_info != NULL) - { - if (!init_reloc_cookie (&cookie, info, abfd)) - return -1; - - if ((*bed->elf_backend_discard_info) (abfd, &cookie, info)) - changed = 1; - - fini_reloc_cookie (&cookie, abfd); - } - } - - if (info->eh_frame_hdr_type == COMPACT_EH_HDR) - _bfd_elf_end_eh_frame_parsing (info); - - if (info->eh_frame_hdr_type - && !bfd_link_relocatable (info) - && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info)) - changed = 1; - - return changed; -} - -bfd_boolean -_bfd_elf_section_already_linked (bfd *abfd, - asection *sec, - struct bfd_link_info *info) -{ - flagword flags; - const char *name, *key; - struct bfd_section_already_linked *l; - struct bfd_section_already_linked_hash_entry *already_linked_list; - - if (sec->output_section == bfd_abs_section_ptr) - return FALSE; - - flags = sec->flags; - - /* Return if it isn't a linkonce section. A comdat group section - also has SEC_LINK_ONCE set. */ - if ((flags & SEC_LINK_ONCE) == 0) - return FALSE; - - /* Don't put group member sections on our list of already linked - sections. They are handled as a group via their group section. */ - if (elf_sec_group (sec) != NULL) - return FALSE; - - /* For a SHT_GROUP section, use the group signature as the key. */ - name = sec->name; - if ((flags & SEC_GROUP) != 0 - && elf_next_in_group (sec) != NULL - && elf_group_name (elf_next_in_group (sec)) != NULL) - key = elf_group_name (elf_next_in_group (sec)); - else - { - /* Otherwise we should have a .gnu.linkonce.. section. */ - if (CONST_STRNEQ (name, ".gnu.linkonce.") - && (key = strchr (name + sizeof (".gnu.linkonce.") - 1, '.')) != NULL) - key++; - else - /* Must be a user linkonce section that doesn't follow gcc's - naming convention. In this case we won't be matching - single member groups. */ - key = name; - } - - already_linked_list = bfd_section_already_linked_table_lookup (key); - - for (l = already_linked_list->entry; l != NULL; l = l->next) - { - /* We may have 2 different types of sections on the list: group - sections with a signature of ( is some string), - and linkonce sections named .gnu.linkonce... - Match like sections. LTO plugin sections are an exception. - They are always named .gnu.linkonce.t. and match either - type of section. */ - if (((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP) - && ((flags & SEC_GROUP) != 0 - || strcmp (name, l->sec->name) == 0)) - || (l->sec->owner->flags & BFD_PLUGIN) != 0) - { - /* The section has already been linked. See if we should - issue a warning. */ - if (!_bfd_handle_already_linked (sec, l, info)) - return FALSE; - - 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 TRUE; - } - } - - /* A single member comdat group section may be discarded by a - linkonce section and vice versa. */ - if ((flags & SEC_GROUP) != 0) - { - asection *first = elf_next_in_group (sec); - - if (first != NULL && elf_next_in_group (first) == first) - /* Check this single member group against linkonce sections. */ - for (l = already_linked_list->entry; l != NULL; l = l->next) - if ((l->sec->flags & SEC_GROUP) == 0 - && bfd_elf_match_symbols_in_sections (l->sec, first, info)) - { - first->output_section = bfd_abs_section_ptr; - first->kept_section = l->sec; - sec->output_section = bfd_abs_section_ptr; - break; - } - } - else - /* Check this linkonce section against single member groups. */ - 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, info)) - { - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = first; - break; - } - } - - /* Do not complain on unresolved relocations in `.gnu.linkonce.r.F' - referencing its discarded `.gnu.linkonce.t.F' counterpart - g++-3.4 - specific as g++-4.x is using COMDAT groups (without the `.gnu.linkonce' - prefix) instead. `.gnu.linkonce.r.*' were the `.rodata' part of its - matching `.gnu.linkonce.t.*'. If `.gnu.linkonce.r.F' is not discarded - but its `.gnu.linkonce.t.F' is discarded means we chose one-only - `.gnu.linkonce.t.F' section from a different bfd not requiring any - `.gnu.linkonce.r.F'. Thus `.gnu.linkonce.r.F' should be discarded. - The reverse order cannot happen as there is never a bfd with only the - `.gnu.linkonce.r.F' section. The order of sections in a bfd does not - matter as here were are looking only for cross-bfd sections. */ - - if ((flags & SEC_GROUP) == 0 && CONST_STRNEQ (name, ".gnu.linkonce.r.")) - for (l = already_linked_list->entry; l != NULL; l = l->next) - if ((l->sec->flags & SEC_GROUP) == 0 - && CONST_STRNEQ (l->sec->name, ".gnu.linkonce.t.")) - { - if (abfd != l->sec->owner) - sec->output_section = bfd_abs_section_ptr; - break; - } - - /* This is the first section with this name. Record it. */ - if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) - info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); - return sec->output_section == bfd_abs_section_ptr; -} - -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; -} - -bfd_vma -_bfd_elf_default_got_elt_size (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - struct elf_link_hash_entry *h ATTRIBUTE_UNUSED, - bfd *ibfd ATTRIBUTE_UNUSED, - unsigned long symndx ATTRIBUTE_UNUSED) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - return bed->s->arch_size / 8; -} - -/* Routines to support the creation of dynamic relocs. */ - -/* Returns the name of the dynamic reloc section associated with SEC. */ - -static const char * -get_dynamic_reloc_section_name (bfd * abfd, - asection * sec, - bfd_boolean is_rela) -{ - char *name; - const char *old_name = bfd_get_section_name (NULL, sec); - const char *prefix = is_rela ? ".rela" : ".rel"; - - if (old_name == NULL) - return NULL; - - name = bfd_alloc (abfd, strlen (prefix) + strlen (old_name) + 1); - sprintf (name, "%s%s", prefix, old_name); - - return name; -} - -/* Returns the dynamic reloc section associated with SEC. - If necessary compute the name of the dynamic reloc section based - on SEC's name (looked up in ABFD's string table) and the setting - of IS_RELA. */ - -asection * -_bfd_elf_get_dynamic_reloc_section (bfd * abfd, - asection * sec, - bfd_boolean is_rela) -{ - asection * reloc_sec = elf_section_data (sec)->sreloc; - - if (reloc_sec == NULL) - { - const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela); - - if (name != NULL) - { - reloc_sec = bfd_get_linker_section (abfd, name); - - if (reloc_sec != NULL) - elf_section_data (sec)->sreloc = reloc_sec; - } - } - - return reloc_sec; -} - -/* Returns the dynamic reloc section associated with SEC. If the - section does not exist it is created and attached to the DYNOBJ - bfd and stored in the SRELOC field of SEC's elf_section_data - structure. - - ALIGNMENT is the alignment for the newly created section and - IS_RELA defines whether the name should be .rela. - or .rel.. The section name is looked up in the - string table associated with ABFD. */ - -asection * -_bfd_elf_make_dynamic_reloc_section (asection *sec, - bfd *dynobj, - unsigned int alignment, - bfd *abfd, - bfd_boolean is_rela) -{ - asection * reloc_sec = elf_section_data (sec)->sreloc; - - if (reloc_sec == NULL) - { - const char * name = get_dynamic_reloc_section_name (abfd, sec, is_rela); - - if (name == NULL) - return NULL; - - reloc_sec = bfd_get_linker_section (dynobj, name); - - if (reloc_sec == NULL) - { - flagword flags = (SEC_HAS_CONTENTS | SEC_READONLY - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; - - reloc_sec = bfd_make_section_anyway_with_flags (dynobj, name, flags); - if (reloc_sec != NULL) - { - /* _bfd_elf_get_sec_type_attr chooses a section type by - name. Override as it may be wrong, eg. for a user - section named "auto" we'll get ".relauto" which is - seen to be a .rela section. */ - elf_section_type (reloc_sec) = is_rela ? SHT_RELA : SHT_REL; - if (! bfd_set_section_alignment (dynobj, reloc_sec, alignment)) - reloc_sec = NULL; - } - } - - elf_section_data (sec)->sreloc = reloc_sec; - } - - return reloc_sec; -} - -/* Copy the ELF symbol type and other attributes for a linker script - assignment from HSRC to HDEST. Generally this should be treated as - if we found a strong non-dynamic definition for HDEST (except that - ld ignores multiple definition errors). */ -void -_bfd_elf_copy_link_hash_symbol_type (bfd *abfd, - struct bfd_link_hash_entry *hdest, - struct bfd_link_hash_entry *hsrc) -{ - struct elf_link_hash_entry *ehdest = (struct elf_link_hash_entry *) hdest; - struct elf_link_hash_entry *ehsrc = (struct elf_link_hash_entry *) hsrc; - Elf_Internal_Sym isym; - - ehdest->type = ehsrc->type; - ehdest->target_internal = ehsrc->target_internal; - - isym.st_other = ehsrc->other; - elf_merge_st_other (abfd, ehdest, &isym, NULL, TRUE, FALSE); -} - -/* Append a RELA relocation REL to section S in BFD. */ - -void -elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela); - BFD_ASSERT (loc + bed->s->sizeof_rela <= s->contents + s->size); - bed->s->swap_reloca_out (abfd, rel, loc); -} - -/* Append a REL relocation REL to section S in BFD. */ - -void -elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - bfd_byte *loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rel); - BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size); - bed->s->swap_reloc_out (abfd, rel, loc); -} - -/* Define __start, __stop, .startof. or .sizeof. symbol. */ - -struct bfd_link_hash_entry * -bfd_elf_define_start_stop (struct bfd_link_info *info, - const char *symbol, asection *sec) -{ - struct elf_link_hash_entry *h; - - h = elf_link_hash_lookup (elf_hash_table (info), symbol, - FALSE, FALSE, TRUE); - if (h != NULL - && (h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak - || (h->ref_regular && !h->def_regular))) - { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = sec; - h->root.u.def.value = 0; - h->def_regular = 1; - h->def_dynamic = 0; - h->start_stop = 1; - h->u2.start_stop_section = sec; - if (symbol[0] == '.') - { - /* .startof. and .sizeof. symbols are local. */ - const struct elf_backend_data *bed; - bed = get_elf_backend_data (info->output_bfd); - (*bed->elf_backend_hide_symbol) (info, h, TRUE); - } - else if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_PROTECTED; - return &h->root; - } - return NULL; -} diff --git a/sdcc/support/sdbinutils/bfd/elfn32-mips.c b/sdcc/support/sdbinutils/bfd/elfn32-mips.c deleted file mode 100644 index 141ec9609..000000000 --- a/sdcc/support/sdbinutils/bfd/elfn32-mips.c +++ /dev/null @@ -1,3895 +0,0 @@ -/* MIPS-specific support for 32-bit ELF - Copyright (C) 1993-2018 Free Software Foundation, Inc. - - Most of the information added by Ian Lance Taylor, Cygnus Support, - . - N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC. - - Traditional MIPS targets support added by Koundinya.K, Dansk Data - Elektronik & Operations Research Group. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - - -/* This file handles MIPS ELF targets. SGI Irix 5 uses a slightly - different MIPS ELF from other targets. This matters when linking. - This file supports both, switching at runtime. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "bfdlink.h" -#include "genlink.h" -#include "elf-bfd.h" -#include "elfxx-mips.h" -#include "elf/mips.h" - -/* Get the ECOFF swapping routines. */ -#include "coff/sym.h" -#include "coff/symconst.h" -#include "coff/internal.h" -#include "coff/ecoff.h" -#include "coff/mips.h" -#define ECOFF_SIGNED_32 -#include "ecoffswap.h" - -static bfd_boolean mips_elf_assign_gp - (bfd *, bfd_vma *); -static bfd_reloc_status_type mips_elf_final_gp - (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *); -static bfd_reloc_status_type mips_elf_gprel16_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips_elf_literal_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips_elf_gprel32_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type gprel32_with_gp - (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma); -static bfd_reloc_status_type mips_elf_shift6_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static bfd_reloc_status_type mips16_gprel_reloc - (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); -static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup - (bfd *, bfd_reloc_code_real_type); -static reloc_howto_type *mips_elf_n32_rtype_to_howto - (unsigned int, bfd_boolean); -static void mips_info_to_howto_rel - (bfd *, arelent *, Elf_Internal_Rela *); -static void mips_info_to_howto_rela - (bfd *, arelent *, Elf_Internal_Rela *); -static bfd_boolean mips_elf_sym_is_global - (bfd *, asymbol *); -static bfd_boolean mips_elf_n32_object_p - (bfd *); -static bfd_boolean elf32_mips_grok_prstatus - (bfd *, Elf_Internal_Note *); -static bfd_boolean elf32_mips_grok_psinfo - (bfd *, Elf_Internal_Note *); -static bfd_boolean elf_n32_mips_grok_freebsd_prstatus - (bfd *, Elf_Internal_Note *); -static irix_compat_t elf_n32_mips_irix_compat - (bfd *); -static bfd_boolean mips_elf_n32_mkobject - (bfd *); - -extern const bfd_target mips_elf32_n_be_vec; -extern const bfd_target mips_elf32_n_le_vec; - -/* Nonzero if ABFD is using the N32 ABI. */ -#define ABI_N32_P(abfd) \ - ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0) - -/* Whether we are trying to be compatible with IRIX at all. */ -#define SGI_COMPAT(abfd) \ - (elf_n32_mips_irix_compat (abfd) != ict_none) - -/* The number of local .got entries we reserve. */ -#define MIPS_RESERVED_GOTNO (2) - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value - from smaller values. Start with zero, widen, *then* decrement. */ -#define MINUS_ONE (((bfd_vma)0) - 1) - -/* The relocation table used for SHT_REL sections. */ - -static reloc_howto_type elf_mips_howto_table_rel[] = -{ - /* No relocation. */ - HOWTO (R_MIPS_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit relocation. */ - HOWTO (R_MIPS_16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation. */ - HOWTO (R_MIPS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_MIPS_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 26 bit jump address. */ - HOWTO (R_MIPS_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC + 4. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_26", /* name */ - TRUE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* R_MIPS_HI16 and R_MIPS_LO16 are unsupported for NewABI REL. - However, the native IRIX6 tools use them, so we try our best. */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ - "R_MIPS_GPREL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf_literal_reloc, /* special_function */ - "R_MIPS_LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative reference. Note that the ABI document has a typo - and claims R_MIPS_PC16 to be not rightshifted, rendering it useless. - We do the right thing here. */ - HOWTO (R_MIPS_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_MIPS_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips_elf_gprel32_reloc, /* special_function */ - "R_MIPS_GPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The remaining relocs are defined on Irix 5, although they are - not defined by the ABI. */ - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - - /* A 5 bit shift field. */ - HOWTO (R_MIPS_SHIFT5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SHIFT5", /* name */ - TRUE, /* partial_inplace */ - 0x000007c0, /* src_mask */ - 0x000007c0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 6 bit shift field. */ - HOWTO (R_MIPS_SHIFT6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf_shift6_reloc, /* special_function */ - "R_MIPS_SHIFT6", /* name */ - TRUE, /* partial_inplace */ - 0x000007c4, /* src_mask */ - 0x000007c4, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 64 bit relocation. */ - HOWTO (R_MIPS_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_64", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement in the global offset table. */ - HOWTO (R_MIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_DISP", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_PAGE", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_OFST", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. */ - HOWTO (R_MIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SUB", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_A, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_A", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction, and change all relocations - to refer to the old instruction at the address. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_B", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Delete a 32 bit instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_DELETE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_DELETE", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The MIPS ELF64 ABI Draft wants us to support these for REL relocations. - We don't, because - a) It means building the addend from a R_MIPS_HIGHEST/R_MIPS_HIGHER/ - R_MIPS_HI16/R_MIPS_LO16 sequence with varying ordering, using - fallable heuristics. - b) No other NewABI toolchain actually emits such relocations. */ - EMPTY_HOWTO (R_MIPS_HIGHER), - EMPTY_HOWTO (R_MIPS_HIGHEST), - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SCN_DISP", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL16", /* name */ - TRUE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* These two are obsolete. */ - EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE), - EMPTY_HOWTO (R_MIPS_PJUMP), - - /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section. - It must be used for multigot GOT's (and only there). */ - HOWTO (R_MIPS_RELGOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_RELGOT", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0x00000000, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS GD/LD dynamic relocations. */ - HOWTO (R_MIPS_TLS_DTPMOD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPMOD32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_TLS_DTPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), - EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), - - /* TLS general dynamic variable reference. */ - HOWTO (R_MIPS_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_MIPS_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS IE dynamic relocations. */ - HOWTO (R_MIPS_TLS_TPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_TLS_TPREL64), - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation with no addend. */ - HOWTO (R_MIPS_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - - HOWTO (R_MIPS_PC21_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC21_S2", /* name */ - TRUE, /* partial_inplace */ - 0x001fffff, /* src_mask */ - 0x001fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC26_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC26_S2", /* name */ - TRUE, /* partial_inplace */ - 0x03ffffff, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC18_S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC18_S3", /* name */ - TRUE, /* partial_inplace */ - 0x0003ffff, /* src_mask */ - 0x0003ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC19_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC19_S2", /* name */ - TRUE, /* partial_inplace */ - 0x0007ffff, /* src_mask */ - 0x0007ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCHI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCHI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCLO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCLO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - -}; - -/* The relocation table used for SHT_RELA sections. */ - -static reloc_howto_type elf_mips_howto_table_rela[] = -{ - /* No relocation. */ - HOWTO (R_MIPS_NONE, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit relocation. */ - HOWTO (R_MIPS_16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation. */ - HOWTO (R_MIPS_32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit symbol relative relocation. */ - HOWTO (R_MIPS_REL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 26 bit jump address. */ - HOWTO (R_MIPS_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper 36 - bits must match the PC + 4. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_26", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MIPS_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf_gprel16_reloc, /* special_function */ - "R_MIPS_GPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips_elf_literal_reloc, /* special_function */ - "R_MIPS_LITERAL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit PC relative reference. Note that the ABI document has a typo - and claims R_MIPS_PC16 to be not rightshifted, rendering it useless. - We do the right thing here. */ - HOWTO (R_MIPS_PC16, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit GP relative reference. */ - HOWTO (R_MIPS_GPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - mips_elf_gprel32_reloc, /* special_function */ - "R_MIPS_GPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - - /* A 5 bit shift field. */ - HOWTO (R_MIPS_SHIFT5, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 5, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SHIFT5", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000007c0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A 6 bit shift field. */ - HOWTO (R_MIPS_SHIFT6, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 6, /* bitsize */ - FALSE, /* pc_relative */ - 6, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - mips_elf_shift6_reloc, /* special_function */ - "R_MIPS_SHIFT6", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000007c4, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit relocation. */ - HOWTO (R_MIPS_64, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_64", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement in the global offset table. */ - HOWTO (R_MIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_DISP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_PAGE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_OFST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GOT_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. */ - HOWTO (R_MIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SUB", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_A, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_A", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Insert the addend as an instruction, and change all relocations - to refer to the old instruction at the address. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_INSERT_B, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_INSERT_B", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Delete a 32 bit instruction. */ - /* FIXME: Not handled correctly. */ - HOWTO (R_MIPS_DELETE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_DELETE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the higher value of a 64 bit addend. */ - HOWTO (R_MIPS_HIGHER, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the highest value of a 64 bit addend. */ - HOWTO (R_MIPS_HIGHEST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_CALL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement, used by an associated event location section. */ - HOWTO (R_MIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_SCN_DISP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 16 bit relocation. */ - HOWTO (R_MIPS_REL16, /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_REL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* These two are obsolete. */ - EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE), - EMPTY_HOWTO (R_MIPS_PJUMP), - - /* Similiar to R_MIPS_REL32, but used for relocations in a GOT section. - It must be used for multigot GOT's (and only there). */ - HOWTO (R_MIPS_RELGOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_RELGOT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS GD/LD dynamic relocations. */ - HOWTO (R_MIPS_TLS_DTPMOD32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPMOD32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (R_MIPS_TLS_DTPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), - EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), - - /* TLS general dynamic variable reference. */ - HOWTO (R_MIPS_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic variable reference. */ - HOWTO (R_MIPS_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_LDM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS local dynamic offset. */ - HOWTO (R_MIPS_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_DTPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_GOTTPREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS IE dynamic relocations. */ - HOWTO (R_MIPS_TLS_TPREL32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL32", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (R_MIPS_TLS_TPREL64), - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* TLS thread pointer offset. */ - HOWTO (R_MIPS_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_TLS_TPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 32 bit relocation with no addend. */ - HOWTO (R_MIPS_GLOB_DAT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GLOB_DAT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (52), - EMPTY_HOWTO (53), - EMPTY_HOWTO (54), - EMPTY_HOWTO (55), - EMPTY_HOWTO (56), - EMPTY_HOWTO (57), - EMPTY_HOWTO (58), - EMPTY_HOWTO (59), - - HOWTO (R_MIPS_PC21_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC21_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x001fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC26_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC26_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x03ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC18_S3, /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 18, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC18_S3", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0003ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PC19_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC19_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0007ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCHI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCHI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MIPS_PCLO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PCLO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - -}; - -static reloc_howto_type elf_mips16_howto_table_rel[] = -{ - /* The reloc used for the mips16 jump instruction. */ - HOWTO (R_MIPS16_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_26", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The reloc used for the mips16 gprel instruction. */ - HOWTO (R_MIPS16_GPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips16_gprel_reloc, /* special_function */ - "R_MIPS16_GPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 reference to the global offset table. */ - HOWTO (R_MIPS16_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS16_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 call through the global offset table. */ - HOWTO (R_MIPS16_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 high 16 bits of symbol value. */ - HOWTO (R_MIPS16_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS16_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 low 16 bits of symbol value. */ - HOWTO (R_MIPS16_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS16_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS general dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GD", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_LDM", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GOTTPREL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 16-bit PC-relative branch offset. */ - HOWTO (R_MIPS16_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_PC16_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -static reloc_howto_type elf_mips16_howto_table_rela[] = -{ - /* The reloc used for the mips16 jump instruction. */ - HOWTO (R_MIPS16_26, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_26", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* The reloc used for the mips16 gprel instruction. */ - HOWTO (R_MIPS16_GPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - mips16_gprel_reloc, /* special_function */ - "R_MIPS16_GPREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 reference to the global offset table. */ - HOWTO (R_MIPS16_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MIPS16_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* A MIPS16 call through the global offset table. */ - HOWTO (R_MIPS16_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_CALL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 high 16 bits of symbol value. */ - HOWTO (R_MIPS16_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MIPS16_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 low 16 bits of symbol value. */ - HOWTO (R_MIPS16_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MIPS16_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS general dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_GD, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GD", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic variable reference. */ - HOWTO (R_MIPS16_TLS_LDM, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_LDM", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS local dynamic offset. */ - HOWTO (R_MIPS16_TLS_DTPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_DTPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_GOTTPREL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_GOTTPREL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 TLS thread pointer offset. */ - HOWTO (R_MIPS16_TLS_TPREL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_TLS_TPREL_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MIPS16 16-bit PC-relative branch offset. */ - HOWTO (R_MIPS16_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS16_PC16_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ -}; - -static reloc_howto_type elf_micromips_howto_table_rel[] = -{ - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - - /* 26 bit jump address. */ - HOWTO (R_MICROMIPS_26_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_26_S1", /* name */ - TRUE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MICROMIPS_HI16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MICROMIPS_LO16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MICROMIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_GPREL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MICROMIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_LITERAL", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MICROMIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MICROMIPS_GOT16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is for microMIPS branches. */ - HOWTO (R_MICROMIPS_PC7_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC7_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000007f, /* src_mask */ - 0x0000007f, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC10_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC10_S1", /* name */ - TRUE, /* partial_inplace */ - 0x000003ff, /* src_mask */ - 0x000003ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC16_S1", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MICROMIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL16", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - - /* Displacement in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_DISP",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_PAGE",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_OFST",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_HI16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. Used in the N32 ABI. */ - HOWTO (R_MICROMIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SUB", /* name */ - TRUE, /* partial_inplace */ - MINUS_ONE, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* We don't support these for REL relocations, because it means building - the addend from a R_MICROMIPS_HIGHEST/R_MICROMIPS_HIGHER/ - R_MICROMIPS_HI16/R_MICROMIPS_LO16 sequence with varying ordering, - using fallable heuristics. */ - EMPTY_HOWTO (R_MICROMIPS_HIGHER), - EMPTY_HOWTO (R_MICROMIPS_HIGHEST), - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_HI16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_LO16",/* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MICROMIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SCN_DISP", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MICROMIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -static reloc_howto_type elf_micromips_howto_table_rela[] = -{ - EMPTY_HOWTO (130), - EMPTY_HOWTO (131), - EMPTY_HOWTO (132), - - /* 26 bit jump address. */ - HOWTO (R_MICROMIPS_26_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - /* This needs complex overflow - detection, because the upper four - bits must match the PC. */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_26_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x3ffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_HI16, /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_hi16_reloc, /* special_function */ - "R_MICROMIPS_HI16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of symbol value. */ - HOWTO (R_MICROMIPS_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_lo16_reloc, /* special_function */ - "R_MICROMIPS_LO16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* GP relative reference. */ - HOWTO (R_MICROMIPS_GPREL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_GPREL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to literal section. */ - HOWTO (R_MICROMIPS_LITERAL, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf32_gprel16_reloc, /* special_function */ - "R_MICROMIPS_LITERAL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Reference to global offset table. */ - HOWTO (R_MICROMIPS_GOT16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_got16_reloc, /* special_function */ - "R_MICROMIPS_GOT16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* This is for microMIPS branches. */ - HOWTO (R_MICROMIPS_PC7_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 7, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC7_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000007f, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC10_S1, /* type */ - 1, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC10_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x000003ff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (R_MICROMIPS_PC16_S1, /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_PC16_S1", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* 16 bit call through global offset table. */ - HOWTO (R_MICROMIPS_CALL16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL16", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (143), - EMPTY_HOWTO (144), - - /* Displacement in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_DISP",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Displacement to page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_PAGE, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_PAGE",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Offset from page pointer in the global offset table. */ - HOWTO (R_MICROMIPS_GOT_OFST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_OFST",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_HI16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_GOT_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_GOT_LO16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* 64 bit subtraction. Used in the N32 ABI. */ - HOWTO (R_MICROMIPS_SUB, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SUB", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the higher value of a 64 bit addend. */ - HOWTO (R_MICROMIPS_HIGHER, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HIGHER", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get the highest value of a 64 bit addend. */ - HOWTO (R_MICROMIPS_HIGHEST, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_HIGHEST", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* High 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_HI16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_HI16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Low 16 bits of displacement in global offset table. */ - HOWTO (R_MICROMIPS_CALL_LO16, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_CALL_LO16",/* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Section displacement. */ - HOWTO (R_MICROMIPS_SCN_DISP, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_SCN_DISP", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Protected jump conversion. This is an optimization hint. No - relocation is required for correctness. */ - HOWTO (R_MICROMIPS_JALR, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MICROMIPS_JALR", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x00000000, /* dst_mask */ - FALSE), /* pcrel_offset */ -}; - -/* GNU extension to record C++ vtable hierarchy */ -static reloc_howto_type elf_mips_gnu_vtinherit_howto = - HOWTO (R_MIPS_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_MIPS_GNU_VTINHERIT", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* GNU extension to record C++ vtable member usage */ -static reloc_howto_type elf_mips_gnu_vtentry_howto = - HOWTO (R_MIPS_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_MIPS_GNU_VTENTRY", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* 16 bit offset for pc-relative branches. */ -static reloc_howto_type elf_mips_gnu_rel16_s2 = - HOWTO (R_MIPS_GNU_REL16_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GNU_REL16_S2", /* name */ - TRUE, /* partial_inplace */ - 0x0000ffff, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - -/* 16 bit offset for pc-relative branches. */ -static reloc_howto_type elf_mips_gnu_rela16_s2 = - HOWTO (R_MIPS_GNU_REL16_S2, /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_GNU_REL16_S2", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0x0000ffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - -/* 32 bit pc-relative. Used for compact EH tables. */ -static reloc_howto_type elf_mips_gnu_pcrel32 = - HOWTO (R_MIPS_PC32, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_PC32", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE); /* pcrel_offset */ - - -/* Originally a VxWorks extension, but now used for other systems too. */ -static reloc_howto_type elf_mips_copy_howto = - HOWTO (R_MIPS_COPY, /* type */ - 0, /* rightshift */ - 0, /* this one is variable size */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_COPY", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Originally a VxWorks extension, but now used for other systems too. */ -static reloc_howto_type elf_mips_jump_slot_howto = - HOWTO (R_MIPS_JUMP_SLOT, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_JUMP_SLOT", /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Used in EH tables. */ -static reloc_howto_type elf_mips_eh_howto = - HOWTO (R_MIPS_EH, /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - _bfd_mips_elf_generic_reloc, /* special_function */ - "R_MIPS_EH", /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE); /* pcrel_offset */ - - -/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a - dangerous relocation. */ - -static bfd_boolean -mips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) -{ - unsigned int count; - asymbol **sym; - unsigned int i; - - /* If we've already figured out what GP will be, just return it. */ - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp) - return TRUE; - - count = bfd_get_symcount (output_bfd); - sym = bfd_get_outsymbols (output_bfd); - - /* The linker script will have created a symbol named `_gp' with the - appropriate value. */ - if (sym == NULL) - i = count; - else - { - for (i = 0; i < count; i++, sym++) - { - register const char *name; - - name = bfd_asymbol_name (*sym); - if (*name == '_' && strcmp (name, "_gp") == 0) - { - *pgp = bfd_asymbol_value (*sym); - _bfd_set_gp_value (output_bfd, *pgp); - break; - } - } - } - - if (i >= count) - { - /* Only get the error once. */ - *pgp = 4; - _bfd_set_gp_value (output_bfd, *pgp); - return FALSE; - } - - return TRUE; -} - -/* We have to figure out the gp value, so that we can adjust the - symbol value correctly. We look up the symbol _gp in the output - BFD. If we can't find it, we're stuck. We cache it in the ELF - target data. We don't need to adjust the symbol value for an - external symbol if we are producing relocatable output. */ - -static bfd_reloc_status_type -mips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, - char **error_message, bfd_vma *pgp) -{ - if (bfd_is_und_section (symbol->section) - && ! relocatable) - { - *pgp = 0; - return bfd_reloc_undefined; - } - - *pgp = _bfd_get_gp_value (output_bfd); - if (*pgp == 0 - && (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0)) - { - if (relocatable) - { - /* Make up a value. */ - *pgp = symbol->section->output_section->vma /*+ 0x4000*/; - _bfd_set_gp_value (output_bfd, *pgp); - } - else if (!mips_elf_assign_gp (output_bfd, pgp)) - { - *error_message = - (char *) _("GP relative relocation when _gp not defined"); - return bfd_reloc_dangerous; - } - } - - return bfd_reloc_ok; -} - -/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -mips_elf_gprel16_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) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); -} - -/* Do a R_MIPS_LITERAL relocation. */ - -static bfd_reloc_status_type -mips_elf_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* R_MIPS_LITERAL relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("literal relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - /* FIXME: The entries in the .lit8 and .lit4 sections should be merged. */ - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); -} - -/* Do a R_MIPS_GPREL32 relocation. This is a 32 bit value which must - become the offset from the gp register. */ - -static bfd_reloc_status_type -mips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_vma gp; - - /* R_MIPS_GPREL32 relocations are defined for local symbols only. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - *error_message = (char *) - _("32bits gp relative relocation occurs for an external symbol"); - return bfd_reloc_outofrange; - } - - if (output_bfd != NULL) - { - relocatable = TRUE; - gp = _bfd_get_gp_value (output_bfd); - } - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, - error_message, &gp); - if (ret != bfd_reloc_ok) - return ret; - } - - return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, - relocatable, data, gp); -} - -static bfd_reloc_status_type -gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, - asection *input_section, bfd_boolean relocatable, - void *data, bfd_vma gp) -{ - bfd_vma relocation; - unsigned long val; - - if (bfd_is_com_section (symbol->section)) - relocation = 0; - else - relocation = symbol->value; - - relocation += symbol->section->output_section->vma; - relocation += symbol->section->output_offset; - - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) - return bfd_reloc_outofrange; - - if (reloc_entry->howto->src_mask == 0) - val = 0; - else - val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - - /* Set val to the offset into the section or symbol. */ - val += reloc_entry->addend; - - /* Adjust val for the final section location and GP value. If we - are producing relocatable output, we don't want to do this for - an external symbol. */ - if (! relocatable - || (symbol->flags & BSF_SECTION_SYM) != 0) - val += relocation - gp; - - bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); - - if (relocatable) - reloc_entry->address += input_section->output_offset; - - return bfd_reloc_ok; -} - -/* Do a R_MIPS_SHIFT6 relocation. The MSB of the shift is stored at bit 2, - the rest is at bits 6-10. The bitpos already got right by the howto. */ - -static bfd_reloc_status_type -mips_elf_shift6_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - if (reloc_entry->howto->partial_inplace) - { - reloc_entry->addend = ((reloc_entry->addend & 0x00007c0) - | (reloc_entry->addend & 0x00000800) >> 9); - } - - return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, - input_section, output_bfd, - error_message); -} - -/* Handle a mips16 GP relative reloc. */ - -static bfd_reloc_status_type -mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - void *data, asection *input_section, bfd *output_bfd, - char **error_message) -{ - bfd_boolean relocatable; - bfd_reloc_status_type ret; - bfd_byte *location; - bfd_vma gp; - - /* If we're relocating, and this is an external symbol, we don't want - to change anything. */ - if (output_bfd != NULL - && (symbol->flags & BSF_SECTION_SYM) == 0 - && (symbol->flags & BSF_LOCAL) != 0) - { - reloc_entry->address += input_section->output_offset; - return bfd_reloc_ok; - } - - if (output_bfd != NULL) - relocatable = TRUE; - else - { - relocatable = FALSE; - output_bfd = symbol->section->output_section->owner; - } - - ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, - &gp); - if (ret != bfd_reloc_ok) - return ret; - - location = (bfd_byte *) data + reloc_entry->address; - _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE, - location); - ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, - input_section, relocatable, - data, gp); - _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, !relocatable, - location); - - return ret; -} - -/* A mapping from BFD reloc types to MIPS ELF reloc types. */ - -struct elf_reloc_map { - bfd_reloc_code_real_type bfd_val; - enum elf_mips_reloc_type elf_val; -}; - -static const struct elf_reloc_map mips_reloc_map[] = -{ - { BFD_RELOC_NONE, R_MIPS_NONE }, - { BFD_RELOC_16, R_MIPS_16 }, - { BFD_RELOC_32, R_MIPS_32 }, - /* There is no BFD reloc for R_MIPS_REL32. */ - { BFD_RELOC_CTOR, R_MIPS_32 }, - { BFD_RELOC_64, R_MIPS_64 }, - { BFD_RELOC_16_PCREL_S2, R_MIPS_PC16 }, - { BFD_RELOC_HI16_S, R_MIPS_HI16 }, - { BFD_RELOC_LO16, R_MIPS_LO16 }, - { BFD_RELOC_GPREL16, R_MIPS_GPREL16 }, - { BFD_RELOC_GPREL32, R_MIPS_GPREL32 }, - { BFD_RELOC_MIPS_JMP, R_MIPS_26 }, - { BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL }, - { BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 }, - { BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 }, - { BFD_RELOC_MIPS_SHIFT5, R_MIPS_SHIFT5 }, - { BFD_RELOC_MIPS_SHIFT6, R_MIPS_SHIFT6 }, - { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP }, - { BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE }, - { BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST }, - { BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 }, - { BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 }, - { BFD_RELOC_MIPS_SUB, R_MIPS_SUB }, - { BFD_RELOC_MIPS_INSERT_A, R_MIPS_INSERT_A }, - { BFD_RELOC_MIPS_INSERT_B, R_MIPS_INSERT_B }, - { BFD_RELOC_MIPS_DELETE, R_MIPS_DELETE }, - { BFD_RELOC_MIPS_HIGHEST, R_MIPS_HIGHEST }, - { BFD_RELOC_MIPS_HIGHER, R_MIPS_HIGHER }, - { BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 }, - { BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 }, - { BFD_RELOC_MIPS_SCN_DISP, R_MIPS_SCN_DISP }, - { BFD_RELOC_MIPS_REL16, R_MIPS_REL16 }, - /* Use of R_MIPS_ADD_IMMEDIATE and R_MIPS_PJUMP is deprecated. */ - { BFD_RELOC_MIPS_RELGOT, R_MIPS_RELGOT }, - { BFD_RELOC_MIPS_JALR, R_MIPS_JALR }, - { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 }, - { BFD_RELOC_MIPS_TLS_DTPREL32, R_MIPS_TLS_DTPREL32 }, - { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 }, - { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 }, - { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD }, - { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM }, - { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 }, - { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL }, - { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, - { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, - { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, - { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }, - { BFD_RELOC_MIPS_21_PCREL_S2, R_MIPS_PC21_S2 }, - { BFD_RELOC_MIPS_26_PCREL_S2, R_MIPS_PC26_S2 }, - { BFD_RELOC_MIPS_18_PCREL_S3, R_MIPS_PC18_S3 }, - { BFD_RELOC_MIPS_19_PCREL_S2, R_MIPS_PC19_S2 }, - { BFD_RELOC_HI16_S_PCREL, R_MIPS_PCHI16 }, - { BFD_RELOC_LO16_PCREL, R_MIPS_PCLO16 } -}; - -static const struct elf_reloc_map mips16_reloc_map[] = -{ - { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min }, - { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_GD, R_MIPS16_TLS_GD - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_LDM, R_MIPS16_TLS_LDM - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_DTPREL_HI16, - R_MIPS16_TLS_DTPREL_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_DTPREL_LO16, - R_MIPS16_TLS_DTPREL_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_GOTTPREL, R_MIPS16_TLS_GOTTPREL - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_TPREL_HI16, R_MIPS16_TLS_TPREL_HI16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_TLS_TPREL_LO16, R_MIPS16_TLS_TPREL_LO16 - R_MIPS16_min }, - { BFD_RELOC_MIPS16_16_PCREL_S1, R_MIPS16_PC16_S1 - R_MIPS16_min } -}; - -static const struct elf_reloc_map micromips_reloc_map[] = -{ - { BFD_RELOC_MICROMIPS_JMP, R_MICROMIPS_26_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HI16_S, R_MICROMIPS_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_LO16, R_MICROMIPS_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GPREL16, R_MICROMIPS_GPREL16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_LITERAL, R_MICROMIPS_LITERAL - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT16, R_MICROMIPS_GOT16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_7_PCREL_S1, R_MICROMIPS_PC7_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_10_PCREL_S1, R_MICROMIPS_PC10_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_16_PCREL_S1, R_MICROMIPS_PC16_S1 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL16, R_MICROMIPS_CALL16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_DISP, R_MICROMIPS_GOT_DISP - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_PAGE, R_MICROMIPS_GOT_PAGE - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_OFST, R_MICROMIPS_GOT_OFST - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_HI16, R_MICROMIPS_GOT_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_GOT_LO16, R_MICROMIPS_GOT_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_SUB, R_MICROMIPS_SUB - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HIGHER, R_MICROMIPS_HIGHER - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_HIGHEST, R_MICROMIPS_HIGHEST - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL_HI16, R_MICROMIPS_CALL_HI16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_CALL_LO16, R_MICROMIPS_CALL_LO16 - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_SCN_DISP, R_MICROMIPS_SCN_DISP - R_MICROMIPS_min }, - { BFD_RELOC_MICROMIPS_JALR, R_MICROMIPS_JALR - R_MICROMIPS_min }, -}; - -/* Given a BFD reloc type, return a howto structure. */ - -static reloc_howto_type * -bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - unsigned int i; - /* FIXME: We default to RELA here instead of choosing the right - relocation variant. */ - reloc_howto_type *howto_table = elf_mips_howto_table_rela; - reloc_howto_type *howto16_table = elf_mips16_howto_table_rela; - reloc_howto_type *howto_micromips_table = elf_micromips_howto_table_rela; - - for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (mips_reloc_map[i].bfd_val == code) - return &howto_table[(int) mips_reloc_map[i].elf_val]; - } - - for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (mips16_reloc_map[i].bfd_val == code) - return &howto16_table[(int) mips16_reloc_map[i].elf_val]; - } - - for (i = 0; i < sizeof (micromips_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (micromips_reloc_map[i].bfd_val == code) - return &howto_micromips_table[(int) micromips_reloc_map[i].elf_val]; - } - - switch (code) - { - case BFD_RELOC_VTABLE_INHERIT: - return &elf_mips_gnu_vtinherit_howto; - case BFD_RELOC_VTABLE_ENTRY: - return &elf_mips_gnu_vtentry_howto; - case BFD_RELOC_32_PCREL: - return &elf_mips_gnu_pcrel32; - case BFD_RELOC_MIPS_EH: - return &elf_mips_eh_howto; - case BFD_RELOC_MIPS_COPY: - return &elf_mips_copy_howto; - case BFD_RELOC_MIPS_JUMP_SLOT: - return &elf_mips_jump_slot_howto; - default: - bfd_set_error (bfd_error_bad_value); - return NULL; - } -} - -static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 0; - i < (sizeof (elf_mips_howto_table_rela) - / sizeof (elf_mips_howto_table_rela[0])); - i++) - if (elf_mips_howto_table_rela[i].name != NULL - && strcasecmp (elf_mips_howto_table_rela[i].name, r_name) == 0) - return &elf_mips_howto_table_rela[i]; - - for (i = 0; - i < (sizeof (elf_mips16_howto_table_rela) - / sizeof (elf_mips16_howto_table_rela[0])); - i++) - if (elf_mips16_howto_table_rela[i].name != NULL - && strcasecmp (elf_mips16_howto_table_rela[i].name, r_name) == 0) - return &elf_mips16_howto_table_rela[i]; - - for (i = 0; - i < (sizeof (elf_micromips_howto_table_rela) - / sizeof (elf_micromips_howto_table_rela[0])); - i++) - if (elf_micromips_howto_table_rela[i].name != NULL - && strcasecmp (elf_micromips_howto_table_rela[i].name, r_name) == 0) - return &elf_micromips_howto_table_rela[i]; - - if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0) - return &elf_mips_gnu_vtinherit_howto; - if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0) - return &elf_mips_gnu_vtentry_howto; - if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0) - return &elf_mips_gnu_rel16_s2; - if (strcasecmp (elf_mips_gnu_rela16_s2.name, r_name) == 0) - return &elf_mips_gnu_rela16_s2; - if (strcasecmp (elf_mips_gnu_pcrel32.name, r_name) == 0) - return &elf_mips_gnu_pcrel32; - if (strcasecmp (elf_mips_eh_howto.name, r_name) == 0) - return &elf_mips_eh_howto; - if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0) - return &elf_mips_copy_howto; - if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0) - return &elf_mips_jump_slot_howto; - - return NULL; -} - -/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure. */ - -static reloc_howto_type * -mips_elf_n32_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p) -{ - switch (r_type) - { - case R_MIPS_GNU_VTINHERIT: - return &elf_mips_gnu_vtinherit_howto; - case R_MIPS_GNU_VTENTRY: - return &elf_mips_gnu_vtentry_howto; - case R_MIPS_GNU_REL16_S2: - if (rela_p) - return &elf_mips_gnu_rela16_s2; - else - return &elf_mips_gnu_rel16_s2; - case R_MIPS_PC32: - return &elf_mips_gnu_pcrel32; - case R_MIPS_EH: - return &elf_mips_eh_howto; - case R_MIPS_COPY: - return &elf_mips_copy_howto; - case R_MIPS_JUMP_SLOT: - return &elf_mips_jump_slot_howto; - default: - if (r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max) - { - if (rela_p) - return &elf_micromips_howto_table_rela[r_type - R_MICROMIPS_min]; - else - return &elf_micromips_howto_table_rel[r_type - R_MICROMIPS_min]; - } - if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max) - { - if (rela_p) - return &elf_mips16_howto_table_rela[r_type - R_MIPS16_min]; - else - return &elf_mips16_howto_table_rel[r_type - R_MIPS16_min]; - } - if (r_type >= R_MIPS_max) - { - _bfd_error_handler (_("unrecognised MIPS reloc number: %d"), r_type); - bfd_set_error (bfd_error_bad_value); - r_type = R_MIPS_NONE; - } - if (rela_p) - return &elf_mips_howto_table_rela[r_type]; - else - return &elf_mips_howto_table_rel[r_type]; - break; - } -} - -/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure. */ - -static void -mips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - cache_ptr->howto = mips_elf_n32_rtype_to_howto (r_type, FALSE); - - /* The addend for a GPREL16 or LITERAL relocation comes from the GP - value for the object file. We get the addend now, rather than - when we do the relocation, because the symbol manipulations done - by the linker may cause us to lose track of the input BFD. */ - if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0 - && (gprel16_reloc_p (r_type) || r_type == (unsigned int) R_MIPS_LITERAL)) - cache_ptr->addend = elf_gp (abfd); -} - -/* Given a MIPS Elf_Internal_Rela, fill in an arelent structure. */ - -static void -mips_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, Elf_Internal_Rela *dst) -{ - unsigned int r_type; - - r_type = ELF32_R_TYPE (dst->r_info); - cache_ptr->howto = mips_elf_n32_rtype_to_howto (r_type, TRUE); - cache_ptr->addend = dst->r_addend; -} - -/* Determine whether a symbol is global for the purposes of splitting - the symbol table into global symbols and local symbols. At least - on Irix 5, this split must be between section symbols and all other - symbols. On most ELF targets the split is between static symbols - and externally visible symbols. */ - -static bfd_boolean -mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) -{ - if (SGI_COMPAT (abfd)) - return (sym->flags & BSF_SECTION_SYM) == 0; - else - return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 - || bfd_is_und_section (bfd_get_section (sym)) - || bfd_is_com_section (bfd_get_section (sym))); -} - -/* Set the right machine number for a MIPS ELF file. */ - -static bfd_boolean -mips_elf_n32_object_p (bfd *abfd) -{ - unsigned long mach; - - if (!ABI_N32_P (abfd)) - return FALSE; - - /* Irix 5 and 6 are broken. Object file symbol tables are not always - sorted correctly such that local symbols precede global symbols, - and the sh_info field in the symbol table is not always right. */ - if (SGI_COMPAT (abfd)) - elf_bad_symtab (abfd) = TRUE; - - mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags); - bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach); - return TRUE; -} - -/* Support for core dump NOTE sections. */ -static bfd_boolean -elf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - int offset; - unsigned int size; - - switch (note->descsz) - { - default: - return FALSE; - - case 440: /* Linux/MIPS N32 */ - /* pr_cursig */ - elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); - - /* pr_pid */ - elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); - - /* pr_reg */ - offset = 72; - size = 360; - - break; - } - - /* Make a ".reg/999" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", size, - note->descpos + offset); -} - -static bfd_boolean -elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) -{ - switch (note->descsz) - { - default: - return FALSE; - - case 128: /* Linux/MIPS elf_prpsinfo */ - elf_tdata (abfd)->core->pid - = bfd_get_32 (abfd, note->descdata + 16); - elf_tdata (abfd)->core->program - = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core->command - = _bfd_elfcore_strndup (abfd, note->descdata + 48, 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; -} - -static bfd_boolean -elf_n32_mips_grok_freebsd_prstatus (bfd *abfd, Elf_Internal_Note *note) -{ - size_t offset; - size_t size; - size_t min_size; - - /* Compute offset of pr_getregsz, skipping over pr_statussz. - Also compute minimum size of this note. */ - offset = 4 + 4; - min_size = offset + 4 * 2 + 4 + 4 + 4; - - if (note->descsz < min_size) - return FALSE; - - /* Check for version 1 in pr_version. */ - if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1) - return FALSE; - - /* Extract size of pr_reg from pr_gregsetsz. */ - /* Skip over pr_gregsetsz and pr_fpregsetsz. */ - size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset); - offset += 4 * 2; - - /* Skip over pr_osreldate. */ - offset += 4; - - /* Read signal from pr_cursig. */ - if (elf_tdata (abfd)->core->signal == 0) - elf_tdata (abfd)->core->signal - = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset); - offset += 4; - - /* Read TID from pr_pid. */ - elf_tdata (abfd)->core->lwpid - = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset); - offset += 4; - - /* Padding before pr_reg. */ - offset += 4; - - /* Make sure that there is enough data remaining in the note. */ - if (note->descsz - offset < size) - return FALSE; - - /* Make a ".reg/999" section and a ".reg" section. */ - return _bfd_elfcore_make_pseudosection (abfd, ".reg", - size, note->descpos + offset); -} - -/* Write Linux core PRSTATUS note into core file. */ - -static char * -elf32_mips_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, - ...) -{ - switch (note_type) - { - default: - return NULL; - - case NT_PRPSINFO: - BFD_FAIL (); - return NULL; - - case NT_PRSTATUS: - { - char data[440]; - va_list ap; - long pid; - int cursig; - const void *greg; - - va_start (ap, note_type); - memset (data, 0, 72); - pid = va_arg (ap, long); - bfd_put_32 (abfd, pid, data + 24); - cursig = va_arg (ap, int); - bfd_put_16 (abfd, cursig, data + 12); - greg = va_arg (ap, const void *); - memcpy (data + 72, greg, 360); - memset (data + 432, 0, 8); - va_end (ap); - return elfcore_write_note (abfd, buf, bufsiz, - "CORE", note_type, data, sizeof (data)); - } - } -} - -/* Depending on the target vector we generate some version of Irix - executables or "normal" MIPS ELF ABI executables. */ -static irix_compat_t -elf_n32_mips_irix_compat (bfd *abfd) -{ - if ((abfd->xvec == &mips_elf32_n_be_vec) - || (abfd->xvec == &mips_elf32_n_le_vec)) - return ict_irix6; - else - return ict_none; -} - -/* Make an n32 MIPS object. We need to set the n32 ABI flag in - `e_flags' to tell the object apart from an o32 object. */ - -static bfd_boolean -mips_elf_n32_mkobject (bfd *abfd) -{ - bfd_boolean ret; - - ret = _bfd_mips_elf_mkobject (abfd); - if (ret) - elf_elfheader (abfd)->e_flags |= EF_MIPS_ABI2; - - return ret; -} - -/* ECOFF swapping routines. These are used when dealing with the - .mdebug section, which is in the ECOFF debugging format. */ -static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { - /* Symbol table magic number. */ - magicSym, - /* Alignment of debugging information. E.g., 4. */ - 4, - /* Sizes of external symbolic information. */ - sizeof (struct hdr_ext), - sizeof (struct dnr_ext), - sizeof (struct pdr_ext), - sizeof (struct sym_ext), - sizeof (struct opt_ext), - sizeof (struct fdr_ext), - sizeof (struct rfd_ext), - sizeof (struct ext_ext), - /* Functions to swap in external symbolic data. */ - ecoff_swap_hdr_in, - ecoff_swap_dnr_in, - ecoff_swap_pdr_in, - ecoff_swap_sym_in, - ecoff_swap_opt_in, - ecoff_swap_fdr_in, - ecoff_swap_rfd_in, - ecoff_swap_ext_in, - _bfd_ecoff_swap_tir_in, - _bfd_ecoff_swap_rndx_in, - /* Functions to swap out external symbolic data. */ - ecoff_swap_hdr_out, - ecoff_swap_dnr_out, - ecoff_swap_pdr_out, - ecoff_swap_sym_out, - ecoff_swap_opt_out, - ecoff_swap_fdr_out, - ecoff_swap_rfd_out, - ecoff_swap_ext_out, - _bfd_ecoff_swap_tir_out, - _bfd_ecoff_swap_rndx_out, - /* Function to read in symbolic data. */ - _bfd_mips_elf_read_ecoff_info -}; - -#define ELF_ARCH bfd_arch_mips -#define ELF_TARGET_ID MIPS_ELF_DATA -#define ELF_MACHINE_CODE EM_MIPS - -#define elf_backend_collect TRUE -#define elf_backend_type_change_ok TRUE -#define elf_backend_can_gc_sections TRUE -#define elf_backend_gc_mark_extra_sections \ - _bfd_mips_elf_gc_mark_extra_sections -#define elf_info_to_howto mips_info_to_howto_rela -#define elf_info_to_howto_rel mips_info_to_howto_rel -#define elf_backend_sym_is_global mips_elf_sym_is_global -#define elf_backend_object_p mips_elf_n32_object_p -#define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing -#define elf_backend_section_processing _bfd_mips_elf_section_processing -#define elf_backend_section_from_shdr _bfd_mips_elf_section_from_shdr -#define elf_backend_fake_sections _bfd_mips_elf_fake_sections -#define elf_backend_section_from_bfd_section \ - _bfd_mips_elf_section_from_bfd_section -#define elf_backend_add_symbol_hook _bfd_mips_elf_add_symbol_hook -#define elf_backend_link_output_symbol_hook \ - _bfd_mips_elf_link_output_symbol_hook -#define elf_backend_create_dynamic_sections \ - _bfd_mips_elf_create_dynamic_sections -#define elf_backend_check_relocs _bfd_mips_elf_check_relocs -#define elf_backend_merge_symbol_attribute \ - _bfd_mips_elf_merge_symbol_attribute -#define elf_backend_get_target_dtag _bfd_mips_elf_get_target_dtag -#define elf_backend_adjust_dynamic_symbol \ - _bfd_mips_elf_adjust_dynamic_symbol -#define elf_backend_always_size_sections \ - _bfd_mips_elf_always_size_sections -#define elf_backend_size_dynamic_sections \ - _bfd_mips_elf_size_dynamic_sections -#define elf_backend_init_index_section _bfd_elf_init_1_index_section -#define elf_backend_relocate_section _bfd_mips_elf_relocate_section -#define elf_backend_finish_dynamic_symbol \ - _bfd_mips_elf_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - _bfd_mips_elf_finish_dynamic_sections -#define elf_backend_final_write_processing \ - _bfd_mips_elf_final_write_processing -#define elf_backend_additional_program_headers \ - _bfd_mips_elf_additional_program_headers -#define elf_backend_modify_segment_map _bfd_mips_elf_modify_segment_map -#define elf_backend_gc_mark_hook _bfd_mips_elf_gc_mark_hook -#define elf_backend_gc_sweep_hook _bfd_mips_elf_gc_sweep_hook -#define elf_backend_copy_indirect_symbol \ - _bfd_mips_elf_copy_indirect_symbol -#define elf_backend_grok_prstatus elf32_mips_grok_prstatus -#define elf_backend_grok_psinfo elf32_mips_grok_psinfo -#define elf_backend_grok_freebsd_prstatus \ - elf_n32_mips_grok_freebsd_prstatus -#define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap - -#define elf_backend_got_header_size (4 * MIPS_RESERVED_GOTNO) -#define elf_backend_want_dynrelro 1 - -/* MIPS n32 ELF can use a mixture of REL and RELA, but some Relocations - work better/work only in RELA, so we default to this. */ -#define elf_backend_may_use_rel_p 1 -#define elf_backend_may_use_rela_p 1 -#define elf_backend_default_use_rela_p 1 -#define elf_backend_rela_plts_and_copies_p 0 -#define elf_backend_sign_extend_vma TRUE -#define elf_backend_plt_readonly 1 -#define elf_backend_plt_sym_val _bfd_mips_elf_plt_sym_val - -#define elf_backend_discard_info _bfd_mips_elf_discard_info -#define elf_backend_ignore_discarded_relocs \ - _bfd_mips_elf_ignore_discarded_relocs -#define elf_backend_write_section _bfd_mips_elf_write_section -#define elf_backend_mips_irix_compat elf_n32_mips_irix_compat -#define elf_backend_mips_rtype_to_howto mips_elf_n32_rtype_to_howto -#define bfd_elf32_bfd_is_target_special_symbol \ - _bfd_mips_elf_is_target_special_symbol -#define bfd_elf32_find_nearest_line _bfd_mips_elf_find_nearest_line -#define bfd_elf32_find_inliner_info _bfd_mips_elf_find_inliner_info -#define bfd_elf32_new_section_hook _bfd_mips_elf_new_section_hook -#define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents -#define bfd_elf32_bfd_get_relocated_section_contents \ - _bfd_elf_mips_get_relocated_section_contents -#define bfd_elf32_bfd_link_hash_table_create \ - _bfd_mips_elf_link_hash_table_create -#define bfd_elf32_bfd_final_link _bfd_mips_elf_final_link -#define bfd_elf32_bfd_merge_private_bfd_data \ - _bfd_mips_elf_merge_private_bfd_data -#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags -#define bfd_elf32_bfd_print_private_bfd_data \ - _bfd_mips_elf_print_private_bfd_data -#define bfd_elf32_mkobject mips_elf_n32_mkobject - -/* Support for SGI-ish mips targets using n32 ABI. */ - -#define TARGET_LITTLE_SYM mips_elf32_n_le_vec -#define TARGET_LITTLE_NAME "elf32-nlittlemips" -#define TARGET_BIG_SYM mips_elf32_n_be_vec -#define TARGET_BIG_NAME "elf32-nbigmips" - -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x1000 - -#include "elf32-target.h" - -/* Support for traditional mips targets using n32 ABI. */ -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#undef ELF_MAXPAGESIZE -#undef ELF_COMMONPAGESIZE - -#define TARGET_LITTLE_SYM mips_elf32_ntrad_le_vec -#define TARGET_LITTLE_NAME "elf32-ntradlittlemips" -#define TARGET_BIG_SYM mips_elf32_ntrad_be_vec -#define TARGET_BIG_NAME "elf32-ntradbigmips" - -#define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x1000 -#define elf32_bed elf32_tradbed - -#undef elf_backend_write_core_note -#define elf_backend_write_core_note elf32_mips_write_core_note - -/* Include the target file again for this target. */ -#include "elf32-target.h" - - -/* FreeBSD support. */ - -#undef TARGET_LITTLE_SYM -#undef TARGET_LITTLE_NAME -#undef TARGET_BIG_SYM -#undef TARGET_BIG_NAME - -#define TARGET_LITTLE_SYM mips_elf32_ntradfbsd_le_vec -#define TARGET_LITTLE_NAME "elf32-ntradlittlemips-freebsd" -#define TARGET_BIG_SYM mips_elf32_ntradfbsd_be_vec -#define TARGET_BIG_NAME "elf32-ntradbigmips-freebsd" - -#undef ELF_OSABI -#define ELF_OSABI ELFOSABI_FREEBSD - -#undef elf32_bed -#define elf32_bed elf32_fbsd_tradbed - -#undef elf_backend_write_core_note - -#include "elf32-target.h" diff --git a/sdcc/support/sdbinutils/bfd/elfnn-aarch64.c b/sdcc/support/sdbinutils/bfd/elfnn-aarch64.c deleted file mode 100644 index d5711e0eb..000000000 --- a/sdcc/support/sdbinutils/bfd/elfnn-aarch64.c +++ /dev/null @@ -1,9437 +0,0 @@ -/* AArch64-specific support for NN-bit ELF. - Copyright (C) 2009-2018 Free Software Foundation, Inc. - Contributed by ARM Ltd. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING3. If not, - see . */ - -/* Notes on implementation: - - Thread Local Store (TLS) - - Overview: - - The implementation currently supports both traditional TLS and TLS - descriptors, but only general dynamic (GD). - - For traditional TLS the assembler will present us with code - fragments of the form: - - adrp x0, :tlsgd:foo - R_AARCH64_TLSGD_ADR_PAGE21(foo) - add x0, :tlsgd_lo12:foo - R_AARCH64_TLSGD_ADD_LO12_NC(foo) - bl __tls_get_addr - nop - - For TLS descriptors the assembler will present us with code - fragments of the form: - - adrp x0, :tlsdesc:foo R_AARCH64_TLSDESC_ADR_PAGE21(foo) - ldr x1, [x0, #:tlsdesc_lo12:foo] R_AARCH64_TLSDESC_LD64_LO12(foo) - add x0, x0, #:tlsdesc_lo12:foo R_AARCH64_TLSDESC_ADD_LO12(foo) - .tlsdesccall foo - blr x1 R_AARCH64_TLSDESC_CALL(foo) - - The relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} against foo - indicate that foo is thread local and should be accessed via the - traditional TLS mechanims. - - The relocations R_AARCH64_TLSDESC_{ADR_PAGE21,LD64_LO12_NC,ADD_LO12_NC} - against foo indicate that 'foo' is thread local and should be accessed - via a TLS descriptor mechanism. - - The precise instruction sequence is only relevant from the - perspective of linker relaxation which is currently not implemented. - - The static linker must detect that 'foo' is a TLS object and - allocate a double GOT entry. The GOT entry must be created for both - global and local TLS symbols. Note that this is different to none - TLS local objects which do not need a GOT entry. - - In the traditional TLS mechanism, the double GOT entry is used to - provide the tls_index structure, containing module and offset - entries. The static linker places the relocation R_AARCH64_TLS_DTPMOD - on the module entry. The loader will subsequently fixup this - relocation with the module identity. - - For global traditional TLS symbols the static linker places an - R_AARCH64_TLS_DTPREL relocation on the offset entry. The loader - will subsequently fixup the offset. For local TLS symbols the static - linker fixes up offset. - - In the TLS descriptor mechanism the double GOT entry is used to - provide the descriptor. The static linker places the relocation - R_AARCH64_TLSDESC on the first GOT slot. The loader will - subsequently fix this up. - - Implementation: - - The handling of TLS symbols is implemented across a number of - different backend functions. The following is a top level view of - what processing is performed where. - - The TLS implementation maintains state information for each TLS - symbol. The state information for local and global symbols is kept - in different places. Global symbols use generic BFD structures while - local symbols use backend specific structures that are allocated and - maintained entirely by the backend. - - The flow: - - elfNN_aarch64_check_relocs() - - This function is invoked for each relocation. - - The TLS relocations R_AARCH64_TLSGD_{ADR_PREL21,ADD_LO12_NC} and - R_AARCH64_TLSDESC_{ADR_PAGE21,LD64_LO12_NC,ADD_LO12_NC} are - spotted. One time creation of local symbol data structures are - created when the first local symbol is seen. - - The reference count for a symbol is incremented. The GOT type for - each symbol is marked as general dynamic. - - elfNN_aarch64_allocate_dynrelocs () - - For each global with positive reference count we allocate a double - GOT slot. For a traditional TLS symbol we allocate space for two - relocation entries on the GOT, for a TLS descriptor symbol we - allocate space for one relocation on the slot. Record the GOT offset - for this symbol. - - elfNN_aarch64_size_dynamic_sections () - - Iterate all input BFDS, look for in the local symbol data structure - constructed earlier for local TLS symbols and allocate them double - GOT slots along with space for a single GOT relocation. Update the - local symbol structure to record the GOT offset allocated. - - elfNN_aarch64_relocate_section () - - Calls elfNN_aarch64_final_link_relocate () - - Emit the relevant TLS relocations against the GOT for each TLS - symbol. For local TLS symbols emit the GOT offset directly. The GOT - relocations are emitted once the first time a TLS symbol is - encountered. The implementation uses the LSB of the GOT offset to - flag that the relevant GOT relocations for a symbol have been - emitted. All of the TLS code that uses the GOT offset needs to take - care to mask out this flag bit before using the offset. - - elfNN_aarch64_final_link_relocate () - - Fixup the R_AARCH64_TLSGD_{ADR_PREL21, ADD_LO12_NC} relocations. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libiberty.h" -#include "libbfd.h" -#include "bfd_stdint.h" -#include "elf-bfd.h" -#include "bfdlink.h" -#include "objalloc.h" -#include "elf/aarch64.h" -#include "elfxx-aarch64.h" - -#define ARCH_SIZE NN - -#if ARCH_SIZE == 64 -#define AARCH64_R(NAME) R_AARCH64_ ## NAME -#define AARCH64_R_STR(NAME) "R_AARCH64_" #NAME -#define HOWTO64(...) HOWTO (__VA_ARGS__) -#define HOWTO32(...) EMPTY_HOWTO (0) -#define LOG_FILE_ALIGN 3 -#define BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC BFD_RELOC_AARCH64_TLSDESC_LD64_LO12 -#endif - -#if ARCH_SIZE == 32 -#define AARCH64_R(NAME) R_AARCH64_P32_ ## NAME -#define AARCH64_R_STR(NAME) "R_AARCH64_P32_" #NAME -#define HOWTO64(...) EMPTY_HOWTO (0) -#define HOWTO32(...) HOWTO (__VA_ARGS__) -#define LOG_FILE_ALIGN 2 -#define BFD_RELOC_AARCH64_TLSDESC_LD32_LO12 BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC -#define R_AARCH64_P32_TLSDESC_ADD_LO12 R_AARCH64_P32_TLSDESC_ADD_LO12_NC -#endif - -#define IS_AARCH64_TLS_RELOC(R_TYPE) \ - ((R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G1 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLS_DTPMOD \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLS_DTPREL \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLS_TPREL \ - || IS_AARCH64_TLSDESC_RELOC ((R_TYPE))) - -#define IS_AARCH64_TLS_RELAX_RELOC(R_TYPE) \ - ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDNN_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADR_PREL21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSGD_MOVW_G1 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSIE_LDNN_GOTTPREL_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSLD_ADR_PREL21) - -#define IS_AARCH64_TLSDESC_RELOC(R_TYPE) \ - ((R_TYPE) == BFD_RELOC_AARCH64_TLSDESC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADD_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_CALL \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD64_LO12 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LDR \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_LD_PREL19 \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC \ - || (R_TYPE) == BFD_RELOC_AARCH64_TLSDESC_OFF_G1) - -#define ELIMINATE_COPY_RELOCS 1 - -/* Return size of a relocation entry. HTAB is the bfd's - elf_aarch64_link_hash_entry. */ -#define RELOC_SIZE(HTAB) (sizeof (ElfNN_External_Rela)) - -/* GOT Entry size - 8 bytes in ELF64 and 4 bytes in ELF32. */ -#define GOT_ENTRY_SIZE (ARCH_SIZE / 8) -#define PLT_ENTRY_SIZE (32) -#define PLT_SMALL_ENTRY_SIZE (16) -#define PLT_TLSDESC_ENTRY_SIZE (32) - -/* Encoding of the nop instruction. */ -#define INSN_NOP 0xd503201f - -#define aarch64_compute_jump_table_size(htab) \ - (((htab)->root.srelplt == NULL) ? 0 \ - : (htab)->root.srelplt->reloc_count * GOT_ENTRY_SIZE) - -/* The first entry in a procedure linkage table looks like this - if the distance between the PLTGOT and the PLT is < 4GB use - these PLT entries. Note that the dynamic linker gets &PLTGOT[2] - in x16 and needs to work out PLTGOT[1] by using an address of - [x16,#-GOT_ENTRY_SIZE]. */ -static const bfd_byte elfNN_aarch64_small_plt0_entry[PLT_ENTRY_SIZE] = -{ - 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */ - 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */ -#if ARCH_SIZE == 64 - 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */ - 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */ -#else - 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */ - 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */ -#endif - 0x20, 0x02, 0x1f, 0xd6, /* br x17 */ - 0x1f, 0x20, 0x03, 0xd5, /* nop */ - 0x1f, 0x20, 0x03, 0xd5, /* nop */ - 0x1f, 0x20, 0x03, 0xd5, /* nop */ -}; - -/* Per function entry in a procedure linkage table looks like this - if the distance between the PLTGOT and the PLT is < 4GB use - these PLT entries. */ -static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] = -{ - 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */ -#if ARCH_SIZE == 64 - 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */ - 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */ -#else - 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */ - 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */ -#endif - 0x20, 0x02, 0x1f, 0xd6, /* br x17. */ -}; - -static const bfd_byte -elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] = -{ - 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */ - 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */ - 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */ -#if ARCH_SIZE == 64 - 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */ - 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */ -#else - 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */ - 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */ -#endif - 0x40, 0x00, 0x1f, 0xd6, /* br x2 */ - 0x1f, 0x20, 0x03, 0xd5, /* nop */ - 0x1f, 0x20, 0x03, 0xd5, /* nop */ -}; - -#define elf_info_to_howto elfNN_aarch64_info_to_howto -#define elf_info_to_howto_rel elfNN_aarch64_info_to_howto - -#define AARCH64_ELF_ABI_VERSION 0 - -/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ -#define ALL_ONES (~ (bfd_vma) 0) - -/* Indexed by the bfd interal reloc enumerators. - Therefore, the table needs to be synced with BFD_RELOC_AARCH64_* - in reloc.c. */ - -static reloc_howto_type elfNN_aarch64_howto_table[] = -{ - EMPTY_HOWTO (0), - - /* Basic data relocations. */ - - /* Deprecated, but retained for backwards compatibility. */ - HOWTO64 (R_AARCH64_NULL, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AARCH64_NULL", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - HOWTO (R_AARCH64_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AARCH64_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* .xword: (S+A) */ - HOWTO64 (AARCH64_R (ABS64), /* type */ - 0, /* rightshift */ - 4, /* size (4 = long long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ABS64), /* name */ - FALSE, /* partial_inplace */ - ALL_ONES, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* .word: (S+A) */ - HOWTO (AARCH64_R (ABS32), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ABS32), /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* .half: (S+A) */ - HOWTO (AARCH64_R (ABS16), /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ABS16), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* .xword: (S+A-P) */ - HOWTO64 (AARCH64_R (PREL64), /* type */ - 0, /* rightshift */ - 4, /* size (4 = long long) */ - 64, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (PREL64), /* name */ - FALSE, /* partial_inplace */ - ALL_ONES, /* src_mask */ - ALL_ONES, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* .word: (S+A-P) */ - HOWTO (AARCH64_R (PREL32), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (PREL32), /* name */ - FALSE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* .half: (S+A-P) */ - HOWTO (AARCH64_R (PREL16), /* type */ - 0, /* rightshift */ - 1, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (PREL16), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Group relocations to create a 16, 32, 48 or 64 bit - unsigned data or abs address inline. */ - - /* MOVZ: ((S+A) >> 0) & 0xffff */ - HOWTO (AARCH64_R (MOVW_UABS_G0), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G0), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVK: ((S+A) >> 0) & 0xffff [no overflow check] */ - HOWTO (AARCH64_R (MOVW_UABS_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVZ: ((S+A) >> 16) & 0xffff */ - HOWTO (AARCH64_R (MOVW_UABS_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVK: ((S+A) >> 16) & 0xffff [no overflow check] */ - HOWTO64 (AARCH64_R (MOVW_UABS_G1_NC), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G1_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVZ: ((S+A) >> 32) & 0xffff */ - HOWTO64 (AARCH64_R (MOVW_UABS_G2), /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G2), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVK: ((S+A) >> 32) & 0xffff [no overflow check] */ - HOWTO64 (AARCH64_R (MOVW_UABS_G2_NC), /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G2_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVZ: ((S+A) >> 48) & 0xffff */ - HOWTO64 (AARCH64_R (MOVW_UABS_G3), /* type */ - 48, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_UABS_G3), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Group relocations to create high part of a 16, 32, 48 or 64 bit - signed data or abs address inline. Will change instruction - to MOVN or MOVZ depending on sign of calculated value. */ - - /* MOV[ZN]: ((S+A) >> 0) & 0xffff */ - HOWTO (AARCH64_R (MOVW_SABS_G0), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_SABS_G0), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOV[ZN]: ((S+A) >> 16) & 0xffff */ - HOWTO64 (AARCH64_R (MOVW_SABS_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_SABS_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOV[ZN]: ((S+A) >> 32) & 0xffff */ - HOWTO64 (AARCH64_R (MOVW_SABS_G2), /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 17, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_SABS_G2), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - -/* Relocations to generate 19, 21 and 33 bit PC-relative load/store - addresses: PG(x) is (x & ~0xfff). */ - - /* LD-lit: ((S+A-P) >> 2) & 0x7ffff */ - HOWTO (AARCH64_R (LD_PREL_LO19), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LD_PREL_LO19), /* name */ - FALSE, /* partial_inplace */ - 0x7ffff, /* src_mask */ - 0x7ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* ADR: (S+A-P) & 0x1fffff */ - HOWTO (AARCH64_R (ADR_PREL_LO21), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ADR_PREL_LO21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */ - HOWTO (AARCH64_R (ADR_PREL_PG_HI21), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ADR_PREL_PG_HI21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff [no overflow check] */ - HOWTO64 (AARCH64_R (ADR_PREL_PG_HI21_NC), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ADR_PREL_PG_HI21_NC), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* ADD: (S+A) & 0xfff [no overflow check] */ - HOWTO (AARCH64_R (ADD_ABS_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ADD_ABS_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0x3ffc00, /* src_mask */ - 0x3ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST8: (S+A) & 0xfff */ - HOWTO (AARCH64_R (LDST8_ABS_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LDST8_ABS_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Relocations for control-flow instructions. */ - - /* TBZ/NZ: ((S+A-P) >> 2) & 0x3fff */ - HOWTO (AARCH64_R (TSTBR14), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 14, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TSTBR14), /* name */ - FALSE, /* partial_inplace */ - 0x3fff, /* src_mask */ - 0x3fff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* B.cond: ((S+A-P) >> 2) & 0x7ffff */ - HOWTO (AARCH64_R (CONDBR19), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (CONDBR19), /* name */ - FALSE, /* partial_inplace */ - 0x7ffff, /* src_mask */ - 0x7ffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* B: ((S+A-P) >> 2) & 0x3ffffff */ - HOWTO (AARCH64_R (JUMP26), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (JUMP26), /* name */ - FALSE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* BL: ((S+A-P) >> 2) & 0x3ffffff */ - HOWTO (AARCH64_R (CALL26), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 26, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (CALL26), /* name */ - FALSE, /* partial_inplace */ - 0x3ffffff, /* src_mask */ - 0x3ffffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* LD/ST16: (S+A) & 0xffe */ - HOWTO (AARCH64_R (LDST16_ABS_LO12_NC), /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LDST16_ABS_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffe, /* src_mask */ - 0xffe, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST32: (S+A) & 0xffc */ - HOWTO (AARCH64_R (LDST32_ABS_LO12_NC), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LDST32_ABS_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffc, /* src_mask */ - 0xffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST64: (S+A) & 0xff8 */ - HOWTO (AARCH64_R (LDST64_ABS_LO12_NC), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LDST64_ABS_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xff8, /* src_mask */ - 0xff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST128: (S+A) & 0xff0 */ - HOWTO (AARCH64_R (LDST128_ABS_LO12_NC), /* type */ - 4, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LDST128_ABS_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xff0, /* src_mask */ - 0xff0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Set a load-literal immediate field to bits - 0x1FFFFC of G(S)-P */ - HOWTO (AARCH64_R (GOT_LD_PREL19), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte,1 = short,2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (GOT_LD_PREL19), /* name */ - FALSE, /* partial_inplace */ - 0xffffe0, /* src_mask */ - 0xffffe0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Get to the page for the GOT entry for the symbol - (G(S) - P) using an ADRP instruction. */ - HOWTO (AARCH64_R (ADR_GOT_PAGE), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (ADR_GOT_PAGE), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* LD64: GOT offset G(S) & 0xff8 */ - HOWTO64 (AARCH64_R (LD64_GOT_LO12_NC), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LD64_GOT_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xff8, /* src_mask */ - 0xff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD32: GOT offset G(S) & 0xffc */ - HOWTO32 (AARCH64_R (LD32_GOT_LO12_NC), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LD32_GOT_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffc, /* src_mask */ - 0xffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 16 bits of GOT offset for the symbol. */ - HOWTO64 (AARCH64_R (MOVW_GOTOFF_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_GOTOFF_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Higher 16 bits of GOT offset for the symbol. */ - HOWTO64 (AARCH64_R (MOVW_GOTOFF_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (MOVW_GOTOFF_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD64: GOT offset for the symbol. */ - HOWTO64 (AARCH64_R (LD64_GOTOFF_LO15), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LD64_GOTOFF_LO15), /* name */ - FALSE, /* partial_inplace */ - 0x7ff8, /* src_mask */ - 0x7ff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD32: GOT offset to the page address of GOT table. - (G(S) - PAGE (_GLOBAL_OFFSET_TABLE_)) & 0x5ffc. */ - HOWTO32 (AARCH64_R (LD32_GOTPAGE_LO14), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LD32_GOTPAGE_LO14), /* name */ - FALSE, /* partial_inplace */ - 0x5ffc, /* src_mask */ - 0x5ffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD64: GOT offset to the page address of GOT table. - (G(S) - PAGE (_GLOBAL_OFFSET_TABLE_)) & 0x7ff8. */ - HOWTO64 (AARCH64_R (LD64_GOTPAGE_LO15), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (LD64_GOTPAGE_LO15), /* name */ - FALSE, /* partial_inplace */ - 0x7ff8, /* src_mask */ - 0x7ff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get to the page for the GOT entry for the symbol - (G(S) - P) using an ADRP instruction. */ - HOWTO (AARCH64_R (TLSGD_ADR_PAGE21), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSGD_ADR_PAGE21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSGD_ADR_PREL21), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSGD_ADR_PREL21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* ADD: GOT offset G(S) & 0xff8 [no overflow check] */ - HOWTO (AARCH64_R (TLSGD_ADD_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSGD_ADD_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Lower 16 bits of GOT offset to tls_index. */ - HOWTO64 (AARCH64_R (TLSGD_MOVW_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSGD_MOVW_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Higher 16 bits of GOT offset to tls_index. */ - HOWTO64 (AARCH64_R (TLSGD_MOVW_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSGD_MOVW_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSIE_ADR_GOTTPREL_PAGE21), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSIE_ADR_GOTTPREL_PAGE21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSIE_LD64_GOTTPREL_LO12_NC), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSIE_LD64_GOTTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xff8, /* src_mask */ - 0xff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO32 (AARCH64_R (TLSIE_LD32_GOTTPREL_LO12_NC), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSIE_LD32_GOTTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffc, /* src_mask */ - 0xffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSIE_LD_GOTTPREL_PREL19), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSIE_LD_GOTTPREL_PREL19), /* name */ - FALSE, /* partial_inplace */ - 0x1ffffc, /* src_mask */ - 0x1ffffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSIE_MOVW_GOTTPREL_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSIE_MOVW_GOTTPREL_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* ADD: bit[23:12] of byte offset to module TLS base address. */ - HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_HI12), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_ADD_DTPREL_HI12), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Unsigned 12 bit byte offset to module TLS base address. */ - HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_LO12), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_ADD_DTPREL_LO12), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12. */ - HOWTO (AARCH64_R (TLSLD_ADD_DTPREL_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_ADD_DTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* ADD: GOT offset G(S) & 0xff8 [no overflow check] */ - HOWTO (AARCH64_R (TLSLD_ADD_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_ADD_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Get to the page for the GOT entry for the symbol - (G(S) - P) using an ADRP instruction. */ - HOWTO (AARCH64_R (TLSLD_ADR_PAGE21), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_ADR_PAGE21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLD_ADR_PREL21), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_signed, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_ADR_PREL21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* LD/ST16: bit[11:1] of byte offset to module TLS base address. */ - HOWTO64 (AARCH64_R (TLSLD_LDST16_DTPREL_LO12), /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST16_DTPREL_LO12), /* name */ - FALSE, /* partial_inplace */ - 0x1ffc00, /* src_mask */ - 0x1ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Same as BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12, but no overflow check. */ - HOWTO64 (AARCH64_R (TLSLD_LDST16_DTPREL_LO12_NC), /* type */ - 1, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 11, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST16_DTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0x1ffc00, /* src_mask */ - 0x1ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST32: bit[11:2] of byte offset to module TLS base address. */ - HOWTO64 (AARCH64_R (TLSLD_LDST32_DTPREL_LO12), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST32_DTPREL_LO12), /* name */ - FALSE, /* partial_inplace */ - 0x3ffc00, /* src_mask */ - 0x3ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Same as BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12, but no overflow check. */ - HOWTO64 (AARCH64_R (TLSLD_LDST32_DTPREL_LO12_NC), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 10, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST32_DTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffc00, /* src_mask */ - 0xffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST64: bit[11:3] of byte offset to module TLS base address. */ - HOWTO64 (AARCH64_R (TLSLD_LDST64_DTPREL_LO12), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST64_DTPREL_LO12), /* name */ - FALSE, /* partial_inplace */ - 0x3ffc00, /* src_mask */ - 0x3ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Same as BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12, but no overflow check. */ - HOWTO64 (AARCH64_R (TLSLD_LDST64_DTPREL_LO12_NC), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 9, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST64_DTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0x7fc00, /* src_mask */ - 0x7fc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD/ST8: bit[11:0] of byte offset to module TLS base address. */ - HOWTO64 (AARCH64_R (TLSLD_LDST8_DTPREL_LO12), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST8_DTPREL_LO12), /* name */ - FALSE, /* partial_inplace */ - 0x3ffc00, /* src_mask */ - 0x3ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* Same as BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12, but no overflow check. */ - HOWTO64 (AARCH64_R (TLSLD_LDST8_DTPREL_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 10, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_LDST8_DTPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0x3ffc00, /* src_mask */ - 0x3ffc00, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVZ: bit[15:0] of byte offset to module TLS base address. */ - HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G0), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_MOVW_DTPREL_G0), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0. */ - HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_MOVW_DTPREL_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVZ: bit[31:16] of byte offset to module TLS base address. */ - HOWTO (AARCH64_R (TLSLD_MOVW_DTPREL_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_MOVW_DTPREL_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* No overflow check version of BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1. */ - HOWTO64 (AARCH64_R (TLSLD_MOVW_DTPREL_G1_NC), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_MOVW_DTPREL_G1_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* MOVZ: bit[47:32] of byte offset to module TLS base address. */ - HOWTO64 (AARCH64_R (TLSLD_MOVW_DTPREL_G2), /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLD_MOVW_DTPREL_G2), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G2), /* type */ - 32, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_MOVW_TPREL_G2), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_MOVW_TPREL_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSLE_MOVW_TPREL_G1_NC), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_MOVW_TPREL_G1_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G0), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_MOVW_TPREL_G0), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLE_MOVW_TPREL_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 16, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_MOVW_TPREL_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLE_ADD_TPREL_HI12), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_ADD_TPREL_HI12), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLE_ADD_TPREL_LO12), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_ADD_TPREL_LO12), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSLE_ADD_TPREL_LO12_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSLE_ADD_TPREL_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSDESC_LD_PREL19), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 19, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_LD_PREL19), /* name */ - FALSE, /* partial_inplace */ - 0x0ffffe0, /* src_mask */ - 0x0ffffe0, /* dst_mask */ - TRUE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSDESC_ADR_PREL21), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_ADR_PREL21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* Get to the page for the GOT entry for the symbol - (G(S) - P) using an ADRP instruction. */ - HOWTO (AARCH64_R (TLSDESC_ADR_PAGE21), /* type */ - 12, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 21, /* bitsize */ - TRUE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_ADR_PAGE21), /* name */ - FALSE, /* partial_inplace */ - 0x1fffff, /* src_mask */ - 0x1fffff, /* dst_mask */ - TRUE), /* pcrel_offset */ - - /* LD64: GOT offset G(S) & 0xff8. */ - HOWTO64 (AARCH64_R (TLSDESC_LD64_LO12), /* type */ - 3, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_LD64_LO12), /* name */ - FALSE, /* partial_inplace */ - 0xff8, /* src_mask */ - 0xff8, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* LD32: GOT offset G(S) & 0xffc. */ - HOWTO32 (AARCH64_R (TLSDESC_LD32_LO12_NC), /* type */ - 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_LD32_LO12_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffc, /* src_mask */ - 0xffc, /* dst_mask */ - FALSE), /* pcrel_offset */ - - /* ADD: GOT offset G(S) & 0xfff. */ - HOWTO (AARCH64_R (TLSDESC_ADD_LO12), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_ADD_LO12), /* name */ - FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSDESC_OFF_G1), /* type */ - 16, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_unsigned, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_OFF_G1), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSDESC_OFF_G0_NC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_OFF_G0_NC), /* name */ - FALSE, /* partial_inplace */ - 0xffff, /* src_mask */ - 0xffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSDESC_LDR), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_LDR), /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO64 (AARCH64_R (TLSDESC_ADD), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 12, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_ADD), /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSDESC_CALL), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC_CALL), /* name */ - FALSE, /* partial_inplace */ - 0x0, /* src_mask */ - 0x0, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (COPY), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (COPY), /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (GLOB_DAT), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (GLOB_DAT), /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (JUMP_SLOT), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (JUMP_SLOT), /* name */ - TRUE, /* partial_inplace */ - 0xffffffff, /* src_mask */ - 0xffffffff, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (RELATIVE), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (RELATIVE), /* name */ - TRUE, /* partial_inplace */ - ALL_ONES, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLS_DTPMOD), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ -#if ARCH_SIZE == 64 - AARCH64_R_STR (TLS_DTPMOD64), /* name */ -#else - AARCH64_R_STR (TLS_DTPMOD), /* name */ -#endif - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pc_reloffset */ - - HOWTO (AARCH64_R (TLS_DTPREL), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ -#if ARCH_SIZE == 64 - AARCH64_R_STR (TLS_DTPREL64), /* name */ -#else - AARCH64_R_STR (TLS_DTPREL), /* name */ -#endif - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLS_TPREL), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ -#if ARCH_SIZE == 64 - AARCH64_R_STR (TLS_TPREL64), /* name */ -#else - AARCH64_R_STR (TLS_TPREL), /* name */ -#endif - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (TLSDESC), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (TLSDESC), /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pcrel_offset */ - - HOWTO (AARCH64_R (IRELATIVE), /* type */ - 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - AARCH64_R_STR (IRELATIVE), /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - ALL_ONES, /* dst_mask */ - FALSE), /* pcrel_offset */ - - EMPTY_HOWTO (0), -}; - -static reloc_howto_type elfNN_aarch64_howto_none = - HOWTO (R_AARCH64_NONE, /* type */ - 0, /* rightshift */ - 3, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - FALSE, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ - bfd_elf_generic_reloc, /* special_function */ - "R_AARCH64_NONE", /* name */ - FALSE, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - FALSE); /* pcrel_offset */ - -/* Given HOWTO, return the bfd internal relocation enumerator. */ - -static bfd_reloc_code_real_type -elfNN_aarch64_bfd_reloc_from_howto (reloc_howto_type *howto) -{ - const int size - = (int) ARRAY_SIZE (elfNN_aarch64_howto_table); - const ptrdiff_t offset - = howto - elfNN_aarch64_howto_table; - - if (offset > 0 && offset < size - 1) - return BFD_RELOC_AARCH64_RELOC_START + offset; - - if (howto == &elfNN_aarch64_howto_none) - return BFD_RELOC_AARCH64_NONE; - - return BFD_RELOC_AARCH64_RELOC_START; -} - -/* Given R_TYPE, return the bfd internal relocation enumerator. */ - -static bfd_reloc_code_real_type -elfNN_aarch64_bfd_reloc_from_type (unsigned int r_type) -{ - static bfd_boolean initialized_p = FALSE; - /* Indexed by R_TYPE, values are offsets in the howto_table. */ - static unsigned int offsets[R_AARCH64_end]; - - if (!initialized_p) - { - unsigned int i; - - for (i = 1; i < ARRAY_SIZE (elfNN_aarch64_howto_table) - 1; ++i) - if (elfNN_aarch64_howto_table[i].type != 0) - offsets[elfNN_aarch64_howto_table[i].type] = i; - - initialized_p = TRUE; - } - - if (r_type == R_AARCH64_NONE || r_type == R_AARCH64_NULL) - return BFD_RELOC_AARCH64_NONE; - - /* PR 17512: file: b371e70a. */ - if (r_type >= R_AARCH64_end) - { - _bfd_error_handler (_("Invalid AArch64 reloc number: %d"), r_type); - bfd_set_error (bfd_error_bad_value); - return BFD_RELOC_AARCH64_NONE; - } - - return BFD_RELOC_AARCH64_RELOC_START + offsets[r_type]; -} - -struct elf_aarch64_reloc_map -{ - bfd_reloc_code_real_type from; - bfd_reloc_code_real_type to; -}; - -/* Map bfd generic reloc to AArch64-specific reloc. */ -static const struct elf_aarch64_reloc_map elf_aarch64_reloc_map[] = -{ - {BFD_RELOC_NONE, BFD_RELOC_AARCH64_NONE}, - - /* Basic data relocations. */ - {BFD_RELOC_CTOR, BFD_RELOC_AARCH64_NN}, - {BFD_RELOC_64, BFD_RELOC_AARCH64_64}, - {BFD_RELOC_32, BFD_RELOC_AARCH64_32}, - {BFD_RELOC_16, BFD_RELOC_AARCH64_16}, - {BFD_RELOC_64_PCREL, BFD_RELOC_AARCH64_64_PCREL}, - {BFD_RELOC_32_PCREL, BFD_RELOC_AARCH64_32_PCREL}, - {BFD_RELOC_16_PCREL, BFD_RELOC_AARCH64_16_PCREL}, -}; - -/* Given the bfd internal relocation enumerator in CODE, return the - corresponding howto entry. */ - -static reloc_howto_type * -elfNN_aarch64_howto_from_bfd_reloc (bfd_reloc_code_real_type code) -{ - unsigned int i; - - /* Convert bfd generic reloc to AArch64-specific reloc. */ - if (code < BFD_RELOC_AARCH64_RELOC_START - || code > BFD_RELOC_AARCH64_RELOC_END) - for (i = 0; i < ARRAY_SIZE (elf_aarch64_reloc_map); i++) - if (elf_aarch64_reloc_map[i].from == code) - { - code = elf_aarch64_reloc_map[i].to; - break; - } - - if (code > BFD_RELOC_AARCH64_RELOC_START - && code < BFD_RELOC_AARCH64_RELOC_END) - if (elfNN_aarch64_howto_table[code - BFD_RELOC_AARCH64_RELOC_START].type) - return &elfNN_aarch64_howto_table[code - BFD_RELOC_AARCH64_RELOC_START]; - - if (code == BFD_RELOC_AARCH64_NONE) - return &elfNN_aarch64_howto_none; - - return NULL; -} - -static reloc_howto_type * -elfNN_aarch64_howto_from_type (unsigned int r_type) -{ - bfd_reloc_code_real_type val; - reloc_howto_type *howto; - -#if ARCH_SIZE == 32 - if (r_type > 256) - { - bfd_set_error (bfd_error_bad_value); - return NULL; - } -#endif - - if (r_type == R_AARCH64_NONE) - return &elfNN_aarch64_howto_none; - - val = elfNN_aarch64_bfd_reloc_from_type (r_type); - howto = elfNN_aarch64_howto_from_bfd_reloc (val); - - if (howto != NULL) - return howto; - - bfd_set_error (bfd_error_bad_value); - return NULL; -} - -static void -elfNN_aarch64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, - Elf_Internal_Rela *elf_reloc) -{ - unsigned int r_type; - - r_type = ELFNN_R_TYPE (elf_reloc->r_info); - bfd_reloc->howto = elfNN_aarch64_howto_from_type (r_type); -} - -static reloc_howto_type * -elfNN_aarch64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, - bfd_reloc_code_real_type code) -{ - reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (code); - - if (howto != NULL) - return howto; - - bfd_set_error (bfd_error_bad_value); - return NULL; -} - -static reloc_howto_type * -elfNN_aarch64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, - const char *r_name) -{ - unsigned int i; - - for (i = 1; i < ARRAY_SIZE (elfNN_aarch64_howto_table) - 1; ++i) - if (elfNN_aarch64_howto_table[i].name != NULL - && strcasecmp (elfNN_aarch64_howto_table[i].name, r_name) == 0) - return &elfNN_aarch64_howto_table[i]; - - return NULL; -} - -#define TARGET_LITTLE_SYM aarch64_elfNN_le_vec -#define TARGET_LITTLE_NAME "elfNN-littleaarch64" -#define TARGET_BIG_SYM aarch64_elfNN_be_vec -#define TARGET_BIG_NAME "elfNN-bigaarch64" - -/* The linker script knows the section names for placement. - The entry_names are used to do simple name mangling on the stubs. - Given a function name, and its type, the stub can be found. The - name can be changed. The only requirement is the %s be present. */ -#define STUB_ENTRY_NAME "__%s_veneer" - -/* The name of the dynamic interpreter. This is put in the .interp - section. */ -#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1" - -#define AARCH64_MAX_FWD_BRANCH_OFFSET \ - (((1 << 25) - 1) << 2) -#define AARCH64_MAX_BWD_BRANCH_OFFSET \ - (-((1 << 25) << 2)) - -#define AARCH64_MAX_ADRP_IMM ((1 << 20) - 1) -#define AARCH64_MIN_ADRP_IMM (-(1 << 20)) - -static int -aarch64_valid_for_adrp_p (bfd_vma value, bfd_vma place) -{ - bfd_signed_vma offset = (bfd_signed_vma) (PG (value) - PG (place)) >> 12; - return offset <= AARCH64_MAX_ADRP_IMM && offset >= AARCH64_MIN_ADRP_IMM; -} - -static int -aarch64_valid_branch_p (bfd_vma value, bfd_vma place) -{ - bfd_signed_vma offset = (bfd_signed_vma) (value - place); - return (offset <= AARCH64_MAX_FWD_BRANCH_OFFSET - && offset >= AARCH64_MAX_BWD_BRANCH_OFFSET); -} - -static const uint32_t aarch64_adrp_branch_stub [] = -{ - 0x90000010, /* adrp ip0, X */ - /* R_AARCH64_ADR_HI21_PCREL(X) */ - 0x91000210, /* add ip0, ip0, :lo12:X */ - /* R_AARCH64_ADD_ABS_LO12_NC(X) */ - 0xd61f0200, /* br ip0 */ -}; - -static const uint32_t aarch64_long_branch_stub[] = -{ -#if ARCH_SIZE == 64 - 0x58000090, /* ldr ip0, 1f */ -#else - 0x18000090, /* ldr wip0, 1f */ -#endif - 0x10000011, /* adr ip1, #0 */ - 0x8b110210, /* add ip0, ip0, ip1 */ - 0xd61f0200, /* br ip0 */ - 0x00000000, /* 1: .xword or .word - R_AARCH64_PRELNN(X) + 12 - */ - 0x00000000, -}; - -static const uint32_t aarch64_erratum_835769_stub[] = -{ - 0x00000000, /* Placeholder for multiply accumulate. */ - 0x14000000, /* b